Problem mit WaveIn
-
Ich will ein Osziloskop programmieren und das ganze funktioniert auch soweit ganz gut. Ich hol mir die Daten vom Mikrophon per WaveIn, komischerweise funktioniert dies Allerdings nicht richtig. Der Zeitliche Abstand zwischen 2 WM_DATA messages ist zu groß,müsste eigenltich ungefähr 33,3 ms betragen da ich mit 22050 Samples pro Sekunde aufnehme und ein Buffer 735 Samples groß ist. Außerdem kommt noch hinzu das die Buffer in einer nicht logischen Reihenfolge wieder an mein Programm zurückgegeben werden. Müsste ja eigenltich bei Double-Buffering 1.2.1.2.1.2... sein, sieht aber eher so aus 1.2.1.1.1.2.2.2.1.1.1.2.2.2.1.1.2.2..
Die Routine die die Daten ausliest und den Buffer wieder in die Schlange hängt braucht allerdings nur 0.05 ms wobei sie eigentlich 33,3 ms Zeit hätte, daran kann es also auch nicht liegen. Eine vergrößerung / Verkleinerung des Buffers bringt auch keine Besserung, es dauert im Durchschnitt immer 10 ms länger bis eine Buffer-Full message eintrifft als es eigentlich der Fall sein dürfte.
Der Umstieg von einer Callback-Funktion auf einen Callback-Thread hat leider auch keine Besserung gebracht.
Das Programm könnt ihr euch anschauen unter
http://stuff.benjamin-thaut.de/jf-cpp.zip
Mit F4 startet ihr die Aufnahme und mit F5 beendet ihr sie wieder, per ESC gehts aus dem Programm raus.Ich Probier jetzt scho an die 10h an diesem Problem rum hab es auch schon mit 3 Buffern versucht und was weiß ich sonst noch was, bringt nichts. Wäre nett wenn ihr mir sagen könntet wo mein Fehler liegt.
Hier noch der Quellcode
Soundin.h#ifndef _SOUNDIN_H_ #define _SOUNDIN_H_ class soundin { public: bool recording; bool init_done; char fault[256]; int BufferSize; //Record @ 60 FPS int SampleRate; short int fps; short int *buffer1;//Buffer 1 short int *buffer2;//Buffer 2 short int *buffer3;//Buffer 3 DWORD WINAPI (*CallbackFunc)(LPVOID arg); float LastDataBlock,CurrentDataBlock,DataBlockNormTime,TimeDifference; FILE *debugtxt; HWAVEIN InputDevice; WAVEFORMATEX format; WAVEHDR WaveInHdr1; WAVEHDR WaveInHdr2; MMRESULT result; DWORD CallbackThread; unsigned short number_DataOutFuncs; std::vector<BaseDataIn*> DataOut; //Funktionen soundin(int BufferSizeIn,int SampleRateIn, short int fps); ~soundin(); void AddSoundDataOut(BaseDataIn*); bool StartRecording(); void StopRecording(); }; #endifSoundin.cpp
#include <windows.h> #include <stdio.h> #include <gl/gl.h> #include <gl/glu.h> #include <vector> #include "waveview.h" #include "thengine.h" #include "soundin.h" extern renderer *render1; DWORD WINAPI SoundInProc(LPVOID arg){ MSG msg; float start,stop; short int *temp; unsigned short i,rest; soundin *klasse; FILE *debugtxt; WAVEHDR* data; while (GetMessage(&msg, 0, 0, 0) == 1) { switch(msg.message){ case MM_WIM_DATA: data = (WAVEHDR*) msg.lParam; if(data){ klasse = (soundin*) data->dwUser; if(klasse){ if(klasse->number_DataOutFuncs > 0){ klasse->CurrentDataBlock = render1->TimerGetTime(); start = klasse->CurrentDataBlock; klasse->TimeDifference = klasse->CurrentDataBlock - klasse->LastDataBlock; //Daten aus der Struktur auslesen temp = new short int[klasse->BufferSize]; for(i=0;i<data->dwBytesRecorded/2;i++){ temp[i] = data->lpData[i]; } if(klasse->recording){ //Do we need to add headers? //Header leeren und wieder anhängen /*data->dwBufferLength = klasse->BufferSize*2; data->dwBytesRecorded=0; data->dwUser = 0L; data->dwFlags = 0L; data->dwLoops = 0L; klasse->result = waveInPrepareHeader(klasse->InputDevice, data, sizeof(WAVEHDR)); if (klasse->result) { waveInGetErrorText(klasse->result, klasse->fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error preparing Buffer on the run: %s\n",klasse->fault); fprintf(debugtxt,"BufferLength=%i,BufferSize=%i\n",data->dwBufferLength,data->dwBytesRecorded); fclose(debugtxt); }*/ klasse->result = waveInAddBuffer(klasse->InputDevice, data, sizeof(WAVEHDR)); if (klasse->result) { waveInGetErrorText(klasse->result, klasse->fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error Adding Buffer on the run: %s\n",klasse->fault); fclose(debugtxt); } } /*rest = data->dwBytesRecorded/2 - i; //restliche bytes null setzten for(i=rest;i<data->dwBytesRecorded/2;i++){ temp[i] = 0; }*/ //allen erwähnten DataOut Funnktionen die Daten übergeben for(i=0;i<klasse->number_DataOutFuncs;i++){ klasse->DataOut[i]->DataIn(temp); } //Speicher freigeben delete temp; stop = render1->TimerGetTime(); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Buffer 0x%X in %.2f\n",msg.lParam,stop-start); if(klasse->TimeDifference > klasse->DataBlockNormTime){ fprintf(debugtxt,"Critical Time between Buffers(%X): %.4f\n",msg.lParam,klasse->TimeDifference); fclose(debugtxt); } klasse->LastDataBlock = klasse->CurrentDataBlock; } } } continue; case MM_WIM_CLOSE: /* Terminate this thread (by return'ing) */ break; } } return(0); } soundin::soundin(int BufferSizeIn,int SampleRateIn, short int fps){ HANDLE TempHandle; debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"soundin(%i,%i,%i)\n",BufferSizeIn,SampleRateIn,fps); fclose(debugtxt); SampleRate = SampleRateIn; BufferSize = SampleRate / fps; DataBlockNormTime = 1000 / fps; format.wFormatTag=WAVE_FORMAT_PCM; // simple, uncompressed format format.nChannels=1; // 1=mono, 2=stereo format.nSamplesPerSec=SampleRate; // 44100 format.nAvgBytesPerSec=SampleRate*2; // = nSamplesPerSec * n.Channels * wBitsPerSample/8 format.nBlockAlign=2; // = n.Channels * wBitsPerSample/8 format.wBitsPerSample=16; // 16 for high quality, 8 for telephone-grade format.cbSize=0; //Set Callbackfunc CallbackFunc = SoundInProc; TempHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)CallbackFunc, 0, 0, &CallbackThread); if (!TempHandle) { debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Can't create WAVE recording thread! -- %08X\n", GetLastError()); fclose(debugtxt); init_done = false; } CloseHandle(TempHandle); //Create Our Buffers buffer1 = new short int[BufferSize]; buffer2 = new short int[BufferSize]; //Set Recording false recording = false; number_DataOutFuncs = 0; result = waveInOpen(&InputDevice, WAVE_MAPPER ,&format, (DWORD)CallbackThread, 0, CALLBACK_THREAD); if(result){ waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error Opening Sound In: %s\n",fault); fclose(debugtxt); init_done = false; } else init_done = true; // Set up and prepare first header for input WaveInHdr1.lpData = (LPSTR)buffer1; WaveInHdr1.dwBufferLength = BufferSize*2; WaveInHdr1.dwBytesRecorded=0; WaveInHdr1.dwUser = (DWORD)this; WaveInHdr1.dwFlags = 0L; WaveInHdr1.dwLoops = 0L; result = waveInPrepareHeader(InputDevice, &WaveInHdr1, sizeof(WAVEHDR)); if (result) { waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error preparing Buffer 1: %s\n",fault); fprintf(debugtxt,"BufferLength=%i,BufferSize=%i\n",WaveInHdr1.dwBufferLength,WaveInHdr1.dwBytesRecorded); fclose(debugtxt); recording=false; init_done=false; } // Set up and prepare second header for input WaveInHdr2.lpData = (LPSTR)buffer2; WaveInHdr2.dwBufferLength = BufferSize*2; WaveInHdr2.dwBytesRecorded=0; WaveInHdr2.dwUser = (DWORD)this; WaveInHdr2.dwFlags = 0L; WaveInHdr2.dwLoops = 0L; result = waveInPrepareHeader(InputDevice, &WaveInHdr2, sizeof(WAVEHDR)); if (result) { waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error preparing Buffer 1: %s\n",fault); fclose(debugtxt); recording=false; init_done = false; } } soundin::~soundin(){ if(recording && init_done){ recording=false; result = waveInReset(InputDevice); if(result){ waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error resetting SoundIn: %s\n",fault); fclose(debugtxt); init_done = false; } } if(init_done){ Sleep(100); waveInUnprepareHeader(InputDevice, &WaveInHdr1, sizeof(WAVEHDR)); waveInUnprepareHeader(InputDevice, &WaveInHdr2, sizeof(WAVEHDR)); result = waveInClose(InputDevice); if(result){ waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error closing SoundIn: %s\n",fault); fclose(debugtxt); init_done = false; } } delete buffer1; delete buffer2; } bool soundin::StartRecording(){ if(init_done && !recording){ recording = true; LastDataBlock=render1->TimerGetTime(); // Insert Buffers //Buffer 1 result = waveInAddBuffer(InputDevice, &WaveInHdr1, sizeof(WAVEHDR)); if (result) { waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error Adding Buffer 1: %s\n",fault); fclose(debugtxt); recording=false; return false; } //Buffer 2 result = waveInAddBuffer(InputDevice, &WaveInHdr2, sizeof(WAVEHDR)); if (result) { waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error Adding Buffer 2: %s\n",fault); fclose(debugtxt); recording=false; return false; } // Start Recording result = waveInStart(InputDevice); if (result) { waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error Start Recording: %s\n",fault); fclose(debugtxt); recording=false; return false; } return true; } else return false; } void soundin::StopRecording(){ if(recording && init_done){ recording = false; result = waveInReset(InputDevice); if(result){ waveInGetErrorText(result, fault, 256); debugtxt = fopen("debug.txt","a"); fprintf(debugtxt,"Error resetting SoundIn: %s\n",fault); fclose(debugtxt); init_done = false; } } } void soundin::AddSoundDataOut(BaseDataIn* klasse){ number_DataOutFuncs++; DataOut.push_back(klasse); }Bei dieser Version ensteht ab und zu ein Fehler beim Herunterfahren des Programms, allerdings ist das nicht mein Problem.