From d27972cc4209d004a32059bc56f423da5fce809d Mon Sep 17 00:00:00 2001 From: Volker Ruppert Date: Fri, 6 Feb 2015 15:57:26 +0000 Subject: [PATCH] =?UTF-8?q?Implemented=20support=20for=20the=20new=20mixer?= =?UTF-8?q?=20thread=20in=20the=20lowlevel=20sound=20module=20'win'.=20-?= =?UTF-8?q?=20removed=20disabled=20code=20for=20the=20sndPlaySound()=20fun?= =?UTF-8?q?ction.=20-=20removed=20now=20obsolete=20buffer=20ring=20for=20w?= =?UTF-8?q?ave=20output.=20-=20The=20new=20mothod=20waveout()=20is=20drive?= =?UTF-8?q?n=20by=20the=20mixer=20thread.=20For=20the=20best=20results=20?= =?UTF-8?q?=20=20you=20need=20to=20disable=20the=20'realtime'=20sychroniza?= =?UTF-8?q?tion=20and=20to=20find=20out=20a=20usable=20=20=20IPS=20va?= =?UTF-8?q?=C3=B6ue.=20The=20mixer=20also=20polls=20data=20from=20the=20sp?= =?UTF-8?q?eaker=20beep=20generator=20and=20=20=20the=20OPL3=20FM=20genera?= =?UTF-8?q?tor.=20-=20TODO:=20Code=20cleanup=20in=20soundwin.cc,=20impleme?= =?UTF-8?q?ntation=20in=20other=20sound=20modules.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bochs/iodev/sound/soundwin.cc | 341 ++++++++-------------------------- bochs/iodev/sound/soundwin.h | 28 +-- 2 files changed, 83 insertions(+), 286 deletions(-) diff --git a/bochs/iodev/sound/soundwin.cc b/bochs/iodev/sound/soundwin.cc index 7b6602f1f..1da03c25a 100644 --- a/bochs/iodev/sound/soundwin.cc +++ b/bochs/iodev/sound/soundwin.cc @@ -42,7 +42,6 @@ bx_sound_windows_c::bx_sound_windows_c() WaveInOpen = 0; ismidiready = 1; - iswaveready = 1; // size is the total size of the midi header and buffer and the // BX_SOUND_WINDOWS_NBUF wave header and buffers, all aligned @@ -67,11 +66,7 @@ bx_sound_windows_c::bx_sound_windows_c() MidiHeader = (LPMIDIHDR) NEWBUFFER(sizeof(MIDIHDR)); MidiData = (LPSTR) NEWBUFFER(BX_SOUND_WINDOWS_MAXSYSEXLEN); - for (int bufnum=0; bufnumdwFlags = WHDR_DONE; - - head = 0; - tailfull = 0; - tailplay = 0; - needreopen = 0; -#endif - set_pcm_params(real_pcm_param); + pcm_callback_id = register_wave_callback(this, pcm_callback); + BX_INIT_MUTEX(mixer_mutex); + start_mixer_thread(); return BX_SOUNDLOW_OK; } -int bx_sound_windows_c::playnextbuffer() +int bx_sound_windows_c::set_pcm_params(bx_pcm_param_t param) { UINT ret; PCMWAVEFORMAT waveformat; - int bufnum; - // if the format is different, we have to reopen the device, - // so reset it first - if (needreopen != 0) - if (WaveOutOpen != 0) - ret = waveOutReset(hWaveOut); + BX_DEBUG(("set_pcm_params(): %u, %u, %u, %02x", param.samplerate, param.bits, + param.channels, param.format)); + if (WaveOutOpen != 0) { + ret = waveOutReset(hWaveOut); + ret = waveOutClose(hWaveOut); + WaveOutOpen = 0; + } - // clean up the buffers and mark if output is ready - checkwaveready(); + // try three times to find a suitable format + for (int tries = 0; tries < 3; tries++) { + int frequency = real_pcm_param.samplerate; + bx_bool stereo = real_pcm_param.channels == 2; + int bits = real_pcm_param.bits; + int bps = (bits / 8) * (stereo + 1); - // do we have to play anything? - if (tailplay == head) - return BX_SOUNDLOW_OK; + waveformat.wf.wFormatTag = WAVE_FORMAT_PCM; + waveformat.wf.nChannels = stereo + 1; + waveformat.wf.nSamplesPerSec = frequency; + waveformat.wf.nAvgBytesPerSec = frequency * bps; + waveformat.wf.nBlockAlign = bps; + waveformat.wBitsPerSample = bits; - // if the format is different, we have to close and reopen the device - // or, just open the device if it's not open yet - if ((needreopen != 0) || (WaveOutOpen == 0)) - { - if (WaveOutOpen != 0) - { - ret = waveOutClose(hWaveOut); - WaveOutOpen = 0; - } - - // try three times to find a suitable format - for (int tries = 0; tries < 3; tries++) - { - int frequency = WaveInfo[0].frequency; - bx_bool stereo = WaveInfo[0].stereo; - int bits = WaveInfo[0].bits; -// int format = WaveInfo[0].format; - int bps = (bits / 8) * (stereo + 1); - - waveformat.wf.wFormatTag = WAVE_FORMAT_PCM; - waveformat.wf.nChannels = stereo + 1; - waveformat.wf.nSamplesPerSec = frequency; - waveformat.wf.nAvgBytesPerSec = frequency * bps; - waveformat.wf.nBlockAlign = bps; - waveformat.wBitsPerSample = bits; - - ret = waveOutOpen(&(hWaveOut), WaveDevice, (LPWAVEFORMATEX)&(waveformat.wf), 0, 0, CALLBACK_NULL); - if (ret != 0) - { - char errormsg[4*MAXERRORLENGTH+1]; - waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1); - BX_DEBUG(("waveOutOpen: %s", errormsg)); - switch (tries) { + ret = waveOutOpen(&(hWaveOut), WaveDevice, (LPWAVEFORMATEX)&(waveformat.wf), 0, 0, CALLBACK_NULL); + if (ret != 0) { + char errormsg[4*MAXERRORLENGTH+1]; + waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1); + BX_DEBUG(("waveOutOpen: %s", errormsg)); + switch (tries) { case 0: // maybe try a different frequency if (frequency < 15600) frequency = 11025; @@ -293,180 +252,46 @@ int bx_sound_windows_c::playnextbuffer() case 2: // nope, doesn't work BX_ERROR(("Couldn't open wave output device (error = %d)!", ret)); return BX_SOUNDLOW_ERR; - } - - BX_DEBUG(("The format was: wFormatTag=%d, nChannels=%d, nSamplesPerSec=%d,", - waveformat.wf.wFormatTag, waveformat.wf.nChannels, waveformat.wf.nSamplesPerSec)); - BX_DEBUG((" nAvgBytesPerSec=%d, nBlockAlign=%d, wBitsPerSample=%d", - waveformat.wf.nAvgBytesPerSec, waveformat.wf.nBlockAlign, waveformat.wBitsPerSample)); } - else - { - WaveOutOpen = 1; - needreopen = 0; - break; - } - } - } - for (bufnum=tailplay; bufnum != head; - bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK, tailplay=bufnum) - { - BX_DEBUG(("Playing buffer %d", bufnum)); - - // prepare the wave header - WaveHeader[bufnum]->lpData = WaveData[bufnum]; - WaveHeader[bufnum]->dwBufferLength = length[bufnum]; - WaveHeader[bufnum]->dwBytesRecorded = length[bufnum]; - WaveHeader[bufnum]->dwUser = 0; - WaveHeader[bufnum]->dwFlags = 0; - WaveHeader[bufnum]->dwLoops = 1; - - ret = waveOutPrepareHeader(hWaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum])); - if (ret != 0) - { - BX_ERROR(("waveOutPrepareHeader(): error = %d", ret)); - return BX_SOUNDLOW_ERR; - } - - ret = waveOutWrite(hWaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum])); - if (ret != 0) - { - char errormsg[4*MAXERRORLENGTH+1]; - waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1); - BX_ERROR(("waveOutWrite(): %s", errormsg)); + BX_DEBUG(("The format was: wFormatTag=%d, nChannels=%d, nSamplesPerSec=%d,", + waveformat.wf.wFormatTag, waveformat.wf.nChannels, waveformat.wf.nSamplesPerSec)); + BX_DEBUG((" nAvgBytesPerSec=%d, nBlockAlign=%d, wBitsPerSample=%d", + waveformat.wf.nAvgBytesPerSec, waveformat.wf.nBlockAlign, waveformat.wBitsPerSample)); + } else { + WaveOutOpen = 1; + break; } } return BX_SOUNDLOW_OK; } -int bx_sound_windows_c::set_pcm_params(bx_pcm_param_t param) +int bx_sound_windows_c::waveout(int length, Bit8u data[]) { - BX_DEBUG(("set_pcm_params(): %u, %u, %u, %02x", param.samplerate, param.bits, - param.channels, param.format)); - -#ifdef usewaveOut - // check if any of the properties have changed - if ((WaveInfo[0].frequency != param.samplerate) || - (WaveInfo[0].bits != param.bits) || - (WaveInfo[0].stereo != (param.channels == 2)) || - (WaveInfo[0].format != param.format)) - { - needreopen = 1; - - // store the current settings to be used by sendwavepacket() - WaveInfo[0].frequency = param.samplerate; - WaveInfo[0].bits = param.bits; - WaveInfo[0].stereo = (param.channels == 2); - WaveInfo[0].format = param.format; - } -#endif - -#ifdef usesndPlaySnd - int bps = (param.bits / 8) * param.channels; - LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData[0]; - - memcpy(header->RIFF, "RIFF", 4); - memcpy(header->TYPE, "WAVE", 4); - memcpy(header->chnk, "fmt ", 4); - header->chnklen = 16; - header->waveformat.wf.wFormatTag = WAVE_FORMAT_PCM; - header->waveformat.wf.nChannels = param.channels; - header->waveformat.wf.nSamplesPerSec = param.samplerate; - header->waveformat.wf.nAvgBytesPerSec = param.samplerate * bps; - header->waveformat.wf.nBlockAlign = bps; - header->waveformat.wBitsPerSample = param.bits; - memcpy(header->chnk2, "data", 4); -#endif - - return BX_SOUNDLOW_OK; -} - -int bx_sound_windows_c::sendwavepacket(int length, Bit8u data[], bx_pcm_param_t *src_param) -{ - int len2; -#ifdef usewaveOut - int bufnum; -#endif -#ifdef usesndPlaySnd UINT ret; -#endif - BX_DEBUG(("sendwavepacket(%d, %p)", length, data)); + // prepare the wave header + WaveOutHdr->lpData = (LPSTR)data; + WaveOutHdr->dwBufferLength = length; + WaveOutHdr->dwBytesRecorded = length; + WaveOutHdr->dwUser = 0; + WaveOutHdr->dwFlags = 0; + WaveOutHdr->dwLoops = 1; - if (memcmp(src_param, &emu_pcm_param, sizeof(bx_pcm_param_t)) != 0) { - emu_pcm_param = *src_param; - cvt_mult = (src_param->bits == 8) ? 2 : 1; - if (src_param->channels == 1) cvt_mult <<= 1; - if (src_param->samplerate != real_pcm_param.samplerate) { - real_pcm_param.samplerate = src_param->samplerate; - set_pcm_params(real_pcm_param); - } - } - len2 = length * cvt_mult; - -#ifdef usewaveOut - bufnum = head; - - convert_pcm_data(data, length, (Bit8u*)WaveData[bufnum], len2, src_param); - this->length[bufnum] = len2; - - // select next buffer to write to - bufnum++; - bufnum &= BX_SOUND_WINDOWS_NMASK; - - if (((bufnum + 1) & BX_SOUND_WINDOWS_NMASK) == tailfull) - { // this should not actually happen! - BX_ERROR(("Output buffer overflow! Not played. Iswaveready was %d", iswaveready)); - iswaveready = 0; // stop the output for a while + ret = waveOutPrepareHeader(hWaveOut, WaveOutHdr, sizeof(*WaveOutHdr)); + if (ret != 0) { + BX_ERROR(("waveOutPrepareHeader(): error = %d", ret)); return BX_SOUNDLOW_ERR; } - head = bufnum; - - // check if more buffers are available, otherwise stall the emulator - if (((bufnum + 2) & BX_SOUND_WINDOWS_NMASK) == tailfull) - { - BX_DEBUG(("Buffer status: Head %d, TailFull %d, TailPlay %d. Stall.", - head, tailfull, tailplay)); - iswaveready = 0; + ret = waveOutWrite(hWaveOut, WaveOutHdr, sizeof(*WaveOutHdr)); + if (ret != 0) { + char errormsg[4*MAXERRORLENGTH+1]; + waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1); + BX_ERROR(("waveOutWrite(): %s", errormsg)); } - - playnextbuffer(); -#endif - -#ifdef usesndPlaySnd - LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData[0]; - - header->length = len2 + 36; - header->chnk2len = len2; - - convert_wavedata(data, length, (Bit8u*)&(header->data), len2, src_param); - - ret = sndPlaySoundA((LPCSTR) header, SND_SYNC | SND_MEMORY); - if (ret != 0) - { - BX_DEBUG(("sndPlaySoundA: %d", ret)); - } -#endif - - return BX_SOUNDLOW_OK; -} - -int bx_sound_windows_c::stopwaveplayback() -{ - BX_DEBUG(("stopwaveplayback()")); - -#ifdef usewaveOut - // this is handled by checkwaveready() when closing -#endif - -#ifdef usesndPlaySnd - sndPlaySoundA(NULL, SND_ASYNC | SND_MEMORY); - - WaveOpen = 0; -#endif + Sleep(100); return BX_SOUNDLOW_OK; } @@ -475,22 +300,10 @@ int bx_sound_windows_c::closewaveoutput() { BX_DEBUG(("closewaveoutput")); -#ifdef usewaveOut - if (WaveOutOpen == 1) - { + if (WaveOutOpen == 1) { waveOutReset(hWaveOut); - - // let checkwaveready() clean up the buffers - checkwaveready(); - waveOutClose(hWaveOut); - - head = 0; - tailfull = 0; - tailplay = 0; - needreopen = 0; } -#endif return BX_SOUNDLOW_OK; } @@ -505,30 +318,6 @@ void bx_sound_windows_c::checkmidiready() } } -void bx_sound_windows_c::checkwaveready() -{ - int bufnum; - - // clean up all finished buffers and mark them as available - for (bufnum=tailfull; (bufnum != tailplay) && - ((WaveHeader[bufnum]->dwFlags & WHDR_DONE) != 0); - bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK) - { - BX_DEBUG(("Buffer %d done.", bufnum)); - waveOutUnprepareHeader(hWaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum])); - } - - tailfull = bufnum; - - // enable gathering data if a buffer is available - if (((head + 2) & BX_SOUND_WINDOWS_NMASK) != tailfull) - { - BX_DEBUG(("Buffer status: Head %d, TailFull %d, TailPlay %d. Ready.", - head, tailfull, tailplay)); - iswaveready = 1; - } -} - int bx_sound_windows_c::openwaveinput(const char *wavedev, sound_record_handler_t rh) { UNUSED(wavedev); @@ -664,4 +453,24 @@ void bx_sound_windows_c::record_timer(void) record_handler(this, record_packet_size); } +int bx_sound_windows_c::register_wave_callback(void *arg, get_wave_cb_t wd_cb) +{ + if (cb_count < BX_MAX_WAVE_CALLBACKS) { + get_wave[cb_count].device = arg; + get_wave[cb_count].cb = wd_cb; + return cb_count++; + } + return -1; +} + +void bx_sound_windows_c::unregister_wave_callback(int callback_id) +{ + BX_LOCK(mixer_mutex); + if ((callback_id >= 0) && (callback_id < BX_MAX_WAVE_CALLBACKS)) { + get_wave[callback_id].device = NULL; + get_wave[callback_id].cb = NULL; + } + BX_UNLOCK(mixer_mutex); +} + #endif // defined(WIN32) diff --git a/bochs/iodev/sound/soundwin.h b/bochs/iodev/sound/soundwin.h index c0c3f7b43..f3991acee 100644 --- a/bochs/iodev/sound/soundwin.h +++ b/bochs/iodev/sound/soundwin.h @@ -25,10 +25,6 @@ #include -// uncomment one of the following two #defines -//#define usesndPlaySnd -#define usewaveOut - #define BX_SOUND_WINDOWS_MAXSYSEXLEN 256 // maximum supported length of a sysex message #define BX_SOUND_WINDOWS_NBUF 64 // number of buffers for the output, must be power of 2 and >= 4 @@ -171,17 +167,14 @@ public: virtual int get_type() {return BX_SOUNDLOW_WIN;} - virtual int waveready(); - virtual int midiready(); - - virtual int openmidioutput(const char *mididev); - virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]); - virtual int closemidioutput(); + virtual int openmidioutput(const char *mididev); + virtual int midiready(); + virtual int sendmidicommand(int delta, int command, int length, Bit8u data[]); + virtual int closemidioutput(); virtual int openwaveoutput(const char *wavedev); virtual int set_pcm_params(bx_pcm_param_t param); - virtual int sendwavepacket(int length, Bit8u data[], bx_pcm_param_t *src_param); - virtual int stopwaveplayback(); + virtual int waveout(int length, Bit8u data[]); virtual int closewaveoutput(); virtual int openwaveinput(const char *wavedev, sound_record_handler_t rh); @@ -193,6 +186,8 @@ public: static void record_timer_handler(void *); void record_timer(void); + virtual int register_wave_callback(void *, get_wave_cb_t wd_cb); + virtual void unregister_wave_callback(int callback_id); private: struct bx_sound_waveinfo_struct { int frequency; @@ -214,26 +209,19 @@ private: HANDLE DataHandle; // returned by GlobalAlloc() Bit8u *DataPointer; // returned by GlobalLock() - LPWAVEHDR WaveHeader[BX_SOUND_WINDOWS_NBUF]; - LPSTR WaveData[BX_SOUND_WINDOWS_NBUF]; + LPWAVEHDR WaveOutHdr; LPWAVEHDR WaveInHdr; LPSTR WaveInData; bx_bool recording; - int length[BX_SOUND_WINDOWS_NBUF]; // length of the data in the buffer - int needreopen; // if the format has changed - int head,tailfull,tailplay; // These are for three states of the buffers: empty, full, played bx_sound_waveinfo_struct WaveInfo[2]; // format for the next buffer to be played - int iswaveready; // and the midi buffer for the SYSEX messages LPMIDIHDR MidiHeader; LPSTR MidiData; int ismidiready; - int playnextbuffer(); int recordnextpacket(); void checkmidiready(); - void checkwaveready(); }; #endif // defined(WIN32)