]> git.saurik.com Git - wxWidgets.git/commitdiff
Added wxSound for Windows support (successful WAV playback on VC++ 5)
authorGuilhem Lavaux <lavaux@easynet.fr>
Wed, 25 Aug 1999 17:22:26 +0000 (17:22 +0000)
committerGuilhem Lavaux <lavaux@easynet.fr>
Wed, 25 Aug 1999 17:22:26 +0000 (17:22 +0000)
Fixes/Updates for the rest.
PNM decoder uses now wxBufferedInputStream to (to be tested).
Support for G72X is on the road ...

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3487 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/common/imagpnm.cpp
utils/wxMMedia2/lib/sndaiff.cpp
utils/wxMMedia2/lib/sndbase.h
utils/wxMMedia2/lib/sndfile.cpp
utils/wxMMedia2/lib/sndoss.cpp
utils/wxMMedia2/lib/sndoss.h
utils/wxMMedia2/lib/sndwin.cpp [new file with mode: 0644]
utils/wxMMedia2/lib/sndwin.h [new file with mode: 0644]

index e46916c549379feb82e1ca647af31d9ec55e97e7..75a0b49d79c3eaca2a8eecd85fbc1a7945c6a14d 100644 (file)
@@ -64,10 +64,11 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE
      * Read the PNM header
      */
 
-    wxTextInputStream text_stream(stream);
+    wxBufferedInputStream buf_stream(stream);
+    wxTextInputStream text_stream(buf_stream);
 
-    Skip_Comment(stream);
-    if (stream.GetC()==_T('P')) c=stream.GetC();
+    Skip_Comment(buf_stream);
+    if (buf_stream.GetC()==_T('P')) c=buf_stream.GetC();
 
     switch (c)
       {
@@ -84,9 +85,9 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE
       }
 
     text_stream >> line; // for the \n
-    Skip_Comment(stream);
+    Skip_Comment(buf_stream);
     text_stream >> width >> height ;
-    Skip_Comment(stream); 
+    Skip_Comment(buf_stream); 
     text_stream >> maxval;
 
     //cout << width << " " << height << " " << maxval << endl;
@@ -108,7 +109,7 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE
            value=text_stream.Read32();
            *ptr++=(unsigned char)value;
 
-           if (stream.LastError()!=wxSTREAM_NOERROR)
+           if (buf_stream.LastError()!=wxSTREAM_NOERROR)
              {
                wxLogError(_T("Loading PNM image : file seems truncated."));
                return FALSE;
@@ -116,11 +117,11 @@ bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool WXUNUSE
          }
       }
     if (c=='6') // Raw RGB
-      stream.Read( ptr, 3*width*height );
+      buf_stream.Read( ptr, 3*width*height );
 
     image->SetMask( FALSE );
 
-    return (stream.LastError()==wxStream_NOERROR || stream.LastError()==wxStream_EOF);
+    return (buf_stream.LastError()==wxStream_NOERROR || buf_stream.LastError()==wxStream_EOF);
 }
 
 bool wxPNMHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose) )
index a65f8756e9631dfbc3f5f850c5e4ea1468f61b23..9ea8eb0af98d89c19bb3aa93ef8cad9fd6f51502 100644 (file)
@@ -116,11 +116,13 @@ bool wxSoundAiff::PrepareToPlay()
 
 bool wxSoundAiff::PrepareToRecord(unsigned long time)
 {
+  // TODO
   return FALSE;
 }
 
 bool wxSoundAiff::FinishRecording()
 {
+  // TODO
   return FALSE;
 }
 
index 26fae17890868e7c864da513ac1e1d031b429329..c49aefa2f8abc7625f69552f1ff7ce5e796f5368 100644 (file)
@@ -98,6 +98,9 @@ class wxSoundStream {
   wxSoundError GetError() const { return m_snderror; }
   size_t GetLastAccess() const { return m_lastcount; }
 
+  // This is only useful for device (I think).
+  virtual bool QueueFilled() const { return TRUE; }
+
  protected:
   // Current sound format
   wxSoundFormatBase *m_sndformat;
index 6525d2bbc6a8b77357e89a22ec4cbbe9bf2f577d..e3dfd1e7c8364e618dddfecbf63237becc9e7580 100644 (file)
@@ -158,10 +158,11 @@ bool wxSoundFileStream::Play()
   if (!PrepareToPlay())
     return FALSE;
 
+  m_state = wxSOUND_FILE_PLAYING;
+
   if (!StartProduction(wxSOUND_OUTPUT))
     return FALSE;
 
-  m_state = wxSOUND_FILE_PLAYING;
   return TRUE;
 }
 
@@ -175,10 +176,10 @@ bool wxSoundFileStream::Record(unsigned long time)
 
   m_len = m_sndformat->GetBytesFromTime(time);
 
+  m_state = wxSOUND_FILE_RECORDING;
   if (!StartProduction(wxSOUND_INPUT))
     return FALSE;
 
-  m_state = wxSOUND_FILE_RECORDING;
   return TRUE;
 }
 
@@ -265,30 +266,32 @@ void wxSoundFileStream::OnSoundEvent(int evt)
   size_t len = m_sndio->GetBestSize();
   char *buffer;
 
-  buffer = new char[m_sndio->GetBestSize()];
+  buffer = new char[len];
   wxSoundStream::OnSoundEvent(evt);
 
-  switch(evt) {
-  case wxSOUND_INPUT:
-    if (len > m_len)
-      len = m_len;
-
-    len = m_codec.Read(buffer, len).GetLastAccess();
-    PutData(buffer, len);
-    m_len -= len;
-    if (m_len == 0) {
-      Stop();
-      return;
-    }
-    break;
-  case wxSOUND_OUTPUT:
-    len = GetData(buffer, len);
-    if (len == 0) {
-      Stop();
-      return;
+  while (!m_sndio->QueueFilled()) {
+    switch(evt) {
+    case wxSOUND_INPUT:
+      if (len > m_len)
+        len = m_len;
+
+      len = m_codec.Read(buffer, len).GetLastAccess();
+      PutData(buffer, len);
+      m_len -= len;
+      if (m_len == 0) {
+        Stop();
+        return;
+      }
+      break;
+    case wxSOUND_OUTPUT:
+      len = GetData(buffer, len);
+      if (len == 0) {
+        Stop();
+        return;
+      }
+      m_codec.Write(buffer, len);
+      break;
     }
-    m_codec.Write(buffer, len);
-    break;
   }
   delete[] buffer;
 }
index 8b890a02e8af56466aaf10c0dba77c7d224d08ae..e794b2003262564ddd93cf1a544fecb9e0e9f2a4 100644 (file)
@@ -46,6 +46,7 @@ wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name)
   close(m_fd);
 
   m_oss_stop = TRUE;
+  m_q_filled = TRUE;
 }
 
 wxSoundStreamOSS::~wxSoundStreamOSS()
@@ -64,6 +65,7 @@ wxSoundStream& wxSoundStreamOSS::Read(void *buffer, size_t len)
   int ret;
 
   m_lastcount = (size_t)ret = read(m_fd, buffer, len);
+  m_q_filled  = TRUE;
 
   if (ret < 0)
     m_snderror = wxSOUND_IOERR;
@@ -78,6 +80,7 @@ wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, size_t len)
   int ret;
 
   m_lastcount = (size_t)ret = write(m_fd, buffer, len);
+  m_q_filled  = TRUE;
 
   if (ret < 0)
     m_snderror = wxSOUND_IOERR;
@@ -220,6 +223,7 @@ static void _wxSound_OSS_CBack(gpointer data, int source,
 
 void wxSoundStreamOSS::WakeUpEvt(int evt)
 {
+  m_q_filled = FALSE;
   OnSoundEvent(evt);
 }
 
@@ -263,6 +267,7 @@ bool wxSoundStreamOSS::StartProduction(int evt)
   ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
 
   m_oss_stop = FALSE;
+  m_q_filled = FALSE;
 
   return TRUE;
 }
@@ -278,9 +283,15 @@ bool wxSoundStreamOSS::StopProduction()
 
   close(m_fd);
   m_oss_stop = TRUE;
+  m_q_filled = TRUE;
   return TRUE;
 }
 
+bool wxSoundStreamOSS::QueueFilled() const
+{
+  return m_q_filled;
+}
+
 //
 // Detect the closest format (The best).
 //
index 1fa28c0b4ec7fc1cd0f90359e2e1325bcc76296b..84fc3f314e1f8b3a5f1991c2cd89c34ae20b5526 100644 (file)
@@ -35,6 +35,7 @@ class wxSoundStreamOSS : public wxSoundStream {
   bool StopProduction();
 
   void SetDuplexMode(bool duplex) {}
+  bool QueueFilled() const;
 
   // You should not call this.
   void WakeUpEvt(int evt);
@@ -42,7 +43,7 @@ class wxSoundStreamOSS : public wxSoundStream {
   int m_fd;
   wxUint32 m_bufsize;
   int m_tag;
-  bool m_oss_stop;
+  bool m_oss_stop, m_q_filled;
   wxString m_devname;
 
  private:
diff --git a/utils/wxMMedia2/lib/sndwin.cpp b/utils/wxMMedia2/lib/sndwin.cpp
new file mode 100644 (file)
index 0000000..2b89209
--- /dev/null
@@ -0,0 +1,537 @@
+// --------------------------------------------------------------------------
+// Name: sndwin.cpp
+// Purpose:
+// Date: 08/11/1999
+// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
+// CVSID: $Id$
+// --------------------------------------------------------------------------
+#include <wx/wxprec.h>
+
+#include <wx/msw/private.h>
+#include <wx/module.h>
+#include <string.h>
+#include "sndbase.h"
+#include "sndwin.h"
+#include "sndpcm.h"
+
+#include <windows.h>
+#include <mmsystem.h>
+
+typedef struct _wxSoundInternal wxSoundInternal;
+typedef struct _wxSoundInfoHeader wxSoundInfoHeader;
+
+extern char wxCanvasClassName[];
+
+wxList *wxSoundHandleList = NULL;
+
+static inline wxSoundStreamWin *wxFindSoundFromHandle(WXHWND hWnd)
+{
+  wxNode *node = wxSoundHandleList->Find((long)hWnd);
+  if (!node)
+    return NULL;
+  return (wxSoundStreamWin *)node->Data();
+}
+
+struct _wxSoundInternal {
+  HWND m_sndWin;
+  HWAVEIN m_devin;
+  HWAVEOUT m_devout;
+  bool m_output_enabled, m_input_enabled;
+};
+
+struct _wxSoundInfoHeader {
+  HGLOBAL m_h_header, m_h_data;
+  char *m_data;
+  WAVEHDR *m_header;
+  int m_mode;
+  bool m_playing, m_recording;
+  wxUint32 m_position, m_size;
+
+  wxSoundStreamWin *m_driver;
+};
+
+#define WXSOUND_MAX_QUEUE 128
+
+wxSoundStreamWin::wxSoundStreamWin()
+{
+  wxSoundFormatPcm pcm;
+
+  m_production_started = FALSE;
+  m_internal = new wxSoundInternal;
+  m_snderror = wxSOUND_NOERR;
+
+  // Setup defaults
+  CreateSndWindow();
+  SetSoundFormat(pcm);
+
+  if (!OpenDevice(wxSOUND_OUTPUT))
+    return;
+
+  CloseDevice();
+}
+
+wxSoundStreamWin::~wxSoundStreamWin()
+{
+  if (m_production_started)
+    StopProduction();
+  DestroySndWindow();
+
+  delete m_internal;
+}
+
+LRESULT APIENTRY _EXPORT _wxSoundHandlerWndProc(HWND hWnd, UINT message,
+                 WPARAM wParam, LPARAM lParam)
+{
+  switch (message) {
+  case MM_WOM_DONE: {
+    wxFindSoundFromHandle((WXHWND)hWnd)->NotifyDoneBuffer(wParam);
+    break;
+  }
+  default:
+    break;
+  }
+  return (LRESULT)0;
+}
+
+void wxSoundStreamWin::CreateSndWindow()
+{
+  FARPROC proc = MakeProcInstance((FARPROC)_wxSoundHandlerWndProc,
+                                  wxGetInstance());
+  int error;
+
+  m_internal->m_sndWin = ::CreateWindow(wxCanvasClassName, NULL, 0,
+                                       0, 0, 0, 0, NULL, (HMENU) NULL,
+                                        wxGetInstance(), NULL);
+
+  error = GetLastError();
+  wxPrintf("%d\n", error);
+
+  ::SetWindowLong(m_internal->m_sndWin, GWL_WNDPROC, (LONG)proc);
+
+  wxSoundHandleList->Append((long)m_internal->m_sndWin, (wxObject *)this);
+}
+
+void wxSoundStreamWin::DestroySndWindow()
+{
+  if (m_internal->m_sndWin) {
+    ::DestroyWindow(m_internal->m_sndWin);
+    wxSoundHandleList->DeleteObject((wxObject *)this);
+  }
+}
+
+bool wxSoundStreamWin::OpenDevice(int mode)
+{
+  wxSoundFormatPcm *pcm;
+  WAVEFORMATEX wformat;
+
+  if (!m_sndformat) {
+    m_snderror = wxSOUND_INVFRMT;
+    return FALSE;
+  }
+    
+  pcm = (wxSoundFormatPcm *)m_sndformat;
+
+  wformat.wFormatTag      = WAVE_FORMAT_PCM;
+  wformat.nChannels       = pcm->GetChannels();
+  wformat.nBlockAlign     = pcm->GetBPS() / 8 * wformat.nChannels;
+  wformat.nAvgBytesPerSec = pcm->GetBytesFromTime(1);
+  wformat.nSamplesPerSec  = pcm->GetSampleRate();
+  wformat.wBitsPerSample  = pcm->GetBPS();
+  wformat.cbSize          = 0;
+
+  if (mode & wxSOUND_OUTPUT) {
+    MMRESULT result;
+
+    result = waveOutOpen(&m_internal->m_devout,
+                         WAVE_MAPPER, &wformat,
+                         (DWORD)m_internal->m_sndWin, 0,
+                         CALLBACK_WINDOW);
+
+    if (result != MMSYSERR_NOERROR) {
+      m_snderror = wxSOUND_INVDEV;
+      return FALSE;
+    }
+
+    m_output_frag_out  = WXSOUND_MAX_QUEUE-1;
+    m_current_frag_out = 0;
+
+    m_internal->m_output_enabled = TRUE;
+  }
+  if (mode & wxSOUND_INPUT) {
+    MMRESULT result;
+
+    result = waveInOpen(&m_internal->m_devin,
+                        WAVE_MAPPER, &wformat,
+                        (DWORD)m_internal->m_sndWin, 0,
+                        CALLBACK_WINDOW);
+
+    if (result != MMSYSERR_NOERROR) {
+      m_snderror = wxSOUND_INVDEV;
+      return FALSE;
+    }
+
+    m_input_frag_in   = WXSOUND_MAX_QUEUE-1;
+    m_current_frag_in = 0;
+
+    m_internal->m_input_enabled = TRUE;
+  }
+
+  if (!AllocHeaders(mode)) {
+    CloseDevice();
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+void wxSoundStreamWin::CloseDevice()
+{
+  if (m_internal->m_output_enabled) {
+    FreeHeaders(wxSOUND_OUTPUT);
+    waveOutReset(m_internal->m_devout);
+    waveOutClose(m_internal->m_devout);
+  }
+
+  if (m_internal->m_input_enabled) {
+    FreeHeaders(wxSOUND_INPUT);
+    waveInReset(m_internal->m_devin);
+    waveInClose(m_internal->m_devin);
+  }
+
+  m_internal->m_output_enabled = FALSE;
+  m_internal->m_input_enabled  = FALSE;
+}
+
+wxSoundInfoHeader *wxSoundStreamWin::AllocHeader(int mode)
+{
+  wxSoundInfoHeader *info;
+  WAVEHDR *header;
+
+  info = new wxSoundInfoHeader;
+  info->m_h_data   = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, GetBestSize());
+  info->m_h_header = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
+  if (!info->m_h_data || !info->m_h_header) {
+    delete info;
+    m_snderror = wxSOUND_MEMERR;
+    return NULL;
+  }
+
+  info->m_data      = (char *)GlobalLock(info->m_h_data);
+  info->m_header    = (WAVEHDR *)GlobalLock(info->m_h_header);
+  info->m_mode      = mode;
+  info->m_driver    = this;
+  ClearHeader(info);
+
+  header            = info->m_header;
+
+  header->lpData         = info->m_data;
+  header->dwBufferLength = GetBestSize();
+  header->dwUser         = (DWORD)info;
+  header->dwFlags        = WHDR_DONE;
+
+  if (mode == wxSOUND_INPUT) {
+    MMRESULT result;
+
+    result  = waveInPrepareHeader(m_internal->m_devin, header,
+                                  sizeof(WAVEHDR));
+
+    if (result != MMSYSERR_NOERROR) {
+      GlobalUnlock(info->m_data);
+      GlobalUnlock(info->m_header);
+      GlobalFree(info->m_h_data);
+      GlobalFree(info->m_h_header);
+      delete info;
+
+      m_snderror = wxSOUND_IOERR;
+      return NULL;
+    }
+  } else if (mode == wxSOUND_OUTPUT) {
+    MMRESULT result;
+
+    result  = waveOutPrepareHeader(m_internal->m_devout, header,
+                                   sizeof(WAVEHDR));
+
+    if (result != MMSYSERR_NOERROR) {
+      GlobalUnlock(info->m_data);
+      GlobalUnlock(info->m_header);
+      GlobalFree(info->m_h_data);
+      GlobalFree(info->m_h_header);
+      delete info;
+
+      m_snderror = wxSOUND_IOERR;
+      return NULL;
+    }
+  }
+  return info;
+}
+
+bool wxSoundStreamWin::AllocHeaders(int mode)
+{
+  int i;
+  wxSoundInfoHeader **headers;
+
+  if (mode == wxSOUND_OUTPUT)
+    headers = m_headers_play = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
+  else
+    headers = m_headers_rec = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
+
+  memset(headers, 0, WXSOUND_MAX_QUEUE*sizeof(wxSoundInfoHeader *));
+
+  for (i=0;i<WXSOUND_MAX_QUEUE;i++) {
+    headers[i] = AllocHeader(mode);
+    if (!headers[i]) {
+      FreeHeaders(mode);
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+void wxSoundStreamWin::FreeHeader(wxSoundInfoHeader *header, int mode)
+{
+  if (mode == wxSOUND_OUTPUT)
+    waveOutUnprepareHeader(m_internal->m_devout, header->m_header, sizeof(WAVEHDR));
+  else
+    waveInUnprepareHeader(m_internal->m_devin, header->m_header, sizeof(WAVEHDR));
+
+  GlobalUnlock(header->m_data);
+  GlobalUnlock(header->m_header);
+  GlobalFree(header->m_h_header);
+  GlobalFree(header->m_h_data);
+  delete header;
+}
+
+void wxSoundStreamWin::FreeHeaders(int mode)
+{
+  int i;
+  wxSoundInfoHeader ***headers;
+
+  if (mode == wxSOUND_OUTPUT)
+    headers = &m_headers_play;
+  else
+    headers = &m_headers_rec;
+
+  for (i=0;i<WXSOUND_MAX_QUEUE;i++) {
+    if ((*headers)[i]) {
+      WaitFor((*headers)[i]);
+      FreeHeader((*headers)[i], mode);
+    }
+  }
+  delete[] (*headers);
+  (*headers) = NULL;
+}
+
+void wxSoundStreamWin::WaitFor(wxSoundInfoHeader *info)
+{
+  if (info->m_position != 0) {
+    memset(info->m_data + info->m_position, 0, info->m_size);
+    AddToQueue(info);
+  }
+
+  if (!info->m_playing && !info->m_recording)
+    return;
+
+  while (info->m_playing || info->m_recording)
+    wxYield();
+}
+
+bool wxSoundStreamWin::AddToQueue(wxSoundInfoHeader *info)
+{
+  MMRESULT result;
+
+  if (info->m_mode == wxSOUND_INPUT) {
+    m_current_frag_in = (m_current_frag_in + 1) % WXSOUND_MAX_QUEUE;
+    result = waveInAddBuffer(m_internal->m_devin,
+                             info->m_header, sizeof(WAVEHDR));
+    if (result == MMSYSERR_NOERROR)
+      info->m_recording = TRUE;
+    else
+      return FALSE;
+  } else if (info->m_mode == wxSOUND_OUTPUT) {
+    result = waveOutWrite(m_internal->m_devout,
+                          info->m_header, sizeof(WAVEHDR));
+    if (result == MMSYSERR_NOERROR)
+      info->m_playing = TRUE;
+    else
+      return FALSE;
+  }
+  return TRUE;
+}
+
+void wxSoundStreamWin::ClearHeader(wxSoundInfoHeader *info)
+{
+  info->m_playing   = FALSE;
+  info->m_recording = FALSE;
+  info->m_position  = 0;
+  info->m_size      = GetBestSize();
+}
+
+wxSoundInfoHeader *wxSoundStreamWin::NextFragmentOutput()
+{
+  if (m_headers_play[m_current_frag_out]->m_playing) {
+    m_current_frag_out = (m_current_frag_out + 1) % WXSOUND_MAX_QUEUE;
+
+    if (m_headers_play[m_current_frag_out]->m_playing)
+      WaitFor(m_headers_play[m_current_frag_out]);
+  }
+  if (m_current_frag_out == m_output_frag_out)
+    m_queue_filled = TRUE;
+  return m_headers_play[m_current_frag_out];
+}
+
+wxSoundStream& wxSoundStreamWin::Write(const void *buffer, size_t len)
+{
+  m_lastcount = 0;
+  if (!m_internal->m_output_enabled)
+    return *this;
+
+  while (len > 0) {
+    wxSoundInfoHeader *header;
+    size_t to_copy;
+
+    header              = NextFragmentOutput();
+
+    to_copy             = (len > header->m_size) ? header->m_size : len;
+    memcpy(header->m_data + header->m_position, buffer, to_copy);
+
+    header->m_position += to_copy;
+    header->m_size     -= to_copy;
+    buffer              = (((const char *)buffer) + to_copy);
+    len                -= to_copy;
+    m_lastcount        += to_copy;
+    
+    if (header->m_size == 0)
+      if (!AddToQueue(header)) {
+        m_snderror = wxSOUND_IOERR;
+        return *this;
+      }
+  }
+  return *this;
+}
+
+wxSoundInfoHeader *wxSoundStreamWin::NextFragmentInput()
+{
+  wxSoundInfoHeader *header;
+
+  // TODO //
+  header = m_headers_rec[m_current_frag_in];
+  WaitFor(header);
+
+  if (m_current_frag_in == m_input_frag_in)
+    m_queue_filled = TRUE;
+
+  return header;
+}
+
+wxSoundStream& wxSoundStreamWin::Read(void *buffer, size_t len)
+{
+  wxSoundInfoHeader *header;
+  size_t to_copy;
+
+  m_lastcount = 0;
+  if (!m_internal->m_input_enabled)
+    return *this;
+
+  while (len > 0) {
+    header = NextFragmentInput();
+
+    to_copy             = (len > header->m_size) ? header->m_size : len;
+    memcpy(buffer, header->m_data + header->m_position, to_copy);
+
+    header->m_position += to_copy;
+    header->m_size     -= to_copy;
+    buffer              = (((char *)buffer) + to_copy);
+    len                -= to_copy;
+    m_lastcount        += to_copy;
+
+    if (header->m_size == 0) {
+      ClearHeader(header);
+      if (!AddToQueue(header)) {
+        m_snderror = wxSOUND_IOERR;
+        return *this;
+      }
+    }
+  }
+  return *this;
+}
+
+void wxSoundStreamWin::NotifyDoneBuffer(wxUint32 dev_handle)
+{
+  wxSoundInfoHeader *info;
+
+  if (dev_handle == (wxUint32)m_internal->m_devout) {
+    m_output_frag_out = (m_output_frag_out + 1) % WXSOUND_MAX_QUEUE;
+    info = m_headers_play[m_output_frag_out];
+    ClearHeader(info);
+    m_queue_filled = FALSE;
+    OnSoundEvent(wxSOUND_OUTPUT);
+  } else {
+    m_input_frag_in = (m_input_frag_in + 1) % WXSOUND_MAX_QUEUE;
+    OnSoundEvent(wxSOUND_INPUT);
+    m_queue_filled = FALSE;
+  }
+}
+
+bool wxSoundStreamWin::SetSoundFormat(wxSoundFormatBase& base)
+{
+  return wxSoundStream::SetSoundFormat(base);
+}
+
+bool wxSoundStreamWin::StartProduction(int evt)
+{
+  if ((m_internal->m_output_enabled && (evt & wxSOUND_OUTPUT)) ||
+      (m_internal->m_input_enabled && (evt & wxSOUND_INPUT)))
+    CloseDevice();
+
+  if (!OpenDevice(evt))
+    return FALSE;
+
+  m_production_started = TRUE;
+  m_queue_filled = FALSE;
+  // Send a dummy event to start.
+  if (evt & wxSOUND_OUTPUT)
+    OnSoundEvent(evt);
+
+  if (evt & wxSOUND_INPUT) {
+    int i;
+    for (i=0;i<WXSOUND_MAX_QUEUE;i++)
+      AddToQueue(m_headers_rec[i]);
+  }
+
+  return TRUE;
+}
+
+bool wxSoundStreamWin::StopProduction()
+{
+  m_production_started = FALSE;
+  CloseDevice();
+  return TRUE;
+}
+
+bool wxSoundStreamWin::QueueFilled() const
+{
+  return (!m_production_started || m_queue_filled);
+}
+
+
+// --------------------------------------------------------------------------
+// wxSoundWinModule
+// --------------------------------------------------------------------------
+
+class WXDLLEXPORT wxSoundWinModule : public wxModule {
+   DECLARE_DYNAMIC_CLASS(wxSoundWinModule)
+ public:
+   bool OnInit();
+   void OnExit();
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxSoundWinModule, wxModule)
+
+bool wxSoundWinModule::OnInit() {
+  wxSoundHandleList = new wxList(wxKEY_INTEGER);
+  return TRUE;
+}
+
+void wxSoundWinModule::OnExit() {
+  delete wxSoundHandleList;
+}
diff --git a/utils/wxMMedia2/lib/sndwin.h b/utils/wxMMedia2/lib/sndwin.h
new file mode 100644 (file)
index 0000000..8d9a89b
--- /dev/null
@@ -0,0 +1,63 @@
+// --------------------------------------------------------------------------
+// Name: sndwin.h
+// Purpose:
+// Date: 08/11/1999
+// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
+// CVSID: $Id$
+// --------------------------------------------------------------------------
+#ifndef _WX_SNDWIN_H
+#define _WX_SNDWIN_H
+
+#include <wx/wxprec.h>
+#include "sndbase.h"
+
+typedef struct _wxSoundInternal wxSoundInternal;
+typedef struct _wxSoundInfoHeader wxSoundInfoHeader;
+
+class WXDLLEXPORT wxSoundStreamWin : public wxSoundStream {
+ public:
+  wxSoundStreamWin();
+  ~wxSoundStreamWin();
+
+  wxSoundStream& Write(const void *buffer, size_t len);
+  wxSoundStream& Read(void *buffer, size_t len); 
+
+  bool SetSoundFormat(wxSoundFormatBase& base);
+  void SetDuplexMode(bool on) {}
+
+  bool StartProduction(int evt);
+  bool StopProduction();
+
+  bool QueueFilled() const;
+
+  // Internal but defined as public
+  void NotifyDoneBuffer(wxUint32 dev_handle);
+
+ protected:
+  wxSoundInternal *m_internal;
+  wxUint32 m_current_frag_in, m_current_frag_out;
+  wxUint32 m_input_frag_in, m_output_frag_out;
+  wxSoundInfoHeader **m_headers_play, **m_headers_rec;
+
+  bool m_production_started, m_queue_filled;
+
+ protected:
+  void CreateSndWindow();
+  void DestroySndWindow();
+  bool OpenDevice(int mode);
+  void CloseDevice();
+
+  wxSoundInfoHeader *AllocHeader(int mode);
+  void FreeHeader(wxSoundInfoHeader *header, int mode);
+  bool AllocHeaders(int mode);
+  void FreeHeaders(int mode);
+
+  void WaitFor(wxSoundInfoHeader *info);
+  bool AddToQueue(wxSoundInfoHeader *info);
+  void ClearHeader(wxSoundInfoHeader *info);
+
+  wxSoundInfoHeader *NextFragmentOutput();
+  wxSoundInfoHeader *NextFragmentInput();
+};
+
+#endif