cog/Plugins/MIDI/MIDI/AUPlayer.mm

368 lines
10 KiB
Plaintext

#include "AUPlayer.h"
#include <stdlib.h>
#define SF2PACK
// #define AUPLAYERVIEW
#ifdef AUPLAYERVIEW
#import "AUPlayerView.h"
#endif
#define _countof(arr) (sizeof(arr) / sizeof((arr)[0]))
#define BLOCK_SIZE (512)
AUPlayer::AUPlayer()
: MIDIPlayer() {
samplerUnit[0] = NULL;
samplerUnit[1] = NULL;
samplerUnit[2] = NULL;
#ifdef AUPLAYERVIEW
samplerUI[0] = NULL;
samplerUI[1] = NULL;
samplerUI[2] = NULL;
samplerUIinitialized[0] = false;
samplerUIinitialized[1] = false;
samplerUIinitialized[2] = false;
#endif
bufferList = NULL;
audioBuffer = NULL;
componentSubType = kAudioUnitSubType_DLSSynth;
componentManufacturer = kAudioUnitManufacturer_Apple;
}
AUPlayer::~AUPlayer() {
shutdown();
}
void AUPlayer::send_event(uint32_t b) {
send_event_time(b, 0);
}
void AUPlayer::send_sysex(const uint8_t *data, size_t size, size_t port) {
send_sysex_time(data, size, port, 0);
}
void AUPlayer::send_event_time(uint32_t b, unsigned int time) {
#ifdef AUPLAYERVIEW
int _port = -1;
#endif
unsigned char event[3];
event[0] = (unsigned char)b;
event[1] = (unsigned char)(b >> 8);
event[2] = (unsigned char)(b >> 16);
unsigned port = (b >> 24) & 0x7F;
if(port > 2) port = 2;
#ifdef AUPLAYERVIEW
_port = (int)port;
#endif
MusicDeviceMIDIEvent(samplerUnit[port], event[0], event[1], event[2], time);
#ifdef AUPLAYERVIEW
if(_port >= 0 && !samplerUIinitialized[_port]) {
samplerUIinitialized[_port] = true;
dispatch_async(dispatch_get_main_queue(), ^{
samplerUI[_port] = new AUPluginUI(samplerUnit[_port]);
});
}
#endif
}
void AUPlayer::send_sysex_time(const uint8_t *data, size_t size, size_t port, unsigned int time) {
if(port > 2) port = 0;
#ifdef AUPLAYERVIEW
_port = (int)port;
#endif
MusicDeviceSysEx(samplerUnit[port], data, (UInt32)size);
if(port == 0) {
MusicDeviceSysEx(samplerUnit[1], data, (UInt32)size);
MusicDeviceSysEx(samplerUnit[2], data, (UInt32)size);
}
#ifdef AUPLAYERVIEW
if(_port >= 0 && !samplerUIinitialized[_port]) {
samplerUIinitialized[_port] = true;
dispatch_async(dispatch_get_main_queue(), ^{
samplerUI[_port] = new AUPluginUI(samplerUnit[_port]);
});
}
#endif
}
void AUPlayer::render(float *out, unsigned long count) {
float *ptrL, *ptrR;
memset(out, 0, count * sizeof(float) * 2);
while(count) {
UInt32 numberFrames = count > BLOCK_SIZE ? BLOCK_SIZE : (UInt32)count;
for(unsigned long i = 0; i < 3; ++i) {
AudioUnitRenderActionFlags ioActionFlags = 0;
for(unsigned long j = 0; j < 2; j++) {
bufferList->mBuffers[j].mNumberChannels = 1;
bufferList->mBuffers[j].mDataByteSize = (UInt32)(numberFrames * sizeof(float));
bufferList->mBuffers[j].mData = audioBuffer + j * BLOCK_SIZE;
memset(bufferList->mBuffers[j].mData, 0, numberFrames * sizeof(float));
}
AudioUnitRender(samplerUnit[i], &ioActionFlags, &mTimeStamp, 0, numberFrames, bufferList);
ptrL = (float *)bufferList->mBuffers[0].mData;
ptrR = (float *)bufferList->mBuffers[1].mData;
for(unsigned long j = 0; j < numberFrames; ++j) {
out[j * 2 + 0] += ptrL[j];
out[j * 2 + 1] += ptrR[j];
}
}
out += numberFrames * 2;
count -= numberFrames;
mTimeStamp.mSampleTime += (double)numberFrames;
}
}
void AUPlayer::shutdown() {
if(samplerUnit[2]) {
#ifdef AUPLAYERVIEW
if(samplerUI[2]) {
delete samplerUI[2];
samplerUI[2] = 0;
samplerUIinitialized[2] = false;
}
#endif
AudioUnitUninitialize(samplerUnit[2]);
AudioComponentInstanceDispose(samplerUnit[2]);
samplerUnit[2] = NULL;
}
if(samplerUnit[1]) {
#ifdef AUPLAYERVIEW
if(samplerUI[1]) {
delete samplerUI[1];
samplerUI[1] = 0;
samplerUIinitialized[1] = false;
}
#endif
AudioUnitUninitialize(samplerUnit[1]);
AudioComponentInstanceDispose(samplerUnit[1]);
samplerUnit[1] = NULL;
}
if(samplerUnit[0]) {
#ifdef AUPLAYERVIEW
if(samplerUI[0]) {
delete samplerUI[0];
samplerUI[0] = 0;
samplerUIinitialized[0] = false;
}
#endif
AudioUnitUninitialize(samplerUnit[0]);
AudioComponentInstanceDispose(samplerUnit[0]);
samplerUnit[0] = NULL;
}
if(audioBuffer) {
free(audioBuffer);
audioBuffer = NULL;
}
if(bufferList) {
free(bufferList);
bufferList = NULL;
}
initialized = false;
}
void AUPlayer::enumComponents(callback cbEnum) {
AudioComponentDescription cd = { 0 };
cd.componentType = kAudioUnitType_MusicDevice;
AudioComponent comp = NULL;
const char *bytes;
char bytesBuffer[512];
comp = AudioComponentFindNext(comp, &cd);
while(comp != NULL) {
CFStringRef cfName;
AudioComponentCopyName(comp, &cfName);
bytes = CFStringGetCStringPtr(cfName, kCFStringEncodingUTF8);
if(!bytes) {
CFStringGetCString(cfName, bytesBuffer, sizeof(bytesBuffer) - 1, kCFStringEncodingUTF8);
bytes = bytesBuffer;
}
AudioComponentGetDescription(comp, &cd);
cbEnum(cd.componentSubType, cd.componentManufacturer, bytes);
CFRelease(cfName);
comp = AudioComponentFindNext(comp, &cd);
}
}
void AUPlayer::setComponent(OSType uSubType, OSType uManufacturer) {
componentSubType = uSubType;
componentManufacturer = uManufacturer;
shutdown();
}
void AUPlayer::setSoundFont(const char *in) {
const char *ext = strrchr(in, '.');
if(ext && *ext && ((strncasecmp(ext + 1, "sf2", 3) == 0) || (strncasecmp(ext + 1, "dls", 3) == 0))) {
sSoundFontName = in;
shutdown();
}
}
/*void AUPlayer::setFileSoundFont( const char * in )
{
sFileSoundFontName = in;
shutdown();
}*/
static OSStatus renderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
if(inNumberFrames && ioData) {
for(int i = 0, j = ioData->mNumberBuffers; i < j; ++i) {
int k = inNumberFrames * sizeof(float);
if(k > ioData->mBuffers[i].mDataByteSize)
k = ioData->mBuffers[i].mDataByteSize;
memset(ioData->mBuffers[i].mData, 0, k);
}
}
return noErr;
}
bool AUPlayer::startup() {
if(bufferList) return true;
AudioComponentDescription cd = { 0 };
cd.componentType = kAudioUnitType_MusicDevice;
cd.componentSubType = componentSubType;
cd.componentManufacturer = componentManufacturer;
AudioComponent comp = NULL;
comp = AudioComponentFindNext(comp, &cd);
if(!comp)
return false;
OSStatus error;
for(int i = 0; i < 3; i++) {
UInt32 value = 1;
UInt32 size = sizeof(value);
error = AudioComponentInstanceNew(comp, &samplerUnit[i]);
if(error != noErr)
return false;
{
AudioStreamBasicDescription stream = { 0 };
stream.mSampleRate = uSampleRate;
stream.mFormatID = kAudioFormatLinearPCM;
stream.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagsNativeEndian;
stream.mFramesPerPacket = 1;
stream.mBytesPerPacket = 4;
stream.mBytesPerFrame = 4;
stream.mBitsPerChannel = 32;
stream.mChannelsPerFrame = 2;
AudioUnitSetProperty(samplerUnit[i], kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0, &stream, sizeof(stream));
AudioUnitSetProperty(samplerUnit[i], kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, 0, &stream, sizeof(stream));
}
value = BLOCK_SIZE;
AudioUnitSetProperty(samplerUnit[i], kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, 0, &value, size);
value = 127;
AudioUnitSetProperty(samplerUnit[i], kAudioUnitProperty_RenderQuality,
kAudioUnitScope_Global, 0, &value, size);
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = renderCallback;
callbackStruct.inputProcRefCon = 0;
AudioUnitSetProperty(samplerUnit[i], kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct));
/*Float64 sampleRateIn = 0, sampleRateOut = 0;
UInt32 sampleRateSize = sizeof (sampleRateIn);
const Float64 sr = uSampleRate;
AudioUnitGetProperty(samplerUnit[i], kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRateIn, &sampleRateSize);
if (sampleRateIn != sr)
AudioUnitSetProperty(samplerUnit[i], kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sr, sizeof (sr));
AudioUnitGetProperty (samplerUnit[i], kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRateOut, &sampleRateSize);
if (sampleRateOut != sr)
AudioUnitSetProperty (samplerUnit[i], kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, i, &sr, sizeof (sr));*/
AudioUnitReset(samplerUnit[i], kAudioUnitScope_Input, 0);
AudioUnitReset(samplerUnit[i], kAudioUnitScope_Output, 0);
AudioUnitReset(samplerUnit[i], kAudioUnitScope_Global, 0);
value = 1;
AudioUnitSetProperty(samplerUnit[i], kMusicDeviceProperty_StreamFromDisk, kAudioUnitScope_Global, 0, &value, size);
error = AudioUnitInitialize(samplerUnit[i]);
if(error != noErr)
return false;
}
// Now load instruments
if(sSoundFontName.length()) {
loadSoundFont(sSoundFontName.c_str());
}
/*if ( sFileSoundFontName.length() )
{
loadSoundFont( sFileSoundFontName.c_str() );
}*/
bufferList = (AudioBufferList *)calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
if(!bufferList)
return false;
audioBuffer = (float *)malloc(BLOCK_SIZE * 2 * sizeof(float));
if(!audioBuffer)
return false;
bufferList->mNumberBuffers = 2;
memset(&mTimeStamp, 0, sizeof(mTimeStamp));
mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
initialized = true;
setFilterMode(mode, reverb_chorus_disabled);
return true;
}
void AUPlayer::loadSoundFont(const char *name) {
// kMusicDeviceProperty_SoundBankURL was added in 10.5 as a replacement
// In addition, the File Manager API became deprecated starting in 10.8
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8 *)name, strlen(name), false);
if(url) {
for(int i = 0; i < 3; i++)
AudioUnitSetProperty(samplerUnit[i],
kMusicDeviceProperty_SoundBankURL, kAudioUnitScope_Global,
0,
&url, sizeof(url));
CFRelease(url);
}
}
unsigned int AUPlayer::send_event_needs_time() {
return BLOCK_SIZE;
}