diff --git a/app/build.gradle b/app/build.gradle index 422ab44..f07980d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.github.axet.audiorecorder" minSdkVersion 16 targetSdkVersion 23 - versionCode 27 - versionName "1.1.6" + versionCode 28 + versionName "1.1.7" } signingConfigs { release { diff --git a/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java b/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java index 93f2589..fec624e 100644 --- a/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java +++ b/app/src/main/java/com/github/axet/audiorecorder/activities/RecordingActivity.java @@ -54,8 +54,6 @@ import com.github.axet.audiorecorder.widgets.PitchView; import java.io.File; public class RecordingActivity extends AppCompatActivity { - public static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; - public static int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; public static int MAXIMUM_ALTITUDE = 5000; public static final String TAG = RecordingActivity.class.getSimpleName(); @@ -81,7 +79,7 @@ public class RecordingActivity extends AppCompatActivity { Integer bufferSize = 0; // variable from settings. how may samples per second. int sampleRate; - // how many samples count need to update view. 4410 for 100ms update. + // pitch size in samples. how many samples count need to update view. 4410 for 100ms update. int samplesUpdate; // output target file 2016-01-01 01.01.01.wav File targetFile; @@ -125,6 +123,7 @@ public class RecordingActivity extends AppCompatActivity { class PhoneStateChangeListener extends PhoneStateListener { public boolean wasRinging; + public boolean pausedByCall; @Override public void onCallStateChanged(int s, String incomingNumber) { @@ -133,14 +132,18 @@ public class RecordingActivity extends AppCompatActivity { wasRinging = true; break; case TelephonyManager.CALL_STATE_OFFHOOK: - stopRecording("playerPause (hold by call)"); wasRinging = true; + if (thread != null) { + stopRecording("playerPause (hold by call)"); + pausedByCall = true; + } break; case TelephonyManager.CALL_STATE_IDLE: - if (wasRinging && permitted()) { - resumeRecording(); + if (pausedByCall) { + startRecording(); } wasRinging = false; + pausedByCall = false; break; } } @@ -212,7 +215,6 @@ public class RecordingActivity extends AppCompatActivity { public void run() { stopRecording(); storage.delete(storage.getTempRecording()); - //storage.delete(targetFile); finish(); } }); @@ -250,8 +252,10 @@ public class RecordingActivity extends AppCompatActivity { } void loadSamples() { - if (!storage.getTempRecording().exists()) + if (!storage.getTempRecording().exists()) { + updateSamples(0); return; + } RawSamples rs = new RawSamples(storage.getTempRecording()); samplesTime = rs.getSamples(); @@ -270,11 +274,12 @@ public class RecordingActivity extends AppCompatActivity { rs.open(cut, buf.length); int len = rs.read(buf); + rs.close(); + pitch.clear(cut / samplesUpdate); for (int i = 0; i < len; i += samplesUpdate) { pitch.add(getPa(buf, i, samplesUpdate)); } - rs.close(); updateSamples(samplesTime); } @@ -297,16 +302,9 @@ public class RecordingActivity extends AppCompatActivity { if (thread != null) { stopRecording("pause"); } else { - if (editSample != -1) { - RawSamples rs = new RawSamples(storage.getTempRecording()); - rs.trunk(editSample); - loadSamples(); - edit(false); - } + editCut(); - if (permitted(PERMISSIONS)) { - resumeRecording(); - } + startRecording(); } } @@ -315,18 +313,18 @@ public class RecordingActivity extends AppCompatActivity { super.onResume(); Log.d(TAG, "onResume"); + updateBufferSize(false); + // start once if (start) { start = false; if (permitted()) { - record(); + startRecording(); } } - updateBufferSize(false); - if (thread != null) - pitch.resume(); + pitch.record(); } @Override @@ -335,7 +333,7 @@ public class RecordingActivity extends AppCompatActivity { Log.d(TAG, "onPause"); updateBufferSize(true); edit(false); - pitch.pause(); + pitch.stop(); } void stopRecording(String status) { @@ -361,7 +359,7 @@ public class RecordingActivity extends AppCompatActivity { thread.interrupt(); thread = null; } - pitch.pause(); + pitch.stop(); sound.unsilent(); } @@ -377,10 +375,7 @@ public class RecordingActivity extends AppCompatActivity { cut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - RawSamples rs = new RawSamples(storage.getTempRecording()); - rs.trunk(editSample); - loadSamples(); - edit(false); + editCut(); } }); @@ -407,7 +402,7 @@ public class RecordingActivity extends AppCompatActivity { editSample = -1; state.setText("pause"); editPlay(false); - pitch.pause(); + pitch.stop(); View box = findViewById(R.id.recording_edit_box); box.setVisibility(View.GONE); } @@ -429,12 +424,7 @@ public class RecordingActivity extends AppCompatActivity { AudioTrack.OnPlaybackPositionUpdateListener listener = new AudioTrack.OnPlaybackPositionUpdateListener() { @Override public void onMarkerReached(AudioTrack track) { - handler.post(new Runnable() { - @Override - public void run() { - editPlay(false); - } - }); + editPlay(false); } @Override @@ -466,6 +456,18 @@ public class RecordingActivity extends AppCompatActivity { } } + void editCut() { + if (editSample == -1) + return; + + RawSamples rs = new RawSamples(storage.getTempRecording()); + rs.trunk(editSample); + rs.close(); + edit(false); + loadSamples(); + pitch.drawCalc(); + } + @Override public void onBackPressed() { cancelDialog(new Runnable() { @@ -495,13 +497,6 @@ public class RecordingActivity extends AppCompatActivity { builder.show(); } - void resumeRecording() { - if (thread == null) { - record(); - } - pitch.resume(); - } - @Override protected void onDestroy() { super.onDestroy(); @@ -523,7 +518,7 @@ public class RecordingActivity extends AppCompatActivity { showNotificationAlarm(false); } - void record() { + void startRecording() { edit(false); pitch.setOnTouchListener(null); @@ -547,10 +542,7 @@ public class RecordingActivity extends AppCompatActivity { Log.e(TAG, "Unable to set Thread Priority " + android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); } - long startTime = System.currentTimeMillis(); - // start recording after 1 sec or stableRefresh - long goTime = startTime + 1000; - + long start = System.currentTimeMillis(); RawSamples rs = null; AudioRecord recorder = null; try { @@ -558,17 +550,12 @@ public class RecordingActivity extends AppCompatActivity { rs.open(samplesTime); - int min = AudioRecord.getMinBufferSize(sampleRate, CHANNEL_CONFIG, AUDIO_FORMAT); + int min = AudioRecord.getMinBufferSize(sampleRate, RawSamples.CHANNEL_CONFIG, RawSamples.AUDIO_FORMAT); if (min <= 0) { throw new RuntimeException("Unable to initialize AudioRecord: Bad audio values"); } - // make it 5 seconds buffer - int min2 = 5 * sampleRate - * (AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1) - * (CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO ? 2 : 1); - - recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, CHANNEL_CONFIG, AUDIO_FORMAT, Math.min(min2, min)); + recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, RawSamples.CHANNEL_CONFIG, RawSamples.AUDIO_FORMAT, min); if (recorder.getState() != AudioRecord.STATE_INITIALIZED) { throw new RuntimeException("Unable to initialize AudioRecord"); } @@ -578,13 +565,11 @@ public class RecordingActivity extends AppCompatActivity { int samplesUpdateCount = 0; int samplesTimeCount = 0; // how many samples we need to update 'samples'. time clock. every 1000ms. - int samplesTimeUpdate = 1000 / 1000 * sampleRate * (CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? 1 : 2); + int samplesTimeUpdate = 1000 / 1000 * sampleRate * (RawSamples.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? 1 : 2); short[] buffer = null; while (!Thread.currentThread().isInterrupted()) { - long cur = System.currentTimeMillis(); - synchronized (bufferSize) { if (buffer == null || buffer.length != bufferSize) buffer = new short[bufferSize]; @@ -595,14 +580,20 @@ public class RecordingActivity extends AppCompatActivity { break; } - if (cur > goTime || pitch.stableRefresh()) { - rs.write(buffer); + int s = RawSamples.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? readSize : readSize / 2; - int s = CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? readSize : readSize / 2; + if (pitch.stableRefresh()) { + rs.write(buffer); samplesUpdateCount += s; if (samplesUpdateCount >= samplesUpdate) { - pitch.add(getPa(buffer, 0, readSize)); + final float pa = getPa(buffer, 0, readSize); + handle.post(new Runnable() { + @Override + public void run() { + pitch.add(pa); + } + }); samplesUpdateCount -= samplesUpdate; } @@ -630,9 +621,18 @@ public class RecordingActivity extends AppCompatActivity { } }); } finally { - if (rs != null) { + // redraw view, we may add one last pich which is not been drawen because draw tread already interrupted. + // to prevent resume recording jump - draw last added pitch here. + handle.post(new Runnable() { + @Override + public void run() { + pitch.drawEnd(); + } + }); + + if (rs != null) rs.close(); - } + if (recorder != null) recorder.release(); } @@ -640,6 +640,8 @@ public class RecordingActivity extends AppCompatActivity { }, "RecordingThread"); thread.start(); + pitch.record(); + showNotificationAlarm(true); } @@ -653,7 +655,7 @@ public class RecordingActivity extends AppCompatActivity { samplesUpdate = (int) (pitch.getPitchTime() * sampleRate / 1000.0); } - bufferSize = CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? samplesUpdate : samplesUpdate * 2; + bufferSize = RawSamples.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO ? samplesUpdate : samplesUpdate * 2; } } @@ -670,7 +672,7 @@ public class RecordingActivity extends AppCompatActivity { } int amplitude = (int) (Math.sqrt(sum / len)); - float pa = amplitude / (float) MAXIMUM_ALTITUDE + 0.01f; + float pa = amplitude / (float) MAXIMUM_ALTITUDE; return pa; } @@ -716,7 +718,7 @@ public class RecordingActivity extends AppCompatActivity { switch (requestCode) { case 1: if (permitted(permissions)) { - record(); + startRecording(); } else { Toast.makeText(this, "Not permitted", Toast.LENGTH_SHORT).show(); finish(); @@ -748,8 +750,8 @@ public class RecordingActivity extends AppCompatActivity { } EncoderInfo getInfo() { - final int channels = CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO ? 2 : 1; - final int bps = AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 16 : 8; + final int channels = RawSamples.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO ? 2 : 1; + final int bps = RawSamples.AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 16 : 8; return new EncoderInfo(channels, sampleRate, bps); } diff --git a/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java b/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java index b8e4741..0dff0e1 100644 --- a/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java +++ b/app/src/main/java/com/github/axet/audiorecorder/app/RawSamples.java @@ -16,6 +16,8 @@ import java.nio.ByteOrder; import java.nio.channels.FileChannel; public class RawSamples { + public static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; + public static int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO; File in; @@ -42,7 +44,7 @@ public class RawSamples { // bufReadSize - samples count public void open(int bufReadSize) { try { - readBuffer = new byte[getBufferLen(bufReadSize)]; + readBuffer = new byte[(int) getBufferLen(bufReadSize)]; is = new FileInputStream(in); } catch (IOException e) { throw new RuntimeException(e); @@ -55,9 +57,9 @@ public class RawSamples { // bufReadSize - samples size public void open(long offset, int bufReadSize) { try { - readBuffer = new byte[getBufferLen(bufReadSize)]; + readBuffer = new byte[(int) getBufferLen(bufReadSize)]; is = new FileInputStream(in); - is.skip(offset * (RecordingActivity.AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1)); + is.skip(offset * (AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1)); } catch (IOException e) { throw new RuntimeException(e); } @@ -96,18 +98,18 @@ public class RawSamples { return getSamples(in.length()); } - public long getSamples(long len) { - return len / (RecordingActivity.AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1); + public static long getSamples(long len) { + return len / (AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1); } - public int getBufferLen(int samples) { - return samples * (RecordingActivity.AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1); + public static long getBufferLen(long samples) { + return samples * (AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1); } public void trunk(long pos) { try { FileChannel outChan = new FileOutputStream(in, true).getChannel(); - outChan.truncate(pos * (RecordingActivity.AUDIO_FORMAT == AudioFormat.ENCODING_PCM_16BIT ? 2 : 1)); + outChan.truncate(getBufferLen(pos)); outChan.close(); } catch (IOException e) { throw new RuntimeException(e); diff --git a/app/src/main/java/com/github/axet/audiorecorder/app/Sound.java b/app/src/main/java/com/github/axet/audiorecorder/app/Sound.java index 563740b..88687b3 100644 --- a/app/src/main/java/com/github/axet/audiorecorder/app/Sound.java +++ b/app/src/main/java/com/github/axet/audiorecorder/app/Sound.java @@ -56,10 +56,10 @@ public class Sound { int c = 0; - if (RecordingActivity.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO) + if (RawSamples.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_MONO) c = AudioFormat.CHANNEL_OUT_MONO; - if (RecordingActivity.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO) + if (RawSamples.CHANNEL_CONFIG == AudioFormat.CHANNEL_IN_STEREO) c = AudioFormat.CHANNEL_OUT_STEREO; // old phones bug. @@ -67,7 +67,7 @@ public class Sound { // // with MODE_STATIC setNotificationMarkerPosition not called AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, - c, RecordingActivity.AUDIO_FORMAT, + c, RawSamples.AUDIO_FORMAT, len * (Short.SIZE / 8), AudioTrack.MODE_STREAM); track.write(buf, 0, len); if (track.setNotificationMarkerPosition(end) != AudioTrack.SUCCESS) diff --git a/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java b/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java index 9058049..2ace271 100644 --- a/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java +++ b/app/src/main/java/com/github/axet/audiorecorder/widgets/PitchView.java @@ -4,14 +4,9 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; import android.os.Build; import android.os.Handler; -import android.os.Looper; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; @@ -68,20 +63,21 @@ public class PitchView extends ViewGroup { Runnable edit; // index int editPos = 0; - int editCount = 0; + boolean editFlash = false; // current playing position in samples float playPos = -1; Runnable play; Runnable draw; - Thread thread; + float offset = 0; + + Handler handler; int pitchColor = 0xff0433AE; Paint cutColor = new Paint(); int bg; - public class PitchGraphView extends SurfaceView implements SurfaceHolder.Callback { - SurfaceHolder holder; + public class PitchGraphView extends View { Paint editPaint; Paint playPaint; @@ -103,8 +99,6 @@ public class PitchView extends ViewGroup { playPaint = new Paint(); playPaint.setColor(Color.BLUE); playPaint.setStrokeWidth(pitchWidth / 2); - - getHolder().addCallback(this); } @Override @@ -116,6 +110,8 @@ public class PitchView extends ViewGroup { pitchScreenCount = w / pitchSize + 1; pitchMemCount = pitchScreenCount + 1; + + fit(pitchScreenCount); } @Override @@ -123,13 +119,8 @@ public class PitchView extends ViewGroup { super.onLayout(changed, left, top, right, bottom); } - public void draw() { - float offset = 0; - + public void calc() { if (data.size() >= pitchMemCount) { - if (time == 0) - time = System.currentTimeMillis(); - long cur = System.currentTimeMillis(); float tick = (cur - time) / (float) pitchTime; @@ -157,13 +148,10 @@ public class PitchView extends ViewGroup { offset = pitchSize * tick; } - - draw(offset); } - void draw(float offset) { - Canvas canvas = holder.lockCanvas(null); - + @Override + public void onDraw(Canvas canvas) { int m = Math.min(pitchMemCount, data.size()); canvas.drawColor(bg); @@ -186,12 +174,12 @@ public class PitchView extends ViewGroup { p = cutColor; // left channel pitch - canvas.drawLine(x, mid, x, mid - mid * left, p); + canvas.drawLine(x, mid, x, mid - mid * left - 1, p); // right channel pitch - canvas.drawLine(x, mid, x, mid + mid * right, p); + canvas.drawLine(x, mid, x, mid + mid * right + 1, p); } - if (edit != null && editCount == 0) { + if (edit != null && editFlash) { float x = editPos * pitchSize + pitchSize / 2f; canvas.drawLine(x, 0, x, getHeight(), editPaint); } @@ -200,39 +188,11 @@ public class PitchView extends ViewGroup { float x = playPos * pitchSize + pitchSize / 2f; canvas.drawLine(x, 0, x, getHeight(), playPaint); } - - holder.unlockCanvasAndPost(canvas); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - synchronized (PitchView.this) { - this.holder = holder; - fit(); - draw(0); - } - } - - @Override - public void surfaceCreated(final SurfaceHolder holder) { - synchronized (PitchView.this) { - this.holder = holder; - fit(); - draw(0); - } - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - synchronized (PitchView.this) { - this.holder = null; - } } } - public class PitchCurrentView extends SurfaceView implements SurfaceHolder.Callback { + public class PitchCurrentView extends View { Paint paint; - SurfaceHolder holder; public PitchCurrentView(Context context) { this(context, null); @@ -248,8 +208,6 @@ public class PitchView extends ViewGroup { paint = new Paint(); paint.setColor(pitchColor); paint.setStrokeWidth(pitchWidth); - - getHolder().addCallback(this); } @Override @@ -265,8 +223,8 @@ public class PitchView extends ViewGroup { super.onLayout(changed, left, top, right, bottom); } - public void draw() { - Canvas canvas = holder.lockCanvas(null); + @Override + public void onDraw(Canvas canvas) { canvas.drawColor(bg); if (data.size() > 0) { @@ -275,6 +233,9 @@ public class PitchView extends ViewGroup { if (edit != null) { end = editPos; } + if (play != null) { + end = (int) playPos; + } float left = data.get(end); float right = data.get(end); @@ -286,31 +247,6 @@ public class PitchView extends ViewGroup { canvas.drawLine(mid, y, mid - mid * left, y, paint); canvas.drawLine(mid, y, mid + mid * right, y, paint); } - - holder.unlockCanvasAndPost(canvas); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - synchronized (PitchView.this) { - this.holder = holder; - draw(); - } - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - synchronized (PitchView.this) { - this.holder = holder; - draw(); - } - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - synchronized (PitchView.this) { - this.holder = null; - } } } @@ -329,6 +265,8 @@ public class PitchView extends ViewGroup { } void create() { + handler = new Handler(); + pitchDlimiter = dp2px(PITCH_DELIMITER); pitchWidth = dp2px(PITCH_WIDTH); pitchSize = pitchWidth + pitchDlimiter; @@ -369,13 +307,15 @@ public class PitchView extends ViewGroup { public void clear(long s) { data.clear(); samples = s; + offset = 0; edit = null; draw = null; + play = null; } - public void fit() { - if (data.size() > pitchMemCount) { - int cut = data.size() - pitchMemCount; + public void fit(int max) { + if (data.size() > max) { + int cut = data.size() - max; data.subList(0, cut).clear(); samples += cut; } @@ -383,30 +323,24 @@ public class PitchView extends ViewGroup { public void add(float a) { data.add(a); - - // after pause, we still may get one last sample. force view redraw. - if (thread == null) { - draw(); - } } - public void draw() { - synchronized (this) { - if (graph.holder != null) - graph.draw(); - if (current.holder != null) - current.draw(); - } + public void drawCalc() { + graph.calc(); + graph.invalidate(); + current.invalidate(); + } + + public void drawEnd() { + fit(pitchMemCount); + offset = 0; + draw(); } // draw in edit mode - public void drawEdit() { - synchronized (this) { - if (graph.holder != null) - graph.draw(0); - if (current.holder != null) - current.draw(); - } + public void draw() { + graph.invalidate(); + current.invalidate(); } public int getPitchTime() { @@ -452,194 +386,179 @@ public class PitchView extends ViewGroup { current.draw(canvas); } - public void pause() { - if (thread != null) { - thread.interrupt(); - thread = null; - } - + public void stop() { if (edit != null) - edit = null; - if (draw != null) - draw = null; - if (play != null) - play = null; + handler.removeCallbacks(edit); + edit = null; - drawEdit(); + if (draw != null) + handler.removeCallbacks(draw); + draw = null; + + if (play != null) + handler.removeCallbacks(play); + play = null; + + draw(); } public long edit(float offset) { - synchronized (this) { - if (offset < 0) - offset = 0; - editPos = ((int) offset) / pitchSize; + if (offset < 0) + offset = 0; + editPos = ((int) offset) / pitchSize; - if (editPos >= pitchScreenCount) - editPos = pitchScreenCount - 1; + if (editPos >= pitchScreenCount) + editPos = pitchScreenCount - 1; - if (editPos >= data.size()) - editPos = data.size() - 1; - - editCount = 0; - drawEdit(); - } + if (editPos >= data.size()) + editPos = data.size() - 1; if (draw != null) { + handler.removeCallbacks(draw); draw = null; - if (thread != null) { - thread.interrupt(); - thread = null; - } } + if (play != null) { + handler.removeCallbacks(play); + play = null; + } + + draw(); + edit(); return samples + editPos; } public void edit() { - if (thread == null) { + if (edit == null) { + editFlash = true; + edit = new Runnable() { + long start = System.currentTimeMillis(); + @Override public void run() { - while (!Thread.currentThread().isInterrupted()) { - long time = System.currentTimeMillis(); - drawEdit(); + draw(); - editCount++; - if (editCount > 1) - editCount = 0; + editFlash = !editFlash; - long cur = System.currentTimeMillis(); + long cur = System.currentTimeMillis(); - long delay = EDIT_UPDATE_SPEED - (cur - time); + long diff = cur - start; - if (delay > 0) { - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - } - } + long delay = EDIT_UPDATE_SPEED + (EDIT_UPDATE_SPEED - diff); + if (delay > EDIT_UPDATE_SPEED) + delay = EDIT_UPDATE_SPEED; + + start = cur; + + if (delay > 0) + handler.postDelayed(edit, delay); + else + handler.post(edit); } }; - thread = new Thread(edit, TAG); - thread.start(); + // post instead of draw.run() so 'start' will measure actual queue time + handler.post(edit); } } - public void resume() { - if (edit != null) { - edit = null; - if (thread != null) { - thread.interrupt(); - thread = null; - } - } - if (play != null) { - play = null; - if (thread != null) { - thread.interrupt(); - thread = null; - } - } - if (thread == null) { + public void record() { + if (edit != null) + handler.removeCallbacks(edit); + edit = null; + + if (play != null) + handler.removeCallbacks(play); + play = null; + + if (draw == null) { stableRefresh = false; + time = System.currentTimeMillis(); draw = new Runnable() { + long start = System.currentTimeMillis(); + @Override public void run() { - time = System.currentTimeMillis(); - int count = 0; - while (!Thread.currentThread().isInterrupted()) { - long time = System.currentTimeMillis(); - draw(); - long cur = System.currentTimeMillis(); + drawCalc(); + long cur = System.currentTimeMillis(); - long delay = UPDATE_SPEED - (cur - time); + long diff = cur - start; - if (delay > 0) { - count++; - if (count > 5) { - stableRefresh = true; - } - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - } - } + long delay = UPDATE_SPEED + (UPDATE_SPEED - diff); + if (delay > UPDATE_SPEED) + delay = UPDATE_SPEED; + + start = cur; + + stableRefresh = true; + if (delay > 0) + handler.postDelayed(draw, delay); + else + handler.post(draw); } }; - thread = new Thread(draw, TAG); - thread.start(); + // post instead of draw.run() so 'start' will measure actual queue time + handler.post(draw); } } // current paying pos in actual samples public void play(float pos) { - synchronized (this) { - playPos = pos - samples; + playPos = pos - samples; - editCount = 0; + editFlash = true; - if (playPos < 0) - playPos = -1; + if (playPos < 0 || playPos > data.size()) + playPos = -1; - if (playPos < 0) { - if (play != null) { - play = null; - if (thread != null) { - thread.interrupt(); - thread = null; - } - } - if (thread == null) { - edit(); - } - return; + if (playPos < 0) { + if (play != null) { + handler.removeCallbacks(play); + play = null; } + return; } - if (play == null && thread != null) { - thread.interrupt(); - thread = null; - } + if (edit != null) + handler.removeCallbacks(edit); - if (thread == null) { + if (draw != null) + handler.removeCallbacks(draw); + draw = null; + + if (play == null) { + time = System.currentTimeMillis(); play = new Runnable() { + long start = System.currentTimeMillis(); + @Override public void run() { - time = System.currentTimeMillis(); - while (!Thread.currentThread().isInterrupted()) { - long time = System.currentTimeMillis(); - drawEdit(); - long cur = System.currentTimeMillis(); + draw(); + long cur = System.currentTimeMillis(); - long delay = UPDATE_SPEED - (cur - time); + long diff = cur - start; - if (delay > 0) { - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } + start = cur; + + long delay = UPDATE_SPEED + (UPDATE_SPEED - diff); + if (delay > UPDATE_SPEED) + delay = UPDATE_SPEED; + + if (delay > 0) + handler.postDelayed(play, delay); + else + handler.post(play); } }; - thread = new Thread(play, TAG); - thread.start(); + // post instead of draw.run() so 'start' will measure actual queue time + handler.post(play); } } public boolean stableRefresh() { - synchronized (this) { - return stableRefresh; - } + return stableRefresh; } } diff --git a/app/src/main/res/layout/activity_recording.xml b/app/src/main/res/layout/activity_recording.xml index b84a65e..553d664 100644 --- a/app/src/main/res/layout/activity_recording.xml +++ b/app/src/main/res/layout/activity_recording.xml @@ -40,38 +40,42 @@ android:layout_height="120dp" android:layout_centerInParent="true" /> - + android:layout_above="@id/recording_pitch"> - + - + + + - - - + + +