]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/sound.cpp
If no colour name then use "BLACK"
[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
93 void Notify()
94 {
95 if(IsMovieDone(m_movie))
96 {
97 if (!m_bLoop)
98 Shutdown();
99 else
100 {
101 StopMovie(m_movie);
102 GoToBeginningOfMovie(m_movie);
103 StartMovie(m_movie);
104 }
105 }
106 else
107 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
108 }
109
110
111 Movie& GetMovie() {return m_movie;}
112 protected:
113 Movie m_movie;
114 bool m_bLoop;
115 };
116
117
118 class wxSMTimer : public wxTimer
119 {
120 public:
121 wxSMTimer(void* hSnd, void* pSndChannel, const bool& bLoop)
122 : m_hSnd(hSnd), m_pSndChannel(pSndChannel), m_bLoop(bLoop)
123 {
124 }
125
126 ~wxSMTimer()
127 {
128 Shutdown();
129 }
130
131 void Notify()
132 {
133 SCStatus stat;
134
135 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
136 Shutdown();
137
138 //if the sound isn't playing anymore, see if it's looped,
139 //and if so play it again, otherwise close things up
140 if (stat.scChannelBusy == FALSE)
141 {
142 if (m_bLoop)
143 {
144 if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr)
145 Shutdown();
146 }
147 else
148 Shutdown();
149 }
150 }
151
152 void Shutdown()
153 {
154 SndDisposeChannel((SndChannelPtr)m_pSndChannel, TRUE);
155 Stop();
156 }
157
158 protected:
159 void* m_hSnd;
160 void* m_pSndChannel;
161 bool m_bLoop;
162 };
163
164 // ------------------------------------------------------------------
165 // wxSound
166 // ------------------------------------------------------------------
167
168 //Determines whether version 4 of QT is installed
169 Boolean wxIsQuickTime4Installed (void)
170 {
171 #ifdef __WXMAC__
172 short error;
173 long result;
174
175 error = Gestalt (gestaltQuickTime, &result);
176 return (error == noErr) && (result >= 4); //result >= 4 correct?
177 #else
178 return true;
179 #endif
180 }
181
182 inline bool wxInitQT ()
183 {
184 if (wxIsQuickTime4Installed())
185 {
186 #ifndef __WXMAC__
187 int nError;
188 //-2093 no dll
189 if ((nError = InitializeQTML(0)) != noErr)
190 wxLogSysError(wxString::Format("Couldn't Initialize Quicktime-%i", nError));
191 #endif
192 EnterMovies();
193 return true;
194 }
195 else
196 {
197 wxLogSysError("Quicktime is not installed, or Your Version of Quicktime is <= 4.");
198 return false;
199 }
200 }
201
202 wxSound::wxSound()
203 : m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE)
204 {
205 }
206
207 wxSound::wxSound(const wxString& sFileName, bool isResource)
208 : m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE)
209 {
210 Create(sFileName, isResource);
211 }
212
213 wxSound::wxSound(int size, const wxByte* data)
214 : m_hSnd((char*)data), m_waveLength(size), m_pTimer(NULL), m_type(wxSound_MEMORY)
215 {
216 if (!wxInitQT())
217 m_type = wxSound_NONE;
218 }
219
220 wxSound::~wxSound()
221 {
222 FreeData();
223 }
224
225 bool wxSound::Create(const wxString& fileName, bool isResource)
226 {
227 if(!wxInitQT())
228 return false;
229
230 if (isResource)
231 {
232 #ifdef __WXMAC__
233 m_type = wxSound_RESOURCE;
234
235 Str255 lpSnd ;
236
237 wxMacStringToPascal( fileName , lpSnd ) ;
238
239 m_sndname = lpSnd;
240 m_hSnd = (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd);
241 #else
242 return false;
243 #endif
244 }
245 else
246 {
247 m_type = wxSound_FILE;
248 m_sndname = fileName;
249 }
250
251 return true;
252 }
253
254 bool wxSound::DoPlay(unsigned flags) const
255 {
256 wxASSERT(m_pTimer == NULL || !((wxTimer*)m_pTimer)->IsRunning() );
257
258 Movie movie;
259
260 switch(m_type)
261 {
262 case wxSound_MEMORY:
263 {
264 Handle myHandle, dataRef = nil;
265 MovieImportComponent miComponent;
266 Track targetTrack = nil;
267 TimeValue addedDuration = 0;
268 long outFlags = 0;
269 OSErr err;
270 ComponentResult result;
271
272 myHandle = NewHandleClear((Size)m_waveLength);
273
274 BlockMove(m_hSnd, *myHandle, m_waveLength);
275
276 err = PtrToHand(&myHandle, &dataRef, sizeof(Handle));
277
278 if (memcmp(&m_hSnd[8], "WAVE", 4) == 0)
279 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
280 else if (memcmp(&m_hSnd[8], "AIFF", 4) == 0)
281 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFF);
282 else if (memcmp(&m_hSnd[8], "AIFC", 4) == 0)
283 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFC);
284 else
285 {
286 wxLogSysError("wxSound - Location in memory does not contain valid data");
287 return false;
288 }
289
290 movie = NewMovie(0);
291
292 result = MovieImportDataRef(miComponent, dataRef,
293 HandleDataHandlerSubType, movie,
294 nil, &targetTrack,
295 nil, &addedDuration,
296 movieImportCreateTrack, &outFlags);
297
298 if (result != noErr)
299 {
300 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
301 }
302
303 SetMovieVolume(movie, kFullVolume);
304 GoToBeginningOfMovie(movie);
305 }
306 break;
307 case wxSound_RESOURCE:
308 {
309 SoundComponentData data;
310 unsigned long numframes, offset;
311
312 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
313 //m_waveLength = numFrames * data.numChannels;
314
315 SndChannelPtr pSndChannel;
316 SndNewChannel(&pSndChannel, sampledSynth,
317 initNoInterp +
318 (data.numChannels == 1 ? initMono : initStereo), NULL);
319
320 if(SndPlay(pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr)
321 return false;
322
323 if (flags & wxSOUND_ASYNC)
324 {
325 ((wxSMTimer*&)m_pTimer) = new wxSMTimer(pSndChannel, m_hSnd, flags & wxSOUND_LOOP ? 1 : 0);
326
327 ((wxTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
328 }
329 else
330 SndDisposeChannel(pSndChannel, TRUE);
331
332 return true;
333 }
334 break;
335 case wxSound_FILE:
336 {
337 short movieResFile;
338 FSSpec sfFile;
339
340 #ifdef __WXMAC__
341 wxMacFilename2FSSpec( m_sndname , &sfFile ) ;
342 #else
343 int nError;
344 if ((nError = NativePathNameToFSSpec ((char*) m_sndname.c_str(), &sfFile, 0)) != noErr)
345 {
346 wxLogSysError(wxString::Format(wxT("File:%s does not exist\nError:%i"),
347 m_sndname.c_str(), nError));
348 return false;
349 }
350 #endif
351
352 if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
353 {
354 wxLogSysError(wxT("Quicktime couldn't open the file"));
355 return false;
356 }
357
358
359 short movieResID = 0;
360 Str255 movieName;
361 OSErr err;
362
363 err = NewMovieFromFile (
364 &movie,
365 movieResFile,
366 &movieResID,
367 movieName,
368 newMovieActive,
369 NULL); //wasChanged
370
371 CloseMovieFile (movieResFile);
372
373 if (err != noErr)
374 {
375 wxLogSysError(
376 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err )
377 );
378 return false;
379 }
380 }
381 break;
382 default:
383 return false;
384 }//end switch(m_type)
385
386
387 //Start the movie!
388 StartMovie(movie);
389
390 if (flags & wxSOUND_SYNC)
391 {
392 wxASSERT_MSG(!(flags & wxSOUND_LOOP), "Can't loop and play syncronously at the same time");
393
394 //Play movie until it ends, then exit
395 while (!IsMovieDone(movie))
396 MoviesTask(movie, 0);
397
398 DisposeMovie(movie);
399 }
400 else
401 {
402 //Start timer and play movie asyncronously
403 ((wxQTTimer*&)m_pTimer) = new wxQTTimer(movie, flags & wxSOUND_LOOP ? 1 : 0);
404 ((wxQTTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
405 }
406
407 return true;
408 }
409
410 void* wxSound::GetHandle()
411 {
412 return (void*) ((wxQTTimer*) m_pTimer)->GetMovie();
413 }
414
415 bool wxSound::FreeData()
416 {
417 if (m_pTimer != NULL)
418 {
419 delete (wxQTTimer*) m_pTimer;
420 m_pTimer = NULL;
421 }
422
423 //Note that ExitMovies() is not neccessary, but
424 //the docs are fuzzy on whether or not TerminateQTML is
425 ExitMovies();
426
427 #ifndef __WXMAC__
428 TerminateQTML();
429 #endif
430 return true;
431 }
432 #endif //wxUSE_SOUND