]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/wxMMedia/sndwin.cpp
* Added wxMMedia in the repository so people interrested in it can work on it
[wxWidgets.git] / utils / wxMMedia / sndwin.cpp
diff --git a/utils/wxMMedia/sndwin.cpp b/utils/wxMMedia/sndwin.cpp
new file mode 100644 (file)
index 0000000..8161ed8
--- /dev/null
@@ -0,0 +1,384 @@
+////////////////////////////////////////////////////////////////////////////////
+// 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;
+}