]>
Commit | Line | Data |
---|---|---|
489468fe | 1 | ///////////////////////////////////////////////////////////////////////////// |
524c47aa | 2 | // Name: src/osx/carbon/sound.cpp |
489468fe SC |
3 | // Purpose: wxSound class implementation: optional |
4 | // Author: Ryan Norton | |
5 | // Modified by: Stefan Csomor | |
6 | // Created: 1998-01-01 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Ryan Norton | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | // For compilers that support precompilation, includes "wx.h". | |
13 | #include "wx/wxprec.h" | |
14 | ||
15 | #if wxUSE_SOUND | |
16 | ||
deb0a11e SC |
17 | #if wxOSX_USE_QUICKTIME |
18 | ||
489468fe SC |
19 | #include "wx/sound.h" |
20 | ||
21 | #ifndef WX_PRECOMP | |
22 | #include "wx/object.h" | |
23 | #include "wx/string.h" | |
24 | #include "wx/intl.h" | |
25 | #include "wx/log.h" | |
26 | #include "wx/timer.h" | |
27 | #endif | |
28 | ||
29 | #include "wx/file.h" | |
30 | ||
31 | // Carbon QT Implementation Details - | |
32 | // | |
33 | // Memory: | |
34 | // 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave); | |
35 | // 2) NewMovie(0); | |
36 | // 3) MovieImportDataRef() //Pass Memory Location to this | |
37 | // 4) PlayMovie(); | |
38 | // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime | |
39 | // | |
40 | // File: | |
41 | // 1) Path as CFString | |
42 | // 2) Call QTNewDataReferenceFromFullPathCFString | |
43 | // 3) Call NewMovieFromDataRef | |
44 | // 4) Call CloseMovieFile | |
45 | // 4) PlayMovie(); | |
46 | // 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime | |
47 | // | |
48 | ||
49 | #ifdef __WXMAC__ | |
deb0a11e SC |
50 | #include "wx/osx/private.h" |
51 | #if wxOSX_USE_COCOA_OR_CARBON | |
52 | #include <QuickTime/QuickTimeComponents.h> | |
53 | #endif | |
489468fe | 54 | #else |
deb0a11e | 55 | #include <qtml.h> |
489468fe SC |
56 | #endif |
57 | ||
489468fe SC |
58 | #define MOVIE_DELAY 100 |
59 | ||
489468fe | 60 | // ------------------------------------------------------------------ |
deb0a11e | 61 | // SoundManager |
489468fe | 62 | // ------------------------------------------------------------------ |
deb0a11e SC |
63 | |
64 | class wxOSXSoundManagerSoundData : public wxSoundData | |
489468fe SC |
65 | { |
66 | public: | |
deb0a11e SC |
67 | wxOSXSoundManagerSoundData(const wxString& fileName); |
68 | ~wxOSXSoundManagerSoundData(); | |
ce00f59b | 69 | |
deb0a11e SC |
70 | virtual bool Play(unsigned flags); |
71 | virtual void SoundTask(); | |
489468fe | 72 | |
deb0a11e SC |
73 | void DoStop(); |
74 | protected: | |
ce00f59b | 75 | SndListHandle m_hSnd; |
deb0a11e SC |
76 | SndChannelPtr m_pSndChannel; |
77 | }; | |
489468fe | 78 | |
deb0a11e SC |
79 | wxOSXSoundManagerSoundData::wxOSXSoundManagerSoundData(const wxString& fileName) : |
80 | m_pSndChannel(NULL) | |
ce00f59b | 81 | { |
deb0a11e | 82 | Str255 lpSnd ; |
ce00f59b | 83 | |
deb0a11e | 84 | wxMacStringToPascal( fileName , lpSnd ) ; |
ce00f59b | 85 | |
deb0a11e SC |
86 | m_hSnd = (SndListHandle) GetNamedResource('snd ', (const unsigned char *) lpSnd); |
87 | } | |
489468fe | 88 | |
deb0a11e SC |
89 | wxOSXSoundManagerSoundData::~wxOSXSoundManagerSoundData() |
90 | { | |
91 | DoStop(); | |
92 | ReleaseResource((Handle)m_hSnd); | |
93 | } | |
489468fe | 94 | |
deb0a11e SC |
95 | void wxOSXSoundManagerSoundData::DoStop() |
96 | { | |
97 | if ( m_pSndChannel ) | |
489468fe | 98 | { |
deb0a11e SC |
99 | SndDisposeChannel(m_pSndChannel, TRUE /* stop immediately, not after playing */); |
100 | m_pSndChannel = NULL; | |
101 | wxSound::SoundStopped(this); | |
489468fe | 102 | } |
ce00f59b | 103 | |
509da835 KO |
104 | if (IsMarkedForDeletion()) |
105 | delete this; | |
deb0a11e | 106 | } |
489468fe | 107 | |
deb0a11e SC |
108 | bool wxOSXSoundManagerSoundData::Play(unsigned flags) |
109 | { | |
110 | Stop(); | |
489468fe | 111 | |
deb0a11e | 112 | m_flags = flags; |
489468fe | 113 | |
deb0a11e SC |
114 | SoundComponentData data; |
115 | unsigned long numframes, offset; | |
ce00f59b | 116 | |
deb0a11e | 117 | ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset); |
489468fe | 118 | |
deb0a11e SC |
119 | SndNewChannel(&m_pSndChannel, sampledSynth, |
120 | initNoInterp | |
121 | + (data.numChannels == 1 ? initMono : initStereo), NULL); | |
ce00f59b | 122 | |
deb0a11e SC |
123 | if(SndPlay(m_pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr) |
124 | return false; | |
ce00f59b | 125 | |
deb0a11e SC |
126 | if (flags & wxSOUND_ASYNC) |
127 | CreateAndStartTimer(); | |
128 | else | |
129 | DoStop(); | |
ce00f59b | 130 | |
deb0a11e SC |
131 | return true; |
132 | } | |
489468fe | 133 | |
deb0a11e | 134 | void wxOSXSoundManagerSoundData::SoundTask() |
489468fe | 135 | { |
deb0a11e | 136 | SCStatus stat; |
ce00f59b | 137 | |
deb0a11e | 138 | if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0) |
489468fe | 139 | Stop(); |
ce00f59b | 140 | |
deb0a11e SC |
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) | |
489468fe | 144 | { |
deb0a11e | 145 | if (m_flags & wxSOUND_LOOP) |
489468fe | 146 | { |
deb0a11e SC |
147 | if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr) |
148 | Stop(); | |
489468fe | 149 | } |
deb0a11e SC |
150 | else |
151 | Stop(); | |
489468fe | 152 | } |
deb0a11e | 153 | } |
489468fe SC |
154 | |
155 | // ------------------------------------------------------------------ | |
deb0a11e | 156 | // QuickTime |
489468fe SC |
157 | // ------------------------------------------------------------------ |
158 | ||
deb0a11e SC |
159 | bool wxInitQT(); |
160 | bool wxInitQT() | |
489468fe | 161 | { |
deb0a11e SC |
162 | #ifndef __WXMAC__ |
163 | int nError; | |
164 | //-2093 no dll | |
165 | if ((nError = InitializeQTML(0)) != noErr) | |
489468fe | 166 | { |
deb0a11e | 167 | wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError)); |
489468fe SC |
168 | return false; |
169 | } | |
489468fe | 170 | #endif |
deb0a11e SC |
171 | EnterMovies(); |
172 | return true; | |
489468fe SC |
173 | } |
174 | ||
deb0a11e SC |
175 | void wxExitQT(); |
176 | void wxExitQT() | |
489468fe | 177 | { |
deb0a11e SC |
178 | //Note that ExitMovies() is not necessary, but |
179 | //the docs are fuzzy on whether or not TerminateQTML is | |
180 | ExitMovies(); | |
ce00f59b | 181 | |
deb0a11e SC |
182 | #ifndef __WXMAC__ |
183 | TerminateQTML(); | |
184 | #endif | |
489468fe SC |
185 | } |
186 | ||
deb0a11e | 187 | class wxOSXQuickTimeSoundData : public wxSoundData |
489468fe | 188 | { |
deb0a11e SC |
189 | public: |
190 | wxOSXQuickTimeSoundData(const wxString& fileName); | |
191 | wxOSXQuickTimeSoundData(int size, const wxByte* data); | |
192 | ~wxOSXQuickTimeSoundData(); | |
ce00f59b | 193 | |
deb0a11e SC |
194 | virtual bool Play(unsigned flags); |
195 | virtual void SoundTask(); | |
196 | virtual void DoStop(); | |
197 | protected: | |
198 | Movie m_movie; | |
ce00f59b | 199 | |
deb0a11e SC |
200 | wxString m_sndname; //file path |
201 | Handle m_soundHandle; | |
202 | }; | |
203 | ||
204 | ||
205 | wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(const wxString& fileName) : | |
206 | m_movie(NULL), m_soundHandle(NULL) | |
ce00f59b | 207 | { |
deb0a11e | 208 | m_sndname = fileName; |
489468fe SC |
209 | } |
210 | ||
deb0a11e SC |
211 | wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(int size, const wxByte* data) : |
212 | m_movie(NULL) | |
ce00f59b | 213 | { |
deb0a11e SC |
214 | m_soundHandle = NewHandleClear((Size)size); |
215 | BlockMove(data, *m_soundHandle, size); | |
489468fe SC |
216 | } |
217 | ||
deb0a11e | 218 | wxOSXQuickTimeSoundData::~wxOSXQuickTimeSoundData() |
489468fe | 219 | { |
deb0a11e SC |
220 | if ( m_soundHandle ) |
221 | DisposeHandle(m_soundHandle); | |
489468fe SC |
222 | } |
223 | ||
deb0a11e | 224 | bool wxOSXQuickTimeSoundData::Play(unsigned flags) |
489468fe | 225 | { |
deb0a11e SC |
226 | if ( m_movie ) |
227 | Stop(); | |
ce00f59b | 228 | |
deb0a11e | 229 | m_flags = flags; |
ce00f59b | 230 | |
deb0a11e SC |
231 | if (!wxInitQT()) |
232 | return false; | |
489468fe | 233 | |
deb0a11e | 234 | if( m_soundHandle ) |
489468fe | 235 | { |
deb0a11e SC |
236 | Handle dataRef = nil; |
237 | MovieImportComponent miComponent; | |
238 | Track targetTrack = nil; | |
239 | TimeValue addedDuration = 0; | |
240 | long outFlags = 0; | |
241 | OSErr err; | |
242 | ComponentResult result; | |
ce00f59b | 243 | |
deb0a11e | 244 | err = PtrToHand(&m_soundHandle, &dataRef, sizeof(Handle)); |
ce00f59b | 245 | |
deb0a11e SC |
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); | |
253 | else | |
489468fe | 254 | { |
deb0a11e SC |
255 | HUnlock(m_soundHandle); |
256 | wxLogSysError(wxT("wxSound - Location in memory does not contain valid data")); | |
257 | return false; | |
489468fe | 258 | } |
ce00f59b | 259 | |
deb0a11e SC |
260 | HUnlock(m_soundHandle); |
261 | m_movie = NewMovie(0); | |
ce00f59b | 262 | |
deb0a11e SC |
263 | result = MovieImportDataRef(miComponent, dataRef, |
264 | HandleDataHandlerSubType, m_movie, | |
265 | nil, &targetTrack, | |
266 | nil, &addedDuration, | |
267 | movieImportCreateTrack, &outFlags); | |
ce00f59b | 268 | |
deb0a11e | 269 | if (result != noErr) |
489468fe | 270 | { |
deb0a11e | 271 | wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result)); |
489468fe | 272 | } |
ce00f59b | 273 | |
deb0a11e SC |
274 | SetMovieVolume(m_movie, kFullVolume); |
275 | GoToBeginningOfMovie(m_movie); | |
276 | } | |
277 | else | |
278 | { | |
279 | OSErr err = noErr ; | |
ce00f59b | 280 | |
deb0a11e SC |
281 | Handle dataRef = NULL; |
282 | OSType dataRefType; | |
ce00f59b | 283 | |
deb0a11e SC |
284 | err = QTNewDataReferenceFromFullPathCFString(wxCFStringRef(m_sndname,wxLocale::GetSystemEncoding()), |
285 | (UInt32)kQTNativeDefaultPathStyle, 0, &dataRef, &dataRefType); | |
ce00f59b | 286 | |
deb0a11e | 287 | wxASSERT(err == noErr); |
ce00f59b | 288 | |
deb0a11e | 289 | if (NULL != dataRef || err != noErr) |
489468fe | 290 | { |
deb0a11e | 291 | err = NewMovieFromDataRef( &m_movie, newMovieDontAskUnresolvedDataRefs , NULL, dataRef, dataRefType ); |
489468fe | 292 | wxASSERT(err == noErr); |
deb0a11e | 293 | DisposeHandle(dataRef); |
489468fe | 294 | } |
ce00f59b | 295 | |
deb0a11e SC |
296 | if (err != noErr) |
297 | { | |
298 | wxLogSysError( | |
299 | wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err ) | |
300 | ); | |
301 | return false; | |
302 | } | |
303 | } | |
ce00f59b | 304 | |
deb0a11e SC |
305 | //Start the m_movie! |
306 | StartMovie(m_movie); | |
ce00f59b | 307 | |
489468fe SC |
308 | if (flags & wxSOUND_ASYNC) |
309 | { | |
deb0a11e | 310 | CreateAndStartTimer(); |
489468fe SC |
311 | } |
312 | else | |
313 | { | |
314 | wxASSERT_MSG(!(flags & wxSOUND_LOOP), wxT("Can't loop and play syncronously at the same time")); | |
ce00f59b | 315 | |
489468fe SC |
316 | //Play movie until it ends, then exit |
317 | //Note that due to quicktime caching this may not always | |
318 | //work 100% correctly | |
deb0a11e SC |
319 | while (!IsMovieDone(m_movie)) |
320 | MoviesTask(m_movie, 1); | |
ce00f59b | 321 | |
deb0a11e | 322 | DoStop(); |
489468fe | 323 | } |
ce00f59b | 324 | |
489468fe SC |
325 | return true; |
326 | } | |
327 | ||
deb0a11e | 328 | void wxOSXQuickTimeSoundData::DoStop() |
489468fe | 329 | { |
deb0a11e SC |
330 | if( m_movie ) |
331 | { | |
332 | StopMovie(m_movie); | |
333 | DisposeMovie(m_movie); | |
334 | m_movie = NULL; | |
335 | wxSound::SoundStopped(this); | |
336 | wxExitQT(); | |
337 | } | |
489468fe SC |
338 | } |
339 | ||
deb0a11e | 340 | void wxOSXQuickTimeSoundData::SoundTask() |
489468fe | 341 | { |
deb0a11e | 342 | if(IsMovieDone(m_movie)) |
489468fe | 343 | { |
deb0a11e SC |
344 | if (m_flags & wxSOUND_LOOP) |
345 | { | |
346 | StopMovie(m_movie); | |
347 | GoToBeginningOfMovie(m_movie); | |
348 | StartMovie(m_movie); | |
349 | } | |
350 | else | |
351 | Stop(); | |
489468fe | 352 | } |
deb0a11e SC |
353 | else |
354 | MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie | |
489468fe SC |
355 | } |
356 | ||
deb0a11e | 357 | bool wxSound::Create(int size, const wxByte* data) |
489468fe | 358 | { |
deb0a11e SC |
359 | m_data = new wxOSXQuickTimeSoundData(size,data); |
360 | return true; | |
361 | } | |
489468fe | 362 | |
deb0a11e SC |
363 | bool wxSound::Create(const wxString& fileName, bool isResource) |
364 | { | |
365 | if ( isResource ) | |
366 | m_data = new wxOSXSoundManagerSoundData(fileName); | |
367 | else | |
368 | m_data = new wxOSXQuickTimeSoundData(fileName); | |
369 | return true; | |
489468fe SC |
370 | } |
371 | ||
deb0a11e SC |
372 | #endif // wxOSX_USE_QUICKTIME |
373 | ||
489468fe | 374 | #endif //wxUSE_SOUND |