Remove C++/Cli version and replace with P/Invoke wrapper to support all platforms

This commit is contained in:
Flamefire committed 2014-03-26 19:52:35 +01:00
1 parent e54892391f
commit ae9f8bb30a
9 files changed
+283 -100

No files matched your search

+12 -11
View File
@@ -1,9 +1,6 @@
#pragma once
#include "pitch.hh"
#include "PitchWrapper.h"
#pragma managed(push, off)
#include <stdlib.h>
#include <cmath>
@@ -43,19 +40,23 @@ void freeDoubleArray(double* floats){
free(floats);
}
#pragma managed(pop)
double ToneToNote(const Tone* tone){
return 12.0 * std::log(tone->freq / 127.09) / std::log(2.0) + 27.5 - 16; // 16 = C2
}
/*
namespace Native{
namespace PitchTracking{
CTone^ ConvertToneToManaged(Tone tone){
CTone^ ConvertToneToManaged(Tone* tone){
CTone^ result = gcnew CTone();
result->Freq = tone.freq;
result->DB = tone.db;
result->Stabledb = tone.stabledb;
result->Age = static_cast<int>(tone.age);
result->NoteExact = 12.0 * std::log(tone.freq / 127.09) / std::log(2.0) + 27.5 - 16; // 16 = C2
result->Freq = tone->freq;
result->DB = tone->db;
result->Stabledb = tone->stabledb;
result->Age = static_cast<int>(tone->age);
result->NoteExact = 12.0 * std::log(tone->freq / 127.09) / std::log(2.0) + 27.5 - 16; // 16 = C2
result->Note = static_cast<int>(std::round(result->NoteExact));
return result;
}
}
}
}
*/
+1 -14
View File
@@ -170,20 +170,7 @@
<ClCompile Include="compatibility.cpp" />
<ClCompile Include="pitch.cc" />
<ClCompile Include="pitchTracker.cpp" />
<ClCompile Include="PitchWrapper.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</CompileAsManaged>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</CompileAsManaged>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</CompileAsManaged>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</CompileAsManaged>
<MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</MinimalRebuild>
<MinimalRebuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</MinimalRebuild>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExceptionHandling>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExceptionHandling>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExceptionHandling>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExceptionHandling>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="PitchWrapper.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="compatibility.h" />
+79 -6
View File
@@ -1,10 +1,82 @@
#include "PitchWrapper.h"
#pragma managed(push, off)
#include "pitchTracker.h"
#pragma managed(pop)
#include "Helper.h"
void PtFast_Init(double baseToneFrequency, int minHalfTone, int maxHalfTone){
PitchTracker::Init(baseToneFrequency, minHalfTone, maxHalfTone);
}
void PtFast_DeInit(){
PitchTracker::DeInit();
}
int PtFast_GetTone(short* samples, int sampleCt, float* weights){
if(sampleCt <= 0)
return -1;
double* dataDouble = short2DoubleArray(samples, sampleCt, false);
int result = PitchTracker::GetTone(dataDouble, sampleCt, weights, true);
freeDoubleArray(dataDouble);
return result;
}
Analyzer* Analyzer_Create(double rate, unsigned step){
return new Analyzer(rate, "", step);
}
void Analyzer_Free(Analyzer* analyzer){
if(analyzer)
delete analyzer;
}
void Analyzer_InputFloat(Analyzer* analyzer, float* data, int sampleCt){
if(sampleCt == 0 || !analyzer)
return;
analyzer->input(data, data + sampleCt);
}
void Analyzer_InputShort(Analyzer* analyzer, short* data, int sampleCt){
if(sampleCt == 0 || !analyzer)
return;
float* dataFloat = short2FloatArray(data, sampleCt);
analyzer->input(dataFloat, dataFloat + sampleCt);
freeFloatArray(dataFloat);
}
void Analyzer_InputByte(Analyzer* analyzer, char* data, int sampleCt){
if(sampleCt == 0 || !analyzer)
return;
float* dataFloat = short2FloatArray(static_cast<short*>(static_cast<void*>(data)), sampleCt);
analyzer->input(dataFloat, dataFloat + sampleCt);
freeFloatArray(dataFloat);
}
void Analyzer_Process(Analyzer* analyzer){
if(!analyzer)
return;
analyzer->process();
}
double Analyzer_GetPeak(Analyzer* analyzer){
if(!analyzer)
return -999;
return analyzer->getPeak();
}
double Analyzer_FindNote(Analyzer* analyzer, double minFreq, double maxFreq){
if(!analyzer)
return -1;
const Tone* tone = analyzer->findTone(minFreq, maxFreq);
return (tone == NULL) ? -1 : ToneToNote(tone);
}
bool Analyzer_OutputFloat(Analyzer* analyzer, float* data, int sampleCt, float rate){
if(!analyzer)
return false;
return analyzer->output(data, data + sampleCt, rate);
}
/*
namespace Native{
namespace PitchTracking{
@@ -31,7 +103,7 @@ namespace Native{
if(data->Length == 0)
return;
pin_ptr<Byte> dataPtr = &data[0];
float* dataFloat = short2FloatArray(static_cast<short*>(static_cast<void*>(dataPtr)), data->Length);
float* dataFloat = short2FloatArray(static_cast<short*>(static_cast<void*>(dataPtr)), data->Length / 2);
m_analyzer->input(dataFloat, dataFloat + data->Length);
freeFloatArray(dataFloat);
}
@@ -64,7 +136,7 @@ namespace Native{
CTone^ CAnalyzer::FindTone(double minFreq, double maxFreq){
const Tone* tone = m_analyzer->findTone(minFreq, maxFreq);
return (tone == NULL) ? nullptr : ConvertToneToManaged(*tone);
return (tone == NULL) ? nullptr : ConvertToneToManaged(tone);
}
void CAnalyzer::Output(array<float>^ data, float rate){
@@ -98,4 +170,5 @@ namespace Native{
return result;
}
}
}
}
*/
+63 -54
View File
@@ -1,63 +1,72 @@
#pragma once
#pragma managed(push, off)
#include "pitch.hh"
#pragma managed(pop)
using namespace System;
using namespace System::Collections::Generic;
#define DllExport extern "C" __declspec(dllexport)
namespace Native{
namespace PitchTracking{
public ref class CTone {
public:
static const int MAXHARM = 48; ///< The maximum number of harmonics tracked
static const int MINAGE = 2; ///< The minimum age required for a tone to be output
double Freq; ///< Frequency (Hz)
double DB; ///< Level (dB)
double Stabledb; ///< Stable level, useful for graphics rendering
int Age; ///< How many times the tone has been detected in row
double NoteExact;
int Note;
/// Less-than compare by levels (instead of frequencies like operator< does)
static bool dbCompare(CTone l, CTone r) { return l.DB < r.DB; }
};
DllExport void PtFast_Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
DllExport void PtFast_DeInit();
DllExport int PtFast_GetTone(short* samples, int sampleCt, float* weights);
public ref class CAnalyzer {
public:
CAnalyzer(double rate, String^ id) {
m_analyzer = new Analyzer(rate,"");
m_id = id;
}
CAnalyzer(double rate, String^ id, unsigned step) {
m_analyzer = new Analyzer(rate,"",step);
m_id = id;
}
~CAnalyzer() { this->!CAnalyzer(); }
!CAnalyzer() { delete m_analyzer; }
DllExport Analyzer* Analyzer_Create(double rate, unsigned step);
DllExport void Analyzer_Free(Analyzer* analyzer);
DllExport void Analyzer_InputFloat(Analyzer* analyzer, float* data, int sampleCt);
DllExport void Analyzer_InputShort(Analyzer* analyzer, short* data, int sampleCt);
DllExport void Analyzer_InputByte(Analyzer* analyzer, char* data, int sampleCt);
DllExport void Analyzer_Process(Analyzer* analyzer);
DllExport double Analyzer_GetPeak(Analyzer* analyzer);
DllExport double Analyzer_FindNote(Analyzer* analyzer, double minFreq, double maxFreq);
DllExport bool Analyzer_OutputFloat(Analyzer* analyzer, float* data, int sampleCt, float rate);
void Input(array<float>^ data);
void Input(array<short>^ data);
void Input(array<Byte>^ data);
void Process();
double GetPeak();
array<CTone^>^ GetTones();
CTone^ FindTone();
CTone^ FindTone(double minFreq);
CTone^ FindTone(double minFreq, double maxFreq);
void Output(array<float>^ data, float rate);
String^ GetId();
/*
public ref class CTone {
public:
static const int MAXHARM = 48; ///< The maximum number of harmonics tracked
static const int MINAGE = 2; ///< The minimum age required for a tone to be output
double Freq; ///< Frequency (Hz)
double DB; ///< Level (dB)
double Stabledb; ///< Stable level, useful for graphics rendering
int Age; ///< How many times the tone has been detected in row
double NoteExact;
int Note;
/// Less-than compare by levels (instead of frequencies like operator< does)
static bool dbCompare(CTone l, CTone r) { return l.DB < r.DB; }
};
private:
Analyzer* m_analyzer;
String^ m_id;
};
public ref class CPitchTracker abstract sealed{
public:
static void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
static void DeInit();
static int GetTone(array<short>^ samples, array<float>^ weights);
};
public ref class CAnalyzer {
public:
CAnalyzer(double rate, String^ id) {
m_analyzer = new Analyzer(rate,"");
m_id = id;
}
}
CAnalyzer(double rate, String^ id, unsigned step) {
m_analyzer = new Analyzer(rate,"",step);
m_id = id;
}
~CAnalyzer() { this->!CAnalyzer(); }
!CAnalyzer() { delete m_analyzer; }
void Input(array<float>^ data);
void Input(array<short>^ data);
void Input(array<Byte>^ data);
void Process();
double GetPeak();
array<CTone^>^ GetTones();
CTone^ FindTone();
CTone^ FindTone(double minFreq);
CTone^ FindTone(double minFreq, double maxFreq);
void Output(array<float>^ data, float rate);
String^ GetId();
private:
Analyzer* m_analyzer;
String^ m_id;
};
public ref class CPitchTracker abstract sealed{
public:
static void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
static void DeInit();
static int GetTone(array<short>^ samples, array<float>^ weights);
};
*/
+5 -3
View File
@@ -48,14 +48,15 @@ Analyzer::Analyzer(double rate, std::string id, std::size_t step):
}
}
void Analyzer::output(float* begin, float* end, double rate) {
bool Analyzer::output(float* begin, float* end, double rate) {
constexpr unsigned a = 2;
const unsigned size = m_passthrough.size();
const unsigned out = static_cast<unsigned>((end - begin) / 2 /* stereo */);
if (out == 0) return;
if (out == 0) return false;
const unsigned in = static_cast<unsigned>(m_resampleFactor * (m_rate / rate) * out + 2 * a /* lanczos kernel */ + 5 /* safety margin for rounding errors */);
float pcm[m_passthrough.capacity];
m_passthrough.read(pcm, pcm + in + 4);
if(!m_passthrough.read(pcm, pcm + in + 4))
return false;
for (unsigned i = 0; i < out; ++i) {
double s = 0.0;
unsigned k = static_cast<unsigned>(m_resamplePos);
@@ -77,6 +78,7 @@ void Analyzer::output(float* begin, float* end, double rate) {
m_passthrough.pop(num);
m_resampleFactor = 0.99 * m_resampleFactor + 0.01 * (size > 700 ? 1.02 : 0.98);
}
return true;
}
+1 -1
View File
@@ -108,7 +108,7 @@ public:
return best;
}
/** Give data away for mic pass-through */
void output(float* begin, float* end, double rate);
bool output(float* begin, float* end, double rate);
/** Returns the id (color name) of the mic */
std::string const& getId() const { return m_id; }
+117
View File
@@ -0,0 +1,117 @@
using System;
using System.Runtime.InteropServices;
namespace Vocaluxe.Lib.Sound.Record
{
class CAnalyzer : IDisposable
{
#region Imports
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Analyzer_Create(double rate, uint step);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Analyzer_Free(IntPtr analyzer);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Analyzer_InputFloat(IntPtr analyzer, float[] data, int sampleCt);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Analyzer_InputShort(IntPtr analyzer, short[] data, int sampleCt);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Analyzer_InputByte(IntPtr analyzer, byte[] data, int sampleCt);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Analyzer_Process(IntPtr analyzer);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern double Analyzer_GetPeak(IntPtr analyzer);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern double Analyzer_FindNote(IntPtr analyzer, double minFreq, double maxFreq);
[DllImport("PitchTracker.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool Analyzer_OutputFloat(IntPtr analyzer, [Out] float[] data, int sampleCt, float rate);
#endregion
private IntPtr _Instance;
public CAnalyzer(double rate = 44100.0, uint step = 200)
{
_Instance = Analyzer_Create(rate, step);
}
~CAnalyzer()
{
_Dispose(false);
}
public void Input(float[] data)
{
Analyzer_InputFloat(_Instance, data, data.Length);
}
public void Input(short[] data)
{
Analyzer_InputShort(_Instance, data, data.Length);
}
public void Input(byte[] data)
{
Analyzer_InputByte(_Instance, data, data.Length / 2);
}
public void Process()
{
Analyzer_Process(_Instance);
}
public double GetPeak()
{
return Analyzer_GetPeak(_Instance);
}
public double FindNote(double minFreq = 35.0, double maxFreq = 1000.0)
{
return Analyzer_FindNote(_Instance, minFreq, maxFreq);
}
public bool Output(float[] data, float rate)
{
return Analyzer_OutputFloat(_Instance, data, data.Length, rate);
}
private void _Dispose(bool disposing)
{
if (_Instance == IntPtr.Zero)
throw new ObjectDisposedException(GetType().Name);
Analyzer_Free(_Instance);
_Instance = IntPtr.Zero;
}
public void Dispose()
{
_Dispose(true);
GC.SuppressFinalize(this);
}
}
static class CFastAnalyzer
{
#region Imports
[DllImport("PitchTracker.dll", EntryPoint = "PtFast_Init", CallingConvention = CallingConvention.Cdecl)]
public static extern void Init(double baseToneFrequency, int minHalfTone, int maxHalfTone);
[DllImport("PitchTracker.dll", EntryPoint = "PtFast_DeInit", CallingConvention = CallingConvention.Cdecl)]
public static extern void DeInit();
[DllImport("PitchTracker.dll", EntryPoint = "PtFast_GetTone", CallingConvention = CallingConvention.Cdecl)]
private static extern int PtFast_GetTone(short[] samples, int sampleCt, float[] weights);
#endregion
public static int GetTone(short[] samples, float[] weights)
{
return PtFast_GetTone(samples, samples.Length, weights);
}
}
}
+4 -7
View File
@@ -22,10 +22,7 @@
using System;
using System.IO;
using System.Diagnostics;
#if USE_NATIVE_DETECTION
using Native.PitchTracking;
#endif
#if TEST_PITCH
using System.Windows.Forms;
using VocaluxeLib;
@@ -74,7 +71,7 @@ namespace Vocaluxe.Lib.Sound.Record
private double _MinWeightDiff;
// ReSharper restore FieldCanBeMadeReadOnly.Local
#else
private readonly CAnalyzer _Analyzer = new CAnalyzer(44100.0, "");
private readonly CAnalyzer _Analyzer = new CAnalyzer();
#endif
private double _MaxVolume;
private bool _NewSamples;
@@ -115,7 +112,7 @@ namespace Vocaluxe.Lib.Sound.Record
if (_InitCount > 1)
return; //Do init only once
#if USE_NATIVE_DETECTION
CPitchTracker.Init(_BaseToneFreq, _HalfToneMin, _HalfToneMax);
CFastAnalyzer.Init(_BaseToneFreq, _HalfToneMin, _HalfToneMax);
#else
//Init Array to avoid costly calculations
for (int toneIndex = 0; toneIndex <= _HalfToneMax; toneIndex++)
@@ -239,7 +236,7 @@ namespace Vocaluxe.Lib.Sound.Record
private void _AnalyzeTones()
{
#if USE_NATIVE_DETECTION
int maxTone = CPitchTracker.GetTone(_AnalysisBuffer, _TmpWeights);
int maxTone = CFastAnalyzer.GetTone(_AnalysisBuffer, _TmpWeights);
if (maxTone >= 0)
#else
// prepare to analyze
@@ -350,7 +347,7 @@ namespace Vocaluxe.Lib.Sound.Record
Debug.Assert(_InitCount > 0);
_InitCount--;
if (_InitCount == 0)
CPitchTracker.DeInit();
CFastAnalyzer.DeInit();
#endif
}
+1 -4
View File
@@ -199,10 +199,6 @@
<Reference Include="OpenTK.GLControl">
<HintPath>..\Output\OpenTK.GLControl.dll</HintPath>
</Reference>
<Reference Include="PitchTracker">
<HintPath>..\Output\x64\PitchTracker.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="PortAudioSharp, Version=0.19.3.27472, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Output\PortAudioSharp.dll</HintPath>
@@ -227,6 +223,7 @@
<Compile Include="Lib\Sound\Playback\OpenAL\COpenAlStream.cs" />
<Compile Include="Lib\Sound\Playback\PortAudio\CPortAudioStream.cs" />
<Compile Include="Lib\Sound\CPortAudioHandle.cs" />
<Compile Include="Lib\Sound\Record\CAnalyzer.cs" />
<Compile Include="Lib\Sound\Record\CBuffer.cs" />
<Compile Include="Base\CConfig.cs" />
<Compile Include="Base\CCover.cs" />