|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "tsound_t.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "texception.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tthread.h"
|
|
Toshihiro Shimizu |
890ddd |
#include "tthreadmessage.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include <errno.h></errno.h>
|
|
Toshihiro Shimizu |
890ddd |
#include <unistd.h></unistd.h>
|
|
Toshihiro Shimizu |
890ddd |
#include <queue></queue>
|
|
Toshihiro Shimizu |
890ddd |
#include <set></set>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include <coreservices coreservices.h=""></coreservices>
|
|
Toshihiro Shimizu |
890ddd |
#include <audiounit audiounit.h=""></audiounit>
|
|
Toshihiro Shimizu |
890ddd |
#include <coreaudio coreaudio.h=""></coreaudio>
|
|
Toshihiro Shimizu |
890ddd |
#include <audiotoolbox audiotoolbox.h=""></audiotoolbox>
|
|
Toshihiro Shimizu |
890ddd |
using namespace std;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TThread::Mutex MutexOut;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class TSoundOutputDeviceImp
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
bool m_isPlaying;
|
|
Toshihiro Shimizu |
890ddd |
bool m_looped;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat m_currentFormat;
|
|
Toshihiro Shimizu |
890ddd |
std::set<int> m_supportedRate;</int>
|
|
Toshihiro Shimizu |
890ddd |
bool m_opened;
|
|
Toshihiro Shimizu |
890ddd |
AudioFileID musicFileID;
|
|
Toshihiro Shimizu |
890ddd |
AudioUnit theOutputUnit;
|
|
Toshihiro Shimizu |
890ddd |
AudioStreamBasicDescription fileASBD;
|
|
Toshihiro Shimizu |
890ddd |
AudioStreamBasicDescription outputASBD;
|
|
Toshihiro Shimizu |
890ddd |
AudioConverterRef converter;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDeviceImp()
|
|
Toshihiro Shimizu |
890ddd |
: m_isPlaying(false), m_looped(false), m_supportedRate(), m_opened(false){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
std::set<tsoundoutputdevicelistener *=""> m_listeners;</tsoundoutputdevicelistener>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~TSoundOutputDeviceImp(){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool doOpenDevice();
|
|
Toshihiro Shimizu |
890ddd |
bool doSetStreamFormat(const TSoundTrackFormat &format);
|
|
Toshihiro Shimizu |
890ddd |
bool doStopDevice();
|
|
Toshihiro Shimizu |
890ddd |
void play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing);
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//-----------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
namespace
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
struct MyData {
|
|
Toshihiro Shimizu |
890ddd |
char *entireFileBuffer;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UInt64 totalPacketCount;
|
|
Toshihiro Shimizu |
890ddd |
UInt64 fileByteCount;
|
|
Toshihiro Shimizu |
890ddd |
UInt32 maxPacketSize;
|
|
Toshihiro Shimizu |
890ddd |
UInt64 packetOffset;
|
|
Toshihiro Shimizu |
890ddd |
UInt64 byteOffset;
|
|
Toshihiro Shimizu |
890ddd |
bool m_doNotify;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void *sourceBuffer;
|
|
Toshihiro Shimizu |
890ddd |
AudioConverterRef converter;
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDeviceImp *imp;
|
|
Toshihiro Shimizu |
890ddd |
bool isLooping;
|
|
Toshihiro Shimizu |
890ddd |
MyData()
|
|
Toshihiro Shimizu |
890ddd |
: entireFileBuffer(0), totalPacketCount(0), fileByteCount(0), maxPacketSize(0), packetOffset(0), byteOffset(0), sourceBuffer(0), isLooping(false), imp(0), m_doNotify(true)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class PlayCompletedMsg : public TThread::Message
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
std::set<tsoundoutputdevicelistener *=""> m_listeners;</tsoundoutputdevicelistener>
|
|
Toshihiro Shimizu |
890ddd |
MyData *m_data;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
PlayCompletedMsg(MyData *data)
|
|
Toshihiro Shimizu |
890ddd |
: m_data(data)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::Message *clone() const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return new PlayCompletedMsg(*this);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void onDeliver()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (m_data->imp) {
|
|
Toshihiro Shimizu |
890ddd |
if (m_data->m_doNotify == false)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
m_data->m_doNotify = false;
|
|
Toshihiro Shimizu |
890ddd |
if (m_data->imp->m_isPlaying)
|
|
Toshihiro Shimizu |
890ddd |
m_data->imp->doStopDevice();
|
|
Toshihiro Shimizu |
890ddd |
std::set<tsoundoutputdevicelistener *="">::iterator it = m_data->imp->m_listeners.begin();</tsoundoutputdevicelistener>
|
|
Toshihiro Shimizu |
890ddd |
for (; it != m_data->imp->m_listeners.end(); ++it)
|
|
Toshihiro Shimizu |
890ddd |
(*it)->onPlayCompleted();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#define checkStatus(err) \
|
|
Toshihiro Shimizu |
890ddd |
if (err) { \
|
|
Toshihiro Shimizu |
890ddd |
printf("Error: 0x%x -> %s: %d\n", (int)err, __FILE__, __LINE__); \
|
|
Toshihiro Shimizu |
890ddd |
fflush(stdout); \
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
extern "C" {
|
|
Toshihiro Shimizu |
890ddd |
//This is an example of a Input Procedure from a call to AudioConverterFillComplexBuffer.
|
|
Toshihiro Shimizu |
890ddd |
//The total amount of data needed is "ioNumberDataPackets" when this method is first called.
|
|
Toshihiro Shimizu |
890ddd |
//On exit, "ioNumberDataPackets" must be set to the actual amount of data obtained.
|
|
Toshihiro Shimizu |
890ddd |
//Upon completion, all new input data must point to the AudioBufferList in the parameter ( "ioData" )
|
|
Toshihiro Shimizu |
890ddd |
OSStatus MyACComplexInputProc(AudioConverterRef inAudioConverter,
|
|
Toshihiro Shimizu |
890ddd |
UInt32 *ioNumberDataPackets,
|
|
Toshihiro Shimizu |
890ddd |
AudioBufferList *ioData,
|
|
Toshihiro Shimizu |
890ddd |
AudioStreamPacketDescription **outDataPacketDescription,
|
|
Toshihiro Shimizu |
890ddd |
void *inUserData)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
OSStatus err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
UInt32 bytesCopied = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
MyData *myData = static_cast<mydata *="">(inUserData);</mydata>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// initialize in case of failure
|
|
Toshihiro Shimizu |
890ddd |
ioData->mBuffers[0].mData = NULL;
|
|
Toshihiro Shimizu |
890ddd |
ioData->mBuffers[0].mDataByteSize = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
if (myData->imp->m_isPlaying == false)
|
|
Toshihiro Shimizu |
890ddd |
return noErr;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// if there are not enough packets to satisfy request, then read what's left
|
|
Toshihiro Shimizu |
890ddd |
if (myData->packetOffset + *ioNumberDataPackets > myData->totalPacketCount)
|
|
Toshihiro Shimizu |
890ddd |
*ioNumberDataPackets = myData->totalPacketCount - myData->packetOffset;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// do nothing if there are no packets available
|
|
Toshihiro Shimizu |
890ddd |
if (*ioNumberDataPackets) {
|
|
Toshihiro Shimizu |
890ddd |
if (myData->sourceBuffer != NULL) {
|
|
Toshihiro Shimizu |
890ddd |
free(myData->sourceBuffer);
|
|
Toshihiro Shimizu |
890ddd |
myData->sourceBuffer = NULL;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//the total amount of data requested by the AudioConverter
|
|
Toshihiro Shimizu |
890ddd |
bytesCopied = *ioNumberDataPackets * myData->maxPacketSize;
|
|
Toshihiro Shimizu |
890ddd |
//alloc a small buffer for the AudioConverter to use.
|
|
Toshihiro Shimizu |
890ddd |
myData->sourceBuffer = (void *)calloc(1, bytesCopied);
|
|
Toshihiro Shimizu |
890ddd |
//copy the amount of data needed (bytesCopied) from buffer of audio file
|
|
Toshihiro Shimizu |
890ddd |
memcpy(myData->sourceBuffer, myData->entireFileBuffer + myData->byteOffset, bytesCopied);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// keep track of where we want to read from next time
|
|
Toshihiro Shimizu |
890ddd |
myData->byteOffset += *ioNumberDataPackets * myData->maxPacketSize;
|
|
Toshihiro Shimizu |
890ddd |
myData->packetOffset += *ioNumberDataPackets;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ioData->mBuffers[0].mData = myData->sourceBuffer; // tell the Audio Converter where it's source data is
|
|
Toshihiro Shimizu |
890ddd |
ioData->mBuffers[0].mDataByteSize = bytesCopied; // tell the Audio Converter how much data in each buffer
|
|
Toshihiro Shimizu |
890ddd |
} else {
|
|
Toshihiro Shimizu |
890ddd |
// there aren't any more packets to read.
|
|
Toshihiro Shimizu |
890ddd |
// Set the amount of data read (mDataByteSize) to zero
|
|
Toshihiro Shimizu |
890ddd |
// and return noErr to signal the AudioConverter there are
|
|
Toshihiro Shimizu |
890ddd |
// no packets left.
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
ioData->mBuffers[0].mData = NULL;
|
|
Toshihiro Shimizu |
890ddd |
ioData->mBuffers[0].mDataByteSize = 0;
|
|
Toshihiro Shimizu |
890ddd |
delete[] myData->entireFileBuffer;
|
|
Toshihiro Shimizu |
890ddd |
myData->entireFileBuffer = 0;
|
|
Toshihiro Shimizu |
890ddd |
err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
*(myData->isPlaying) = false; //questo lo faccio nel main thread
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
PlayCompletedMsg(myData).send();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return err;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
OSStatus MyFileRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags,
|
|
Toshihiro Shimizu |
890ddd |
const AudioTimeStamp *inTimeStamp,
|
|
Toshihiro Shimizu |
890ddd |
UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
MyData *myData = static_cast<mydata *="">(inRefCon);</mydata>
|
|
Toshihiro Shimizu |
890ddd |
OSStatus err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
void *inInputDataProcUserData = inRefCon;
|
|
Toshihiro Shimizu |
890ddd |
AudioStreamPacketDescription *outPacketDescription = NULL;
|
|
Toshihiro Shimizu |
890ddd |
//To obtain a data buffer of converted data from a complex input source(compressed files, etc.)
|
|
Toshihiro Shimizu |
890ddd |
//use AudioConverterFillComplexBuffer. The total amount of data requested is "inNumFrames" and
|
|
Toshihiro Shimizu |
890ddd |
//on return is set to the actual amount of data recieved.
|
|
Toshihiro Shimizu |
890ddd |
//All converted data is returned to "ioData" (AudioBufferList).
|
|
Toshihiro Shimizu |
890ddd |
err = AudioConverterFillComplexBuffer(myData->converter, MyACComplexInputProc, inInputDataProcUserData, &inNumFrames, ioData, outPacketDescription);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
/*Parameters for AudioConverterFillComplexBuffer()
|
|
Toshihiro Shimizu |
890ddd |
converter - the converter being used
|
|
Toshihiro Shimizu |
890ddd |
ACComplexInputProc() - input procedure to supply data to the Audio Converter
|
|
Toshihiro Shimizu |
890ddd |
inInputDataProcUserData - Used to hold any data that needs to be passed on. Not needed in this example.
|
|
Toshihiro Shimizu |
890ddd |
inNumFrames - The amount of requested data. On output, this
|
|
Toshihiro Shimizu |
890ddd |
number is the amount actually received.
|
|
Toshihiro Shimizu |
890ddd |
ioData - Buffer of the converted data recieved on return
|
|
Toshihiro Shimizu |
890ddd |
outPacketDescription - contains the format of the returned data. Not used in this example.
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
return err;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
} //extern "C"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!inDesc) {
|
|
Toshihiro Shimizu |
890ddd |
printf("Can't print a NULL desc!\n");
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
printf("- - - - - - - - - - - - - - - - - - - -\n");
|
|
Toshihiro Shimizu |
890ddd |
printf(" Sample Rate:%f\n", inDesc->mSampleRate);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Format ID:%.*s\n", (int)sizeof(inDesc->mFormatID), (char *)&inDesc->mFormatID);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Format Flags:%lX\n", inDesc->mFormatFlags);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
|
|
Toshihiro Shimizu |
890ddd |
printf(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
|
|
Toshihiro Shimizu |
890ddd |
printf("- - - - - - - - - - - - - - - - - - - -\n");
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::doOpenDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_opened = false;
|
|
Toshihiro Shimizu |
890ddd |
OSStatus err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
ComponentDescription desc;
|
|
Toshihiro Shimizu |
890ddd |
Component comp;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
desc.componentType = kAudioUnitType_Output;
|
|
Toshihiro Shimizu |
890ddd |
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
|
Toshihiro Shimizu |
890ddd |
//all Audio Units in AUComponent.h must use "kAudioUnitManufacturer_Apple" as the Manufacturer
|
|
Toshihiro Shimizu |
890ddd |
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
|
Toshihiro Shimizu |
890ddd |
desc.componentFlags = 0;
|
|
Toshihiro Shimizu |
890ddd |
desc.componentFlagsMask = 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
comp = FindNextComponent(NULL, &desc); //Finds an component that meets the desc spec's
|
|
Toshihiro Shimizu |
890ddd |
if (comp == NULL)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
err = OpenAComponent(comp, &theOutputUnit); //gains access to the services provided by the component
|
|
Toshihiro Shimizu |
890ddd |
if (err)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
UInt32 size;
|
|
Toshihiro Shimizu |
890ddd |
Boolean outWritable;
|
|
Toshihiro Shimizu |
890ddd |
UInt32 theInputBus = 0;
|
|
Toshihiro Shimizu |
890ddd |
//Gets the size of the Stream Format Property and if it is writable
|
|
Toshihiro Shimizu |
890ddd |
err = AudioUnitGetPropertyInfo(theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitProperty_StreamFormat,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Output,
|
|
Toshihiro Shimizu |
890ddd |
0, &size, &outWritable);
|
|
Toshihiro Shimizu |
890ddd |
//Get the current stream format of the output
|
|
Toshihiro Shimizu |
890ddd |
err = AudioUnitGetProperty(theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitProperty_StreamFormat,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Output,
|
|
Toshihiro Shimizu |
890ddd |
0, &outputASBD, &size);
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
//Set the stream format of the output to match the input
|
|
Toshihiro Shimizu |
890ddd |
err = AudioUnitSetProperty(theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitProperty_StreamFormat,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Input,
|
|
Toshihiro Shimizu |
890ddd |
theInputBus,
|
|
Toshihiro Shimizu |
890ddd |
&outputASBD,
|
|
Toshihiro Shimizu |
890ddd |
size);
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Initialize AudioUnit, alloc mem buffers for processing
|
|
Toshihiro Shimizu |
890ddd |
err = AudioUnitInitialize(theOutputUnit);
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
if (err == noErr)
|
|
Toshihiro Shimizu |
890ddd |
m_opened = true;
|
|
Toshihiro Shimizu |
890ddd |
return m_opened;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::doSetStreamFormat(const TSoundTrackFormat &format)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!m_opened)
|
|
Toshihiro Shimizu |
890ddd |
doOpenDevice();
|
|
Toshihiro Shimizu |
890ddd |
if (!m_opened)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mSampleRate = format.m_sampleRate;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mFormatID = kAudioFormatLinearPCM;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mFormatFlags = 14;
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
Standard flags: kAudioFormatFlagIsFloat = (1L << 0)
|
|
Toshihiro Shimizu |
890ddd |
kAudioFormatFlagIsBigEndian = (1L << 1)
|
|
Toshihiro Shimizu |
890ddd |
kAudioFormatFlagIsSignedInteger = (1L << 2)
|
|
Toshihiro Shimizu |
890ddd |
kAudioFormatFlagIsPacked = (1L << 3)
|
|
Toshihiro Shimizu |
890ddd |
kAudioFormatFlagIsAlignedHigh = (1L << 4)
|
|
Toshihiro Shimizu |
890ddd |
kAudioFormatFlagIsNonInterleaved = (1L << 5)
|
|
Toshihiro Shimizu |
890ddd |
kAudioFormatFlagsAreAllClear = (1L << 31)
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Linear PCM flags:
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagIsFloat = kAudioFormatFlagIsFloat
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagIsBigEndian = kAudioFormatFlagIsBigEndian
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagIsSignedInteger = kAudioFormatFlagIsSignedInteger
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagIsPacked = kAudioFormatFlagIsPacked
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagIsAlignedHigh = kAudioFormatFlagIsAlignedHigh
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagIsNonInterleaved = kAudioFormatFlagIsNonInterleaved
|
|
Toshihiro Shimizu |
890ddd |
kLinearPCMFormatFlagsAreAllClear = kAudioFormatFlagsAreAllClear
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mBytesPerPacket = (format.m_bitPerSample >> 3) * format.m_channelCount;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mFramesPerPacket = 1;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mBytesPerFrame = (format.m_bitPerSample >> 3) * format.m_channelCount;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mChannelsPerFrame = format.m_channelCount;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mBitsPerChannel = format.m_bitPerSample;
|
|
Toshihiro Shimizu |
890ddd |
fileASBD.mReserved = 0;
|
|
Toshihiro Shimizu |
890ddd |
//PrintStreamDesc(&fileASBD);
|
|
Toshihiro Shimizu |
890ddd |
m_opened = true;
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDevice::TSoundOutputDevice() : m_imp(new TSoundOutputDeviceImp)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
supportsVolume();
|
|
Toshihiro Shimizu |
890ddd |
} catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundOutputDevice::~TSoundOutputDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
stop();
|
|
Toshihiro Shimizu |
890ddd |
close();
|
|
Toshihiro Shimizu |
890ddd |
delete m_imp;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::installed()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::open(const TSoundTrackP &st)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->doOpenDevice())
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Problem to open the output device");
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->doSetStreamFormat(st->getFormat()))
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException(
|
|
Toshihiro Shimizu |
890ddd |
TSoundDeviceException::UnableOpenDevice,
|
|
Toshihiro Shimizu |
890ddd |
"Problem to open the output device setting some params");
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::close()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
stop();
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_opened = false;
|
|
Toshihiro Shimizu |
890ddd |
AudioUnitUninitialize(m_imp->theOutputUnit); //release resources without closing the component
|
|
Toshihiro Shimizu |
890ddd |
CloseComponent(m_imp->theOutputUnit); //Terminates your application's access to the services provided
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
int lastSample = st->getSampleCount() - 1;
|
|
Toshihiro Shimizu |
890ddd |
notLessThan(0, s0);
|
|
Toshihiro Shimizu |
890ddd |
notLessThan(0, s1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
notMoreThan(lastSample, s0);
|
|
Toshihiro Shimizu |
890ddd |
notMoreThan(lastSample, s1);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (s0 > s1) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef DEBUG
|
|
Toshihiro Shimizu |
890ddd |
cout << "s0 > s1; reorder" << endl;
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
swap(s0, s1);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (isPlaying()) {
|
|
Toshihiro Shimizu |
890ddd |
#ifdef DEBUG
|
|
Toshihiro Shimizu |
890ddd |
cout << "is playing, stop it!" << endl;
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
stop();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
m_imp->play(st, s0, s1, loop, scrubbing);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDeviceImp::play(const TSoundTrackP &st, TINT32 s0, TINT32 s1, bool loop, bool scrubbing)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!doSetStreamFormat(st->getFormat()))
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
OSStatus err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
MyData *myData = new MyData();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
myData->imp = this;
|
|
Toshihiro Shimizu |
890ddd |
UInt32 magicCookieSize = 0;
|
|
Toshihiro Shimizu |
890ddd |
//PrintStreamDesc(&outputASBD);
|
|
Toshihiro Shimizu |
890ddd |
err = AudioConverterNew(&fileASBD, &outputASBD, &converter);
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
err = AudioFileGetPropertyInfo(musicFileID,
|
|
Toshihiro Shimizu |
890ddd |
kAudioFilePropertyMagicCookieData,
|
|
Toshihiro Shimizu |
890ddd |
&magicCookieSize,
|
|
Toshihiro Shimizu |
890ddd |
NULL);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
if (err == noErr) {
|
|
Toshihiro Shimizu |
890ddd |
void *magicCookie = calloc(1, magicCookieSize);
|
|
Toshihiro Shimizu |
890ddd |
if (magicCookie) {
|
|
Toshihiro Shimizu |
890ddd |
//Get Magic Cookie data from Audio File
|
|
Toshihiro Shimizu |
890ddd |
err = AudioFileGetProperty(musicFileID,
|
|
Toshihiro Shimizu |
890ddd |
kAudioFilePropertyMagicCookieData,
|
|
Toshihiro Shimizu |
890ddd |
&magicCookieSize,
|
|
Toshihiro Shimizu |
890ddd |
magicCookie);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Give the AudioConverter the magic cookie decompression params if there are any
|
|
Toshihiro Shimizu |
890ddd |
if (err == noErr) {
|
|
Toshihiro Shimizu |
890ddd |
err = AudioConverterSetProperty(myData->converter,
|
|
Toshihiro Shimizu |
890ddd |
kAudioConverterDecompressionMagicCookie,
|
|
Toshihiro Shimizu |
890ddd |
magicCookieSize,
|
|
Toshihiro Shimizu |
890ddd |
magicCookie);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
if (magicCookie)
|
|
Toshihiro Shimizu |
890ddd |
free(magicCookie);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
} else //this is OK because some audio data doesn't need magic cookie data
|
|
Toshihiro Shimizu |
890ddd |
err = noErr;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
myData->converter = converter;
|
|
Toshihiro Shimizu |
890ddd |
myData->totalPacketCount = s1 - s0;
|
|
Toshihiro Shimizu |
890ddd |
myData->fileByteCount = (s1 - s0) * st->getSampleSize();
|
|
Toshihiro Shimizu |
890ddd |
myData->entireFileBuffer = new char[myData->fileByteCount];
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#if defined(i386)
|
|
Toshihiro Shimizu |
890ddd |
if (st->getBitPerSample() == 16) {
|
|
Toshihiro Shimizu |
890ddd |
int i;
|
|
Toshihiro Shimizu |
890ddd |
USHORT *dst = (USHORT *)(myData->entireFileBuffer);
|
|
Toshihiro Shimizu |
890ddd |
USHORT *src = (USHORT *)(st->getRawData() + s0 * st->getSampleSize());
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
for (i = 0; i < myData->fileByteCount / 2; i++)
|
|
Toshihiro Shimizu |
890ddd |
*dst++ = swapUshort(*src++);
|
|
Toshihiro Shimizu |
890ddd |
} else
|
|
Toshihiro Shimizu |
890ddd |
memcpy(myData->entireFileBuffer, st->getRawData() + s0 * st->getSampleSize(), myData->fileByteCount);
|
|
Toshihiro Shimizu |
890ddd |
#else
|
|
Toshihiro Shimizu |
890ddd |
memcpy(myData->entireFileBuffer, st->getRawData() + s0 * st->getSampleSize(), myData->fileByteCount);
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
myData->maxPacketSize = fileASBD.mFramesPerPacket * fileASBD.mBytesPerFrame;
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
m_isPlaying = true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
myData->isLooping = loop;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//cout << "total packet count = " << myData->totalPacketCount <
|
|
Toshihiro Shimizu |
890ddd |
//cout << "filebytecount " << myData->fileByteCount << endl;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
AURenderCallbackStruct renderCallback;
|
|
Toshihiro Shimizu |
890ddd |
memset(&renderCallback, 0, sizeof(AURenderCallbackStruct));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
renderCallback.inputProc = MyFileRenderProc;
|
|
Toshihiro Shimizu |
890ddd |
renderCallback.inputProcRefCon = myData;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//Sets the callback for the Audio Unit to the renderCallback
|
|
Toshihiro Shimizu |
890ddd |
err = AudioUnitSetProperty(theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitProperty_SetRenderCallback,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Input,
|
|
Toshihiro Shimizu |
890ddd |
0, &renderCallback,
|
|
Toshihiro Shimizu |
890ddd |
sizeof(AURenderCallbackStruct));
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
err = AudioOutputUnitStart(theOutputUnit);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
checkStatus(err);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDeviceImp::doStopDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_isPlaying = false;
|
|
Toshihiro Shimizu |
890ddd |
AudioOutputUnitStop(theOutputUnit); //you must stop the audio unit from processing
|
|
Toshihiro Shimizu |
890ddd |
AudioConverterDispose(converter); //deallocates the memory used by inAudioConverter
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::stop()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
if (m_imp->m_opened == false)
|
|
Toshihiro Shimizu |
890ddd |
return;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doStopDevice();
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::attach(TSoundOutputDeviceListener *listener)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_listeners.insert(listener);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::detach(TSoundOutputDeviceListener *listener)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_listeners.erase(listener);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double TSoundOutputDevice::getVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
if (!m_imp->m_opened)
|
|
Toshihiro Shimizu |
890ddd |
m_imp->doOpenDevice();
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
Float32 leftVol, rightVol;
|
|
Toshihiro Shimizu |
890ddd |
AudioUnitGetParameter(
|
|
Toshihiro Shimizu |
890ddd |
m_imp->theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kHALOutputParam_Volume,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Output,
|
|
Toshihiro Shimizu |
890ddd |
0,
|
|
Toshihiro Shimizu |
890ddd |
&leftVol);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
AudioUnitGetParameter(
|
|
Toshihiro Shimizu |
890ddd |
m_imp->theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kHALOutputParam_Volume,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Output,
|
|
Toshihiro Shimizu |
890ddd |
0,
|
|
Toshihiro Shimizu |
890ddd |
&rightVol);
|
|
Toshihiro Shimizu |
890ddd |
double vol = (leftVol + rightVol) / 2;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
return (vol < 0. ? 0. : vol);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::setVolume(double volume)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
Float32 vol = volume;
|
|
Toshihiro Shimizu |
890ddd |
AudioUnitSetParameter(
|
|
Toshihiro Shimizu |
890ddd |
m_imp->theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kHALOutputParam_Volume,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Output,
|
|
Toshihiro Shimizu |
890ddd |
0,
|
|
Toshihiro Shimizu |
890ddd |
vol,
|
|
Toshihiro Shimizu |
890ddd |
0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
AudioUnitSetParameter(
|
|
Toshihiro Shimizu |
890ddd |
m_imp->theOutputUnit,
|
|
Toshihiro Shimizu |
890ddd |
kHALOutputParam_Volume,
|
|
Toshihiro Shimizu |
890ddd |
kAudioUnitScope_Output,
|
|
Toshihiro Shimizu |
890ddd |
0,
|
|
Toshihiro Shimizu |
890ddd |
vol,
|
|
Toshihiro Shimizu |
890ddd |
0);
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::supportsVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::isPlaying() const
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_isPlaying;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundOutputDevice::isLooping()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_looped;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundOutputDevice::setLooping(bool loop)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
//TThread::ScopedLock sl(MutexOut);
|
|
Toshihiro Shimizu |
890ddd |
m_imp->m_looped = loop;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 sampleRate, int channelCount, int bitPerSample)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat fmt(
|
|
Toshihiro Shimizu |
890ddd |
sampleRate,
|
|
Toshihiro Shimizu |
890ddd |
bitPerSample,
|
|
Toshihiro Shimizu |
890ddd |
channelCount,
|
|
Toshihiro Shimizu |
890ddd |
true);
|
|
Toshihiro Shimizu |
890ddd |
return fmt;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundOutputDevice::getPreferredFormat(const TSoundTrackFormat &format)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
// try {
|
|
Toshihiro Shimizu |
890ddd |
return getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
format.m_sampleRate, format.m_channelCount, format.m_bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
/*}
|
|
Toshihiro Shimizu |
890ddd |
catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException( e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}*/
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
// REGISTRAZIONE
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class TSoundInputDeviceImp
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
//ALport m_port;
|
|
Toshihiro Shimizu |
890ddd |
bool m_stopped;
|
|
Toshihiro Shimizu |
890ddd |
bool m_isRecording;
|
|
Toshihiro Shimizu |
890ddd |
bool m_oneShotRecording;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
long m_recordedSampleCount;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat m_currentFormat;
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP m_st;
|
|
Toshihiro Shimizu |
890ddd |
std::set<int> m_supportedRate;</int>
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TThread::Executor m_executor;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDeviceImp()
|
|
Toshihiro Shimizu |
890ddd |
: m_stopped(false), m_isRecording(false)
|
|
Toshihiro Shimizu |
890ddd |
// , m_port(NULL)
|
|
Toshihiro Shimizu |
890ddd |
,
|
|
Toshihiro Shimizu |
890ddd |
m_oneShotRecording(false), m_recordedSampleCount(0), m_st(0), m_supportedRate(){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~TSoundInputDeviceImp(){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool doOpenDevice(const TSoundTrackFormat &format,
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::Source devType);
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDeviceImp::doOpenDevice(const TSoundTrackFormat &format,
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::Source devType)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
class RecordTask : public TThread::Runnable
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
public:
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDeviceImp *m_devImp;
|
|
Toshihiro Shimizu |
890ddd |
int m_ByteToSample;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
RecordTask(TSoundInputDeviceImp *devImp, int numByte)
|
|
Toshihiro Shimizu |
890ddd |
: TThread::Runnable(), m_devImp(devImp), m_ByteToSample(numByte){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
~RecordTask(){};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void run();
|
|
Toshihiro Shimizu |
890ddd |
};
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void RecordTask::run()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//==============================================================================
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::TSoundInputDevice() : m_imp(new TSoundInputDeviceImp)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundInputDevice::~TSoundInputDevice()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
if(m_imp->m_port)
|
|
Toshihiro Shimizu |
890ddd |
alClosePort(m_imp->m_port);
|
|
Toshihiro Shimizu |
890ddd |
delete m_imp;
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::installed()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
if (alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, 0, 0, 0, 0) <=0)
|
|
Toshihiro Shimizu |
890ddd |
return false;
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundInputDevice::record(const TSoundTrackFormat &format, TSoundInputDevice::Source type)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
void TSoundInputDevice::record(const TSoundTrackP &st, TSoundInputDevice::Source type)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP TSoundInputDevice::stop()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackP st;
|
|
Toshihiro Shimizu |
890ddd |
return st;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
double TSoundInputDevice::getVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return 0.0;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::setVolume(double volume)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::supportsVolume()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return true;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundInputDevice::getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
TUINT32 sampleRate, int channelCount, int bitPerSample)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat fmt;
|
|
Toshihiro Shimizu |
890ddd |
return fmt;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
TSoundTrackFormat TSoundInputDevice::getPreferredFormat(const TSoundTrackFormat &format)
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
/*
|
|
Toshihiro Shimizu |
890ddd |
try {
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
return getPreferredFormat(
|
|
Toshihiro Shimizu |
890ddd |
format.m_sampleRate, format.m_channelCount, format.m_bitPerSample);
|
|
Toshihiro Shimizu |
890ddd |
/*}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
catch (TSoundDeviceException &e) {
|
|
Toshihiro Shimizu |
890ddd |
throw TSoundDeviceException( e.getType(), e.getMessage());
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
*/
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
//------------------------------------------------------------------------------
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
bool TSoundInputDevice::isRecording()
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Toshihiro Shimizu |
890ddd |
return m_imp->m_isRecording;
|
|
Toshihiro Shimizu |
890ddd |
}
|