package prototypes.audioAnalysis;import java.util.ArrayList;import javax.sound.sampled.AudioInputStream;import javax.sound.sampled.AudioFormat;import java.io.IOException;import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;public class FrequencySelectedSoundEnergy extends BeatDetectionAlgorithm { /* Constants used in this algorithm */ private final int NUM_SAMPLES_TO_TAKE = 1024; //How many samples to take in each iteration of the algorithm private final int NUM_SUBBANDS = 32; private final int ENERGY_HISTORY_BUFFER_SIZE = 43; private final int C_CONSTANT = 250; private final int ONE_MILLION = 1000000; private final int SUBBAND_SIZE = NUM_SAMPLES_TO_TAKE / NUM_SUBBANDS; private final int MINIMUM_BEAT_INTERVAL = 10; /* Used for averaging energy in a subband */ private double average(double[] array, int offset, int count) { double average = 0; for (int i = offset; i < offset + count; i++) average += array[i]; return average / count; } /* Used for averaging the values in a history buffer */ private double average(RingBuffer buffer) { double average = 0; for (double d : buffer) average += d; //Note this is d and not 'd * d' (algorithm had a mistake in it). return average / buffer.getCount(); } private double variance(RingBuffer buffer, double averageLocalEnergy) { double variance = 0; for (double d : buffer) variance += (d - averageLocalEnergy) * (d - averageLocalEnergy); return variance /= buffer.getCount(); } public ArrayList<Long> getBeats(AudioInputStream pcmIn, AudioFormat format) throws IOException { /* Used to store all of the beats that we detect */ ArrayList<Long> beats = new ArrayList<Long>(); boolean beatFound = false; /* Used to read multiple audio frames at a time */ PCMReader pcmReader; long numFramesRead, totalFramesRead = 0; /* Used to perform the fast fourier transform on our samples */ DoubleFFT_1D fft; /* Arrays used by the frequency selected sound energy algorithm */ double[] frequencyAmplitudes = new double[NUM_SAMPLES_TO_TAKE]; RingBuffer[] energyHistoryBuffer = new RingBuffer[NUM_SUBBANDS]; double[] pcmSamples = new double[NUM_SAMPLES_TO_TAKE * 2]; int[] numBeatsInSubband = new int[NUM_SUBBANDS]; /* Used to skip some beats */ boolean beatSkip = false; int beatWaitTime = 0; /* Other variables used by the algorithm */ double averageEnergy; double microsecondsPerFrame; double subbandEnergy; fft = new DoubleFFT_1D(NUM_SAMPLES_TO_TAKE); pcmReader = new PCMReader(pcmIn); microsecondsPerFrame = ONE_MILLION / format.getFrameRate(); /* Initialise the energy history buffers */ for(int i=0; i< NUM_SUBBANDS; i++) energyHistoryBuffer[i] = new RingBuffer(ENERGY_HISTORY_BUFFER_SIZE); while ((numFramesRead = pcmReader.readFrames(pcmSamples,NUM_SAMPLES_TO_TAKE)) != 0) { beatFound = false; totalFramesRead += numFramesRead; //* Perform the Fast Fourier Transform */ fft.complexForward(pcmSamples); /* Calculate the frequency amplitudes of the signal returned from the FFT */ for(int i=0; i < NUM_SAMPLES_TO_TAKE; i++) { frequencyAmplitudes[i] = (pcmSamples[2 * i] * pcmSamples[2 * i]) + (pcmSamples[2*i + 1] * pcmSamples[2*i + 1]); } /* Work out whether or not we should skip a beat detected in this channel */ if (beatSkip) { beatWaitTime++; if (beatWaitTime == MINIMUM_BEAT_INTERVAL) { beatSkip = false; beatWaitTime = 0; } } for(int subband = 0; subband < NUM_SUBBANDS; subband++) { /* Calculate the energy of the current subband */ subbandEnergy = average(frequencyAmplitudes,subband * SUBBAND_SIZE, SUBBAND_SIZE); /* Don't start checking for beats until the history buffer is full */ if (! energyHistoryBuffer[subband].isFull()) energyHistoryBuffer[subband].add(subbandEnergy); else { /* Calculate the average energy for the past second of audio data */ averageEnergy = average(energyHistoryBuffer[subband]); /* Add the new subband energy value to the energy history buffer for * the current subband */ energyHistoryBuffer[subband].add(subbandEnergy); /* Check if we have found a beat on the current subband */ if(beatSkip == false && subbandEnergy > (5 * averageEnergy)) { beatFound = true; numBeatsInSubband[subband]++; } } } if(beatFound) { beats.add((long)(microsecondsPerFrame * totalFramesRead)); beatSkip = true; } } for (int i = 0; i < numBeatsInSubband.length; i++) System.out.println("Channel " + i + ": " + numBeatsInSubband[i]); System.out.println("TOTAL FRAMES READ : " + totalFramesRead); return beats; }}