--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: wave.h
+// Purpose: wxSound class
+// Author: Julian Smart, Vaclav Slavik
+// Modified by:
+// Created: 25/10/98
+// RCS-ID: $Id$
+// Copyright: (c) Julian Smart, Vaclav Slavik
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_SOUND_H_
+#define _WX_SOUND_H_
+
+#include "wx/defs.h"
+
+#if wxUSE_WAVE
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma interface "sound.h"
+#endif
+
+#include "wx/object.h"
+
+// ----------------------------------------------------------------------------
+// wxSound: simple audio playback class
+// ----------------------------------------------------------------------------
+
+class wxSoundBackend;
+class wxSound;
+class wxDynamicLibrary;
+
+/// Sound data, as loaded from .wav file:
+class wxSoundData
+{
+public:
+ wxSoundData() : m_refCnt(1) {}
+ void IncRef();
+ void DecRef();
+
+ // .wav header information:
+ unsigned m_channels; // num of channels (mono:1, stereo:2)
+ unsigned m_samplingRate;
+ unsigned m_bitsPerSample; // if 8, then m_data contains unsigned 8bit
+ // samples (wxUint8), if 16 then signed 16bit
+ // (wxInt16)
+ unsigned m_samples; // length in samples:
+
+ // wave data:
+ size_t m_dataBytes;
+ wxUint8 *m_data; // m_dataBytes bytes of data
+
+private:
+ ~wxSoundData();
+ unsigned m_refCnt;
+ wxUint8 *m_dataWithHeader; // ditto, but prefixed with .wav header
+ friend class wxSound;
+};
+
+
+/// Simple sound class:
+class wxSound : public wxSoundBase
+{
+public:
+ wxSound();
+ wxSound(const wxString& fileName, bool isResource = false);
+ wxSound(int size, const wxByte* data);
+ ~wxSound();
+
+ // Create from resource or file
+ bool Create(const wxString& fileName, bool isResource = false);
+ // Create from data
+ bool Create(int size, const wxByte* data);
+
+ bool IsOk() const { return m_data != NULL; }
+
+ // for internal use
+ static void UnloadBackend();
+
+protected:
+ bool DoPlay(unsigned flags);
+
+ static void EnsureBackend();
+ void Free();
+ bool LoadWAV(const wxUint8 *data, size_t length, bool copyData);
+
+ static wxSoundBackend *ms_backend;
+#if wxUSE_LIBSDL && wxUSE_PLUGINS
+ // FIXME - temporary, until we have plugins architecture
+ static wxDynamicLibrary *ms_backendSDL;
+#endif
+
+private:
+ wxSoundData *m_data;
+};
+
+
+// ----------------------------------------------------------------------------
+// wxSoundBackend:
+// ----------------------------------------------------------------------------
+
+// This is interface to sound playing implementation. There are multiple
+// sound architectures in use on Unix platforms and wxWindows can use several
+// of them for playback, depending on their availability at runtime; hence
+// the need for backends. This class is for use by wxWindows and people writing
+// additional backends only, it is _not_ for use by applications!
+
+class wxSoundBackend
+{
+public:
+ virtual ~wxSoundBackend() {}
+
+ // Returns the name of the backend (e.g. "Open Sound System")
+ virtual wxString GetName() const = 0;
+
+ // Returns priority (higher priority backends are tried first)
+ virtual int GetPriority() const = 0;
+
+ // Checks if the backend's audio system is available and the backend can
+ // be used for playback
+ virtual bool IsAvailable() const = 0;
+
+ // Returns true if the backend is capable of playing sound asynchronously.
+ // If false, then wxWindows creates a playback thread and handles async
+ // playback, otherwise it is left up to the backend (will usually be more
+ // effective)
+ virtual bool HasNativeAsyncPlayback() const = 0;
+
+ // Plays the sound. flags are same flags as those passed to wxSound::Play
+ virtual bool Play(wxSoundData *data, unsigned flags) = 0;
+};
+
+
+#endif // wxUSE_WAVE
+
+#endif
+++ /dev/null
-/////////////////////////////////////////////////////////////////////////////
-// Name: wave.h
-// Purpose: wxWave class
-// Author: Julian Smart
-// Modified by:
-// Created: 25/10/98
-// RCS-ID: $Id$
-// Copyright: (c) Julian Smart
-// Licence: wxWindows licence
-/////////////////////////////////////////////////////////////////////////////
-
-#ifndef _WX_WAVE_H_
-#define _WX_WAVE_H_
-
-#include "wx/defs.h"
-
-#if wxUSE_WAVE
-
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma interface "wave.h"
-#endif
-
-#include "wx/object.h"
-
-#ifndef AUDIODEV
-#define AUDIODEV "/dev/dsp" // Default path for audio device
-#endif
-
-class wxWave : public wxObject
-{
-public:
- wxWave();
- wxWave(const wxString& fileName, bool isResource = FALSE);
- wxWave(int size, const wxByte* data);
- ~wxWave();
-
-public:
- // Create from resource or file
- bool Create(const wxString& fileName, bool isResource = FALSE);
- // Create from data
- bool Create(int size, const wxByte* data);
-
- bool IsOk() const { return (m_waveData ? TRUE : FALSE); };
- bool Play(bool async = TRUE, bool looped = FALSE);
-
-protected:
- bool Free();
-
-private:
- wxByte* m_waveData;
- int m_waveLength;
- bool m_isResource;
-
-
- int OpenDSP(void);
- bool InitDSP(int dev, int iDataBits, int iChannel,unsigned long ulSamplingRate);
- int m_DSPblkSize; // Size of the DSP buffer
- char *m_data;
- int m_sizeData;
-};
-
-#endif
-
-#endif
-
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: sound.cpp
+// Purpose: wxSound
+// Author: Marcel Rasche, Vaclav Slavik
+// Modified by:
+// Created: 25/10/98
+// RCS-ID: $Id$
+// Copyright: (c) Julian Smart, Vaclav Slavik
+// 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"
+
+#include "wx/setup.h"
+
+#if defined(__BORLANDC__)
+#pragma hdrstop
+#endif
+
+#if wxUSE_WAVE
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#if HAVE_SYS_SOUNDCARD_H
+#include <sys/soundcard.h>
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/event.h"
+ #include "wx/intl.h"
+ #include "wx/log.h"
+#endif
+
+#include "wx/thread.h"
+#include "wx/file.h"
+#include "wx/module.h"
+#include "wx/sound.h"
+#include "wx/dynlib.h"
+
+// ----------------------------------------------------------------------------
+// wxSoundBackendNull, used in absence of audio API or card
+// ----------------------------------------------------------------------------
+
+class wxSoundBackendNull : public wxSoundBackend
+{
+public:
+ wxString GetName() const { return _("No sound"); }
+ int GetPriority() const { return 0; }
+ bool IsAvailable() const { return true; }
+ bool HasNativeAsyncPlayback() const { return true; }
+ bool Play(wxSoundData *WXUNUSED(data), unsigned WXUNUSED(flags))
+ { return true; }
+};
+
+
+// ----------------------------------------------------------------------------
+// wxSoundBackendOSS, for Linux
+// ----------------------------------------------------------------------------
+
+#ifdef HAVE_SYS_SOUNDCARD_H
+
+#ifndef AUDIODEV
+#define AUDIODEV "/dev/dsp" // Default path for audio device
+#endif
+
+class wxSoundBackendOSS : public wxSoundBackend
+{
+public:
+ wxString GetName() const { return _T("Open Sound System"); }
+ int GetPriority() const { return 10; }
+ bool IsAvailable() const;
+ bool HasNativeAsyncPlayback() const { return false; }
+ bool Play(wxSoundData *data, unsigned flags);
+
+private:
+ int OpenDSP(const wxSoundData *data);
+ bool InitDSP(int dev, int iDataBits, int iChannel,
+ unsigned long ulSamplingRate);
+
+ int m_DSPblkSize; // Size of the DSP buffer
+};
+
+bool wxSoundBackendOSS::IsAvailable() const
+{
+ int fd;
+ fd = open(AUDIODEV, O_WRONLY | O_NONBLOCK);
+ if (fd < 0)
+ return false;
+ close(fd);
+ return true;
+}
+
+bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags)
+{
+ int dev = OpenDSP(data);
+
+ if (dev < 0)
+ return false;
+
+ ioctl(dev, SNDCTL_DSP_SYNC, 0);
+
+ do
+ {
+ bool play = true;
+ int i;
+ unsigned l = 0;
+ size_t datasize = data->m_dataBytes;
+
+ do
+ {
+ i= (int)((l + m_DSPblkSize) < datasize ?
+ m_DSPblkSize : (datasize - l));
+ if (write(dev, &data->m_data[l], i) != i)
+ {
+ play = false;
+ }
+ l += i;
+ } while (play && l < datasize);
+ } 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))
+ {
+ close(dev);
+ return -1;
+ }
+
+ return dev;
+}
+
+bool wxSoundBackendOSS::InitDSP(int dev, int iDataBits, int iChannel,
+ unsigned long ulSamplingRate)
+{
+ if (ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &m_DSPblkSize) < 0)
+ return false;
+ if (m_DSPblkSize < 4096 || m_DSPblkSize > 65536)
+ return false;
+ if (ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &iDataBits) < 0)
+ return false;
+ if (ioctl(dev, SNDCTL_DSP_STEREO, &iChannel) < 0)
+ return false;
+ if (ioctl(dev, SNDCTL_DSP_SPEED, &ulSamplingRate) < 0)
+ return false;
+ return true;
+}
+
+#endif // HAVE_SYS_SOUNDCARD_H
+
+
+// ----------------------------------------------------------------------------
+// wxSoundData
+// ----------------------------------------------------------------------------
+
+void wxSoundData::IncRef()
+{
+ m_refCnt++;
+}
+
+void wxSoundData::DecRef()
+{
+ if (--m_refCnt == 0)
+ delete this;
+}
+
+wxSoundData::~wxSoundData()
+{
+ delete[] m_dataWithHeader;
+}
+
+
+// ----------------------------------------------------------------------------
+// wxSoundAsyncPlaybackThread
+// ----------------------------------------------------------------------------
+
+#if wxUSE_THREADS
+
+// mutex for all wxSound's synchronization
+static wxMutex gs_soundMutex;
+
+// this class manages asynchronous playback of audio if the backend doesn't
+// support it natively (e.g. OSS backend)
+class wxSoundAsyncPlaybackThread : public wxThread
+{
+public:
+ wxSoundAsyncPlaybackThread(wxSoundBackend *backend,
+ wxSoundData *data, unsigned flags)
+ : wxThread(), m_backend(backend), m_data(data), m_flags(flags) {}
+ virtual ExitCode Entry()
+ {
+ m_backend->Play(m_data, m_flags & ~wxSOUND_ASYNC);
+ wxMutexLocker locker(gs_soundMutex);
+ m_data->DecRef();
+ wxLogTrace(_T("sound"), _T("terminated async playback thread"));
+ return 0;
+ }
+
+protected:
+ wxSoundBackend *m_backend;
+ wxSoundData *m_data;
+ unsigned m_flags;
+};
+
+#endif // wxUSE_THREADS
+
+// ----------------------------------------------------------------------------
+// wxSound
+// ----------------------------------------------------------------------------
+
+wxSoundBackend *wxSound::ms_backend = NULL;
+
+// FIXME - temporary, until we have plugins architecture
+#if wxUSE_LIBSDL
+ #if wxUSE_PLUGINS
+ wxDynamicLibrary *wxSound::ms_backendSDL = NULL;
+ #else
+ extern "C" wxSoundBackend *wxCreateSoundBackendSDL();
+ #endif
+#endif
+
+wxSound::wxSound() : m_data(NULL)
+{
+}
+
+wxSound::wxSound(const wxString& sFileName, bool isResource) : m_data(NULL)
+{
+ Create(sFileName, isResource);
+}
+
+wxSound::wxSound(int size, const wxByte* data) : m_data(NULL)
+{
+ Create(size, data);
+}
+
+wxSound::~wxSound()
+{
+ Free();
+}
+
+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;
+ }
+
+ size_t len = fileWave.Length();
+ wxUint8 *data = new wxUint8[len];
+ if (fileWave.Read(data, len) != len)
+ {
+ wxLogError(_("Couldn't load sound data from '%s'."), fileName.c_str());
+ return false;
+ }
+
+ if (!LoadWAV(data, len, false))
+ {
+ wxLogError(_("Sound file '%s' is in unsupported format."),
+ fileName.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool wxSound::Create(int size, const wxByte* data)
+{
+ wxASSERT( data != NULL );
+
+ Free();
+ if (!LoadWAV(data, size, true))
+ {
+ wxLogError(_("Sound data are in unsupported format."));
+ return false;
+ }
+ return true;
+}
+
+/*static*/ void wxSound::EnsureBackend()
+{
+ if (!ms_backend)
+ {
+ // 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 !wxUSE_PLUGINS
+ ms_backend = wxCreateSoundBackendSDL();
+#else
+ wxString dllname;
+ dllname.Printf(_T("%s/%s"),
+ wxDynamicLibrary::GetPluginsDirectory().c_str(),
+ wxDynamicLibrary::CanonicalizePluginName(
+ _T("sound_sdl"), wxDL_PLUGIN_BASE).c_str());
+ wxLogTrace(_T("sound"),
+ _T("trying to load SDL plugin from '%s'..."),
+ dllname.c_str());
+ wxLogNull null;
+ ms_backendSDL = new wxDynamicLibrary(dllname, wxDL_NOW);
+ if (!ms_backendSDL->IsLoaded())
+ {
+ wxDELETE(ms_backendSDL);
+ }
+ else
+ {
+ typedef wxSoundBackend *(*wxCreateSoundBackend_t)();
+ wxDYNLIB_FUNCTION(wxCreateSoundBackend_t,
+ wxCreateSoundBackendSDL, *ms_backendSDL);
+ if (pfnwxCreateSoundBackendSDL)
+ {
+ ms_backend = (*pfnwxCreateSoundBackendSDL)();
+ }
+ }
+#endif
+ if (ms_backend && !ms_backend->IsAvailable())
+ {
+ wxDELETE(ms_backend);
+ }
+ }
+#endif
+
+ if (!ms_backend)
+ ms_backend = new wxSoundBackendNull();
+
+ wxLogTrace(_T("sound"),
+ _T("using backend '%s'"), ms_backend->GetName().c_str());
+ }
+}
+
+/*static*/ void wxSound::UnloadBackend()
+{
+ if (ms_backend)
+ {
+ wxLogTrace(_T("sound"), _T("unloading backend"));
+ delete ms_backend;
+ ms_backend = NULL;
+#if wxUSE_LIBSDL && wxUSE_PLUGINS
+ delete ms_backendSDL;
+#endif
+ }
+}
+
+bool wxSound::DoPlay(unsigned flags)
+{
+ wxCHECK_MSG( IsOk(), false, _T("Attempt to play invalid wave data") );
+
+ EnsureBackend();
+
+ if ((flags & wxSOUND_ASYNC) && !ms_backend->HasNativeAsyncPlayback())
+ {
+#if wxUSE_THREADS
+ wxMutexLocker locker(gs_soundMutex);
+ m_data->IncRef();
+ wxThread *th = new wxSoundAsyncPlaybackThread(ms_backend, m_data, flags);
+ th->Create();
+ th->Run();
+ wxLogTrace(_T("sound"), _T("launched async playback thread"));
+#else
+ wxLogError(_("Unable to play sound asynchronously."));
+ return false;
+#endif
+ }
+ else
+ {
+ ms_backend->Play(m_data, flags);
+ }
+ return true;
+}
+
+void wxSound::Free()
+{
+#if wxUSE_THREADS
+ wxMutexLocker locker(gs_soundMutex);
+#endif
+ if (m_data)
+ m_data->DecRef();
+}
+
+typedef struct
+{
+ wxUint32 uiSize;
+ wxUint16 uiFormatTag;
+ wxUint16 uiChannels;
+ wxUint32 ulSamplesPerSec;
+ wxUint32 ulAvgBytesPerSec;
+ wxUint16 uiBlockAlign;
+ 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
+
+bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
+{
+ WAVEFORMAT waveformat;
+ wxUint32 ul;
+
+ if (length < 32 + sizeof(WAVEFORMAT))
+ return false;
+
+ memcpy(&waveformat, &data[FMT_INDEX + 4], sizeof(WAVEFORMAT));
+ waveformat.uiSize = wxUINT32_SWAP_ON_BE(waveformat.uiSize);
+ waveformat.uiFormatTag = wxUINT16_SWAP_ON_BE(waveformat.uiFormatTag);
+ waveformat.uiChannels = wxUINT16_SWAP_ON_BE(waveformat.uiChannels);
+ waveformat.ulSamplesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulSamplesPerSec);
+ waveformat.ulAvgBytesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulAvgBytesPerSec);
+ waveformat.uiBlockAlign = wxUINT16_SWAP_ON_BE(waveformat.uiBlockAlign);
+ waveformat.uiBitsPerSample = wxUINT16_SWAP_ON_BE(waveformat.uiBitsPerSample);
+
+ if (memcmp(data, "RIFF", 4) != 0)
+ return false;
+ if (memcmp(&data[WAVE_INDEX], "WAVE", 4) != 0)
+ return false;
+ if (memcmp(&data[FMT_INDEX], "fmt ", 4) != 0)
+ return false;
+ if (memcmp(&data[FMT_INDEX + waveformat.uiSize + 8], "data", 4) != 0)
+ 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 !=
+ waveformat.ulAvgBytesPerSec / waveformat.uiBlockAlign)
+ return false;
+
+ m_data = new wxSoundData;
+ m_data->m_channels = waveformat.uiChannels;
+ m_data->m_samplingRate = waveformat.ulSamplesPerSec;
+ m_data->m_bitsPerSample = waveformat.uiBitsPerSample;
+ m_data->m_samples = ul / (m_data->m_channels * m_data->m_bitsPerSample / 8);
+ m_data->m_dataBytes = ul;
+
+ if (copyData)
+ {
+ m_data->m_dataWithHeader = new wxUint8[length];
+ memcpy(m_data->m_dataWithHeader, data, length);
+ }
+ else
+ m_data->m_dataWithHeader = (wxUint8*)data;
+
+ m_data->m_data =
+ (&m_data->m_dataWithHeader[FMT_INDEX + waveformat.uiSize + 8]);
+
+ return true;
+}
+
+
+// ----------------------------------------------------------------------------
+// wxSoundCleanupModule
+// ----------------------------------------------------------------------------
+
+class wxSoundCleanupModule: public wxModule
+{
+public:
+ bool OnInit() { return true; }
+ void OnExit() { wxSound::UnloadBackend(); }
+ DECLARE_DYNAMIC_CLASS(wxSoundCleanupModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxSoundCleanupModule, wxModule)
+
+#endif
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: sound_sdl.cpp
+// Purpose: wxSound backend using SDL
+// Author: Vaclav Slavik
+// Modified by:
+// Created: 2004/01/31
+// RCS-ID: $Id$
+// Copyright: (c) 2004, Vaclav Slavik
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// for compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#include "wx/setup.h"
+
+#if defined(__BORLANDC__)
+#pragma hdrstop
+#endif
+
+#if wxUSE_WAVE && wxUSE_LIBSDL
+
+#include <SDL.h>
+
+#ifndef WX_PRECOMP
+ #include "wx/event.h"
+ #include "wx/intl.h"
+ #include "wx/log.h"
+ #include "wx/list.h"
+ #include "wx/utils.h"
+#endif
+
+#include "wx/thread.h"
+#include "wx/module.h"
+#include "wx/sound.h"
+#include "wx/listimpl.cpp"
+
+// ----------------------------------------------------------------------------
+// wxSoundBackendSDL, for Unix with libSDL
+// ----------------------------------------------------------------------------
+
+struct wxSoundBackendSDLQueueEntry
+{
+ wxSoundData *m_data;
+ unsigned m_pos;
+ SDL_AudioSpec m_spec;
+ bool m_loop;
+ bool m_finished;
+};
+
+WX_DECLARE_LIST(wxSoundBackendSDLQueueEntry, wxSoundBackendSDLQueue);
+WX_DEFINE_LIST(wxSoundBackendSDLQueue);
+
+
+class wxSoundBackendSDLNotification : public wxEvent
+{
+public:
+ DECLARE_DYNAMIC_CLASS(wxSoundBackendSDLNotification)
+ wxSoundBackendSDLNotification();
+ wxEvent *Clone() const { return new wxSoundBackendSDLNotification(*this); }
+};
+
+typedef void (wxEvtHandler::*wxSoundBackendSDLNotificationFunction)
+ (wxSoundBackendSDLNotification&);
+
+BEGIN_DECLARE_EVENT_TYPES()
+ DECLARE_LOCAL_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, -1)
+END_DECLARE_EVENT_TYPES()
+
+#define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \
+ DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \
+ -1, \
+ -1, \
+ (wxObjectEventFunction) \
+ (wxSoundBackendSDLNotificationFunction)& func, \
+ (wxObject *) NULL ),
+
+IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification, wxEvtHandler)
+DEFINE_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION)
+
+wxSoundBackendSDLNotification::wxSoundBackendSDLNotification()
+{
+ SetEventType(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION);
+}
+
+class wxSoundBackendSDLEvtHandler;
+
+class wxSoundBackendSDL : public wxSoundBackend
+{
+public:
+ wxSoundBackendSDL()
+ : m_initialized(false), m_playing(false), m_evtHandler(NULL) {}
+ virtual ~wxSoundBackendSDL();
+
+ wxString GetName() const { return _T("Simple DirectMedia Layer"); }
+ int GetPriority() const { return 9; }
+ bool IsAvailable() const;
+ bool HasNativeAsyncPlayback() const { return true; }
+ bool Play(wxSoundData *data, unsigned flags);
+
+ void FillAudioBuffer(Uint8 *stream, int len);
+ bool PlayNextSampleInQueue();
+
+private:
+ bool m_initialized;
+ bool m_playing;
+ wxSoundBackendSDLQueue m_queue;
+ wxSoundBackendSDLEvtHandler *m_evtHandler;
+};
+
+class wxSoundBackendSDLEvtHandler : public wxEvtHandler
+{
+public:
+ wxSoundBackendSDLEvtHandler(wxSoundBackendSDL *bk) : m_backend(bk) {}
+
+private:
+ void OnNotify(wxSoundBackendSDLNotification& WXUNUSED(event))
+ {
+ wxLogTrace(_T("sound"),
+ _T("received playback status change notification"));
+ m_backend->PlayNextSampleInQueue();
+ }
+ wxSoundBackendSDL *m_backend;
+
+ DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(wxSoundBackendSDLEvtHandler, wxEvtHandler)
+ EVT_SOUND_BACKEND_SDL_NOTIFICATON(wxSoundBackendSDLEvtHandler::OnNotify)
+END_EVENT_TABLE()
+
+wxSoundBackendSDL::~wxSoundBackendSDL()
+{
+ SDL_LockAudio();
+ if (m_playing)
+ SDL_CloseAudio();
+ SDL_UnlockAudio();
+ wxDELETE(m_evtHandler);
+ WX_CLEAR_LIST(wxSoundBackendSDLQueue, m_queue)
+}
+
+bool wxSoundBackendSDL::IsAvailable() const
+{
+ if (m_initialized)
+ return true;
+ if (SDL_WasInit(SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
+ {
+ if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) == -1)
+ return false;
+ }
+ wxConstCast(this, wxSoundBackendSDL)->m_initialized = true;
+ wxLogTrace(_T("sound"), _T("initialized SDL audio subsystem"));
+ return true;
+}
+
+extern "C" void wx_sdl_audio_callback(void *userdata, Uint8 *stream, int len)
+{
+ wxSoundBackendSDL *bk = (wxSoundBackendSDL*)userdata;
+ bk->FillAudioBuffer(stream, len);
+}
+
+void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
+{
+ wxSoundBackendSDLQueueEntry *e = m_queue.front();
+ if (!e->m_finished)
+ {
+ // finished playing the sample
+ if (e->m_pos == e->m_data->m_dataBytes)
+ {
+ e->m_finished = true;
+ m_playing = false;
+ wxSoundBackendSDLNotification event;
+ m_evtHandler->AddPendingEvent(event);
+ }
+ // still something to play
+ else
+ {
+ unsigned size = ((len + e->m_pos) < e->m_data->m_dataBytes) ?
+ len :
+ (e->m_data->m_dataBytes - e->m_pos);
+ memcpy(stream, e->m_data->m_data + e->m_pos, size);
+ e->m_pos += size;
+ len -= size;
+ stream += size;
+ }
+ }
+ // the sample doesn't play, fill the buffer with silence and wait for
+ // the main thread to shut the playback down:
+ if (len > 0)
+ {
+ if (e->m_loop)
+ {
+ e->m_pos = 0;
+ FillAudioBuffer(stream, len);
+ return;
+ }
+ else
+ {
+ memset(stream, e->m_spec.silence, len);
+ }
+ }
+}
+
+bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags)
+{
+ data->IncRef();
+
+ wxSoundBackendSDLQueueEntry *e = new wxSoundBackendSDLQueueEntry();
+ e->m_data = data;
+ e->m_pos = 0;
+ e->m_loop = (flags & wxSOUND_LOOP);
+ e->m_finished = false;
+ e->m_spec.freq = data->m_samplingRate;
+ e->m_spec.channels = data->m_channels;
+ e->m_spec.silence = 0;
+ e->m_spec.samples = 4096;
+ e->m_spec.size = 0;
+ e->m_spec.callback = wx_sdl_audio_callback;
+ e->m_spec.userdata = (void*)this;
+
+ if (data->m_bitsPerSample == 8)
+ e->m_spec.format = AUDIO_U8;
+ else if (data->m_bitsPerSample == 16)
+ e->m_spec.format = AUDIO_S16LSB;
+ else
+ return false;
+
+ m_queue.push_back(e);
+ wxLogTrace(_T("sound"), _T("queued sample %p for playback"), e);
+
+ if (!PlayNextSampleInQueue())
+ return false;
+
+ if (!(flags & wxSOUND_ASYNC))
+ {
+ wxLogTrace(_T("sound"), _T("waiting for sample to finish"));
+ while (!m_queue.empty() && m_queue.front() == e && !e->m_finished)
+ {
+#if wxUSE_THREADS
+ // give the playback thread a chance to add event to pending
+ // events queue, release GUI lock temporarily:
+ if (wxThread::IsMain())
+ wxMutexGuiLeave();
+#endif
+ wxUsleep(10);
+#if wxUSE_THREADS
+ if (wxThread::IsMain())
+ wxMutexGuiEnter();
+#endif
+ }
+ wxLogTrace(_T("sound"), _T("sample finished"));
+ }
+
+ return true;
+}
+
+bool wxSoundBackendSDL::PlayNextSampleInQueue()
+{
+ bool status = true;
+
+ SDL_LockAudio();
+
+ if (!m_evtHandler)
+ m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
+
+ if (!m_playing && !m_queue.empty())
+ {
+ bool needsReopen = true;
+ // shut down playing of finished sound:
+ wxSoundBackendSDLQueueEntry *e = m_queue.front();
+ if (e->m_finished)
+ {
+ SDL_PauseAudio(1);
+ e->m_data->DecRef();
+ m_queue.pop_front();
+ if (!m_queue.empty() &&
+ e->m_spec.freq == m_queue.front()->m_spec.freq &&
+ e->m_spec.channels == m_queue.front()->m_spec.channels &&
+ e->m_spec.format == m_queue.front()->m_spec.format)
+ {
+ needsReopen = false;
+ }
+ else
+ {
+ SDL_CloseAudio();
+ wxLogTrace(_T("sound"), _T("closed audio"));
+ }
+ delete e;
+ }
+ // start playing another one:
+ if (!m_queue.empty())
+ {
+ wxSoundBackendSDLQueueEntry *e = m_queue.front();
+ m_playing = true;
+ wxLogTrace(_T("sound"), _T("playing sample %p"), e);
+
+ if (needsReopen)
+ {
+ wxLogTrace(_T("sound"), _T("opening SDL audio..."));
+ status = (SDL_OpenAudio(&e->m_spec, NULL) >= 0);
+ if (status)
+ {
+#if wxUSE_LOG_DEBUG
+ char driver[256];
+ SDL_AudioDriverName(driver, 256);
+ wxLogTrace(_T("sound"), _T("opened audio, driver '%s'"),
+ wxString(driver, wxConvLocal).c_str());
+#endif
+ SDL_PauseAudio(0);
+ }
+ else
+ {
+ wxString err(SDL_GetError(), wxConvLocal);
+ wxLogError(_("Couldn't open audio: %s"), err.c_str());
+ m_queue.pop_front();
+ delete e;
+ }
+ }
+ else
+ SDL_PauseAudio(0);
+ }
+ }
+
+ SDL_UnlockAudio();
+
+ return status;
+}
+
+extern "C" wxSoundBackend *wxCreateSoundBackendSDL()
+{
+ return new wxSoundBackendSDL();
+}
+
+#endif // wxUSE_WAVE && wxUSE_LIBSDL
+++ /dev/null
-/////////////////////////////////////////////////////////////////////////////
-// Name: wave.cpp
-// Purpose: wxWave
-// Author: Marcel Rasche
-// Modified by:
-// Created: 25/10/98
-// RCS-ID: $Id$
-// Copyright: (c) Julian Smart
-// Licence: wxWindows licence
-/////////////////////////////////////////////////////////////////////////////
-
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "wave.h"
-#endif
-
-// for compilers that support precompilation, includes "wx.h".
-#include "wx/wxprec.h"
-
-#include "wx/setup.h"
-
-#if wxUSE_WAVE
-
-// For compilers that support precompilation, includes "wx.h".
-#include "wx/wxprec.h"
-
-#if defined(__BORLANDC__)
-#pragma hdrstop
-#endif
-
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/soundcard.h>
-
-#ifndef WX_PRECOMP
-#include "wx/wx.h"
-#endif
-
-#include "wx/file.h"
-#include "wx/wave.h"
-
-//-----------------------------------------------------------------
-// wxWave
-//-----------------------------------------------------------------
-
-wxWave::wxWave()
- : m_waveData(NULL), m_waveLength(0), m_isResource(FALSE)
-{
-}
-
-wxWave::wxWave(const wxString& sFileName, bool isResource)
- : m_waveData(NULL), m_waveLength(0), m_isResource(isResource)
-{
- Create(sFileName, isResource);
-}
-
-wxWave::wxWave(int size, const wxByte* data)
- : m_waveData(NULL), m_waveLength(0), m_isResource(FALSE)
-{
- Create(size, data);
-}
-
-wxWave::~wxWave()
-{
- Free();
-}
-
-bool wxWave::Create(const wxString& fileName, bool isResource)
-{
- Free();
-
- if (isResource)
- {
- // todo
- return (m_waveData ? TRUE : FALSE);
- }
- else
- {
- m_isResource = FALSE;
-
- wxFile fileWave;
- if (!fileWave.Open(fileName, wxFile::read))
- {
- return FALSE;
- }
-
- m_waveLength = (int) fileWave.Length();
-
- m_waveData = new wxByte[m_waveLength];
- if (!m_waveData)
- {
- return FALSE;
- }
-
- fileWave.Read(m_waveData, m_waveLength);
-
- return TRUE;
- }
-}
-
-bool wxWave::Create(int size, const wxByte* data)
-{
- Free();
- m_isResource = FALSE;
- m_waveLength=size;
- m_waveData = new wxByte[size];
- if (!m_waveData)
- {
- return FALSE;
- }
-
- for (int i=0; i<size; i++) m_waveData[i] = data[i];
-
- return TRUE;
-}
-
-bool wxWave::Play(bool async, bool looped)
-{
- if (!IsOk()) return FALSE;
-
- int dev = OpenDSP();
-
- if (dev<0) return FALSE;
-
- ioctl(dev,SNDCTL_DSP_SYNC,0);
-
- bool play=TRUE;
- int i,l=0;
- do
- {
- i= (int)((l+m_DSPblkSize) < m_sizeData ? m_DSPblkSize : (m_sizeData-l));
- if ( write(dev,&m_data[l],i) != i )
- {
- play=FALSE;
- }
- l +=i;
- } while (play == TRUE && l<m_sizeData);
-
- close(dev);
- return TRUE;
-}
-
-bool wxWave::Free()
-{
- if (m_waveData)
- {
- delete[] m_waveData;
- m_waveData = NULL;
- m_waveLength = 0;
- return TRUE;
- }
-
- return FALSE;
-}
-
-typedef struct
-{
- unsigned long uiSize;
- unsigned short uiFormatTag;
- unsigned short uiChannels;
- unsigned long ulSamplesPerSec;
- unsigned long ulAvgBytesPerSec;
- unsigned short uiBlockAlign;
- unsigned short 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
-
-int wxWave::OpenDSP(void)
-{
- WAVEFORMAT waveformat;
- int dev=-1;
- unsigned long ul;
-
- if (m_waveLength < (int)(32+sizeof(WAVEFORMAT)))
- return -1;
-
- memcpy(&waveformat,&m_waveData[FMT_INDEX+4],sizeof(WAVEFORMAT));
-
- if (memcmp(m_waveData, "RIFF", 4) != 0)
- return -1;
- if (memcmp(&m_waveData[WAVE_INDEX], "WAVE", 4) != 0)
- return -1;
- if (memcmp(&m_waveData[FMT_INDEX], "fmt ", 4) != 0)
- return -1;
- if (memcmp(&m_waveData[FMT_INDEX+waveformat.uiSize+8], "data", 4) != 0)
- return -1;
- memcpy(&ul,&m_waveData[FMT_INDEX+waveformat.uiSize+12],4);
- m_sizeData=ul;
- if ((int)(m_sizeData+FMT_INDEX+waveformat.uiSize+16) != m_waveLength)
- return -1;
- m_data=(char *)(&m_waveData[FMT_INDEX+waveformat.uiSize+8]);
-
- if (waveformat.uiFormatTag != WAVE_FORMAT_PCM)
- return -1;
- if (waveformat.ulSamplesPerSec != waveformat.ulAvgBytesPerSec/waveformat.uiBlockAlign)
- return -1;
-
- if ((dev = open(AUDIODEV,O_RDWR,0)) <0)
- return -1;
-
- if (!InitDSP(dev,(int)waveformat.uiBitsPerSample,waveformat.uiChannels == MONO ? 0:1,waveformat.ulSamplesPerSec))
- {
- close(dev);
- return -1;
- }
-
- return dev;
-}
-
-bool wxWave::InitDSP(int dev, int iDataBits, int iChannel,unsigned long ulSamplingRate)
-{
- if ( ioctl(dev,SNDCTL_DSP_GETBLKSIZE,&m_DSPblkSize) < 0 )
- return FALSE;
- if (m_DSPblkSize < 4096 || m_DSPblkSize > 65536)
- return FALSE;
- if ( ioctl(dev,SNDCTL_DSP_SAMPLESIZE,&iDataBits) < 0 )
- return FALSE;
- if ( ioctl(dev,SNDCTL_DSP_STEREO,&iChannel) < 0 )
- return FALSE;
- if ( ioctl(dev,SNDCTL_DSP_SPEED,&ulSamplingRate) < 0 )
- return FALSE;
-
- return TRUE;
-}
-#endif
-