diff options
Diffstat (limited to 'LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java')
-rw-r--r-- | LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java | 56 |
1 files changed, 34 insertions, 22 deletions
diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java index eca9a82..ed70a09 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/SoundLevelCalibration.java @@ -25,7 +25,7 @@ import android.util.Log; class SoundLevelCalibration { private static final int SECONDS_PER_LEVEL = 1; private static final int MAX_STEPS = 15; // The maximum number of levels that should be tried - private static final double CRITICAL_RATIO = 0.4; // Ratio of input over output amplitude at + private static final double CRITICAL_RATIO = 0.41; // Ratio of input over output amplitude at // which the feedback loop neither decays nor // grows (determined experimentally) private static final String TAG = "SoundLevelCalibration"; @@ -68,34 +68,39 @@ class SoundLevelCalibration { // TODO: Allow stopping in the middle of calibration int calibrate() { final int maxLevel = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); - int delta = (maxLevel + MAX_STEPS - 1) / MAX_STEPS; // round up - int level; - // TODO: Use a better algorithm such as binary search. - for(level = maxLevel; level >= 0; level -= delta) { - mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, level, 0); - if (mChangeListener != null) { - mChangeListener.go(level); - } - - mNativeAudioThread.start(); - try { - mNativeAudioThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - double[] data = mNativeAudioThread.getWaveData(); + int levelBottom = 0; + int levelTop = maxLevel + 1; + while(levelTop - levelBottom > 1) { + int level = (levelBottom + levelTop) / 2; + Log.d(TAG, "setting level to " + level); + setVolume(level); + + double amplitude = runAudioThread(mNativeAudioThread); mNativeAudioThread = new NativeAudioThread(mNativeAudioThread); // generate fresh thread - double amplitude = averageAmplitude(data); Log.d(TAG, "calibrate: at sound level " + level + " volume was " + amplitude); if (amplitude < Constant.SINE_WAVE_AMPLITUDE * CRITICAL_RATIO) { - Log.d(TAG, "calibrate: chose sound level " + level); - break; + levelBottom = level; + } else { + levelTop = level; } } + // At this point, levelBottom has the highest proper value, if there is one (0 otherwise) + Log.d(TAG, "Final level: " + levelBottom); + setVolume(levelBottom); + return levelBottom; + } - // Return the maximum level if we can't find a proper one - return level != 0 ? level : maxLevel; + private double runAudioThread(NativeAudioThread thread) { + // runs the native audio thread and returns the average amplitude + thread.start(); + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + double[] data = thread.getWaveData(); + return averageAmplitude(data); } // TODO: Only gives accurate results for an undistorted sine wave. Check for distortion. @@ -110,6 +115,13 @@ class SoundLevelCalibration { return Math.sqrt(2.0 * sumSquare / data.length); // amplitude of the sine wave } + private void setVolume(int level) { + mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, level, 0); + if (mChangeListener != null) { + mChangeListener.go(level); + } + } + void setChangeListener(SoundLevelChangeListener changeListener) { mChangeListener = changeListener; } |