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"
17 #if wxOSX_USE_QUICKTIME
22 #include "wx/object.h"
23 #include "wx/string.h"
31 // Carbon QT Implementation Details -
34 // 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
36 // 3) MovieImportDataRef() //Pass Memory Location to this
38 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
41 // 1) Path as CFString
42 // 2) Call QTNewDataReferenceFromFullPathCFString
43 // 3) Call NewMovieFromDataRef
44 // 4) Call CloseMovieFile
46 // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
50 #include "wx/osx/private.h"
51 #if wxOSX_USE_COCOA_OR_CARBON
52 #include <QuickTime/QuickTimeComponents.h>
58 #define MOVIE_DELAY 100
60 // ------------------------------------------------------------------
62 // ------------------------------------------------------------------
64 class wxOSXSoundManagerSoundData
: public wxSoundData
67 wxOSXSoundManagerSoundData(const wxString
& fileName
);
68 ~wxOSXSoundManagerSoundData();
70 virtual bool Play(unsigned flags
);
71 virtual void SoundTask();
76 SndChannelPtr m_pSndChannel
;
79 wxOSXSoundManagerSoundData::wxOSXSoundManagerSoundData(const wxString
& fileName
) :
84 wxMacStringToPascal( fileName
, lpSnd
) ;
86 m_hSnd
= (SndListHandle
) GetNamedResource('snd ', (const unsigned char *) lpSnd
);
89 wxOSXSoundManagerSoundData::~wxOSXSoundManagerSoundData()
92 ReleaseResource((Handle
)m_hSnd
);
95 void wxOSXSoundManagerSoundData::DoStop()
99 SndDisposeChannel(m_pSndChannel
, TRUE
/* stop immediately, not after playing */);
100 m_pSndChannel
= NULL
;
101 wxSound::SoundStopped(this);
104 if (IsMarkedForDeletion())
108 bool wxOSXSoundManagerSoundData::Play(unsigned flags
)
114 SoundComponentData data
;
115 unsigned long numframes
, offset
;
117 ParseSndHeader((SndListHandle
)m_hSnd
, &data
, &numframes
, &offset
);
119 SndNewChannel(&m_pSndChannel
, sampledSynth
,
121 + (data
.numChannels
== 1 ? initMono
: initStereo
), NULL
);
123 if(SndPlay(m_pSndChannel
, (SndListHandle
) m_hSnd
, flags
& wxSOUND_ASYNC
? 1 : 0) != noErr
)
126 if (flags
& wxSOUND_ASYNC
)
127 CreateAndStartTimer();
134 void wxOSXSoundManagerSoundData::SoundTask()
138 if (SndChannelStatus((SndChannelPtr
)m_pSndChannel
, sizeof(SCStatus
), &stat
) != 0)
141 //if the sound isn't playing anymore, see if it's looped,
142 //and if so play it again, otherwise close things up
143 if (stat
.scChannelBusy
== FALSE
)
145 if (m_flags
& wxSOUND_LOOP
)
147 if(SndPlay((SndChannelPtr
)m_pSndChannel
, (SndListHandle
) m_hSnd
, true) != noErr
)
155 // ------------------------------------------------------------------
157 // ------------------------------------------------------------------
165 if ((nError
= InitializeQTML(0)) != noErr
)
167 wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
));
178 //Note that ExitMovies() is not necessary, but
179 //the docs are fuzzy on whether or not TerminateQTML is
187 class wxOSXQuickTimeSoundData
: public wxSoundData
190 wxOSXQuickTimeSoundData(const wxString
& fileName
);
191 wxOSXQuickTimeSoundData(int size
, const wxByte
* data
);
192 ~wxOSXQuickTimeSoundData();
194 virtual bool Play(unsigned flags
);
195 virtual void SoundTask();
196 virtual void DoStop();
200 wxString m_sndname
; //file path
201 Handle m_soundHandle
;
205 wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(const wxString
& fileName
) :
206 m_movie(NULL
), m_soundHandle(NULL
)
208 m_sndname
= fileName
;
211 wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(int size
, const wxByte
* data
) :
214 m_soundHandle
= NewHandleClear((Size
)size
);
215 BlockMove(data
, *m_soundHandle
, size
);
218 wxOSXQuickTimeSoundData::~wxOSXQuickTimeSoundData()
221 DisposeHandle(m_soundHandle
);
224 bool wxOSXQuickTimeSoundData::Play(unsigned flags
)
236 Handle dataRef
= nil
;
237 MovieImportComponent miComponent
;
238 Track targetTrack
= nil
;
239 TimeValue addedDuration
= 0;
242 ComponentResult result
;
244 err
= PtrToHand(&m_soundHandle
, &dataRef
, sizeof(Handle
));
246 HLock(m_soundHandle
);
247 if (memcmp(&(*m_soundHandle
)[8], "WAVE", 4) == 0)
248 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeWave
);
249 else if (memcmp(&(*m_soundHandle
)[8], "AIFF", 4) == 0)
250 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFF
);
251 else if (memcmp(&(*m_soundHandle
)[8], "AIFC", 4) == 0)
252 miComponent
= OpenDefaultComponent(MovieImportType
, kQTFileTypeAIFC
);
255 HUnlock(m_soundHandle
);
256 wxLogSysError(wxT("wxSound - Location in memory does not contain valid data"));
260 HUnlock(m_soundHandle
);
261 m_movie
= NewMovie(0);
263 result
= MovieImportDataRef(miComponent
, dataRef
,
264 HandleDataHandlerSubType
, m_movie
,
267 movieImportCreateTrack
, &outFlags
);
271 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result
));
274 SetMovieVolume(m_movie
, kFullVolume
);
275 GoToBeginningOfMovie(m_movie
);
281 Handle dataRef
= NULL
;
284 err
= QTNewDataReferenceFromFullPathCFString(wxCFStringRef(m_sndname
,wxLocale::GetSystemEncoding()),
285 (UInt32
)kQTNativeDefaultPathStyle
, 0, &dataRef
, &dataRefType
);
287 wxASSERT(err
== noErr
);
289 if (NULL
!= dataRef
|| err
!= noErr
)
291 err
= NewMovieFromDataRef( &m_movie
, newMovieDontAskUnresolvedDataRefs
, NULL
, dataRef
, dataRefType
);
292 wxASSERT(err
== noErr
);
293 DisposeHandle(dataRef
);
299 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname
.c_str(), err
)
308 if (flags
& wxSOUND_ASYNC
)
310 CreateAndStartTimer();
314 wxASSERT_MSG(!(flags
& wxSOUND_LOOP
), wxT("Can't loop and play syncronously at the same time"));
316 //Play movie until it ends, then exit
317 //Note that due to quicktime caching this may not always
318 //work 100% correctly
319 while (!IsMovieDone(m_movie
))
320 MoviesTask(m_movie
, 1);
328 void wxOSXQuickTimeSoundData::DoStop()
333 DisposeMovie(m_movie
);
335 wxSound::SoundStopped(this);
340 void wxOSXQuickTimeSoundData::SoundTask()
342 if(IsMovieDone(m_movie
))
344 if (m_flags
& wxSOUND_LOOP
)
347 GoToBeginningOfMovie(m_movie
);
354 MoviesTask(m_movie
, MOVIE_DELAY
); //Give QT time to play movie
357 bool wxSound::Create(int size
, const wxByte
* data
)
359 m_data
= new wxOSXQuickTimeSoundData(size
,data
);
363 bool wxSound::Create(const wxString
& fileName
, bool isResource
)
366 m_data
= new wxOSXSoundManagerSoundData(fileName
);
368 m_data
= new wxOSXQuickTimeSoundData(fileName
);
372 #endif // wxOSX_USE_QUICKTIME