]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/wxMMedia2/lib/sndfile.cpp
Ok. Vidwin works again on Windows.
[wxWidgets.git] / utils / wxMMedia2 / lib / sndfile.cpp
index 3040943411dc4c600729b09bc4e45b2b4cffc131..c92ea71d9e32988168320f869d989a5087971443 100644 (file)
 // Name: sndfile.cpp
 // Purpose:
 // Date: 08/11/1999
-// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
+// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
 // CVSID: $Id$
 // --------------------------------------------------------------------------
+#include <wx/wxprec.h>
+
+#ifndef WX_PRECOMP
 #include <wx/stream.h>
+#endif
+
 #include "sndbase.h"
 #include "sndcodec.h"
 #include "sndfile.h"
 #include "sndcpcm.h"
 #include "sndulaw.h"
+#include "sndg72x.h"
 
 // --------------------------------------------------------------------------
 // Sound codec router
+// A very important class: it ensures that everybody is satisfied.
+// It is supposed to create as many codec as it is necessary to transform
+// a signal in a specific format in an another.
 // --------------------------------------------------------------------------
-
 wxSoundRouterStream::wxSoundRouterStream(wxSoundStream& sndio)
   : wxSoundStreamCodec(sndio)
 {
-  m_router = NULL;
+    m_router = NULL;
 }
 
 wxSoundRouterStream::~wxSoundRouterStream()
 {
-  if (m_router)
-    delete m_router;
+    if (m_router)
+        delete m_router;
 }
 
-wxSoundStream& wxSoundRouterStream::Read(void *buffer, size_t len)
+// --------------------------------------------------------------------------
+// Read(void *buffer, wxUint32 len): It reads data synchronously. See sndbase.h
+// for possible errors and behaviours ...
+// --------------------------------------------------------------------------
+wxSoundStream& wxSoundRouterStream::Read(void *buffer, wxUint32 len)
 {
-  if (m_router) {
-    m_router->Read(buffer, len);
-    m_snderror  = m_router->GetError();
-    m_lastcount = m_router->GetLastAccess();
-  } else {
-    m_sndio->Read(buffer, len);
-    m_snderror  = m_sndio->GetError();
-    m_lastcount = m_sndio->GetLastAccess();
-  }
-  return *this;
+    if (m_router) {
+        m_router->Read(buffer, len);
+        m_snderror  = m_router->GetError();
+        m_lastcount = m_router->GetLastAccess();
+    } else {
+        m_sndio->Read(buffer, len);
+        m_snderror  = m_sndio->GetError();
+        m_lastcount = m_sndio->GetLastAccess();
+    }
+    return *this;
 }
 
-wxSoundStream& wxSoundRouterStream::Write(const void *buffer, size_t len)
+// --------------------------------------------------------------------------
+// Write(const void *buffer, wxUint32 len): It writes data synchronously
+// --------------------------------------------------------------------------
+wxSoundStream& wxSoundRouterStream::Write(const void *buffer, wxUint32 len)
 {
-  if (m_router) {
-    m_router->Write(buffer, len);
-    m_snderror  = m_router->GetError();
-    m_lastcount = m_router->GetLastAccess();
-  } else {
-    m_sndio->Write(buffer, len);
-    m_snderror  = m_sndio->GetError();
-    m_lastcount = m_sndio->GetLastAccess();
+    if (m_router) {
+        m_router->Write(buffer, len);
+        m_snderror  = m_router->GetError();
+        m_lastcount = m_router->GetLastAccess();
+    } else {
+        m_sndio->Write(buffer, len);
+        m_snderror  = m_sndio->GetError();
+        m_lastcount = m_sndio->GetLastAccess();
   }
   return *this;
 }
 
+// --------------------------------------------------------------------------
+// SetSoundFormat(const wxSoundFormatBase& format) first tries to setup the
+// sound driver using the specified format. If this fails, it uses personnal
+// codec converters: for the moment there is a PCM converter (PCM to PCM:
+// with optional resampling, ...), an ULAW converter (ULAW to PCM), a G72X
+// converter (G72X to PCM). If nothing works, it returns FALSE.
+// --------------------------------------------------------------------------
 bool wxSoundRouterStream::SetSoundFormat(const wxSoundFormatBase& format)
 {
-  if (m_router)
-    delete m_router;
-
-  if (m_sndio->SetSoundFormat(format)) {
-    wxSoundStream::SetSoundFormat(m_sndio->GetSoundFormat());
+    if (m_router)
+        delete m_router;
+    
+    // First, we try to setup the sound device
+    if (m_sndio->SetSoundFormat(format)) {
+        // We are lucky, it is working.
+        wxSoundStream::SetSoundFormat(m_sndio->GetSoundFormat());
+        return TRUE;
+    }
+    
+    switch(format.GetType()) {
+        case wxSOUND_NOFORMAT:
+            return FALSE;
+        case wxSOUND_PCM:
+            m_router = new wxSoundStreamPcm(*m_sndio);
+            m_router->SetSoundFormat(format);
+            break;
+        case wxSOUND_ULAW:
+            m_router = new wxSoundStreamUlaw(*m_sndio);
+            m_router->SetSoundFormat(format);
+            break;
+        case wxSOUND_G72X:
+            m_router = new wxSoundStreamG72X(*m_sndio);
+            m_router->SetSoundFormat(format);
+            break;
+    }
+    wxSoundStream::SetSoundFormat(m_router->GetSoundFormat());
     return TRUE;
-  }
+}
 
-  switch(format.GetType()) {
-  case wxSOUND_NOFORMAT:
-    return FALSE;
-  case wxSOUND_PCM:
-    m_router = new wxSoundStreamPcm(*m_sndio);
-    m_router->SetSoundFormat(format);
-    break;
-  case wxSOUND_ULAW:
-    m_router = new wxSoundStreamUlaw(*m_sndio);
-    m_router->SetSoundFormat(format);
-    break;
-  }
-  wxSoundStream::SetSoundFormat(m_router->GetSoundFormat());
-  return TRUE;
+// --------------------------------------------------------------------------
+// GetBestSize() returns the specific best buffer size a sound driver
+// can manage. It means that it will be easier for it to manage the buffer
+// and so it will be faster and in some case more accurate for real-time event.
+// --------------------------------------------------------------------------
+wxUint32 wxSoundRouterStream::GetBestSize() const
+{
+  if (m_router)
+    return m_router->GetBestSize();
+  else
+    return m_sndio->GetBestSize();
 }
 
+// --------------------------------------------------------------------------
+// StartProduction(int evt). See sndbase.h 
+// --------------------------------------------------------------------------
 bool wxSoundRouterStream::StartProduction(int evt)
 {
-  if (!m_router) {
-    if (m_sndio->StartProduction(evt))
-      return TRUE;
-
-    m_snderror = m_sndio->GetError();
-    m_lastcount = m_sndio->GetLastAccess();
+    if (!m_router) {
+        if (m_sndio->StartProduction(evt))
+            return TRUE;
+        
+        m_snderror = m_sndio->GetError();
+        m_lastcount = m_sndio->GetLastAccess();
+        return FALSE;
+    }
+    
+    if (m_router->StartProduction(evt))
+        return TRUE;
+    
+    m_snderror = m_router->GetError();
+    m_lastcount = m_router->GetLastAccess();
     return FALSE;
-  }
-
-  if (m_router->StartProduction(evt))
-    return TRUE;
-
-  m_snderror = m_router->GetError();
-  m_lastcount = m_router->GetLastAccess();
-  return FALSE;
 } 
 
+// --------------------------------------------------------------------------
+// StopProduction(). See sndbase.h
+// --------------------------------------------------------------------------
 bool wxSoundRouterStream::StopProduction()
 {
-  if (!m_router) {
-    if (m_sndio->StopProduction())
-      return TRUE;
-
-    m_snderror = m_sndio->GetError();
-    m_lastcount = m_sndio->GetLastAccess();
+    if (!m_router) {
+        if (m_sndio->StopProduction())
+            return TRUE;
+        
+        m_snderror = m_sndio->GetError();
+        m_lastcount = m_sndio->GetLastAccess();
+        return FALSE;
+    }
+    
+    if (m_router->StopProduction())
+        return TRUE;
+    
+    m_snderror = m_router->GetError();
+    m_lastcount = m_router->GetLastAccess();
     return FALSE;
-  }
-
-  if (m_router->StopProduction())
-    return TRUE;
-
-  m_snderror = m_router->GetError();
-  m_lastcount = m_router->GetLastAccess();
-  return FALSE;
 }
 
 // --------------------------------------------------------------------------
 // wxSoundFileStream: generic reader
@@ -127,9 +173,12 @@ bool wxSoundRouterStream::StopProduction()
 
 wxSoundFileStream::wxSoundFileStream(wxInputStream& stream,
                                      wxSoundStream& io_sound)
-  : m_codec(io_sound), m_sndio(&io_sound),
-    m_input(&stream), m_output(NULL), m_state(wxSOUND_FILE_STOPPED)
+        : m_codec(io_sound), m_sndio(&io_sound),
+          m_input(&stream), m_output(NULL), m_state(wxSOUND_FILE_STOPPED)
 {
+    m_length = 0;
+    m_bytes_left = 0;
+    m_prepared = FALSE;
 }
 
 wxSoundFileStream::wxSoundFileStream(wxOutputStream& stream,
@@ -137,6 +186,9 @@ wxSoundFileStream::wxSoundFileStream(wxOutputStream& stream,
   : m_codec(io_sound), m_sndio(&io_sound),
     m_input(NULL), m_output(&stream), m_state(wxSOUND_FILE_STOPPED)
 {
+  m_length = 0;
+  m_bytes_left = 0;
+  m_prepared = FALSE;
 }
 
 wxSoundFileStream::~wxSoundFileStream()
@@ -150,17 +202,19 @@ bool wxSoundFileStream::Play()
   if (m_state != wxSOUND_FILE_STOPPED)
     return FALSE;
 
-  if (!PrepareToPlay())
-    return FALSE;
+  if (!m_prepared)
+    if (!PrepareToPlay())
+      return FALSE;
+
+  m_state = wxSOUND_FILE_PLAYING;
 
   if (!StartProduction(wxSOUND_OUTPUT))
     return FALSE;
 
-  m_state = wxSOUND_FILE_PLAYING;
   return TRUE;
 }
 
-bool wxSoundFileStream::Record(unsigned long time)
+bool wxSoundFileStream::Record(wxUint32 time)
 {
   if (m_state != wxSOUND_FILE_STOPPED)
     return FALSE;
@@ -168,12 +222,12 @@ bool wxSoundFileStream::Record(unsigned long time)
   if (!PrepareToRecord(time))
     return FALSE;
 
-  m_len = m_sndformat->GetBytesFromTime(time);
+  FinishPreparation(m_sndformat->GetBytesFromTime(time));
 
+  m_state = wxSOUND_FILE_RECORDING;
   if (!StartProduction(wxSOUND_INPUT))
     return FALSE;
 
-  m_state = wxSOUND_FILE_RECORDING;
   return TRUE;
 }
 
@@ -185,13 +239,20 @@ bool wxSoundFileStream::Stop()
   if (!StopProduction())
     return FALSE;
 
+  m_prepared = FALSE;
+
   if (m_state == wxSOUND_FILE_RECORDING)
     if (!FinishRecording()) {
       m_state = wxSOUND_FILE_STOPPED;
       return FALSE;
     }
+
+  if (m_input)
+    m_input->SeekI(0, wxFromStart);
+
+  if (m_output)
+    m_output->SeekO(0, wxFromStart);
  
-  // TODO reset counter
   m_state = wxSOUND_FILE_STOPPED;
   return TRUE;
 }
@@ -224,22 +285,18 @@ bool wxSoundFileStream::Resume()
   return TRUE;
 }
 
-wxSoundStream& wxSoundFileStream::Read(void *buffer, size_t len)
+wxSoundStream& wxSoundFileStream::Read(void *buffer, wxUint32 len)
 {
   m_lastcount = GetData(buffer, len);
   return *this;
 }
 
-wxSoundStream& wxSoundFileStream::Write(const void *buffer, size_t len)
+wxSoundStream& wxSoundFileStream::Write(const void *buffer, wxUint32 len)
 {
   m_lastcount = PutData(buffer, len);
   return *this;
 }
 
-void wxSoundFileStream::SetDuplexMode(bool duplex)
-{
-}
-
 bool wxSoundFileStream::StartProduction(int evt)
 {
   m_sndio->SetEventHandler(this);
@@ -255,35 +312,92 @@ bool wxSoundFileStream::StopProduction()
   return m_codec.StopProduction();
 }
 
+void wxSoundFileStream::FinishPreparation(wxUint32 len)
+{
+  m_bytes_left = m_length = len;
+  m_prepared = TRUE;
+}
+
+wxString wxSoundFileStream::GetCodecName() const
+{
+    return wxString(wxT("wxSoundFileStream base codec"));
+}
+
+wxUint32 wxSoundFileStream::GetLength()
+{
+  if (m_input && !m_prepared && GetError() == wxSOUND_NOERR)
+    return (PrepareToPlay()) ? m_length : 0;
+
+  return m_length;
+}
+
+wxUint32 wxSoundFileStream::GetPosition()
+{
+  if (!m_prepared && m_input != NULL && GetError() == wxSOUND_NOERR)
+    PrepareToPlay();
+
+  return m_length-m_bytes_left;
+}
+
+wxUint32 wxSoundFileStream::SetPosition(wxUint32 new_position)
+{
+  if (!m_prepared && m_input != NULL && GetError() == wxSOUND_NOERR)
+    PrepareToPlay();
+
+  if (!m_prepared)
+    return 0;
+
+  if (!RepositionStream(new_position))
+      return m_length-m_bytes_left;
+  
+  if (new_position >= m_length) {
+    m_bytes_left = 0;
+    return m_length;
+  }
+
+  m_bytes_left = m_length-new_position;
+  return new_position;
+}
+
 void wxSoundFileStream::OnSoundEvent(int evt)
 {
-  size_t len = m_sndio->GetBestSize();
-  char buffer[m_sndio->GetBestSize()];
+  wxUint32 len = m_codec.GetBestSize();
+  char *buffer;
 
+  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_bytes_left)
+        len = m_bytes_left;
+
+      len = m_codec.Read(buffer, len).GetLastAccess();
+      PutData(buffer, len);
+      m_bytes_left -= len;
+      if (m_bytes_left == 0) {
+        Stop();
+        delete[] buffer;
+        return;
+      }
+      break;
+    case wxSOUND_OUTPUT:
+      if (len > m_bytes_left)
+        len = m_bytes_left;
+
+      len = GetData(buffer, len);
+      m_bytes_left -= len;
+      if (m_bytes_left == 0) {
+        Stop();
+        delete[] buffer;
+        return;
+      }
+      m_codec.Write(buffer, len);
+      break;
     }
-    m_codec.Write(buffer, len);
-    break;
   }
+  delete[] buffer;
 }
 
 bool wxSoundFileStream::SetSoundFormat(const wxSoundFormatBase& format)