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