1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxSound class implementation: optional
4 // Author: Ryan Norton, Stefan Csomor
8 // Copyright: (c) Ryan Norton, Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "sound.h"
16 #include "wx/object.h"
17 #include "wx/string.h"
25 // Carbon QT Implementation Details -
28 // 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
30 // 3) MovieImportDataRef() //Pass Memory Location to this
32 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
36 // 2) Call OpenMovieFile
37 // 3) Call NewMovieFromFile
38 // 4) Call CloseMovieFile
40 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
44 #include "wx/mac/private.h"
49 #if defined __WXMAC__ && defined __DARWIN__/*TARGET_CARBON*/
51 #include <Carbon/Carbon.h>
59 //quicktime media layer only required for mac emulation on pc
64 #include <QuickTimeComponents.h>
66 //Time inbetween timer calls
67 #define MOVIE_DELAY 100
69 // ------------------------------------------------------------------
70 // wxQTTimer - Handle Asyncronous Playing
71 // ------------------------------------------------------------------
72 class wxQTTimer
: public wxTimer
75 wxQTTimer(Movie movie
, bool bLoop
) :
76 m_movie(movie
), m_bLoop(bLoop
)
88 DisposeMovie(m_movie
);
92 //Note that ExitMovies() is not neccessary, but
93 //the docs are fuzzy on whether or not TerminateQTML is
103 if(IsMovieDone(m_movie
))
110 GoToBeginningOfMovie(m_movie
);
115 MoviesTask(m_movie
, MOVIE_DELAY
); //Give QT time to play movie
119 Movie
& GetMovie() {return m_movie
;}
126 class wxSMTimer
: public wxTimer
129 wxSMTimer(void* hSnd
, void* pSndChannel
, const bool& bLoop
)
130 : m_hSnd(hSnd
), m_pSndChannel(pSndChannel
), m_bLoop(bLoop
)
143 if (SndChannelStatus((SndChannelPtr
)m_pSndChannel
, sizeof(SCStatus
), &stat
) != 0)
146 //if the sound isn't playing anymore, see if it's looped,
147 //and if so play it again, otherwise close things up
148 if (stat
.scChannelBusy
== FALSE
)
152 if(SndPlay((SndChannelPtr
)m_pSndChannel
, (SndListHandle
) m_hSnd
, true) != noErr
)
162 SndDisposeChannel((SndChannelPtr
)m_pSndChannel
, TRUE
);
172 // ------------------------------------------------------------------
174 // ------------------------------------------------------------------
176 //Determines whether version 4 of QT is installed
177 Boolean
wxIsQuickTime4Installed (void)
183 error
= Gestalt (gestaltQuickTime
, &result
);
184 return (error
== noErr
) && (((result
>> 16) & 0xffff) >= 0x0400);
190 inline bool wxInitQT ()
192 if (wxIsQuickTime4Installed())
197 if ((nError
= InitializeQTML(0)) != noErr
)
198 wxLogSysError(wxString::Format("Couldn't Initialize Quicktime-%i", nError
));
205 wxLogSysError("Quicktime is not installed, or Your Version of Quicktime is <= 4.");
211 : m_hSnd(NULL
), m_waveLength(0), m_pTimer(NULL
), m_type(wxSound_NONE
)
215 wxSound::wxSound(const wxString
& sFileName
, bool isResource
)
216 : m_hSnd(NULL
), m_waveLength(0), m_pTimer(NULL
), m_type(wxSound_NONE
)
218 Create(sFileName
, isResource
);
221 wxSound::wxSound(int size
, const wxByte
* data
)
222 : m_hSnd((char*)data
), m_waveLength(size
), m_pTimer(NULL
), m_type(wxSound_MEMORY
)
225 m_type
= wxSound_NONE
;
232 bool wxSound::Create(const wxString
& fileName
, bool isResource
)
240 m_type
= wxSound_RESOURCE
;
244 wxMacStringToPascal( fileName
, lpSnd
) ;
247 m_hSnd
= (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd
);
254 m_type
= wxSound_FILE
;
255 m_sndname
= fileName
;
261 bool wxSound::DoPlay(unsigned flags
) const
263 wxASSERT(m_pTimer
== NULL
|| !((wxTimer
*)m_pTimer
)->IsRunning() );
271 Handle myHandle
, dataRef
= nil
;
272 MovieImportComponent miComponent
;
273 Track targetTrack
= nil
;
274 TimeValue addedDuration
= 0;
277 ComponentResult result
;
279 myHandle
= NewHandleClear((Size
)m_waveLength
);
281 BlockMove(m_hSnd
, *myHandle
, m_waveLength
);
283 err
= PtrToHand(&myHandle
, &dataRef
, sizeof(Handle
));
285 if (memcmp(&m_hSnd
[8], "WAVE", 4) == 0)
286 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeWave
);
287 else if (memcmp(&m_hSnd
[8], "AIFF", 4) == 0)
288 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFF
);
289 else if (memcmp(&m_hSnd
[8], "AIFC", 4) == 0)
290 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFC
);
293 wxLogSysError("wxSound - Location in memory does not contain valid data");
299 result
= MovieImportDataRef(miComponent
, dataRef
,
300 HandleDataHandlerSubType
, movie
,
303 movieImportCreateTrack
, &outFlags
);
307 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result
));
310 SetMovieVolume(movie
, kFullVolume
);
311 GoToBeginningOfMovie(movie
);
313 DisposeHandle(myHandle
);
316 case wxSound_RESOURCE
:
318 SoundComponentData data
;
319 unsigned long numframes
, offset
;
321 ParseSndHeader((SndListHandle
)m_hSnd
, &data
, &numframes
, &offset
);
322 //m_waveLength = numFrames * data.numChannels;
324 SndChannelPtr pSndChannel
;
325 SndNewChannel(&pSndChannel
, sampledSynth
,
327 (data
.numChannels
== 1 ? initMono
: initStereo
), NULL
);
329 if(SndPlay(pSndChannel
, (SndListHandle
) m_hSnd
, flags
& wxSOUND_ASYNC
? 1 : 0) != noErr
)
332 if (flags
& wxSOUND_ASYNC
)
334 ((wxSMTimer
*&)m_pTimer
) = new wxSMTimer(pSndChannel
, m_hSnd
, flags
& wxSOUND_LOOP
? 1 : 0);
336 ((wxTimer
*)m_pTimer
)->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
339 SndDisposeChannel(pSndChannel
, TRUE
);
350 wxMacFilename2FSSpec( m_sndname
, &sfFile
) ;
353 if ((nError
= NativePathNameToFSSpec ((char*) m_sndname
.c_str(), &sfFile
, 0)) != noErr
)
355 wxLogSysError(wxString::Format(wxT("File:%s does not exist\nError:%i"),
356 m_sndname
.c_str(), nError
));
361 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
363 wxLogSysError(wxT("Quicktime couldn't open the file"));
368 short movieResID
= 0;
372 err
= NewMovieFromFile (
380 CloseMovieFile (movieResFile
);
385 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname
.c_str(), err
)
393 }//end switch(m_type)
399 if (flags
& wxSOUND_ASYNC
)
401 //Start timer and play movie asyncronously
402 ((wxQTTimer
*&)m_pTimer
) = new wxQTTimer(movie
, flags
& wxSOUND_LOOP
? 1 : 0);
403 ((wxQTTimer
*)m_pTimer
)->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
407 wxASSERT_MSG(!(flags
& wxSOUND_LOOP
), "Can't loop and play syncronously at the same time");
409 //Play movie until it ends, then exit
410 while (!IsMovieDone(movie
))
411 MoviesTask(movie
, 0);
419 void* wxSound::GetHandle()
421 return (void*) ((wxQTTimer
*) m_pTimer
)->GetMovie();
424 bool wxSound::FreeData()
426 if (m_pTimer
!= NULL
)
428 delete (wxQTTimer
*) m_pTimer
;