Remove C++/Cli version and replace with P/Invoke wrapper to support all platforms
This commit is contained in:
1 parent
e54892391f
commit
ae9f8bb30a
9 files changed
+283
-100
No files matched your search
+12
-11
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -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" />
|
||||
|
||||
@@ -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
@@ -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);
|
||||
};
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
Reference in new issue
Block a user