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