//////////////////////////////////////////////////////////////////////////////// // Name: sndwin.cpp // Purpose: wxMMedia // Author: Guilhem Lavaux // Created: 1997 // Updated: 1998 // Copyright: (C) 1997, 1998, Guilhem Lavaux // License: wxWindows license //////////////////////////////////////////////////////////////////////////////// #ifdef WX_PRECOMP #include "wx/wxprec.h" #else #include "wx/wx.h" #endif #include #define WXMMEDIA_INTERNAL #include "sndwin.h" #define MMD_WIN_IO_BSIZE 16384 #include #ifdef __BORLANDC__ #pragma hdrstop #endif wxSndWinFragment::wxSndWinFragment(wxSound& io_drv) : wxFragmentBuffer(io_drv) { } wxSndWinFragment::~wxSndWinFragment(void) { } void wxSndWinFragment::AllocIOBuffer(void) { wxWinSound *w_snd = (wxWinSound *) m_iodrv; wxUint8 i; m_maxoq = 5; m_maxiq = 5; m_lstoptrs = new wxFragBufPtr[m_maxoq]; m_lstiptrs = new wxFragBufPtr[m_maxiq]; for (i=0;iPrepareHeader(m_lstoptrs[i], wxSND_OUTPUT); } for (i=0;iPrepareHeader(m_lstiptrs[i], wxSND_INPUT); } } void wxSndWinFragment::FreeIOBuffer(void) { wxWinSound *w_snd = (wxWinSound *)m_iodrv; wxUint8 i; if (!m_lstoptrs && !m_lstiptrs) return; for (i=0;iUnprepareHeader(m_lstoptrs[i], wxSND_OUTPUT); delete m_lstoptrs[i].buffers; } for (i=0;iUnprepareHeader(m_lstiptrs[i], wxSND_INPUT); delete m_lstiptrs[i].buffers; } delete[] m_lstoptrs; delete[] m_lstiptrs; m_lstoptrs = m_lstiptrs = NULL; m_maxoq = m_maxiq = 0; } void wxSndWinFragment::WaitForAll() { bool buf_busy = TRUE; int i; m_dontq = TRUE; while (buf_busy) { buf_busy = FALSE; for (i=0;iuser_data; wxWinSound *w_snd = (wxWinSound *)m_iodrv; MMRESULT result; switch (mode) { case wxSND_INPUT: result = waveInAddBuffer(w_snd->internal->devin_id, info->hdr, sizeof(WAVEHDR)); break; case wxSND_OUTPUT: result = waveOutWrite(w_snd->internal->devout_id, info->hdr, sizeof(WAVEHDR)); printf("WINOUT: result=%d\n", result); break; } return TRUE; } wxWinSound::wxWinSound(void) : wxSound(), fragments(*this) { internal = new wxWinSoundInternal; internal->devout_id = 0; internal->devin_id = 0; internal->sndWin = 0; wout_opened = FALSE; win_opened = FALSE; curr_o_srate = (wxUint32)-1; curr_o_bps = (wxUint8)-1; curr_o_stereo = (bool)-1; curr_i_srate = (wxUint32)-1; curr_i_bps = (wxUint8)-1; curr_i_stereo = (bool)-1; } wxWinSound::~wxWinSound(void) { int i; fragments.WaitForAll(); if (wout_opened) waveOutReset(internal->devout_id); if (win_opened) waveInReset(internal->devout_id); fragments.FreeIOBuffer(); if (wout_opened) waveOutClose(internal->devout_id); if (win_opened) waveInClose(internal->devin_id); if (internal->sndWin) ::DestroyWindow(internal->sndWin); delete internal; } bool wxWinSound::Wakeup(wxSndBuffer& buf) { if (!Reopen(buf, FALSE)) { buf.Clear(wxSND_BUFLOCKED); return FALSE; } fragments.OnBufferFinished(NULL); return TRUE; } void wxWinSound::PrepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, wxSndMode mode) { wxSndWinInfo *info; WAVEHDR *hdr; if ((mode == wxSND_INPUT && !win_opened) || (mode == wxSND_OUTPUT && !wout_opened)) return; info = new wxSndWinInfo; info->h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, MMD_WIN_IO_BSIZE); info->h_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); info->data = (char *)GlobalLock(info->h_data); hdr = info->hdr = (WAVEHDR *)GlobalLock(info->h_hdr); memset(hdr, 0, sizeof(*hdr)); hdr->lpData = info->data; hdr->dwBufferLength = frag.size; hdr->dwUser = (DWORD)&frag; hdr->dwFlags = WHDR_DONE; if (mode == wxSND_INPUT) { MMRESULT result = waveInPrepareHeader(internal->devin_id, hdr, sizeof(WAVEHDR)); if (result != MMSYSERR_NOERROR) wxExit(); } else { MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr, sizeof(WAVEHDR)); if (result != MMSYSERR_NOERROR) wxExit(); } frag.sndbuf = new wxStreamBuffer(); frag.sndbuf->SetBufferIO(info->data, info->data + MMD_WIN_IO_BSIZE); frag.user_data = (char *)info; } void wxWinSound::UnprepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, wxSndMode mode) { wxSndWinInfo *info = (wxSndWinInfo *)frag.user_data; if ((mode == wxSND_INPUT && !win_opened) || (mode == wxSND_OUTPUT && !wout_opened)) return; MMRESULT result; if (mode == wxSND_INPUT) { result = waveInUnprepareHeader(internal->devin_id, info->hdr, sizeof(*info->hdr)); } else { result = waveOutUnprepareHeader(internal->devout_id, info->hdr, sizeof(*info->hdr)); } delete frag.sndbuf; printf("unprepare = %d\n", result); GlobalUnlock(info->h_hdr); GlobalUnlock(info->h_data); GlobalFree(info->h_hdr); GlobalFree(info->h_data); delete info; } extern char wxCanvasClassName[]; LRESULT APIENTRY _EXPORT wxSoundHandlerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case MM_WOM_DONE: { wxWinSound *snd_drv = (wxWinSound *)GetWindowLong(hWnd, GWL_USERDATA); WAVEHDR *hdr = (WAVEHDR *)lParam; wxFragmentBuffer::wxFragBufPtr *buf = (wxFragmentBuffer::wxFragBufPtr *)hdr->dwUser; // To be sure ... hdr->dwFlags |= WHDR_DONE; snd_drv->fragments.OnBufferFinished(buf); break; } case MM_WOM_OPEN: printf("wave Open ack\n"); break; case MM_WOM_CLOSE: printf("wave Close ack\n"); break; default: // TODO: Useful ? return DefWindowProc(hWnd, message, wParam, lParam); } return (LRESULT)0; } void wxWinSound::StopBuffer(wxSndBuffer& buf) { buf.HardLock(); buf.Set(wxSND_BUFSTOP); fragments.AbortBuffer(buf); buf.HardUnlock(); while (buf.IsSet(wxSND_BUFSTOP)) wxYield(); } bool wxWinSound::Reopen(wxSndBuffer& buf, bool force) { WAVEFORMATEX wformat; if ((buf.GetSampleRate() != curr_o_srate) || (buf.GetBps() != curr_o_bps) || (buf.GetStereo() != curr_o_stereo) || (buf.GetMode() != curr_mode)) force = TRUE; if (force) { wxUint32 *curr_srate = (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_srate : &curr_i_srate; wxUint8 *curr_bps = (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_bps : &curr_i_bps; bool *curr_stereo = (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_stereo : &curr_i_stereo; fragments.WaitForAll(); fragments.FreeIOBuffer(); if (!internal->sndWin) { FARPROC proc = MakeProcInstance((FARPROC)wxSoundHandlerWndProc, wxGetInstance()); internal->sndWin = ::CreateWindow(wxCanvasClassName, NULL, 0, 0, 0, 0, 0, NULL, (HMENU) NULL, wxGetInstance(), 0); ::SetWindowLong(internal->sndWin, GWL_WNDPROC, (LONG)proc); ::SetWindowLong(internal->sndWin, GWL_USERDATA, (LONG) this); } if (wout_opened) { waveOutClose(internal->devout_id); wout_opened = FALSE; } if (win_opened) { waveInClose(internal->devin_id); win_opened = FALSE; } *curr_srate = buf.GetSampleRate(); *curr_bps = buf.GetBps(); *curr_stereo = buf.GetStereo(); wformat.wFormatTag = WAVE_FORMAT_PCM; wformat.nChannels = curr_o_stereo+1; wformat.nSamplesPerSec = curr_o_srate; wformat.nBlockAlign = curr_o_bps / 8 * wformat.nChannels; wformat.nAvgBytesPerSec = wformat.nSamplesPerSec * wformat.nBlockAlign; wformat.wBitsPerSample = curr_o_bps; wformat.cbSize = 0; if (buf.GetMode() == wxSND_OUTPUT) { MMRESULT result = waveOutOpen(&internal->devout_id, WAVE_MAPPER, &wformat, (DWORD)internal->sndWin, (DWORD)this, CALLBACK_WINDOW); if (result != MMSYSERR_NOERROR) return FALSE; internal->devin_id = 0; wout_opened = TRUE; curr_mode = wxSND_OUTPUT; fragments.AllocIOBuffer(); } else { MMRESULT result = waveInOpen(&internal->devin_id, WAVE_MAPPER, &wformat, (DWORD)internal->sndWin, (DWORD)this, CALLBACK_FUNCTION); if (result != MMSYSERR_NOERROR) return FALSE; internal->devout_id = 0; win_opened = TRUE; curr_mode = wxSND_INPUT; fragments.AllocIOBuffer(); } } return TRUE; }