]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/sound.cpp
Also update focus rect when changing selection in single selection mode, fixes #11332
[wxWidgets.git] / src / osx / carbon / sound.cpp
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