diff --git a/.gitignore b/.gitignore
index 6413e521..a12662d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,13 +14,13 @@ Output/Songs
/*.ctl
/Output/Registration.xml
/Vocaluxe.suo
-/Vocaluxe/Vocaluxe.csproj.user
+*.csproj.user
+*.vcxproj.user
/Output/Config.xml
*.ipch
*.log
/Output/Playlists/*.xml
-/Output/x64/gstreamer/GstreamerHelper.dll
-/Output/x86/gstreamer/GstreamerHelper.dll
+GstreamerHelper.dll
*.tlog
*.suo
*.obj
@@ -39,11 +39,7 @@ Output/Songs
*.Cache
/GstreamerHelper/bin/*
/VocaluxeLib/bin
-/ClientServerLib/ClientServerLib/ClientServerLib.csproj.user
-/ClientServerLib/ClientServerLib/bin/Debug/ClientServerLib.dll
-/ClientServerLib/ClientTest/bin/Debug/ClientServerLib.dll
-/ClientServerLib/ClientTest/bin/Release/ClientServerLib.dll
-/ClientServerLib/ClientServerLib/bin/ClientServerLib.dll
+ClientServerLib.dll
ClientTest.exe
*.vshost.*
*.userprefs
@@ -63,3 +59,4 @@ Output/Vocaluxe_x64.exe
/Output/VocaluxeServerConfig.exe.config
/PhoneGap/
/Output/Profiles
+PitchTracker.dll
diff --git a/PitchTracker/PitchTracker.vcxproj b/PitchTracker/PitchTracker.vcxproj
new file mode 100644
index 00000000..73e5ca52
--- /dev/null
+++ b/PitchTracker/PitchTracker.vcxproj
@@ -0,0 +1,178 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}
+ Win32Proj
+ PitchTracker
+ PitchTracker
+
+
+
+ DynamicLibrary
+ true
+ v110_xp
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v110_xp
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v110_xp
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v110_xp
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ bin\$(Configuration).$(Platform)\
+ obj\$(Configuration).$(Platform)\
+
+
+ true
+ bin\$(Configuration).$(Platform)\
+ obj\$(Configuration).$(Platform)\
+
+
+ false
+ bin\$(Configuration).$(Platform)\
+ obj\$(Configuration).$(Platform)\
+
+
+ false
+ bin\$(Configuration).$(Platform)\
+ obj\$(Configuration).$(Platform)\
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ WIN64;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Fast
+
+
+ Windows
+ true
+
+
+ xcopy "$(OutDir)*.dll" "$(SolutionDir)Output\x64\" /I /Y
+
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Fast
+
+
+ Windows
+ true
+
+
+ xcopy "$(OutDir)*.dll" "$(SolutionDir)Output\x86\" /I /Y
+
+
+
+
+ Level3
+ NotUsing
+ MaxSpeed
+ true
+ true
+ WIN64;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Speed
+ true
+ Fast
+
+
+ Windows
+ false
+ true
+ true
+
+
+ xcopy "$(OutDir)*.dll" "$(SolutionDir)Output\x64\" /I /Y
+
+
+
+
+ Level3
+ NotUsing
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Speed
+ Fast
+
+
+ Windows
+ false
+ true
+ true
+
+
+ xcopy "$(OutDir)*.dll" "$(SolutionDir)Output\x86\" /I /Y
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PitchTracker/PitchTracker.vcxproj.filters b/PitchTracker/PitchTracker.vcxproj.filters
new file mode 100644
index 00000000..aa287032
--- /dev/null
+++ b/PitchTracker/PitchTracker.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Quelldateien
+
+
+
+
+ Headerdateien
+
+
+
\ No newline at end of file
diff --git a/PitchTracker/pitchTracker.cpp b/PitchTracker/pitchTracker.cpp
new file mode 100644
index 00000000..72904102
--- /dev/null
+++ b/PitchTracker/pitchTracker.cpp
@@ -0,0 +1,115 @@
+// This file is part of Vocaluxe.
+//
+// Vocaluxe is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Vocaluxe is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Vocaluxe. If not, see .
+
+#include "pitchTracker.h"
+#include
+#include
+#include
+#include
+
+void doLog(const char* msg,...){
+ va_list argptr = NULL;
+ va_start(argptr, msg);
+
+ char buffer[200];
+ vsprintf_s(buffer,msg, argptr);
+ if(Log) Log(buffer);
+ va_end(argptr);
+}
+
+void SetLogCallback(LogCallback Callback){
+ Log=Callback;
+}
+
+double *SamplesPerPeriodPerTone = NULL;
+int MinHalfTone = 0, MaxHalfTone = 38;
+const double HalftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
+
+void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone){
+ MinHalfTone = minHalfTone;
+ MaxHalfTone = maxHalfTone;
+ DeInit();
+ if(maxHalfTone <= 0)
+ return;
+ SamplesPerPeriodPerTone = (double*) malloc(MaxHalfTone * sizeof(double));
+ //Init Array to avoid costly calculations
+ for (int toneIndex = 0; toneIndex <= MaxHalfTone; toneIndex++)
+ {
+ double freq = baseToneFrequency * pow(HalftoneBase, toneIndex);
+ SamplesPerPeriodPerTone[toneIndex] = 44100.0 / freq; // samples in one period
+ }
+}
+
+void DeInit(){
+ if(SamplesPerPeriodPerTone){
+ free(SamplesPerPeriodPerTone);
+ SamplesPerPeriodPerTone=NULL;
+ }
+}
+
+static double _AnalyzeToneFunc(double *samples, int sampleCt, int toneIndex){
+ double samplesPerPeriodD = SamplesPerPeriodPerTone[toneIndex]; // samples in one period
+ int samplesPerPeriod = (int)samplesPerPeriodD;
+ double fHigh = samplesPerPeriodD - samplesPerPeriod;
+ double fLow = 1.0 - fHigh;
+
+ double accumDist = 0; // accumulated distances
+
+ // compare correlating samples
+ int sampleIndex = 0; // index of sample to analyze
+ // Start value= index of sample one period ahead
+ for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex + 1 < sampleCt; correlatingSampleIndex++, sampleIndex++)
+ {
+ // calc distance to corresponding sample in next period (lower means more distant)
+ double dist = samples[sampleIndex] * (samples[correlatingSampleIndex] * fLow + samples[correlatingSampleIndex + 1] * fHigh);
+ accumDist += dist;
+ }
+
+ //Using _AnalysisBufLen here makes it return correct values among all analyzed frequencies
+ double scaleValue = 32767.0 * 32767.0 * sampleCt; // Divide also by Int16.MaxValue^2
+ return accumDist / scaleValue;
+}
+
+int GetTone(double *samples, int sampleCt, float *weights){
+ double maxVolume = 0;
+ for(int i = 0; i < sampleCt; i++){
+ double vol = abs(samples[i]);
+ if(vol > maxVolume)
+ maxVolume = vol;
+ }
+ double maxWeight = -1;
+ double minWeight = 1;
+ int maxTone = -1;
+ for (int toneIndex = MinHalfTone; toneIndex <= MaxHalfTone; toneIndex++)
+ {
+ double curWeight = _AnalyzeToneFunc(samples, sampleCt, toneIndex) / maxVolume * 32767.0;
+
+ if (curWeight > maxWeight)
+ {
+ maxWeight = curWeight;
+ maxTone = toneIndex;
+ }
+
+ if (curWeight < minWeight)
+ minWeight = curWeight;
+
+ weights[toneIndex] = (float) curWeight;
+ }
+
+ if(maxWeight - minWeight > 0.01){
+ return maxTone;
+ }else return -1;
+}
+
diff --git a/PitchTracker/pitchTracker.h b/PitchTracker/pitchTracker.h
new file mode 100644
index 00000000..99b477b0
--- /dev/null
+++ b/PitchTracker/pitchTracker.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#ifndef dywapitchtrack__H
+#define dywapitchtrack__H
+
+#define DllExport extern "C" __declspec(dllexport)
+
+DllExport void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
+DllExport void DeInit();
+DllExport int GetTone(double *samples, int sampleCt, float *weights);
+
+typedef void (__stdcall * LogCallback)(const char* text);
+static LogCallback Log;
+DllExport void SetLogCallback(LogCallback Callback);
+
+#endif
+
diff --git a/Vocaluxe.sln b/Vocaluxe.sln
index 347f685a..0298c529 100644
--- a/Vocaluxe.sln
+++ b/Vocaluxe.sln
@@ -9,6 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocalu
{EC5167E4-CCFB-4CEE-987C-CF816F1062A3} = {EC5167E4-CCFB-4CEE-987C-CF816F1062A3}
{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}
{5A4053F1-5AD5-441F-B254-D97A088127B6} = {5A4053F1-5AD5-441F-B254-D97A088127B6}
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A} = {54A48AF7-515C-4EDD-B395-2BFFA096050A}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VocaluxeLib", "VocaluxeLib\VocaluxeLib.csproj", "{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}"
@@ -25,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerLib", "ClientServerLi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebserverInitalConfig", "WebserverInitalConfig\WebserverInitalConfig.csproj", "{55F89808-4E79-4FFE-BC13-48258913F5C9}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PitchTracker", "PitchTracker\PitchTracker.vcxproj", "{54A48AF7-515C-4EDD-B395-2BFFA096050A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
DebugLinux|x64 = DebugLinux|x64
@@ -191,6 +194,26 @@ Global
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.Build.0 = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.ActiveCfg = Release|Any CPU
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.Build.0 = Release|Any CPU
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x64.ActiveCfg = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x64.Build.0 = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x86.ActiveCfg = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugLinux|x86.Build.0 = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x64.ActiveCfg = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x64.Build.0 = Debug|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x86.ActiveCfg = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.DebugWin|x86.Build.0 = Debug|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x64.ActiveCfg = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x64.Build.0 = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x86.ActiveCfg = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.InstallerWin|x86.Build.0 = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x64.ActiveCfg = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x64.Build.0 = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x86.ActiveCfg = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseLinux|x86.Build.0 = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x64.ActiveCfg = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x64.Build.0 = Release|x64
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x86.ActiveCfg = Release|Win32
+ {54A48AF7-515C-4EDD-B395-2BFFA096050A}.ReleaseWin|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Vocaluxe/Lib/Sound/Record/CBuffer.cs b/Vocaluxe/Lib/Sound/Record/CBuffer.cs
index 7aece259..70334af4 100644
--- a/Vocaluxe/Lib/Sound/Record/CBuffer.cs
+++ b/Vocaluxe/Lib/Sound/Record/CBuffer.cs
@@ -1,9 +1,29 @@
-#define TEST_PITCH
+#region license
+// This file is part of Vocaluxe.
+//
+// Vocaluxe is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Vocaluxe is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Vocaluxe. If not, see .
+#endregion
+
+#define TEST_PITCH
+#define USE_NATIVE_DETECTION
+//If defined, it uses a library with native code that speeds up detection by a factor of 10
using System;
using System.IO;
#if TEST_PITCH
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Windows.Forms;
using VocaluxeLib;
@@ -11,16 +31,29 @@ using VocaluxeLib;
namespace Vocaluxe.Lib.Sound.Record
{
+#if USE_NATIVE_DETECTION
+ static class CPitchTracker
+ {
+ [DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
+
+ [DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void DeInit();
+
+ [DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int GetTone(double[] samples, int sampleCt, float[] weights);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ public delegate void LogCallback(string message);
+
+ [DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern void SetLogCallback(LogCallback c);
+ }
+#endif
+
class CBuffer : IDisposable
{
- public enum EAnalyzeFunction
- {
- AutoCorrelation, //Faster, more resistent to noise, good value for HalfToneMax=38 (higher->wrong results in test case, WHY?) with 38 no wrong values in test case
- Amdf //Average magnitude difference, slower, detects everything in range -> HalfToneMax=45
- }
-
- private delegate double DAnalyzeTone(int tone);
-
+ private static int _InitCount;
//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)
@@ -34,9 +67,18 @@ namespace Vocaluxe.Lib.Sound.Record
private readonly double[] _AnalysisBuffer = new double[_AnalysisBufLen];
private readonly byte[] _AnalysisByteBuffer = new byte[_AnalysisByteBufLen]; //tmp buffer (stream->tmpBuffer->(Int16)AnalysisBuffer)
- //Precalculated table holding sample# per period for each tone (actually we may not use the lower few entries, but keep it to avoid index modification
+ private readonly float[] _TmpWeights = new float[NumHalfTones]; //tmp buffer for weights (gets copied to ToneWeight when checked)
+#if !USE_NATIVE_DETECTION
+ //Precalculated table holding sample# per period for each tone (actually we may not use the lower few entries, but keep it to avoid index modification
private static readonly double[] _SamplesPerPeriodPerTone = new double[_HalfToneMax + 1];
- private readonly float[] _TmpWeight = new float[NumHalfTones]; //tmp buffer for weights (gets copied to ToneWeight when checked)
+
+ public enum EAnalyzeFunction
+ {
+ AutoCorrelation, //Faster, more resistent to noise, good value for HalfToneMax=38 (higher->wrong results in test case, WHY?) with 38 no wrong values in test case
+ Amdf //Average magnitude difference, slower, detects everything in range -> HalfToneMax=45
+ }
+ private delegate double DAnalyzeTone(int tone);
+
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable ConvertToConstant.Global
// ReSharper disable FieldCanBeMadeReadOnly.Global
@@ -48,7 +90,7 @@ namespace Vocaluxe.Lib.Sound.Record
private DAnalyzeTone _AnalyzeToneFunc;
private double _MinWeightDiff;
// ReSharper restore FieldCanBeMadeReadOnly.Local
-
+#endif
private double _MaxVolume;
private bool _NewSamples;
@@ -56,9 +98,11 @@ namespace Vocaluxe.Lib.Sound.Record
public CBuffer()
{
+ _Init();
MinVolume = 0.02f;
ToneWeigth = new float[NumHalfTones];
Reset();
+#if !USE_NATIVE_DETECTION
if (AnalyzeFunction == EAnalyzeFunction.Amdf)
{
_AnalyzeToneFunc = _GetAmdf;
@@ -69,19 +113,32 @@ namespace Vocaluxe.Lib.Sound.Record
_AnalyzeToneFunc = _GetAutoCorrelation;
_MinWeightDiff = 0.0001;
}
+#endif
#if TEST_PITCH
_TestPitchDetection();
#endif
}
- static CBuffer()
+ ~CBuffer()
{
- //Init Array to avoid costly calculations
+ _Dispose();
+ }
+
+ private static void _Init()
+ {
+ _InitCount++;
+ if (_InitCount > 1)
+ return; //Do init only once
+#if USE_NATIVE_DETECTION
+ CPitchTracker.Init(_BaseToneFreq, _HalfToneMin, _HalfToneMax);
+#else
+ //Init Array to avoid costly calculations
for (int toneIndex = 0; toneIndex <= _HalfToneMax; toneIndex++)
{
double freq = _BaseToneFreq * Math.Pow(_HalftoneBase, toneIndex);
_SamplesPerPeriodPerTone[toneIndex] = 44100.0 / freq; // samples in one period
}
+#endif
}
public int ToneAbs { get; private set; }
@@ -98,7 +155,7 @@ namespace Vocaluxe.Lib.Sound.Record
public float[] ToneWeigth { get; private set; }
///
- /// Minimum volume for a tone to be valid
+ /// Minimum volume for a tone to be valid
///
public float MinVolume { get; set; }
@@ -183,7 +240,11 @@ namespace Vocaluxe.Lib.Sound.Record
private void _AnalyzeTones()
{
- // prepare to analyze
+#if USE_NATIVE_DETECTION
+ int maxTone = CPitchTracker.GetTone(_AnalysisBuffer, _AnalysisBufLen, _TmpWeights);
+ if (maxTone >= 0)
+#else
+ // prepare to analyze
double maxWeight = -1.0;
double minWeight = 1.0;
int maxTone = -1;
@@ -206,12 +267,13 @@ namespace Vocaluxe.Lib.Sound.Record
if (curWeight < minWeight)
minWeight = curWeight;
- _TmpWeight[toneIndex - _HalfToneMin] = (float)curWeight;
+ _TmpWeights[toneIndex - _HalfToneMin] = (float)curWeight;
}
if (maxWeight - minWeight > _MinWeightDiff)
+#endif
{
- Array.Copy(_TmpWeight, ToneWeigth, NumHalfTones);
+ Array.Copy(_TmpWeights, ToneWeigth, NumHalfTones);
ToneAbs = maxTone;
//Console.WriteLine(maxTone);
@@ -222,6 +284,7 @@ namespace Vocaluxe.Lib.Sound.Record
ToneValid = false;
}
+#if !USE_NATIVE_DETECTION
private double _GetAutoCorrelation(int tone)
{
double samplesPerPeriodD = _SamplesPerPeriodPerTone[tone]; // samples in one period
@@ -269,17 +332,29 @@ namespace Vocaluxe.Lib.Sound.Record
accumDist += dist;
}
//Use analyzed sample count here. BufLen yields more errors
- return 1.0 - (double)accumDist / Int16.MaxValue / sampleIndex;
+ return 1.0 - accumDist / Int16.MaxValue / sampleIndex;
}
+#endif
public void Dispose()
+ {
+ _Dispose();
+ GC.SuppressFinalize(this);
+ }
+
+ private void _Dispose()
{
if (_Stream != null)
{
_Stream.Dispose();
_Stream = null;
}
- GC.SuppressFinalize(this);
+#if USE_NATIVE_DETECTION
+ Debug.Assert(_InitCount > 0);
+ _InitCount--;
+ if (_InitCount == 0)
+ CPitchTracker.DeInit();
+#endif
}
#if TEST_PITCH