Files
itgmania212121/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp
T

299 lines
8.2 KiB
C++
Raw Normal View History

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
const unsigned numchannels = 2;
const unsigned samplesize = 16 * numchannels;
2003-08-05 11:40:21 +00:00
const unsigned samples = 40960;
const unsigned freq = 44100;
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() {
#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();
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]);
}
HUnlock(Handle(sHdl));
err = MemError();
TEST_ERR(err, HUnlock);
2003-07-28 10:42:20 +00:00
DisposeHandle(Handle(sHdl));
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);
LOG->Trace("StartMixing()");
2003-07-28 10:42:20 +00:00
soundInfoHdl sHdl = (soundInfoHdl)NewHandle(sizeof(soundInfo));
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;
HUnlock(Handle(sHdl));
err = MemError();
TEST_ERR(err, HUnlock);
2003-07-28 10:42:20 +00:00
sounds.push_back(sHdl);
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);
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];
HLock(Handle(sHdl));
OSStatus err = MemError();
TEST_ERR(err, HLock);
2003-07-28 10:42:20 +00:00
soundInfoPtr s = *sHdl;
if (s->snd != snd) {
HUnlock(Handle(sHdl));
err = MemError();
TEST_ERR(err, HUnlock);
2003-07-28 10:42:20 +00:00
continue;
}
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]);
}
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));
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;
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) {
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])) ||
(s->movie[1] && !IsMovieDone(s->movie[1]))) {
HUnlock(Handle(sHdl));
2003-07-28 10:42:20 +00:00
continue;
}
/* 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) {
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;
}
if (s->finishedBuffers == -1) {
HUnlock(Handle(sHdl));
2003-07-28 10:42:20 +00:00
return 0; /* It hasn't started yet. */
}
2003-08-05 11:40:21 +00:00
int ret = s->finishedBuffers * samples + GetMovieTime(s->movie[s->fillme], NULL);
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);
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;
ASSERT(s->movie[playme]);
2003-07-28 10:42:20 +00:00
GoToBeginningOfMovie(s->movie[playme]);
StartMovie(s->movie[playme]);
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
}
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) {
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
}