]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/sound.cpp
adapting to new sound file organization for osx
[wxWidgets.git] / src / osx / carbon / sound.cpp
CommitLineData
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
64class wxOSXSoundManagerSoundData : public wxSoundData
489468fe
SC
65{
66public:
deb0a11e
SC
67 wxOSXSoundManagerSoundData(const wxString& fileName);
68 ~wxOSXSoundManagerSoundData();
69
70 virtual bool Play(unsigned flags);
71 virtual void SoundTask();
489468fe 72
deb0a11e
SC
73 void DoStop();
74protected:
75 SndListHandle m_hSnd;
76 SndChannelPtr m_pSndChannel;
77};
489468fe 78
deb0a11e
SC
79wxOSXSoundManagerSoundData::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}
489468fe 88
deb0a11e
SC
89wxOSXSoundManagerSoundData::~wxOSXSoundManagerSoundData()
90{
91 DoStop();
92 ReleaseResource((Handle)m_hSnd);
93}
489468fe 94
deb0a11e
SC
95void 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 }
deb0a11e 103}
489468fe 104
deb0a11e
SC
105bool wxOSXSoundManagerSoundData::Play(unsigned flags)
106{
107 Stop();
489468fe 108
deb0a11e 109 m_flags = flags;
489468fe 110
deb0a11e
SC
111 SoundComponentData data;
112 unsigned long numframes, offset;
113
114 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
489468fe 115
deb0a11e
SC
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}
489468fe 130
deb0a11e 131void wxOSXSoundManagerSoundData::SoundTask()
489468fe 132{
deb0a11e
SC
133 SCStatus stat;
134
135 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
489468fe 136 Stop();
deb0a11e
SC
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)
489468fe 141 {
deb0a11e 142 if (m_flags & wxSOUND_LOOP)
489468fe 143 {
deb0a11e
SC
144 if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr)
145 Stop();
489468fe 146 }
deb0a11e
SC
147 else
148 Stop();
489468fe 149 }
deb0a11e 150}
489468fe
SC
151
152// ------------------------------------------------------------------
deb0a11e 153// QuickTime
489468fe
SC
154// ------------------------------------------------------------------
155
deb0a11e
SC
156bool wxInitQT();
157bool wxInitQT()
489468fe 158{
deb0a11e
SC
159#ifndef __WXMAC__
160 int nError;
161 //-2093 no dll
162 if ((nError = InitializeQTML(0)) != noErr)
489468fe 163 {
deb0a11e 164 wxLogSysError(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
489468fe
SC
165 return false;
166 }
489468fe 167#endif
deb0a11e
SC
168 EnterMovies();
169 return true;
489468fe
SC
170}
171
deb0a11e
SC
172void wxExitQT();
173void wxExitQT()
489468fe 174{
deb0a11e
SC
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
489468fe
SC
182}
183
deb0a11e 184class wxOSXQuickTimeSoundData : public wxSoundData
489468fe 185{
deb0a11e
SC
186public:
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();
194protected:
195 Movie m_movie;
196
197 wxString m_sndname; //file path
198 Handle m_soundHandle;
199};
200
201
202wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(const wxString& fileName) :
203 m_movie(NULL), m_soundHandle(NULL)
204{
205 m_sndname = fileName;
489468fe
SC
206}
207
deb0a11e
SC
208wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(int size, const wxByte* data) :
209 m_movie(NULL)
210{
211 m_soundHandle = NewHandleClear((Size)size);
212 BlockMove(data, *m_soundHandle, size);
489468fe
SC
213}
214
deb0a11e 215wxOSXQuickTimeSoundData::~wxOSXQuickTimeSoundData()
489468fe 216{
deb0a11e
SC
217 if ( m_soundHandle )
218 DisposeHandle(m_soundHandle);
489468fe
SC
219}
220
deb0a11e 221bool wxOSXQuickTimeSoundData::Play(unsigned flags)
489468fe 222{
deb0a11e
SC
223 if ( m_movie )
224 Stop();
225
226 m_flags = flags;
227
228 if (!wxInitQT())
229 return false;
489468fe 230
deb0a11e 231 if( m_soundHandle )
489468fe 232 {
deb0a11e
SC
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
489468fe 251 {
deb0a11e
SC
252 HUnlock(m_soundHandle);
253 wxLogSysError(wxT("wxSound - Location in memory does not contain valid data"));
254 return false;
489468fe 255 }
deb0a11e
SC
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)
489468fe 267 {
deb0a11e 268 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
489468fe 269 }
deb0a11e
SC
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)
489468fe 287 {
deb0a11e 288 err = NewMovieFromDataRef( &m_movie, newMovieDontAskUnresolvedDataRefs , NULL, dataRef, dataRefType );
489468fe 289 wxASSERT(err == noErr);
deb0a11e 290 DisposeHandle(dataRef);
489468fe 291 }
deb0a11e
SC
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
489468fe
SC
305 if (flags & wxSOUND_ASYNC)
306 {
deb0a11e 307 CreateAndStartTimer();
489468fe
SC
308 }
309 else
310 {
311 wxASSERT_MSG(!(flags & wxSOUND_LOOP), wxT("Can't loop and play syncronously at the same time"));
deb0a11e 312
489468fe
SC
313 //Play movie until it ends, then exit
314 //Note that due to quicktime caching this may not always
315 //work 100% correctly
deb0a11e
SC
316 while (!IsMovieDone(m_movie))
317 MoviesTask(m_movie, 1);
318
319 DoStop();
489468fe 320 }
deb0a11e 321
489468fe
SC
322 return true;
323}
324
deb0a11e 325void wxOSXQuickTimeSoundData::DoStop()
489468fe 326{
deb0a11e
SC
327 if( m_movie )
328 {
329 StopMovie(m_movie);
330 DisposeMovie(m_movie);
331 m_movie = NULL;
332 wxSound::SoundStopped(this);
333 wxExitQT();
334 }
489468fe
SC
335}
336
deb0a11e 337void wxOSXQuickTimeSoundData::SoundTask()
489468fe 338{
deb0a11e 339 if(IsMovieDone(m_movie))
489468fe 340 {
deb0a11e
SC
341 if (m_flags & wxSOUND_LOOP)
342 {
343 StopMovie(m_movie);
344 GoToBeginningOfMovie(m_movie);
345 StartMovie(m_movie);
346 }
347 else
348 Stop();
489468fe 349 }
deb0a11e
SC
350 else
351 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
489468fe
SC
352}
353
deb0a11e 354bool wxSound::Create(int size, const wxByte* data)
489468fe 355{
deb0a11e
SC
356 m_data = new wxOSXQuickTimeSoundData(size,data);
357 return true;
358}
489468fe 359
deb0a11e
SC
360bool 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;
489468fe
SC
367}
368
deb0a11e
SC
369#endif // wxOSX_USE_QUICKTIME
370
489468fe 371#endif //wxUSE_SOUND