1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/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/mac/uma.h" 
  55 #if defined __WXMAC__ && defined __DARWIN__/*TARGET_CARBON*/ 
  57 #include <Carbon/Carbon.h> 
  65 //quicktime media layer only required for mac emulation on pc 
  71 #include <QuickTimeComponents.h> 
  73 #include <QuickTime/QuickTimeComponents.h> 
  76 //Time between timer calls 
  77 #define MOVIE_DELAY 100 
  79 static wxTimer
* lastSoundTimer
=NULL
; 
  80 static bool lastSoundIsPlaying
=false; 
  82 // ------------------------------------------------------------------ 
  83 //          wxQTTimer - Handle Asyncronous Playing 
  84 // ------------------------------------------------------------------ 
  85 class wxQTTimer 
: public wxTimer
 
  88     wxQTTimer(Movie movie
, bool bLoop
, bool* playing
) : 
  89         m_movie(movie
), m_bLoop(bLoop
), m_pbPlaying(playing
) 
  99         DisposeMovie(m_movie
); 
 102         //Note that ExitMovies() is not necessary, but 
 103         //the docs are fuzzy on whether or not TerminateQTML is 
 118         if (m_pbPlaying 
&& !*m_pbPlaying
) 
 123         if(IsMovieDone(m_movie
)) 
 130                 GoToBeginningOfMovie(m_movie
); 
 135             MoviesTask(m_movie
, MOVIE_DELAY
); //Give QT time to play movie 
 139     Movie
& GetMovie() {return m_movie
;} 
 151 class wxSMTimer 
: public wxTimer
 
 154     wxSMTimer(void* hSnd
, void* pSndChannel
, bool bLoop
, bool* playing
) 
 155         : m_hSnd(hSnd
), m_pSndChannel(pSndChannel
), m_bLoop(bLoop
), m_pbPlaying(playing
) 
 162             *m_pbPlaying 
= false; 
 163         SndDisposeChannel((SndChannelPtr
)m_pSndChannel
, TRUE
); 
 169         if (m_pbPlaying 
&& !*m_pbPlaying
) 
 176         if (SndChannelStatus((SndChannelPtr
)m_pSndChannel
, sizeof(SCStatus
), &stat
) != 0) 
 179         //if the sound isn't playing anymore, see if it's looped, 
 180         //and if so play it again, otherwise close things up 
 181         if (stat
.scChannelBusy 
== FALSE
) 
 185                 if(SndPlay((SndChannelPtr
)m_pSndChannel
, (SndListHandle
) m_hSnd
, true) != noErr
) 
 198     void* GetChannel() {return m_pSndChannel
;} 
 209 // ------------------------------------------------------------------ 
 211 // ------------------------------------------------------------------ 
 213 //Determines whether version 4 of QT is installed 
 214 Boolean 
wxIsQuickTime4Installed (void) 
 220     error 
= Gestalt (gestaltQuickTime
, &result
); 
 221     return (error 
== noErr
) && (((result 
>> 16) & 0xffff) >= 0x0400); 
 227 inline bool wxInitQT () 
 229     if (wxIsQuickTime4Installed()) 
 234             if ((nError 
= InitializeQTML(0)) != noErr
) 
 235                 wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
)); 
 242         wxLogSysError(wxT("Quicktime is not installed, or Your Version of Quicktime is <= 4.")); 
 248 : m_hSnd(NULL
), m_waveLength(0), m_pTimer(NULL
), m_type(wxSound_NONE
) 
 252 wxSound::wxSound(const wxString
& sFileName
, bool isResource
) 
 253 : m_hSnd(NULL
), m_waveLength(0), m_pTimer(NULL
), m_type(wxSound_NONE
) 
 255     Create(sFileName
, isResource
); 
 258 wxSound::wxSound(int size
, const wxByte
* data
) 
 259 : m_hSnd((char*)data
), m_waveLength(size
), m_pTimer(NULL
), m_type(wxSound_MEMORY
) 
 267 bool wxSound::Create(const wxString
& fileName
, bool isResource
) 
 274         m_type 
= wxSound_RESOURCE
; 
 278         wxMacStringToPascal( fileName 
, lpSnd 
) ; 
 280         m_sndname 
= fileName
; 
 281         m_hSnd 
= (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd
); 
 288         m_type 
= wxSound_FILE
; 
 289         m_sndname 
= fileName
; 
 295 bool wxSound::DoPlay(unsigned flags
) const 
 307             Handle myHandle
, dataRef 
= nil
; 
 308             MovieImportComponent miComponent
; 
 309             Track targetTrack 
= nil
; 
 310             TimeValue addedDuration 
= 0; 
 313             ComponentResult result
; 
 315             myHandle 
= NewHandleClear((Size
)m_waveLength
); 
 317             BlockMove(m_hSnd
, *myHandle
, m_waveLength
); 
 319             err 
= PtrToHand(&myHandle
, &dataRef
, sizeof(Handle
)); 
 321             if (memcmp(&m_hSnd
[8], "WAVE", 4) == 0) 
 322                 miComponent 
= OpenDefaultComponent(MovieImportType
, kQTFileTypeWave
); 
 323             else if (memcmp(&m_hSnd
[8], "AIFF", 4) == 0) 
 324                 miComponent 
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFF
); 
 325             else if (memcmp(&m_hSnd
[8], "AIFC", 4) == 0) 
 326                 miComponent 
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFC
); 
 329                 wxLogSysError(wxT("wxSound - Location in memory does not contain valid data")); 
 335             result 
= MovieImportDataRef(miComponent
,                dataRef
, 
 336                                         HandleDataHandlerSubType
,   movie
, 
 339                                         movieImportCreateTrack
,     &outFlags
); 
 343                 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result
)); 
 346             SetMovieVolume(movie
, kFullVolume
); 
 347             GoToBeginningOfMovie(movie
); 
 349             DisposeHandle(myHandle
); 
 352     case wxSound_RESOURCE
: 
 354             SoundComponentData data
; 
 355             unsigned long numframes
, offset
; 
 357             ParseSndHeader((SndListHandle
)m_hSnd
, &data
, &numframes
, &offset
); 
 358             //m_waveLength = numFrames * data.numChannels; 
 360             SndChannelPtr pSndChannel
; 
 361             SndNewChannel(&pSndChannel
, sampledSynth
, 
 363                 + (data
.numChannels 
== 1 ? initMono 
: initStereo
), NULL
); 
 365             if(SndPlay(pSndChannel
, (SndListHandle
) m_hSnd
, flags 
& wxSOUND_ASYNC 
? 1 : 0) != noErr
) 
 368             if (flags 
& wxSOUND_ASYNC
) 
 370                 lastSoundTimer 
= ((wxSMTimer
*&)m_pTimer
) 
 371                     = new wxSMTimer(pSndChannel
, m_hSnd
, flags 
& wxSOUND_LOOP 
? 1 : 0, 
 372                                     &lastSoundIsPlaying
); 
 373                 lastSoundIsPlaying 
= true; 
 375                 ((wxTimer
*)m_pTimer
)->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
); 
 378                 SndDisposeChannel(pSndChannel
, TRUE
); 
 390             Handle dataRef 
= NULL
; 
 393             err 
= QTNewDataReferenceFromFullPathCFString(wxMacCFStringHolder(m_sndname
,wxLocale::GetSystemEncoding()), 
 394                 (UInt32
)kQTNativeDefaultPathStyle
, 0, &dataRef
, &dataRefType
); 
 396             wxASSERT(err 
== noErr
); 
 398             if (NULL 
!= dataRef 
|| err 
!= noErr
) 
 400                 err 
= NewMovieFromDataRef( &movie
, newMovieDontAskUnresolvedDataRefs 
, NULL
, dataRef
, dataRefType 
); 
 401                 wxASSERT(err 
== noErr
); 
 402                 DisposeHandle(dataRef
); 
 408                     wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname
.c_str(), err 
) 
 416     }//end switch(m_type) 
 421     if (flags 
& wxSOUND_ASYNC
) 
 423         //Start timer and play movie asyncronously 
 424         lastSoundTimer 
= ((wxQTTimer
*&)m_pTimer
) = 
 425             new wxQTTimer(movie
, flags 
& wxSOUND_LOOP 
? 1 : 0, 
 426                           &lastSoundIsPlaying
); 
 427         lastSoundIsPlaying 
= true; 
 428         ((wxQTTimer
*)m_pTimer
)->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
); 
 432         wxASSERT_MSG(!(flags 
& wxSOUND_LOOP
), wxT("Can't loop and play syncronously at the same time")); 
 434         //Play movie until it ends, then exit 
 435         //Note that due to quicktime caching this may not always 
 436         //work 100% correctly 
 437         while (!IsMovieDone(movie
)) 
 438             MoviesTask(movie
, 1); 
 446 bool wxSound::IsPlaying() 
 448     return lastSoundIsPlaying
; 
 453     if (lastSoundIsPlaying
) 
 455         delete (wxTimer
*&) lastSoundTimer
; 
 456         lastSoundIsPlaying 
= false; 
 457         lastSoundTimer 
= NULL
; 
 461 void* wxSound::GetHandle() 
 463     if(m_type 
== wxSound_RESOURCE
) 
 464         return (void*)  ((wxSMTimer
*)m_pTimer
)->GetChannel(); 
 466     return (void*) ((wxQTTimer
*) m_pTimer
)->GetMovie();