1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/sound_sdl.cpp
3 // Purpose: wxSound backend using SDL
4 // Author: Vaclav Slavik
8 // Copyright: (c) 2004, Open Source Applications Foundation
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // for compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
15 #if defined(__BORLANDC__)
19 #if wxUSE_SOUND && wxUSE_LIBSDL
30 #include "wx/thread.h"
31 #include "wx/module.h"
34 // ----------------------------------------------------------------------------
35 // wxSoundBackendSDL, for Unix with libSDL
36 // ----------------------------------------------------------------------------
38 class wxSoundBackendSDLNotification
: public wxEvent
41 DECLARE_DYNAMIC_CLASS(wxSoundBackendSDLNotification
)
42 wxSoundBackendSDLNotification();
43 wxEvent
*Clone() const { return new wxSoundBackendSDLNotification(*this); }
46 typedef void (wxEvtHandler::*wxSoundBackendSDLNotificationFunction
)
47 (wxSoundBackendSDLNotification
&);
49 BEGIN_DECLARE_EVENT_TYPES()
50 DECLARE_LOCAL_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION
, -1)
51 END_DECLARE_EVENT_TYPES()
53 #define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \
54 DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \
57 (wxObjectEventFunction) wxStaticCastEvent( wxSoundBackendSDLNotificationFunction, & func ), \
60 IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification
, wxEvtHandler
)
61 DEFINE_EVENT_TYPE(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION
)
63 wxSoundBackendSDLNotification::wxSoundBackendSDLNotification()
65 SetEventType(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION
);
68 class wxSoundBackendSDLEvtHandler
;
70 class wxSoundBackendSDL
: public wxSoundBackend
74 : m_initialized(false), m_playing(false), m_audioOpen(false),
75 m_data(NULL
), m_evtHandler(NULL
) {}
76 virtual ~wxSoundBackendSDL();
78 wxString
GetName() const { return _T("Simple DirectMedia Layer"); }
79 int GetPriority() const { return 9; }
80 bool IsAvailable() const;
81 bool HasNativeAsyncPlayback() const { return true; }
82 bool Play(wxSoundData
*data
, unsigned flags
,
83 volatile wxSoundPlaybackStatus
*status
);
85 void FillAudioBuffer(Uint8
*stream
, int len
);
86 void FinishedPlayback();
89 bool IsPlaying() const { return m_playing
; }
96 bool m_playing
, m_audioOpen
;
97 // playback information:
100 SDL_AudioSpec m_spec
;
103 wxSoundBackendSDLEvtHandler
*m_evtHandler
;
106 class wxSoundBackendSDLEvtHandler
: public wxEvtHandler
109 wxSoundBackendSDLEvtHandler(wxSoundBackendSDL
*bk
) : m_backend(bk
) {}
112 void OnNotify(wxSoundBackendSDLNotification
& WXUNUSED(event
))
114 wxLogTrace(_T("sound"),
115 _T("received playback status change notification"));
116 m_backend
->FinishedPlayback();
118 wxSoundBackendSDL
*m_backend
;
120 DECLARE_EVENT_TABLE()
123 BEGIN_EVENT_TABLE(wxSoundBackendSDLEvtHandler
, wxEvtHandler
)
124 EVT_SOUND_BACKEND_SDL_NOTIFICATON(wxSoundBackendSDLEvtHandler::OnNotify
)
127 wxSoundBackendSDL::~wxSoundBackendSDL()
134 bool wxSoundBackendSDL::IsAvailable() const
138 if (SDL_WasInit(SDL_INIT_AUDIO
) != SDL_INIT_AUDIO
)
140 if (SDL_Init(SDL_INIT_AUDIO
| SDL_INIT_NOPARACHUTE
) == -1)
143 wxConstCast(this, wxSoundBackendSDL
)->m_initialized
= true;
144 wxLogTrace(_T("sound"), _T("initialized SDL audio subsystem"));
148 extern "C" void wx_sdl_audio_callback(void *userdata
, Uint8
*stream
, int len
)
150 wxSoundBackendSDL
*bk
= (wxSoundBackendSDL
*)userdata
;
151 bk
->FillAudioBuffer(stream
, len
);
154 void wxSoundBackendSDL::FillAudioBuffer(Uint8
*stream
, int len
)
158 // finished playing the sample
159 if (m_pos
== m_data
->m_dataBytes
)
162 wxSoundBackendSDLNotification event
;
163 m_evtHandler
->AddPendingEvent(event
);
165 // still something to play
168 unsigned size
= ((len
+ m_pos
) < m_data
->m_dataBytes
) ?
170 (m_data
->m_dataBytes
- m_pos
);
171 memcpy(stream
, m_data
->m_data
+ m_pos
, size
);
177 // the sample doesn't play, fill the buffer with silence and wait for
178 // the main thread to shut the playback down:
184 FillAudioBuffer(stream
, len
);
189 memset(stream
, m_spec
.silence
, len
);
194 void wxSoundBackendSDL::FinishedPlayback()
200 bool wxSoundBackendSDL::OpenAudio()
205 m_evtHandler
= new wxSoundBackendSDLEvtHandler(this);
208 m_spec
.samples
= 4096;
210 m_spec
.callback
= wx_sdl_audio_callback
;
211 m_spec
.userdata
= (void*)this;
213 wxLogTrace(_T("sound"), _T("opening SDL audio..."));
214 if (SDL_OpenAudio(&m_spec
, NULL
) >= 0)
218 SDL_AudioDriverName(driver
, 256);
219 wxLogTrace(_T("sound"), _T("opened audio, driver '%s'"),
220 wxString(driver
, wxConvLocal
).c_str());
227 wxString
err(SDL_GetError(), wxConvLocal
);
228 wxLogError(_("Couldn't open audio: %s"), err
.c_str());
235 void wxSoundBackendSDL::CloseAudio()
240 wxLogTrace(_T("sound"), _T("closed audio"));
245 bool wxSoundBackendSDL::Play(wxSoundData
*data
, unsigned flags
,
246 volatile wxSoundPlaybackStatus
*WXUNUSED(status
))
251 if (data
->m_bitsPerSample
== 8)
253 else if (data
->m_bitsPerSample
== 16)
254 format
= AUDIO_S16LSB
;
258 bool needsOpen
= true;
261 if (format
== m_spec
.format
&&
262 m_spec
.freq
== (int)data
->m_samplingRate
&&
263 m_spec
.channels
== data
->m_channels
)
275 m_spec
.format
= format
;
276 m_spec
.freq
= data
->m_samplingRate
;
277 m_spec
.channels
= data
->m_channels
;
283 wxLogTrace(_T("sound"), _T("playing new sound"));
286 m_loop
= (flags
& wxSOUND_LOOP
);
293 // wait until playback finishes if called in sync mode:
294 if (!(flags
& wxSOUND_ASYNC
))
296 wxLogTrace(_T("sound"), _T("waiting for sample to finish"));
297 while (m_playing
&& m_data
== data
)
300 // give the playback thread a chance to add event to pending
301 // events queue, release GUI lock temporarily:
302 if (wxThread::IsMain())
307 if (wxThread::IsMain())
311 wxLogTrace(_T("sound"), _T("sample finished"));
317 void wxSoundBackendSDL::Stop()
330 extern "C" wxSoundBackend
*wxCreateSoundBackendSDL()
332 return new wxSoundBackendSDL();
335 #endif // wxUSE_SOUND && wxUSE_LIBSDL