~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Externals/wxWidgets3/src/unix/sound_sdl.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/unix/sound_sdl.cpp
 
3
// Purpose:     wxSound backend using SDL
 
4
// Author:      Vaclav Slavik
 
5
// Modified by:
 
6
// Created:     2004/01/31
 
7
// Copyright:   (c) 2004, Open Source Applications Foundation
 
8
// Licence:     wxWindows licence
 
9
/////////////////////////////////////////////////////////////////////////////
 
10
 
 
11
// for compilers that support precompilation, includes "wx.h".
 
12
#include "wx/wxprec.h"
 
13
 
 
14
#if defined(__BORLANDC__)
 
15
    #pragma hdrstop
 
16
#endif
 
17
 
 
18
#if wxUSE_SOUND && wxUSE_LIBSDL
 
19
 
 
20
#include <SDL.h>
 
21
 
 
22
#ifndef WX_PRECOMP
 
23
    #include "wx/event.h"
 
24
    #include "wx/intl.h"
 
25
    #include "wx/log.h"
 
26
    #include "wx/utils.h"
 
27
    #include "wx/module.h"
 
28
#endif
 
29
 
 
30
#include "wx/thread.h"
 
31
#include "wx/sound.h"
 
32
 
 
33
// ----------------------------------------------------------------------------
 
34
// wxSoundBackendSDL, for Unix with libSDL
 
35
// ----------------------------------------------------------------------------
 
36
 
 
37
class wxSoundBackendSDLNotification : public wxEvent
 
38
{
 
39
public:
 
40
    DECLARE_DYNAMIC_CLASS(wxSoundBackendSDLNotification)
 
41
    wxSoundBackendSDLNotification();
 
42
    wxEvent *Clone() const { return new wxSoundBackendSDLNotification(*this); }
 
43
};
 
44
 
 
45
typedef void (wxEvtHandler::*wxSoundBackendSDLNotificationFunction)
 
46
             (wxSoundBackendSDLNotification&);
 
47
 
 
48
wxDECLARE_EVENT(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, wxSoundBackendSDLNotification);
 
49
 
 
50
#define EVT_SOUND_BACKEND_SDL_NOTIFICATON(func) \
 
51
    DECLARE_EVENT_TABLE_ENTRY(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, \
 
52
                              -1,                       \
 
53
                              -1,                       \
 
54
                              wxEVENT_HANDLER_CAST( wxSoundBackendSDLNotificationFunction, func ), \
 
55
                              NULL ),
 
56
 
 
57
IMPLEMENT_DYNAMIC_CLASS(wxSoundBackendSDLNotification, wxEvtHandler)
 
58
wxDEFINE_EVENT( wxEVT_SOUND_BACKEND_SDL_NOTIFICATION, wxSoundBackendSDLNotification );
 
59
 
 
60
wxSoundBackendSDLNotification::wxSoundBackendSDLNotification()
 
61
{
 
62
    SetEventType(wxEVT_SOUND_BACKEND_SDL_NOTIFICATION);
 
63
}
 
64
 
 
65
class wxSoundBackendSDLEvtHandler;
 
66
 
 
67
class wxSoundBackendSDL : public wxSoundBackend
 
68
{
 
69
public:
 
70
    wxSoundBackendSDL()
 
71
        : m_initialized(false), m_playing(false), m_audioOpen(false),
 
72
          m_data(NULL), m_evtHandler(NULL) {}
 
73
    virtual ~wxSoundBackendSDL();
 
74
 
 
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);
 
81
 
 
82
    void FillAudioBuffer(Uint8 *stream, int len);
 
83
    void FinishedPlayback();
 
84
 
 
85
    void Stop();
 
86
    bool IsPlaying() const { return m_playing; }
 
87
 
 
88
private:
 
89
    bool OpenAudio();
 
90
    void CloseAudio();
 
91
 
 
92
    bool                        m_initialized;
 
93
    bool                        m_playing, m_audioOpen;
 
94
    // playback information:
 
95
    wxSoundData                 *m_data;
 
96
    unsigned                     m_pos;
 
97
    SDL_AudioSpec                m_spec;
 
98
    bool                         m_loop;
 
99
 
 
100
    wxSoundBackendSDLEvtHandler *m_evtHandler;
 
101
};
 
102
 
 
103
class wxSoundBackendSDLEvtHandler : public wxEvtHandler
 
104
{
 
105
public:
 
106
    wxSoundBackendSDLEvtHandler(wxSoundBackendSDL *bk) : m_backend(bk) {}
 
107
 
 
108
private:
 
109
    void OnNotify(wxSoundBackendSDLNotification& WXUNUSED(event))
 
110
    {
 
111
        wxLogTrace(wxT("sound"),
 
112
                   wxT("received playback status change notification"));
 
113
        m_backend->FinishedPlayback();
 
114
    }
 
115
    wxSoundBackendSDL *m_backend;
 
116
 
 
117
    DECLARE_EVENT_TABLE()
 
118
};
 
119
 
 
120
BEGIN_EVENT_TABLE(wxSoundBackendSDLEvtHandler, wxEvtHandler)
 
121
    EVT_SOUND_BACKEND_SDL_NOTIFICATON(wxSoundBackendSDLEvtHandler::OnNotify)
 
122
END_EVENT_TABLE()
 
123
 
 
124
wxSoundBackendSDL::~wxSoundBackendSDL()
 
125
{
 
126
    Stop();
 
127
    CloseAudio();
 
128
    delete m_evtHandler;
 
129
}
 
130
 
 
131
bool wxSoundBackendSDL::IsAvailable() const
 
132
{
 
133
    if (m_initialized)
 
134
        return true;
 
135
    if (SDL_WasInit(SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
 
136
    {
 
137
        if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE) == -1)
 
138
            return false;
 
139
    }
 
140
    wxConstCast(this, wxSoundBackendSDL)->m_initialized = true;
 
141
    wxLogTrace(wxT("sound"), wxT("initialized SDL audio subsystem"));
 
142
    return true;
 
143
}
 
144
 
 
145
extern "C" void wx_sdl_audio_callback(void *userdata, Uint8 *stream, int len)
 
146
{
 
147
    wxSoundBackendSDL *bk = (wxSoundBackendSDL*)userdata;
 
148
    bk->FillAudioBuffer(stream, len);
 
149
}
 
150
 
 
151
void wxSoundBackendSDL::FillAudioBuffer(Uint8 *stream, int len)
 
152
{
 
153
    if (m_playing)
 
154
    {
 
155
        // finished playing the sample
 
156
        if (m_pos == m_data->m_dataBytes)
 
157
        {
 
158
            m_playing = false;
 
159
            wxSoundBackendSDLNotification event;
 
160
            m_evtHandler->AddPendingEvent(event);
 
161
        }
 
162
        // still something to play
 
163
        else
 
164
        {
 
165
            unsigned size = ((len + m_pos) < m_data->m_dataBytes) ?
 
166
                            len :
 
167
                            (m_data->m_dataBytes - m_pos);
 
168
            memcpy(stream, m_data->m_data + m_pos, size);
 
169
            m_pos += size;
 
170
            len -= size;
 
171
            stream += size;
 
172
        }
 
173
    }
 
174
    // the sample doesn't play, fill the buffer with silence and wait for
 
175
    // the main thread to shut the playback down:
 
176
    if (len > 0)
 
177
    {
 
178
        if (m_loop)
 
179
        {
 
180
            m_pos = 0;
 
181
            FillAudioBuffer(stream, len);
 
182
            return;
 
183
        }
 
184
        else
 
185
        {
 
186
            memset(stream, m_spec.silence, len);
 
187
        }
 
188
    }
 
189
}
 
190
 
 
191
void wxSoundBackendSDL::FinishedPlayback()
 
192
{
 
193
    if (!m_playing)
 
194
        Stop();
 
195
}
 
196
 
 
197
bool wxSoundBackendSDL::OpenAudio()
 
198
{
 
199
    if (!m_audioOpen)
 
200
    {
 
201
        if (!m_evtHandler)
 
202
            m_evtHandler = new wxSoundBackendSDLEvtHandler(this);
 
203
 
 
204
        m_spec.silence = 0;
 
205
        m_spec.samples = 4096;
 
206
        m_spec.size = 0;
 
207
        m_spec.callback = wx_sdl_audio_callback;
 
208
        m_spec.userdata = (void*)this;
 
209
 
 
210
        wxLogTrace(wxT("sound"), wxT("opening SDL audio..."));
 
211
        if (SDL_OpenAudio(&m_spec, NULL) >= 0)
 
212
        {
 
213
#if wxUSE_LOG_DEBUG
 
214
            char driver[256];
 
215
#if SDL_MAJOR_VERSION == 1
 
216
            SDL_AudioDriverName(driver, 256);
 
217
#elif SDL_MAJOR_VERSION > 1            
 
218
            strncpy(driver, SDL_GetCurrentAudioDriver(), 256);
 
219
#endif
 
220
            wxLogTrace(wxT("sound"), wxT("opened audio, driver '%s'"),
 
221
                       wxString(driver, wxConvLocal).c_str());
 
222
#endif
 
223
            m_audioOpen = true;
 
224
            return true;
 
225
        }
 
226
        else
 
227
        {
 
228
            wxString err(SDL_GetError(), wxConvLocal);
 
229
            wxLogError(_("Couldn't open audio: %s"), err.c_str());
 
230
            return false;
 
231
        }
 
232
    }
 
233
    return true;
 
234
}
 
235
 
 
236
void wxSoundBackendSDL::CloseAudio()
 
237
{
 
238
    if (m_audioOpen)
 
239
    {
 
240
        SDL_CloseAudio();
 
241
        wxLogTrace(wxT("sound"), wxT("closed audio"));
 
242
        m_audioOpen = false;
 
243
    }
 
244
}
 
245
 
 
246
bool wxSoundBackendSDL::Play(wxSoundData *data, unsigned flags,
 
247
                             volatile wxSoundPlaybackStatus *WXUNUSED(status))
 
248
{
 
249
    Stop();
 
250
 
 
251
    int format;
 
252
    if (data->m_bitsPerSample == 8)
 
253
        format = AUDIO_U8;
 
254
    else if (data->m_bitsPerSample == 16)
 
255
        format = AUDIO_S16LSB;
 
256
    else
 
257
        return false;
 
258
 
 
259
    bool needsOpen = true;
 
260
    if (m_audioOpen)
 
261
    {
 
262
        if (format == m_spec.format &&
 
263
            m_spec.freq == (int)data->m_samplingRate &&
 
264
            m_spec.channels == data->m_channels)
 
265
        {
 
266
            needsOpen = false;
 
267
        }
 
268
        else
 
269
        {
 
270
            CloseAudio();
 
271
        }
 
272
    }
 
273
 
 
274
    if (needsOpen)
 
275
    {
 
276
        m_spec.format = format;
 
277
        m_spec.freq = data->m_samplingRate;
 
278
        m_spec.channels = data->m_channels;
 
279
        if (!OpenAudio())
 
280
            return false;
 
281
    }
 
282
 
 
283
    SDL_LockAudio();
 
284
    wxLogTrace(wxT("sound"), wxT("playing new sound"));
 
285
    m_playing = true;
 
286
    m_pos = 0;
 
287
    m_loop = (flags & wxSOUND_LOOP);
 
288
    m_data = data;
 
289
    data->IncRef();
 
290
    SDL_UnlockAudio();
 
291
 
 
292
    SDL_PauseAudio(0);
 
293
 
 
294
    // wait until playback finishes if called in sync mode:
 
295
    if (!(flags & wxSOUND_ASYNC))
 
296
    {
 
297
        wxLogTrace(wxT("sound"), wxT("waiting for sample to finish"));
 
298
        while (m_playing && m_data == data)
 
299
        {
 
300
#if wxUSE_THREADS
 
301
            // give the playback thread a chance to add event to pending
 
302
            // events queue, release GUI lock temporarily:
 
303
            if (wxThread::IsMain())
 
304
                wxMutexGuiLeave();
 
305
#endif
 
306
            wxMilliSleep(10);
 
307
#if wxUSE_THREADS
 
308
            if (wxThread::IsMain())
 
309
                wxMutexGuiEnter();
 
310
#endif
 
311
        }
 
312
        wxLogTrace(wxT("sound"), wxT("sample finished"));
 
313
    }
 
314
 
 
315
    return true;
 
316
}
 
317
 
 
318
void wxSoundBackendSDL::Stop()
 
319
{
 
320
    SDL_LockAudio();
 
321
    SDL_PauseAudio(1);
 
322
    m_playing = false;
 
323
    if (m_data)
 
324
    {
 
325
        m_data->DecRef();
 
326
        m_data = NULL;
 
327
    }
 
328
    SDL_UnlockAudio();
 
329
}
 
330
 
 
331
extern "C" wxSoundBackend *wxCreateSoundBackendSDL()
 
332
{
 
333
    return new wxSoundBackendSDL();
 
334
}
 
335
 
 
336
#endif // wxUSE_SOUND && wxUSE_LIBSDL