1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/unix/sound_sdl.cpp
3
// Purpose: wxSound backend using SDL
4
// Author: Vaclav Slavik
7
// Copyright: (c) 2004, Open Source Applications Foundation
8
// Licence: wxWindows licence
9
/////////////////////////////////////////////////////////////////////////////
11
// for compilers that support precompilation, includes "wx.h".
12
#include "wx/wxprec.h"
14
#if defined(__BORLANDC__)
18
#if wxUSE_SOUND && wxUSE_LIBSDL
27
#include "wx/module.h"
30
#include "wx/thread.h"
33
// ----------------------------------------------------------------------------
34
// wxSoundBackendSDL, for Unix with libSDL
35
// ----------------------------------------------------------------------------
37
class wxSoundBackendSDLNotification : public wxEvent
40
DECLARE_DYNAMIC_CLASS(wxSoundBackendSDLNotification)
41
wxSoundBackendSDLNotification();
42
wxEvent *Clone() const { return new wxSoundBackendSDLNotification(*this); }
45
typedef void (wxEvtHandler::*wxSoundBackendSDLNotificationFunction)
46
(wxSoundBackendSDLNotification&);
48
wxDECLARE_EVENT(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, wxSoundBackendSDLNotification);
50
#define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \
51
DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \
54
wxEVENT_HANDLER_CAST( wxSoundBackendSDLNotificationFunction, func ), \
57
IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification, wxEvtHandler)
58
wxDEFINE_EVENT( wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, wxSoundBackendSDLNotification );
60
wxSoundBackendSDLNotification::wxSoundBackendSDLNotification()
62
SetEventType(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION);
65
class wxSoundBackendSDLEvtHandler;
67
class wxSoundBackendSDL : public wxSoundBackend
71
: m_initialized(false), m_playing(false), m_audioOpen(false),
72
m_data(NULL), m_evtHandler(NULL) {}
73
virtual ~wxSoundBackendSDL();
75
wxString GetName() const { return wxT("Simple DirectMedia Layer"); }
76
int GetPriority() const { return 9; }
77
bool IsAvailable() const;
78
bool HasNativeAsyncPlayback() const { return true; }
79
bool Play(wxSoundData *data, unsigned flags,
80
volatile wxSoundPlaybackStatus *status);
82
void FillAudioBuffer(Uint8 *stream, int len);
83
void FinishedPlayback();
86
bool IsPlaying() const { return m_playing; }
93
bool m_playing, m_audioOpen;
94
// playback information:
100
wxSoundBackendSDLEvtHandler *m_evtHandler;
103
class wxSoundBackendSDLEvtHandler : public wxEvtHandler
106
wxSoundBackendSDLEvtHandler(wxSoundBackendSDL *bk) : m_backend(bk) {}
109
void OnNotify(wxSoundBackendSDLNotification& WXUNUSED(event))
111
wxLogTrace(wxT("sound"),
112
wxT("received playback status change notification"));
113
m_backend->FinishedPlayback();
115
wxSoundBackendSDL *m_backend;
117
DECLARE_EVENT_TABLE()
120
BEGIN_EVENT_TABLE(wxSoundBackendSDLEvtHandler, wxEvtHandler)
121
EVT_SOUND_BACKEND_SDL_NOTIFICATON(wxSoundBackendSDLEvtHandler::OnNotify)
124
wxSoundBackendSDL::~wxSoundBackendSDL()
131
bool wxSoundBackendSDL::IsAvailable() const
135
if (SDL_WasInit(SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
137
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) == -1)
140
wxConstCast(this, wxSoundBackendSDL)->m_initialized = true;
141
wxLogTrace(wxT("sound"), wxT("initialized SDL audio subsystem"));
145
extern "C" void wx_sdl_audio_callback(void *userdata, Uint8 *stream, int len)
147
wxSoundBackendSDL *bk = (wxSoundBackendSDL*)userdata;
148
bk->FillAudioBuffer(stream, len);
151
void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
155
// finished playing the sample
156
if (m_pos == m_data->m_dataBytes)
159
wxSoundBackendSDLNotification event;
160
m_evtHandler->AddPendingEvent(event);
162
// still something to play
165
unsigned size = ((len + m_pos) < m_data->m_dataBytes) ?
167
(m_data->m_dataBytes - m_pos);
168
memcpy(stream, m_data->m_data + m_pos, size);
174
// the sample doesn't play, fill the buffer with silence and wait for
175
// the main thread to shut the playback down:
181
FillAudioBuffer(stream, len);
186
memset(stream, m_spec.silence, len);
191
void wxSoundBackendSDL::FinishedPlayback()
197
bool wxSoundBackendSDL::OpenAudio()
202
m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
205
m_spec.samples = 4096;
207
m_spec.callback = wx_sdl_audio_callback;
208
m_spec.userdata = (void*)this;
210
wxLogTrace(wxT("sound"), wxT("opening SDL audio..."));
211
if (SDL_OpenAudio(&m_spec, NULL) >= 0)
215
#if SDL_MAJOR_VERSION == 1
216
SDL_AudioDriverName(driver, 256);
217
#elif SDL_MAJOR_VERSION > 1
218
strncpy(driver, SDL_GetCurrentAudioDriver(), 256);
220
wxLogTrace(wxT("sound"), wxT("opened audio, driver '%s'"),
221
wxString(driver, wxConvLocal).c_str());
228
wxString err(SDL_GetError(), wxConvLocal);
229
wxLogError(_("Couldn't open audio: %s"), err.c_str());
236
void wxSoundBackendSDL::CloseAudio()
241
wxLogTrace(wxT("sound"), wxT("closed audio"));
246
bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
247
volatile wxSoundPlaybackStatus *WXUNUSED(status))
252
if (data->m_bitsPerSample == 8)
254
else if (data->m_bitsPerSample == 16)
255
format = AUDIO_S16LSB;
259
bool needsOpen = true;
262
if (format == m_spec.format &&
263
m_spec.freq == (int)data->m_samplingRate &&
264
m_spec.channels == data->m_channels)
276
m_spec.format = format;
277
m_spec.freq = data->m_samplingRate;
278
m_spec.channels = data->m_channels;
284
wxLogTrace(wxT("sound"), wxT("playing new sound"));
287
m_loop = (flags & wxSOUND_LOOP);
294
// wait until playback finishes if called in sync mode:
295
if (!(flags & wxSOUND_ASYNC))
297
wxLogTrace(wxT("sound"), wxT("waiting for sample to finish"));
298
while (m_playing && m_data == data)
301
// give the playback thread a chance to add event to pending
302
// events queue, release GUI lock temporarily:
303
if (wxThread::IsMain())
308
if (wxThread::IsMain())
312
wxLogTrace(wxT("sound"), wxT("sample finished"));
318
void wxSoundBackendSDL::Stop()
331
extern "C" wxSoundBackend *wxCreateSoundBackendSDL()
333
return new wxSoundBackendSDL();
336
#endif // wxUSE_SOUND && wxUSE_LIBSDL