Not quite working but I can work out a bug or two it _should_ play back the audio much better for computers that support multitple channels (I assume that they all can!) and it should play the same for those computers that don't support it.
Right now I'm getting an error of -223 from the bufferCmd but I haven't figured out what the hell that actually is. If you want a working sound driver for OS X, just use the previous version of these files.
This commit is contained in:
@@ -19,184 +19,410 @@ using namespace QT;
|
||||
|
||||
const unsigned channels = 2;
|
||||
const unsigned samplesize = channels*16;
|
||||
const unsigned samples = 512;
|
||||
const unsigned samples = 4096;
|
||||
const unsigned freq = 44100;
|
||||
const unsigned buffersize = samples*samplesize/8;
|
||||
const unsigned initialQTSoundChannels = 8;
|
||||
const unsigned SndCommand_qLength = 2;
|
||||
|
||||
static ComponentInstance soundClock;
|
||||
static bool useMultipleChannels;
|
||||
|
||||
/* Oh boy! dealing with memory at inturupt time. What fun! */
|
||||
#pragma options align=power
|
||||
static volatile Uint32 fill_me = 0;
|
||||
static UInt8 *buffer[2];
|
||||
static CmpSoundHeader header;
|
||||
struct channelInfo {
|
||||
RageSound *snd;
|
||||
volatile bool stopping;
|
||||
volatile int last_pos;
|
||||
volatile int flush_pos;
|
||||
volatile Uint64 start_time;
|
||||
volatile Uint32 fill_me;
|
||||
SndChannelPtr channel;
|
||||
CmpSoundHeader header;
|
||||
Uint8 *buffer[2]; /* Double Buffer */
|
||||
channelInfo() { snd=NULL; channel=NULL; }
|
||||
void reset() { stopping=false; flush_pos=0; last_pos=0; start_time=0; fill_me=0; }
|
||||
};
|
||||
|
||||
static deque<channelInfo *>free_channels;
|
||||
static vector<channelInfo *>playing_channels;
|
||||
|
||||
RageSound_QT::RageSound_QT() {
|
||||
SndCallBackUPP callback;
|
||||
callback = NewSndCallBackUPP(GetData);
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.numChannels = channels;
|
||||
header.sampleSize = samplesize / channels;
|
||||
header.sampleRate = rate44khz; /* really 44.1kHz */
|
||||
header.numFrames = samples;
|
||||
header.encode = cmpSH;
|
||||
useMultipleChannels = canPlayMultiChannels();
|
||||
LOG->Trace("Can we use multiple channels? %s", (useMultipleChannels ? "yes" : "no"));
|
||||
soundOutput = OpenDefaultComponent(kSoundOutputDeviceType, NULL);
|
||||
ASSERT(soundOutput != NULL);
|
||||
TimeRecord record;
|
||||
ComponentInstance soundOutput;
|
||||
SoundComponentGetInfo(soundOutput, NULL, siOutputLatency, &record);
|
||||
latency = record.value.lo / record.scale;
|
||||
if (!useMultipleChannels)
|
||||
latency += samples / freq; /* double buffer */
|
||||
|
||||
buffer[0] = new Uint8[buffersize];
|
||||
buffer[1] = new Uint8[buffersize];
|
||||
memset(buffer[0], 0, buffersize);
|
||||
memset(buffer[1], 0, buffersize);
|
||||
SndCallBackUPP callback = NewSndCallBackUPP(GetData);
|
||||
|
||||
channel = new SndChannel;
|
||||
channel->userInfo = reinterpret_cast<long>(this);
|
||||
channel->qLength = 2;
|
||||
soundClock = NULL;
|
||||
SndChannelPtr chan = NULL;
|
||||
SndCommand cmd;
|
||||
OSErr err;
|
||||
Uint8 *zero = NULL;
|
||||
Uint8 *one = NULL;
|
||||
|
||||
soundOutput = OpenDefaultComponent(kSoundOutputDeviceType, NULL);
|
||||
ASSERT(soundOutput != NULL);
|
||||
for (unsigned i=0; i<initialQTSoundChannels; ++i) {
|
||||
channelInfo *info = new channelInfo;
|
||||
|
||||
TimeRecord record;
|
||||
SoundComponentGetInfo(soundOutput, NULL, siOutputLatency, &record);
|
||||
latency = record.value.lo / record.scale;
|
||||
latency += samples / freq; /* double buffer */
|
||||
memset(&info->header, 0, sizeof(&info->header));
|
||||
info->header.numChannels = channels;
|
||||
info->header.sampleSize = samplesize / channels;
|
||||
info->header.sampleRate = rate44khz; /* really 44.1kHz */
|
||||
info->header.numFrames = samples;
|
||||
info->header.encode = cmpSH;
|
||||
|
||||
OSErr err = SndNewChannel(&channel, sampledSynth, initStereo, callback);
|
||||
if (useMultipleChannels || zero == NULL) {
|
||||
zero = new Uint8[buffersize];
|
||||
one = new Uint8[buffersize];
|
||||
memset(zero, 0, buffersize);
|
||||
memset(one, 0, buffersize);
|
||||
}
|
||||
info->buffer[0] = zero;
|
||||
info->buffer[1] = one;
|
||||
|
||||
if (err != noErr) {
|
||||
delete channel;
|
||||
channel = NULL;
|
||||
RageException::ThrowNonfatal("Unable to create audio channel");
|
||||
}
|
||||
if (useMultipleChannels || chan == NULL) {
|
||||
chan = new SndChannel;
|
||||
chan->userInfo = reinterpret_cast<long>(info);
|
||||
chan->qLength = SndCommand_qLength;
|
||||
err = SndNewChannel(&chan, sampledSynth, initStereo, callback);
|
||||
if (err != noErr) {
|
||||
SAFE_DELETE(info->channel);
|
||||
RageException::ThrowNonfatal("Unable to create audio channel. THIS IS A BUG!");
|
||||
}
|
||||
}
|
||||
info->channel = chan;
|
||||
|
||||
SndCommand cmd;
|
||||
cmd.cmd = clockComponentCmd;
|
||||
cmd.param1 = true;
|
||||
cmd.param2 = 0;
|
||||
err |= SndDoImmediate(channel, &cmd);
|
||||
if (!soundClock) {
|
||||
cmd.cmd = clockComponentCmd;
|
||||
cmd.param1 = true;
|
||||
cmd.param2 = 0;
|
||||
err |= SndDoImmediate(info->channel, &cmd);
|
||||
|
||||
cmd.cmd = getClockComponentCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = reinterpret_cast<long>(&clock);
|
||||
err |= SndDoImmediate(channel, &cmd);
|
||||
last_pos = 0;
|
||||
|
||||
cmd.cmd = callBackCmd;
|
||||
cmd.param2 = 0;
|
||||
err |= SndDoCommand(channel, &cmd, false);
|
||||
cmd.cmd = getClockComponentCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = reinterpret_cast<long>(&soundClock);
|
||||
err |= SndDoImmediate(info->channel, &cmd);
|
||||
}
|
||||
|
||||
if (err != noErr)
|
||||
RageException::ThrowNonfatal("Unable to create audio channel");
|
||||
if (err != noErr)
|
||||
RageException::ThrowNonfatal("Unable to create audio channel. THIS IS A BUG!");
|
||||
free_channels.push_back(info);
|
||||
}
|
||||
|
||||
ASSERT(free_channels.size() == initialQTSoundChannels);
|
||||
playing_channels.reserve(initialQTSoundChannels);
|
||||
if (!useMultipleChannels) { /* start the callbacks */
|
||||
cmd.cmd = callBackCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = 0;
|
||||
err |= SndDoCommand(chan, &cmd, false);
|
||||
}
|
||||
}
|
||||
|
||||
RageSound_QT::~RageSound_QT() {
|
||||
if (channel)
|
||||
SndDisposeChannel(channel, true);
|
||||
SAFE_DELETE_ARRAY(buffer[0]);
|
||||
SAFE_DELETE_ARRAY(buffer[1]);
|
||||
if (soundOutput)
|
||||
CloseComponent(soundOutput);
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
int size = playing_channels.size();
|
||||
|
||||
for (int i=0; i<size; ++i) {
|
||||
channelInfo *info = playing_channels.back();
|
||||
|
||||
playing_channels.pop_back();
|
||||
if (info->channel)
|
||||
SndDisposeChannel(info->channel, true);
|
||||
SAFE_DELETE_ARRAY(info->buffer[0]);
|
||||
SAFE_DELETE_ARRAY(info->buffer[1]);
|
||||
}
|
||||
|
||||
size = free_channels.size();
|
||||
for (int i=0; i<size; ++i) {
|
||||
channelInfo *info = free_channels.back();
|
||||
|
||||
free_channels.pop_back();
|
||||
if (info->channel)
|
||||
SndDisposeChannel(info->channel, true);
|
||||
SAFE_DELETE_ARRAY(info->buffer[0]);
|
||||
SAFE_DELETE_ARRAY(info->buffer[1]);
|
||||
if (!useMultipleChannels)
|
||||
break;
|
||||
}
|
||||
|
||||
if (soundOutput)
|
||||
CloseComponent(soundOutput);
|
||||
if (soundClock)
|
||||
CloseComponent(soundClock);
|
||||
}
|
||||
|
||||
void RageSound_QT::GetData(SndChannel *chan, SndCommand *cmd_passed) {
|
||||
while (!SOUNDMAN)
|
||||
SDL_Delay(10);
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
static SoundMixBuffer mix;
|
||||
RageSound_QT *P = reinterpret_cast<RageSound_QT *>(chan->userInfo);
|
||||
void RageSound_QT::GetData(SndChannelPtr chan, SndCommand *cmd_passed) {
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
register OSErr err = noErr;
|
||||
static bool gettingData=false;
|
||||
static int recursiveCalls = 0;
|
||||
if (gettingData) {
|
||||
LOG->Warn( "GetData() called recursively %D times.", ++recursiveCalls);
|
||||
if (recursiveCalls >=10)
|
||||
RageException::Throw("GetData() called recursively too many times.");
|
||||
} else
|
||||
recursiveCalls = 0;
|
||||
gettingData=true;
|
||||
channelInfo *info = reinterpret_cast<channelInfo *>(chan->userInfo);
|
||||
ASSERT(info);
|
||||
LOG->Trace("GetData() sound 0x%X", reinterpret_cast<long>(info->snd));
|
||||
SndCommand cmd;
|
||||
register UInt32 play_me;
|
||||
|
||||
fill_me = cmd_passed->param2;
|
||||
UInt32 play_me = !fill_me;
|
||||
if (cmd_passed != NULL) {
|
||||
info->fill_me = cmd_passed->param2;
|
||||
play_me = !info->fill_me;
|
||||
info->header.samplePtr = reinterpret_cast<Ptr>(info->buffer[play_me]);
|
||||
cmd.cmd = bufferCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = reinterpret_cast<long>(&info->header);
|
||||
LOG->Trace("Sending bufferCmd sound 0x%X", reinterpret_cast<long>(info->snd));
|
||||
err = SndDoCommand(chan, &cmd, false);
|
||||
if (err != noErr)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (!P->last_pos){
|
||||
TimeRecord tr;
|
||||
ClockGetTime(P->clock, &tr);
|
||||
UInt64 temp = tr.value.hi;
|
||||
temp <<= 32;
|
||||
temp |= tr.value.lo;
|
||||
double d = static_cast<double>(temp)/tr.scale*freq;
|
||||
temp = static_cast<UInt64>(d);
|
||||
P->last_pos = static_cast<UInt32>(temp % 0x00000000FFFFFFFFLL);
|
||||
} else
|
||||
P->last_pos += samples;
|
||||
if (info->stopping){
|
||||
LOG->Trace("Stopping");
|
||||
return; /* We're done */
|
||||
}
|
||||
|
||||
/* Swap buffers */
|
||||
header.samplePtr = reinterpret_cast<Ptr>(buffer[play_me]);
|
||||
SndCommand cmd;
|
||||
cmd.cmd = bufferCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = reinterpret_cast<long>(&header);
|
||||
SndDoCommand(chan, &cmd, 0);
|
||||
/* Clear the fill buffer */
|
||||
memset(info->buffer[info->fill_me], 0, buffersize);
|
||||
|
||||
/* Clear the fill buffer */
|
||||
memset(buffer[fill_me], 0, buffersize);
|
||||
|
||||
for (unsigned i=0; i<P->sounds.size(); ++i) {
|
||||
if (P->sounds[i]->stopping)
|
||||
continue;
|
||||
if (useMultipleChannels) {
|
||||
if (!info->last_pos){
|
||||
TimeRecord tr;
|
||||
ClockGetTime(soundClock, &tr);
|
||||
info->start_time = tr.value.hi;
|
||||
info->start_time <<= 32;
|
||||
info->start_time |= tr.value.lo;
|
||||
}
|
||||
|
||||
unsigned got = P->sounds[i]->snd->GetPCM(reinterpret_cast<char *>(buffer[fill_me]), buffersize, P->last_pos);
|
||||
mix.write(reinterpret_cast<SInt16 *>(buffer[fill_me]), got / 2);
|
||||
if (got < buffersize) {
|
||||
P->sounds[i]->stopping = true;
|
||||
P->sounds[i]->flush_pos = P->last_pos + (got / samplesize / 8);
|
||||
}
|
||||
}
|
||||
LOG->Trace("About to GetPCM() sound 0x%X", reinterpret_cast<long>(info->snd));
|
||||
register int got = info->snd->GetPCM(reinterpret_cast<char *>(info->buffer[info->fill_me]), buffersize, info->last_pos);
|
||||
LOG->Trace("Got %D bytes", got);
|
||||
if (static_cast<unsigned>(got) < buffersize) {
|
||||
info->stopping = true;
|
||||
info->flush_pos = info->last_pos + (got * 8 / samplesize); /* (got / (samplesize / 8)) */
|
||||
}
|
||||
info->last_pos += samples;
|
||||
} else {
|
||||
static SoundMixBuffer mix;
|
||||
register int size = playing_channels.size();
|
||||
for (int i=0; i<size; ++i) {
|
||||
channelInfo *info2 = playing_channels[i];
|
||||
if (!info2->last_pos){
|
||||
TimeRecord tr;
|
||||
ClockGetTime(soundClock, &tr);
|
||||
info2->start_time = tr.value.hi;
|
||||
info2->start_time <<= 32;
|
||||
info2->start_time |= tr.value.lo;
|
||||
}
|
||||
|
||||
mix.read(reinterpret_cast<SInt16 *>(buffer[fill_me]));
|
||||
LOG->Trace("About to GetPCM() sound 0x%X", reinterpret_cast<long>(info2->snd));
|
||||
register int got = info2->snd->GetPCM(reinterpret_cast<char *>(info->buffer[info->fill_me]), buffersize, info2->last_pos);
|
||||
LOG->Trace("Got %D bytes", got);
|
||||
if (static_cast<unsigned>(got) < buffersize) {
|
||||
info2->stopping = true;
|
||||
info2->flush_pos = info2->last_pos + (got * 8 / samplesize);
|
||||
}
|
||||
mix.write(reinterpret_cast<Sint16 *>(info->buffer[info->fill_me]), got / 2);
|
||||
info2->last_pos += samples;
|
||||
}
|
||||
mix.read(reinterpret_cast<Sint16 *>(info->buffer[info->fill_me]));
|
||||
}
|
||||
|
||||
cmd.cmd = callBackCmd;
|
||||
cmd.param2 = play_me;
|
||||
SndDoCommand(chan, &cmd, 0);
|
||||
if (cmd_passed != NULL) {
|
||||
cmd.cmd = callBackCmd;
|
||||
cmd.param2 = play_me;
|
||||
LOG->Trace("Sending callBackCmd sound 0x%X", reinterpret_cast<long>(info->snd));
|
||||
err = SndDoCommand(chan, &cmd, false);
|
||||
if (err != noErr)
|
||||
goto bail;
|
||||
}
|
||||
gettingData=false;
|
||||
return;
|
||||
|
||||
bail:
|
||||
RageException::Throw("SndDoCommand failed with error %d", err);
|
||||
}
|
||||
|
||||
|
||||
void RageSound_QT::StartMixing(RageSound *snd) {
|
||||
sound *s = new sound;
|
||||
s->snd = snd;
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
LOG->Trace("StartMixing(). Mixing sound 0x%X", reinterpret_cast<long>(snd));
|
||||
SndCommand cmd;
|
||||
channelInfo *info;
|
||||
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
sounds.push_back(s);
|
||||
if (free_channels.size()) {
|
||||
info = free_channels.front();
|
||||
free_channels.pop_front();
|
||||
} else { /* No free audio channels, create another */
|
||||
LOG->Warn("Out of audio channels, creating channel number %D", playing_channels.size()+1);
|
||||
info = new channelInfo;
|
||||
|
||||
memset(&info->header, 0, sizeof(&info->header));
|
||||
info->header.numChannels = channels;
|
||||
info->header.sampleSize = samplesize / channels;
|
||||
info->header.sampleRate = rate44khz; /* really 44.1kHz */
|
||||
info->header.numFrames = samples;
|
||||
info->header.encode = cmpSH;
|
||||
|
||||
info->buffer[0] = new Uint8[buffersize];
|
||||
info->buffer[1] = new Uint8[buffersize];
|
||||
memset(info->buffer[0], 0, buffersize);
|
||||
memset(info->buffer[1], 0, buffersize);
|
||||
|
||||
if (useMultipleChannels) {
|
||||
info->channel = new SndChannel;
|
||||
info->channel->userInfo = reinterpret_cast<long>(info);
|
||||
info->channel->qLength = SndCommand_qLength;
|
||||
register OSErr err = SndNewChannel(&(info->channel), sampledSynth, initStereo, NewSndCallBackUPP(GetData));
|
||||
|
||||
if (err != noErr) {
|
||||
SAFE_DELETE(info->channel);
|
||||
RageException::Throw("Unable to create audio channel. THIS IS A BUG.");
|
||||
}
|
||||
}
|
||||
}
|
||||
info->reset();
|
||||
info->snd = snd;
|
||||
/* Fill the first buffer with data */
|
||||
playing_channels.push_back(info);
|
||||
if (useMultipleChannels) {
|
||||
GetData(info->channel, NULL);
|
||||
cmd.cmd = callBackCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = !info->fill_me;
|
||||
SndDoCommand(info->channel, &cmd, 0); /* command queue is empty */
|
||||
}
|
||||
}
|
||||
|
||||
void RageSound_QT::StopMixing(RageSound *snd) {
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
LOG->Trace("StopMixing(). Stopping sound 0x%X", reinterpret_cast<long>(snd));
|
||||
/* Find the sound. */
|
||||
int size = playing_channels.size();
|
||||
int i;
|
||||
channelInfo *info;
|
||||
|
||||
/* Find the sound. */
|
||||
unsigned i;
|
||||
for(i = 0; i < sounds.size(); ++i)
|
||||
if(sounds[i]->snd == snd) break;
|
||||
if(i == sounds.size())
|
||||
{
|
||||
LOG->Trace("not stopping a sound because it's not playing");
|
||||
return;
|
||||
}
|
||||
for (i=0; i<=size; ++i)
|
||||
if ((info=playing_channels[i])->snd == snd)
|
||||
break;
|
||||
if (i==size) {
|
||||
LOG->Trace("Not stopping a sound because it's not playing.");
|
||||
return;
|
||||
}
|
||||
|
||||
delete sounds[i];
|
||||
sounds.erase(sounds.begin()+i, sounds.begin()+i+1);
|
||||
playing_channels.erase(playing_channels.begin()+i);
|
||||
if (useMultipleChannels) {
|
||||
SndCommand cmd;
|
||||
cmd.cmd = flushCmd;
|
||||
cmd.param1 = 0;
|
||||
cmd.param2 = 0;
|
||||
LOG->Trace("Flushing channel with song %X", reinterpret_cast<long>(snd));
|
||||
SndDoImmediate(info->channel, &cmd);
|
||||
cmd.cmd = quietCmd;
|
||||
SndDoImmediate(info->channel, &cmd);
|
||||
}
|
||||
free_channels.push_back(info);
|
||||
}
|
||||
|
||||
void RageSound_QT::Update(float delta) {
|
||||
#pragma unused (delta)
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
|
||||
vector<sound *>snds = sounds;
|
||||
for (unsigned i = 0; i < snds.size(); ++i) {
|
||||
if (!sounds[i]->stopping)
|
||||
continue;
|
||||
if (GetPosition(snds[i]->snd) < sounds[i]->flush_pos)
|
||||
continue;
|
||||
snds[i]->snd->StopPlaying();
|
||||
}
|
||||
vector<channelInfo *> playing = playing_channels;
|
||||
int size = playing.size();
|
||||
for (int i=0; i<size; ++i) {
|
||||
channelInfo *info = playing[i];
|
||||
if (info->stopping != 0)
|
||||
continue;
|
||||
if (GetPosition(info->snd) < info->flush_pos)
|
||||
continue;
|
||||
info->snd->StopPlaying();
|
||||
}
|
||||
}
|
||||
|
||||
int RageSound_QT::GetPosition(const RageSound *snd) const {
|
||||
#pragma unused (snd)
|
||||
TimeRecord tr;
|
||||
ClockGetTime(clock, &tr);
|
||||
UInt64 temp = tr.value.hi;
|
||||
temp <<= 32;
|
||||
temp |= tr.value.lo;
|
||||
double d = static_cast<double>(temp)/tr.scale*freq;
|
||||
temp = static_cast<UInt64>(d);
|
||||
return static_cast<UInt32>(temp % 0x00000000FFFFFFFFLL);
|
||||
LockMutex L(SOUNDMAN->lock);
|
||||
TimeRecord tr;
|
||||
ClockGetTime(soundClock, &tr);
|
||||
UInt64 time = tr.value.hi;
|
||||
time <<= 32;
|
||||
time |= tr.value.lo;
|
||||
|
||||
/* Find the info */
|
||||
register int size = playing_channels.size();
|
||||
register int i;
|
||||
channelInfo *info;
|
||||
for (i=0; i<size; ++i)
|
||||
if ((info = playing_channels[i])->snd == snd)
|
||||
break;
|
||||
if (i == size)
|
||||
RageException::Throw("Can't get the position of a sound that isn't playing");
|
||||
|
||||
LOG->Trace("GetPosition() sound 0x%X", reinterpret_cast<long>(snd));
|
||||
|
||||
time -= info->start_time; /* Now time contains the total time the sound was played. */
|
||||
time = time * freq / tr.scale; /* Now time contains the number of samples played. */
|
||||
return static_cast<int>(time % 0x00000000FFFFFFFFLL);
|
||||
}
|
||||
|
||||
float RageSound_QT::GetPlayLatency() const {
|
||||
return latency;
|
||||
return latency;
|
||||
}
|
||||
|
||||
|
||||
/* Pascal code from SoundManager docs.
|
||||
|
||||
FUNCTION MyCanPlayMultiChannels: Boolean;
|
||||
VAR
|
||||
myResponse: LongInt;
|
||||
myResult: Boolean;
|
||||
myErr: OSErr;
|
||||
myVersion: NumVersion;
|
||||
BEGIN
|
||||
myResult := FALSE;
|
||||
myVersion := SndSoundManagerVersion;
|
||||
myErr := Gestalt(gestaltSoundAttr, myResponse);
|
||||
IF myVersion.majorRev >= 3 THEN
|
||||
IF (myErr = noErr) AND (BTst(myResponse, gestaltMultiChannels)) THEN
|
||||
myResult := TRUE
|
||||
ELSE
|
||||
BEGIN
|
||||
myErr := Gestalt(gestaltHardwareAttr, myResponse);
|
||||
IF (myErr = noErr) AND (BTst(myResponse, gestaltHasASC)) THEN
|
||||
myResult := TRUE
|
||||
END;
|
||||
MyCanPlayMultiChannels := myResult;
|
||||
END;
|
||||
*/
|
||||
|
||||
bool canPlayMultiChannels(){
|
||||
register long response;
|
||||
register OSErr err;
|
||||
NumVersion version;
|
||||
register bool result;
|
||||
|
||||
result = false;
|
||||
version = SndSoundManagerVersion();
|
||||
err = Gestalt(gestaltSoundAttr, &response);
|
||||
if (version.majorRev >= 3){
|
||||
if((err == noErr) && (response & gestaltMultiChannels == gestaltMultiChannels))
|
||||
result = true;
|
||||
} else {
|
||||
err = Gestalt(gestaltHardwareAttr, &response);
|
||||
if ((err == noErr) && (response & gestaltHasASC == gestaltHasASC))
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Copyright (c) 2003 Steve Checkoway. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "global.h"
|
||||
/* ugh, what a hack! QT includes Carbon/Carbon.h which
|
||||
* has defs for a few things defined in RageUtil.h which
|
||||
* is included in arch.cpp along w/ (eventually) this.
|
||||
@@ -18,23 +18,13 @@
|
||||
namespace QT {
|
||||
#include <QuickTime/QuickTime.h>
|
||||
}
|
||||
|
||||
#include "RageSound.h"
|
||||
#include "RageSoundDriver.h"
|
||||
|
||||
class RageSound_QT: public RageSoundDriver {
|
||||
private:
|
||||
struct sound {
|
||||
RageSound *snd;
|
||||
bool stopping;
|
||||
int flush_pos;
|
||||
sound() { snd=NULL; stopping=false; flush_pos=0; }
|
||||
};
|
||||
|
||||
vector<sound *> sounds;
|
||||
QT::ComponentInstance clock;
|
||||
QT::ComponentInstance soundOutput;
|
||||
QT::SndChannelPtr channel;
|
||||
int last_pos;
|
||||
float latency;
|
||||
|
||||
protected:
|
||||
@@ -50,5 +40,7 @@ public:
|
||||
static void GetData(QT::SndChannel *chan, QT::SndCommand *cmd_passed);
|
||||
};
|
||||
|
||||
bool canPlayMultiChannels();
|
||||
|
||||
#endif /* RAGE_SOUND_QT */
|
||||
|
||||
Reference in New Issue
Block a user