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 
  28     #include "wx/module.h" 
  31 #include "wx/thread.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 wxDECLARE_EVENT(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION
, wxSoundBackendSDLNotification
); 
  51 #define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \ 
  52     DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \ 
  55                               wxEVENT_HANDLER_CAST( wxSoundBackendSDLNotificationFunction, func ), \ 
  58 IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification
, wxEvtHandler
) 
  59 wxDEFINE_EVENT( wxEVT_SOUND_BACKEND_SDL_NOTIFICATION
, wxSoundBackendSDLNotification 
); 
  61 wxSoundBackendSDLNotification::wxSoundBackendSDLNotification() 
  63     SetEventType(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION
); 
  66 class wxSoundBackendSDLEvtHandler
; 
  68 class wxSoundBackendSDL 
: public wxSoundBackend
 
  72         : m_initialized(false), m_playing(false), m_audioOpen(false), 
  73           m_data(NULL
), m_evtHandler(NULL
) {} 
  74     virtual ~wxSoundBackendSDL(); 
  76     wxString 
GetName() const { return wxT("Simple DirectMedia Layer"); } 
  77     int GetPriority() const { return 9; } 
  78     bool IsAvailable() const; 
  79     bool HasNativeAsyncPlayback() const { return true; } 
  80     bool Play(wxSoundData 
*data
, unsigned flags
, 
  81               volatile wxSoundPlaybackStatus 
*status
); 
  83     void FillAudioBuffer(Uint8 
*stream
, int len
); 
  84     void FinishedPlayback(); 
  87     bool IsPlaying() const { return m_playing
; } 
  94     bool                        m_playing
, m_audioOpen
; 
  95     // playback information: 
 101     wxSoundBackendSDLEvtHandler 
*m_evtHandler
; 
 104 class wxSoundBackendSDLEvtHandler 
: public wxEvtHandler
 
 107     wxSoundBackendSDLEvtHandler(wxSoundBackendSDL 
*bk
) : m_backend(bk
) {} 
 110     void OnNotify(wxSoundBackendSDLNotification
& WXUNUSED(event
)) 
 112         wxLogTrace(wxT("sound"), 
 113                    wxT("received playback status change notification")); 
 114         m_backend
->FinishedPlayback(); 
 116     wxSoundBackendSDL 
*m_backend
; 
 118     DECLARE_EVENT_TABLE() 
 121 BEGIN_EVENT_TABLE(wxSoundBackendSDLEvtHandler
, wxEvtHandler
) 
 122     EVT_SOUND_BACKEND_SDL_NOTIFICATON(wxSoundBackendSDLEvtHandler::OnNotify
) 
 125 wxSoundBackendSDL::~wxSoundBackendSDL() 
 132 bool wxSoundBackendSDL::IsAvailable() const 
 136     if (SDL_WasInit(SDL_INIT_AUDIO
) != SDL_INIT_AUDIO
) 
 138         if (SDL_Init(SDL_INIT_AUDIO 
| SDL_INIT_NOPARACHUTE
) == -1) 
 141     wxConstCast(this, wxSoundBackendSDL
)->m_initialized 
= true; 
 142     wxLogTrace(wxT("sound"), wxT("initialized SDL audio subsystem")); 
 146 extern "C" void wx_sdl_audio_callback(void *userdata
, Uint8 
*stream
, int len
) 
 148     wxSoundBackendSDL 
*bk 
= (wxSoundBackendSDL
*)userdata
; 
 149     bk
->FillAudioBuffer(stream
, len
); 
 152 void wxSoundBackendSDL::FillAudioBuffer(Uint8 
*stream
, int len
) 
 156         // finished playing the sample 
 157         if (m_pos 
== m_data
->m_dataBytes
) 
 160             wxSoundBackendSDLNotification event
; 
 161             m_evtHandler
->AddPendingEvent(event
); 
 163         // still something to play 
 166             unsigned size 
= ((len 
+ m_pos
) < m_data
->m_dataBytes
) ? 
 168                             (m_data
->m_dataBytes 
- m_pos
); 
 169             memcpy(stream
, m_data
->m_data 
+ m_pos
, size
); 
 175     // the sample doesn't play, fill the buffer with silence and wait for 
 176     // the main thread to shut the playback down: 
 182             FillAudioBuffer(stream
, len
); 
 187             memset(stream
, m_spec
.silence
, len
); 
 192 void wxSoundBackendSDL::FinishedPlayback() 
 198 bool wxSoundBackendSDL::OpenAudio() 
 203             m_evtHandler 
= new wxSoundBackendSDLEvtHandler(this); 
 206         m_spec
.samples 
= 4096; 
 208         m_spec
.callback 
= wx_sdl_audio_callback
; 
 209         m_spec
.userdata 
= (void*)this; 
 211         wxLogTrace(wxT("sound"), wxT("opening SDL audio...")); 
 212         if (SDL_OpenAudio(&m_spec
, NULL
) >= 0) 
 216             SDL_AudioDriverName(driver
, 256); 
 217             wxLogTrace(wxT("sound"), wxT("opened audio, driver '%s'"), 
 218                        wxString(driver
, wxConvLocal
).c_str()); 
 225             wxString 
err(SDL_GetError(), wxConvLocal
); 
 226             wxLogError(_("Couldn't open audio: %s"), err
.c_str()); 
 233 void wxSoundBackendSDL::CloseAudio() 
 238         wxLogTrace(wxT("sound"), wxT("closed audio")); 
 243 bool wxSoundBackendSDL::Play(wxSoundData 
*data
, unsigned flags
, 
 244                              volatile wxSoundPlaybackStatus 
*WXUNUSED(status
)) 
 249     if (data
->m_bitsPerSample 
== 8) 
 251     else if (data
->m_bitsPerSample 
== 16) 
 252         format 
= AUDIO_S16LSB
; 
 256     bool needsOpen 
= true; 
 259         if (format 
== m_spec
.format 
&& 
 260             m_spec
.freq 
== (int)data
->m_samplingRate 
&& 
 261             m_spec
.channels 
== data
->m_channels
) 
 273         m_spec
.format 
= format
; 
 274         m_spec
.freq 
= data
->m_samplingRate
; 
 275         m_spec
.channels 
= data
->m_channels
; 
 281     wxLogTrace(wxT("sound"), wxT("playing new sound")); 
 284     m_loop 
= (flags 
& wxSOUND_LOOP
); 
 291     // wait until playback finishes if called in sync mode: 
 292     if (!(flags 
& wxSOUND_ASYNC
)) 
 294         wxLogTrace(wxT("sound"), wxT("waiting for sample to finish")); 
 295         while (m_playing 
&& m_data 
== data
) 
 298             // give the playback thread a chance to add event to pending 
 299             // events queue, release GUI lock temporarily: 
 300             if (wxThread::IsMain()) 
 305             if (wxThread::IsMain()) 
 309         wxLogTrace(wxT("sound"), wxT("sample finished")); 
 315 void wxSoundBackendSDL::Stop() 
 328 extern "C" wxSoundBackend 
*wxCreateSoundBackendSDL() 
 330     return new wxSoundBackendSDL(); 
 333 #endif // wxUSE_SOUND && wxUSE_LIBSDL