我正在尝试为我女儿的 jr. 的职业日准备一个“很酷的演示”。5 天内很高,所以我正在尝试使用echoprint 库来执行无线 (OTA) 音频识别。我从来没有真正比 C++ 中的“hello world”走得更远,我正在尝试使用 C++/CLI 来包装 echoprint codegen 库,以便我可以从 C# 调用它。这是我的头文件:
// echoprint-cli.h
#pragma once
#include "Codegen.h";
using namespace System;
namespace echoprintcli {
public ref class CodegenCLI
{
public:
String^ getCodeString(array<float>^ buffer, unsigned int samples, int start_offset);
};
}
这是我的实现:
#include "stdafx.h"
#include <msclr\marshal_cppstd.h>
#include "echoprint-cli.h"
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
namespace echoprintcli {
String^ CodegenCLI::getCodeString(array<float>^ buffer, unsigned int samples, int start_offset){
String^ result = String::Empty;
if(buffer->Length > 0){
GCHandle h = GCHandle::Alloc(buffer, System::Runtime::InteropServices::GCHandleType::Pinned);
try{
float* pcm = (float*)(void*)h.AddrOfPinnedObject();
Codegen* codegen = new Codegen(pcm, samples, start_offset); //System.AccessViolationException here
std::string code;
try{
code = codegen->getCodeString();
}finally{
delete codegen;
}
result = marshal_as<String^>(code);
}
finally{
h.Free();
}
}
return result;
}
}
我正在使用 XNA 麦克风类来录制音频。它返回一个字节 [] 数组,因此我将字节转换为浮点数,然后通过我的包装器将其传递给 Codegen 类,如下所示(C#):
var mic = Microphone.Default;
Log(String.Format("Using '{0}' as audio input...", mic.Name));
var buffer = new byte[mic.GetSampleSizeInBytes(TimeSpan.FromSeconds(22))];
int bytesRead = 0;
string fileName = String.Empty;
try
{
mic.Start();
try
{
Log(String.Format("{0:HH:mm:ss} Start recording audio stream...", DateTime.Now));
while (bytesRead < buffer.Length)
{
Thread.Sleep(1000);
var bytes = mic.GetData(buffer, bytesRead, (buffer.Length - bytesRead));
Log(String.Format("{0:HH:mm:ss} Saving {1} bytes to stream...", DateTime.Now, bytes));
bytesRead += bytes;
}
Log(String.Format("{0:HH:mm:ss} Finished recording audio stream...", DateTime.Now));
}
finally
{
mic.Stop();
}
Func<byte, float> convert = (b) => System.Convert.ToSingle(b);
var converter = new Converter<byte, float>(convert);
float[] pcm = Array.ConvertAll<byte, float>(buffer, converter);
Log(String.Format("{0:HH:mm:ss} Generating audio fingerprint...", DateTime.Now));
var codeg = new CodegenCLI();
String code = codeg.getCodeString(pcm, (uint)pcm.Length, 0);
但是当我的 C++/CLI 方法 (getCodeString) 调用本机方法时,我得到了 Sysetem.AccessViolationException。
整个源代码在 github 上作为 VS 2010 SP1 或 VS 11 解决方案提供:https ://github.com/developmentalmadness/echoprint-net/tree/3c48d3783136188bfa213d3e9fd1ebea0f151bed
该 URL 应指向当前遇到问题的修订版。
编辑 我在这里尝试了这个建议:AccessViolation,当从 C++/CLI 调用 C++-DLL 时
#include "stdafx.h"
#include <msclr\marshal_cppstd.h>
#include "echoprint-cli.h"
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
namespace echoprintcli {
String^ CodegenCLI::getCodeString(array<float>^ buffer, unsigned int samples, int start_offset){
String^ result = String::Empty;
IntPtr p = Marshal::AllocHGlobal(buffer->Length * sizeof(float));
try{
pin_ptr<float> pcm = static_cast<float*>(p.ToPointer());
Codegen* codegen = new Codegen(pcm, samples, start_offset); // System.AccessViolationException here
std::string code;
try{
code = codegen->getCodeString();
}finally{
delete codegen;
}
result = marshal_as<String^>(code);
}
finally{
Marshal::FreeHGlobal(p);
}
return result;
}
}
而且我仍然遇到访问冲突,但是在调试器崩溃后将我放到本机代码中(我不知道自己如何到达那里)。它在ctor内部爆炸。指针 (pcm) 的地址值为 0.0000000,但除了在此处显示源代码之外,我不知道如何自己调试代码:
Codegen::Codegen(const float* pcm, unsigned int numSamples, int start_offset) {
if (Params::AudioStreamInput::MaxSamples < (uint)numSamples)
throw std::runtime_error("File was too big\n");
Whitening *pWhitening = new Whitening(pcm, numSamples); //System.AccessViolationException
由于无法调试,我只能假设遵循堆栈两个步骤:
Whitening::Whitening(const float* pSamples, uint numSamples) :
_pSamples(pSamples), _NumSamples(numSamples) {
Init();
}
我想它会在某个地方的 Init() 方法中爆炸:
void Whitening::Init() {
int i;
_p = 40;
_R = (float *)malloc((_p+1)*sizeof(float));
for (i = 0; i <= _p; ++i) { _R[i] = 0.0; }
_R[0] = 0.001;
_Xo = (float *)malloc((_p+1)*sizeof(float));
for (i = 0; i < _p; ++i) { _Xo[i] = 0.0; }
_ai = (float *)malloc((_p+1)*sizeof(float));
_whitened = (float*) malloc(sizeof(float)*_NumSamples);
}