]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/sound.cpp
new file added
[wxWidgets.git] / src / osx / carbon / sound.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
524c47aa 2// Name: src/osx/carbon/sound.cpp
489468fe
SC
3// Purpose: wxSound class implementation: optional
4// Author: Ryan Norton
5// Modified by: Stefan Csomor
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#if wxUSE_SOUND
16
deb0a11e
SC
17#if wxOSX_USE_QUICKTIME
18
489468fe
SC
19#include "wx/sound.h"
20
21#ifndef WX_PRECOMP
22 #include "wx/object.h"
23 #include "wx/string.h"
24 #include "wx/intl.h"
25 #include "wx/log.h"
26 #include "wx/timer.h"
27#endif
28
29#include "wx/file.h"
30
31// Carbon QT Implementation Details -
32//
33// Memory:
34// 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
35// 2) NewMovie(0);
36// 3) MovieImportDataRef() //Pass Memory Location to this
37// 4) PlayMovie();
38// 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
39//
40// File:
41// 1) Path as CFString
42// 2) Call QTNewDataReferenceFromFullPathCFString
43// 3) Call NewMovieFromDataRef
44// 4) Call CloseMovieFile
45// 4) PlayMovie();
46// 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
47//
48
49#ifdef __WXMAC__
deb0a11e
SC
50 #include "wx/osx/private.h"
51 #if wxOSX_USE_COCOA_OR_CARBON
52 #include <QuickTime/QuickTimeComponents.h>
53 #endif
489468fe 54#else
deb0a11e 55 #include <qtml.h>
489468fe
SC
56#endif
57
489468fe
SC
58#define MOVIE_DELAY 100
59
489468fe 60// ------------------------------------------------------------------
deb0a11e 61// SoundManager
489468fe 62// ------------------------------------------------------------------
deb0a11e
SC
63
64class wxOSXSoundManagerSoundData : public wxSoundData
489468fe
SC
65{
66public:
deb0a11e
SC
67 wxOSXSoundManagerSoundData(const wxString& fileName);
68 ~wxOSXSoundManagerSoundData();
ce00f59b 69
deb0a11e
SC
70 virtual bool Play(unsigned flags);
71 virtual void SoundTask();
489468fe 72
deb0a11e
SC
73 void DoStop();
74protected:
ce00f59b 75 SndListHandle m_hSnd;
deb0a11e
SC
76 SndChannelPtr m_pSndChannel;
77};
489468fe 78
deb0a11e
SC
79wxOSXSoundManagerSoundData::wxOSXSoundManagerSoundData(const wxString& fileName) :
80 m_pSndChannel(NULL)
ce00f59b 81{
deb0a11e 82 Str255 lpSnd ;
ce00f59b 83
deb0a11e 84 wxMacStringToPascal( fileName , lpSnd ) ;
ce00f59b 85
deb0a11e
SC
86 m_hSnd = (SndListHandle) GetNamedResource('snd ', (const unsigned char *) lpSnd);
87}
489468fe 88
deb0a11e
SC
89wxOSXSoundManagerSoundData::~wxOSXSoundManagerSoundData()
90{
91 DoStop();
92 ReleaseResource((Handle)m_hSnd);
93}
489468fe 94
deb0a11e
SC
95void wxOSXSoundManagerSoundData::DoStop()
96{
97 if ( m_pSndChannel )
489468fe 98 {
deb0a11e
SC
99 SndDisposeChannel(m_pSndChannel, TRUE /* stop immediately, not after playing */);
100 m_pSndChannel = NULL;
101 wxSound::SoundStopped(this);
489468fe 102 }
ce00f59b 103
509da835
KO
104 if (IsMarkedForDeletion())
105 delete this;
deb0a11e 106}
489468fe 107
deb0a11e
SC
108bool wxOSXSoundManagerSoundData::Play(unsigned flags)
109{
110 Stop();
489468fe 111
deb0a11e 112 m_flags = flags;
489468fe 113
deb0a11e
SC
114 SoundComponentData data;
115 unsigned long numframes, offset;
ce00f59b 116
deb0a11e 117 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
489468fe 118
deb0a11e
SC
119 SndNewChannel(&m_pSndChannel, sampledSynth,
120 initNoInterp
121 + (data.numChannels == 1 ? initMono : initStereo), NULL);
ce00f59b 122
deb0a11e
SC
123 if(SndPlay(m_pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr)
124 return false;
ce00f59b 125
deb0a11e
SC
126 if (flags & wxSOUND_ASYNC)
127 CreateAndStartTimer();
128 else
129 DoStop();
ce00f59b 130
deb0a11e
SC
131 return true;
132}
489468fe 133
deb0a11e 134void wxOSXSoundManagerSoundData::SoundTask()
489468fe 135{
deb0a11e 136 SCStatus stat;
ce00f59b 137
deb0a11e 138 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
489468fe 139 Stop();
ce00f59b 140
deb0a11e
SC
141 //if the sound isn't playing anymore, see if it's looped,
142 //and if so play it again, otherwise close things up
143 if (stat.scChannelBusy == FALSE)
489468fe 144 {
deb0a11e 145 if (m_flags & wxSOUND_LOOP)
489468fe 146 {
deb0a11e
SC
147 if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr)
148 Stop();
489468fe 149 }
deb0a11e
SC
150 else
151 Stop();
489468fe 152 }
deb0a11e 153}
489468fe
SC
154
155// ------------------------------------------------------------------
deb0a11e 156// QuickTime
489468fe
SC
157// ------------------------------------------------------------------
158
deb0a11e
SC
159bool wxInitQT();
160bool wxInitQT()
489468fe 161{
deb0a11e
SC
162#ifndef __WXMAC__
163 int nError;
164 //-2093 no dll
165 if ((nError = InitializeQTML(0)) != noErr)
489468fe 166 {
deb0a11e 167 wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
489468fe
SC
168 return false;
169 }
489468fe 170#endif
deb0a11e
SC
171 EnterMovies();
172 return true;
489468fe
SC
173}
174
deb0a11e
SC
175void wxExitQT();
176void wxExitQT()
489468fe 177{
deb0a11e
SC
178 //Note that ExitMovies() is not necessary, but
179 //the docs are fuzzy on whether or not TerminateQTML is
180 ExitMovies();
ce00f59b 181
deb0a11e
SC
182#ifndef __WXMAC__
183 TerminateQTML();
184#endif
489468fe
SC
185}
186
deb0a11e 187class wxOSXQuickTimeSoundData : public wxSoundData
489468fe 188{
deb0a11e
SC
189public:
190 wxOSXQuickTimeSoundData(const wxString& fileName);
c559c4b3 191 wxOSXQuickTimeSoundData(size_t size, const void* data);
deb0a11e 192 ~wxOSXQuickTimeSoundData();
ce00f59b 193
deb0a11e
SC
194 virtual bool Play(unsigned flags);
195 virtual void SoundTask();
196 virtual void DoStop();
197protected:
198 Movie m_movie;
ce00f59b 199
deb0a11e
SC
200 wxString m_sndname; //file path
201 Handle m_soundHandle;
202};
203
204
205wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(const wxString& fileName) :
206 m_movie(NULL), m_soundHandle(NULL)
ce00f59b 207{
deb0a11e 208 m_sndname = fileName;
489468fe
SC
209}
210
c559c4b3 211wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(size_t size, const void* data) :
deb0a11e 212 m_movie(NULL)
ce00f59b 213{
deb0a11e
SC
214 m_soundHandle = NewHandleClear((Size)size);
215 BlockMove(data, *m_soundHandle, size);
489468fe
SC
216}
217
deb0a11e 218wxOSXQuickTimeSoundData::~wxOSXQuickTimeSoundData()
489468fe 219{
deb0a11e
SC
220 if ( m_soundHandle )
221 DisposeHandle(m_soundHandle);
489468fe
SC
222}
223
deb0a11e 224bool wxOSXQuickTimeSoundData::Play(unsigned flags)
489468fe 225{
deb0a11e
SC
226 if ( m_movie )
227 Stop();
ce00f59b 228
deb0a11e 229 m_flags = flags;
ce00f59b 230
deb0a11e
SC
231 if (!wxInitQT())
232 return false;
489468fe 233
deb0a11e 234 if( m_soundHandle )
489468fe 235 {
deb0a11e
SC
236 Handle dataRef = nil;
237 MovieImportComponent miComponent;
238 Track targetTrack = nil;
239 TimeValue addedDuration = 0;
240 long outFlags = 0;
241 OSErr err;
242 ComponentResult result;
ce00f59b 243
deb0a11e 244 err = PtrToHand(&m_soundHandle, &dataRef, sizeof(Handle));
ce00f59b 245
deb0a11e
SC
246 HLock(m_soundHandle);
247 if (memcmp(&(*m_soundHandle)[8], "WAVE", 4) == 0)
248 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
249 else if (memcmp(&(*m_soundHandle)[8], "AIFF", 4) == 0)
250 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFF);
251 else if (memcmp(&(*m_soundHandle)[8], "AIFC", 4) == 0)
252 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFC);
253 else
489468fe 254 {
deb0a11e
SC
255 HUnlock(m_soundHandle);
256 wxLogSysError(wxT("wxSound - Location in memory does not contain valid data"));
257 return false;
489468fe 258 }
ce00f59b 259
deb0a11e
SC
260 HUnlock(m_soundHandle);
261 m_movie = NewMovie(0);
ce00f59b 262
deb0a11e
SC
263 result = MovieImportDataRef(miComponent, dataRef,
264 HandleDataHandlerSubType, m_movie,
265 nil, &targetTrack,
266 nil, &addedDuration,
267 movieImportCreateTrack, &outFlags);
ce00f59b 268
deb0a11e 269 if (result != noErr)
489468fe 270 {
deb0a11e 271 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
489468fe 272 }
ce00f59b 273
deb0a11e
SC
274 SetMovieVolume(m_movie, kFullVolume);
275 GoToBeginningOfMovie(m_movie);
276 }
277 else
278 {
279 OSErr err = noErr ;
ce00f59b 280
deb0a11e
SC
281 Handle dataRef = NULL;
282 OSType dataRefType;
ce00f59b 283
deb0a11e
SC
284 err = QTNewDataReferenceFromFullPathCFString(wxCFStringRef(m_sndname,wxLocale::GetSystemEncoding()),
285 (UInt32)kQTNativeDefaultPathStyle, 0, &dataRef, &dataRefType);
ce00f59b 286
deb0a11e 287 wxASSERT(err == noErr);
ce00f59b 288
deb0a11e 289 if (NULL != dataRef || err != noErr)
489468fe 290 {
deb0a11e 291 err = NewMovieFromDataRef( &m_movie, newMovieDontAskUnresolvedDataRefs , NULL, dataRef, dataRefType );
489468fe 292 wxASSERT(err == noErr);
deb0a11e 293 DisposeHandle(dataRef);
489468fe 294 }
ce00f59b 295
deb0a11e
SC
296 if (err != noErr)
297 {
298 wxLogSysError(
299 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err )
300 );
301 return false;
302 }
303 }
ce00f59b 304
deb0a11e
SC
305 //Start the m_movie!
306 StartMovie(m_movie);
ce00f59b 307
489468fe
SC
308 if (flags & wxSOUND_ASYNC)
309 {
deb0a11e 310 CreateAndStartTimer();
489468fe
SC
311 }
312 else
313 {
314 wxASSERT_MSG(!(flags & wxSOUND_LOOP), wxT("Can't loop and play syncronously at the same time"));
ce00f59b 315
489468fe
SC
316 //Play movie until it ends, then exit
317 //Note that due to quicktime caching this may not always
318 //work 100% correctly
deb0a11e
SC
319 while (!IsMovieDone(m_movie))
320 MoviesTask(m_movie, 1);
ce00f59b 321
deb0a11e 322 DoStop();
489468fe 323 }
ce00f59b 324
489468fe
SC
325 return true;
326}
327
deb0a11e 328void wxOSXQuickTimeSoundData::DoStop()
489468fe 329{
deb0a11e
SC
330 if( m_movie )
331 {
332 StopMovie(m_movie);
333 DisposeMovie(m_movie);
334 m_movie = NULL;
335 wxSound::SoundStopped(this);
336 wxExitQT();
337 }
489468fe
SC
338}
339
deb0a11e 340void wxOSXQuickTimeSoundData::SoundTask()
489468fe 341{
deb0a11e 342 if(IsMovieDone(m_movie))
489468fe 343 {
deb0a11e
SC
344 if (m_flags & wxSOUND_LOOP)
345 {
346 StopMovie(m_movie);
347 GoToBeginningOfMovie(m_movie);
348 StartMovie(m_movie);
349 }
350 else
351 Stop();
489468fe 352 }
deb0a11e
SC
353 else
354 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
489468fe
SC
355}
356
c559c4b3 357bool wxSound::Create(size_t size, const void* data)
489468fe 358{
deb0a11e
SC
359 m_data = new wxOSXQuickTimeSoundData(size,data);
360 return true;
361}
489468fe 362
deb0a11e
SC
363bool wxSound::Create(const wxString& fileName, bool isResource)
364{
365 if ( isResource )
366 m_data = new wxOSXSoundManagerSoundData(fileName);
367 else
368 m_data = new wxOSXQuickTimeSoundData(fileName);
369 return true;
489468fe
SC
370}
371
deb0a11e
SC
372#endif // wxOSX_USE_QUICKTIME
373
489468fe 374#endif //wxUSE_SOUND