Note that there are some explanatory texts on larger screens.

plurals
  1. PORecording an audio stream in C# from C++ ASIO library
    primarykey
    data
    text
    <p>I need to find the best way to record an audio stream. I have already built the low level code in C++ and interfaced parts of it to C#.</p> <p>So i have a C++ callback that gives me an array of array of floats - the audio signal. At the moment, my C++ lib is recording the data straight to the file in the wav format and it just notify my C# app when it ends recording.</p> <p>But, I would like to have more interactivity on the UI side, like 'infinite' progress bar, amount of the data recorded, cancel button etc, and since it's gonna be a minute at worst, maybe it's better to keep it in memory. I know very little about .NET and C# memory management, so i don't know how to make it efficiently.</p> <p>Is there any fast resizable container in C#, where i could just put the data inside and later access it like an array?</p> <p>I also would like to build a waveform image off it. I already have those things done in C++, but somehow i don't like the idea to write too much messaging, transfer objects etc.</p> <p>So to put things together:</p> <ol> <li><p>I have C++ unmanaged callback that does some stuff and from within i'd like to call C# method once it has processed the data, the C prototype would be:</p> <p>void process(float **signal, int n); (usually [2][n] - for stereo)</p> <p>What would be C# equivalent and how do i call it from that C++ callback ?</p></li> <li><p>What is the best class to write continuous stream to (like mem.put(float[][] data, int size) ) and then read it as an array or with other easy way (to save a wav file from it for example or make a waveform bitmap)</p></li> <li><p>Is there going to be a significant performance loss if i do it in C#? (managed c++ wrapper calling c# function etc... and probably some DSP stuff) or i am just paranoid ? :)</p></li> </ol> <p>Cheers,</p> <p>pablox</p> <h2>My solution</h2> <p>Ok i solved it that way:</p> <p>In my C++ header file i got transfer structure:</p> <pre><code>public ref struct CVAudio { public: float *left; float *right; int length; }; </code></pre> <p>Then in managed C++ class i have declared:</p> <pre><code>delegate void GetAudioData([In, Out] CVAudio^ audio); </code></pre> <p>Then i can use it as an argument to the method that initialize audio:</p> <pre><code>void initializeSoundSystem(void *HWnd, GetAudioData ^audio); </code></pre> <p>That delegate has also a C prototype of </p> <pre><code>typedef void (CALLBACK *GETAUDIODATA)(CVAudio ^a); </code></pre> <p>Which is used in the internal C++ class as:</p> <pre><code>void initializeSoundSystem(HWND HWnd, GETAUDIODATA audio); </code></pre> <p>Then body of the first method is:</p> <pre><code>void VDAudio::initializeSoundSystem(void *HWnd, GetAudioData ^audio) { HWND h = (HWND) HWnd; acb = audio; pin_ptr&lt;GetAudioData ^&gt; tmp = &amp;audio; IntPtr ip = Marshal::GetFunctionPointerForDelegate(audio); GETAUDIODATA cb = static_cast&lt;GETAUDIODATA&gt;(ip.ToPointer()); audioObserver-&gt;initializeSoundSystem(h, cb); } </code></pre> <p>Body of audioObserver just stores that callback in the object and do some audio related things.</p> <p>Callback is then called in the processing method like that:</p> <pre><code> VDAudio^ a = gcnew VDAudio(); a-&gt;left = VHOST-&gt;Master-&gt;getSample()[0]; //returns left channel float* a-&gt;right = VHOST-&gt;Master-&gt;getSample()[1]; a-&gt;length = length; (*callback)(a); </code></pre> <p>And the body of C# delegate:</p> <pre><code>public void GetSamples(CVAudio audio) { unsafe { float* l = (float*)audio.left; float* r = (float*)audio.right; if (l != null) { SamplePack sample = new SamplePack(); sample.left = new float[audio.length]; sample.right = new float[audio.length]; IntPtr lptr = new IntPtr((void*)l); IntPtr rptr = new IntPtr((void*)r); Marshal.Copy(lptr, sample.left, 0, audio.length); Marshal.Copy(rptr, sample.right, 0, audio.length); this.Dispatcher.Invoke(new Action(delegate() { GetSamples(sample); })); } } } </code></pre> <p>So probably that's not a best code around - i have no idea. Only can say it works, doesn't seem to leak etc. :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload