Extract class for testing pitchtrackers

Fix some typos
This commit is contained in:
Flamefire committed 2014-04-17 00:13:02 +02:00
1 parent 9bf12315b7
commit 001884ed9d
5 files changed
+398 -333

No files matched your search

+1 -1
View File
@@ -71,7 +71,7 @@ int PtAKF_GetNumHalfTones(){
return PtAKF::GetNumHalfTones();
}
void PtAKF_SetVolumeTreshold(PtAKF* analyzer, float threshold){
void PtAKF_SetVolumeThreshold(PtAKF* analyzer, float threshold){
if(!analyzer)
return;
analyzer->SetVolumeThreshold(threshold);
+1 -1
View File
@@ -29,7 +29,7 @@ DllExport void PtDyWa_Free(PtDyWa* analyzer);
DllExport void PtDyWa_SetVolumeTreshold(PtDyWa* analyzer,float threshold);
DllExport float PtDyWa_GetVolumeThreshold(PtDyWa* analyzer);
DllExport void PtDyWa_InputByte(PtDyWa* analyzer, char* data, int sampleCt);
DllExport double PtDyWa_FindNote(PtDyWa* analyzer);
DllExport double PtDyWa_FindNote(PtDyWa* analyzer, float* maxVolume);
/*
public ref class CTone {
+7 -331
View File
@@ -18,28 +18,12 @@
#define TEST_PITCH
using System;
#if TEST_PITCH
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;
using Pitch;
using Vocaluxe.Lib.Sound.Record.Pitch;
using Vocaluxe.Lib.Sound.Record.PitchTracker;
using VocaluxeLib;
using VocaluxeLib.Utils;
#endif
namespace Vocaluxe.Lib.Sound.Record
{
class CBuffer : IDisposable
{
#if TEST_PITCH
//Half tones: C C# D D# E F F# G G# A A# 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)
#endif
private CPitchTracker _PitchTracker = new CPtAKF();
private float _MaxVolume;
@@ -50,8 +34,12 @@ namespace Vocaluxe.Lib.Sound.Record
ToneWeigths = new float[GetNumHalfTones()];
Reset();
#if TEST_PITCH
_TestPitchDetection();
Reset();
CPitchTrackerTest tester = new CPitchTrackerTest();
tester.AddAnalyzer(new CAnalyzer());
tester.AddAnalyzer(new CPtAKF());
tester.AddAnalyzer(new CPtDyWa());
tester.AddAnalyzer(new CPtSharp());
tester.RunTest();
#endif
}
@@ -109,8 +97,7 @@ namespace Vocaluxe.Lib.Sound.Record
public void AnalyzeBuffer()
{
//_MaxVolume = _Analyzer.GetPeak() / 43 + 1;
int tone = _PitchTracker.GetNote(out _MaxVolume, ToneWeigths); //(int)Math.Round(_Analyzer.FindNote()); //
int tone = _PitchTracker.GetNote(out _MaxVolume, ToneWeigths);
if (tone >= 0)
{
ToneAbs = tone;
@@ -135,316 +122,5 @@ namespace Vocaluxe.Lib.Sound.Record
_PitchTracker = null;
}
}
#if TEST_PITCH
private static bool _PitchTestRun;
private static string _ToneToNote(int tone, bool withOctave = true)
{
if (tone < 0)
return "inv.";
tone += 24;
string[] notes = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
string result = notes[tone % 12];
if (withOctave)
result += (tone / 12);
return result;
}
private void _TestPitchDetection()
{
if (_PitchTestRun)
return;
_PitchTestRun = true;
const int toneFrom = 0;
const int toneTo = -1; // 47; //B5
Console.WriteLine("Testing notes " + _ToneToNote(toneFrom) + " - " + _ToneToNote(toneTo));
byte[] data;
byte[] data2 = new byte[2048];
int ok = 0;
int tests = 0;
double angle = 0;
for (int distort = 0; distort < 10; distort++)
{
for (int tone = toneFrom; tone <= toneTo; tone++)
{
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, tone), 44100, ref angle, out data);
_Distort(data, tone, distort);
for (int i = 0; i < 4; i++)
{
Buffer.BlockCopy(data, i * 2048, data2, 0, 2048);
ProcessNewBuffer(data2);
AnalyzeBuffer();
}
if (!ToneValid)
CBase.Log.LogDebug("Note " + _ToneToNote(tone) + " not detected (Distortion: " + distort + ")");
else if (Tone != tone % 12)
{
CBase.Log.LogDebug("Note " + _ToneToNote(tone) + " wrongly detected as " + _ToneToNote(Tone, false) + " (Distortion: " + distort + ")");
CWavFile file = new CWavFile();
file.Create(tone + "-" + distort + ".wav", 1, 44100, 16);
file.Write16BitSamples(data, 1);
file.Close();
}
else
ok++;
tests++;
}
}
/*if (_TestFile("toneG3.wav", 19))
ok++;
tests++;
if (_TestFile("toneG3Miss.wav", 19))
ok++;
tests++;
if (_TestFile("toneG4.wav", 31))
ok++;
tests++;*/
_TestFile("whistling3.wav", "whistling3.txt", ref tests, ref ok);
_TestFile("sClausVoc.wav", "sClausVoc.txt", ref tests, ref ok);
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, 5), 44100, ref angle, out data);
Stopwatch sw = new Stopwatch();
sw.Start();
const int repeats = 100;
for (int i = 0; i < repeats; i++)
{
ProcessNewBuffer(data);
AnalyzeBuffer();
}
sw.Stop();
string msg = "Analyser: Errors: " + (tests - ok) + "/" + tests + "; Speed: " +
(int)(repeats / (sw.ElapsedMilliseconds / 1000.0)) + " buffers/s";
Console.WriteLine(msg);
MessageBox.Show(msg);
Reset();
}
private struct STimedNote
{
public int Time, Note;
}
private void _TestFile(string fileName, string testFileName, ref int ct, ref int ok)
{
if (!File.Exists(testFileName))
{
ok = ct = 0;
return;
}
List<STimedNote> tones = new List<STimedNote>();
using (StreamReader reader = new StreamReader(testFileName))
{
String line;
while ((line = reader.ReadLine()) != null)
{
int p = line.IndexOf(' ');
if (p < 0)
continue;
STimedNote note;
note.Time = int.Parse(line.Substring(0, p));
note.Note = int.Parse(line.Substring(p + 1));
tones.Add(note);
}
}
_TestFile(fileName, tones, ref ct, ref ok);
}
private bool _TestFile(string fileName, int tone)
{
STimedNote note;
note.Note = tone;
note.Time = 46;
List<STimedNote> tones = new List<STimedNote> {note};
int ct = 0;
int ok = 0;
_TestFile(fileName, tones, ref ct, ref ok);
return ok >= ct - 4;
}
private bool _IsNoteValid(int note, int time, IList<STimedNote> tones)
{
const int lastNoteMaxTimeDiff = 1024 * 1000 / 44100; // old note is valid for 1024 more samples
for (int i = 0; i < tones.Count; i++)
{
if (tones[i].Time > time)
break;
if (i + 1 == tones.Count || time <= tones[i + 1].Time + lastNoteMaxTimeDiff)
{
if (tones[i].Note == note)
return true;
}
}
return false;
}
private void _TestFile(string fileName, IList<STimedNote> tones, ref int ct, ref int ok)
{
CWavFile wavFile = new CWavFile();
try
{
if (!wavFile.Open(fileName))
return;
if (wavFile.BitsPerSample != 16)
{
wavFile.Close();
return;
}
int samplesRead = 0;
int curTimeIndex = -1;
int curNote = -1;
const int maxSamplesPerBatch = 512;
CPitchTracker analyzer2 = new CAnalyzer();
CPitchTracker analyzer3 = new CPtDyWa();
CPitchTracker analyzer4 = new CPtSharp();
int[] detectedTones = new int[4];
int[] oks = new int[4];
float dummyMaxVol;
float[] dummyWeights = new float[ToneWeigths.Length];
int lCt = 0;
while (wavFile.NumSamplesLeft > maxSamplesPerBatch)
{
byte[] samples = wavFile.GetNextSamples16BitAsBytes(maxSamplesPerBatch, 1);
samplesRead += samples.Length / 2;
int time = samplesRead * 1000 / wavFile.SampleRate;
ProcessNewBuffer(samples);
AnalyzeBuffer();
analyzer2.Input(samples);
analyzer3.Input(samples);
analyzer4.Input(samples);
while (curTimeIndex + 1 < tones.Count && time >= tones[curTimeIndex + 1].Time)
{
curTimeIndex++;
curNote = tones[curTimeIndex].Note;
}
if (curNote < 0)
continue;
detectedTones[0] = ToneValid ? ToneAbs : -1;
detectedTones[1] = analyzer2.GetNote(out dummyMaxVol, dummyWeights);
detectedTones[2] = analyzer3.GetNote(out dummyMaxVol, dummyWeights);
detectedTones[3] = analyzer4.GetNote(out dummyMaxVol, dummyWeights);
lCt++;
/*if (!ToneValid)
CBase.Log.LogDebug("Note " + _ToneToNote(curNote) + " at " + time + "ms not detected");
else if (ToneAbs % 12 != curNote % 12)
CBase.Log.LogDebug("Note " + _ToneToNote(curNote) + " at " + time + "ms wrongly detected as " + _ToneToNote(ToneAbs));
else
ok++;*/
bool[] valids = new bool[4];
bool error = false;
for (int i = 0; i < 4; i++)
{
valids[i] = _IsNoteValid(detectedTones[i], time, tones);
if (valids[i])
oks[i]++;
else
error = true;
}
if (error)
{
string msg = "Note " + _ToneToNote(curNote) + " at " + time + "ms detected as ";
for (int i = 0; i < 4; i++)
msg += _ToneToNote(detectedTones[i]) + (valids[i] ? "" : "(!)") + "; ";
CBase.Log.LogDebug(msg);
}
}
string msg2 = "Detected ";
for (int i = 0; i < 4; i++)
msg2 += oks[i] + "|" + (lCt - oks[i]) + " ";
CBase.Log.LogDebug(msg2);
}
catch (Exception e)
{
Console.WriteLine("Error on file " + fileName + ": " + e);
}
wavFile.Close();
}
private static short[] _GetDistort(int len, int tone, int type)
{
short[] sdata = new short[len];
if (type < 9)
{
int newTone = 1;
switch (type)
{
case 0:
newTone = 2;
break;
case 1:
newTone = 3;
break;
case 2:
newTone = 6;
break;
case 3:
newTone = 8;
break;
case 4:
newTone = 10;
break;
case 5:
newTone = 15;
break;
case 6:
newTone = 25;
break;
case 7:
newTone = 26;
break;
case 8:
newTone = 29;
break;
}
byte[] data2;
double angle = 0;
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, tone + newTone), 44100, ref angle, out data2);
Buffer.BlockCopy(data2, 0, sdata, 0, len * 2);
}
else
{
Random r = new Random(0xBEEF);
for (int i = 0; i < sdata.Length; i++)
sdata[i] = (short)(r.Next() - Int16.MinValue);
}
return sdata;
}
private static void _Distort(byte[] data, int tone, int distortCt)
{
if (distortCt < 1)
return;
short[] sdata = new short[data.Length / 2];
Buffer.BlockCopy(data, 0, sdata, 0, data.Length);
short[][] distortions = new short[distortCt][];
for (int i = 0; i < distortCt; i++)
distortions[i] = _GetDistort(data.Length / 2, tone, i);
for (int i = 0; i < sdata.Length; i++)
{
double distortion = 0;
for (int j = 0; j < distortCt; j++)
distortion += distortions[j][i];
distortion /= distortCt;
sdata[i] = (short)(sdata[i] * 4.0 / 5.0 + distortion / 5.0);
}
Buffer.BlockCopy(sdata, 0, data, 0, data.Length);
}
private static void _GetSineWave(double freq, int sampleRate, ref double angle, out byte[] data)
{
const short max = short.MaxValue;
const int len = 4096; //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 + angle) * max);
angle = 2 * Math.PI * len / sampleRate * freq + angle;
angle = angle % (2 * Math.PI);
data = new byte[data16Bit.Length * 2];
Buffer.BlockCopy(data16Bit, 0, data, 0, data.Length);
}
#endif
}
}
@@ -0,0 +1,388 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using VocaluxeLib;
using VocaluxeLib.Utils;
namespace Vocaluxe.Lib.Sound.Record.PitchTracker
{
class CPitchTrackerTest
{
//Half tones: C C# D D# E F F# G G# A A# 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)
private readonly List<CPitchTracker> _Analyzers = new List<CPitchTracker>();
private int[] _Tones;
private float[][] _Weights;
private float _MaxVolume;
private int _CurTestCount;
private int[] _CurPassedCount;
private int _TestCount;
private int[] _PassedCount;
private int[] _SamplesPerSec;
private static bool _IsRun;
public void AddAnalyzer(CPitchTracker analyzer)
{
_Analyzers.Add(analyzer);
}
#region Init
private void _InitTests()
{
_Tones = new int[_Analyzers.Count];
_TestCount = 0;
_PassedCount = new int[_Analyzers.Count];
_CurTestCount = 0;
_CurPassedCount = new int[_Analyzers.Count];
_Weights = new float[_Analyzers.Count][];
for (int i = 0; i < _Analyzers.Count; i++)
_Weights[i] = new float[_Analyzers[i].GetNumHalfTones()];
_SamplesPerSec = new int[_Analyzers.Count];
}
private void _InitNext(string lastTest)
{
string msg = "Errors " + lastTest + ": ";
for (int i = 0; i < _CurPassedCount.Length; i++)
{
msg += _CurTestCount - _CurPassedCount[i] + " ";
_PassedCount[i] += _CurPassedCount[i];
_CurPassedCount[i] = 0;
}
msg += "of " + _CurTestCount;
CBase.Log.LogDebug(msg);
_TestCount += _CurTestCount;
_CurTestCount = 0;
}
#endregion
public void RunTest(bool reRun = false)
{
if (_IsRun && !reRun)
return;
_IsRun = true;
_InitTests();
_TestSines();
_InitNext("Sines");
_TestFile("toneG3.wav", 19);
_InitNext("Real G3");
_TestFile("toneG3Miss.wav", 19);
_InitNext("Real G3 with miss. fundamental");
_TestFile("toneG4.wav", 31);
_InitNext("Real G4");
_TestFile("whistling3.wav", "whistling3.txt");
_InitNext("High whistling");
_TestFile("sClausVoc.wav", "sClausVoc.txt");
_InitNext("Real song");
_TestSpeed();
CBase.Log.LogDebug("Finished: ");
for (int i = 0; i < _Analyzers.Count; i++)
{
string msg = _Analyzers[i].GetType().Name + ":";
msg += " Errors=" + (_TestCount - _PassedCount[i]);
msg += " Passed=" + _PassedCount[i];
msg += " Total=" + _TestCount;
msg += " Speed=" + _SamplesPerSec[i] + "samples/s (=" + (_SamplesPerSec[i] / 44100) + "rec.s/s)";
CBase.Log.LogDebug(msg);
}
}
private void _TestSpeed()
{
const int samplesPerBuffer = 512;
byte[] data;
byte[] data2 = new byte[samplesPerBuffer * 2];
double angle = 0;
const int repeats = 100;
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, 5), 44100, samplesPerBuffer * repeats, ref angle, out data);
for (int i = 0; i < _Analyzers.Count; i++)
{
CPitchTracker analyzer = _Analyzers[i];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int j = 0; j < repeats; j++)
{
Buffer.BlockCopy(data, 0, data2, 0, samplesPerBuffer * 2);
analyzer.Input(data2);
analyzer.GetNote(out _MaxVolume, _Weights[j]);
}
sw.Stop();
_SamplesPerSec[i] = (int)Math.Round(samplesPerBuffer * repeats / (sw.ElapsedMilliseconds / 1000.0));
}
}
private void _Process(byte[] data)
{
for (int j = 0; j < _Analyzers.Count; j++)
{
_Analyzers[j].Input(data);
_Tones[j] = _Analyzers[j].GetNote(out _MaxVolume, _Weights[j]);
}
}
private static string _ToneToNote(int tone, bool withOctave = true)
{
if (tone < 0)
return "inv.";
tone += 24;
string[] notes = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
string result = notes[tone % 12];
if (withOctave)
result += (tone / 12);
return result;
}
#region Sines
private void _TestSines()
{
const int toneFrom = 0;
const int toneTo = 47; //B5
const int sampleCt = 4096;
const int batchCt = 512;
byte[] data2 = new byte[batchCt * 2];
Console.WriteLine("Testing notes " + _ToneToNote(toneFrom) + " - " + _ToneToNote(toneTo));
double angle = 0;
bool[] valids = new bool[_Analyzers.Count];
for (int distort = 0; distort < 10; distort++)
{
for (int tone = toneFrom; tone <= toneTo; tone++)
{
byte[] data;
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, tone), 44100, sampleCt, ref angle, out data);
_Distort(data, tone, distort);
for (int i = 0; i < sampleCt / batchCt; i++)
{
Buffer.BlockCopy(data, i * batchCt * 2, data2, 0, batchCt * 2);
_Process(data2);
if (i * batchCt < 2048)
continue;
_CurTestCount++;
bool ok = true;
for (int j = 0; j < valids.Length; j++)
{
valids[j] = _Tones[j] == tone;
if (!valids[j])
ok = false;
else
_CurPassedCount[j]++;
}
if (ok)
continue;
string msg = "Note " + _ToneToNote(tone) + " detected as ";
for (int j = 0; j < valids.Length; j++)
msg += _ToneToNote(_Tones[j]) + (valids[j] ? "" : "(!)") + "; ";
CBase.Log.LogDebug(msg);
}
}
}
}
private static short[] _GetDistort(int sampleCt, int tone, int type)
{
short[] sdata = new short[sampleCt];
if (type < 9)
{
int newTone = 1;
switch (type)
{
case 0:
newTone = 2;
break;
case 1:
newTone = 3;
break;
case 2:
newTone = 6;
break;
case 3:
newTone = 8;
break;
case 4:
newTone = 10;
break;
case 5:
newTone = 15;
break;
case 6:
newTone = 25;
break;
case 7:
newTone = 26;
break;
case 8:
newTone = 29;
break;
}
byte[] data2;
double angle = 0;
_GetSineWave(_BaseToneFreq * Math.Pow(_HalftoneBase, tone + newTone), 44100, sampleCt, ref angle, out data2);
Buffer.BlockCopy(data2, 0, sdata, 0, sampleCt * 2);
}
else
{
Random r = new Random(0xBEEF);
for (int i = 0; i < sdata.Length; i++)
sdata[i] = (short)(r.Next() - Int16.MinValue);
}
return sdata;
}
private static void _Distort(byte[] data, int tone, int distortCt)
{
if (distortCt < 1)
return;
short[] sdata = new short[data.Length / 2];
Buffer.BlockCopy(data, 0, sdata, 0, data.Length);
short[][] distortions = new short[distortCt][];
for (int i = 0; i < distortCt; i++)
distortions[i] = _GetDistort(data.Length / 2, tone, i);
for (int i = 0; i < sdata.Length; i++)
{
double distortion = 0;
for (int j = 0; j < distortCt; j++)
distortion += distortions[j][i];
distortion /= distortCt;
sdata[i] = (short)(sdata[i] * 4.0 / 5.0 + distortion / 5.0);
}
Buffer.BlockCopy(sdata, 0, data, 0, data.Length);
}
private static void _GetSineWave(double freq, int sampleRate, int sampleCt, ref double angle, out byte[] data)
{
const short max = short.MaxValue;
short[] data16Bit = new short[sampleCt];
for (int i = 0; i < sampleCt; i++)
data16Bit[i] = (short)(Math.Sin(2 * Math.PI * i / sampleRate * freq + angle) * max);
angle = 2 * Math.PI * sampleCt / sampleRate * freq + angle;
angle = angle % (2 * Math.PI);
data = new byte[data16Bit.Length * 2];
Buffer.BlockCopy(data16Bit, 0, data, 0, data.Length);
}
#endregion
#region File
private struct STimedNote
{
public int Time, Note;
}
private void _TestFile(string fileName, string testFileName)
{
if (!File.Exists(testFileName))
return;
List<STimedNote> tones = new List<STimedNote>();
using (StreamReader reader = new StreamReader(testFileName))
{
String line;
while ((line = reader.ReadLine()) != null)
{
int p = line.IndexOf(' ');
if (p < 0)
continue;
STimedNote note;
note.Time = int.Parse(line.Substring(0, p));
note.Note = int.Parse(line.Substring(p + 1));
tones.Add(note);
}
}
_TestFile(fileName, tones);
}
private void _TestFile(string fileName, int tone)
{
STimedNote note;
note.Note = tone;
note.Time = 46;
List<STimedNote> tones = new List<STimedNote> {note};
_TestFile(fileName, tones);
}
private static bool _IsNoteValid(int note, int time, IList<STimedNote> tones)
{
const int lastNoteMaxTimeDiff = 1024 * 1000 / 44100; // old note is valid for 1024 more samples
for (int i = 0; i < tones.Count; i++)
{
if (tones[i].Time > time)
break;
if (i + 1 == tones.Count || time <= tones[i + 1].Time + lastNoteMaxTimeDiff)
{
if (tones[i].Note == note)
return true;
}
}
return false;
}
private void _TestFile(string fileName, IList<STimedNote> tones)
{
CWavFile wavFile = new CWavFile();
try
{
if (!wavFile.Open(fileName))
return;
if (wavFile.BitsPerSample != 16)
{
wavFile.Close();
return;
}
int samplesRead = 0;
int curTimeIndex = -1;
int curNote = -1;
const int maxSamplesPerBatch = 512;
bool[] valids = new bool[_Tones.Length];
while (wavFile.NumSamplesLeft > maxSamplesPerBatch)
{
byte[] samples = wavFile.GetNextSamples16BitAsBytes(maxSamplesPerBatch, 1);
samplesRead += samples.Length / 2;
int time = samplesRead * 1000 / wavFile.SampleRate;
_Process(samples);
while (curTimeIndex + 1 < tones.Count && time >= tones[curTimeIndex + 1].Time)
{
curTimeIndex++;
curNote = tones[curTimeIndex].Note;
}
if (curNote < 0)
continue;
_CurTestCount++;
bool error = false;
for (int i = 0; i < _Tones.Length; i++)
{
valids[i] = _IsNoteValid(_Tones[i], time, tones);
if (valids[i])
_CurPassedCount[i]++;
else
error = true;
}
if (error)
{
string msg = "Note " + _ToneToNote(curNote) + " at " + time + "ms detected as ";
for (int i = 0; i < 4; i++)
msg += _ToneToNote(_Tones[i]) + (valids[i] ? "" : "(!)") + "; ";
CBase.Log.LogDebug(msg);
}
}
}
catch (Exception e)
{
Console.WriteLine("Error on file " + fileName + ": " + e);
}
wavFile.Close();
}
#endregion
}
}
+1
View File
@@ -268,6 +268,7 @@
<Compile Include="Lib\Sound\Record\CRecordBase.cs" />
<Compile Include="Lib\Sound\Record\DirectSound\CSampleDataEventArgs.cs" />
<Compile Include="Lib\Sound\Record\DirectSound\CSoundCardSource.cs" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPitchTrackerTest.cs" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPtAKF.cs" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPtDyWa.cs" />
<Compile Include="Lib\Sound\Record\PitchTracker\CPtSharp.cs" />