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