#include "AUPlayer.h" #include #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 && ((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); 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; }