]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/sound.cpp
avoid setting initial position if it was not specified, broken in r70734
[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
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
63class wxOSXSoundManagerSoundData : public wxSoundData
489468fe
SC
64{
65public:
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();
73protected:
ce00f59b 74 SndListHandle m_hSnd;
deb0a11e
SC
75 SndChannelPtr m_pSndChannel;
76};
489468fe 77
deb0a11e
SC
78wxOSXSoundManagerSoundData::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
88wxOSXSoundManagerSoundData::~wxOSXSoundManagerSoundData()
89{
90 DoStop();
91 ReleaseResource((Handle)m_hSnd);
92}
489468fe 93
deb0a11e
SC
94void 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
107bool 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 133void 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
158bool wxInitQT();
159bool 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
174void wxExitQT();
175void 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 186class wxOSXQuickTimeSoundData : public wxSoundData
489468fe 187{
deb0a11e
SC
188public:
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();
196protected:
197 Movie m_movie;
ce00f59b 198
deb0a11e
SC
199 wxString m_sndname; //file path
200 Handle m_soundHandle;
201};
202
203
204wxOSXQuickTimeSoundData::wxOSXQuickTimeSoundData(const wxString& fileName) :
205 m_movie(NULL), m_soundHandle(NULL)
ce00f59b 206{
deb0a11e 207 m_sndname = fileName;
489468fe
SC
208}
209
c559c4b3 210wxOSXQuickTimeSoundData::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 217wxOSXQuickTimeSoundData::~wxOSXQuickTimeSoundData()
489468fe 218{
deb0a11e
SC
219 if ( m_soundHandle )
220 DisposeHandle(m_soundHandle);
489468fe
SC
221}
222
deb0a11e 223bool 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 327void 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 339void 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 356bool 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
362bool 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