--- /dev/null
+////////////////////////////////////////////////////////////////////////////////
+// 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 <wx/msw/private.h>
+
+#define WXMMEDIA_INTERNAL
+#include "sndwin.h"
+
+#define MMD_WIN_IO_BSIZE 16384
+
+#include <mmsystem.h>
+
+#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 = m_optrs = new wxFragBufPtr[m_maxoq];
+ m_lstiptrs = m_iptrs = new wxFragBufPtr[m_maxiq];
+
+ for (i=0;i<m_maxoq;i++) {
+ m_lstoptrs[i].size = MMD_WIN_IO_BSIZE;
+ m_lstoptrs[i].ptr = 0;
+ m_lstoptrs[i].buffers = new wxList();
+ m_lstoptrs[i].state = wxBUFFER_FREE;
+
+ w_snd->PrepareHeader(m_lstoptrs[i], wxSND_OUTPUT);
+ }
+
+ for (i=0;i<m_maxiq;i++) {
+ m_lstiptrs[i].size = MMD_WIN_IO_BSIZE;
+ m_lstiptrs[i].ptr = 0;
+ m_lstiptrs[i].buffers = new wxList();
+ m_lstiptrs[i].state = wxBUFFER_FREE;
+
+ w_snd->PrepareHeader(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;i<m_maxoq;i++) {
+ w_snd->UnprepareHeader(m_lstoptrs[i], wxSND_OUTPUT);
+ delete m_lstoptrs[i].buffers;
+ }
+
+ for (i=0;i<m_maxiq;i++) {
+ w_snd->UnprepareHeader(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;i<m_maxoq;i++) {
+ if (m_lstoptrs[i].state == wxBUFFER_FFILLED) {
+ buf_busy = TRUE;
+ break;
+ }
+ }
+ wxYield();
+ }
+
+ m_dontq = FALSE;
+ FreeBufToFree(TRUE);
+}
+
+bool wxSndWinFragment::OnBufferFilled(wxFragBufPtr *ptr, wxSndMode mode)
+{
+ wxSndWinInfo *info = (wxSndWinInfo *)ptr->user_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, frag.size);
+ 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));
+
+ printf("prepareIn = %d\n", result);
+ if (result != MMSYSERR_NOERROR)
+ wxExit();
+ } else {
+ MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr,
+ sizeof(WAVEHDR));
+ printf("prepareOut = %d\n", result);
+ if (result != MMSYSERR_NOERROR)
+ wxExit();
+ }
+
+ frag.user_data = (char *)info;
+ frag.data = info->data;
+}
+
+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));
+ }
+
+ 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:
+ 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;
+}