1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/sound.cpp
3 // Purpose: wxSound class implementation: optional
5 // Modified by: Stefan Csomor
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
20 #include "wx/object.h"
21 #include "wx/string.h"
29 // Carbon QT Implementation Details -
32 // 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
34 // 3) MovieImportDataRef() //Pass Memory Location to this
36 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
39 // 1) Path as CFString
40 // 2) Call QTNewDataReferenceFromFullPathCFString
41 // 3) Call NewMovieFromDataRef
42 // 4) Call CloseMovieFile
44 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
48 #include "wx/osx/uma.h"
56 #include "wx/osx/private.h"
59 #include <Carbon/Carbon.h>
61 //quicktime media layer only required for mac emulation on pc
67 #include <QuickTimeComponents.h>
69 #include <QuickTime/QuickTimeComponents.h>
72 //Time between timer calls
73 #define MOVIE_DELAY 100
75 static wxTimer
* lastSoundTimer
=NULL
;
76 static bool lastSoundIsPlaying
=false;
78 #if !defined(__LP64__)
79 #define USE_QUICKTIME 1
81 #define USE_QUICKTIME 0
85 // ------------------------------------------------------------------
86 // wxQTTimer - Handle Asyncronous Playing
87 // ------------------------------------------------------------------
88 class wxQTTimer
: public wxTimer
91 wxQTTimer(Movie movie
, bool bLoop
, bool* playing
) :
92 m_movie(movie
), m_bLoop(bLoop
), m_pbPlaying(playing
)
102 DisposeMovie(m_movie
);
105 //Note that ExitMovies() is not necessary, but
106 //the docs are fuzzy on whether or not TerminateQTML is
121 if (m_pbPlaying
&& !*m_pbPlaying
)
126 if(IsMovieDone(m_movie
))
133 GoToBeginningOfMovie(m_movie
);
138 MoviesTask(m_movie
, MOVIE_DELAY
); //Give QT time to play movie
142 Movie
& GetMovie() {return m_movie
;}
154 class wxSMTimer
: public wxTimer
157 wxSMTimer(void* hSnd
, void* pSndChannel
, bool bLoop
, bool* playing
)
158 : m_hSnd(hSnd
), m_pSndChannel(pSndChannel
), m_bLoop(bLoop
), m_pbPlaying(playing
)
165 *m_pbPlaying
= false;
166 SndDisposeChannel((SndChannelPtr
)m_pSndChannel
, TRUE
);
172 if (m_pbPlaying
&& !*m_pbPlaying
)
179 if (SndChannelStatus((SndChannelPtr
)m_pSndChannel
, sizeof(SCStatus
), &stat
) != 0)
182 //if the sound isn't playing anymore, see if it's looped,
183 //and if so play it again, otherwise close things up
184 if (stat
.scChannelBusy
== FALSE
)
188 if(SndPlay((SndChannelPtr
)m_pSndChannel
, (SndListHandle
) m_hSnd
, true) != noErr
)
201 void* GetChannel() {return m_pSndChannel
;}
212 // ------------------------------------------------------------------
214 // ------------------------------------------------------------------
216 //Determines whether version 4 of QT is installed
217 Boolean
wxIsQuickTime4Installed (void)
223 error
= Gestalt (gestaltQuickTime
, &result
);
224 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
230 inline bool wxInitQT ()
232 if (wxIsQuickTime4Installed())
237 if ((nError
= InitializeQTML(0)) != noErr
)
238 wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
));
245 wxLogSysError(wxT("Quicktime is not installed, or Your Version of Quicktime is <= 4."));
253 : m_hSnd(NULL
), m_waveLength(0), m_pTimer(NULL
), m_type(wxSound_NONE
)
257 wxSound::wxSound(const wxString
& sFileName
, bool isResource
)
258 : m_hSnd(NULL
), m_waveLength(0), m_pTimer(NULL
), m_type(wxSound_NONE
)
260 Create(sFileName
, isResource
);
263 wxSound::wxSound(int size
, const wxByte
* data
)
264 : m_hSnd((char*)data
), m_waveLength(size
), m_pTimer(NULL
), m_type(wxSound_MEMORY
)
272 bool wxSound::Create(const wxString
& fileName
, bool isResource
)
279 m_type
= wxSound_RESOURCE
;
283 wxMacStringToPascal( fileName
, lpSnd
) ;
285 m_sndname
= fileName
;
286 m_hSnd
= (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd
);
293 m_type
= wxSound_FILE
;
294 m_sndname
= fileName
;
300 bool wxSound::DoPlay(unsigned flags
) const
314 Handle myHandle
, dataRef
= nil
;
315 MovieImportComponent miComponent
;
316 Track targetTrack
= nil
;
317 TimeValue addedDuration
= 0;
320 ComponentResult result
;
322 myHandle
= NewHandleClear((Size
)m_waveLength
);
324 BlockMove(m_hSnd
, *myHandle
, m_waveLength
);
326 err
= PtrToHand(&myHandle
, &dataRef
, sizeof(Handle
));
328 if (memcmp(&m_hSnd
[8], "WAVE", 4) == 0)
329 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeWave
);
330 else if (memcmp(&m_hSnd
[8], "AIFF", 4) == 0)
331 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFF
);
332 else if (memcmp(&m_hSnd
[8], "AIFC", 4) == 0)
333 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFC
);
336 wxLogSysError(wxT("wxSound - Location in memory does not contain valid data"));
342 result
= MovieImportDataRef(miComponent
, dataRef
,
343 HandleDataHandlerSubType
, movie
,
346 movieImportCreateTrack
, &outFlags
);
350 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result
));
353 SetMovieVolume(movie
, kFullVolume
);
354 GoToBeginningOfMovie(movie
);
356 DisposeHandle(myHandle
);
359 case wxSound_RESOURCE
:
361 SoundComponentData data
;
362 unsigned long numframes
, offset
;
364 ParseSndHeader((SndListHandle
)m_hSnd
, &data
, &numframes
, &offset
);
365 //m_waveLength = numFrames * data.numChannels;
367 SndChannelPtr pSndChannel
;
368 SndNewChannel(&pSndChannel
, sampledSynth
,
370 + (data
.numChannels
== 1 ? initMono
: initStereo
), NULL
);
372 if(SndPlay(pSndChannel
, (SndListHandle
) m_hSnd
, flags
& wxSOUND_ASYNC
? 1 : 0) != noErr
)
375 if (flags
& wxSOUND_ASYNC
)
377 lastSoundTimer
= ((wxSMTimer
*&)m_pTimer
)
378 = new wxSMTimer(pSndChannel
, m_hSnd
, flags
& wxSOUND_LOOP
? 1 : 0,
379 &lastSoundIsPlaying
);
380 lastSoundIsPlaying
= true;
382 ((wxTimer
*)m_pTimer
)->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
385 SndDisposeChannel(pSndChannel
, TRUE
);
397 Handle dataRef
= NULL
;
400 err
= QTNewDataReferenceFromFullPathCFString(wxCFStringRef(m_sndname
,wxLocale::GetSystemEncoding()),
401 (UInt32
)kQTNativeDefaultPathStyle
, 0, &dataRef
, &dataRefType
);
403 wxASSERT(err
== noErr
);
405 if (NULL
!= dataRef
|| err
!= noErr
)
407 err
= NewMovieFromDataRef( &movie
, newMovieDontAskUnresolvedDataRefs
, NULL
, dataRef
, dataRefType
);
408 wxASSERT(err
== noErr
);
409 DisposeHandle(dataRef
);
415 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname
.c_str(), err
)
423 }//end switch(m_type)
428 if (flags
& wxSOUND_ASYNC
)
430 //Start timer and play movie asyncronously
431 lastSoundTimer
= ((wxQTTimer
*&)m_pTimer
) =
432 new wxQTTimer(movie
, flags
& wxSOUND_LOOP
? 1 : 0,
433 &lastSoundIsPlaying
);
434 lastSoundIsPlaying
= true;
435 ((wxQTTimer
*)m_pTimer
)->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
439 wxASSERT_MSG(!(flags
& wxSOUND_LOOP
), wxT("Can't loop and play syncronously at the same time"));
441 //Play movie until it ends, then exit
442 //Note that due to quicktime caching this may not always
443 //work 100% correctly
444 while (!IsMovieDone(movie
))
445 MoviesTask(movie
, 1);
454 bool wxSound::IsPlaying()
456 return lastSoundIsPlaying
;
461 if (lastSoundIsPlaying
)
463 delete (wxTimer
*&) lastSoundTimer
;
464 lastSoundIsPlaying
= false;
465 lastSoundTimer
= NULL
;
469 void* wxSound::GetHandle()
472 if(m_type
== wxSound_RESOURCE
)
473 return (void*) ((wxSMTimer
*)m_pTimer
)->GetChannel();
475 return (void*) ((wxQTTimer
*) m_pTimer
)->GetMovie();