diff --git a/objc/AudioHelpers.h b/objc/AudioHelpers.h index 908c54050..3f6b1274c 100644 --- a/objc/AudioHelpers.h +++ b/objc/AudioHelpers.h @@ -12,33 +12,33 @@ #pragma mark - Audio Unit / Audio Session Debugging -// uncomment this to log more information from the audio classes, or define it in "Other C Flags" build settings +/// uncomment this to log more information from the audio classes, or define it in "Other C Flags" build settings //#define AU_DEBUG_VERBOSE -// returns the name of the const value associated with the OSStatus as a string +/// returns the name of the const value associated with the OSStatus as a string extern NSString *AVStatusCodeAsString(OSStatus status); extern NSString *AUStatusCodeAsString(OSStatus status); -// log debug info along with the class, function and line number +/// log debug info along with the class, function and line number #define AU_LOG(nslog_string, ...) do {\ NSLog((@"%s[%d] " nslog_string), __func__, __LINE__, ##__VA_ARGS__);\ } while (0) -// same as AU_Log, but only logs if AU_DEBUG_VERBOSE is defined +/// same as AU_Log, but only logs if AU_DEBUG_VERBOSE is defined #if defined(AU_DEBUG_VERBOSE) -#define AU_LOGV(nslog_string, ...) AU_LOG(nslog_string, ##__VA_ARGS__) + #define AU_LOGV(nslog_string, ...) AU_LOG(nslog_string, ##__VA_ARGS__) #else -#define AU_LOGV(nslog_string, ...) + #define AU_LOGV(nslog_string, ...) #endif -// a debug check, which will only log if the value is non-zero +/// a debug check, which will only log if the value is non-zero #define AU_LOG_IF_ERROR(value, nslog_string, ...) do {\ if(value) {\ NSLog((@"*** ERROR *** %s[%d] " nslog_string), __func__, __LINE__, ##__VA_ARGS__);\ }\ } while (0) -// check if the audio unit had an error, and if so print it and return +/// check if the audio unit had an error, and if so print it and return #define AU_RETURN_IF_ERROR(status) do {\ if(status) {\ NSLog(@"*** ERROR *** %s[%d] status code = %@", __func__, __LINE__, AUStatusCodeAsString(status));\ @@ -46,7 +46,7 @@ return;\ }\ } while (0) -// check if the audio unit had an error, and if so print it and return false +/// check if the audio unit had an error, and if so print it and return false #define AU_RETURN_FALSE_IF_ERROR(status) do {\ if(status) {\ NSLog(@"*** ERROR *** %s[%d] status code = %@", __func__, __LINE__, AUStatusCodeAsString(status));\ diff --git a/objc/AudioHelpers.m b/objc/AudioHelpers.m index 4ba58fe31..fbda9ca02 100644 --- a/objc/AudioHelpers.m +++ b/objc/AudioHelpers.m @@ -91,7 +91,7 @@ BOOL floatsAreEqual(Float64 f1, Float64 f2) { return ((fabs(f1 - f2) < 0.0001) ? YES : NO); } -//http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious +// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious int log2int(int x) { int y = 0; while (x >>= 1) { diff --git a/objc/PdAudioController.h b/objc/PdAudioController.h index ce8a0812a..ecdbd0924 100644 --- a/objc/PdAudioController.h +++ b/objc/PdAudioController.h @@ -13,17 +13,17 @@ #import "PdAudioUnit.h" typedef enum PdAudioStatus { - PdAudioOK = 0, // success - PdAudioError = -1, // unrecoverable error + PdAudioOK = 0, // success + PdAudioError = -1, // unrecoverable error PdAudioPropertyChanged = 1 // some properties have changed to run correctly (not fatal) } PdAudioStatus; -/* PdAudioController: A class for managing PdAudioUnit within iOS - * by using the AVFoundation and Audio Services APIs. - * Handles phone interruptions and provides high level configuration methods - * The returned PdAudioStatus is used to indicate success, failure, or - * that parameters had to be adjusted in order to work. - */ +/// PdAudioController: A class for managing PdAudioUnit within iOS +/// by using the AVFoundation and Audio Services APIs. +/// Handles phone interruptions and provides high level configuration methods +/// The returned PdAudioStatus is used to indicate success, failure, or +/// that parameters had to be adjusted in order to work. +/// #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 @interface PdAudioController : NSObject #else @@ -31,38 +31,39 @@ typedef enum PdAudioStatus { @interface PdAudioController : NSObject #endif -// Read only properties that are set by the configure methods +/// Read only properties that are set by the configure methods @property (nonatomic, readonly) int sampleRate; @property (nonatomic, readonly) int numberChannels; @property (nonatomic, readonly) BOOL inputEnabled; @property (nonatomic, readonly) BOOL mixingEnabled; @property (nonatomic, readonly) int ticksPerBuffer; -// Check or set the active status of the audio unit +/// Check or set the active status of the audio unit @property (nonatomic, getter=isActive) BOOL active; -// Configure the audio with the specified samplerate, as well as number of output channels (which will also be the number of -// input channels if input is enable). Note that this method has three possible outcomes: success, failure, or conditional -// success, where parameters had to be adjusted to set up the audio. In the third case, you can query the sample rate and -// channel properties to determine whether the selected configuration is acceptable. Specifying mixingEnabled = YES will -// allow the app to continue playing audio along with other apps (such as iPod music player). +/// Configure the audio with the specified samplerate, as well as number of output channels (which will also be the number of +/// input channels if input is enable). Note that this method has three possible outcomes: success, failure, or conditional +/// success, where parameters had to be adjusted to set up the audio. In the third case, you can query the sample rate and +/// channel properties to determine whether the selected configuration is acceptable. Specifying mixingEnabled = YES will +/// allow the app to continue playing audio along with other apps (such as iPod music player). - (PdAudioStatus)configurePlaybackWithSampleRate:(int)sampleRate numberChannels:(int)numChannels inputEnabled:(BOOL)inputEnabled mixingEnabled:(BOOL)mixingEnabled; -// Configure audio for ambient use, without input channels. Specifying mixingEnabled = YES will allow the app to continue -// playing audio along with other apps (such as iPod music player). +/// Configure audio for ambient use, without input channels. Specifying mixingEnabled = YES will allow the app to continue +/// playing audio along with other apps (such as iPod music player). - (PdAudioStatus)configureAmbientWithSampleRate:(int)sampleRate numberChannels:(int)numChannels mixingEnabled:(BOOL)mixingEnabled; -// Configure the ticksPerBuffer parameter, which will change the audio sessions IO buffer size. -// This can be done on the fly, while audio is running. Note that the audio session only accepts -// values that correspond to a number of frames that are a power of 2 and sometimes this value -// is ignored by the audio unit, which tries to work with whatever number of frames it is provided. +/// Configure the ticksPerBuffer parameter, which will change the audio sessions IO buffer size. +/// This can be done on the fly, while audio is running. Note that the audio session only accepts +/// values that correspond to a number of frames that are a power of 2 and sometimes this value +/// is ignored by the audio unit, which tries to work with whatever number of frames it is provided. - (PdAudioStatus)configureTicksPerBuffer:(int)ticksPerBuffer; +/// Print current settings to the console. - (void)print; @end diff --git a/objc/PdAudioController.m b/objc/PdAudioController.m index aee965b0a..150ad73eb 100644 --- a/objc/PdAudioController.m +++ b/objc/PdAudioController.m @@ -43,21 +43,21 @@ @implementation PdAudioController - (id)init { self = [super init]; - if (self) { - AVAudioSession *globalSession = [AVAudioSession sharedInstance]; + if (self) { + AVAudioSession *globalSession = [AVAudioSession sharedInstance]; [AVAudioSession sharedInstance]; #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interruptionOcurred:) name:AVAudioSessionInterruptionNotification object:nil]; - #else + #else // AVAudioSessionDelegate is deprecated starting in iOS 6 globalSession.delegate = self; #endif - NSError *error = nil; - [globalSession setActive:YES error:&error]; - AU_LOG_IF_ERROR(error, @"Audio Session activation failed"); - AU_LOGV(@"Audio Session initialized"); - self.audioUnit = [[[PdAudioUnit alloc] init] autorelease]; + NSError *error = nil; + [globalSession setActive:YES error:&error]; + AU_LOG_IF_ERROR(error, @"Audio Session activation failed"); + AU_LOGV(@"Audio Session initialized"); + self.audioUnit = [[[PdAudioUnit alloc] init] autorelease]; } return self; } @@ -71,9 +71,9 @@ - (int)ticksPerBuffer { OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &asBufferDuration); AU_LOG_IF_ERROR(status, @"error getting audio session buffer duration (status = %ld)", status); AU_LOGV(@"kAudioSessionProperty_CurrentHardwareIOBufferDuration: %f seconds", asBufferDuration); - + ticksPerBuffer_ = round((asBufferDuration * self.sampleRate) / (NSTimeInterval)[PdBase getBlockSize]); - return ticksPerBuffer_; + return ticksPerBuffer_; } - (void)dealloc { @@ -82,47 +82,47 @@ - (void)dealloc { } - (PdAudioStatus)configurePlaybackWithSampleRate:(int)sampleRate - numberChannels:(int)numChannels - inputEnabled:(BOOL)inputEnabled - mixingEnabled:(BOOL)mixingEnabled { + numberChannels:(int)numChannels + inputEnabled:(BOOL)inputEnabled + mixingEnabled:(BOOL)mixingEnabled { PdAudioStatus status = PdAudioOK; - if (inputEnabled && ![[AVAudioSession sharedInstance] inputIsAvailable]) { - inputEnabled = NO; - status |= PdAudioPropertyChanged; - } - status |= [self updateSampleRate:sampleRate]; - if (status == PdAudioError) { - return PdAudioError; - } - status |= [self selectCategoryWithInputs:inputEnabled isAmbient:NO allowsMixing:mixingEnabled]; - if (status == PdAudioError) { - return PdAudioError; - } - status |= [self configureAudioUnitWithNumberChannels:numChannels inputEnabled:inputEnabled]; + if (inputEnabled && ![[AVAudioSession sharedInstance] inputIsAvailable]) { + inputEnabled = NO; + status |= PdAudioPropertyChanged; + } + status |= [self updateSampleRate:sampleRate]; + if (status == PdAudioError) { + return PdAudioError; + } + status |= [self selectCategoryWithInputs:inputEnabled isAmbient:NO allowsMixing:mixingEnabled]; + if (status == PdAudioError) { + return PdAudioError; + } + status |= [self configureAudioUnitWithNumberChannels:numChannels inputEnabled:inputEnabled]; AU_LOGV(@"configuration finished. status: %d", status); return status; } - (PdAudioStatus)configureAmbientWithSampleRate:(int)sampleRate - numberChannels:(int)numChannels - mixingEnabled:(BOOL)mixingEnabled { + numberChannels:(int)numChannels + mixingEnabled:(BOOL)mixingEnabled { PdAudioStatus status = [self updateSampleRate:sampleRate]; - if (status == PdAudioError) { - return PdAudioError; - } - status |= [self selectCategoryWithInputs:NO isAmbient:YES allowsMixing:mixingEnabled]; - if (status == PdAudioError) { - return PdAudioError; - } - status |= [self configureAudioUnitWithNumberChannels:numChannels inputEnabled:NO]; + if (status == PdAudioError) { + return PdAudioError; + } + status |= [self selectCategoryWithInputs:NO isAmbient:YES allowsMixing:mixingEnabled]; + if (status == PdAudioError) { + return PdAudioError; + } + status |= [self configureAudioUnitWithNumberChannels:numChannels inputEnabled:NO]; AU_LOGV(@"configuration finished. status: %d", status); return status; } - (PdAudioStatus)configureAudioUnitWithNumberChannels:(int)numChannels inputEnabled:(BOOL)inputEnabled { - inputEnabled_ = inputEnabled; - numberChannels_ = numChannels; - return [self.audioUnit configureWithSampleRate:self.sampleRate numberChannels:numChannels inputEnabled:inputEnabled] ? PdAudioError : PdAudioOK; + inputEnabled_ = inputEnabled; + numberChannels_ = numChannels; + return [self.audioUnit configureWithSampleRate:self.sampleRate numberChannels:numChannels inputEnabled:inputEnabled] ? PdAudioError : PdAudioOK; } - (PdAudioStatus)updateSampleRate:(int)sampleRate { @@ -133,16 +133,16 @@ - (PdAudioStatus)updateSampleRate:(int)sampleRate { #else [globalSession setPreferredHardwareSampleRate:sampleRate error:&error]; #endif - if (error) { - return PdAudioError; - } + if (error) { + return PdAudioError; + } #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 double currentHardwareSampleRate = globalSession.sampleRate; #else double currentHardwareSampleRate = globalSession.currentHardwareSampleRate; #endif AU_LOGV(@"currentHardwareSampleRate: %.0f", currentHardwareSampleRate); - sampleRate_ = currentHardwareSampleRate; + sampleRate_ = currentHardwareSampleRate; if (!floatsAreEqual(sampleRate, currentHardwareSampleRate)) { AU_LOG(@"*** WARNING *** could not update samplerate, resetting to match audio session (%.0fHz)", currentHardwareSampleRate); return PdAudioPropertyChanged; @@ -151,22 +151,22 @@ - (PdAudioStatus)updateSampleRate:(int)sampleRate { } - (PdAudioStatus)selectCategoryWithInputs:(BOOL)hasInputs isAmbient:(BOOL)isAmbient allowsMixing:(BOOL)allowsMixing { - NSString *category; + NSString *category; OSStatus status; - if (hasInputs && isAmbient) { - AU_LOG(@"impossible session config; this should never happen"); - return PdAudioError; - } else if (!isAmbient) { - category = hasInputs ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback; - } else { - category = allowsMixing ? AVAudioSessionCategoryAmbient : AVAudioSessionCategorySoloAmbient; - } - NSError *error = nil; - [[AVAudioSession sharedInstance] setCategory:category error:&error]; - if (error) { - AU_LOG(@"failed to set session category, error %@", error); - return PdAudioError; - } + if (hasInputs && isAmbient) { + AU_LOG(@"impossible session config; this should never happen"); + return PdAudioError; + } else if (!isAmbient) { + category = hasInputs ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback; + } else { + category = allowsMixing ? AVAudioSessionCategoryAmbient : AVAudioSessionCategorySoloAmbient; + } + NSError *error = nil; + [[AVAudioSession sharedInstance] setCategory:category error:&error]; + if (error) { + AU_LOG(@"failed to set session category, error %@", error); + return PdAudioError; + } if ([category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) { UInt32 defaultToSpeaker = 1; status = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(defaultToSpeaker), &defaultToSpeaker); @@ -175,14 +175,14 @@ - (PdAudioStatus)selectCategoryWithInputs:(BOOL)hasInputs isAmbient:(BOOL)isAmbi return PdAudioError; } } - UInt32 mix = allowsMixing ? 1 : 0; - status = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(mix), &mix); - if (status) { - AU_LOG(@"error setting kAudioSessionProperty_OverrideCategoryMixWithOthers to %@ (status = %ld)", (allowsMixing ? @"YES" : @"NO"), status); - return PdAudioError; - } - mixingEnabled_ = allowsMixing; - return PdAudioOK; + UInt32 mix = allowsMixing ? 1 : 0; + status = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(mix), &mix); + if (status) { + AU_LOG(@"error setting kAudioSessionProperty_OverrideCategoryMixWithOthers to %@ (status = %ld)", (allowsMixing ? @"YES" : @"NO"), status); + return PdAudioError; + } + mixingEnabled_ = allowsMixing; + return PdAudioOK; } /* note about the magic 0.5 added to numberFrames: @@ -193,46 +193,46 @@ - (PdAudioStatus)selectCategoryWithInputs:(BOOL)hasInputs isAmbient:(BOOL)isAmbi * value is not halved. */ - (PdAudioStatus)configureTicksPerBuffer:(int)ticksPerBuffer { - int numberFrames = [PdBase getBlockSize] * ticksPerBuffer; - NSTimeInterval bufferDuration = (Float32) (numberFrames + 0.5) / self.sampleRate; - - NSError *error = nil; - AVAudioSession *globalSession = [AVAudioSession sharedInstance]; - [globalSession setPreferredIOBufferDuration:bufferDuration error:&error]; - if (error) return PdAudioError; - - AU_LOGV(@"numberFrames: %d, specified bufferDuration: %f", numberFrames, bufferDuration); - AU_LOGV(@"preferredIOBufferDuration: %f", globalSession.preferredIOBufferDuration); - - int tpb = self.ticksPerBuffer; - if (tpb != ticksPerBuffer) { - AU_LOG(@"*** WARNING *** could not set IO buffer duration to match %d ticks, got %d ticks instead", ticksPerBuffer, tpb); - return PdAudioPropertyChanged; - } - return PdAudioOK; + int numberFrames = [PdBase getBlockSize] * ticksPerBuffer; + NSTimeInterval bufferDuration = (Float32) (numberFrames + 0.5) / self.sampleRate; + + NSError *error = nil; + AVAudioSession *globalSession = [AVAudioSession sharedInstance]; + [globalSession setPreferredIOBufferDuration:bufferDuration error:&error]; + if (error) return PdAudioError; + + AU_LOGV(@"numberFrames: %d, specified bufferDuration: %f", numberFrames, bufferDuration); + AU_LOGV(@"preferredIOBufferDuration: %f", globalSession.preferredIOBufferDuration); + + int tpb = self.ticksPerBuffer; + if (tpb != ticksPerBuffer) { + AU_LOG(@"*** WARNING *** could not set IO buffer duration to match %d ticks, got %d ticks instead", ticksPerBuffer, tpb); + return PdAudioPropertyChanged; + } + return PdAudioOK; } - (void)setActive:(BOOL)active { - self.audioUnit.active = active; - active_ = self.audioUnit.isActive; + self.audioUnit.active = active; + active_ = self.audioUnit.isActive; } #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 // receives interrupt notification and calls ex-AVAudioSessionDelegate methods - (void)interruptionOcurred:(NSNotification*)notification { - NSDictionary *interuptionDict = notification.userInfo; - NSUInteger interuptionType = (NSUInteger)[interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey]; - if (interuptionType == AVAudioSessionInterruptionTypeBegan) { - [self beginInterruption]; + NSDictionary *interuptionDict = notification.userInfo; + NSUInteger interuptionType = (NSUInteger)[interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey]; + if (interuptionType == AVAudioSessionInterruptionTypeBegan) { + [self beginInterruption]; } - else if (interuptionType == AVAudioSessionInterruptionTypeEnded) { - [self endInterruptionWithFlags:(NSUInteger)[interuptionDict valueForKey:AVAudioSessionInterruptionOptionKey]]; + else if (interuptionType == AVAudioSessionInterruptionTypeEnded) { + [self endInterruptionWithFlags:(NSUInteger)[interuptionDict valueForKey:AVAudioSessionInterruptionOptionKey]]; } } #endif - (void)beginInterruption { - self.audioUnit.active = NO; // Leave active_ unchanged. + self.audioUnit.active = NO; // Leave active_ unchanged. AU_LOGV(@"interrupted"); } @@ -242,7 +242,7 @@ - (void)endInterruptionWithFlags:(NSUInteger)flags { #else if (flags == AVAudioSessionInterruptionFlags_ShouldResume) { #endif - self.active = active_; // Not redundant due to weird ObjC accessor. + self.active = active_; // Not redundant due to weird ObjC accessor. AU_LOGV(@"ended interruption"); } else { AU_LOGV(@"still interrupted"); diff --git a/objc/PdAudioUnit.h b/objc/PdAudioUnit.h index 58cf936c5..01b805bdd 100644 --- a/objc/PdAudioUnit.h +++ b/objc/PdAudioUnit.h @@ -11,28 +11,28 @@ #import #import "AudioUnit/AudioUnit.h" -/* PdAudioUnit: object that operates pd's audio input and - * output through an Audio Unit. The parameters can be changed - * after it has been instatiated with its configure method, - * which will cause the underlying audio unit to be reconstructed. - * - * For debugging, AU_DEBUG_VERBOSE can be defined to print extra information. - */ +/// PdAudioUnit: object that operates pd's audio input and +/// output through an Audio Unit. The parameters can be changed +/// after it has been instatiated with its configure method, +/// which will cause the underlying audio unit to be reconstructed. +/// +/// For debugging, AU_DEBUG_VERBOSE can be defined to print extra information. +/// @interface PdAudioUnit : NSObject -// A reference to the audio unit, which can be used to query or set other properties +/// A reference to the audio unit, which can be used to query or set other properties @property (nonatomic, readonly) AudioUnit audioUnit; -// Check or set the active status of the audio unit +/// Check or set the active status of the audio unit @property (nonatomic, getter = isActive) BOOL active; -// The configure method sets all parameters of the audio unit that may require it to be -// recreated at the same time. This is an expensive process and will stop the audio unit -// before any reconstruction, causing a momentary pause in audio and UI if -// run from the main thread. Returns zero on success. +/// The configure method sets all parameters of the audio unit that may require it to be +/// recreated at the same time. This is an expensive process and will stop the audio unit +/// before any reconstruction, causing a momentary pause in audio and UI if +/// run from the main thread. Returns zero on success. - (int)configureWithSampleRate:(Float64)sampleRate numberChannels:(int)numChannels inputEnabled:(BOOL)inputEnabled; -// Print info on the audio unit settings to the console +/// Print info on the audio unit settings to the console - (void)print; @end diff --git a/objc/PdAudioUnit.m b/objc/PdAudioUnit.m index 4cb87d09d..92e1bc71c 100644 --- a/objc/PdAudioUnit.m +++ b/objc/PdAudioUnit.m @@ -18,8 +18,8 @@ @interface PdAudioUnit () { @private - BOOL inputEnabled_; - BOOL initialized_; + BOOL inputEnabled_; + BOOL initialized_; int blockSizeAsLog_; } @@ -38,9 +38,9 @@ @implementation PdAudioUnit #pragma mark - Init / Dealloc - (id)init { - self = [super init]; - if (self) { - initialized_ = NO; + self = [super init]; + if (self) { + initialized_ = NO; active_ = NO; blockSizeAsLog_ = log2int([PdBase getBlockSize]); } @@ -56,10 +56,10 @@ - (void)dealloc { - (int)configureWithSampleRate:(Float64)sampleRate numberChannels:(int)numChannels inputEnabled:(BOOL)inputEnabled { Boolean wasActive = self.isActive; - inputEnabled_ = inputEnabled; + inputEnabled_ = inputEnabled; if (![self initAudioUnitWithSampleRate:sampleRate numberChannels:numChannels inputEnabled:inputEnabled_]) { - return -1; - } + return -1; + } [PdBase openAudioWithSampleRate:sampleRate inputChannels:(inputEnabled_ ? numChannels : 0) outputChannels:numChannels]; [PdBase computeAudio:YES]; self.active = wasActive; @@ -67,36 +67,36 @@ - (int)configureWithSampleRate:(Float64)sampleRate numberChannels:(int)numChanne } - (void)setActive:(BOOL)active { - if (!initialized_) { - return; - } - if (active == active_) { - return; - } - if (active) { - AU_RETURN_IF_ERROR(AudioOutputUnitStart(audioUnit_)); - } else { - AU_RETURN_IF_ERROR(AudioOutputUnitStop(audioUnit_)); - } - active_ = active; + if (!initialized_) { + return; + } + if (active == active_) { + return; + } + if (active) { + AU_RETURN_IF_ERROR(AudioOutputUnitStart(audioUnit_)); + } else { + AU_RETURN_IF_ERROR(AudioOutputUnitStop(audioUnit_)); + } + active_ = active; } #pragma mark - AURenderCallback static OSStatus AudioRenderCallback(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData) { + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) { PdAudioUnit *pdAudioUnit = (PdAudioUnit *)inRefCon; Float32 *auBuffer = (Float32 *)ioData->mBuffers[0].mData; - + if (pdAudioUnit->inputEnabled_) { AudioUnitRender(pdAudioUnit->audioUnit_, ioActionFlags, inTimeStamp, kInputElement, inNumberFrames, ioData); } - + int ticks = inNumberFrames >> pdAudioUnit->blockSizeAsLog_; // this is a faster way of computing (inNumberFrames / blockSize) [PdBase processFloatWithInputBuffer:auBuffer outputBuffer:auBuffer ticks:ticks]; return noErr; @@ -105,24 +105,24 @@ static OSStatus AudioRenderCallback(void *inRefCon, #pragma mark - Private - (void)destroyAudioUnit { - if (!initialized_) { - return; - } - self.active = NO; - initialized_ = NO; + if (!initialized_) { + return; + } + self.active = NO; + initialized_ = NO; AU_RETURN_IF_ERROR(AudioUnitUninitialize(audioUnit_)); AU_RETURN_IF_ERROR(AudioComponentInstanceDispose(audioUnit_)); AU_LOGV(@"destroyed audio unit"); } - (BOOL)initAudioUnitWithSampleRate:(Float64)sampleRate numberChannels:(int)numChannels inputEnabled:(BOOL)inputEnabled { - [self destroyAudioUnit]; + [self destroyAudioUnit]; AudioComponentDescription ioDescription = [self ioDescription]; AudioComponent audioComponent = AudioComponentFindNext(NULL, &ioDescription); AU_RETURN_FALSE_IF_ERROR(AudioComponentInstanceNew(audioComponent, &audioUnit_)); - - AudioStreamBasicDescription streamDescription = [self ASBDForSampleRate:sampleRate numberChannels:numChannels]; - if (inputEnabled) { + + AudioStreamBasicDescription streamDescription = [self ASBDForSampleRate:sampleRate numberChannels:numChannels]; + if (inputEnabled) { UInt32 enableInput = 1; AU_RETURN_FALSE_IF_ERROR(AudioUnitSetProperty(audioUnit_, kAudioOutputUnitProperty_EnableIO, @@ -155,9 +155,9 @@ - (BOOL)initAudioUnitWithSampleRate:(Float64)sampleRate numberChannels:(int)numC kOutputElement, &callbackStruct, sizeof(callbackStruct))); - + AU_RETURN_FALSE_IF_ERROR(AudioUnitInitialize(audioUnit_)); - initialized_ = YES; + initialized_ = YES; AU_LOGV(@"initialized audio unit"); return true; } @@ -176,7 +176,7 @@ - (AudioComponentDescription)ioDescription { - (AudioStreamBasicDescription)ASBDForSampleRate:(Float64)sampleRate numberChannels:(UInt32)numberChannels { const int kFloatSize = 4; const int kBitSize = 8; - + AudioStreamBasicDescription description; memset(&description, 0, sizeof(description)); @@ -193,22 +193,22 @@ - (AudioStreamBasicDescription)ASBDForSampleRate:(Float64)sampleRate numberChann } - (void)print { - if (!initialized_) { + if (!initialized_) { AU_LOG(@"Audio Unit not initialized"); - return; - } - + return; + } + UInt32 sizeASBD = sizeof(AudioStreamBasicDescription); - + if (inputEnabled_) { AudioStreamBasicDescription inputStreamDescription; memset (&inputStreamDescription, 0, sizeof(inputStreamDescription)); AU_RETURN_IF_ERROR(AudioUnitGetProperty(audioUnit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - kInputElement, - &inputStreamDescription, - &sizeASBD)); + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + kInputElement, + &inputStreamDescription, + &sizeASBD)); AU_LOG(@"input ASBD:"); AU_LOG(@" mSampleRate: %.0fHz", inputStreamDescription.mSampleRate); AU_LOG(@" mChannelsPerFrame: %lu", inputStreamDescription.mChannelsPerFrame); @@ -221,15 +221,15 @@ - (void)print { } else { AU_LOG(@"no input ASBD"); } - + AudioStreamBasicDescription outputStreamDescription; memset(&outputStreamDescription, 0, sizeASBD); AU_RETURN_IF_ERROR(AudioUnitGetProperty(audioUnit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - kOutputElement, - &outputStreamDescription, - &sizeASBD)); + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + kOutputElement, + &outputStreamDescription, + &sizeASBD)); AU_LOG(@"output ASBD:"); AU_LOG(@" mSampleRate: %.0fHz", outputStreamDescription.mSampleRate); AU_LOG(@" mChannelsPerFrame: %lu", outputStreamDescription.mChannelsPerFrame); diff --git a/objc/PdBase.h b/objc/PdBase.h index 29dced6de..993571a7b 100644 --- a/objc/PdBase.h +++ b/objc/PdBase.h @@ -37,8 +37,7 @@ #import - -// Listener interface for messages from Pd. +/// Listener interface for messages from Pd. @protocol PdListener @optional - (void)receiveBangFromSource:(NSString *)source; @@ -48,14 +47,14 @@ - (void)receiveMessage:(NSString *)message withArguments:(NSArray *)arguments fromSource:(NSString *)source; @end -// Receiver interface for printing and receiving messages from Pd. +/// Receiver interface for printing and receiving messages from Pd. @protocol PdReceiverDelegate @optional - (void)receivePrint:(NSString *)message; @end -// Listener interface for MIDI from Pd. +/// Listener interface for MIDI from Pd. @protocol PdMidiListener @optional - (void)receiveNoteOn:(int)pitch withVelocity:(int)velocity forChannel:(int)channel; @@ -67,7 +66,7 @@ @end -// Receiver interface for MIDI messages from Pd. +/// Receiver interface for MIDI messages from Pd. @protocol PdMidiReceiverDelegate @optional - (void)receiveMidiByte:(int)byte forPort:(int)port; @@ -80,13 +79,13 @@ + (void)initialize; -// Set the delegates to receive messages and midi. Only to be called from main thread. -// An NSTimer is used to poll for messages be default. However, the input queues can be processed -// manually when setting the respective delegate using pollingEnabled:NO. -// -// Setting the delegate to nil disconnects the existing delegate and turns off message polling if it's running. -// -// Note: PdBase retains the delegates: call setDelegate or setMidiDelegate with nil in order to release delegate. +/// Set the delegates to receive messages and midi. Only to be called from main thread. +/// An NSTimer is used to poll for messages be default. However, the input queues can be processed +/// manually when setting the respective delegate using pollingEnabled:NO. +/// +/// Setting the delegate to nil disconnects the existing delegate and turns off message polling if it's running. +/// +/// Note: PdBase retains the delegates: call setDelegate or setMidiDelegate with nil in order to release delegate. + (void)setDelegate:(NSObject *)newDelegate pollingEnabled:(BOOL)pollingEnabled; + (void)setMidiDelegate:(NSObject *)newDelegate pollingEnabled:(BOOL)pollingEnabled; + (void)setDelegate:(NSObject *)newDelegate; // Starts with polling enabled. @@ -95,8 +94,8 @@ + (NSObject *)delegate; + (NSObject *)midiDelegate; -// Process the message and midi input queues manually. -// Only required if the respective delegate was set with pollingEnabled:NO. +/// Process the message and midi input queues manually. +/// Only required if the respective delegate was set with pollingEnabled:NO. + (void)receiveMessages; + (void)receiveMidi; @@ -108,15 +107,10 @@ + (int)dollarZeroForFile:(void *)x; + (int)getBlockSize; -+ (int)openAudioWithSampleRate:(int)samplerate - inputChannels:(int)inputChannels - outputChannels:(int)outputchannels; -+ (int)processFloatWithInputBuffer:(const float *)inputBuffer - outputBuffer:(float *)outputBuffer ticks:(int)ticks; -+ (int)processDoubleWithInputBuffer:(const double *)inputBuffer - outputBuffer:(double *)outputBuffer ticks:(int)ticks; -+ (int)processShortWithInputBuffer:(const short *)inputBuffer - outputBuffer:(short *)outputBuffer ticks:(int)ticks; ++ (int)openAudioWithSampleRate:(int)samplerate inputChannels:(int)inputChannels outputChannels:(int)outputchannels; ++ (int)processFloatWithInputBuffer:(const float *)inputBuffer outputBuffer:(float *)outputBuffer ticks:(int)ticks; ++ (int)processDoubleWithInputBuffer:(const double *)inputBuffer outputBuffer:(double *)outputBuffer ticks:(int)ticks; ++ (int)processShortWithInputBuffer:(const short *)inputBuffer outputBuffer:(short *)outputBuffer ticks:(int)ticks; + (void)computeAudio:(BOOL)enable; + (void *)subscribe:(NSString *)symbol; + (void)unsubscribe:(void *)subscription; diff --git a/objc/PdBase.m b/objc/PdBase.m index 8a3be4bcc..16afd4bc4 100644 --- a/objc/PdBase.m +++ b/objc/PdBase.m @@ -40,143 +40,143 @@ #include "z_queued.h" #include "z_print_util.h" -static NSObject *delegate = nil; -static NSObject *midiDelegate = nil; + static NSObject *delegate = nil; + static NSObject *midiDelegate = nil; #pragma mark - List Conversion static NSArray *decodeList(int argc, t_atom *argv) { - NSMutableArray *list = [[NSMutableArray alloc] initWithCapacity:argc]; - for (int i = 0; i < argc; i++) { - t_atom *a = &argv[i]; - if (libpd_is_float(a)) { - float x = libpd_get_float(a); - NSNumber *num = [[NSNumber alloc] initWithFloat:x]; - [list addObject:num]; - [num release]; - } else if (libpd_is_symbol(a)) { - const char *s = libpd_get_symbol(a); - NSString *str = [[NSString alloc] initWithCString:s encoding:NSASCIIStringEncoding]; - [list addObject:str]; - [str release]; - } else { - NSLog(@"PdBase: element type unsupported: %i", a->a_type); - } - } - return (NSArray *)list; // The receiver owns the array and is responsible for releasing it. + NSMutableArray *list = [[NSMutableArray alloc] initWithCapacity:argc]; + for (int i = 0; i < argc; i++) { + t_atom *a = &argv[i]; + if (libpd_is_float(a)) { + float x = libpd_get_float(a); + NSNumber *num = [[NSNumber alloc] initWithFloat:x]; + [list addObject:num]; + [num release]; + } else if (libpd_is_symbol(a)) { + const char *s = libpd_get_symbol(a); + NSString *str = [[NSString alloc] initWithCString:s encoding:NSASCIIStringEncoding]; + [list addObject:str]; + [str release]; + } else { + NSLog(@"PdBase: element type unsupported: %i", a->a_type); + } + } + return (NSArray *)list; // The receiver owns the array and is responsible for releasing it. } static void encodeList(NSArray *list) { - for (int i = 0; i < [list count]; i++) { - NSObject *object = [list objectAtIndex:i]; - if ([object isKindOfClass:[NSNumber class]]) { - libpd_add_float([(NSNumber *)object floatValue]); - } else if ([object isKindOfClass:[NSString class]]) { - libpd_add_symbol([(NSString *)object cStringUsingEncoding:NSASCIIStringEncoding]); - } else { - NSLog(@"PdBase: message not supported. %@", [object class]); - } - } + for (int i = 0; i < [list count]; i++) { + NSObject *object = [list objectAtIndex:i]; + if ([object isKindOfClass:[NSNumber class]]) { + libpd_add_float([(NSNumber *)object floatValue]); + } else if ([object isKindOfClass:[NSString class]]) { + libpd_add_symbol([(NSString *)object cStringUsingEncoding:NSASCIIStringEncoding]); + } else { + NSLog(@"PdBase: message not supported. %@", [object class]); + } + } } #pragma mark - Hooks static void printHook(const char *s) { - if ([delegate respondsToSelector:@selector(receivePrint:)]) { - NSString *msg = [[NSString alloc] initWithCString:s encoding:NSASCIIStringEncoding]; - [delegate receivePrint:msg]; - [msg release]; - } + if ([delegate respondsToSelector:@selector(receivePrint:)]) { + NSString *msg = [[NSString alloc] initWithCString:s encoding:NSASCIIStringEncoding]; + [delegate receivePrint:msg]; + [msg release]; + } } static void bangHook(const char *src) { - if ([delegate respondsToSelector:@selector(receiveBangFromSource:)]) { - NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; - [delegate receiveBangFromSource:source]; - [source release]; - } + if ([delegate respondsToSelector:@selector(receiveBangFromSource:)]) { + NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; + [delegate receiveBangFromSource:source]; + [source release]; + } } static void floatHook(const char *src, float x) { - if ([delegate respondsToSelector:@selector(receiveFloat:fromSource:)]) { - NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; - [delegate receiveFloat:x fromSource:source]; - [source release]; - } + if ([delegate respondsToSelector:@selector(receiveFloat:fromSource:)]) { + NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; + [delegate receiveFloat:x fromSource:source]; + [source release]; + } } static void symbolHook(const char *src, const char *sym) { - if ([delegate respondsToSelector:@selector(receiveSymbol:fromSource:)]) { - NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; - NSString *symbol = [[NSString alloc] initWithCString:sym encoding:NSASCIIStringEncoding]; - [delegate receiveSymbol:symbol fromSource:source]; - [source release]; - [symbol release]; - } + if ([delegate respondsToSelector:@selector(receiveSymbol:fromSource:)]) { + NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; + NSString *symbol = [[NSString alloc] initWithCString:sym encoding:NSASCIIStringEncoding]; + [delegate receiveSymbol:symbol fromSource:source]; + [source release]; + [symbol release]; + } } static void listHook(const char *src, int argc, t_atom *argv) { - if ([delegate respondsToSelector:@selector(receiveList:fromSource:)]) { - NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; - NSArray *args = decodeList(argc, argv); - [delegate receiveList:args fromSource:source]; - [source release]; - [args release]; - } + if ([delegate respondsToSelector:@selector(receiveList:fromSource:)]) { + NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; + NSArray *args = decodeList(argc, argv); + [delegate receiveList:args fromSource:source]; + [source release]; + [args release]; + } } static void messageHook(const char *src, const char* sym, int argc, t_atom *argv) { - if ([delegate respondsToSelector:@selector(receiveMessage:withArguments:fromSource:)]) { - NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; - NSString *symbol = [[NSString alloc] initWithCString:sym encoding:NSASCIIStringEncoding]; - NSArray *args = decodeList(argc, argv); - [delegate receiveMessage:symbol withArguments:args fromSource:source]; - [source release]; - [symbol release]; - [args release]; - } + if ([delegate respondsToSelector:@selector(receiveMessage:withArguments:fromSource:)]) { + NSString *source = [[NSString alloc] initWithCString:src encoding:NSASCIIStringEncoding]; + NSString *symbol = [[NSString alloc] initWithCString:sym encoding:NSASCIIStringEncoding]; + NSArray *args = decodeList(argc, argv); + [delegate receiveMessage:symbol withArguments:args fromSource:source]; + [source release]; + [symbol release]; + [args release]; + } } static void noteonHook(int channel, int pitch, int velocity) { - if ([midiDelegate respondsToSelector:@selector(receiveNoteOn:withVelocity:forChannel:)]) { - [midiDelegate receiveNoteOn:pitch withVelocity:velocity forChannel:channel]; - } + if ([midiDelegate respondsToSelector:@selector(receiveNoteOn:withVelocity:forChannel:)]) { + [midiDelegate receiveNoteOn:pitch withVelocity:velocity forChannel:channel]; + } } static void controlChangeHook(int channel, int controller, int value) { - if ([midiDelegate respondsToSelector:@selector(receiveControlChange:forController:forChannel:)]) { - [midiDelegate receiveControlChange:value forController:controller forChannel:channel]; - } + if ([midiDelegate respondsToSelector:@selector(receiveControlChange:forController:forChannel:)]) { + [midiDelegate receiveControlChange:value forController:controller forChannel:channel]; + } } static void programChangeHook(int channel, int value) { - if ([midiDelegate respondsToSelector:@selector(receiveProgramChange:forChannel:)]) { - [midiDelegate receiveProgramChange:value forChannel:channel]; - } + if ([midiDelegate respondsToSelector:@selector(receiveProgramChange:forChannel:)]) { + [midiDelegate receiveProgramChange:value forChannel:channel]; + } } static void pitchBendHook(int channel, int value) { - if ([midiDelegate respondsToSelector:@selector(receivePitchBend:forChannel:)]) { - [midiDelegate receivePitchBend:value forChannel:channel]; - } + if ([midiDelegate respondsToSelector:@selector(receivePitchBend:forChannel:)]) { + [midiDelegate receivePitchBend:value forChannel:channel]; + } } static void aftertouchHook(int channel, int value) { - if ([midiDelegate respondsToSelector:@selector(receiveAftertouch:forChannel:)]) { - [midiDelegate receiveAftertouch:value forChannel:channel]; - } + if ([midiDelegate respondsToSelector:@selector(receiveAftertouch:forChannel:)]) { + [midiDelegate receiveAftertouch:value forChannel:channel]; + } } static void polyAftertouchHook(int channel, int pitch, int value) { - if ([midiDelegate respondsToSelector:@selector(receiveAftertouch:forChannel:)]) { - [midiDelegate receivePolyAftertouch:value forPitch:pitch forChannel:channel]; - } + if ([midiDelegate respondsToSelector:@selector(receiveAftertouch:forChannel:)]) { + [midiDelegate receivePolyAftertouch:value forPitch:pitch forChannel:channel]; + } } static void midiByteHook(int port, int byte) { - if ([midiDelegate respondsToSelector:@selector(receiveMidiByte:forPort:)]) { - [midiDelegate receiveMidiByte:byte forPort:port]; - } + if ([midiDelegate respondsToSelector:@selector(receiveMidiByte:forPort:)]) { + [midiDelegate receiveMidiByte:byte forPort:port]; + } } #pragma mark - @@ -196,285 +196,285 @@ @implementation PdBase + (void)initialize { libpd_set_queued_printhook(libpd_print_concatenator); - libpd_set_concatenated_printhook(printHook); + libpd_set_concatenated_printhook(printHook); - libpd_set_queued_banghook(bangHook); - libpd_set_queued_floathook(floatHook); - libpd_set_queued_symbolhook(symbolHook); - libpd_set_queued_listhook(listHook); - libpd_set_queued_messagehook(messageHook); + libpd_set_queued_banghook(bangHook); + libpd_set_queued_floathook(floatHook); + libpd_set_queued_symbolhook(symbolHook); + libpd_set_queued_listhook(listHook); + libpd_set_queued_messagehook(messageHook); - libpd_set_queued_noteonhook(noteonHook); - libpd_set_queued_controlchangehook(controlChangeHook); - libpd_set_queued_programchangehook(programChangeHook); - libpd_set_queued_pitchbendhook(pitchBendHook); - libpd_set_queued_aftertouchhook(aftertouchHook); - libpd_set_queued_polyaftertouchhook(polyAftertouchHook); - libpd_set_queued_midibytehook(midiByteHook); + libpd_set_queued_noteonhook(noteonHook); + libpd_set_queued_controlchangehook(controlChangeHook); + libpd_set_queued_programchangehook(programChangeHook); + libpd_set_queued_pitchbendhook(pitchBendHook); + libpd_set_queued_aftertouchhook(aftertouchHook); + libpd_set_queued_polyaftertouchhook(polyAftertouchHook); + libpd_set_queued_midibytehook(midiByteHook); - libpd_queued_init(); + libpd_queued_init(); } // Only to be called from main thread. + (void)setDelegate:(NSObject *)newDelegate { - [self setDelegate:newDelegate pollingEnabled:YES]; + [self setDelegate:newDelegate pollingEnabled:YES]; } // Only to be called from main thread. + (void)setMidiDelegate:(NSObject *)newDelegate { - [self setMidiDelegate:newDelegate pollingEnabled:YES]; + [self setMidiDelegate:newDelegate pollingEnabled:YES]; } + (void)setDelegate:(NSObject *)newDelegate pollingEnabled:(BOOL)pollingEnabled { - if (messagePollTimer) { - [messagePollTimer invalidate]; // This also releases the timer. - messagePollTimer = nil; - } - [newDelegate retain]; - [delegate release]; - delegate = newDelegate; - if (delegate && pollingEnabled) { - messagePollTimer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(receiveMessagesTimer:) userInfo:nil repeats:YES]; - [[NSRunLoop mainRunLoop] addTimer:messagePollTimer forMode:NSRunLoopCommonModes]; - } + if (messagePollTimer) { + [messagePollTimer invalidate]; // this also releases the timer. + messagePollTimer = nil; + } + [newDelegate retain]; + [delegate release]; + delegate = newDelegate; + if (delegate && pollingEnabled) { + messagePollTimer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(receiveMessagesTimer:) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:messagePollTimer forMode:NSRunLoopCommonModes]; + } } + (void)setMidiDelegate:(NSObject *)newDelegate pollingEnabled:(BOOL)pollingEnabled { - if (midiPollTimer) { - [midiPollTimer invalidate]; // This also releases the timer. - midiPollTimer = nil; - } - [newDelegate retain]; - [midiDelegate release]; - midiDelegate = newDelegate; - if (midiDelegate && pollingEnabled) { - midiPollTimer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(receiveMidiTimer:) userInfo:nil repeats:YES]; - [[NSRunLoop mainRunLoop] addTimer:midiPollTimer forMode:NSRunLoopCommonModes]; - } + if (midiPollTimer) { + [midiPollTimer invalidate]; // this also releases the timer. + midiPollTimer = nil; + } + [newDelegate retain]; + [midiDelegate release]; + midiDelegate = newDelegate; + if (midiDelegate && pollingEnabled) { + midiPollTimer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(receiveMidiTimer:) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:midiPollTimer forMode:NSRunLoopCommonModes]; + } } // Only to be initialized from main thread. + (NSObject *)delegate { - return delegate; + return delegate; } // Only to be initialized from main thread. + (NSObject *)midiDelegate { - return midiDelegate; + return midiDelegate; } + (void)receiveMessages { - libpd_queued_receive_pd_messages(); + libpd_queued_receive_pd_messages(); } + (void)receiveMidi { - libpd_queued_receive_midi_messages(); + libpd_queued_receive_midi_messages(); } + (void)receiveMessagesTimer:(NSTimer*)theTimer { - libpd_queued_receive_pd_messages(); + libpd_queued_receive_pd_messages(); } + (void)receiveMidiTimer:(NSTimer*)theTimer { - libpd_queued_receive_midi_messages(); + libpd_queued_receive_midi_messages(); } + (void *)subscribe:(NSString *)symbol { - @synchronized(self) { - return libpd_bind([symbol cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + return libpd_bind([symbol cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (void)unsubscribe:(void *)subscription { - @synchronized(self) { - libpd_unbind(subscription); - } + @synchronized(self) { + libpd_unbind(subscription); + } } + (int)sendBangToReceiver:(NSString *)receiverName { - @synchronized(self) { - return libpd_bang([receiverName cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + return libpd_bang([receiverName cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (int)sendFloat:(float)value toReceiver:(NSString *)receiverName { - @synchronized(self) { - return libpd_float([receiverName cStringUsingEncoding:NSASCIIStringEncoding], value); - } + @synchronized(self) { + return libpd_float([receiverName cStringUsingEncoding:NSASCIIStringEncoding], value); + } } + (int)sendSymbol:(NSString *)symbol toReceiver:(NSString *)receiverName { - @synchronized(self) { - return libpd_symbol([receiverName cStringUsingEncoding:NSASCIIStringEncoding], - [symbol cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + return libpd_symbol([receiverName cStringUsingEncoding:NSASCIIStringEncoding], + [symbol cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (int)sendList:(NSArray *)list toReceiver:(NSString *)receiverName { - @synchronized(self) { - if (libpd_start_message((int) [list count])) return -100; - encodeList(list); - return libpd_finish_list([receiverName cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + if (libpd_start_message((int) [list count])) return -100; + encodeList(list); + return libpd_finish_list([receiverName cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (int)sendMessage:(NSString *)message withArguments:(NSArray *)list toReceiver:(NSString *)receiverName { - @synchronized(self) { - if (libpd_start_message((int) [list count])) return -100; - encodeList(list); - return libpd_finish_message([receiverName cStringUsingEncoding:NSASCIIStringEncoding], - [message cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + if (libpd_start_message((int) [list count])) return -100; + encodeList(list); + return libpd_finish_message([receiverName cStringUsingEncoding:NSASCIIStringEncoding], + [message cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (void)clearSearchPath { - @synchronized(self) { - libpd_clear_search_path(); - } + @synchronized(self) { + libpd_clear_search_path(); + } } + (void)addToSearchPath:(NSString *)path { - @synchronized(self) { - libpd_add_to_search_path([path cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + libpd_add_to_search_path([path cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (int)getBlockSize { - @synchronized(self) { - return libpd_blocksize(); - } + @synchronized(self) { + return libpd_blocksize(); + } } + (BOOL)exists:(NSString *)symbol { - @synchronized(self) { - return (BOOL) libpd_exists([symbol cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + return (BOOL) libpd_exists([symbol cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (int)openAudioWithSampleRate:(int)samplerate inputChannels:(int)inputChannels outputChannels:(int)outputchannels { - @synchronized(self) { - return libpd_init_audio(inputChannels, outputchannels, samplerate); - } + @synchronized(self) { + return libpd_init_audio(inputChannels, outputchannels, samplerate); + } } + (int)processFloatWithInputBuffer:(const float *)inputBuffer outputBuffer:(float *)outputBuffer ticks:(int)ticks { - @synchronized(self) { - return libpd_process_float(ticks, inputBuffer, outputBuffer); - } + @synchronized(self) { + return libpd_process_float(ticks, inputBuffer, outputBuffer); + } } + (int)processDoubleWithInputBuffer:(const double *)inputBuffer outputBuffer:(double *)outputBuffer ticks:(int)ticks { - @synchronized(self) { - return libpd_process_double(ticks, inputBuffer, outputBuffer); - } + @synchronized(self) { + return libpd_process_double(ticks, inputBuffer, outputBuffer); + } } + (int)processShortWithInputBuffer:(const short *)inputBuffer outputBuffer:(short *)outputBuffer ticks:(int)ticks { - @synchronized(self) { - return libpd_process_short(ticks, inputBuffer, outputBuffer); - } + @synchronized(self) { + return libpd_process_short(ticks, inputBuffer, outputBuffer); + } } + (void)computeAudio:(BOOL)enable { - NSNumber *val = [[NSNumber alloc] initWithBool:enable]; - NSArray *args = [[NSArray alloc] initWithObjects:val, nil]; - [PdBase sendMessage:@"dsp" withArguments:args toReceiver:@"pd"]; - [args release]; - [val release]; + NSNumber *val = [[NSNumber alloc] initWithBool:enable]; + NSArray *args = [[NSArray alloc] initWithObjects:val, nil]; + [PdBase sendMessage:@"dsp" withArguments:args toReceiver:@"pd"]; + [args release]; + [val release]; } + (void *)openFile:(NSString *)baseName path:(NSString *)pathName { - @synchronized(self) { - const char *base = [baseName cStringUsingEncoding:NSASCIIStringEncoding]; - const char *path = [pathName cStringUsingEncoding:NSASCIIStringEncoding]; - return libpd_openfile(base, path); - } + @synchronized(self) { + const char *base = [baseName cStringUsingEncoding:NSASCIIStringEncoding]; + const char *path = [pathName cStringUsingEncoding:NSASCIIStringEncoding]; + return libpd_openfile(base, path); + } } + (void)closeFile:(void *)x { - @synchronized(self) { - libpd_closefile(x); - } + @synchronized(self) { + libpd_closefile(x); + } } + (int)dollarZeroForFile:(void *)x { - @synchronized(self) { - return libpd_getdollarzero(x); - } + @synchronized(self) { + return libpd_getdollarzero(x); + } } + (int)arraySizeForArrayNamed:(NSString *)arrayName { - @synchronized(self) { - return libpd_arraysize([arrayName cStringUsingEncoding:NSASCIIStringEncoding]); - } + @synchronized(self) { + return libpd_arraysize([arrayName cStringUsingEncoding:NSASCIIStringEncoding]); + } } + (int)copyArrayNamed:(NSString *)arrayName withOffset:(int)offset toArray:(float *)destinationArray count:(int)n { - @synchronized(self) { - const char *name = [arrayName cStringUsingEncoding:NSASCIIStringEncoding]; - return libpd_read_array(destinationArray, name, offset, n); - } + @synchronized(self) { + const char *name = [arrayName cStringUsingEncoding:NSASCIIStringEncoding]; + return libpd_read_array(destinationArray, name, offset, n); + } } + (int)copyArray:(float *)sourceArray toArrayNamed:(NSString *)arrayName withOffset:(int)offset count:(int)n { - @synchronized(self) { - const char *name = [arrayName cStringUsingEncoding:NSASCIIStringEncoding]; - return libpd_write_array(name, offset, sourceArray, n); - } + @synchronized(self) { + const char *name = [arrayName cStringUsingEncoding:NSASCIIStringEncoding]; + return libpd_write_array(name, offset, sourceArray, n); + } } + (int)sendNoteOn:(int)channel pitch:(int)pitch velocity:(int)velocity { - @synchronized(self) { - return libpd_noteon(channel, pitch, velocity); - } + @synchronized(self) { + return libpd_noteon(channel, pitch, velocity); + } } + (int)sendControlChange:(int)channel controller:(int)controller value:(int)value { - @synchronized(self) { - return libpd_controlchange(channel, controller, value); - } + @synchronized(self) { + return libpd_controlchange(channel, controller, value); + } } + (int)sendProgramChange:(int)channel value:(int)value { - @synchronized(self) { - return libpd_programchange(channel, value); - } + @synchronized(self) { + return libpd_programchange(channel, value); + } } + (int)sendPitchBend:(int)channel value:(int)value { - @synchronized(self) { - return libpd_pitchbend(channel, value); - } + @synchronized(self) { + return libpd_pitchbend(channel, value); + } } + (int)sendAftertouch:(int)channel value:(int)value { - @synchronized(self) { - return libpd_aftertouch(channel, value); - } + @synchronized(self) { + return libpd_aftertouch(channel, value); + } } + (int)sendPolyAftertouch:(int)channel pitch:(int)pitch value:(int)value { - @synchronized(self) { - return libpd_polyaftertouch(channel, pitch, value); - } + @synchronized(self) { + return libpd_polyaftertouch(channel, pitch, value); + } } + (int)sendMidiByte:(int)port byte:(int)byte { - @synchronized(self) { - return libpd_midibyte(port, byte); - } + @synchronized(self) { + return libpd_midibyte(port, byte); + } } + (int)sendSysex:(int)port byte:(int)byte { - @synchronized(self) { - return libpd_sysex(port, byte); - } + @synchronized(self) { + return libpd_sysex(port, byte); + } } + (int)sendSysRealTime:(int)port byte:(int)byte { - @synchronized(self) { - return libpd_sysrealtime(port, byte); - } + @synchronized(self) { + return libpd_sysrealtime(port, byte); + } } @end diff --git a/objc/PdDispatcher.h b/objc/PdDispatcher.h index 942901c9e..92ad4a3cc 100644 --- a/objc/PdDispatcher.h +++ b/objc/PdDispatcher.h @@ -11,30 +11,30 @@ #import #import "PdBase.h" -// Implementation of the PdReceiverDelegate protocol from PdBase.h. Client code -// registers one instance of this class with PdBase, and then listeners for individual -// sources will be registered with the dispatcher object. -// -// Printing from Pd is done via NSLog by default; subclass and override the receivePrint -// method if you want different printing behavior. +/// Implementation of the PdReceiverDelegate protocol from PdBase.h. Client code +/// registers one instance of this class with PdBase, and then listeners for individual +/// sources will be registered with the dispatcher object. +/// +/// Printing from Pd is done via NSLog by default; subclass and override the receivePrint +/// method if you want different printing behavior. @interface PdDispatcher : NSObject { - NSMutableDictionary *listenerMap; - NSMutableDictionary *subscriptions; + NSMutableDictionary *listenerMap; + NSMutableDictionary *subscriptions; } -// Adds a listener for the given source (i.e., send symbol) in Pd. If this is the first -// listener for this source, a subscription for this symbol will automatically be registered -// with PdBase. +/// Adds a listener for the given source (i.e., send symbol) in Pd. If this is the first +/// listener for this source, a subscription for this symbol will automatically be registered +/// with PdBase. - (int)addListener:(NSObject *)listener forSource:(NSString *)source; -// Removes a listener for a source symbol and unsubscribes from messages to this symbol if -// the listener was the last listener for this symbol. +/// Removes a listener for a source symbol and unsubscribes from messages to this symbol if +/// the listener was the last listener for this symbol. - (int)removeListener:(NSObject *)listener forSource:(NSString *)source; -// Removes all listeners. +/// Removes all listeners. - (void)removeAllListeners; @end -// Subclass of PdDispatcher that logs all callbacks, mostly for development and debugging. +/// Subclass of PdDispatcher that logs all callbacks, mostly for development and debugging. @interface LoggingDispatcher : PdDispatcher {} @end diff --git a/objc/PdDispatcher.m b/objc/PdDispatcher.m index 5c41fbdb2..619e9e27b 100644 --- a/objc/PdDispatcher.m +++ b/objc/PdDispatcher.m @@ -10,131 +10,130 @@ #import "PdDispatcher.h" - @implementation PdDispatcher - (id)init { - self = [super init]; - if (self) { - listenerMap = [[NSMutableDictionary alloc] init]; - subscriptions = [[NSMutableDictionary alloc] init]; - } - return self; + self = [super init]; + if (self) { + listenerMap = [[NSMutableDictionary alloc] init]; + subscriptions = [[NSMutableDictionary alloc] init]; + } + return self; } - (void)dealloc { - for (NSValue *handle in [subscriptions allValues]) { - void *ptr = [handle pointerValue]; - [PdBase unsubscribe:ptr]; - } - [subscriptions release]; - [listenerMap release]; - [super dealloc]; + for (NSValue *handle in [subscriptions allValues]) { + void *ptr = [handle pointerValue]; + [PdBase unsubscribe:ptr]; + } + [subscriptions release]; + [listenerMap release]; + [super dealloc]; } - (int)addListener:(NSObject *)listener forSource:(NSString *)symbol { - NSMutableArray *listeners = [listenerMap objectForKey:symbol]; - if (!listeners) { - void *ptr = [PdBase subscribe:symbol]; - if (!ptr) { - return -1; - } - NSValue *handle = [NSValue valueWithPointer:ptr]; - [subscriptions setObject:handle forKey:symbol]; - listeners = [[NSMutableArray alloc] init]; - [listenerMap setObject:listeners forKey:symbol]; - [listeners release]; - } - [listeners addObject:listener]; - return 0; + NSMutableArray *listeners = [listenerMap objectForKey:symbol]; + if (!listeners) { + void *ptr = [PdBase subscribe:symbol]; + if (!ptr) { + return -1; + } + NSValue *handle = [NSValue valueWithPointer:ptr]; + [subscriptions setObject:handle forKey:symbol]; + listeners = [[NSMutableArray alloc] init]; + [listenerMap setObject:listeners forKey:symbol]; + [listeners release]; + } + [listeners addObject:listener]; + return 0; } - (int)removeListener:(NSObject *)listener forSource:(NSString *)symbol { - NSMutableArray *listeners = [listenerMap objectForKey:symbol]; - if (listeners) { - [listeners removeObject:listener]; - if ([listeners count] == 0) { - NSValue *handle = [subscriptions objectForKey:symbol]; - void *ptr = [handle pointerValue]; - [PdBase unsubscribe:ptr]; - [subscriptions removeObjectForKey:symbol]; - [listenerMap removeObjectForKey:symbol]; - } - } + NSMutableArray *listeners = [listenerMap objectForKey:symbol]; + if (listeners) { + [listeners removeObject:listener]; + if ([listeners count] == 0) { + NSValue *handle = [subscriptions objectForKey:symbol]; + void *ptr = [handle pointerValue]; + [PdBase unsubscribe:ptr]; + [subscriptions removeObjectForKey:symbol]; + [listenerMap removeObjectForKey:symbol]; + } + } return 0; } - (void)removeAllListeners { - [listenerMap removeAllObjects]; - NSEnumerator *enumerator = [subscriptions objectEnumerator]; - id object; - while (object = [enumerator nextObject]) { - NSValue *handle = object; - void *ptr = [handle pointerValue]; - [PdBase unsubscribe:ptr]; - } - [subscriptions removeAllObjects]; + [listenerMap removeAllObjects]; + NSEnumerator *enumerator = [subscriptions objectEnumerator]; + id object; + while (object = [enumerator nextObject]) { + NSValue *handle = object; + void *ptr = [handle pointerValue]; + [PdBase unsubscribe:ptr]; + } + [subscriptions removeAllObjects]; } // Override this method in subclasses if you want different printing behavior. // No need to synchronize here. - (void)receivePrint:(NSString *)message { - NSLog(@"Pd: %@\n", message); + NSLog(@"Pd: %@\n", message); } - (void)receiveBangFromSource:(NSString *)source { - NSArray *listeners = [listenerMap objectForKey:source]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveBangFromSource:)]) { - [listener receiveBangFromSource:source]; - } else { - NSLog(@"Unhandled bang from %@", source); - } - } + NSArray *listeners = [listenerMap objectForKey:source]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveBangFromSource:)]) { + [listener receiveBangFromSource:source]; + } else { + NSLog(@"Unhandled bang from %@", source); + } + } } - (void)receiveFloat:(float)received fromSource:(NSString *)source { - NSArray *listeners = [listenerMap objectForKey:source]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveFloat:fromSource:)]) { - [listener receiveFloat:received fromSource:source]; - } else { - NSLog(@"Unhandled float from %@", source); - } - } + NSArray *listeners = [listenerMap objectForKey:source]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveFloat:fromSource:)]) { + [listener receiveFloat:received fromSource:source]; + } else { + NSLog(@"Unhandled float from %@", source); + } + } } - (void)receiveSymbol:(NSString *)symbol fromSource:(NSString *)source { - NSArray *listeners = [listenerMap objectForKey:source]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveSymbol:fromSource:)]) { - [listener receiveSymbol:symbol fromSource:source]; - } else { - NSLog(@"Unhandled symbol from %@", source); - } - } + NSArray *listeners = [listenerMap objectForKey:source]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveSymbol:fromSource:)]) { + [listener receiveSymbol:symbol fromSource:source]; + } else { + NSLog(@"Unhandled symbol from %@", source); + } + } } - (void)receiveList:(NSArray *)list fromSource:(NSString *)source { - NSArray *listeners = [listenerMap objectForKey:source]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveList:fromSource:)]) { - [listener receiveList:list fromSource:source]; - } else { - NSLog(@"Unhandled list from %@", source); - } - } + NSArray *listeners = [listenerMap objectForKey:source]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveList:fromSource:)]) { + [listener receiveList:list fromSource:source]; + } else { + NSLog(@"Unhandled list from %@", source); + } + } } - (void) receiveMessage:(NSString *)message withArguments:(NSArray *)arguments fromSource:(NSString *)source { - NSArray *listeners = [listenerMap objectForKey:source]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveMessage:withArguments:fromSource:)]) { - [listener receiveMessage:message withArguments:arguments fromSource:source]; - } else { - NSLog(@"Unhandled typed message from %@", source); - } - } + NSArray *listeners = [listenerMap objectForKey:source]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveMessage:withArguments:fromSource:)]) { + [listener receiveMessage:message withArguments:arguments fromSource:source]; + } else { + NSLog(@"Unhandled typed message from %@", source); + } + } } @end @@ -143,28 +142,28 @@ - (void) receiveMessage:(NSString *)message withArguments:(NSArray *)arguments f @implementation LoggingDispatcher -(void)receiveBangFromSource:(NSString *)source { - NSLog(@"Received bang from source %@", source); - [super receiveBangFromSource:source]; + NSLog(@"Received bang from source %@", source); + [super receiveBangFromSource:source]; } -(void)receiveFloat:(float)received fromSource:(NSString *)source { - NSLog(@"Received float %f from source %@", received, source); - [super receiveFloat:received fromSource:source]; + NSLog(@"Received float %f from source %@", received, source); + [super receiveFloat:received fromSource:source]; } -(void)receiveSymbol:(NSString *)symbol fromSource:(NSString *)source { - NSLog(@"Received symbol %@ from source %@", symbol, source); - [super receiveSymbol:symbol fromSource:source]; + NSLog(@"Received symbol %@ from source %@", symbol, source); + [super receiveSymbol:symbol fromSource:source]; } -(void)receiveList:(NSArray *)list fromSource:(NSString *)source { - NSLog(@"Received list %@ from source %@", list, source); - [super receiveList:list fromSource:source]; + NSLog(@"Received list %@ from source %@", list, source); + [super receiveList:list fromSource:source]; } -(void)receiveMessage:(NSString *)message withArguments:(NSArray *)arguments fromSource:(NSString *)source { - NSLog(@"Received message %@ with arguments %@ from source %@", message, arguments, source); - [super receiveMessage:message withArguments:arguments fromSource:source]; + NSLog(@"Received message %@ with arguments %@ from source %@", message, arguments, source); + [super receiveMessage:message withArguments:arguments fromSource:source]; } @end diff --git a/objc/PdFile.h b/objc/PdFile.h index 24d70f907..b4f815527 100644 --- a/objc/PdFile.h +++ b/objc/PdFile.h @@ -13,19 +13,21 @@ #import @interface PdFile : NSObject { - NSValue *fileReference_; - int dollarZero_; - NSString *baseName_; - NSString *pathName_; + NSValue *fileReference_; + int dollarZero_; + NSString *baseName_; + NSString *pathName_; } -@property (nonatomic, assign, readonly) int dollarZero; // unique $0 argument assigned by pd -@property (nonatomic, copy, readonly) NSString *baseName; // stored file base name -@property (nonatomic, copy, readonly) NSString *pathName; // stored file path name +@property (nonatomic, assign, readonly) int dollarZero; //< unique $0 argument assigned by pd +@property (nonatomic, copy, readonly) NSString *baseName; //< stored file base name +@property (nonatomic, copy, readonly) NSString *pathName; //< stored file path name -+ (id)openFileNamed:(NSString *)baseName path:(NSString *)pathName; // open a pd file/patch and return a representative PdFile object -- (id)openNewInstance; // open a new instance of an existing PdFile -- (bool)isValid; // is the file reference valid? (aka non-nil) -- (void)closeFile; // close an opened pd file (also called in dealloc) +/// open a pd file/patch and return a representative PdFile object ++ (id)openFileNamed:(NSString *)baseName path:(NSString *)pathName; + +- (id)openNewInstance; //< open a new instance of an existing PdFile +- (bool)isValid; //< is the file reference valid? (aka non-nil) +- (void)closeFile; //< close an opened pd file (also called in dealloc) @end diff --git a/objc/PdFile.m b/objc/PdFile.m index cec3b9df7..da507522c 100644 --- a/objc/PdFile.m +++ b/objc/PdFile.m @@ -35,67 +35,67 @@ @implementation PdFile #pragma mark - Class Open method + (id)openFileNamed:(NSString *)baseName path:(NSString *)pathName { - PdFile *pdFile = [[[self alloc] init] autorelease]; - if (pdFile) { - [pdFile openFile:baseName path:pathName]; - if (![pdFile fileReference]) { - return nil; - } - } - return pdFile; + PdFile *pdFile = [[[self alloc] init] autorelease]; + if (pdFile) { + [pdFile openFile:baseName path:pathName]; + if (![pdFile fileReference]) { + return nil; + } + } + return pdFile; } #pragma mark - #pragma mark - Dealloc - (void)dealloc { - [self closeFile]; - self.pathName = nil; - self.baseName = nil; - self.fileReference = nil; + [self closeFile]; + self.pathName = nil; + self.baseName = nil; + self.fileReference = nil; - [super dealloc]; + [super dealloc]; } #pragma mark - #pragma mark - Public Open / Close methods - (void)openFile:(NSString *)baseName path:(NSString *)pathName { - if (!baseName || !pathName) { - return; - } - self.baseName = baseName; - self.pathName = pathName; - - void *x = [PdBase openFile:baseName path:pathName]; - if (x) { - self.fileReference = [NSValue valueWithPointer:x]; - self.dollarZero = [PdBase dollarZeroForFile:x]; - } + if (!baseName || !pathName) { + return; + } + self.baseName = baseName; + self.pathName = pathName; + + void *x = [PdBase openFile:baseName path:pathName]; + if (x) { + self.fileReference = [NSValue valueWithPointer:x]; + self.dollarZero = [PdBase dollarZeroForFile:x]; + } } - (PdFile *)openNewInstance { - return [PdFile openFileNamed:self.baseName path:self.pathName]; + return [PdFile openFileNamed:self.baseName path:self.pathName]; } - (bool)isValid { - return (bool) self.fileReference; + return (bool) self.fileReference; } - (void)closeFile { - void *x = [self.fileReference pointerValue]; - if (x) { - [PdBase closeFile:x]; - self.fileReference = nil; - } + void *x = [self.fileReference pointerValue]; + if (x) { + [PdBase closeFile:x]; + self.fileReference = nil; + } } #pragma mark - #pragma mark - Util - (NSString *)description { - return [NSString stringWithFormat: @"Patch: \"%@\" $0: %d valid: %d", - self.baseName, self.dollarZero, [self isValid]]; + return [NSString stringWithFormat: @"Patch: \"%@\" $0: %d valid: %d", + self.baseName, self.dollarZero, [self isValid]]; } @end diff --git a/objc/PdMidiDispatcher.h b/objc/PdMidiDispatcher.h index 0a17cc9ea..2ca830743 100644 --- a/objc/PdMidiDispatcher.h +++ b/objc/PdMidiDispatcher.h @@ -11,26 +11,26 @@ #import #import "PdBase.h" -// Implementation of the PdMidiReceiverDelegate protocol from PdBase.h. Client code -// registers one instance of this class with PdBase, and then listeners for individual -// channels will be registered with the dispatcher object. -// -// Raw MIDI bytes are only printed by default; subclass and override the receiveMidiByte -// method if you want to handle raw MIDI aka data sent to [midiout]. +/// Implementation of the PdMidiReceiverDelegate protocol from PdBase.h. Client code +/// registers one instance of this class with PdBase, and then listeners for individual +/// channels will be registered with the dispatcher object. +/// +/// Raw MIDI bytes are only printed by default; subclass and override the receiveMidiByte +/// method if you want to handle raw MIDI aka data sent to [midiout]. @interface PdMidiDispatcher : NSObject { - NSMutableDictionary *listenerMap; + NSMutableDictionary *listenerMap; } -// Adds a listener for the given MIDI channel in Pd. +/// Adds a listener for the given MIDI channel in Pd. - (int)addListener:(NSObject *)listener forChannel:(int)channel; -// Removes a listener for a channel. +/// Removes a listener for a channel. - (int)removeListener:(NSObject *)listener forChannel:(int)channel; -// Removes all listeners. +/// Removes all listeners. - (void)removeAllListeners; @end -// Subclass of PdMidiDisptcher that logs all callbacks, mostly for development and debugging. +/// Subclass of PdMidiDisptcher that logs all callbacks, mostly for development and debugging. @interface LoggingMidiDispatcher : PdMidiDispatcher {} @end diff --git a/objc/PdMidiDispatcher.m b/objc/PdMidiDispatcher.m index 04f81944d..83785b949 100644 --- a/objc/PdMidiDispatcher.m +++ b/objc/PdMidiDispatcher.m @@ -10,159 +10,157 @@ #import "PdMidiDispatcher.h" - @implementation PdMidiDispatcher - (id)init { - self = [super init]; - if (self) { - listenerMap = [[NSMutableDictionary alloc] init]; - } - return self; + self = [super init]; + if (self) { + listenerMap = [[NSMutableDictionary alloc] init]; + } + return self; } - (void)dealloc { - [listenerMap removeAllObjects]; - [listenerMap release]; - [super dealloc]; + [listenerMap removeAllObjects]; + [listenerMap release]; + [super dealloc]; } - (int)addListener:(NSObject *)listener forChannel: (int)channel { - NSMutableArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - if (!listeners) { - listeners = [[NSMutableArray alloc] init]; - [listenerMap setObject:listeners forKey:[NSNumber numberWithInt:channel]]; - [listeners release]; - } - [listeners addObject:listener]; - return 0; + NSMutableArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + if (!listeners) { + listeners = [[NSMutableArray alloc] init]; + [listenerMap setObject:listeners forKey:[NSNumber numberWithInt:channel]]; + [listeners release]; + } + [listeners addObject:listener]; + return 0; } - (int)removeListener:(NSObject *)listener forChannel:(int)channel { - NSMutableArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - if (listeners) { - [listeners removeObject:listener]; - if ([listeners count] == 0) { - [listenerMap removeObjectForKey:[NSNumber numberWithInt:channel]]; - } - } - return 0; + NSMutableArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + if (listeners) { + [listeners removeObject:listener]; + if ([listeners count] == 0) { + [listenerMap removeObjectForKey:[NSNumber numberWithInt:channel]]; + } + } + return 0; } - (void)removeAllListeners { - [listenerMap removeAllObjects]; + [listenerMap removeAllObjects]; } - (void)receiveNoteOn:(int)pitch withVelocity:(int)velocity forChannel:(int)channel { - NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveNoteOn:pitch:velocity:)]) { - [listener receiveNoteOn:pitch withVelocity:velocity forChannel:channel]; - } else { - NSLog(@"Unhandled noteon on channel %d", channel); - } - } + NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveNoteOn:pitch:velocity:)]) { + [listener receiveNoteOn:pitch withVelocity:velocity forChannel:channel]; + } else { + NSLog(@"Unhandled noteon on channel %d", channel); + } + } } - (void)receiveControlChange:(int)value forController:(int)controller forChannel:(int)channel { - NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveControlChange:controller:value:)]) { - [listener receiveControlChange:value forController:controller forChannel:channel]; - } else { - NSLog(@"Unhandled control change on channel %d", channel); - } - } + NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveControlChange:controller:value:)]) { + [listener receiveControlChange:value forController:controller forChannel:channel]; + } else { + NSLog(@"Unhandled control change on channel %d", channel); + } + } } - (void)receiveProgramChange:(int)value forChannel:(int)channel { - NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveProgramChange:value:)]) { - [listener receiveProgramChange:value forChannel:channel]; - } else { - NSLog(@"Unhandled program change on channel %d", channel); - } - } + NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveProgramChange:value:)]) { + [listener receiveProgramChange:value forChannel:channel]; + } else { + NSLog(@"Unhandled program change on channel %d", channel); + } + } } - (void)receivePitchBend:(int)value forChannel:(int)channel { - NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receivePitchBend:value:)]) { - [listener receivePitchBend:value forChannel:channel]; - } else { - NSLog(@"Unhandled pitch bend on channel %d", channel); - } - } + NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receivePitchBend:value:)]) { + [listener receivePitchBend:value forChannel:channel]; + } else { + NSLog(@"Unhandled pitch bend on channel %d", channel); + } + } } - (void)receiveAftertouch:(int)value forChannel:(int)channel { - NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receiveAftertouch:value:)]) { - [listener receiveAftertouch:value forChannel:channel]; - } else { - NSLog(@"Unhandled aftertouch on channel %d", channel); - } - } + NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receiveAftertouch:value:)]) { + [listener receiveAftertouch:value forChannel:channel]; + } else { + NSLog(@"Unhandled aftertouch on channel %d", channel); + } + } } - (void)receivePolyAftertouch:(int)value forPitch:(int)pitch forChannel:(int)channel { - NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; - for (NSObject *listener in listeners) { - if ([listener respondsToSelector:@selector(receivePolyAftertouch:pitch:value:)]) { - [listener receivePolyAftertouch:value forPitch:pitch forChannel:channel]; - } else { - NSLog(@"Unhandled poly aftertouch on channel %d", channel); - } - } + NSArray *listeners = [listenerMap objectForKey:[NSNumber numberWithInt:channel]]; + for (NSObject *listener in listeners) { + if ([listener respondsToSelector:@selector(receivePolyAftertouch:pitch:value:)]) { + [listener receivePolyAftertouch:value forPitch:pitch forChannel:channel]; + } else { + NSLog(@"Unhandled poly aftertouch on channel %d", channel); + } + } } // Override this method in subclasses if you want different printing behavior. // No need to synchronize here. - (void)receiveMidiByte:(int)byte forPort: (int)port { - NSLog(@"Received midi byte: %d 0x%X", port, byte); + NSLog(@"Received midi byte: %d 0x%X", port, byte); } @end - @implementation LoggingMidiDispatcher - (void)receiveNoteOn:(int)pitch withVelocity:(int)velocity forChannel:(int)channel { - NSLog(@"Received noteon %d %d %d", channel, pitch, velocity); - [super receiveNoteOn:pitch withVelocity:velocity forChannel:channel]; + NSLog(@"Received noteon %d %d %d", channel, pitch, velocity); + [super receiveNoteOn:pitch withVelocity:velocity forChannel:channel]; } - (void)receiveControlChange:(int)value forController:(int)controller forChannel:(int)channel { - NSLog(@"Received control change %d %d %d", channel, controller, value); - [super receiveControlChange:value forController:controller forChannel:channel]; + NSLog(@"Received control change %d %d %d", channel, controller, value); + [super receiveControlChange:value forController:controller forChannel:channel]; } - (void)receiveProgramChange:(int)value forChannel:(int)channel { - NSLog(@"Received program change %d %d", channel, value); - [super receiveProgramChange:value forChannel:channel]; + NSLog(@"Received program change %d %d", channel, value); + [super receiveProgramChange:value forChannel:channel]; } - (void)receivePitchBend:(int)value forChannel:(int)channel { - NSLog(@"Received pitch bend %d %d", channel, value); - [super receivePitchBend:value forChannel:channel]; + NSLog(@"Received pitch bend %d %d", channel, value); + [super receivePitchBend:value forChannel:channel]; } - (void)receiveAftertouch:(int)value forChannel:(int)channel { - NSLog(@"Received aftertouch %d %d", channel, value); - [super receiveAftertouch:value forChannel:channel]; + NSLog(@"Received aftertouch %d %d", channel, value); + [super receiveAftertouch:value forChannel:channel]; } - (void)receivePolyAftertouch: (int)value forPitch:(int)pitch forChannel:(int)channel { - NSLog(@"Received poly aftertouch: %d %d %d", channel, pitch, value); - [super receivePolyAftertouch:value forPitch:pitch forChannel:channel]; + NSLog(@"Received poly aftertouch: %d %d %d", channel, pitch, value); + [super receivePolyAftertouch:value forPitch:pitch forChannel:channel]; } - (void)receiveMidiByte: (int)byte forPort: (int)port { - NSLog(@"Received midi byte: %d 0x%X", port, byte); - [super receiveMidiByte:byte forPort:port]; + NSLog(@"Received midi byte: %d 0x%X", port, byte); + [super receiveMidiByte:byte forPort:port]; } @end