// Beat detection, algorithm put together by Ben Fisher after reading some things // numbers here are arbitrary, based on what seemed to work ok. I'm sure it could be better. public static double GuessBpm(WaveAudio input) { const double minBpm = 60, maxBpm = 150; WaveAudio w = Effects.Derivative(input); // take the derivative of samples. // divide samples into chunks of size 1024. int nBufsize = 1024; double chunkframerate = input.getSampleRate() / nBufsize; // the chunks go by at this rate. // do first FFT double[][] frequencyData = SpectrumContentOverTime(w, 4, nBufsize); // create a new signal in time, consisting of the energy at lowest 1/4 freqs of the chunks. int slength = (int)Fourier.findNearestPowerOfTwo((uint)frequencyData.Length); double[] lowerdata = new double[slength]; for (int i = 0; i < slength; i++) { lowerdata[i] = frequencyData[i][0]; // the bottom 1/4 freqs (index 0-255,0Hz to 5512.5Hz or something ?) } // now take a second FFT on this new signal. Frequency should be range 0.6 to 2.5 Hz (40 to 150 Bpm). double[] reout, imgout; RawSamplesToFrequency(lowerdata, out reout, out imgout); // only keep track of output inside the range we are interested in int minFreqindex = (int)(reout.Length * ((minBpm / 60) / chunkframerate)); int maxFreqindex = (int)(reout.Length * ((maxBpm / 60) / chunkframerate)); // find the best candidate double highestEnergy = -1; int highestEnergyIndex = -1; for (int b = minFreqindex; b < maxFreqindex; b++) { double magnitude = Math.Sqrt(reout[b] * reout[b] + imgout[b] + imgout[b]); if (magnitude > highestEnergy) { highestEnergyIndex = b; highestEnergy = magnitude; } } double freqHertz = chunkframerate * (highestEnergyIndex / (double)reout.Length); double freqInBpm = freqHertz * 60; return(freqInBpm); }
public WaveAudio doModify(WaveAudio src, int bufsize) { WaveAudio wout = new WaveAudio(src.getSampleRate(), 1); wout.LengthInSamples = src.LengthInSamples; //reuse the buffers. double[] ffreqmaghalfout = new double[bufsize / 2], ffreqanghalfout = new double[bufsize / 2]; double[] ffreqmaghalfin = new double[bufsize / 2], ffreqanghalfin = new double[bufsize / 2]; double[] fbuffertime = new double[bufsize]; for (int partnum = 0; partnum < src.LengthInSamples / bufsize; partnum++) { //copy into buffer. Array.Copy(src.data[0], partnum * bufsize, fbuffertime, 0, bufsize); double[] ffreqreal, ffreqimag; Fourier.RawSamplesToFrequency(fbuffertime, out ffreqreal, out ffreqimag); //we only care about the first half of these results. for (int i = 0; i < bufsize / 2; i++) { ffreqmaghalfin[i] = Math.Sqrt(ffreqreal[i] * ffreqreal[i] + ffreqimag[i] * ffreqimag[i]); ffreqanghalfin[i] = Math.Atan2(ffreqimag[i], ffreqreal[i]); } this.modifyAngular(ffreqmaghalfin, ffreqanghalfin, ffreqmaghalfout, ffreqanghalfout); if (partnum == 0) { this.drawPlots(ffreqmaghalfin, ffreqanghalfin, ffreqmaghalfout, ffreqanghalfout); } for (int i = 0; i < ffreqreal.Length / 2; i++) { ffreqreal[i] = ffreqmaghalfout[i] * Math.Sin(ffreqanghalfout[i]); ffreqimag[i] = ffreqmaghalfout[i] * Math.Cos(ffreqanghalfout[i]); } for (int i = ffreqreal.Length / 2; i < ffreqreal.Length; i++) { ffreqreal[i] = ffreqimag[i] = 0; } double[] fbufout; Fourier.RawFrequencyToSamples(out fbufout, ffreqreal, ffreqimag); Array.Copy(fbufout, 0, wout.data[0], partnum * bufsize, bufsize); } return(wout); }
public WaveAudio doModify(WaveAudio src, int bufsize) { WaveAudio wout = new WaveAudio(src.getSampleRate(), 1); wout.LengthInSamples = src.LengthInSamples; //reuse the buffers. double[] ffreqmaghalfout = new double[bufsize / 2], ffreqanghalfout = new double[bufsize / 2]; double[] ffreqmaghalfin = new double[bufsize / 2], ffreqanghalfin = new double[bufsize / 2]; double[] fbuffertime = new double[bufsize]; for (int index = 0; index < src.LengthInSamples - bufsize; index += bufsize / overlap) { //copy into buffer. Array.Copy(src.data[0], index, fbuffertime, 0, bufsize); double[] ffreqreal, ffreqimag; Fourier.RawSamplesToFrequency(fbuffertime, out ffreqreal, out ffreqimag); //we only care about the first half of these results. for (int i = 0; i < bufsize / 2; i++) { ffreqmaghalfin[i] = Math.Sqrt(ffreqreal[i] * ffreqreal[i] + ffreqimag[i] * ffreqimag[i]); ffreqanghalfin[i] = Math.Atan2(ffreqimag[i], ffreqreal[i]); } this.modifyAngular(ffreqmaghalfin, ffreqanghalfin, ffreqmaghalfout, ffreqanghalfout); for (int i = 0; i < ffreqreal.Length / 2; i++) { ffreqreal[i] = ffreqmaghalfout[i] * Math.Sin(ffreqanghalfout[i]); ffreqimag[i] = ffreqmaghalfout[i] * Math.Cos(ffreqanghalfout[i]); } for (int i = ffreqreal.Length / 2; i < ffreqreal.Length; i++) { ffreqreal[i] = ffreqimag[i] = 0; } double[] fbufout; Fourier.RawFrequencyToSamples(out fbufout, ffreqreal, ffreqimag); WaveAudio ww = new WaveAudio(44100, 1); ww.data[0] = fbufout; //Array.Copy(fbufout, 0, wout.data[0], partnum*bufsize, bufsize); ConstructionUtil.placeAudioRamp(wout, ww, index, (bufsize / overlapRamp)); } return(wout); }