2003-06-24 08:44:02 +00:00
|
|
|
/*
|
|
|
|
|
* RageSoundDriver_QT.cpp
|
|
|
|
|
* stepmania
|
|
|
|
|
*
|
|
|
|
|
* Created by Steve Checkoway on Mon Jun 23 2003.
|
|
|
|
|
* Copyright (c) 2003 Steve Checkoway. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "global.h"
|
|
|
|
|
#include "RageSoundDriver_QT.h"
|
2003-07-28 10:42:20 +00:00
|
|
|
#include "RageSoundManager.h"
|
|
|
|
|
#include "RageSound.h"
|
2003-06-24 08:44:02 +00:00
|
|
|
#include "RageLog.h"
|
2003-07-28 10:42:20 +00:00
|
|
|
#include "RageThreads.h"
|
2003-06-24 08:44:02 +00:00
|
|
|
#include <QuickTime/QuickTime.h>
|
2003-07-09 08:27:27 +00:00
|
|
|
#include <queue>
|
|
|
|
|
#include <vector>
|
2003-07-28 10:42:20 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
|
#include <sys/types.h>
|
2003-06-24 08:44:02 +00:00
|
|
|
|
2003-08-04 11:22:33 +00:00
|
|
|
const unsigned numchannels = 2;
|
|
|
|
|
const unsigned samplesize = 16 * numchannels;
|
2003-08-05 11:40:21 +00:00
|
|
|
const unsigned samples = 40960;
|
2003-06-24 13:23:30 +00:00
|
|
|
const unsigned freq = 44100;
|
2003-08-04 11:22:33 +00:00
|
|
|
const unsigned buffersize = samples * samplesize / 8;
|
|
|
|
|
|
|
|
|
|
#if defined(DEBUG)
|
|
|
|
|
#define TEST_ERR(err, func) \
|
|
|
|
|
if (__builtin_expect(err, noErr)) \
|
|
|
|
|
RageException::Throw(#func " failed with error: %d", err)
|
|
|
|
|
#else
|
|
|
|
|
#define TEST_ERR(err, func)
|
|
|
|
|
#endif
|
2003-06-24 08:44:02 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
typedef struct soundInfo{
|
|
|
|
|
RageSound *snd;
|
|
|
|
|
Movie movie[2];
|
|
|
|
|
long fillme;
|
|
|
|
|
long stopPos;
|
|
|
|
|
long lastPos;
|
|
|
|
|
long finishedBuffers;
|
|
|
|
|
} *soundInfoPtr, **soundInfoHdl;
|
2003-07-09 08:27:27 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
static void CallBack(QTCallBack cb, long refCon);
|
|
|
|
|
static inline void GetData(soundInfoPtr s);
|
|
|
|
|
|
|
|
|
|
static vector<soundInfoHdl> sounds;
|
2003-06-24 08:44:02 +00:00
|
|
|
|
|
|
|
|
RageSound_QT::RageSound_QT() {
|
2003-08-04 11:32:30 +00:00
|
|
|
#if 1
|
2003-07-28 10:42:20 +00:00
|
|
|
RageException::ThrowNonfatal("Class not finished!");
|
2003-07-09 08:27:27 +00:00
|
|
|
#endif
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RageSound_QT::~RageSound_QT() {
|
2003-07-28 10:42:20 +00:00
|
|
|
LockMutex L(SOUNDMAN->lock);
|
|
|
|
|
while (!sounds.empty()) {
|
|
|
|
|
soundInfoHdl sHdl = sounds.back();
|
2003-08-04 11:22:33 +00:00
|
|
|
HLock(Handle(sHdl));
|
|
|
|
|
OSStatus err = MemError();
|
|
|
|
|
TEST_ERR(err, HLock);
|
2003-07-28 10:42:20 +00:00
|
|
|
soundInfoPtr s = *sHdl;
|
|
|
|
|
if (s->movie[0]) {
|
|
|
|
|
StopMovie(s->movie[0]);
|
|
|
|
|
DisposeMovie(s->movie[0]);
|
|
|
|
|
}
|
|
|
|
|
if (s->movie[1]) {
|
|
|
|
|
StopMovie(s->movie[1]);
|
|
|
|
|
DisposeMovie(s->movie[1]);
|
|
|
|
|
}
|
2003-08-04 11:22:33 +00:00
|
|
|
HUnlock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HUnlock);
|
2003-07-28 10:42:20 +00:00
|
|
|
DisposeHandle(Handle(sHdl));
|
2003-08-04 11:22:33 +00:00
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, DisposeHandle);
|
2003-07-28 10:42:20 +00:00
|
|
|
sounds.pop_back();
|
|
|
|
|
}
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageSound_QT::StartMixing(RageSound *snd) {
|
2003-07-28 10:42:20 +00:00
|
|
|
LockMutex L(SOUNDMAN->lock);
|
2003-08-04 11:22:33 +00:00
|
|
|
LOG->Trace("StartMixing()");
|
2003-07-28 10:42:20 +00:00
|
|
|
soundInfoHdl sHdl = (soundInfoHdl)NewHandle(sizeof(soundInfo));
|
2003-08-04 11:22:33 +00:00
|
|
|
OSStatus err = MemError();
|
|
|
|
|
TEST_ERR(err, NewHandle);
|
|
|
|
|
HLock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HLock);
|
2003-07-28 10:42:20 +00:00
|
|
|
soundInfoPtr s = *sHdl;
|
2003-07-09 08:27:27 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
s->fillme = 0;
|
|
|
|
|
s->movie[0] = NULL;
|
|
|
|
|
s->movie[1] = NULL;
|
|
|
|
|
s->stopPos = 0;
|
|
|
|
|
s->lastPos = 0;
|
|
|
|
|
s->snd = snd;
|
|
|
|
|
s->finishedBuffers = -1;
|
2003-08-04 11:22:33 +00:00
|
|
|
HUnlock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HUnlock);
|
2003-07-28 10:42:20 +00:00
|
|
|
sounds.push_back(sHdl);
|
2003-08-04 11:22:33 +00:00
|
|
|
CallBack(NULL, long(sHdl));
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageSound_QT::StopMixing(RageSound *snd) {
|
2003-07-28 10:42:20 +00:00
|
|
|
LockMutex L(SOUNDMAN->lock);
|
2003-08-04 11:22:33 +00:00
|
|
|
LOG->Trace("StopMixing");
|
2003-07-28 10:42:20 +00:00
|
|
|
unsigned size = sounds.size();
|
2003-06-24 08:44:02 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
for (unsigned i=0; i<size; ++i) {
|
|
|
|
|
soundInfoHdl sHdl = sounds[i];
|
2003-08-04 11:22:33 +00:00
|
|
|
HLock(Handle(sHdl));
|
|
|
|
|
OSStatus err = MemError();
|
|
|
|
|
TEST_ERR(err, HLock);
|
2003-07-28 10:42:20 +00:00
|
|
|
soundInfoPtr s = *sHdl;
|
2003-08-04 11:22:33 +00:00
|
|
|
if (s->snd != snd) {
|
|
|
|
|
HUnlock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HUnlock);
|
2003-07-28 10:42:20 +00:00
|
|
|
continue;
|
2003-08-04 11:22:33 +00:00
|
|
|
}
|
2003-07-28 10:42:20 +00:00
|
|
|
if (s->movie[0]) {
|
|
|
|
|
StopMovie(s->movie[0]);
|
|
|
|
|
DisposeMovie(s->movie[0]);
|
|
|
|
|
}
|
|
|
|
|
if (s->movie[1]) {
|
|
|
|
|
StopMovie(s->movie[1]);
|
|
|
|
|
DisposeMovie(s->movie[1]);
|
|
|
|
|
}
|
2003-08-04 11:22:33 +00:00
|
|
|
sounds.erase(sounds.begin()+i);
|
|
|
|
|
HUnlock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HUnlock);
|
2003-07-28 10:42:20 +00:00
|
|
|
DisposeHandle(Handle(sHdl));
|
2003-08-04 11:22:33 +00:00
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, DisposeHandle);
|
|
|
|
|
break;
|
2003-07-28 10:42:20 +00:00
|
|
|
}
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RageSound_QT::Update(float delta) {
|
|
|
|
|
#pragma unused (delta)
|
2003-07-28 10:42:20 +00:00
|
|
|
LockMutex L(SOUNDMAN->lock);
|
|
|
|
|
unsigned size = sounds.size();
|
|
|
|
|
vector<soundInfoHdl> snds = sounds;
|
2003-08-04 11:22:33 +00:00
|
|
|
OSErr err;
|
2003-06-24 08:44:02 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
for (unsigned i=0; i<size; ++i) {
|
2003-08-04 11:22:33 +00:00
|
|
|
soundInfoHdl sHdl = snds[i];
|
|
|
|
|
HLock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HLock);
|
|
|
|
|
soundInfoPtr s = *sHdl;
|
2003-07-28 10:42:20 +00:00
|
|
|
if ((s->movie[0] && !IsMovieDone(s->movie[0])) ||
|
2003-08-04 11:22:33 +00:00
|
|
|
(s->movie[1] && !IsMovieDone(s->movie[1]))) {
|
|
|
|
|
HUnlock(Handle(sHdl));
|
2003-07-28 10:42:20 +00:00
|
|
|
continue;
|
2003-08-04 11:22:33 +00:00
|
|
|
}
|
|
|
|
|
/* StopPlaying() will call StopMixing which will unlock and dispose of the handle */
|
2003-07-28 10:42:20 +00:00
|
|
|
s->snd->StopPlaying();
|
|
|
|
|
}
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int RageSound_QT::GetPosition(const RageSound *snd) const {
|
2003-07-28 10:42:20 +00:00
|
|
|
LockMutex L(SOUNDMAN->lock);
|
|
|
|
|
unsigned size = sounds.size();
|
|
|
|
|
/* Find the info */
|
|
|
|
|
for (unsigned i=0; i<size; ++i) {
|
2003-08-04 11:22:33 +00:00
|
|
|
soundInfoHdl sHdl = sounds[i];
|
|
|
|
|
HLock(Handle(sHdl));
|
|
|
|
|
OSStatus err = MemError();
|
|
|
|
|
TEST_ERR(err, HLock);
|
|
|
|
|
soundInfoPtr s = *sHdl;
|
|
|
|
|
if (s->snd != snd) {
|
|
|
|
|
HUnlock(Handle(sHdl));
|
2003-07-28 10:42:20 +00:00
|
|
|
continue;
|
2003-08-04 11:22:33 +00:00
|
|
|
}
|
|
|
|
|
if (s->finishedBuffers == -1) {
|
|
|
|
|
HUnlock(Handle(sHdl));
|
2003-07-28 10:42:20 +00:00
|
|
|
return 0; /* It hasn't started yet. */
|
2003-08-04 11:22:33 +00:00
|
|
|
}
|
2003-08-05 11:40:21 +00:00
|
|
|
int ret = s->finishedBuffers * samples + GetMovieTime(s->movie[s->fillme], NULL);
|
2003-08-04 11:22:33 +00:00
|
|
|
HUnlock(Handle(sHdl));
|
|
|
|
|
return ret;
|
2003-07-28 10:42:20 +00:00
|
|
|
}
|
|
|
|
|
RageException::Throw("Can't get the position of a sound that isn't playing");
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
|
|
|
|
|
2003-07-09 08:27:27 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
void CallBack(QTCallBack cb, long refCon) {
|
|
|
|
|
LockMutex L(SOUNDMAN->lock);
|
2003-08-04 11:22:33 +00:00
|
|
|
LOG->Trace("CallBack");
|
|
|
|
|
soundInfoHdl sHdl = soundInfoHdl(refCon);
|
|
|
|
|
HLock(Handle(sHdl));
|
|
|
|
|
OSStatus err = MemError();
|
|
|
|
|
TEST_ERR(err, HLock);
|
|
|
|
|
soundInfoPtr s = *sHdl;
|
2003-07-09 08:27:27 +00:00
|
|
|
|
2003-07-28 10:42:20 +00:00
|
|
|
s->finishedBuffers++;
|
|
|
|
|
if (!cb)
|
|
|
|
|
GetData(s);
|
2003-08-05 11:40:21 +00:00
|
|
|
else
|
|
|
|
|
DisposeCallBack(cb);
|
2003-07-28 10:42:20 +00:00
|
|
|
long playme = !s->fillme;
|
2003-08-04 11:22:33 +00:00
|
|
|
ASSERT(s->movie[playme]);
|
2003-07-28 10:42:20 +00:00
|
|
|
GoToBeginningOfMovie(s->movie[playme]);
|
|
|
|
|
StartMovie(s->movie[playme]);
|
2003-08-04 11:22:33 +00:00
|
|
|
err = GetMoviesError();
|
|
|
|
|
TEST_ERR(err, StartMovie);
|
2003-07-28 10:42:20 +00:00
|
|
|
if (s->stopPos == 0) {
|
|
|
|
|
/* Not stopping */
|
|
|
|
|
GetData(s);
|
|
|
|
|
QTCallBack callBack = NewCallBack(GetMovieTimeBase(s->movie[playme]), callBackAtExtremes);
|
2003-08-05 11:40:21 +00:00
|
|
|
CallMeWhen(callBack, CallBack, long(sHdl), triggerAtStop, triggerAtStop, triggerAtStop);
|
2003-07-28 10:42:20 +00:00
|
|
|
}
|
2003-08-04 11:22:33 +00:00
|
|
|
HUnlock(Handle(sHdl));
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, HUnlock);
|
|
|
|
|
|
2003-06-24 08:44:02 +00:00
|
|
|
}
|
2003-07-28 10:42:20 +00:00
|
|
|
|
|
|
|
|
inline void GetData(soundInfoPtr s) {
|
2003-08-04 11:22:33 +00:00
|
|
|
LOG->Trace("GetData");
|
|
|
|
|
char buffer[buffersize];
|
|
|
|
|
unsigned got = s->snd->GetPCM(buffer, buffersize, s->lastPos);
|
|
|
|
|
|
|
|
|
|
if (got < buffersize) {
|
|
|
|
|
s->stopPos = got / samplesize + s->lastPos;
|
|
|
|
|
if (got == 0)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
s->lastPos += samples;
|
|
|
|
|
|
|
|
|
|
OSErr err = noErr;
|
|
|
|
|
if (s->movie[s->fillme])
|
|
|
|
|
DisposeMovie(s->movie[s->fillme]);
|
|
|
|
|
|
|
|
|
|
s->movie[s->fillme] = NewMovie(newMovieActive);
|
|
|
|
|
err = GetMoviesError();
|
|
|
|
|
TEST_ERR(err, NewMovie);
|
|
|
|
|
SetMovieTimeScale(s->movie[s->fillme], freq);
|
|
|
|
|
err = GetMoviesError();
|
|
|
|
|
TEST_ERR(err, SetMovieTimeScale);
|
|
|
|
|
|
|
|
|
|
/* Put the sound data into a handle */
|
|
|
|
|
Handle sndHdl;
|
|
|
|
|
|
|
|
|
|
err = PtrToHand(buffer, &sndHdl, got);
|
|
|
|
|
TEST_ERR(err, PtrToHand);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Create the SoundDescription */
|
|
|
|
|
SoundDescriptionHandle sndDescHdl = (SoundDescriptionHandle)NewHandleClear(sizeof(SoundDescription));
|
|
|
|
|
|
|
|
|
|
err = MemError();
|
|
|
|
|
TEST_ERR(err, NewHandle);
|
|
|
|
|
{
|
|
|
|
|
SoundDescriptionPtr sndDescPtr = *sndDescHdl;
|
|
|
|
|
sndDescPtr->descSize = sizeof(SoundDescription);
|
|
|
|
|
sndDescPtr->dataFormat = k16BitBigEndianFormat;
|
|
|
|
|
sndDescPtr->numChannels = numchannels;
|
|
|
|
|
sndDescPtr->sampleSize = samplesize / numchannels;
|
|
|
|
|
sndDescPtr->sampleRate = freq << 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add data to media and then add media to track */
|
|
|
|
|
Handle dataRef;
|
|
|
|
|
|
|
|
|
|
PtrToHand(&sndHdl, &dataRef, sizeof(Handle));
|
|
|
|
|
LOG->Trace("Create new Track");
|
|
|
|
|
Track track = NewMovieTrack(s->movie[s->fillme], 0, 0, kFullVolume);
|
|
|
|
|
err = GetMoviesError();
|
|
|
|
|
TEST_ERR(err, NewMovieTrack);
|
|
|
|
|
ASSERT(track);
|
|
|
|
|
|
|
|
|
|
LOG->Trace("Create new Media");
|
|
|
|
|
Media media = NewTrackMedia(track, SoundMediaType, freq, dataRef, HandleDataHandlerSubType);
|
|
|
|
|
err = GetMoviesError();
|
|
|
|
|
TEST_ERR(err, NewTrackMedia);
|
|
|
|
|
ASSERT(media);
|
|
|
|
|
|
|
|
|
|
LOG->Trace("BeginMediaEdits");
|
|
|
|
|
err = BeginMediaEdits(media);
|
|
|
|
|
TEST_ERR(err, BeginMediaEdits);
|
|
|
|
|
err = AddMediaSample(media, sndHdl, 0, got, 1, (SampleDescriptionHandle)sndDescHdl,
|
|
|
|
|
samples, 0, NULL);
|
|
|
|
|
TEST_ERR(err, AddMediaSample);
|
|
|
|
|
err = EndMediaEdits(media);
|
|
|
|
|
TEST_ERR(err, EndMediaEdits);
|
|
|
|
|
err = InsertMediaIntoTrack(track, 0, 0, GetMediaDuration(media), 0x00010000);
|
|
|
|
|
TEST_ERR(err, InsertMediaIntoTrack);
|
|
|
|
|
if (sndDescHdl)
|
|
|
|
|
DisposeHandle(Handle(sndDescHdl));
|
|
|
|
|
s->fillme = !s->fillme;
|
2003-07-28 10:42:20 +00:00
|
|
|
}
|
|
|
|
|
|