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