00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package com.meapsoft;
00024
00025
00026
00035 public class BeatOnsetDetector extends OnsetDetector {
00036
00037 double bpmMin = 60;
00038 double bpmMax = 150;
00039 int minDelay = 10;
00040
00041 double entThresh = 10;
00042
00043 double framesPerSecond;
00044 double[] real, imag;
00045 FFT fft;
00046 long nextOnset;
00047 int zeroFrames;
00048
00049 public BeatOnsetDetector(STFT stft, double bandThresh, double bandFrac) {
00050 super(stft, bandThresh, bandFrac);
00051
00052
00053
00054
00055 real = new double[onsets.length];
00056 imag = new double[onsets.length];
00057 fft = new FFT(onsets.length);
00058
00059 zeroFrames = 0;
00060 nextOnset = 256;
00061 }
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 public void checkOnsets(long lastSeen, long newestFrame) {
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 if(nextOnset > lastSeen && nextOnset <= newestFrame) {
00086
00087
00088
00089 notifyListeners(nextOnset, zeroFrames);
00090
00091 } else if(nextOnset > newestFrame) {
00092
00093
00094 } else if(nextOnset <= lastSeen) {
00095
00096
00097
00098 for(int i=0; i<onsets.length; i++) {
00099 real[i] = onsets[(int)((newestFrame+1+i) % onsets.length)];
00100 imag[i] = 0;
00101 }
00102
00103 fft.fft(real, imag);
00104
00105 double maxMag = 0, mag, meanMag = 0;
00106 int argMaxMag = 0;
00107
00108
00109 for(int i=1; i<real.length/2; i++) {
00110 mag = real[i]*real[i] + imag[i]*imag[i];
00111 meanMag += mag;
00112 if(mag > maxMag) {
00113 maxMag = mag;
00114 argMaxMag = i;
00115 }
00116 }
00117 meanMag /= real.length/2.0 - 1;
00118
00119
00120
00121
00122 double magP = real[argMaxMag+1]*real[argMaxMag+1]
00123 + imag[argMaxMag+1]*imag[argMaxMag+1];
00124 double mag0 = real[argMaxMag]*real[argMaxMag]
00125 + imag[argMaxMag]*imag[argMaxMag];
00126 double magN = real[argMaxMag-1]*real[argMaxMag-1]
00127 + imag[argMaxMag-1]*imag[argMaxMag-1];
00128 double rem = -(magP - magN) / (magP - 2.0*mag0 + magN);
00129
00130
00131 int period = (int)((double)real.length / (rem + argMaxMag));
00132 double angle = Math.atan2(imag[argMaxMag], real[argMaxMag]);
00133
00134 int delay = (int)(-angle * period/(2*Math.PI));
00135 delay = (delay+period) % period;
00136 if(delay < minDelay)
00137 delay = delay + period;
00138
00139
00140
00141
00142 nextOnset = newestFrame + delay;
00143
00144
00145
00146
00147
00148
00149 if(maxMag < entThresh*meanMag)
00150 zeroFrames += delay;
00151 else
00152 zeroFrames = 0;
00153 }
00154 }
00155 }