]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/sound.cpp
undoing last change, widgets sample had slider label offset
[wxWidgets.git] / src / mac / carbon / sound.cpp
CommitLineData
e9576ca5 1/////////////////////////////////////////////////////////////////////////////
315ebf68
VS
2// Name: sound.cpp
3// Purpose: wxSound class implementation: optional
4b430ee1 4// Author: Ryan Norton
e9576ca5 5// Modified by:
a31a5f85 6// Created: 1998-01-01
e9576ca5 7// RCS-ID: $Id$
625d14ab 8// Copyright: (c) Ryan Norton, Stefan Csomor
65571936 9// Licence: wxWindows licence
e9576ca5
SC
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
315ebf68 13#pragma implementation "sound.h"
e9576ca5
SC
14#endif
15
16#include "wx/object.h"
17#include "wx/string.h"
625d14ab
SC
18#include "wx/log.h"
19#include "wx/file.h"
315ebf68 20#include "wx/sound.h"
625d14ab 21#include "wx/timer.h"
e9576ca5 22
315ebf68 23#if wxUSE_SOUND
4a69b060 24
625d14ab
SC
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
76a5e5d2
SC
43#ifdef __WXMAC__
44#include "wx/mac/private.h"
625d14ab
SC
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>
66a09d47 54#endif
625d14ab
SC
55#else
56#include <Sound.h>
76a5e5d2
SC
57#endif
58
625d14ab
SC
59//quicktime media layer only required for mac emulation on pc
60#ifndef __WXMAC__
61#include <qtml.h>
62#endif
e9576ca5 63
625d14ab 64#include <QuickTimeComponents.h>
e9576ca5 65
625d14ab
SC
66//Time inbetween timer calls
67#define MOVIE_DELAY 100
e9576ca5 68
625d14ab
SC
69// ------------------------------------------------------------------
70// wxQTTimer - Handle Asyncronous Playing
71// ------------------------------------------------------------------
72class wxQTTimer : public wxTimer
e9576ca5 73{
625d14ab 74public:
4b430ee1
DS
75 wxQTTimer(Movie movie, bool bLoop, bool& playing) :
76 m_movie(movie), m_bLoop(bLoop), m_pbPlaying(&playing)
625d14ab
SC
77 {
78 }
e9576ca5 79
625d14ab
SC
80 ~wxQTTimer()
81 {
4b430ee1
DS
82 if(m_pbPlaying)
83 *m_pbPlaying = false;
5b781a67 84
625d14ab
SC
85 StopMovie(m_movie);
86 DisposeMovie(m_movie);
625d14ab 87 Stop();
9e783cc0
RD
88
89 //Note that ExitMovies() is not neccessary, but
90 //the docs are fuzzy on whether or not TerminateQTML is
91 ExitMovies();
92
4b430ee1 93#ifndef __WXMAC__
9e783cc0 94 TerminateQTML();
4b430ee1
DS
95#endif
96 }
97
98 void Shutdown()
99 {
100 delete this;
625d14ab 101 }
e40298d5 102
625d14ab
SC
103 void Notify()
104 {
4b430ee1
DS
105 if (m_pbPlaying && !*m_pbPlaying)
106 {
107 Shutdown();
108 }
109
625d14ab
SC
110 if(IsMovieDone(m_movie))
111 {
112 if (!m_bLoop)
113 Shutdown();
114 else
115 {
116 StopMovie(m_movie);
4b430ee1 117 GoToBeginningOfMovie(m_movie);
625d14ab 118 StartMovie(m_movie);
4b430ee1 119 }
625d14ab
SC
120 }
121 else
122 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
123 }
e40298d5 124
e40298d5 125
625d14ab 126 Movie& GetMovie() {return m_movie;}
4b430ee1 127
625d14ab
SC
128protected:
129 Movie m_movie;
130 bool m_bLoop;
4b430ee1
DS
131
132public:
133 bool* m_pbPlaying;
134
625d14ab 135};
e40298d5 136
e40298d5 137
625d14ab
SC
138class wxSMTimer : public wxTimer
139{
140public:
4b430ee1
DS
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 }
e40298d5 145
625d14ab 146 ~wxSMTimer()
4b430ee1
DS
147 {
148 if(m_pbPlaying)
149 *m_pbPlaying = false;
150 SndDisposeChannel((SndChannelPtr)m_pSndChannel, TRUE);
151 Stop();
152 }
e40298d5 153
625d14ab 154 void Notify()
4b430ee1
DS
155 {
156 if (m_pbPlaying && !*m_pbPlaying)
e40298d5 157 {
4b430ee1
DS
158 Shutdown();
159 }
160
161 SCStatus stat;
625d14ab
SC
162
163 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
4b430ee1
DS
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();
e40298d5 177 }
625d14ab 178 }
e40298d5 179
625d14ab
SC
180 void Shutdown()
181 {
4b430ee1 182 delete this;
625d14ab 183 }
4b430ee1
DS
184
185 void* GetChannel() {return m_pSndChannel;}
186
625d14ab
SC
187protected:
188 void* m_hSnd;
189 void* m_pSndChannel;
190 bool m_bLoop;
4b430ee1
DS
191
192public:
193 bool* m_pbPlaying;
625d14ab
SC
194};
195
196// ------------------------------------------------------------------
197// wxSound
198// ------------------------------------------------------------------
4b430ee1
DS
199wxTimer* lastSoundTimer=NULL;
200bool lastSoundIsPlaying=false;
625d14ab
SC
201
202//Determines whether version 4 of QT is installed
203Boolean wxIsQuickTime4Installed (void)
204{
205#ifdef __WXMAC__
206 short error;
207 long result;
e40298d5 208
625d14ab 209 error = Gestalt (gestaltQuickTime, &result);
9e783cc0 210 return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
625d14ab
SC
211#else
212 return true;
213#endif
214}
e40298d5 215
625d14ab
SC
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));
4b430ee1 225 #endif
625d14ab
SC
226 EnterMovies();
227 return true;
228 }
229 else
4b430ee1 230 {
625d14ab 231 wxLogSysError("Quicktime is not installed, or Your Version of Quicktime is <= 4.");
4b430ee1
DS
232 return false;
233 }
625d14ab 234}
e40298d5 235
625d14ab
SC
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{
625d14ab
SC
250}
251
252wxSound::~wxSound()
253{
4b430ee1
DS
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 }
625d14ab
SC
261}
262
263bool wxSound::Create(const wxString& fileName, bool isResource)
264{
4b430ee1 265 Stop();
2116a0d1 266
625d14ab
SC
267 if (isResource)
268 {
269#ifdef __WXMAC__
270 m_type = wxSound_RESOURCE;
271
272 Str255 lpSnd ;
273
274 wxMacStringToPascal( fileName , lpSnd ) ;
275
4b430ee1 276 m_sndname = lpSnd;
625d14ab
SC
277 m_hSnd = (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd);
278#else
279 return false;
280#endif
4b430ee1
DS
281 }
282 else
283 {
625d14ab
SC
284 m_type = wxSound_FILE;
285 m_sndname = fileName;
e40298d5
JS
286 }
287
625d14ab 288 return true;
e9576ca5
SC
289}
290
315ebf68 291bool wxSound::DoPlay(unsigned flags) const
e9576ca5 292{
4b430ee1 293 Stop();
4a69b060 294
625d14ab
SC
295 Movie movie;
296
297 switch(m_type)
298 {
299 case wxSound_MEMORY:
300 {
4b430ee1
DS
301 if (!wxInitQT())
302 return false;
625d14ab 303 Handle myHandle, dataRef = nil;
4b430ee1 304 MovieImportComponent miComponent;
625d14ab
SC
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);
4b430ee1 312
625d14ab
SC
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
4b430ee1 324 {
625d14ab
SC
325 wxLogSysError("wxSound - Location in memory does not contain valid data");
326 return false;
327 }
328
329 movie = NewMovie(0);
4a69b060 330
625d14ab
SC
331 result = MovieImportDataRef(miComponent, dataRef,
332 HandleDataHandlerSubType, movie,
333 nil, &targetTrack,
334 nil, &addedDuration,
335 movieImportCreateTrack, &outFlags);
e9576ca5 336
625d14ab
SC
337 if (result != noErr)
338 {
339 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
4b430ee1 340 }
4a69b060 341
625d14ab
SC
342 SetMovieVolume(movie, kFullVolume);
343 GoToBeginningOfMovie(movie);
9e783cc0
RD
344
345 DisposeHandle(myHandle);
625d14ab
SC
346 }
347 break;
348 case wxSound_RESOURCE:
349 {
350 SoundComponentData data;
351 unsigned long numframes, offset;
e9576ca5 352
625d14ab
SC
353 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
354 //m_waveLength = numFrames * data.numChannels;
5b781a67 355
625d14ab
SC
356 SndChannelPtr pSndChannel;
357 SndNewChannel(&pSndChannel, sampledSynth,
4b430ee1
DS
358 initNoInterp
359 + (data.numChannels == 1 ? initMono : initStereo), NULL);
e40298d5 360
625d14ab 361 if(SndPlay(pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr)
4b430ee1 362 return false;
625d14ab
SC
363
364 if (flags & wxSOUND_ASYNC)
4b430ee1
DS
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
625d14ab
SC
373 SndDisposeChannel(pSndChannel, TRUE);
374
375 return true;
376 }
377 break;
378 case wxSound_FILE:
379 {
4b430ee1
DS
380 if (!wxInitQT())
381 return false;
382
625d14ab
SC
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)
4b430ee1
DS
391 {
392 wxLogSysError(wxString::Format(wxT("File:%s does not exist\nError:%i"),
625d14ab
SC
393 m_sndname.c_str(), nError));
394 return false;
4b430ee1 395 }
625d14ab 396#endif
e40298d5 397
625d14ab
SC
398 if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
399 {
400 wxLogSysError(wxT("Quicktime couldn't open the file"));
401 return false;
402 }
e9576ca5
SC
403
404
625d14ab
SC
405 short movieResID = 0;
406 Str255 movieName;
407 OSErr err;
5b781a67 408
625d14ab
SC
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)
4b430ee1 420 {
625d14ab
SC
421 wxLogSysError(
422 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err )
423 );
424 return false;
4b430ee1 425 }
625d14ab
SC
426 }
427 break;
428 default:
429 return false;
430 }//end switch(m_type)
e40298d5 431
e40298d5 432
625d14ab
SC
433 //Start the movie!
434 StartMovie(movie);
e40298d5 435
4b430ee1 436 if (flags & wxSOUND_SYNC)
625d14ab
SC
437 {
438 wxASSERT_MSG(!(flags & wxSOUND_LOOP), "Can't loop and play syncronously at the same time");
e40298d5 439
625d14ab
SC
440 //Play movie until it ends, then exit
441 while (!IsMovieDone(movie))
442 MoviesTask(movie, 0);
e40298d5 443
625d14ab
SC
444 DisposeMovie(movie);
445 }
4b430ee1
DS
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 }
625d14ab
SC
452
453 return true;
5b781a67
SC
454}
455
4b430ee1 456bool wxSound::IsPlaying()
625d14ab 457{
4b430ee1 458 return lastSoundIsPlaying;
625d14ab 459}
5b781a67 460
4b430ee1 461void wxSound::Stop()
5b781a67 462{
4b430ee1 463 if(lastSoundIsPlaying)
e40298d5 464 {
4b430ee1
DS
465 delete (wxTimer*&) lastSoundTimer;
466 lastSoundIsPlaying = false;
e40298d5 467 }
625d14ab 468}
9e783cc0 469
4b430ee1
DS
470void* wxSound::GetHandle()
471{
472 if(m_type == wxSound_RESOURCE)
473 return (void*) ((wxSMTimer*)m_pTimer)->GetChannel();
9e783cc0 474
4b430ee1
DS
475 return (void*) ((wxQTTimer*) m_pTimer)->GetMovie();
476}
9e783cc0 477
4b430ee1 478#endif //wxUSE_SOUND