commit d07cddb37046b0f27498dcf68d12f103f6e87b65 parent f0ad6e283c6c29f37e8c8eea5c14869fec3178d3 Author: gstraube <gstraube@mailbox.org> Date: Tue, 14 Aug 2018 11:38:25 +0200 Merge branch 'TacoTheDank-master' Diffstat:
37 files changed, 292 insertions(+), 328 deletions(-)
diff --git a/.gitignore b/.gitignore @@ -1,9 +1,12 @@ *.iml .gradle /local.properties -/.idea/workspace.xml -/.idea/libraries -.DS_Store /build -/captures -.externalNativeBuild +.idea/caches/ +.idea/codeStyles/ +.idea/dbnavigator.xml +.idea/libraries/ +.idea/markdown-navigator.xml +.idea/markdown-navigator/ +.idea/modules.xml +.idea/workspace.xml diff --git a/.idea/misc.xml b/.idea/misc.xml @@ -24,7 +24,7 @@ </value> </option> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/build/classes" /> </component> <component name="ProjectType"> diff --git a/.idea/modules.xml b/.idea/modules.xml @@ -2,8 +2,8 @@ <project version="4"> <component name="ProjectModuleManager"> <modules> - <module fileurl="file://$PROJECT_DIR$/Cythara.iml" filepath="$PROJECT_DIR$/Cythara.iml" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> + <module fileurl="file://$PROJECT_DIR$/cythara.iml" filepath="$PROJECT_DIR$/cythara.iml" /> </modules> </component> </project> \ No newline at end of file diff --git a/.travis.yml b/.travis.yml @@ -5,16 +5,17 @@ android: - tools - platform-tools - tools - - build-tools-27.0.3 - - android-26 + - build-tools-28.0.2 + - android-28 - extra-android-support before_install: - mkdir "$ANDROID_HOME/licenses" || true - - echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license" + - echo -e "8933bad161af4178b1185d1a37fbf41ea5269c55\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license" script: ./gradlew test licenses: - android-sdk-license-.+ + - android-sdk-preview-license-.+ - '.+' +notifications: + email: false diff --git a/app/build.gradle b/app/build.gradle @@ -3,41 +3,49 @@ apply plugin: 'com.android.application' apply plugin: 'findbugs' android { - compileSdkVersion 26 - buildToolsVersion '27.0.3' + compileSdkVersion 28 + buildToolsVersion '28.0.2' defaultConfig { applicationId "com.github.cythara" minSdkVersion 15 - targetSdkVersion 26 + targetSdkVersion 28 versionCode 18 versionName "2.7" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + lintOptions { disable 'GoogleAppIndexingWarning', 'IconLocation' } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - androidTestImplementation('com.android.support.test:runner:1.0.0', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - androidTestImplementation('com.android.support.test:rules:1.0.0', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - implementation 'com.android.support:appcompat-v7:26.1.0' - implementation 'com.jaredrummler:material-spinner:1.2.1' - implementation 'com.shawnlin:number-picker:2.4.5' + androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.2', { + exclude group: 'com.android.support', module: 'support-annotations' }) + + androidTestImplementation('com.android.support.test:runner:1.0.2', { + exclude group: 'com.android.support', module: 'support-annotations' }) + + androidTestImplementation('com.android.support.test:rules:1.0.2', { + exclude group: 'com.android.support', module: 'support-annotations' }) + + implementation 'com.android.support:appcompat-v7:28.0.0-rc01' + implementation 'com.jaredrummler:material-spinner:1.2.5' + implementation 'com.shawnlin:number-picker:2.4.6' + testImplementation 'junit:junit:4.12' testImplementation group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3' - testImplementation group: 'org.robolectric', name: 'robolectric', version: '3.3.2' + testImplementation group: 'org.robolectric', name: 'robolectric', version: '3.8' //4.0-alpha-3 } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.github.cythara"> + package="com.github.cythara" + android:installLocation="auto"> <uses-permission android:name="android.permission.RECORD_AUDIO" /> diff --git a/app/src/main/java/be/tarsos/dsp/AudioEvent.java b/app/src/main/java/be/tarsos/dsp/AudioEvent.java @@ -184,10 +184,10 @@ public class AudioEvent { */ public static double calculateRMS(float[] floatBuffer){ double rms = 0.0; - for (int i = 0; i < floatBuffer.length; i++) { - rms += floatBuffer[i] * floatBuffer[i]; + for (float aFloatBuffer : floatBuffer) { + rms += aFloatBuffer * aFloatBuffer; } - rms = rms / Double.valueOf(floatBuffer.length); + rms = rms / (double) floatBuffer.length; rms = Math.sqrt(rms); return rms; } diff --git a/app/src/main/java/be/tarsos/dsp/AudioGenerator.java b/app/src/main/java/be/tarsos/dsp/AudioGenerator.java @@ -99,8 +99,8 @@ public class AudioGenerator implements Runnable { } public AudioGenerator(final int audioBufferSize, final int bufferOverlap,final int samplerate){ - - audioProcessors = new CopyOnWriteArrayList<AudioProcessor>(); + + audioProcessors = new CopyOnWriteArrayList<>(); format = getTargetAudioFormat(samplerate); @@ -126,12 +126,12 @@ public class AudioGenerator implements Runnable { * @return The audio format after conversion. */ private TarsosDSPAudioFormat getTargetAudioFormat(int targetSampleRate) { - TarsosDSPAudioFormat audioFormat = new TarsosDSPAudioFormat(TarsosDSPAudioFormat.Encoding.PCM_SIGNED, - targetSampleRate, - 2 * 8, - 1, - 2 * 1, - targetSampleRate, + TarsosDSPAudioFormat audioFormat = new TarsosDSPAudioFormat(TarsosDSPAudioFormat.Encoding.PCM_SIGNED, + targetSampleRate, + 2 * 8, + 1, + 2, + targetSampleRate, ByteOrder.BIG_ENDIAN.equals(ByteOrder.nativeOrder())); return audioFormat; } diff --git a/app/src/main/java/be/tarsos/dsp/AutoCorrelation.java b/app/src/main/java/be/tarsos/dsp/AutoCorrelation.java @@ -36,8 +36,8 @@ public class AutoCorrelation implements AudioProcessor { result = 0; - for (int i=0; i<audioFloatbuffer.length; i++){ - result += ((float)Math.abs(audioFloatbuffer[i]))/(float)audioFloatbuffer.length; + for (float anAudioFloatbuffer : audioFloatbuffer) { + result += Math.abs(anAudioFloatbuffer) / (float) audioFloatbuffer.length; } return true; } diff --git a/app/src/main/java/be/tarsos/dsp/ConstantQ.java b/app/src/main/java/be/tarsos/dsp/ConstantQ.java @@ -214,8 +214,8 @@ public class ConstantQ implements AudioProcessor { int len = (int)Math.min(Math.ceil( q * sampleRate / frequencies[i]), fftLength); for (int j = 0; j < len; j++) { - - double window = -.5*Math.cos(2.*Math.PI*(double)j/(double)len)+.5;; // Hanning Window + + double window = -.5 * Math.cos(2. * Math.PI * (double) j / (double) len) + .5;// Hanning Window // double window = -.46*Math.cos(2.*Math.PI*(double)j/(double)len)+.54; // Hamming Window window /= len; @@ -252,10 +252,8 @@ public class ConstantQ implements AudioProcessor { sKernel = new float[k * 2]; int[] indexes = new int[k]; - for (int j = 0; j < k * 2; j++) - sKernel[j] = cKernel[j]; - for (int j = 0; j < k; j++) - indexes[j] = cindexes[j]; + System.arraycopy(cKernel, 0, sKernel, 0, k * 2); + System.arraycopy(cindexes, 0, indexes, 0, k); // Normalize fft output for (int j = 0; j < sKernel.length; j++) diff --git a/app/src/main/java/be/tarsos/dsp/FadeOut.java b/app/src/main/java/be/tarsos/dsp/FadeOut.java @@ -1,9 +1,5 @@ package be.tarsos.dsp; -import be.tarsos.dsp.AudioEvent; -import be.tarsos.dsp.AudioProcessor; -import be.tarsos.dsp.GainProcessor; - public class FadeOut implements AudioProcessor { // VARIABLES @@ -31,7 +27,7 @@ public class FadeOut implements AudioProcessor public boolean process(AudioEvent audioEvent) { // Don't do anything before the beginning of Fade Out - if(isFadeOut==true) + if (isFadeOut) { if(firstTime==-1) firstTime=audioEvent.getTimeStamp(); diff --git a/app/src/main/java/be/tarsos/dsp/SilenceDetector.java b/app/src/main/java/be/tarsos/dsp/SilenceDetector.java @@ -124,13 +124,9 @@ public class SilenceDetector implements AudioProcessor { public boolean process(AudioEvent audioEvent) { boolean isSilence = isSilence(audioEvent.getFloatBuffer()); //break processing chain on silence? - if(breakProcessingQueueOnSilence){ - //break if silent - return !isSilence; - }else{ - //never break the chain - return true; - } + //break if silent + return !breakProcessingQueueOnSilence || !isSilence; +//never break the chain } diff --git a/app/src/main/java/be/tarsos/dsp/SpectralPeakProcessor.java b/app/src/main/java/be/tarsos/dsp/SpectralPeakProcessor.java @@ -124,11 +124,11 @@ public class SpectralPeakProcessor implements AudioProcessor { frequencyEstimates = new float[bufferSize / 2]; dt = (bufferSize - overlap) / (double) sampleRate; - cbin = (double) (dt * sampleRate / (double) bufferSize); + cbin = dt * sampleRate / (double) bufferSize; - inv_2pi = (double) (1.0 / (2.0 * Math.PI)); - inv_deltat = (double) (1.0 / dt); - inv_2pideltat = (double) (inv_deltat * inv_2pi); + inv_2pi = 1.0 / (2.0 * Math.PI); + inv_deltat = 1.0 / dt; + inv_2pideltat = inv_deltat * inv_2pi; this.sampleRate = sampleRate; @@ -140,18 +140,49 @@ public class SpectralPeakProcessor implements AudioProcessor { // Extract the power and phase data fft.powerPhaseFFT(fftData, magnitudes, currentPhaseOffsets); } - - private void normalizeMagintudes(){ - float maxMagnitude = (float) -1e6; - for(int i = 0;i<magnitudes.length;i++){ - maxMagnitude = Math.max(maxMagnitude, magnitudes[i]); - } - - //log10 of the normalized value - //adding 75 makes sure the value is above zero, a bit ugly though... - for(int i = 1;i<magnitudes.length;i++){ - magnitudes[i] = (float) (10 * Math.log10(magnitudes[i]/maxMagnitude)) + 75; - } + + /** + * Calculate a noise floor for an array of magnitudes. + * + * @param magnitudes The magnitudes of the current frame. + * @param medianFilterLength The length of the median filter used to determine the noise floor. + * @param noiseFloorFactor The noise floor is multiplied with this factor to determine if the + * information is either noise or an interesting spectral peak. + * @return a float array representing the noise floor. + */ + public static float[] calculateNoiseFloor(float[] magnitudes, int medianFilterLength, float noiseFloorFactor) { + double[] noiseFloorBuffer; + float[] noisefloor = new float[magnitudes.length]; + + float median = (float) median(magnitudes.clone()); + + // Naive median filter implementation. + // For each element take a median of surrounding values (noiseFloorBuffer) + // Store the median as the noise floor. + for (int i = 0; i < magnitudes.length; i++) { + noiseFloorBuffer = new double[medianFilterLength]; + int index = 0; + for (int j = i - medianFilterLength / 2; j <= i + medianFilterLength / 2 && index < noiseFloorBuffer.length; j++) { + if (j >= 0 && j < magnitudes.length) { + noiseFloorBuffer[index] = magnitudes[j]; + } else { + noiseFloorBuffer[index] = median; + } + index++; + } + // calculate the noise floor value. + noisefloor[i] = median(noiseFloorBuffer) * (noiseFloorFactor); + } + + float rampLength = 12.0f; + for (int i = 0; i <= rampLength; i++) { + //ramp + float ramp = 1.0f; + ramp = (float) (-1 * (Math.log(i / rampLength))) + 1.0f; + noisefloor[i] = ramp * noisefloor[i]; + } + + return noisefloor; } @Override @@ -223,51 +254,21 @@ public class SpectralPeakProcessor implements AudioProcessor { frequencyInHertz = (float) (inv_2pideltat * phaseDelta + inv_deltat * k); } else { frequencyInHertz = (float) fft.binToHz(binIndex, sampleRate); + } + return frequencyInHertz; + } + + private void normalizeMagintudes() { + float maxMagnitude = (float) -1e6; + for (float magnitude : magnitudes) { + maxMagnitude = Math.max(maxMagnitude, magnitude); + } + + //log10 of the normalized value + //adding 75 makes sure the value is above zero, a bit ugly though... + for (int i = 1; i < magnitudes.length; i++) { + magnitudes[i] = (float) (10 * Math.log10(magnitudes[i]/maxMagnitude)) + 75; } - return frequencyInHertz; - } - - /** - * Calculate a noise floor for an array of magnitudes. - * @param magnitudes The magnitudes of the current frame. - * @param medianFilterLength The length of the median filter used to determine the noise floor. - * @param noiseFloorFactor The noise floor is multiplied with this factor to determine if the - * information is either noise or an interesting spectral peak. - * @return a float array representing the noise floor. - */ - public static float[] calculateNoiseFloor(float[] magnitudes, int medianFilterLength, float noiseFloorFactor) { - double[] noiseFloorBuffer; - float[] noisefloor = new float[magnitudes.length]; - - float median = (float) median(magnitudes.clone()); - - // Naive median filter implementation. - // For each element take a median of surrounding values (noiseFloorBuffer) - // Store the median as the noise floor. - for (int i = 0; i < magnitudes.length; i++) { - noiseFloorBuffer = new double[medianFilterLength]; - int index = 0; - for (int j = i - medianFilterLength/2; j <= i + medianFilterLength/2 && index < noiseFloorBuffer.length; j++) { - if(j >= 0 && j < magnitudes.length){ - noiseFloorBuffer[index] = magnitudes[j]; - } else{ - noiseFloorBuffer[index] = median; - } - index++; - } - // calculate the noise floor value. - noisefloor[i] = (float) (median(noiseFloorBuffer) * (noiseFloorFactor)) ; - } - - float rampLength = 12.0f; - for(int i = 0 ; i <= rampLength ; i++){ - //ramp - float ramp = 1.0f; - ramp = (float) (-1 * (Math.log(i/rampLength))) + 1.0f; - noisefloor[i] = ramp * noisefloor[i]; - } - - return noisefloor; } /** @@ -419,8 +420,7 @@ public class SpectralPeakProcessor implements AudioProcessor { return (m[middle-1] + m[middle]) / 2.0; } } - - + public static class SpectralPeak{ private final float frequencyInHertz; private final float magnitude; @@ -473,6 +473,4 @@ public class SpectralPeakProcessor implements AudioProcessor { return bin; } } - - } diff --git a/app/src/main/java/be/tarsos/dsp/WaveformSimilarityBasedOverlapAdd.java b/app/src/main/java/be/tarsos/dsp/WaveformSimilarityBasedOverlapAdd.java @@ -136,10 +136,10 @@ public class WaveformSimilarityBasedOverlapAdd implements AudioProcessor { * @param output The output buffer. * @param input The input buffer. */ - private void overlap(final float[] output, int outputOffset, float[] input,int inputOffset){ + private void overlap(final float[] output, float[] input, int inputOffset) { for(int i = 0 ; i < overlapLength ; i++){ int itemp = overlapLength - i; - output[i + outputOffset] = (input[i + inputOffset] * i + pMidBuffer[i] * itemp ) / overlapLength; + output[i + 0] = (input[i + inputOffset] * i + pMidBuffer[i] * itemp) / overlapLength; } } @@ -152,10 +152,9 @@ public class WaveformSimilarityBasedOverlapAdd implements AudioProcessor { * cross-correlation value over the overlapping period * * @param inputBuffer The input buffer - * @param postion The position where to start the seek operation, in the input buffer. * @return The best position. */ - private int seekBestOverlapPosition(float[] inputBuffer, int postion) { + private int seekBestOverlapPosition(float[] inputBuffer) { int bestOffset; double bestCorrelation, currentCorrelation; int tempOffset; @@ -173,12 +172,12 @@ public class WaveformSimilarityBasedOverlapAdd implements AudioProcessor { // over the permitted range. for (tempOffset = 0; tempOffset < seekLength; tempOffset++) { - comparePosition = postion + tempOffset; + comparePosition = tempOffset; // Calculates correlation value for the mixing position // corresponding // to 'tempOffset' - currentCorrelation = (double) calcCrossCorr(pRefMidBuffer, inputBuffer,comparePosition); + currentCorrelation = calcCrossCorr(pRefMidBuffer, inputBuffer, comparePosition); // heuristic rule to slightly favor values close to mid of the // range double tmp = (double) (2 * tempOffset - seekLength) / seekLength; @@ -229,13 +228,13 @@ public class WaveformSimilarityBasedOverlapAdd implements AudioProcessor { assert audioFloatBuffer.length == getInputBufferSize(); //Search for the best overlapping position. - int offset = seekBestOverlapPosition(audioFloatBuffer,0); + int offset = seekBestOverlapPosition(audioFloatBuffer); // Mix the samples in the 'inputBuffer' at position of 'offset' with the // samples in 'midBuffer' using sliding overlapping // ... first partially overlap with the end of the previous sequence // (that's in 'midBuffer') - overlap(outputFloatBuffer,0,audioFloatBuffer,offset); + overlap(outputFloatBuffer, audioFloatBuffer, offset); //copy sequence samples from input to output int sequenceLength = seekWindowLength - 2 * overlapLength; diff --git a/app/src/main/java/be/tarsos/dsp/beatroot/Agent.java b/app/src/main/java/be/tarsos/dsp/beatroot/Agent.java @@ -61,18 +61,18 @@ public class Agent { /** The maximum amount by which a beat can be earlier than the predicted beat time, * expressed as a fraction of the beat period. */ public static double PRE_MARGIN_FACTOR = 0.15; - - /** The default value of innerMargin, which is the maximum time (in seconds) that a + + /** The default value of innerMargin, which is the maximum time (in seconds) that a * beat can deviate from the predicted beat time without a fork occurring. */ public static final double INNER_MARGIN = 0.040; - - /** The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period. */ + + /** The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period. */ public static double MAX_CHANGE = 0.2; - - /** The slope of the penalty function for onsets which do not coincide precisely with predicted beat times. */ + + /** The slope of the penalty function for onsets which do not coincide precisely with predicted beat times. */ public static double CONF_FACTOR = 0.5; - - /** The reactiveness/inertia balance, i.e. degree of change in the tempo, is controlled by the correctionFactor + + /** The reactiveness/inertia balance, i.e. degree of change in the tempo, is controlled by the correctionFactor * variable. This constant defines its default value, which currently is not subsequently changed. The * beat period is updated by the reciprocal of the correctionFactor multiplied by the difference between the * predicted beat time and matching onset. */ diff --git a/app/src/main/java/be/tarsos/dsp/beatroot/AgentList.java b/app/src/main/java/be/tarsos/dsp/beatroot/AgentList.java @@ -53,11 +53,11 @@ public class AgentList { /** Flag for choice between sum and average beat salience values for Agent scores. * The use of summed saliences favours faster tempi or lower metrical levels. */ public static boolean useAverageSalience = false; - - /** Flag for printing debugging output. */ + + /** Flag for printing debugging output. */ public static boolean debug = false; - - /** For the purpose of removing duplicate agents, the default JND of IBI */ + + /** For the purpose of removing duplicate agents, the default JND of IBI */ public static final double DEFAULT_BI = 0.02; /** For the purpose of removing duplicate agents, the default JND of phase */ diff --git a/app/src/main/java/be/tarsos/dsp/beatroot/BeatRootOnsetEventHandler.java b/app/src/main/java/be/tarsos/dsp/beatroot/BeatRootOnsetEventHandler.java @@ -47,9 +47,9 @@ public class BeatRootOnsetEventHandler implements OnsetHandler { e.salience = salience; onsetList.add(e); } - - - /** + + + /** * Creates a new Event object representing an onset or beat. * * @param time @@ -70,7 +70,7 @@ public class BeatRootOnsetEventHandler implements OnsetHandler { * the beat is not calculated: -1 is returned. */ public void trackBeats(OnsetHandler beatHandler){ - AgentList agents = null; + AgentList agents = null; // tempo not given; use tempo induction agents = Induction.beatInduction(onsetList); agents.beatTrack(onsetList, -1); diff --git a/app/src/main/java/be/tarsos/dsp/util/AudioResourceUtils.java b/app/src/main/java/be/tarsos/dsp/util/AudioResourceUtils.java @@ -152,7 +152,7 @@ public class AudioResourceUtils { * @return The contents of the file. */ public static String readTextFromUrl(URL url) { - StringBuffer fubber = new StringBuffer(); + StringBuilder fubber = new StringBuilder(); try { BufferedReader in = new BufferedReader(new InputStreamReader( url.openStream())); @@ -166,5 +166,4 @@ public class AudioResourceUtils { } return fubber.toString(); } - } diff --git a/app/src/main/java/be/tarsos/dsp/util/ConcurrencyUtils.java b/app/src/main/java/be/tarsos/dsp/util/ConcurrencyUtils.java @@ -57,6 +57,8 @@ * ***** END LICENSE BLOCK ***** */ package be.tarsos.dsp.util; +import android.support.annotation.NonNull; + import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -95,21 +97,15 @@ public class ConcurrencyUtils { } - private static class CustomThreadFactory implements ThreadFactory { - private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); - - private final Thread.UncaughtExceptionHandler handler; - - CustomThreadFactory(Thread.UncaughtExceptionHandler handler) { - this.handler = handler; - } - - public Thread newThread(Runnable r) { - Thread t = defaultFactory.newThread(r); - t.setUncaughtExceptionHandler(handler); - return t; - } - }; + /** + * Checks if x is a power-of-two number. + * + * @param x + * @return true if x is a power-of-two number + */ + public static boolean isPowerOf2(int x) { + return x > 0 && (x & (x - 1)) == 0; + } /** * Returns the number of available processors. @@ -273,17 +269,20 @@ public class ConcurrencyUtils { return (int) Math.pow(2, Math.floor(Math.log(x) / Math.log(2))); } - /** - * Checks if x is a power-of-two number. - * - * @param x - * @return true if x is a power-of-two number - */ - public static boolean isPowerOf2(int x) { - if (x <= 0) - return false; - else - return (x & (x - 1)) == 0; + private static class CustomThreadFactory implements ThreadFactory { + private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); + + private final Thread.UncaughtExceptionHandler handler; + + CustomThreadFactory(Thread.UncaughtExceptionHandler handler) { + this.handler = handler; + } + + public Thread newThread(@NonNull Runnable r) { + Thread t = defaultFactory.newThread(r); + t.setUncaughtExceptionHandler(handler); + return t; + } } /** diff --git a/app/src/main/java/be/tarsos/dsp/util/CubicSplineFast.java b/app/src/main/java/be/tarsos/dsp/util/CubicSplineFast.java @@ -69,9 +69,9 @@ package be.tarsos.dsp.util; public class CubicSplineFast{ private int nPoints = 0; // no. of tabulated points - private double[] y = null; // y=f(x) tabulated function - private double[] x = null; // x in tabulated function f(x) - private double[] d2ydx2 = null; // second derivatives of y + private double[] y; // y=f(x) tabulated function + private double[] x; // x in tabulated function f(x) + private double[] d2ydx2; // second derivatives of y // Constructors // Constructor with data arrays initialised to arrays x and y @@ -110,8 +110,7 @@ public class CubicSplineFast{ // Primarily for use in BiCubicSplineFast public static CubicSplineFast zero(int n){ if(n<3)throw new IllegalArgumentException("A minimum of three data points is needed"); - CubicSplineFast aa = new CubicSplineFast(n); - return aa; + return new CubicSplineFast(n); } // Create a one dimensional array of cubic spline objects of length n each of array length m @@ -129,7 +128,7 @@ public class CubicSplineFast{ // for use by the cubic spline interpolation method (.interpolate) // This method follows the procedure in Numerical Methods C language procedure for calculating second derivatives public void calcDeriv(){ - double p=0.0D,qn=0.0D,sig=0.0D,un=0.0D; + double p, qn, sig, un; double[] u = new double[nPoints]; d2ydx2[0]=u[0]=0.0; @@ -155,8 +154,8 @@ public class CubicSplineFast{ // then stored for use on all subsequent calls public double interpolate(double xx){ - double h=0.0D,b=0.0D,a=0.0D, yy=0.0D; - int k=0; + double h, b, a, yy; + int k; int klo=0; int khi=this.nPoints-1; while (khi-klo > 1){ diff --git a/app/src/main/java/be/tarsos/dsp/util/FFMPEGDownloader.java b/app/src/main/java/be/tarsos/dsp/util/FFMPEGDownloader.java @@ -84,9 +84,9 @@ public class FFMPEGDownloader { String operatingSystem = System.getProperty("os.name").toLowerCase(); if(operatingSystem.indexOf("indows") > 0 ){ name = "windows"; - }else if(operatingSystem.indexOf("nux") >= 0){ + } else if (operatingSystem.contains("nux")) { name="linux"; - }else if(operatingSystem.indexOf("mac") >= 0){ + } else if (operatingSystem.contains("mac")) { name="mac_os_x"; }else{ name = null; @@ -95,11 +95,11 @@ public class FFMPEGDownloader { } private String processorArchitecture(){ - boolean is64bit = false; + boolean is64bit; if (System.getProperty("os.name").contains("Windows")) { is64bit = (System.getenv("ProgramFiles(x86)") != null); } else { - is64bit = (System.getProperty("os.arch").indexOf("64") != -1); + is64bit = (System.getProperty("os.arch").contains("64")); } if(is64bit){ return "64_bits"; diff --git a/app/src/main/java/be/tarsos/dsp/util/PeakPicker.java b/app/src/main/java/be/tarsos/dsp/util/PeakPicker.java @@ -99,8 +99,8 @@ public class PeakPicker { * @return True if a peak is detected, false otherwise. **/ public boolean pickPeak(float onset) { - float mean = 0.f; - float median = 0.f; + float mean; + float median; int length = win_post + win_pre + 1; @@ -116,7 +116,7 @@ public class PeakPicker { onset_proc[length-1] = onset; /* filter onset_proc */ - /** \bug filtfilt calculated post+pre times, should be only once !? */ + /* \bug filtfilt calculated post+pre times, should be only once !? */ biquad.doFiltering(onset_proc,scratch); /* calculate mean and median for onset_proc */ @@ -129,16 +129,14 @@ public class PeakPicker { } Arrays.sort(scratch); median = scratch[scratch.length/2]; - mean = sum/Float.valueOf(length); + mean = sum / (float) length; /* shift peek array */ - for (int j=0;j<3-1;j++){ - onset_peek[j] = onset_peek[j+1]; - } + System.arraycopy(onset_peek, 1, onset_peek, 0, 3 - 1); /* calculate new peek value */ onset_peek[2] = (float) (onset_proc[win_post] - median - mean * threshold); - - boolean isPeak = isPeak(1); + + boolean isPeak = isPeak(); lastPeekValue = onset; return isPeak; @@ -155,13 +153,11 @@ public class PeakPicker { /** * Returns true if the onset is a peak. * - * @param index - * the index in onset_peak to check. * @return True if the onset is a peak, false otherwise. */ - private boolean isPeak(int index) { - return ( onset_peek[index] > onset_peek[index - 1] && - onset_peek[index] > onset_peek[index + 1] && - onset_peek[index] > 0.); + private boolean isPeak() { + return (onset_peek[1] > onset_peek[0] && + onset_peek[1] > onset_peek[1 + 1] && + onset_peek[1] > 0.); } } diff --git a/app/src/main/java/be/tarsos/dsp/util/PitchConverter.java b/app/src/main/java/be/tarsos/dsp/util/PitchConverter.java @@ -109,10 +109,10 @@ public final class PitchConverter { return absoluteCentValue % 1200.0; } - /** - * This method is not really practical. Maybe I will need it someday. - * - * @param relativeCent + /* + This method is not really practical. Maybe I will need it someday. + + @param relativeCent * @return public static double relativeCentToHertz(double relativeCent){ if * (relativeCent < 0 || relativeCent >= 1200) throw new * IllegalArgumentException diff --git a/app/src/main/java/be/tarsos/dsp/wavelet/HaarWaveletDecoder.java b/app/src/main/java/be/tarsos/dsp/wavelet/HaarWaveletDecoder.java @@ -43,7 +43,5 @@ public class HaarWaveletDecoder implements AudioProcessor{ @Override public void processingFinished() { - } - } diff --git a/app/src/main/java/be/tarsos/dsp/wavelet/HaarWaveletTransform.java b/app/src/main/java/be/tarsos/dsp/wavelet/HaarWaveletTransform.java @@ -111,10 +111,7 @@ public class HaarWaveletTransform { if (number <= 0) { throw new IllegalArgumentException("number: " + number); } - if ((number & -number) == number) { - return true; - } - return false; + return (number & -number) == number; } /** diff --git a/app/src/main/java/be/tarsos/dsp/writer/WaveHeader.java b/app/src/main/java/be/tarsos/dsp/writer/WaveHeader.java @@ -5,9 +5,6 @@ import java.io.InputStream; import java.io.OutputStream; /** - * this source code is copied from : https://android.googlesource.com/platform/frameworks/base.git/+/android-4.3_r2/core/java/android/speech/srec/WaveHeader.java - */ -/** * This class represents the header of a WAVE format audio file, which usually * have a .wav suffix. The following integer valued fields are contained: * <ul> @@ -240,14 +237,14 @@ public class WaveHeader { } private static void writeInt(OutputStream out, int val) throws IOException { - out.write(val >> 0); + out.write(val); out.write(val >> 8); out.write(val >> 16); out.write(val >> 24); } private static void writeShort(OutputStream out, short val) throws IOException { - out.write(val >> 0); + out.write(val); out.write(val >> 8); } diff --git a/app/src/main/java/be/tarsos/dsp/writer/WriterProcessor.java b/app/src/main/java/be/tarsos/dsp/writer/WriterProcessor.java @@ -1,6 +1,5 @@ package be.tarsos.dsp.writer; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.RandomAccessFile; diff --git a/app/src/main/java/com/github/cythara/CanvasPainter.java b/app/src/main/java/com/github/cythara/CanvasPainter.java @@ -12,6 +12,7 @@ import android.support.v4.content.ContextCompat; import android.text.TextPaint; import java.util.Locale; +import java.util.Objects; import static android.content.Context.MODE_PRIVATE; import static com.github.cythara.ListenerFragment.IS_RECORDING; @@ -181,7 +182,7 @@ class CanvasPainter { int x = (int) (canvas.getWidth() / 2F); int y = (int) (canvas.getHeight() - canvas.getHeight() / 3F); - int width = drawable.getIntrinsicWidth() * 2; + int width = Objects.requireNonNull(drawable).getIntrinsicWidth() * 2; int height = drawable.getIntrinsicHeight() * 2; drawable.setBounds(x - width / 2, y, x + width / 2, y + height); diff --git a/app/src/main/java/com/github/cythara/ListenerFragment.java b/app/src/main/java/com/github/cythara/ListenerFragment.java @@ -11,14 +11,12 @@ import java.util.ArrayList; import java.util.List; import be.tarsos.dsp.AudioDispatcher; -import be.tarsos.dsp.AudioEvent; import be.tarsos.dsp.pitch.PitchDetectionHandler; -import be.tarsos.dsp.pitch.PitchDetectionResult; import be.tarsos.dsp.pitch.PitchProcessor; import static be.tarsos.dsp.io.android.AudioDispatcherFactory.fromDefaultMicrophone; import static be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm.FFT_YIN; -import static com.github.cythara.PitchComparator.*; +import static com.github.cythara.PitchComparator.retrieveNote; public class ListenerFragment extends Fragment { @@ -97,37 +95,33 @@ public class ListenerFragment extends Fragment { @Override protected Void doInBackground(Void... params) { - PitchDetectionHandler pitchDetectionHandler = new PitchDetectionHandler() { - @Override - public void handlePitch(PitchDetectionResult pitchDetectionResult, - AudioEvent audioEvent) { - - if (isCancelled()) { - stopAudioDispatcher(); - return; - } + PitchDetectionHandler pitchDetectionHandler = (pitchDetectionResult, audioEvent) -> { - if (!IS_RECORDING) { - IS_RECORDING = true; - publishProgress(); - } + if (isCancelled()) { + stopAudioDispatcher(); + return; + } + + if (!IS_RECORDING) { + IS_RECORDING = true; + publishProgress(); + } - float pitch = pitchDetectionResult.getPitch(); + float pitch = pitchDetectionResult.getPitch(); - if (pitch != -1) { - float adjustedPitch = MainActivity.adjustPitch(pitch); - PitchDifference pitchDifference = retrieveNote(adjustedPitch); + if (pitch != -1) { + float adjustedPitch = MainActivity.adjustPitch(pitch); + PitchDifference pitchDifference = retrieveNote(adjustedPitch); - pitchDifferences.add(pitchDifference); + pitchDifferences.add(pitchDifference); - if (pitchDifferences.size() >= MIN_ITEMS_COUNT) { - PitchDifference average = - Sampler.calculateAverageDifference(pitchDifferences); + if (pitchDifferences.size() >= MIN_ITEMS_COUNT) { + PitchDifference average = + Sampler.calculateAverageDifference(pitchDifferences); - publishProgress(average); + publishProgress(average); - pitchDifferences.clear(); - } + pitchDifferences.clear(); } } }; diff --git a/app/src/main/java/com/github/cythara/MainActivity.java b/app/src/main/java/com/github/cythara/MainActivity.java @@ -3,7 +3,6 @@ package com.github.cythara; import android.Manifest; import android.app.AlertDialog; import android.app.FragmentManager; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -111,18 +110,15 @@ public class MainActivity extends AppCompatActivity implements ListenerFragment. R.style.AppTheme)); builder.setTitle(R.string.choose_notation); builder.setSingleChoiceItems(R.array.notations, checkedItem, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean(USE_SCIENTIFIC_NOTATION, which == 0); - editor.apply(); + (dialog, which) -> { + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(USE_SCIENTIFIC_NOTATION, which == 0); + editor.apply(); - dialog.dismiss(); + dialog.dismiss(); - TunerView tunerView = findViewById(R.id.pitch); - tunerView.invalidate(); - } + TunerView tunerView = findViewById(R.id.pitch); + tunerView.invalidate(); }); builder.show(); @@ -188,14 +184,12 @@ public class MainActivity extends AppCompatActivity implements ListenerFragment. alertDialog.setTitle(R.string.permission_required); alertDialog.setMessage("Microphone permission is required. App will be closed"); alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - finishAffinity(); - } else { - finish(); - } + (dialog, which) -> { + dialog.dismiss(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + finishAffinity(); + } else { + finish(); } }); alertDialog.show(); diff --git a/app/src/main/java/com/github/cythara/NumberPickerDialog.java b/app/src/main/java/com/github/cythara/NumberPickerDialog.java @@ -4,7 +4,6 @@ package com.github.cythara; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; -import android.content.DialogInterface; import android.os.Bundle; import android.view.ContextThemeWrapper; @@ -36,17 +35,10 @@ public class NumberPickerDialog extends DialogFragment { R.style.AppTheme)); builder.setMessage(R.string.choose_a_frequency); - builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - valueChangeListener.onValueChange(numberPicker, - numberPicker.getValue(), numberPicker.getValue()); - } - }); + builder.setPositiveButton("OK", (dialog, which) -> valueChangeListener.onValueChange(numberPicker, + numberPicker.getValue(), numberPicker.getValue())); - builder.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { } + builder.setNegativeButton("CANCEL", (dialog, which) -> { }); builder.setView(numberPicker); diff --git a/app/src/main/java/com/github/cythara/PitchComparator.java b/app/src/main/java/com/github/cythara/PitchComparator.java @@ -1,7 +1,6 @@ package com.github.cythara; import java.util.Arrays; -import java.util.Comparator; class PitchComparator { @@ -9,12 +8,7 @@ class PitchComparator { Tuning tuning = MainActivity.getCurrentTuning(); Note[] notes = tuning.getNotes(); - Arrays.sort(notes, new Comparator<Note>() { - @Override - public int compare(Note o1, Note o2) { - return Float.compare(o1.getFrequency(), o2.getFrequency()); - } - }); + Arrays.sort(notes, (o1, o2) -> Float.compare(o1.getFrequency(), o2.getFrequency())); double minCentDifference = Float.POSITIVE_INFINITY; Note closest = notes[0]; diff --git a/build.gradle b/build.gradle @@ -5,8 +5,9 @@ buildscript { jcenter() google() } + dependencies { - classpath 'com.android.tools.build:gradle:3.1.2' + classpath 'com.android.tools.build:gradle:3.1.4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -16,9 +17,8 @@ buildscript { allprojects { repositories { jcenter() - maven { - url "https://maven.google.com" - } + google() + maven { url "https://maven.google.com" } } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar Binary files differ. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sat Mar 31 10:31:38 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/gradlew b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line