question audio waveInProc / Windows

J’utilise l’API Windows pour obtenir une entrée audio. J’ai suivi toutes les étapes sur MSDN et j’ai réussi à enregistrer de l’audio dans un fichier WAV. Aucun problème. J’utilise plusieurs tampons et tout ça. Je voudrais faire plus avec les tampons que simplement écrire dans un fichier, donc maintenant j’ai un callback configuré. Cela fonctionne très bien et j’obtiens les données, mais je ne sais pas quoi en faire une fois que je les ai.

Voici mon rappel … tout fonctionne ici:

// 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 <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(dwParam1)->waveInProc(hWaveIn, uMsg, dwInstance, dwParam1, dwParam2); } 

Comme je l’ai dit, cela fonctionne très bien, mais j’essaie de faire ce qui suit:

  • Convertir les données en abrégé et les copier dans un tableau
  • Convertir les données pour flotter et copier dans un tableau
  • Copiez les données dans un tableau de caractères plus grand que je vais écrire dans un fichier WAV
  • Relayer les données sur un périphérique de sortie arbitraire

J’ai beaucoup travaillé avec FMOD et je suis familier avec l’entrelacement et tout ça. Mais le FMOD fait tout pour devenir des flotteurs. Dans ce cas, je vais dans l’autre sens. Je suppose que je cherche essentiellement des ressources sur comment passer du LPSTR au caractère court, flottant et non signé.

Merci beaucoup d’avance!

 typedef struct { LPSTR lpData; // etc.. } WAVEHDR; 

Hmya, type maladroit là-bas. Ce n’est pas une STR bien sûr, cela aurait dû être un PVOID. Il suffit de le lancer sur le type dont vous avez besoin:

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

J’ai fait tout cela mais c’est juste trop d’informations pour tout expliquer en détail ici. Je vous suggère de regarder le code source de PortAudio : c’est une très bonne implémentation de MME, bien que certaines parties soient un peu trop compliquées à mon goût, mais elles contiennent tout ce que vous recherchez, y compris les conversions.

  • convertir les données: cela dépend de votre format de saisie. Le tampon MME stocke tout dans un caractère *, mais cela ne signifie pas que les échantillons réels sont des caractères. Ils peuvent être 8, 16, 24, 32 (int ou float) ou 64 bit (float). La conversion d’un entier à un autre de taille différente se fait généralement à l’aide d’un simple décalage. La conversion d’un entier en flottant se fait généralement en convertissant d’abord l’entier en flottant en utilisant une dissortingbution simple, puis en le divisant par la valeur maximale de cet entier afin d’obtenir un nombre compris entre -1,0 et 1,0. Cela s’appelle aussi la normalisation. Vous pouvez également append le tramage à toutes ces conversions.
  • mise en mémoire tampon des données: vous ne voulez pas passer trop de temps dans le rappel ou vous supprimez des tampons, donc les E / S disque dans le rappel ne sont pas effectuées. Imo un tampon circulaire combiné avec un pattern producteur / consommateur est le plus pratique pour résoudre ce problème: le tampon est rempli (en utilisant un simple memcpy qui est assez rapide) dans le callback MME, qui signale ensuite un autre thread. Lorsque vous êtes averti que le thread vérifie la quantité de données dans le tampon et l’écrit dans un fichier s’il est suffisant (vous ne voulez pas écrire de petits morceaux à chaque fois, attendez plutôt une grande partie des données et videz-le immediatement). De cette façon, vous séparez les E / S de disque lentes du rappel.
  • récupérer les données sur le périphérique de sortie: tout comme vous avez un waveInProc, vous aurez un waveOutProc pour la sortie. Dans ce rappel, vous êtes censé écrire les données à sortir dans le tampon.

Tableau de conversion 8/16/32 bits / échantillon en 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)) ; } } 

Pour jouer les samples, vous devrez faire le contraire:

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