From 625d14abfaf803bec9e8c1c42ed2b4bc94afd75e Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Wed, 21 Jul 2004 18:20:18 +0000 Subject: [PATCH] ryan's QT implementation git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@28359 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/mac/carbon/sound.h | 19 +- src/mac/carbon/sound.cpp | 491 +++++++++++++++++++++++----------- 2 files changed, 353 insertions(+), 157 deletions(-) diff --git a/include/wx/mac/carbon/sound.h b/include/wx/mac/carbon/sound.h index 18a84d101b..ee2743b631 100644 --- a/include/wx/mac/carbon/sound.h +++ b/include/wx/mac/carbon/sound.h @@ -33,6 +33,7 @@ public: bool Create(const wxString& fileName, bool isResource = FALSE); bool IsOk() const { return !m_sndname.IsEmpty(); } + void* GetHandle(); protected: // prevent collision with some BSD definitions of macro Free() bool FreeData(); @@ -40,12 +41,18 @@ protected: bool DoPlay(unsigned flags) const; private: - void* m_sndChan; - - wxString m_sndname; - void* m_hSnd; - int m_waveLength; - bool m_isResource; + wxString m_sndname; //file path + char* m_hSnd; //pointer to resource or memory location + int m_waveLength; //size of file in memory mode + void* m_pTimer; //timer + + enum wxSoundType + { + wxSound_MEMORY, + wxSound_FILE, + wxSound_RESOURCE, + wxSound_NONE + } m_type; //mode }; #endif diff --git a/src/mac/carbon/sound.cpp b/src/mac/carbon/sound.cpp index d6d13bb595..19cd045091 100644 --- a/src/mac/carbon/sound.cpp +++ b/src/mac/carbon/sound.cpp @@ -1,11 +1,11 @@ ///////////////////////////////////////////////////////////////////////////// // Name: sound.cpp // Purpose: wxSound class implementation: optional -// Author: Stefan Csomor +// Author: Ryan Norton, Stefan Csomor // Modified by: // Created: 1998-01-01 // RCS-ID: $Id$ -// Copyright: (c) Stefan Csomor +// Copyright: (c) Ryan Norton, Stefan Csomor // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -15,229 +15,418 @@ #include "wx/object.h" #include "wx/string.h" +#include "wx/log.h" +#include "wx/file.h" #include "wx/sound.h" +#include "wx/timer.h" #if wxUSE_SOUND +// Carbon QT Implementation Details - +// +// Memory: +// 1) OpenDefaultComponent(MovieImportType, kQTFileTypeWave); +// 2) NewMovie(0); +// 3) MovieImportDataRef() //Pass Memory Location to this +// 4) PlayMovie(); +// 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime +// +// File: +// 1) Obtain FSSpec +// 2) Call OpenMovieFile +// 3) Call NewMovieFromFile +// 4) Call CloseMovieFile +// 4) PlayMovie(); +// 5) IsMovieDone(), MoviesTask() //2nd param is minimum wait time to allocate to quicktime +// + #ifdef __WXMAC__ #include "wx/mac/private.h" -#ifndef __DARWIN__ -#include +#include +#include +#endif + +#if defined __WXMAC__ && defined __DARWIN__/*TARGET_CARBON*/ +#ifdef __APPLE_CC__ +#include +#else +#include #endif +#else +#include #endif -wxSound::wxSound() - : m_sndChan(0), m_hSnd(NULL), m_waveLength(0), m_isResource(true) -{ -} +//quicktime media layer only required for mac emulation on pc +#ifndef __WXMAC__ +#include +#endif -wxSound::wxSound(const wxString& sFileName, bool isResource) - : m_sndChan(0), m_hSnd(NULL), m_waveLength(0), m_isResource(true) -{ - Create(sFileName, isResource); -} +#include +//Time inbetween timer calls +#define MOVIE_DELAY 100 -wxSound::~wxSound() +// ------------------------------------------------------------------ +// wxQTTimer - Handle Asyncronous Playing +// ------------------------------------------------------------------ +class wxQTTimer : public wxTimer { - FreeData(); -} +public: + wxQTTimer(Movie movie, bool bLoop) : + m_movie(movie), m_bLoop(bLoop) + { + } -wxSound::wxSound(int size, const wxByte* data) - : m_sndChan(0), m_hSnd(NULL), m_waveLength(0), m_isResource(false) -{ - //TODO convert data -} + ~wxQTTimer() + { + Shutdown(); + } -bool wxSound::Create(const wxString& fileName, bool isResource) -{ - bool ret = false; - m_sndname = fileName; - m_isResource = isResource; + void Shutdown() + { + StopMovie(m_movie); + DisposeMovie(m_movie); + m_movie = NULL ; + Stop(); + } - if (m_isResource) - ret = true; - else - { /* - if (sndChan) - { // we're playing - FSClose(SndRefNum); - SndRefNum = 0; - SndDisposeChannel(sndChan, TRUE); - free(sndChan); - sndChan = 0; - KillTimer(0,timerID); + void Notify() + { + if(IsMovieDone(m_movie)) + { + if (!m_bLoop) + Shutdown(); + else + { + StopMovie(m_movie); + GoToBeginningOfMovie(m_movie); + StartMovie(m_movie); } + } + else + MoviesTask(m_movie, MOVIE_DELAY); //Give QT time to play movie + } - if (!lpSnd) - return true; - - if (_access(lpSnd,0)) // no file, no service - return false; - // Allocate SndChannel - sndChan = (SndChannelPtr) malloc (sizeof(SndChannel)); + Movie& GetMovie() {return m_movie;} +protected: + Movie m_movie; + bool m_bLoop; +}; - if (!sndChan) - return false; - sndChan->qLength = 128; +class wxSMTimer : public wxTimer +{ +public: + wxSMTimer(void* hSnd, void* pSndChannel, const bool& bLoop) + : m_hSnd(hSnd), m_pSndChannel(pSndChannel), m_bLoop(bLoop) + { + } - if (noErr != SndNewChannel (&sndChan, sampledSynth, initMono | initNoInterp, 0)) + ~wxSMTimer() { - free(sndChan); - sndChan = 0; - return false; + Shutdown(); } - if (!(SndRefNum = MacOpenSndFile ((char *)lpSnd))) + void Notify() { - SndDisposeChannel(sndChan, TRUE); - free(sndChan); - sndChan = 0; - - return false; + SCStatus stat; + + if (SndChannelStatus((SndChannelPtr)m_pSndChannel, sizeof(SCStatus), &stat) != 0) + Shutdown(); + + //if the sound isn't playing anymore, see if it's looped, + //and if so play it again, otherwise close things up + if (stat.scChannelBusy == FALSE) + { + if (m_bLoop) + { + if(SndPlay((SndChannelPtr)m_pSndChannel, (SndListHandle) m_hSnd, true) != noErr) + Shutdown(); + } + else + Shutdown(); } + } - bool async = false; + void Shutdown() + { + SndDisposeChannel((SndChannelPtr)m_pSndChannel, TRUE); + Stop(); + } + +protected: + void* m_hSnd; + void* m_pSndChannel; + bool m_bLoop; +}; + +// ------------------------------------------------------------------ +// wxSound +// ------------------------------------------------------------------ + +//Determines whether version 4 of QT is installed +Boolean wxIsQuickTime4Installed (void) +{ +#ifdef __WXMAC__ + short error; + long result; - if (fdwSound & SND_ASYNC) - async = true; + error = Gestalt (gestaltQuickTime, &result); + return (error == noErr) && (result >= 4); //result >= 4 correct? +#else + return true; +#endif +} - if (SndStartFilePlay(sndChan, SndRefNum, 0, 81920, 0, 0, 0, async) != noErr) +inline bool wxInitQT () +{ + if (wxIsQuickTime4Installed()) + { + #ifndef __WXMAC__ + int nError; + //-2093 no dll + if ((nError = InitializeQTML(0)) != noErr) + wxLogSysError(wxString::Format("Couldn't Initialize Quicktime-%i", nError)); + #endif + EnterMovies(); + return true; + } + else { - FSClose (SndRefNum); - SndRefNum = 0; - SndDisposeChannel (sndChan, TRUE); - free (sndChan); - sndChan = 0; + wxLogSysError("Quicktime is not installed, or Your Version of Quicktime is <= 4."); return false; } +} - if (async) - { // haven't finish yet - timerID = SetTimer(0, 0, 250, TimerCallBack); +wxSound::wxSound() +: m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE) +{ +} + +wxSound::wxSound(const wxString& sFileName, bool isResource) +: m_hSnd(NULL), m_waveLength(0), m_pTimer(NULL), m_type(wxSound_NONE) +{ + Create(sFileName, isResource); +} + +wxSound::wxSound(int size, const wxByte* data) +: m_hSnd((char*)data), m_waveLength(size), m_pTimer(NULL), m_type(wxSound_MEMORY) +{ + if (!wxInitQT()) + m_type = wxSound_NONE; +} + +wxSound::~wxSound() +{ + FreeData(); +} + +bool wxSound::Create(const wxString& fileName, bool isResource) +{ + if(!wxInitQT()) + return false; + + if (isResource) + { +#ifdef __WXMAC__ + m_type = wxSound_RESOURCE; + + Str255 lpSnd ; + + wxMacStringToPascal( fileName , lpSnd ) ; + + m_sndname = lpSnd; + m_hSnd = (char*) GetNamedResource('snd ', (const unsigned char *) lpSnd); +#else + return false; +#endif } else { - FSClose (SndRefNum); - SndRefNum = 0; - SndDisposeChannel (sndChan, TRUE); - free (sndChan); - sndChan = 0; - }*/ + m_type = wxSound_FILE; + m_sndname = fileName; } - return ret; + return true; } - -//don't know what to do with looped, wth bool wxSound::DoPlay(unsigned flags) const { - bool ret = false; + wxASSERT(m_pTimer == NULL || !((wxTimer*)m_pTimer)->IsRunning() ); - if (m_isResource) + Movie movie; + + switch(m_type) + { + case wxSound_MEMORY: + { + Handle myHandle, dataRef = nil; + MovieImportComponent miComponent; + Track targetTrack = nil; + TimeValue addedDuration = 0; + long outFlags = 0; + OSErr err; + ComponentResult result; + + myHandle = NewHandleClear((Size)m_waveLength); + + BlockMove(m_hSnd, *myHandle, m_waveLength); + + err = PtrToHand(&myHandle, &dataRef, sizeof(Handle)); + + if (memcmp(&m_hSnd[8], "WAVE", 4) == 0) + miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeWave); + else if (memcmp(&m_hSnd[8], "AIFF", 4) == 0) + miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFF); + else if (memcmp(&m_hSnd[8], "AIFC", 4) == 0) + miComponent = OpenDefaultComponent(MovieImportType, kQTFileTypeAIFC); + else { - Str255 snd ; - wxMacStringToPascal( m_sndname , snd ) ; - SndListHandle hSnd; + wxLogSysError("wxSound - Location in memory does not contain valid data"); + return false; + } + + movie = NewMovie(0); - hSnd = (SndListHandle) GetNamedResource('snd ', snd); + result = MovieImportDataRef(miComponent, dataRef, + HandleDataHandlerSubType, movie, + nil, &targetTrack, + nil, &addedDuration, + movieImportCreateTrack, &outFlags); - if ((hSnd != NULL) && (SndPlay((SndChannelPtr)m_sndChan, (SndListHandle) hSnd, (flags & wxSOUND_ASYNC)) == noErr)) - ret = true; + if (result != noErr) + { + wxLogSysError(wxString::Format(wxT("Couldn't import movie data\nError:%i"), (int)result)); } - return ret; -} + SetMovieVolume(movie, kFullVolume); + GoToBeginningOfMovie(movie); + } + break; + case wxSound_RESOURCE: + { + SoundComponentData data; + unsigned long numframes, offset; + ParseSndHeader((SndListHandle)m_hSnd, &data, &numframes, &offset); + //m_waveLength = numFrames * data.numChannels; -bool wxSound::FreeData() -{ - bool ret = false; + SndChannelPtr pSndChannel; + SndNewChannel(&pSndChannel, sampledSynth, + initNoInterp + + (data.numChannels == 1 ? initMono : initStereo), NULL); - if (m_isResource) + if(SndPlay(pSndChannel, (SndListHandle) m_hSnd, flags & wxSOUND_ASYNC ? 1 : 0) != noErr) + return false; + + if (flags & wxSOUND_ASYNC) { - m_sndname.Empty(); - ret = true; + ((wxSMTimer*&)m_pTimer) = new wxSMTimer(pSndChannel, m_hSnd, flags & wxSOUND_LOOP ? 1 : 0); + + ((wxTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS); } else + SndDisposeChannel(pSndChannel, TRUE); + + return true; + } + break; + case wxSound_FILE: + { + short movieResFile; + FSSpec sfFile; + +#ifdef __WXMAC__ + wxMacFilename2FSSpec( m_sndname , &sfFile ) ; +#else + int nError; + if ((nError = NativePathNameToFSSpec ((char*) m_sndname.c_str(), &sfFile, 0)) != noErr) { - //TODO, + wxLogSysError(wxString::Format(wxT("File:%s does not exist\nError:%i"), + m_sndname.c_str(), nError)); + return false; } +#endif - return ret; -} + if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr) + { + wxLogSysError(wxT("Quicktime couldn't open the file")); + return false; + } -//code below is from an old implementation used for telinfo with MSVC crossplatform support -//technology proceeds, so it would be the wisest to drop this code, but it's left here just -//for the sake of a reference. BTW: Wave files can now be played with QT, starting from V3 + short movieResID = 0; + Str255 movieName; + OSErr err; -/*static short MacOpenSndFile (char * path) -{ - VolumeParam vp; - FSSpec fspec; - Str255 name; - char *c; - - // first, get the volume reference number for the file. Start by - // making a Pstring with just the volume name - strcpy ((char *) name, path); - if (c = strchr ((char *) name, ':')) + err = NewMovieFromFile ( + &movie, + movieResFile, + &movieResID, + movieName, + newMovieActive, + NULL); //wasChanged + + CloseMovieFile (movieResFile); + + if (err != noErr) { - c++; - *c = '\0'; + wxLogSysError( + wxString::Format(wxT("wxSound - Could not open file: %s\nError:%i"), m_sndname.c_str(), err ) + ); + return false; } + } + break; + default: + return false; + }//end switch(m_type) - c2pstr ((char *) name); - vp.ioCompletion = 0; - vp.ioVolIndex = -1; - vp.ioNamePtr = name; - vp.ioVRefNum = 0; - if (PBGetVInfo((ParamBlockRec *)&vp, 0) != noErr) - return 0; + //Start the movie! + StartMovie(movie); - // next, buld an FSSpec for the file - strcpy ((char *) name, path); - c2pstr ((char *) name); - if (FSMakeFSSpec (vp.ioVRefNum, 0, name, &fspec) != noErr) - return 0; + if (flags & wxSOUND_SYNC) + { + wxASSERT_MSG(!(flags & wxSOUND_LOOP), "Can't loop and play syncronously at the same time"); - short frefnum; - // now open the file, and return it's reference number - if (FSpOpenDF(&fspec, fsRdPerm, &frefnum) != noErr) - return 0; + //Play movie until it ends, then exit + while (!IsMovieDone(movie)) + MoviesTask(movie, 0); - return frefnum; + DisposeMovie(movie); + } + else + { + //Start timer and play movie asyncronously + ((wxQTTimer*&)m_pTimer) = new wxQTTimer(movie, flags & wxSOUND_LOOP ? 1 : 0); + ((wxQTTimer*)m_pTimer)->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS); + } + + return true; } +void* wxSound::GetHandle() +{ + return (void*) ((wxQTTimer*) m_pTimer)->GetMovie(); +} -void TimerCallBack(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime) +bool wxSound::FreeData() { - if(!sndChan) + if (m_pTimer != NULL) { - KillTimer(0,timerID); - return; + delete (wxQTTimer*) m_pTimer; + m_pTimer = NULL; } - SCStatus scstat; - - if (noErr == SndChannelStatus (sndChan, sizeof (SCStatus), &scstat)) { - if (scstat.scChannelPaused || scstat.scChannelBusy) - return; // not done yet - } - - // either error or done. - FSClose (SndRefNum); - SndRefNum = 0; - SndDisposeChannel (sndChan, TRUE); - free (sndChan); - sndChan = 0; - KillTimer(0,timerID); -}*/ - + //Note that ExitMovies() is not neccessary, but + //the docs are fuzzy on whether or not TerminateQTML is + ExitMovies(); +#ifndef __WXMAC__ + TerminateQTML(); #endif + return true; +} +#endif //wxUSE_SOUND -- 2.45.2