]> git.saurik.com Git - wxWidgets.git/blame - src/unix/sound.cpp
Fixed #1338966.
[wxWidgets.git] / src / unix / sound.cpp
CommitLineData
9be32e8f
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: sound.cpp
3// Purpose: wxSound
4// Author: Marcel Rasche, Vaclav Slavik
5// Modified by:
6// Created: 25/10/98
7// RCS-ID: $Id$
f156e20c 8// Copyright: (c) Julian Smart, Open Source Applications Foundation
f8a586e0 9// Licence: wxWindows licence
9be32e8f
VS
10/////////////////////////////////////////////////////////////////////////////
11
9be32e8f
VS
12// for compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#include "wx/setup.h"
16
17#if defined(__BORLANDC__)
18#pragma hdrstop
19#endif
20
f156e20c 21#if wxUSE_SOUND
9be32e8f
VS
22
23#include <stdio.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <sys/ioctl.h>
27
83f7f12d 28#ifdef HAVE_SYS_SOUNDCARD_H
9be32e8f
VS
29#include <sys/soundcard.h>
30#endif
31
32#ifndef WX_PRECOMP
33 #include "wx/event.h"
34 #include "wx/intl.h"
35 #include "wx/log.h"
36#endif
37
38#include "wx/thread.h"
39#include "wx/file.h"
40#include "wx/module.h"
41#include "wx/sound.h"
42#include "wx/dynlib.h"
43
83f7f12d
VS
44
45#if wxUSE_THREADS
46// mutex for all wxSound's synchronization
47static wxMutex gs_soundMutex;
48#endif
49
50// ----------------------------------------------------------------------------
51// wxSoundData
52// ----------------------------------------------------------------------------
f8a586e0 53
83f7f12d
VS
54void wxSoundData::IncRef()
55{
56#if wxUSE_THREADS
57 wxMutexLocker locker(gs_soundMutex);
58#endif
59 m_refCnt++;
60}
61
62void wxSoundData::DecRef()
63{
64#if wxUSE_THREADS
65 wxMutexLocker locker(gs_soundMutex);
66#endif
67 if (--m_refCnt == 0)
68 delete this;
69}
70
71wxSoundData::~wxSoundData()
72{
73 delete[] m_dataWithHeader;
74}
75
76
9be32e8f
VS
77// ----------------------------------------------------------------------------
78// wxSoundBackendNull, used in absence of audio API or card
79// ----------------------------------------------------------------------------
80
81class wxSoundBackendNull : public wxSoundBackend
82{
83public:
84 wxString GetName() const { return _("No sound"); }
85 int GetPriority() const { return 0; }
86 bool IsAvailable() const { return true; }
87 bool HasNativeAsyncPlayback() const { return true; }
83f7f12d
VS
88 bool Play(wxSoundData *WXUNUSED(data), unsigned WXUNUSED(flags),
89 volatile wxSoundPlaybackStatus *WXUNUSED(status))
9be32e8f 90 { return true; }
83f7f12d
VS
91 void Stop() {}
92 bool IsPlaying() const { return false; }
9be32e8f
VS
93};
94
95
96// ----------------------------------------------------------------------------
97// wxSoundBackendOSS, for Linux
98// ----------------------------------------------------------------------------
99
100#ifdef HAVE_SYS_SOUNDCARD_H
101
102#ifndef AUDIODEV
103#define AUDIODEV "/dev/dsp" // Default path for audio device
104#endif
105
106class wxSoundBackendOSS : public wxSoundBackend
107{
108public:
109 wxString GetName() const { return _T("Open Sound System"); }
110 int GetPriority() const { return 10; }
111 bool IsAvailable() const;
112 bool HasNativeAsyncPlayback() const { return false; }
83f7f12d
VS
113 bool Play(wxSoundData *data, unsigned flags,
114 volatile wxSoundPlaybackStatus *status);
115 void Stop() {}
116 bool IsPlaying() const { return false; }
9be32e8f
VS
117
118private:
119 int OpenDSP(const wxSoundData *data);
544c4a3b 120 bool InitDSP(int dev, const wxSoundData *data);
f8a586e0 121
9be32e8f 122 int m_DSPblkSize; // Size of the DSP buffer
544c4a3b 123 bool m_needConversion;
9be32e8f
VS
124};
125
126bool wxSoundBackendOSS::IsAvailable() const
127{
128 int fd;
129 fd = open(AUDIODEV, O_WRONLY | O_NONBLOCK);
130 if (fd < 0)
131 return false;
132 close(fd);
133 return true;
134}
135
83f7f12d
VS
136bool wxSoundBackendOSS::Play(wxSoundData *data, unsigned flags,
137 volatile wxSoundPlaybackStatus *status)
9be32e8f
VS
138{
139 int dev = OpenDSP(data);
f8a586e0 140
9be32e8f
VS
141 if (dev < 0)
142 return false;
143
144 ioctl(dev, SNDCTL_DSP_SYNC, 0);
544c4a3b 145
9be32e8f
VS
146 do
147 {
148 bool play = true;
149 int i;
150 unsigned l = 0;
151 size_t datasize = data->m_dataBytes;
152
153 do
154 {
83f7f12d
VS
155 if (status->m_stopRequested)
156 {
157 wxLogTrace(_T("sound"), _T("playback stopped"));
158 close(dev);
159 return true;
160 }
161
9be32e8f 162 i= (int)((l + m_DSPblkSize) < datasize ?
544c4a3b 163 m_DSPblkSize : (datasize - l));
9be32e8f
VS
164 if (write(dev, &data->m_data[l], i) != i)
165 {
166 play = false;
167 }
168 l += i;
169 } while (play && l < datasize);
170 } while (flags & wxSOUND_LOOP);
f8a586e0 171
544c4a3b 172 close(dev);
9be32e8f
VS
173 return true;
174}
175
176int wxSoundBackendOSS::OpenDSP(const wxSoundData *data)
177{
178 int dev = -1;
f8a586e0 179
9be32e8f
VS
180 if ((dev = open(AUDIODEV, O_WRONLY, 0)) <0)
181 return -1;
f8a586e0 182
544c4a3b 183 if (!InitDSP(dev, data) || m_needConversion)
9be32e8f
VS
184 {
185 close(dev);
186 return -1;
187 }
188
189 return dev;
190}
191
544c4a3b
RD
192
193bool wxSoundBackendOSS::InitDSP(int dev, const wxSoundData *data)
9be32e8f 194{
544c4a3b
RD
195 unsigned tmp;
196
197 // Reset the dsp
198 if (ioctl(dev, SNDCTL_DSP_RESET, 0) < 0)
199 {
200 wxLogTrace(_T("sound"), _T("unable to reset dsp"));
9be32e8f 201 return false;
544c4a3b
RD
202 }
203
204 m_needConversion = false;
f8a586e0 205
544c4a3b
RD
206 tmp = data->m_bitsPerSample;
207 if (ioctl(dev, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
208 {
209 wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SAMPLESIZE)"));
9be32e8f 210 return false;
544c4a3b
RD
211 }
212 if (tmp != data->m_bitsPerSample)
213 {
214 wxLogTrace(_T("sound"),
215 _T("Unable to set DSP sample size to %d (wants %d)"),
216 data->m_bitsPerSample, tmp);
217 m_needConversion = true;
f8a586e0
RL
218 }
219
544c4a3b
RD
220 unsigned stereo = data->m_channels == 1 ? 0 : 1;
221 tmp = stereo;
222 if (ioctl(dev, SNDCTL_DSP_STEREO, &tmp) < 0)
223 {
224 wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_STEREO)"));
9be32e8f 225 return false;
544c4a3b
RD
226 }
227 if (tmp != stereo)
228 {
f8a586e0 229 wxLogTrace(_T("sound"), _T("Unable to set DSP to %s."), stereo? _T("stereo"):_T("mono"));
544c4a3b
RD
230 m_needConversion = true;
231 }
232
233 tmp = data->m_samplingRate;
234 if (ioctl(dev, SNDCTL_DSP_SPEED, &tmp) < 0)
235 {
236 wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_SPEED)"));
237 return false;
238 }
239 if (tmp != data->m_samplingRate)
240 {
241 // If the rate the sound card is using is not within 1% of what the
242 // data specified then override the data setting. The only reason not
243 // to always override this is because of clock-rounding
244 // problems. Sound cards will sometimes use things like 44101 when you
245 // ask for 44100. No need overriding this and having strange output
246 // file rates for something that we can't hear anyways.
f8a586e0
RL
247 if (data->m_samplingRate - tmp > (tmp * .01) ||
248 tmp - data->m_samplingRate > (tmp * .01)) {
249 wxLogTrace(_T("sound"),
544c4a3b
RD
250 _T("Unable to set DSP sampling rate to %d (wants %d)"),
251 data->m_samplingRate, tmp);
252 m_needConversion = true;
f8a586e0 253 }
544c4a3b
RD
254 }
255
256 // Do this last because some drivers can adjust the buffer sized based on
257 // the sampling rate, etc.
258 if (ioctl(dev, SNDCTL_DSP_GETBLKSIZE, &m_DSPblkSize) < 0)
259 {
260 wxLogTrace(_T("sound"), _T("IOCTL failure (SNDCTL_DSP_GETBLKSIZE)"));
9be32e8f 261 return false;
544c4a3b 262 }
9be32e8f
VS
263 return true;
264}
f8a586e0 265
9be32e8f
VS
266#endif // HAVE_SYS_SOUNDCARD_H
267
9be32e8f 268// ----------------------------------------------------------------------------
83f7f12d 269// wxSoundSyncOnlyAdaptor
9be32e8f
VS
270// ----------------------------------------------------------------------------
271
272#if wxUSE_THREADS
273
83f7f12d 274class wxSoundSyncOnlyAdaptor;
9be32e8f
VS
275
276// this class manages asynchronous playback of audio if the backend doesn't
277// support it natively (e.g. OSS backend)
278class wxSoundAsyncPlaybackThread : public wxThread
279{
280public:
83f7f12d 281 wxSoundAsyncPlaybackThread(wxSoundSyncOnlyAdaptor *adaptor,
9be32e8f 282 wxSoundData *data, unsigned flags)
83f7f12d
VS
283 : wxThread(), m_adapt(adaptor), m_data(data), m_flags(flags) {}
284 virtual ExitCode Entry();
f8a586e0 285
9be32e8f 286protected:
83f7f12d 287 wxSoundSyncOnlyAdaptor *m_adapt;
9be32e8f
VS
288 wxSoundData *m_data;
289 unsigned m_flags;
290};
291
292#endif // wxUSE_THREADS
293
83f7f12d
VS
294// This class turns wxSoundBackend that doesn't support asynchronous playback
295// into one that does
296class wxSoundSyncOnlyAdaptor : public wxSoundBackend
297{
298public:
299 wxSoundSyncOnlyAdaptor(wxSoundBackend *backend)
300 : m_backend(backend), m_playing(false) {}
301 ~wxSoundSyncOnlyAdaptor()
302 {
303 delete m_backend;
304 }
305 wxString GetName() const
306 {
307 return m_backend->GetName();
308 }
309 int GetPriority() const
310 {
311 return m_backend->GetPriority();
312 }
313 bool IsAvailable() const
314 {
315 return m_backend->IsAvailable();
316 }
317 bool HasNativeAsyncPlayback() const
318 {
319 return true;
320 }
321 bool Play(wxSoundData *data, unsigned flags,
322 volatile wxSoundPlaybackStatus *status);
323 void Stop();
324 bool IsPlaying() const;
325
326private:
327 friend class wxSoundAsyncPlaybackThread;
328
329 wxSoundBackend *m_backend;
330 bool m_playing;
331#if wxUSE_THREADS
332 // player thread holds this mutex and releases it after it finishes
333 // playing, so that the main thread knows when it can play sound
334 wxMutex m_mutexRightToPlay;
335 wxSoundPlaybackStatus m_status;
336#endif
337};
338
339
340#if wxUSE_THREADS
341wxThread::ExitCode wxSoundAsyncPlaybackThread::Entry()
342{
343 m_adapt->m_backend->Play(m_data, m_flags & ~wxSOUND_ASYNC,
344 &m_adapt->m_status);
345
346 m_data->DecRef();
347 m_adapt->m_playing = false;
348 m_adapt->m_mutexRightToPlay.Unlock();
349 wxLogTrace(_T("sound"), _T("terminated async playback thread"));
350 return 0;
351}
352#endif
353
354bool wxSoundSyncOnlyAdaptor::Play(wxSoundData *data, unsigned flags,
355 volatile wxSoundPlaybackStatus *status)
356{
357 Stop();
358 if (flags & wxSOUND_ASYNC)
359 {
360#if wxUSE_THREADS
361 m_mutexRightToPlay.Lock();
362 m_status.m_playing = true;
363 m_status.m_stopRequested = false;
364 data->IncRef();
365 wxThread *th = new wxSoundAsyncPlaybackThread(this, data, flags);
366 th->Create();
367 th->Run();
368 wxLogTrace(_T("sound"), _T("launched async playback thread"));
369 return true;
370#else
371 wxLogError(_("Unable to play sound asynchronously."));
372 return false;
373#endif
374 }
375 else
376 {
377#if wxUSE_THREADS
378 m_mutexRightToPlay.Lock();
379#endif
380 bool rv = m_backend->Play(data, flags, status);
381#if wxUSE_THREADS
382 m_mutexRightToPlay.Unlock();
383#endif
384 return rv;
385 }
386}
387
388void wxSoundSyncOnlyAdaptor::Stop()
389{
390 wxLogTrace(_T("sound"), _T("asking audio to stop"));
f8a586e0 391
a333f34d 392#if wxUSE_THREADS
83f7f12d
VS
393 // tell the player thread (if running) to stop playback ASAP:
394 m_status.m_stopRequested = true;
f8a586e0 395
83f7f12d
VS
396 // acquire the mutex to be sure no sound is being played, then
397 // release it because we don't need it for anything (the effect of this
398 // is that calling thread will wait until playback thread reacts to
399 // our request to interrupt playback):
400 m_mutexRightToPlay.Lock();
401 m_mutexRightToPlay.Unlock();
402 wxLogTrace(_T("sound"), _T("audio was stopped"));
a333f34d 403#endif
83f7f12d
VS
404}
405
406bool wxSoundSyncOnlyAdaptor::IsPlaying() const
407{
a333f34d 408#if wxUSE_THREADS
83f7f12d 409 return m_status.m_playing;
a333f34d 410#else
8fbe65e9 411 return false;
a333f34d 412#endif
83f7f12d
VS
413}
414
415
9be32e8f 416// ----------------------------------------------------------------------------
f8a586e0 417// wxSound
9be32e8f
VS
418// ----------------------------------------------------------------------------
419
420wxSoundBackend *wxSound::ms_backend = NULL;
421
422// FIXME - temporary, until we have plugins architecture
423#if wxUSE_LIBSDL
424 #if wxUSE_PLUGINS
425 wxDynamicLibrary *wxSound::ms_backendSDL = NULL;
426 #else
427 extern "C" wxSoundBackend *wxCreateSoundBackendSDL();
428 #endif
429#endif
430
431wxSound::wxSound() : m_data(NULL)
432{
433}
434
435wxSound::wxSound(const wxString& sFileName, bool isResource) : m_data(NULL)
436{
437 Create(sFileName, isResource);
438}
439
440wxSound::wxSound(int size, const wxByte* data) : m_data(NULL)
441{
442 Create(size, data);
443}
444
445wxSound::~wxSound()
446{
447 Free();
448}
449
3f9ee1cd
VZ
450bool wxSound::Create(const wxString& fileName,
451 bool WXUNUSED_UNLESS_DEBUG(isResource))
9be32e8f
VS
452{
453 wxASSERT_MSG( !isResource,
454 _T("Loading sound from resources is only supported on Windows") );
f8a586e0 455
9be32e8f 456 Free();
f8a586e0 457
9be32e8f
VS
458 wxFile fileWave;
459 if (!fileWave.Open(fileName, wxFile::read))
f8a586e0
RL
460 {
461 return false;
462 }
9be32e8f 463
c781c316
VZ
464 wxFileOffset lenOrig = fileWave.Length();
465 if ( lenOrig == wxInvalidOffset )
466 return false;
467
468 size_t len = wx_truncate_cast(size_t, lenOrig);
9be32e8f 469 wxUint8 *data = new wxUint8[len];
0586024f 470 if ( fileWave.Read(data, len) != lenOrig )
9be32e8f
VS
471 {
472 wxLogError(_("Couldn't load sound data from '%s'."), fileName.c_str());
473 return false;
474 }
475
476 if (!LoadWAV(data, len, false))
477 {
478 wxLogError(_("Sound file '%s' is in unsupported format."),
479 fileName.c_str());
480 return false;
481 }
f8a586e0 482
9be32e8f
VS
483 return true;
484}
485
486bool wxSound::Create(int size, const wxByte* data)
487{
488 wxASSERT( data != NULL );
489
490 Free();
491 if (!LoadWAV(data, size, true))
492 {
493 wxLogError(_("Sound data are in unsupported format."));
494 return false;
495 }
496 return true;
497}
498
499/*static*/ void wxSound::EnsureBackend()
500{
501 if (!ms_backend)
502 {
503 // FIXME -- make this fully dynamic when plugins architecture is in
504 // place
9be32e8f 505#if wxUSE_LIBSDL
3209f765 506 //if (!ms_backend)
9be32e8f
VS
507 {
508#if !wxUSE_PLUGINS
509 ms_backend = wxCreateSoundBackendSDL();
510#else
511 wxString dllname;
512 dllname.Printf(_T("%s/%s"),
513 wxDynamicLibrary::GetPluginsDirectory().c_str(),
514 wxDynamicLibrary::CanonicalizePluginName(
515 _T("sound_sdl"), wxDL_PLUGIN_BASE).c_str());
516 wxLogTrace(_T("sound"),
517 _T("trying to load SDL plugin from '%s'..."),
518 dllname.c_str());
519 wxLogNull null;
520 ms_backendSDL = new wxDynamicLibrary(dllname, wxDL_NOW);
521 if (!ms_backendSDL->IsLoaded())
522 {
523 wxDELETE(ms_backendSDL);
524 }
525 else
526 {
527 typedef wxSoundBackend *(*wxCreateSoundBackend_t)();
528 wxDYNLIB_FUNCTION(wxCreateSoundBackend_t,
529 wxCreateSoundBackendSDL, *ms_backendSDL);
530 if (pfnwxCreateSoundBackendSDL)
531 {
532 ms_backend = (*pfnwxCreateSoundBackendSDL)();
533 }
534 }
535#endif
536 if (ms_backend && !ms_backend->IsAvailable())
537 {
538 wxDELETE(ms_backend);
539 }
540 }
541#endif
542
3209f765
VS
543#ifdef HAVE_SYS_SOUNDCARD_H
544 if (!ms_backend)
545 {
546 ms_backend = new wxSoundBackendOSS();
547 if (!ms_backend->IsAvailable())
548 {
549 wxDELETE(ms_backend);
550 }
551 }
552#endif
553
9be32e8f
VS
554 if (!ms_backend)
555 ms_backend = new wxSoundBackendNull();
556
83f7f12d
VS
557 if (!ms_backend->HasNativeAsyncPlayback())
558 ms_backend = new wxSoundSyncOnlyAdaptor(ms_backend);
559
9be32e8f
VS
560 wxLogTrace(_T("sound"),
561 _T("using backend '%s'"), ms_backend->GetName().c_str());
562 }
563}
564
565/*static*/ void wxSound::UnloadBackend()
566{
567 if (ms_backend)
568 {
569 wxLogTrace(_T("sound"), _T("unloading backend"));
83f7f12d
VS
570
571 Stop();
f8a586e0 572
9be32e8f
VS
573 delete ms_backend;
574 ms_backend = NULL;
575#if wxUSE_LIBSDL && wxUSE_PLUGINS
576 delete ms_backendSDL;
577#endif
578 }
579}
580
f156e20c 581bool wxSound::DoPlay(unsigned flags) const
9be32e8f
VS
582{
583 wxCHECK_MSG( IsOk(), false, _T("Attempt to play invalid wave data") );
584
585 EnsureBackend();
83f7f12d
VS
586 wxSoundPlaybackStatus status;
587 status.m_playing = true;
588 status.m_stopRequested = false;
589 return ms_backend->Play(m_data, flags, &status);
590}
9be32e8f 591
83f7f12d
VS
592/*static*/ void wxSound::Stop()
593{
594 if (ms_backend)
595 ms_backend->Stop();
596}
597
598/*static*/ bool wxSound::IsPlaying()
599{
600 if (ms_backend)
601 return ms_backend->IsPlaying();
9be32e8f 602 else
83f7f12d 603 return false;
9be32e8f
VS
604}
605
606void wxSound::Free()
607{
9be32e8f
VS
608 if (m_data)
609 m_data->DecRef();
610}
611
612typedef struct
f8a586e0 613{
9be32e8f
VS
614 wxUint32 uiSize;
615 wxUint16 uiFormatTag;
616 wxUint16 uiChannels;
617 wxUint32 ulSamplesPerSec;
618 wxUint32 ulAvgBytesPerSec;
619 wxUint16 uiBlockAlign;
620 wxUint16 uiBitsPerSample;
83f7f12d 621} WAVEFORMAT;
9be32e8f 622
9be32e8f
VS
623#define WAVE_FORMAT_PCM 1
624#define WAVE_INDEX 8
625#define FMT_INDEX 12
626
627bool wxSound::LoadWAV(const wxUint8 *data, size_t length, bool copyData)
628{
629 WAVEFORMAT waveformat;
630 wxUint32 ul;
631
632 if (length < 32 + sizeof(WAVEFORMAT))
633 return false;
634
635 memcpy(&waveformat, &data[FMT_INDEX + 4], sizeof(WAVEFORMAT));
636 waveformat.uiSize = wxUINT32_SWAP_ON_BE(waveformat.uiSize);
637 waveformat.uiFormatTag = wxUINT16_SWAP_ON_BE(waveformat.uiFormatTag);
638 waveformat.uiChannels = wxUINT16_SWAP_ON_BE(waveformat.uiChannels);
639 waveformat.ulSamplesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulSamplesPerSec);
640 waveformat.ulAvgBytesPerSec = wxUINT32_SWAP_ON_BE(waveformat.ulAvgBytesPerSec);
641 waveformat.uiBlockAlign = wxUINT16_SWAP_ON_BE(waveformat.uiBlockAlign);
642 waveformat.uiBitsPerSample = wxUINT16_SWAP_ON_BE(waveformat.uiBitsPerSample);
643
644 if (memcmp(data, "RIFF", 4) != 0)
645 return false;
646 if (memcmp(&data[WAVE_INDEX], "WAVE", 4) != 0)
647 return false;
648 if (memcmp(&data[FMT_INDEX], "fmt ", 4) != 0)
649 return false;
650 if (memcmp(&data[FMT_INDEX + waveformat.uiSize + 8], "data", 4) != 0)
651 return false;
652 memcpy(&ul,&data[FMT_INDEX + waveformat.uiSize + 12], 4);
653 ul = wxUINT32_SWAP_ON_BE(ul);
f8a586e0 654
9be32e8f
VS
655 //WAS: if (ul + FMT_INDEX + waveformat.uiSize + 16 != length)
656 if (ul + FMT_INDEX + waveformat.uiSize + 16 > length)
657 return false;
f8a586e0 658
9be32e8f
VS
659 if (waveformat.uiFormatTag != WAVE_FORMAT_PCM)
660 return false;
f8a586e0
RL
661
662 if (waveformat.ulSamplesPerSec !=
9be32e8f
VS
663 waveformat.ulAvgBytesPerSec / waveformat.uiBlockAlign)
664 return false;
f8a586e0 665
9be32e8f
VS
666 m_data = new wxSoundData;
667 m_data->m_channels = waveformat.uiChannels;
668 m_data->m_samplingRate = waveformat.ulSamplesPerSec;
669 m_data->m_bitsPerSample = waveformat.uiBitsPerSample;
670 m_data->m_samples = ul / (m_data->m_channels * m_data->m_bitsPerSample / 8);
671 m_data->m_dataBytes = ul;
672
673 if (copyData)
674 {
675 m_data->m_dataWithHeader = new wxUint8[length];
676 memcpy(m_data->m_dataWithHeader, data, length);
677 }
678 else
679 m_data->m_dataWithHeader = (wxUint8*)data;
680
f8a586e0 681 m_data->m_data =
9be32e8f
VS
682 (&m_data->m_dataWithHeader[FMT_INDEX + waveformat.uiSize + 8]);
683
684 return true;
685}
686
687
688// ----------------------------------------------------------------------------
689// wxSoundCleanupModule
690// ----------------------------------------------------------------------------
691
692class wxSoundCleanupModule: public wxModule
693{
694public:
695 bool OnInit() { return true; }
696 void OnExit() { wxSound::UnloadBackend(); }
697 DECLARE_DYNAMIC_CLASS(wxSoundCleanupModule)
698};
699
700IMPLEMENT_DYNAMIC_CLASS(wxSoundCleanupModule, wxModule)
701
702#endif