Interop C++/CLI noob:System.AccessViolationException
我正试图在5天内为我女儿高中的职业生涯日准备一个“酷炫的演示”,所以我正试图用它来执行空中传送(OTA)音频识别。我从来没有真正的比“Hello World”在C++中做得更远,我尝试用C++/CLI来封装ECHOPLUNT代码库,这样我就可以从C++调用它。这是我的头文件:Interop C++/CLI noob:System.AccessViolationException,interop,c++-cli,native,access-violation,Interop,C++ Cli,Native,Access Violation,我正试图在5天内为我女儿高中的职业生涯日准备一个“酷炫的演示”,所以我正试图用它来执行空中传送(OTA)音频识别。我从来没有真正的比“Hello World”在C++中做得更远,我尝试用C++/CLI来封装ECHOPLUNT代码库,这样我就可以从C++调用它。这是我的头文件: // echoprint-cli.h #pragma once #include "Codegen.h"; using namespace System; namespace echoprintcli {
// 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);
};
}
我想象它在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);
}
void美白::Init(){
int i;
_p=40;
_R=(浮动*)malloc((_p+1)*浮动大小);
对于EchoNest论坛上承诺的(i=0;i,以下是我的方法。如果修改codegen.dll并提供合适的导出函数,您可以更轻松地使用CLI
要在codegen中添加main.cxx
,请添加以下方法:
extern "C" __declspec(dllexport) void GetCodeStringFromPcm(const float* pcm, uint numSamples, int start_offset, BSTR* sResultString)
{
// pcm: a buffer of floats, mono, 11025 Hz
Codegen * pCodegen = new Codegen(pcm, numSamples, start_offset);
string code = pCodegen->getCodeString();
// http://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t
std::wstring ws(code.size(), L' '); // Overestimate number of code points.
ws.resize(mbstowcs(&ws[0], code.c_str(), code.size())); // Shrink to fit.
*sResultString = SysAllocStringLen(ws.data(), ws.size());
}
现在在C#端,您可以简单地执行以下操作:
/// <summary>
/// Generates audio fringerprint for usage with Echonest.
/// </summary>
/// <param name="pcm">const float*, 4 byte per float in C++</param>
[DllImport("codegen.dll")]
private static extern void GetCodeStringFromPcm(float[] pcm, uint numSamples, int start_offset, [MarshalAs(UnmanagedType.BStr)] ref string sResultString);
//
///生成用于Echonest的音频边缘打印。
///
//const浮点*,C++中的每个浮点4字节
[DllImport(“codegen.dll”)]
private static extern void GetCodeStringFromPcm(float[]pcm,uint numSamples,int start_offset,[MarshalAs(UnmanagedType.BStr)]ref string sResultString);
现在,对于第一个参数,您只需要这个特殊的浮点缓冲区。您提到已经有了一个,但作为对所有拥有其他格式音频数据的人的奖励,下面是一种将几乎所有音频文件转换为正确的浮点缓冲区的方法。要求如下:
使用BassLib=Un4seen.Bass.Bass;
使用BassMix=Un4seen.Bass.AddOn.Mix.BassMix;
///
///使用codegen.dll为音频曲目创建指纹代码。
///
公共字符串GetCodeStringFromFile(字符串文件名)
{
//读取输入流
int streamIn=BassLib.BASS_StreamCreateFile(文件名,0,0,Un4seen.BASS.basslafg.BASS_STREAM_DECODE);
if(streamIn==0)返回null;
//新的混音器流,允许我们读取浮点样本。EchoNest需要单声道数据。
int mixerStream=BassMix.BASS_Mixer_StreamCreate(targetSampleRate,1,Un4seen.BASS.bassfagal.BASS_STREAM_DECODE | Un4seen.BASS.bassfagal.BASS_SAMPLE_FLOAT);
BassMix.BASS_Mixer_StreamAddChannel(混音器流、streamIn、Un4seen.BASS.BASSFlag.BASS_STREAM_解码| Un4seen.BASS.BASSFlag.BASS_Mixer_DOWNMIX);
long bufferSizeInBytes=BassLib.BASS_ChannelSeconds2Bytes(混音器流,0.1f);
double totalSeconds=BassLib.BASS_ChannelBytes2秒(streamIn,BassLib.BASS_ChannelGetLength(streamIn));
//以任何需要的方式使用进度数据。
int progress=0;
List resultData=新列表();
while(true)
{
浮点[]数据=新浮点[bufferSizeInBytes/4];
int readBytes=BassLib.BASS_ChannelGetData(混音器流,数据,(int)缓冲大小字节);
如果(readBytes当您调试到本机代码时会发生什么?您是否在项目设置中打开了“本机调试”?您好,floele,请您向我提供经过编辑的DLL,因为我在编译该DLL时遇到很多问题project@alizx当然,这里下载,这里是ENMFP和Echoprint签名生成器dll都有相同的codegen.dll名称?这让我有点困惑!!@alixx不确定它们是否具有相同的DLL名称。但我创建的DLL仅用于EchoPrint。您好(您知道)您是否使用Windows CLI通过EchoPrint标记或检索文件?谢谢!
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();
}
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);
}
extern "C" __declspec(dllexport) void GetCodeStringFromPcm(const float* pcm, uint numSamples, int start_offset, BSTR* sResultString)
{
// pcm: a buffer of floats, mono, 11025 Hz
Codegen * pCodegen = new Codegen(pcm, numSamples, start_offset);
string code = pCodegen->getCodeString();
// http://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t
std::wstring ws(code.size(), L' '); // Overestimate number of code points.
ws.resize(mbstowcs(&ws[0], code.c_str(), code.size())); // Shrink to fit.
*sResultString = SysAllocStringLen(ws.data(), ws.size());
}
/// <summary>
/// Generates audio fringerprint for usage with Echonest.
/// </summary>
/// <param name="pcm">const float*, 4 byte per float in C++</param>
[DllImport("codegen.dll")]
private static extern void GetCodeStringFromPcm(float[] pcm, uint numSamples, int start_offset, [MarshalAs(UnmanagedType.BStr)] ref string sResultString);
using BassLib = Un4seen.Bass.Bass;
using BassMix = Un4seen.Bass.AddOn.Mix.BassMix;
/// <summary>
/// Creates a fingerprint code for an audio track, using the codegen.dll.
/// </summary>
public string GetCodeStringFromFile(string fileName)
{
// Read input stream
int streamIn = BassLib.BASS_StreamCreateFile(fileName, 0, 0, Un4seen.Bass.BASSFlag.BASS_STREAM_DECODE);
if (streamIn == 0) return null;
// New mixer stream that allows us to read floating point samples. EchoNest requires mono data.
int mixerStream = BassMix.BASS_Mixer_StreamCreate(targetSampleRate, 1, Un4seen.Bass.BASSFlag.BASS_STREAM_DECODE | Un4seen.Bass.BASSFlag.BASS_SAMPLE_FLOAT);
BassMix.BASS_Mixer_StreamAddChannel(mixerStream, streamIn, Un4seen.Bass.BASSFlag.BASS_STREAM_DECODE | Un4seen.Bass.BASSFlag.BASS_MIXER_DOWNMIX);
long bufferSizeInBytes = BassLib.BASS_ChannelSeconds2Bytes(mixerStream, 0.1f);
double totalSeconds = BassLib.BASS_ChannelBytes2Seconds(streamIn, BassLib.BASS_ChannelGetLength(streamIn));
// Use progress data in whatever way you need it.
int progress = 0;
List<float> resultData = new List<float>();
while (true)
{
float[] data = new float[bufferSizeInBytes / 4];
int readBytes = BassLib.BASS_ChannelGetData(mixerStream, data, (int)bufferSizeInBytes);
if (readBytes <= 0) break;
for (int i = 0; i < readBytes / 4; i++)
{
resultData.Add(data[i]);
}
double secondsPos = BassLib.BASS_ChannelBytes2Seconds(mixerStream, BassLib.BASS_ChannelGetPosition(mixerStream));
progress = (int)(secondsPos / totalSeconds * 100);
}
BassLib.BASS_StreamFree(streamIn);
BassLib.BASS_StreamFree(mixerStream);
// We need to pass an array of samples to C.
float[] resultArray = resultData.ToArray();
// Clear list to prevent occupying too much memory.
resultData.Clear();
// Marshaller will pass float[] just fine to C.
string resultCodegenData = string.Empty;
GetCodeStringFromPcm(resultArray, (uint)resultArray.Length, 0, ref resultCodegenData);
return resultCodegenData;
}