]> git.saurik.com Git - wxWidgets.git/blobdiff - src/unix/sound.cpp
wxColour source cleaning. Corrections to 'const unsigned char' within wxColour docs.
[wxWidgets.git] / src / unix / sound.cpp
index 30ce40656f2775736896b0121937a367dc7efbe9..ce7557247174a2fe5fb96cd1e4dd442a07273bd1 100644 (file)
@@ -6,14 +6,9 @@
 // Created:     25/10/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart, Open Source Applications Foundation
-// Licence:    wxWindows licence
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "sound.h"
-#pragma implementation "soundbase.h"
-#endif
-
 // for compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
@@ -55,7 +50,7 @@ static wxMutex gs_soundMutex;
 // ----------------------------------------------------------------------------
 // wxSoundData
 // ----------------------------------------------------------------------------
-  
+
 void wxSoundData::IncRef()
 {
 #if wxUSE_THREADS
@@ -122,10 +117,10 @@ public:
 
 private:
     int OpenDSP(const wxSoundData *data);
-    bool InitDSP(int dev, int iDataBits, int iChannel,
-                 unsigned long ulSamplingRate);
-    
+    bool InitDSP(int dev, const wxSoundData *data);
+
     int m_DSPblkSize;        // Size of the DSP buffer
+    bool m_needConversion;
 };
 
 bool wxSoundBackendOSS::IsAvailable() const
@@ -142,12 +137,12 @@ bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags,
                              volatile wxSoundPlaybackStatus *status)
 {
     int dev = OpenDSP(data);
-    
+
     if (dev < 0)
         return false;
 
     ioctl(dev, SNDCTL_DSP_SYNC, 0);
+
     do
     {
         bool play = true;
@@ -165,7 +160,7 @@ bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags,
             }
 
             i= (int)((l + m_DSPblkSize) < datasize ?
-                    m_DSPblkSize : (datasize - l));
+                     m_DSPblkSize : (datasize - l));
             if (write(dev, &data->m_data[l], i) != i)
             {
                 play = false;
@@ -175,21 +170,17 @@ bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags,
     } while (flags & wxSOUND_LOOP);
 
     close(dev);
-    
     return true;
 }
 
 int wxSoundBackendOSS::OpenDSP(const wxSoundData *data)
 {
     int dev = -1;
-  
+
     if ((dev = open(AUDIODEV, O_WRONLY, 0)) <0)
         return -1;
-  
-    if (!InitDSP(dev,
-                 (int)data->m_bitsPerSample,
-                 data->m_channels == 1 ? 0 : 1,
-                 data->m_samplingRate))
+
+    if (!InitDSP(dev, data) || m_needConversion)
     {
         close(dev);
         return -1;
@@ -198,20 +189,77 @@ int wxSoundBackendOSS::OpenDSP(const wxSoundData *data)
     return dev;
 }
 
-bool wxSoundBackendOSS::InitDSP(int dev, int iDataBits, int iChannel,
-                               unsigned long ulSamplingRate)
+
+bool wxSoundBackendOSS::InitDSP(int dev, const wxSoundData *data)
 {
-    if (ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &m_DSPblkSize) < 0)
-        return false;
-    wxLogTrace(_T("sound"), _T("OSS block size: %i"), m_DSPblkSize);
-    if (m_DSPblkSize < 4096 || m_DSPblkSize > 65536)
+    unsigned tmp;
+
+    // Reset the dsp
+    if (ioctl(dev, SNDCTL_DSP_RESET, 0) < 0)
+    {
+        wxLogTrace(_T("sound"), _T("unable to reset dsp"));
         return false;
-    if (ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &iDataBits) < 0)
+    }
+
+    m_needConversion = false;
+
+    tmp = data->m_bitsPerSample;
+    if (ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
+    {
+        wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SAMPLESIZE)"));
         return false;
-    if (ioctl(dev, SNDCTL_DSP_STEREO, &iChannel) < 0)
+    }
+    if (tmp != data->m_bitsPerSample)
+    {
+        wxLogTrace(_T("sound"),
+                   _T("Unable to set DSP sample size to %d (wants %d)"),
+                   data->m_bitsPerSample, tmp);
+        m_needConversion = true;
+    }
+
+    unsigned stereo = data->m_channels == 1 ? 0 : 1;
+    tmp = stereo;
+    if (ioctl(dev, SNDCTL_DSP_STEREO, &tmp) < 0)
+    {
+        wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_STEREO)"));
         return false;
-    if (ioctl(dev, SNDCTL_DSP_SPEED, &ulSamplingRate) < 0)
+    }
+    if (tmp != stereo)
+    {
+        wxLogTrace(_T("sound"), _T("Unable to set DSP to %s."), stereo?  _T("stereo"):_T("mono"));
+        m_needConversion = true;
+    }
+
+    tmp = data->m_samplingRate;
+    if (ioctl(dev, SNDCTL_DSP_SPEED, &tmp) < 0)
+    {
+        wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SPEED)"));
+       return false;
+    }
+    if (tmp != data->m_samplingRate)
+    {
+        // If the rate the sound card is using is not within 1% of what the
+        // data specified then override the data setting.  The only reason not
+        // to always override this is because of clock-rounding
+        // problems. Sound cards will sometimes use things like 44101 when you
+        // ask for 44100.  No need overriding this and having strange output
+        // file rates for something that we can't hear anyways.
+        if (data->m_samplingRate - tmp > (tmp * .01) ||
+            tmp - data->m_samplingRate > (tmp * .01)) {
+            wxLogTrace(_T("sound"),
+                       _T("Unable to set DSP sampling rate to %d (wants %d)"),
+                       data->m_samplingRate, tmp);
+            m_needConversion = true;
+        }
+    }
+
+    // Do this last because some drivers can adjust the buffer sized based on
+    // the sampling rate, etc.
+    if (ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &m_DSPblkSize) < 0)
+    {
+        wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_GETBLKSIZE)"));
         return false;
+    }
     return true;
 }
 
@@ -234,7 +282,7 @@ public:
                               wxSoundData *data, unsigned flags)
         : wxThread(), m_adapt(adaptor), m_data(data), m_flags(flags) {}
     virtual ExitCode Entry();
-    
+
 protected:
     wxSoundSyncOnlyAdaptor *m_adapt;
     wxSoundData *m_data;
@@ -340,9 +388,11 @@ bool wxSoundSyncOnlyAdaptor::Play(wxSoundData *data, unsigned flags,
 void wxSoundSyncOnlyAdaptor::Stop()
 {
     wxLogTrace(_T("sound"), _T("asking audio to stop"));
+
+#if wxUSE_THREADS
     // tell the player thread (if running) to stop playback ASAP:
     m_status.m_stopRequested = true;
-    
+
     // acquire the mutex to be sure no sound is being played, then
     // release it because we don't need it for anything (the effect of this
     // is that calling thread will wait until playback thread reacts to
@@ -350,16 +400,21 @@ void wxSoundSyncOnlyAdaptor::Stop()
     m_mutexRightToPlay.Lock();
     m_mutexRightToPlay.Unlock();
     wxLogTrace(_T("sound"), _T("audio was stopped"));
+#endif
 }
 
 bool wxSoundSyncOnlyAdaptor::IsPlaying() const
 {
+#if wxUSE_THREADS
     return m_status.m_playing;
+#else
+    return false;
+#endif
 }
 
 
 // ----------------------------------------------------------------------------
-// wxSound 
+// wxSound
 // ----------------------------------------------------------------------------
 
 wxSoundBackend *wxSound::ms_backend = NULL;
@@ -396,18 +451,22 @@ bool wxSound::Create(const wxString& fileName, bool isResource)
 {
     wxASSERT_MSG( !isResource,
              _T("Loading sound from resources is only supported on Windows") );
+
     Free();
-  
+
     wxFile fileWave;
     if (!fileWave.Open(fileName, wxFile::read))
-       {
-            return false;
-       }
+    {
+        return false;
+    }
+
+    wxFileOffset lenOrig = fileWave.Length();
+    if ( lenOrig == wxInvalidOffset )
+        return false;
 
-    size_t len = fileWave.Length();
+    size_t len = wx_truncate_cast(size_t, lenOrig);
     wxUint8 *data = new wxUint8[len];
-    if (fileWave.Read(data, len) != len)
+    if ( fileWave.Read(data, len) != lenOrig )
     {
         wxLogError(_("Couldn't load sound data from '%s'."), fileName.c_str());
         return false;
@@ -419,7 +478,7 @@ bool wxSound::Create(const wxString& fileName, bool isResource)
                    fileName.c_str());
         return false;
     }
-    
+
     return true;
 }
 
@@ -442,16 +501,8 @@ bool wxSound::Create(int size, const wxByte* data)
     {
         // FIXME -- make this fully dynamic when plugins architecture is in
         // place
-#ifdef HAVE_SYS_SOUNDCARD_H
-        ms_backend = new wxSoundBackendOSS();
-        if (!ms_backend->IsAvailable())
-        {
-            wxDELETE(ms_backend);
-        }
-#endif
-
 #if wxUSE_LIBSDL
-        if (!ms_backend)
+        //if (!ms_backend)
         {
 #if !wxUSE_PLUGINS
             ms_backend = wxCreateSoundBackendSDL();
@@ -488,6 +539,17 @@ bool wxSound::Create(int size, const wxByte* data)
         }
 #endif
 
+#ifdef HAVE_SYS_SOUNDCARD_H
+        if (!ms_backend)
+        {
+            ms_backend = new wxSoundBackendOSS();
+            if (!ms_backend->IsAvailable())
+            {
+                wxDELETE(ms_backend);
+            }
+        }
+#endif
+
         if (!ms_backend)
             ms_backend = new wxSoundBackendNull();
 
@@ -506,7 +568,7 @@ bool wxSound::Create(int size, const wxByte* data)
         wxLogTrace(_T("sound"), _T("unloading backend"));
 
         Stop();
+
         delete ms_backend;
         ms_backend = NULL;
 #if wxUSE_LIBSDL && wxUSE_PLUGINS
@@ -547,7 +609,7 @@ void wxSound::Free()
 }
 
 typedef struct
-{ 
+{
     wxUint32      uiSize;
     wxUint16      uiFormatTag;
     wxUint16      uiChannels;
@@ -557,7 +619,6 @@ typedef struct
     wxUint16      uiBitsPerSample;
 } WAVEFORMAT;
 
-#define MONO             1  // and stereo is 2 by wav format
 #define WAVE_FORMAT_PCM  1
 #define WAVE_INDEX       8
 #define FMT_INDEX       12
@@ -589,18 +650,18 @@ bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
         return false;
     memcpy(&ul,&data[FMT_INDEX + waveformat.uiSize + 12], 4);
     ul = wxUINT32_SWAP_ON_BE(ul);
-    
+
     //WAS: if (ul + FMT_INDEX + waveformat.uiSize + 16 != length)
     if (ul + FMT_INDEX + waveformat.uiSize + 16 > length)
         return false;
-  
+
     if (waveformat.uiFormatTag != WAVE_FORMAT_PCM)
         return false;
-  
-    if (waveformat.ulSamplesPerSec != 
+
+    if (waveformat.ulSamplesPerSec !=
         waveformat.ulAvgBytesPerSec / waveformat.uiBlockAlign)
         return false;
-    
+
     m_data = new wxSoundData;
     m_data->m_channels = waveformat.uiChannels;
     m_data->m_samplingRate = waveformat.ulSamplesPerSec;
@@ -616,7 +677,7 @@ bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
     else
         m_data->m_dataWithHeader = (wxUint8*)data;
 
-    m_data->m_data = 
+    m_data->m_data =
         (&m_data->m_dataWithHeader[FMT_INDEX + waveformat.uiSize + 8]);
 
     return true;