]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/mac/carbon/sound.cpp
Refresh is necessary in earlier systems, no penalty when doing in 10.3+
[wxWidgets.git] / src / mac / carbon / sound.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: sound.cpp
3// Purpose: wxSound class implementation: optional
4// Author: Ryan Norton, Stefan Csomor
5// Modified by:
6// Created: 1998-01-01
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton, Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "sound.h"
14#endif
15
16#include "wx/object.h"
17#include "wx/string.h"
18#include "wx/log.h"
19#include "wx/file.h"
20#include "wx/sound.h"
21#include "wx/timer.h"
22
23#if wxUSE_SOUND
24
25// Carbon QT Implementation Details -
26//
27// Memory:
28// 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
29// 2) NewMovie(0);
30// 3) MovieImportDataRef() //Pass Memory Location to this
31// 4) PlayMovie();
32// 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
33//
34// File:
35// 1) Obtain FSSpec
36// 2) Call OpenMovieFile
37// 3) Call NewMovieFromFile
38// 4) Call CloseMovieFile
39// 4) PlayMovie();
40// 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime
41//
42
43#ifdef __WXMAC__
44#include "wx/mac/private.h"
45#include <Movies.h>
46#include <Gestalt.h>
47#endif
48
49#if defined __WXMAC__ && defined __DARWIN__/*TARGET_CARBON*/
50#ifdef __APPLE_CC__
51#include <Carbon/Carbon.h>
52#else
53#include <Carbon.h>
54#endif
55#else
56#include <Sound.h>
57#endif
58
59//quicktime media layer only required for mac emulation on pc
60#ifndef __WXMAC__
61#include <qtml.h>
62#endif
63
64#include <QuickTimeComponents.h>
65
66//Time inbetween timer calls
67#define MOVIE_DELAY 100
68
69// ------------------------------------------------------------------
70// wxQTTimer - Handle Asyncronous Playing
71// ------------------------------------------------------------------
72class wxQTTimer : public wxTimer
73{
74public:
75 wxQTTimer(Movie movie, bool bLoop) :
76 m_movie(movie), m_bLoop(bLoop)
77 {
78 }
79
80 ~wxQTTimer()
81 {
82 Shutdown();
83 }
84
85 void Shutdown()
86 {
87 StopMovie(m_movie);
88 DisposeMovie(m_movie);
89 m_movie = NULL ;
90 Stop();
91
92 //Note that ExitMovies() is not neccessary, but
93 //the docs are fuzzy on whether or not TerminateQTML is
94 ExitMovies();
95
96 #ifndef __WXMAC__
97 TerminateQTML();
98 #endif
99 }
100
101 void Notify()
102 {
103 if(IsMovieDone(m_movie))
104 {
105 if (!m_bLoop)
106 Shutdown();
107 else
108 {
109 StopMovie(m_movie);
110 GoToBeginningOfMovie(m_movie);
111 StartMovie(m_movie);
112 }
113 }
114 else
115 MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie
116 }
117
118
119 Movie& GetMovie() {return m_movie;}
120protected:
121 Movie m_movie;
122 bool m_bLoop;
123};
124
125
126class wxSMTimer : public wxTimer
127{
128public:
129 wxSMTimer(void* hSnd, void* pSndChannel, const bool& bLoop)
130 : m_hSnd(hSnd), m_pSndChannel(pSndChannel), m_bLoop(bLoop)
131 {
132 }
133
134 ~wxSMTimer()
135 {
136 Shutdown();
137 }
138
139 void Notify()
140 {
141 SCStatus stat;
142
143 if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0)
144 Shutdown();
145
146 //if the sound isn't playing anymore, see if it's looped,
147 //and if so play it again, otherwise close things up
148 if (stat.scChannelBusy == FALSE)
149 {
150 if (m_bLoop)
151 {
152 if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr)
153 Shutdown();
154 }
155 else
156 Shutdown();
157 }
158 }
159
160 void Shutdown()
161 {
162 SndDisposeChannel((SndChannelPtr)m_pSndChannel, TRUE);
163 Stop();
164 }
165
166protected:
167 void* m_hSnd;
168 void* m_pSndChannel;
169 bool m_bLoop;
170};
171
172// ------------------------------------------------------------------
173// wxSound
174// ------------------------------------------------------------------
175
176//Determines whether version 4 of QT is installed
177Boolean wxIsQuickTime4Installed (void)
178{
179#ifdef __WXMAC__
180 short error;
181 long result;
182
183 error = Gestalt (gestaltQuickTime, &result);
184 return (error == noErr) && (((result >> 16) & 0xffff) >= 0x0400);
185#else
186 return true;
187#endif
188}
189
190inline bool wxInitQT ()
191{
192 if (wxIsQuickTime4Installed())
193 {
194 #ifndef __WXMAC__
195 int nError;
196 //-2093 no dll
197 if ((nError = InitializeQTML(0)) != noErr)
198 wxLogSysError(wxString::Format("Couldn't Initialize Quicktime-%i", nError));
199 #endif
200 EnterMovies();
201 return true;
202 }
203 else
204 {
205 wxLogSysError("Quicktime is not installed, or Your Version of Quicktime is <= 4.");
206 return false;
207 }
208}
209
210wxSound::wxSound()
211: m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE)
212{
213}
214
215wxSound::wxSound(const wxString& sFileName, bool isResource)
216: m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE)
217{
218 Create(sFileName, isResource);
219}
220
221wxSound::wxSound(int size, const wxByte* data)
222: m_hSnd((char*)data), m_waveLength(size), m_pTimer(NULL), m_type(wxSound_MEMORY)
223{
224 if (!wxInitQT())
225 m_type = wxSound_NONE;
226}
227
228wxSound::~wxSound()
229{
230}
231
232bool wxSound::Create(const wxString& fileName, bool isResource)
233{
234 if(!wxInitQT())
235 return false;
236
237 FreeData();
238
239 if (isResource)
240 {
241#ifdef __WXMAC__
242 m_type = wxSound_RESOURCE;
243
244 Str255 lpSnd ;
245
246 wxMacStringToPascal( fileName , lpSnd ) ;
247
248 m_sndname = lpSnd;
249 m_hSnd = (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd);
250#else
251 return false;
252#endif
253 }
254 else
255 {
256 m_type = wxSound_FILE;
257 m_sndname = fileName;
258 }
259
260 return true;
261}
262
263bool wxSound::DoPlay(unsigned flags) const
264{
265// wxASSERT(m_pTimer == NULL || !((wxTimer*)m_pTimer)->IsRunning() );
266 FreeData();
267
268 Movie movie;
269
270 switch(m_type)
271 {
272 case wxSound_MEMORY:
273 {
274 Handle myHandle, dataRef = nil;
275 MovieImportComponent miComponent;
276 Track targetTrack = nil;
277 TimeValue addedDuration = 0;
278 long outFlags = 0;
279 OSErr err;
280 ComponentResult result;
281
282 myHandle = NewHandleClear((Size)m_waveLength);
283
284 BlockMove(m_hSnd, *myHandle, m_waveLength);
285
286 err = PtrToHand(&myHandle, &dataRef, sizeof(Handle));
287
288 if (memcmp(&m_hSnd[8], "WAVE", 4) == 0)
289 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeWave);
290 else if (memcmp(&m_hSnd[8], "AIFF", 4) == 0)
291 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFF);
292 else if (memcmp(&m_hSnd[8], "AIFC", 4) == 0)
293 miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFC);
294 else
295 {
296 wxLogSysError("wxSound - Location in memory does not contain valid data");
297 return false;
298 }
299
300 movie = NewMovie(0);
301
302 result = MovieImportDataRef(miComponent, dataRef,
303 HandleDataHandlerSubType, movie,
304 nil, &targetTrack,
305 nil, &addedDuration,
306 movieImportCreateTrack, &outFlags);
307
308 if (result != noErr)
309 {
310 wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result));
311 }
312
313 SetMovieVolume(movie, kFullVolume);
314 GoToBeginningOfMovie(movie);
315
316 DisposeHandle(myHandle);
317 }
318 break;
319 case wxSound_RESOURCE:
320 {
321 SoundComponentData data;
322 unsigned long numframes, offset;
323
324 ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset);
325 //m_waveLength = numFrames * data.numChannels;
326
327 SndChannelPtr pSndChannel;
328 SndNewChannel(&pSndChannel, sampledSynth,
329 initNoInterp +
330 (data.numChannels == 1 ? initMono : initStereo), NULL);
331
332 if(SndPlay(pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr)
333 return false;
334
335 if (flags & wxSOUND_ASYNC)
336 {
337 ((wxSMTimer*&)m_pTimer) = new wxSMTimer(pSndChannel, m_hSnd, flags & wxSOUND_LOOP ? 1 : 0);
338
339 ((wxTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
340 }
341 else
342 SndDisposeChannel(pSndChannel, TRUE);
343
344 return true;
345 }
346 break;
347 case wxSound_FILE:
348 {
349 short movieResFile;
350 FSSpec sfFile;
351
352#ifdef __WXMAC__
353 wxMacFilename2FSSpec( m_sndname , &sfFile ) ;
354#else
355 int nError;
356 if ((nError = NativePathNameToFSSpec ((char*) m_sndname.c_str(), &sfFile, 0)) != noErr)
357 {
358 wxLogSysError(wxString::Format(wxT("File:%s does not exist\nError:%i"),
359 m_sndname.c_str(), nError));
360 return false;
361 }
362#endif
363
364 if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
365 {
366 wxLogSysError(wxT("Quicktime couldn't open the file"));
367 return false;
368 }
369
370
371 short movieResID = 0;
372 Str255 movieName;
373 OSErr err;
374
375 err = NewMovieFromFile (
376 &movie,
377 movieResFile,
378 &movieResID,
379 movieName,
380 newMovieActive,
381 NULL); //wasChanged
382
383 CloseMovieFile (movieResFile);
384
385 if (err != noErr)
386 {
387 wxLogSysError(
388 wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err )
389 );
390 return false;
391 }
392 }
393 break;
394 default:
395 return false;
396 }//end switch(m_type)
397
398
399 //Start the movie!
400 StartMovie(movie);
401
402 if (flags & wxSOUND_ASYNC)
403 {
404 //Start timer and play movie asyncronously
405 ((wxQTTimer*&)m_pTimer) = new wxQTTimer(movie, flags & wxSOUND_LOOP ? 1 : 0);
406 ((wxQTTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
407 }
408 else
409 {
410 wxASSERT_MSG(!(flags & wxSOUND_LOOP), "Can't loop and play syncronously at the same time");
411
412 //Play movie until it ends, then exit
413 while (!IsMovieDone(movie))
414 MoviesTask(movie, 0);
415
416 DisposeMovie(movie);
417 }
418
419 return true;
420}
421
422void* wxSound::GetHandle()
423{
424 return (void*) ((wxQTTimer*) m_pTimer)->GetMovie();
425}
426
427bool wxSound::FreeData()
428{
429 if (m_pTimer != NULL)
430 {
431 delete (wxQTTimer*) m_pTimer;
432 m_pTimer = NULL;
433 }
434
435 return true;
436}
437#endif //wxUSE_SOUND
438
439
440