]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/sound.cpp
5d8f7ddacc1d8d73908bef188982de7613cfbf0d
[wxWidgets.git] / src / mac / carbon / sound.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: sound.cpp
3 // Purpose: wxSound class implementation: optional
4 // Author: Ryan Norton, Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton, Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "sound.h"
14 #endif
15
16 #include "wx/object.h"
17 #include "wx/string.h"
18 #include "wx/log.h"
19 #include "wx/file.h"
20 #include "wx/sound.h"
21 #include "wx/timer.h"
22
23 #if wxUSE_SOUND
24
25 // Carbon QT Implementation Details -
26 //
27 // Memory:
28 // 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
29 // 2) NewMovie(0);
30 // 3) MovieImportDataRef() //Pass Memory Location to this
31 // 4) PlayMovie();
32 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
33 //
34 // File:
35 // 1) Obtain FSSpec
36 // 2) Call OpenMovieFile
37 // 3) Call NewMovieFromFile
38 // 4) Call CloseMovieFile
39 // 4) PlayMovie();
40 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
41 //
42
43 #ifdef __WXMAC__
44 #include "wx/mac/private.h"
45 #include <Movies.h>
46 #include <Gestalt.h>
47 #endif
48
49 #if defined __WXMAC__ && defined __DARWIN__/*TARGET_CARBON*/
50 #ifdef __APPLE_CC__
51 #include <Carbon/Carbon.h>
52 #else
53 #include <Carbon.h>
54 #endif
55 #else
56 #include <Sound.h>
57 #endif
58
59 //quicktime media layer only required for mac emulation on pc
60 #ifndef __WXMAC__
61 #include <qtml.h>
62 #endif
63
64 #include <QuickTimeComponents.h>
65
66 //Time inbetween timer calls
67 #define MOVIE_DELAY 100
68
69 // ------------------------------------------------------------------
70 // wxQTTimer - Handle Asyncronous Playing
71 // ------------------------------------------------------------------
72 class wxQTTimer : public wxTimer
73 {
74 public:
75 wxQTTimer(Movie movie, bool bLoop) :
76 m_movie(movie), m_bLoop(bLoop)
77 {
78 }
79
80 ~wxQTTimer()
81 {
82 Shutdown();
83 }
84
85 void Shutdown()
86 {
87 StopMovie(m_movie);
88 DisposeMovie(m_movie);
89 m_movie = NULL ;
90 Stop();
91
92 //Note that ExitMovies() is not neccessary, but
93 //the docs are fuzzy on whether or not TerminateQTML is
94 ExitMovies();
95
96 #ifndef __WXMAC__
97 TerminateQTML();
98 #endif
99 }
100
101 void Notify()
102 {
103 if(IsMovieDone(m_movie))
104 {
105 if (!m_bLoop)
106 Shutdown();
107 else
108 {
109 StopMovie(m_movie);
110 GoToBeginningOfMovie(m_movie);
111 StartMovie(m_movie);
112 }
113 }
114 else
115 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
116 }
117
118
119 Movie& GetMovie() {return m_movie;}
120 protected:
121 Movie m_movie;
122 bool m_bLoop;
123 };
124
125
126 class wxSMTimer : public wxTimer
127 {
128 public:
129 wxSMTimer(void* hSnd, void* pSndChannel, const bool& bLoop)
130 : m_hSnd(hSnd), m_pSndChannel(pSndChannel), m_bLoop(bLoop)
131 {
132 }
133
134 ~wxSMTimer()
135 {
136 Shutdown();
137 }
138
139 void Notify()
140 {
141 SCStatus stat;
142
143 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
144 Shutdown();
145
146 //if the sound isn't playing anymore, see if it's looped,
147 //and if so play it again, otherwise close things up
148 if (stat.scChannelBusy == FALSE)
149 {
150 if (m_bLoop)
151 {
152 if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr)
153 Shutdown();
154 }
155 else
156 Shutdown();
157 }
158 }
159
160 void Shutdown()
161 {
162 SndDisposeChannel((SndChannelPtr)m_pSndChannel, TRUE);
163 Stop();
164 }
165
166 protected:
167 void* m_hSnd;
168 void* m_pSndChannel;
169 bool m_bLoop;
170 };
171
172 // ------------------------------------------------------------------
173 // wxSound
174 // ------------------------------------------------------------------
175
176 //Determines whether version 4 of QT is installed
177 Boolean wxIsQuickTime4Installed (void)
178 {
179 #ifdef __WXMAC__
180 short error;
181 long result;
182
183 error = Gestalt (gestaltQuickTime, &result);
184 return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
185 #else
186 return true;
187 #endif
188 }
189
190 inline bool wxInitQT ()
191 {
192 if (wxIsQuickTime4Installed())
193 {
194 #ifndef __WXMAC__
195 int nError;
196 //-2093 no dll
197 if ((nError = InitializeQTML(0)) != noErr)
198 wxLogSysError(wxString::Format("Couldn't Initialize Quicktime-%i", nError));
199 #endif
200 EnterMovies();
201 return true;
202 }
203 else
204 {
205 wxLogSysError("Quicktime is not installed, or Your Version of Quicktime is <= 4.");
206 return false;
207 }
208 }
209
210 wxSound::wxSound()
211 : m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE)
212 {
213 }
214
215 wxSound::wxSound(const wxString& sFileName, bool isResource)
216 : m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE)
217 {
218 Create(sFileName, isResource);
219 }
220
221 wxSound::wxSound(int size, const wxByte* data)
222 : m_hSnd((char*)data), m_waveLength(size), m_pTimer(NULL), m_type(wxSound_MEMORY)
223 {
224 if (!wxInitQT())
225 m_type = wxSound_NONE;
226 }
227
228 wxSound::~wxSound()
229 {
230 }
231
232 bool wxSound::Create(const wxString& fileName, bool isResource)
233 {
234 if(!wxInitQT())
235 return false;
236
237 if (isResource)
238 {
239 #ifdef __WXMAC__
240 m_type = wxSound_RESOURCE;
241
242 Str255 lpSnd ;
243
244 wxMacStringToPascal( fileName , lpSnd ) ;
245
246 m_sndname = lpSnd;
247 m_hSnd = (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd);
248 #else
249 return false;
250 #endif
251 }
252 else
253 {
254 m_type = wxSound_FILE;
255 m_sndname = fileName;
256 }
257
258 return true;
259 }
260
261 bool wxSound::DoPlay(unsigned flags) const
262 {
263 wxASSERT(m_pTimer == NULL || !((wxTimer*)m_pTimer)->IsRunning() );
264
265 Movie movie;
266
267 switch(m_type)
268 {
269 case wxSound_MEMORY:
270 {
271 Handle myHandle, dataRef = nil;
272 MovieImportComponent miComponent;
273 Track targetTrack = nil;
274 TimeValue addedDuration = 0;
275 long outFlags = 0;
276 OSErr err;
277 ComponentResult result;
278
279 myHandle = NewHandleClear((Size)m_waveLength);
280
281 BlockMove(m_hSnd, *myHandle, m_waveLength);
282
283 err = PtrToHand(&myHandle, &dataRef, sizeof(Handle));
284
285 if (memcmp(&m_hSnd[8], "WAVE", 4) == 0)
286 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
287 else if (memcmp(&m_hSnd[8], "AIFF", 4) == 0)
288 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFF);
289 else if (memcmp(&m_hSnd[8], "AIFC", 4) == 0)
290 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFC);
291 else
292 {
293 wxLogSysError("wxSound - Location in memory does not contain valid data");
294 return false;
295 }
296
297 movie = NewMovie(0);
298
299 result = MovieImportDataRef(miComponent, dataRef,
300 HandleDataHandlerSubType, movie,
301 nil, &targetTrack,
302 nil, &addedDuration,
303 movieImportCreateTrack, &outFlags);
304
305 if (result != noErr)
306 {
307 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
308 }
309
310 SetMovieVolume(movie, kFullVolume);
311 GoToBeginningOfMovie(movie);
312
313 DisposeHandle(myHandle);
314 }
315 break;
316 case wxSound_RESOURCE:
317 {
318 SoundComponentData data;
319 unsigned long numframes, offset;
320
321 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
322 //m_waveLength = numFrames * data.numChannels;
323
324 SndChannelPtr pSndChannel;
325 SndNewChannel(&pSndChannel, sampledSynth,
326 initNoInterp +
327 (data.numChannels == 1 ? initMono : initStereo), NULL);
328
329 if(SndPlay(pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr)
330 return false;
331
332 if (flags & wxSOUND_ASYNC)
333 {
334 ((wxSMTimer*&)m_pTimer) = new wxSMTimer(pSndChannel, m_hSnd, flags & wxSOUND_LOOP ? 1 : 0);
335
336 ((wxTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
337 }
338 else
339 SndDisposeChannel(pSndChannel, TRUE);
340
341 return true;
342 }
343 break;
344 case wxSound_FILE:
345 {
346 short movieResFile;
347 FSSpec sfFile;
348
349 #ifdef __WXMAC__
350 wxMacFilename2FSSpec( m_sndname , &sfFile ) ;
351 #else
352 int nError;
353 if ((nError = NativePathNameToFSSpec ((char*) m_sndname.c_str(), &sfFile, 0)) != noErr)
354 {
355 wxLogSysError(wxString::Format(wxT("File:%s does not exist\nError:%i"),
356 m_sndname.c_str(), nError));
357 return false;
358 }
359 #endif
360
361 if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
362 {
363 wxLogSysError(wxT("Quicktime couldn't open the file"));
364 return false;
365 }
366
367
368 short movieResID = 0;
369 Str255 movieName;
370 OSErr err;
371
372 err = NewMovieFromFile (
373 &movie,
374 movieResFile,
375 &movieResID,
376 movieName,
377 newMovieActive,
378 NULL); //wasChanged
379
380 CloseMovieFile (movieResFile);
381
382 if (err != noErr)
383 {
384 wxLogSysError(
385 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err )
386 );
387 return false;
388 }
389 }
390 break;
391 default:
392 return false;
393 }//end switch(m_type)
394
395
396 //Start the movie!
397 StartMovie(movie);
398
399 if (flags & wxSOUND_ASYNC)
400 {
401 //Start timer and play movie asyncronously
402 ((wxQTTimer*&)m_pTimer) = new wxQTTimer(movie, flags & wxSOUND_LOOP ? 1 : 0);
403 ((wxQTTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
404 }
405 else
406 {
407 wxASSERT_MSG(!(flags & wxSOUND_LOOP), "Can't loop and play syncronously at the same time");
408
409 //Play movie until it ends, then exit
410 while (!IsMovieDone(movie))
411 MoviesTask(movie, 0);
412
413 DisposeMovie(movie);
414 }
415
416 return true;
417 }
418
419 void* wxSound::GetHandle()
420 {
421 return (void*) ((wxQTTimer*) m_pTimer)->GetMovie();
422 }
423
424 bool wxSound::FreeData()
425 {
426 if (m_pTimer != NULL)
427 {
428 delete (wxQTTimer*) m_pTimer;
429 m_pTimer = NULL;
430 }
431
432 return true;
433 }
434 #endif //wxUSE_SOUND
435
436
437