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