J'ai créé cette classe SoundAnalyzer pour détecter les battements dans les chansons:
class SoundAnalyzer
{
public SoundBuffer soundData;
public Sound sound;
public List<double> beatMarkers = new List<double>();
public SoundAnalyzer(string path)
{
soundData = new SoundBuffer(path);
sound = new Sound(soundData);
}
// C = threshold, N = size of history buffer / 1024 B = bands
public void PlaceBeatMarkers(float C, int N, int B)
{
List<double>[] instantEnergyList = new List<double>[B];
GetEnergyList(B, ref instantEnergyList);
for (int i = 0; i < B; i++)
{
PlaceMarkers(instantEnergyList[i], N, C);
}
beatMarkers.Sort();
}
private short[] getRange(int begin, int end, short[] array)
{
short[] result = new short[end - begin];
for (int i = 0; i < end - begin; i++)
{
result[i] = array[begin + i];
}
return result;
}
// get a array of with a list of energy for each band
private void GetEnergyList(int B, ref List<double>[] instantEnergyList)
{
for (int i = 0; i < B; i++)
{
instantEnergyList[i] = new List<double>();
}
short[] samples = soundData.Samples;
float timePerSample = 1 / (float)soundData.SampleRate;
int sampleIndex = 0;
int nextSamples = 1024;
int samplesPerBand = nextSamples / B;
// for the whole song
while (sampleIndex + nextSamples < samples.Length)
{
complex[] FFT = FastFourier.Calculate(getRange(sampleIndex, nextSamples + sampleIndex, samples));
// foreach band
for (int i = 0; i < B; i++)
{
double energy = 0;
for (int j = 0; j < samplesPerBand; j++)
energy += FFT[i * samplesPerBand + j].GetMagnitude();
energy /= samplesPerBand;
instantEnergyList[i].Add(energy);
}
if (sampleIndex + nextSamples >= samples.Length)
nextSamples = samples.Length - sampleIndex - 1;
sampleIndex += nextSamples;
samplesPerBand = nextSamples / B;
}
}
// place the actual markers
private void PlaceMarkers(List<double> instantEnergyList, int N, float C)
{
double timePerSample = 1 / (double)soundData.SampleRate;
int index = N;
int numInBuffer = index;
double historyBuffer = 0;
//Fill the history buffer with n * instant energy
for (int i = 0; i < index; i++)
{
historyBuffer += instantEnergyList[i];
}
// If instantEnergy / samples in buffer < instantEnergy for the next sample then add beatmarker.
while (index + 1 < instantEnergyList.Count)
{
if(instantEnergyList[index + 1] > (historyBuffer / numInBuffer) * C)
beatMarkers.Add((index + 1) * 1024 * timePerSample);
historyBuffer -= instantEnergyList[index - numInBuffer];
historyBuffer += instantEnergyList[index + 1];
index++;
}
}
}
Pour une raison quelconque, il détecte uniquement les temps compris entre 637 et 641 secondes, et je ne sais pas pourquoi. Je sais que les battements sont insérés dans plusieurs bandes car je trouve des doublons, et il semble assigner un battement à chaque valeur d'énergie instantanée entre ces valeurs.
Son modèle est le suivant: http://www.flipcode.com/misc/BeatDetectionAlgorithms.pdf
Alors pourquoi les battements ne s'enregistrent-ils pas correctement?