]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/sound.cpp
cfd49959a9c2015c2290c8ce0c2449b5c99dcb5b
[wxWidgets.git] / src / osx / carbon / sound.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/sound.cpp
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
17 #if wxOSX_USE_QUICKTIME
18
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__
50 #include "wx/osx/private.h"
51 #if wxOSX_USE_COCOA_OR_CARBON
52 #include <QuickTime/QuickTimeComponents.h>
53 #endif
54 #else
55 #include <qtml.h>
56 #endif
57
58 #define MOVIE_DELAY 100
59
60 // ------------------------------------------------------------------
61 // SoundManager
62 // ------------------------------------------------------------------
63
64 class wxOSXSoundManagerSoundData : public wxSoundData
65 {
66 public:
67 wxOSXSoundManagerSoundData(const wxString& fileName);
68 ~wxOSXSoundManagerSoundData();
69
70 virtual bool Play(unsigned flags);
71 virtual void SoundTask();
72
73 void DoStop();
74 protected:
75 SndListHandle m_hSnd;
76 SndChannelPtr m_pSndChannel;
77 };
78
79 wxOSXSoundManagerSoundData::wxOSXSoundManagerSoundData(const wxString& fileName) :
80 m_pSndChannel(NULL)
81 {
82 Str255 lpSnd ;
83
84 wxMacStringToPascal( fileName , lpSnd ) ;
85
86 m_hSnd = (SndListHandle) GetNamedResource('snd ', (const unsigned char *) lpSnd);
87 }
88
89 wxOSXSoundManagerSoundData::~wxOSXSoundManagerSoundData()
90 {
91 DoStop();
92 ReleaseResource((Handle)m_hSnd);
93 }
94
95 void wxOSXSoundManagerSoundData::DoStop()
96 {
97 if ( m_pSndChannel )
98 {
99 SndDisposeChannel(m_pSndChannel, TRUE /* stop immediately, not after playing */);
100 m_pSndChannel = NULL;
101 wxSound::SoundStopped(this);
102 }
103
104 if (IsMarkedForDeletion())
105 delete this;
106 }
107
108 bool wxOSXSoundManagerSoundData::Play(unsigned flags)
109 {
110 Stop();
111
112 m_flags = flags;
113
114 SoundComponentData data;
115 unsigned long numframes, offset;
116
117 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
118
119 SndNewChannel(&m_pSndChannel, sampledSynth,
120 initNoInterp
121 + (data.numChannels == 1 ? initMono : initStereo), NULL);
122
123 if(SndPlay(m_pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr)
124 return false;
125
126 if (flags & wxSOUND_ASYNC)
127 CreateAndStartTimer();
128 else
129 DoStop();
130
131 return true;
132 }
133
134 void wxOSXSoundManagerSoundData::SoundTask()
135 {
136 SCStatus stat;
137
138 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
139 Stop();
140
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)
144 {
145 if (m_flags & wxSOUND_LOOP)
146 {
147 if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr)
148 Stop();
149 }
150 else
151 Stop();
152 }
153 }
154
155 // ------------------------------------------------------------------
156 // QuickTime
157 // ------------------------------------------------------------------
158
159 bool wxInitQT();
160 bool wxInitQT()
161 {
162 #ifndef __WXMAC__
163 int nError;
164 //-2093 no dll
165 if ((nError = InitializeQTML(0)) != noErr)
166 {
167 wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
168 return false;
169 }
170 #endif
171 EnterMovies();
172 return true;
173 }
174
175 void wxExitQT();
176 void wxExitQT()
177 {
178 //Note that ExitMovies() is not necessary, but
179 //the docs are fuzzy on whether or not TerminateQTML is
180 ExitMovies();
181
182 #ifndef __WXMAC__
183 TerminateQTML();
184 #endif
185 }
186
187 class wxOSXQuickTimeSoundData : public wxSoundData
188 {
189 public:
190 wxOSXQuickTimeSoundData(const wxString& fileName);
191 wxOSXQuickTimeSoundData(size_t size, const void* data);
192 ~wxOSXQuickTimeSoundData();
193
194 virtual bool Play(unsigned flags);
195 virtual void SoundTask();
196 virtual void DoStop();
197 protected:
198 Movie m_movie;
199
200 wxString m_sndname; //file path
201 Handle m_soundHandle;
202 };
203
204
205 wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(const wxString& fileName) :
206 m_movie(NULL), m_soundHandle(NULL)
207 {
208 m_sndname = fileName;
209 }
210
211 wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(size_t size, const void* data) :
212 m_movie(NULL)
213 {
214 m_soundHandle = NewHandleClear((Size)size);
215 BlockMove(data, *m_soundHandle, size);
216 }
217
218 wxOSXQuickTimeSoundData::~wxOSXQuickTimeSoundData()
219 {
220 if ( m_soundHandle )
221 DisposeHandle(m_soundHandle);
222 }
223
224 bool wxOSXQuickTimeSoundData::Play(unsigned flags)
225 {
226 if ( m_movie )
227 Stop();
228
229 m_flags = flags;
230
231 if (!wxInitQT())
232 return false;
233
234 if( m_soundHandle )
235 {
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;
243
244 err = PtrToHand(&m_soundHandle, &dataRef, sizeof(Handle));
245
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
254 {
255 HUnlock(m_soundHandle);
256 wxLogSysError(wxT("wxSound - Location in memory does not contain valid data"));
257 return false;
258 }
259
260 HUnlock(m_soundHandle);
261 m_movie = NewMovie(0);
262
263 result = MovieImportDataRef(miComponent, dataRef,
264 HandleDataHandlerSubType, m_movie,
265 nil, &targetTrack,
266 nil, &addedDuration,
267 movieImportCreateTrack, &outFlags);
268
269 if (result != noErr)
270 {
271 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
272 }
273
274 SetMovieVolume(m_movie, kFullVolume);
275 GoToBeginningOfMovie(m_movie);
276 }
277 else
278 {
279 OSErr err = noErr ;
280
281 Handle dataRef = NULL;
282 OSType dataRefType;
283
284 err = QTNewDataReferenceFromFullPathCFString(wxCFStringRef(m_sndname,wxLocale::GetSystemEncoding()),
285 (UInt32)kQTNativeDefaultPathStyle, 0, &dataRef, &dataRefType);
286
287 wxASSERT(err == noErr);
288
289 if (NULL != dataRef || err != noErr)
290 {
291 err = NewMovieFromDataRef( &m_movie, newMovieDontAskUnresolvedDataRefs , NULL, dataRef, dataRefType );
292 wxASSERT(err == noErr);
293 DisposeHandle(dataRef);
294 }
295
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 }
304
305 //Start the m_movie!
306 StartMovie(m_movie);
307
308 if (flags & wxSOUND_ASYNC)
309 {
310 CreateAndStartTimer();
311 }
312 else
313 {
314 wxASSERT_MSG(!(flags & wxSOUND_LOOP), wxT("Can't loop and play syncronously at the same time"));
315
316 //Play movie until it ends, then exit
317 //Note that due to quicktime caching this may not always
318 //work 100% correctly
319 while (!IsMovieDone(m_movie))
320 MoviesTask(m_movie, 1);
321
322 DoStop();
323 }
324
325 return true;
326 }
327
328 void wxOSXQuickTimeSoundData::DoStop()
329 {
330 if( m_movie )
331 {
332 StopMovie(m_movie);
333 DisposeMovie(m_movie);
334 m_movie = NULL;
335 wxSound::SoundStopped(this);
336 wxExitQT();
337 }
338 }
339
340 void wxOSXQuickTimeSoundData::SoundTask()
341 {
342 if(IsMovieDone(m_movie))
343 {
344 if (m_flags & wxSOUND_LOOP)
345 {
346 StopMovie(m_movie);
347 GoToBeginningOfMovie(m_movie);
348 StartMovie(m_movie);
349 }
350 else
351 Stop();
352 }
353 else
354 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
355 }
356
357 bool wxSound::Create(size_t size, const void* data)
358 {
359 m_data = new wxOSXQuickTimeSoundData(size,data);
360 return true;
361 }
362
363 bool 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;
370 }
371
372 #endif // wxOSX_USE_QUICKTIME
373
374 #endif //wxUSE_SOUND