2

私は娘のジュニアでのキャリアデーのための「クールなデモ」をまとめようとしています。5日間で高値になるため、エコープリントライブラリを使用して無線(OTA)オーディオ認識を実行しようとしています。私はC++の「helloworld」よりもはるかに遠くまで行ったことがなく、C ++ /CLIを使用してechoprintcodegenライブラリをラップし、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マイククラスを使用して音声を録音しています。これはbyte[]の配列を返すので、バイトをfloatに変換してから、ラッパーを介して次のように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 2010SP1またはVS11ソリューションとして入手できます:https ://github.com/developmentalmadness/echoprint-net/tree/3c48d3783136188bfa213d3e9fd1ebea0f151bed

そのURLは、現在問題が発生しているリビジョンを指している必要があります。

編集 私はここで提案を試しました:C ++/CLIからC++-DLLを呼び出すときのAccessViolation

#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;
    }
}

それでもアクセス違反が発生しますが、デバッガーがクラッシュした後、ネイティブコードにドロップしました(自分でそこに到達する方法がわかりません)。そして、コンストラクター内で爆撃します。ポインター(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

デバッグできなければ、スタックを2つのステップでたどることしかできません。

    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);
}
4

1 に答える 1