WaveInProc / Windows Audio Question

I use the Windows API to receive audio input. I followed all the steps in MSDN and was able to record audio to a WAV file. No problems. I use several buffers and all that. I would like to do more with buffers than just writing to a file, so now I have a callback set. It works fine, and I get the data, but I'm not sure what to do with it as soon as it appears.

Here is my callback ... everything works here:

// Media API callback void CALLBACK AudioRecorder::waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { // Data received if (uMsg == WIM_DATA) { // Get wav header LPWAVEHDR mBuffer = (WAVEHDR *)dwParam1; // Now what? for (unsigned i = 0; i != mBuffer->dwBytesRecorded; ++i) { // I can see the char, how do get them into my file and audio buffers? cout << mBuffer->lpData[i] << "\n"; } // Re-use buffer mResultHnd = waveInAddBuffer(hWaveIn, mBuffer, sizeof(mInputBuffer[0])); // mInputBuffer is a const WAVEHDR * } } // waveInOpen cannot use an instance method as its callback, // so we create a static method which calls the instance version void CALLBACK AudioRecorder::staticWaveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { // Call instance version of method reinterpret_cast<AudioRecorder *>(dwParam1)->waveInProc(hWaveIn, uMsg, dwInstance, dwParam1, dwParam2); } 

As I said, it works fine, but I'm trying to do the following:

  • Convert data to short and copy to array
  • Convert data to float and copy to array
  • Copy the data to a char array, which I will write in WAV
  • Transferring data to an arbitrary output device

I worked a lot with FMOD, and I am familiar with interleaving and all that. But FMOD offers everything that floats. In this case, I go the other way. I guess I'm just looking for resources to go from LPSTR to short, float and unsigned char.

Thank you very much!

+4
source share
3 answers
 typedef struct { LPSTR lpData; // etc.. } WAVEHDR; 

Well, uncomfortable type there. This, of course, is not STR, it must be PVOID. Just add it to whatever type you need:

 short* data = (short*)(mBuffer->lpData); unsigned samples = mBuffer->dwBytesRecorded / sizeof(short); // etc.. 
+2
source

I have done all this, but this is too much information to explain it all in detail here. I suggest you take a look at the source code of PortAudio : this is a pretty good implementation of MME, although some parts are too confusing for mine, but it contains everything you need, including conversions.

  • data conversion: it depends on your input format. The MME buffer stores everything in char *, but this does not mean that the actual patterns are characters. They can be 8, 16, 24, 32 (int or float) or 64 bits (float). Converting from one whole to another with different sizes is usually done using a simple bit shift. Converting an integer to a float is done by converting an integer to a float using a simple cast, than dividing it by the maximum value of that integer to get a number from -1.0 to 1.0. This is also called normalization. You can also add smoothing to all these transformations.
  • data buffering: you do not want to spend a lot of time on a callback or flush buffers, so disk I / O is not performed in the callback. Imo a circular buffer combined with a producer / consumer pattern is most convenient for solving this issue: the buffer is filled (using simple memcpy, which is pretty fast) in the MME callback, which then signals another thread. After reporting that the stream checks how much data is in the buffer, and writes it to the file if it is enough (you do not want to write small fragments to the file every time, instead, expect a large piece of data and upload it once). This way you separate slow disk I / O from the callback.
  • get data for device output: just like you have waveInProc, you will have waveOutProc for output. In this callback, you must write the data to be output to the buffer.
+2
source

Convert 8/16/32 bit / array of samples to float-array:

 void src_BYTE_to_float_array(const unsigned char* in, float* out, int len) { while (len) { len--; out[len]= (float) (in [len] / (1.0 * 0x80) -1.0); } } void src_short_to_float_array(const short* in, float* out, int len) { while (len) { len--; out[len]= (float) (in [len] / (1.0 * 0x8000)) ; } } void src_int_to_float_array(const int* in, float* out, int len) { while (len) { len--; out[len]= (float) (in [len] / (8.0 * 0x10000000)) ; } } 

To reproduce the samples, you will need to do the opposite:

 void src_float_to_BYTE_array(const float* in, unsigned char* out, int len) { double scaled_value; while (len) { len--; scaled_value= in[len] * (8.0 * 0x10000000); if (scaled_value >= (1.0 * 0x7FFFFFFF)) { out[len]= 255; continue ; } out[len]= (unsigned char)((lrint(scaled_value) >> 24) + 0x80); } } void src_float_to_short_array(const float* in, short* out, int len) { double scaled_value; while (len) { len--; scaled_value= in[len] * (8.0 * 0x10000000); if (scaled_value >= (1.0 * 0x7FFFFFFF)) { out[len]= 32767; continue ; } out[len]= (short)(lrint(scaled_value) >> 16); } } void src_float_to_int_array(const float* in, int* out, int len) { double scaled_value; while (len) { len--; scaled_value= in[len] * (8.0 * 0x10000000); if (scaled_value >= (1.0 * 0x7FFFFFFF)) { out[len]= 0x7fffffff; continue; } out[len]= lrint(scaled_value); } } 
+2
source

Source: https://habr.com/ru/post/1334733/


All Articles