public void AdjustBeat(List<double[]> features, ref DetectStatus ds, ref BeatStatus bs) { int nstep = (int)Math.Floor(ds.SamplePerSec * (60 / bs.BpmDancer)); double maxe = 0; int maxs = -1; for (int s = 0; s < nstep; s += 2) { double e = 0; for (int i = 0; i < _bandLimits.Length; i++) { for (int j = 0; j < features[i].Length; j++) { double peakValue = 1 - (j % (s + nstep)) / (double)nstep; e += Math.Pow(features[i][j] * peakValue, 2) * _bandWeights[i]; } } if (maxe < e) { maxe = e; maxs = s; } } int beatStartSample = maxs; bs.BeatTickRaw = bs.SampleStartTick + beatStartSample * 1000 / ds.SamplePerSec; }
public List<double[]> DetectBpm(double[] sig, ref DetectStatus ds, ref BeatStatus bs) { // 必要数の入力を複素数に変換 int n = (int)Math.Floor(Math.Log(sig.Length, 2)); int size = (int)Math.Pow(2, n > 14 ? 14 : n); // limit of AForge.NET Complex[] input = new Complex[size]; for (int i = 0; i < size; i++) { input[i] = new Complex(sig[i], 0); } // Bpm検出処理 List<Complex[]> filtered = filterBank(input); List<Complex[]> windowed = hwindow(filtered, 0.2); List<Complex[]> differentiated = diffrect(windowed); List<Complex[]> dft = timeCombPre(differentiated); double rBpm = timeCombRough(dft, ref ds); int maxBand = -1; double b2 = timeComb(dft, 0.1, rBpm - 1, rBpm + 1, ds.SamplePerSec, ref maxBand); bs.BpmRaw = b2; List<double[]> features = new List<double[]>(); for (int i = 0; i < _bandLimits.Length; i++) { double[] f = Array.ConvertAll<Complex, double>(differentiated[i], c => c.Re); features.Add(f); } //double[] features = Array.ConvertAll<Complex, double>(differentiated[maxBand], c => c.Re); return features; }
/// <summary>各BPM候補でエネルギーを算出</summary> private double timeCombRough(List<Complex[]> dft, ref DetectStatus ds) { int n = dft[0].Length; int nbands = _bandLimits.Length; double maxe = 0; double bpmResult = 0; int ei = 0; for (double bpm = ds.MinBpm; bpm <= ds.MaxBpm; bpm += ds.BpmAcc) { /// Initialize energy and filter to zero(s) double e = 0; Complex[] fil = new Complex[n]; for (int i = 0; i < fil.Length; i++) fil[i] = new Complex(0, 0); /// Calculate the difference between peaks in the filter for a certain tempo int nstep = (int)Math.Floor(ds.SamplePerSec * 60 / bpm); /// Set every nstep samples of the filter to one for (int i = 0; i < _npulses && i * nstep < fil.Length; i++) { fil[i * nstep] = new Complex(1, 0); } /// Get the filter in the frequency domain FourierTransform.FFT(fil, FourierTransform.Direction.Forward); /// Calculate the energy after convolution for (int i = 0; i < nbands; i++) { double sum = 0; for (int j = 0; j < fil.Length; j++) { Complex c = fil[j] * dft[i][j]; sum += Math.Pow(c.Re, 2) + Math.Pow(c.Im, 2); } e += sum * _bandWeights[i]; } /// Set the energy to DetectStatus lock (ds.BpmEnergies) { ds.BpmEnergies[ei] = (1 - _energyDecay) * ds.BpmEnergies[ei] + _energyDecay * e; } if (maxe < ds.BpmEnergies[ei]) { maxe = ds.BpmEnergies[ei]; bpmResult = bpm; } ei++; } return bpmResult; }