Simplify
This commit is contained in:
@@ -1,63 +0,0 @@
|
||||
#include "global.h"
|
||||
#include "RageSoundDriver_CA.h"
|
||||
#include "CAHelpers.h"
|
||||
|
||||
AudioConverter::AudioConverter( RageSound_CA *driver, const Desc &procFormat )
|
||||
: mBuffer(NULL), mBufferSize(0)
|
||||
{
|
||||
const Desc SMFormat(44100.0, kAudioFormatLinearPCM, kBytesPerPacket,
|
||||
kFramesPerPacket, kBytesPerFrame, kChannelsPerFrame,
|
||||
kBitsPerChannel, kFormatFlags);
|
||||
|
||||
SMFormat.Print();
|
||||
procFormat.Print();
|
||||
|
||||
if( this->Initialize(SMFormat, procFormat) )
|
||||
RageException::ThrowNonfatal( "Couldn't create the converter." );
|
||||
|
||||
mDriver = driver;
|
||||
}
|
||||
|
||||
OSStatus AudioConverter::FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
||||
AudioBufferList& ioData,
|
||||
AudioStreamPacketDescription **outDesc)
|
||||
{
|
||||
AudioBuffer& buf = ioData.mBuffers[0];
|
||||
|
||||
if( mBufferSize < buf.mDataByteSize )
|
||||
{
|
||||
delete [] mBuffer;
|
||||
mBuffer = new UInt8[buf.mDataByteSize];
|
||||
mBufferSize = buf.mDataByteSize;
|
||||
}
|
||||
buf.mData = mBuffer;
|
||||
|
||||
const int frames = buf.mDataByteSize / kBytesPerPacket;
|
||||
mDriver->FillConverter( buf.mData, frames );
|
||||
return noErr;
|
||||
}
|
||||
|
||||
/*
|
||||
* (c) 2004 Steve Checkoway
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||
* whom the Software is furnished to do so, provided that the above
|
||||
* copyright notice(s) and this permission notice appear in all copies of
|
||||
* the Software and that both the above copyright notice(s) and this
|
||||
* permission notice appear in supporting documentation.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
@@ -1,58 +0,0 @@
|
||||
#ifndef CA_HELPERS_H
|
||||
#define CA_HELPERS_H
|
||||
|
||||
#include "FormatConverterClient.h"
|
||||
#include "CAStreamBasicDescription.h"
|
||||
|
||||
static const UInt32 kFramesPerPacket = 1;
|
||||
static const UInt32 kChannelsPerFrame = 2;
|
||||
static const UInt32 kBitsPerChannel = 16;
|
||||
static const UInt32 kBytesPerPacket = kChannelsPerFrame * kBitsPerChannel / 8;
|
||||
static const UInt32 kBytesPerFrame = kBytesPerPacket;
|
||||
static const UInt32 kFormatFlags = kAudioFormatFlagsNativeEndian |
|
||||
kAudioFormatFlagIsSignedInteger;
|
||||
|
||||
typedef CAStreamBasicDescription Desc;
|
||||
|
||||
class AudioConverter : public FormatConverterClient
|
||||
{
|
||||
public:
|
||||
AudioConverter( RageSound_CA *driver, const Desc &procFormat );
|
||||
~AudioConverter() { delete [] mBuffer; }
|
||||
protected:
|
||||
OSStatus FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
||||
AudioBufferList& ioData,
|
||||
AudioStreamPacketDescription **outDesc);
|
||||
private:
|
||||
RageSound_CA *mDriver;
|
||||
UInt8 *mBuffer;
|
||||
UInt32 mBufferSize;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* (c) 2004 Steve Checkoway
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, and/or sell copies of the Software, and to permit persons to
|
||||
* whom the Software is furnished to do so, provided that the above
|
||||
* copyright notice(s) and this permission notice appear in all copies of
|
||||
* the Software and that both the above copyright notice(s) and this
|
||||
* permission notice appear in supporting documentation.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
||||
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
||||
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
||||
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "global.h"
|
||||
#include "RageUtil.h"
|
||||
#include "RageSoundDriver_CA.h"
|
||||
#include "CAHelpers.h"
|
||||
#include "RageLog.h"
|
||||
#include "RageTimer.h"
|
||||
|
||||
#include <AudioToolbox/AudioConverter.h>
|
||||
#include "CAAudioHardwareSystem.h"
|
||||
#include "CAAudioHardwareDevice.h"
|
||||
#include "CAAudioHardwareStream.h"
|
||||
@@ -15,7 +15,16 @@
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_error.h>
|
||||
|
||||
static AudioConverter *gConverter = NULL;
|
||||
static const UInt32 kFramesPerPacket = 1;
|
||||
static const UInt32 kChannelsPerFrame = 2;
|
||||
static const UInt32 kBitsPerChannel = 16;
|
||||
static const UInt32 kBytesPerPacket = kChannelsPerFrame * kBitsPerChannel / 8;
|
||||
static const UInt32 kBytesPerFrame = kBytesPerPacket;
|
||||
static const UInt32 kFormatFlags = kAudioFormatFlagsNativeEndian |
|
||||
kAudioFormatFlagIsSignedInteger;
|
||||
|
||||
typedef CAStreamBasicDescription Desc;
|
||||
|
||||
|
||||
/* temporary hack: */
|
||||
static float g_fLastIOProcTime = 0;
|
||||
@@ -40,79 +49,8 @@ static CString FormatToString( int fmt )
|
||||
return ssprintf( "%c%c%c%c", c[0], c[1], c[2], c[3] );
|
||||
}
|
||||
|
||||
static Desc FindClosestFormat(const vector<Desc>& formats,
|
||||
RageSound_CA::format& type)
|
||||
{
|
||||
vector<Desc> v;
|
||||
|
||||
vector<Desc>::const_iterator i;
|
||||
for (i = formats.begin(); i != formats.end(); ++i)
|
||||
{
|
||||
const Desc& format = *i;
|
||||
|
||||
if( !format.IsPCM() )
|
||||
continue;
|
||||
|
||||
if( format.mSampleRate != 0. && format.mSampleRate != 44100.0 )
|
||||
continue;
|
||||
|
||||
if (format.SampleWordSize() == 2 &&
|
||||
(format.mFormatFlags & kFormatFlags) == kFormatFlags)
|
||||
{ // exact match
|
||||
type = RageSound_CA::EXACT;
|
||||
return format;
|
||||
}
|
||||
v.push_back(format);
|
||||
}
|
||||
|
||||
const Desc CanonicalFormat(44100.0, kAudioFormatLinearPCM, 8, 1, 8, 2, 32,
|
||||
kAudioFormatFlagsNativeFloatPacked);
|
||||
|
||||
for (i = v.begin(); i != v.end(); ++i)
|
||||
{
|
||||
const Desc& format = *i;
|
||||
|
||||
if (format == CanonicalFormat)
|
||||
{
|
||||
type = RageSound_CA::CANONICAL;
|
||||
return format;
|
||||
}
|
||||
}
|
||||
if (v.empty())
|
||||
RageException::ThrowNonfatal("Couldn't find a close format.");
|
||||
type = RageSound_CA::OTHER;
|
||||
return v[0]; // something is better than nothing.
|
||||
}
|
||||
|
||||
static void GetIOProcFormats( CAAudioHardwareStream stream,
|
||||
vector<Desc> &procFormats )
|
||||
{
|
||||
UInt32 numFormats = stream.GetNumberAvailableIOProcFormats();
|
||||
|
||||
for( UInt32 i=0; i<numFormats; ++i )
|
||||
{
|
||||
Desc desc;
|
||||
|
||||
stream.GetAvailableIOProcFormatByIndex( i, desc );
|
||||
procFormats.push_back( desc );
|
||||
}
|
||||
}
|
||||
|
||||
static void GetPhysicalFormats( CAAudioHardwareStream stream,
|
||||
vector<Desc> &physicalFormats )
|
||||
{
|
||||
UInt32 numFormats = stream.GetNumberAvailablePhysicalFormats();
|
||||
for( UInt32 i=0; i<numFormats; ++i )
|
||||
{
|
||||
Desc desc;
|
||||
|
||||
stream.GetAvailablePhysicalFormatByIndex( i, desc );
|
||||
physicalFormats.push_back( desc );
|
||||
}
|
||||
}
|
||||
|
||||
RageSound_CA::RageSound_CA()
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
AudioDeviceID dID;
|
||||
@@ -150,44 +88,20 @@ RageSound_CA::RageSound_CA()
|
||||
LOG->Warn("Could not install the overload listener.");
|
||||
}
|
||||
|
||||
vector<Desc> physicalFormats;
|
||||
GetPhysicalFormats( sID, physicalFormats );
|
||||
unsigned i;
|
||||
LOG->Info("Available physical formats:");
|
||||
for (i = 0; i < physicalFormats.size(); ++i)
|
||||
const Desc CanonicalFormat(44100.0, kAudioFormatLinearPCM, 8, 1, 8, 2, 32,
|
||||
kAudioFormatFlagsNativeFloatPacked);
|
||||
const Desc SMFormat(44100.0, kAudioFormatLinearPCM, kBytesPerPacket,
|
||||
kFramesPerPacket, kBytesPerFrame, kChannelsPerFrame,
|
||||
kBitsPerChannel, kFormatFlags);
|
||||
|
||||
stream.SetCurrentIOProcFormat(CanonicalFormat);
|
||||
|
||||
if (AudioConverterNew(&SMFormat, &CanonicalFormat, &mConverter))
|
||||
{
|
||||
const Desc& f = physicalFormats[i];
|
||||
|
||||
LOG->Info("Format %u: Rate: %i ID: %s Flags 0x%lx bpp %lu fpp %lu"
|
||||
" bpf %lu channels %lu bits %lu", i, int(f.mSampleRate),
|
||||
FormatToString(f.mFormatID).c_str(), f.mFormatFlags,
|
||||
f.mBytesPerPacket, f.mFramesPerPacket, f.mBytesPerFrame,
|
||||
f.mChannelsPerFrame, f.mBitsPerChannel);
|
||||
delete mOutputDevice;
|
||||
RageException::ThrowNonfatal("Couldn't create the audio converter");
|
||||
}
|
||||
const Desc& physicalFormat = FindClosestFormat( physicalFormats, mFormat );
|
||||
stream.SetCurrentPhysicalFormat( physicalFormat );
|
||||
|
||||
vector<Desc> procFormats;
|
||||
GetIOProcFormats( sID, procFormats );
|
||||
LOG->Info("Available I/O procedure formats:");
|
||||
for (i = 0; i < procFormats.size(); ++i)
|
||||
{
|
||||
const Desc& f = procFormats[i];
|
||||
|
||||
LOG->Info("Format %u: Rate: %i ID: %s Flags 0x%lx bpp %lu fpp %lu"
|
||||
" bpf %lu channels %lu bits %lu", i, int(f.mSampleRate),
|
||||
FormatToString(f.mFormatID).c_str(), f.mFormatFlags,
|
||||
f.mBytesPerPacket, f.mFramesPerPacket, f.mBytesPerFrame,
|
||||
f.mChannelsPerFrame, f.mBitsPerChannel);
|
||||
}
|
||||
|
||||
const Desc& procFormat = FindClosestFormat( procFormats, mFormat );
|
||||
stream.SetCurrentIOProcFormat( procFormat );
|
||||
|
||||
LOG->Info("Proc format is %s.",
|
||||
mFormat == EXACT ? "exact" : (mFormat == CANONICAL ?
|
||||
"canonical" : "other"));
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
UInt32 bufferSize = mOutputDevice->GetIOBufferSize();
|
||||
@@ -218,13 +132,11 @@ RageSound_CA::RageSound_CA()
|
||||
catch (const CAException& e)
|
||||
{
|
||||
delete mOutputDevice;
|
||||
AudioConverterDispose(mConverter);
|
||||
RageException::ThrowNonfatal("Couldn't get Latency.");
|
||||
}
|
||||
|
||||
StartDecodeThread();
|
||||
|
||||
if (mFormat == OTHER)
|
||||
gConverter = new AudioConverter( this, procFormat );
|
||||
|
||||
try
|
||||
{
|
||||
@@ -233,8 +145,8 @@ RageSound_CA::RageSound_CA()
|
||||
}
|
||||
catch(const CAException& e)
|
||||
{
|
||||
delete gConverter;
|
||||
delete mOutputDevice;
|
||||
AudioConverterDispose(mConverter);
|
||||
RageException::Throw("Couldn't start the IOProc.");
|
||||
}
|
||||
}
|
||||
@@ -243,7 +155,7 @@ RageSound_CA::~RageSound_CA()
|
||||
{
|
||||
mOutputDevice->StopIOProc(GetData);
|
||||
delete mOutputDevice;
|
||||
delete gConverter;
|
||||
AudioConverterDispose(mConverter);
|
||||
}
|
||||
|
||||
int64_t RageSound_CA::GetPosition(const RageSoundBase *sound) const
|
||||
@@ -254,17 +166,6 @@ int64_t RageSound_CA::GetPosition(const RageSoundBase *sound) const
|
||||
return int64_t(time.mSampleTime);
|
||||
}
|
||||
|
||||
void RageSound_CA::FillConverter( void *data, UInt32 frames )
|
||||
{
|
||||
RageTimer tm;
|
||||
|
||||
Mix( (int16_t *)data, frames, mDecodePos, mNow );
|
||||
|
||||
g_fLastMixTimes[g_fLastMixTimePos] = tm.GetDeltaTime();
|
||||
++g_fLastMixTimePos;
|
||||
wrap( g_fLastMixTimePos, NUM_MIX_TIMES );
|
||||
}
|
||||
|
||||
OSStatus RageSound_CA::GetData(AudioDeviceID inDevice,
|
||||
const AudioTimeStamp *inNow,
|
||||
const AudioBufferList *inInputData,
|
||||
@@ -276,50 +177,21 @@ OSStatus RageSound_CA::GetData(AudioDeviceID inDevice,
|
||||
RageTimer tm;
|
||||
RageSound_CA *This = (RageSound_CA *)inClientData;
|
||||
AudioBuffer& buf = outOutputData->mBuffers[0];
|
||||
UInt32 dataPackets = buf.mDataByteSize;
|
||||
UInt32 dataPackets = buf.mDataByteSize >> 3; // 8 byes per packet
|
||||
int64_t decodePos = int64_t(inOutputTime->mSampleTime);
|
||||
int64_t now = int64_t(inNow->mSampleTime);
|
||||
|
||||
if (This->mFormat == OTHER)
|
||||
{
|
||||
dataPackets /= gConverter->GetOutputFormat().mBytesPerPacket;
|
||||
This->mDecodePos = decodePos;
|
||||
This->mNow = now;
|
||||
gConverter->FillComplexBuffer(dataPackets, *outOutputData, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
RageTimer mixTM;
|
||||
RageTimer tm2;
|
||||
int16_t buffer[dataPackets * (kBytesPerPacket >> 1)];
|
||||
|
||||
if (This->mFormat == EXACT)
|
||||
{
|
||||
dataPackets /= kBytesPerPacket;
|
||||
This->Mix((int16_t *)buf.mData, dataPackets, decodePos, now);
|
||||
}
|
||||
else // This->mFormat == CANONICAL
|
||||
{
|
||||
dataPackets /= 8; // 8 bytes per packet (1 frame per packet)
|
||||
|
||||
int16_t buffer[dataPackets * kBytesPerPacket];
|
||||
int16_t *ip = buffer;
|
||||
float *fp = (float *)buf.mData;
|
||||
|
||||
This->Mix(buffer, dataPackets, decodePos, now);
|
||||
|
||||
// Convert from signed 16 bit int to signed 32 bit float
|
||||
for (unsigned i = 0; i < buf.mDataByteSize; i += 4)
|
||||
{
|
||||
int16_t val = *(ip++);
|
||||
|
||||
*(fp++) = val / (val < 0 ? 32768.0f : 32767.0f);
|
||||
}
|
||||
}
|
||||
This->Mix(buffer, dataPackets, decodePos, now);
|
||||
g_fLastMixTimes[g_fLastMixTimePos] = tm2.GetDeltaTime();
|
||||
++g_fLastMixTimePos;
|
||||
wrap(g_fLastMixTimePos, NUM_MIX_TIMES);
|
||||
|
||||
AudioConverterConvertBuffer(This->mConverter, dataPackets * kBytesPerPacket,
|
||||
buffer, &buf.mDataByteSize, buf.mData);
|
||||
|
||||
g_fLastMixTimes[g_fLastMixTimePos] = tm.GetDeltaTime();
|
||||
++g_fLastMixTimePos;
|
||||
wrap(g_fLastMixTimePos, NUM_MIX_TIMES);
|
||||
}
|
||||
|
||||
g_fLastIOProcTime = tm.GetDeltaTime();
|
||||
++g_iNumIOProcCalls;
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
struct AudioTimeStamp;
|
||||
struct AudioBufferList;
|
||||
struct OpaqueAudioConverter;
|
||||
typedef struct OpaqueAudioConverter *AudioConverterRef;
|
||||
typedef unsigned long UInt32;
|
||||
typedef UInt32 AudioDeviceID;
|
||||
typedef UInt32 AudioDevicePropertyID;
|
||||
@@ -15,20 +17,11 @@ class RageSoundBase;
|
||||
|
||||
class RageSound_CA : public RageSound_Generic_Software
|
||||
{
|
||||
public:
|
||||
enum format
|
||||
{
|
||||
EXACT,
|
||||
CANONICAL,
|
||||
OTHER
|
||||
};
|
||||
|
||||
private:
|
||||
int64_t mDecodePos;
|
||||
float mLatency;
|
||||
CAAudioHardwareDevice *mOutputDevice;
|
||||
int64_t mNow;
|
||||
format mFormat;
|
||||
AudioConverterRef mConverter;
|
||||
|
||||
static OSStatus GetData(AudioDeviceID inDevice,
|
||||
const AudioTimeStamp *inNow,
|
||||
@@ -45,7 +38,6 @@ private:
|
||||
void *inData);
|
||||
|
||||
public:
|
||||
void FillConverter( void *data, UInt32 frames );
|
||||
RageSound_CA();
|
||||
~RageSound_CA();
|
||||
float GetPlayLatency() const { return mLatency; }
|
||||
|
||||
Reference in New Issue
Block a user