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 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