노래의 비트를 감지하기 위해이 SoundAnalyzer 클래스를 만들었습니다.
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++;
}
}
}
어떤 이유로 든 그것은 637 초에서 약 641 초 사이의 비트 만 감지하고 이유를 모릅니다. 중복을 찾은 후 비트가 여러 밴드에서 삽입되고 있음을 알고 있으며, 그 값 사이의 각 인스턴트 에너지 값에 비트를 할당하는 것 같습니다.
http://www.flipcode.com/misc/BeatDetectionAlgorithms.pdf 의 모델입니다 .
비트가 왜 제대로 등록되지 않습니까?
2
한 밴드에서 시간에 따른 instantEnergyList [index + 1] 및 historyBuffer의 진화에 대한 도표를 게시 할 수 있습니까? 두 개의 그래프가 서로 겹쳐져 있습니다. 그것은 문제가 무엇인지에 대한 단서를 줄 것입니다. 또한 에너지는 크기의 제곱이어야합니다.
—
CeeJay
Ahh 네, 문제를 밝힐 수도 있습니다. 어떻게 든 그래프를 만들 수 있는지 봅시다
—
Quincy
그러나이 플롯은 historyBuffer 또는 historyBuffer / numInBuffer * C입니까? 거기에 거대한 C가있는 것 같습니다. 코드를 볼 때 historyBuffer는 instantEnergy와 비슷한 값을 가져야합니다. 그래프는 C가 너무 높거나 numInBuffer가 너무 낮을 때만 가능합니다 (1 미만). 그렇지 않은 것 같습니다.
—
CeeJay
죽지 않을 질문 ...
—
엔지니어