Interop C++/CLI noob:System.AccessViolationException

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 {

我正试图在5天内为我女儿高中的职业生涯日准备一个“酷炫的演示”,所以我正试图用它来执行空中传送(OTA)音频识别。我从来没有真正的比“Hello World”在C++中做得更远,我尝试用C++/CLI来封装ECHOPLUNT代码库,这样我就可以从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);
    };
}
我想象它在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;
}