Fix wrong initial values for weights
Add a test for pitch detection accuracy and performance
This commit is contained in:
1 parent
3bc8fd516f
commit
15e08ca831
1 file changed
+75
-5
@@ -1,12 +1,21 @@
|
||||
using System;
|
||||
//#define TEST_PITCH
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#if TEST_PITCH
|
||||
using System.Diagnostics;
|
||||
using VocaluxeLib;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Vocaluxe.Lib.Sound.Record
|
||||
{
|
||||
class CBuffer : IDisposable
|
||||
{
|
||||
//Half tones: C C♯ D Eb E F F♯ G G♯ A Bb B
|
||||
private const double _BaseToneFreq = 65.4064; // lowest (half-)tone to analyze (C2 = 65.4064 Hz)
|
||||
private const double _HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
|
||||
public const int NumHalfTones = 17; //Number of halftone to analyze C2-E3 (TODO: use more/full octaves?)
|
||||
|
||||
private const int _AnalysisBufLen = 4096;
|
||||
@@ -27,17 +36,18 @@ namespace Vocaluxe.Lib.Sound.Record
|
||||
{
|
||||
MinVolume = 0.02f;
|
||||
ToneWeigth = new float[NumHalfTones];
|
||||
for (int i = 0; i < ToneWeigth.Length; i++)
|
||||
ToneWeigth[i] = 0.99f;
|
||||
Reset();
|
||||
#if TEST_PITCH
|
||||
_TestPitchDetection();
|
||||
#endif
|
||||
}
|
||||
|
||||
static CBuffer()
|
||||
{
|
||||
const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
|
||||
//Init Array to avoid costly calculations
|
||||
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
||||
{
|
||||
double freq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex);
|
||||
double freq = _BaseToneFreq * Math.Pow(_HalftoneBase, toneIndex);
|
||||
_SamplesPerPeriodPerTone[toneIndex] = (int)Math.Round(44100.0 / freq); // samples in one period
|
||||
}
|
||||
}
|
||||
@@ -70,6 +80,8 @@ namespace Vocaluxe.Lib.Sound.Record
|
||||
ToneValid = false;
|
||||
ToneAbs = 0;
|
||||
Tone = 0;
|
||||
for (int i = 0; i < ToneWeigth.Length; i++)
|
||||
ToneWeigth[i] = 0f;
|
||||
}
|
||||
|
||||
private void _Add(byte[] bytes)
|
||||
@@ -212,5 +224,63 @@ namespace Vocaluxe.Lib.Sound.Record
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
#if TEST_PITCH
|
||||
private static bool _PitchTestRun;
|
||||
|
||||
private string _ToneToNote(int tone, bool withOctave = true)
|
||||
{
|
||||
string[] notes = {"C", "C♯", "D", "Eb", "E", "F", "F♯", "G", "G♯", "A", "Bb", "B"};
|
||||
string result = notes[tone % 12];
|
||||
if (withOctave)
|
||||
result += (tone / 12) + 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void _TestPitchDetection()
|
||||
{
|
||||
if (_PitchTestRun)
|
||||
return;
|
||||
_PitchTestRun = true;
|
||||
const int toneFrom = 0;
|
||||
const int tontTo = 47;
|
||||
Console.WriteLine("Testing notes " + _ToneToNote(toneFrom) + " - " + _ToneToNote(tontTo));
|
||||
byte[] data;
|
||||
for (int tone = toneFrom; tone <= tontTo; tone++)
|
||||
{
|
||||
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, tone), 44100, out data);
|
||||
ProcessNewBuffer(data);
|
||||
AnalyzeBuffer();
|
||||
if (!ToneValid)
|
||||
CBase.Log.LogDebug("Note " + _ToneToNote(tone) + " not detected");
|
||||
else if (Tone != tone % 12)
|
||||
CBase.Log.LogDebug("Note " + _ToneToNote(tone) + " wrongly detected as " + _ToneToNote(Tone, false));
|
||||
}
|
||||
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, 5), 44100, out data);
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
// ProcessNewBuffer(data);
|
||||
// AnalyzeBuffer();
|
||||
_FindMaxVolume();
|
||||
_AnalyzeByAutocorrelation();
|
||||
}
|
||||
sw.Stop();
|
||||
Console.WriteLine("Analysing took " + sw.ElapsedMilliseconds + "ms");
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void _GetSineWave(double freq, int sampleRate, out byte[] data)
|
||||
{
|
||||
const short max = short.MaxValue;
|
||||
const int len = _AnalysisBufLen; //sampleRate * durationMs / 1000;
|
||||
short[] data16Bit = new short[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
data16Bit[i] = (short)(Math.Sin(2 * Math.PI * i / sampleRate * freq) * max);
|
||||
data = new byte[data16Bit.Length * 2];
|
||||
Buffer.BlockCopy(data16Bit, 0, data, 0, data.Length);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user