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();
    };
    
    #endif
    

    Soundin.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.


Anmelden zum Antworten