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