/////////////////////////////////////////////////////////////////////////////
-// Name: sound_sdl.cpp
+// Name: src/unix/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
+// Copyright: (c) 2004, Open Source Applications Foundation
+// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
-#include "wx/setup.h"
-
#if defined(__BORLANDC__)
-#pragma hdrstop
+ #pragma hdrstop
#endif
-#if wxUSE_WAVE && wxUSE_LIBSDL
+#if wxUSE_SOUND && wxUSE_LIBSDL
#include <SDL.h>
#include "wx/event.h"
#include "wx/intl.h"
#include "wx/log.h"
- #include "wx/list.h"
#include "wx/utils.h"
+ #include "wx/module.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); }
+ 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()
+wxDECLARE_EVENT( wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, wxSoundBackendSDLNotification )
#define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \
DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \
-1, \
-1, \
- (wxObjectEventFunction) \
- (wxSoundBackendSDLNotificationFunction)& func, \
- (wxObject *) NULL ),
+ wxEVENT_HANDLER_CAST( wxSoundBackendSDLNotificationFunction, func ), \
+ NULL ),
IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification, wxEvtHandler)
-DEFINE_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION)
+wxDEFINE_EVENT( wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, wxSoundBackendSDLNotification );
wxSoundBackendSDLNotification::wxSoundBackendSDLNotification()
{
class wxSoundBackendSDL : public wxSoundBackend
{
public:
- wxSoundBackendSDL()
- : m_initialized(false), m_playing(false), m_evtHandler(NULL) {}
+ wxSoundBackendSDL()
+ : m_initialized(false), m_playing(false), m_audioOpen(false),
+ m_data(NULL), 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);
+ bool Play(wxSoundData *data, unsigned flags,
+ volatile wxSoundPlaybackStatus *status);
void FillAudioBuffer(Uint8 *stream, int len);
- bool PlayNextSampleInQueue();
-
+ void FinishedPlayback();
+
+ void Stop();
+ bool IsPlaying() const { return m_playing; }
+
private:
+ bool OpenAudio();
+ void CloseAudio();
+
bool m_initialized;
- bool m_playing;
- wxSoundBackendSDLQueue m_queue;
+ bool m_playing, m_audioOpen;
+ // playback information:
+ wxSoundData *m_data;
+ unsigned m_pos;
+ SDL_AudioSpec m_spec;
+ bool m_loop;
+
wxSoundBackendSDLEvtHandler *m_evtHandler;
};
{
wxLogTrace(_T("sound"),
_T("received playback status change notification"));
- m_backend->PlayNextSampleInQueue();
+ m_backend->FinishedPlayback();
}
wxSoundBackendSDL *m_backend;
wxSoundBackendSDL::~wxSoundBackendSDL()
{
- SDL_LockAudio();
- if (m_playing)
- SDL_CloseAudio();
- SDL_UnlockAudio();
- wxDELETE(m_evtHandler);
- WX_CLEAR_LIST(wxSoundBackendSDLQueue, m_queue)
+ Stop();
+ CloseAudio();
+ delete m_evtHandler;
}
bool wxSoundBackendSDL::IsAvailable() const
void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
{
- wxSoundBackendSDLQueueEntry *e = m_queue.front();
- if (!e->m_finished)
+ if (m_playing)
{
// finished playing the sample
- if (e->m_pos == e->m_data->m_dataBytes)
+ if (m_pos == 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) ?
+ unsigned size = ((len + m_pos) < 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;
+ (m_data->m_dataBytes - m_pos);
+ memcpy(stream, m_data->m_data + m_pos, size);
+ m_pos += size;
len -= size;
stream += size;
}
// the main thread to shut the playback down:
if (len > 0)
{
- if (e->m_loop)
+ if (m_loop)
{
- e->m_pos = 0;
+ m_pos = 0;
FillAudioBuffer(stream, len);
return;
}
else
{
- memset(stream, e->m_spec.silence, len);
+ memset(stream, m_spec.silence, len);
}
}
}
-bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags)
+void wxSoundBackendSDL::FinishedPlayback()
{
- data->IncRef();
+ if (!m_playing)
+ Stop();
+}
- 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;
-
+bool wxSoundBackendSDL::OpenAudio()
+{
+ if (!m_audioOpen)
+ {
+ if (!m_evtHandler)
+ m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
+
+ m_spec.silence = 0;
+ m_spec.samples = 4096;
+ m_spec.size = 0;
+ m_spec.callback = wx_sdl_audio_callback;
+ m_spec.userdata = (void*)this;
+
+ wxLogTrace(_T("sound"), _T("opening SDL audio..."));
+ if (SDL_OpenAudio(&m_spec, NULL) >= 0)
+ {
+#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
+ m_audioOpen = true;
+ return true;
+ }
+ else
+ {
+ wxString err(SDL_GetError(), wxConvLocal);
+ wxLogError(_("Couldn't open audio: %s"), err.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+void wxSoundBackendSDL::CloseAudio()
+{
+ if (m_audioOpen)
+ {
+ SDL_CloseAudio();
+ wxLogTrace(_T("sound"), _T("closed audio"));
+ m_audioOpen = false;
+ }
+}
+
+bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
+ volatile wxSoundPlaybackStatus *WXUNUSED(status))
+{
+ Stop();
+
+ int format;
if (data->m_bitsPerSample == 8)
- e->m_spec.format = AUDIO_U8;
+ format = AUDIO_U8;
else if (data->m_bitsPerSample == 16)
- e->m_spec.format = AUDIO_S16LSB;
+ format = AUDIO_S16LSB;
else
return false;
- m_queue.push_back(e);
- wxLogTrace(_T("sound"), _T("queued sample %p for playback"), e);
+ bool needsOpen = true;
+ if (m_audioOpen)
+ {
+ if (format == m_spec.format &&
+ m_spec.freq == (int)data->m_samplingRate &&
+ m_spec.channels == data->m_channels)
+ {
+ needsOpen = false;
+ }
+ else
+ {
+ CloseAudio();
+ }
+ }
- if (!PlayNextSampleInQueue())
- return false;
+ if (needsOpen)
+ {
+ m_spec.format = format;
+ m_spec.freq = data->m_samplingRate;
+ m_spec.channels = data->m_channels;
+ if (!OpenAudio())
+ return false;
+ }
+
+ SDL_LockAudio();
+ wxLogTrace(_T("sound"), _T("playing new sound"));
+ m_playing = true;
+ m_pos = 0;
+ m_loop = (flags & wxSOUND_LOOP);
+ m_data = data;
+ data->IncRef();
+ SDL_UnlockAudio();
+ SDL_PauseAudio(0);
+
+ // wait until playback finishes if called in sync mode:
if (!(flags & wxSOUND_ASYNC))
{
wxLogTrace(_T("sound"), _T("waiting for sample to finish"));
- while (!m_queue.empty() && m_queue.front() == e && !e->m_finished)
+ while (m_playing && m_data == data)
{
#if wxUSE_THREADS
// give the playback thread a chance to add event to pending
if (wxThread::IsMain())
wxMutexGuiLeave();
#endif
- wxUsleep(10);
+ wxMilliSleep(10);
#if wxUSE_THREADS
if (wxThread::IsMain())
wxMutexGuiEnter();
}
wxLogTrace(_T("sound"), _T("sample finished"));
}
-
+
return true;
}
-
-bool wxSoundBackendSDL::PlayNextSampleInQueue()
-{
- bool status = true;
+void wxSoundBackendSDL::Stop()
+{
SDL_LockAudio();
-
- if (!m_evtHandler)
- m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
-
- if (!m_playing && !m_queue.empty())
+ SDL_PauseAudio(1);
+ m_playing = false;
+ if (m_data)
{
- 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);
- }
+ m_data->DecRef();
+ m_data = NULL;
}
-
SDL_UnlockAudio();
-
- return status;
}
extern "C" wxSoundBackend *wxCreateSoundBackendSDL()
return new wxSoundBackendSDL();
}
-#endif // wxUSE_WAVE && wxUSE_LIBSDL
+#endif // wxUSE_SOUND && wxUSE_LIBSDL