#import "ViewController.h"
@interface ViewController ()
@property (readwrite) AUGraph processingGraph;
@property (readwrite) AudioUnit samplerUnit;
@property (readwrite) AudioUnit ioUnit;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (BOOL) createAUGraph {
// Each core audio call returns an OSStatus. This means that we
// Can see if there have been any errors in the setup
OSStatus result = noErr;
// Create 2 audio units one sampler and one IO
AUNode samplerNode, ioNode;
// Specify the common portion of an audio unit's identify, used for both audio units
// in the graph.
// Setup the manufacturer - in this case Apple
AudioComponentDescription cd = {};
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
// Instantiate an audio processing graph
result = NewAUGraph (&_processingGraph);
NSCAssert (result == noErr, @"Unable to create an AUGraph object. Error code: %d '%.4s'", (int) result, (const char *)&result);
//Specify the Sampler unit, to be used as the first node of the graph
cd.componentType = kAudioUnitType_MusicDevice; // type - music device
cd.componentSubType = kAudioUnitSubType_Sampler; // sub type - sampler to convert our MIDI
// Add the Sampler unit node to the graph
result = AUGraphAddNode (self.processingGraph, &cd, &samplerNode);
NSCAssert (result == noErr, @"Unable to add the Sampler unit to the audio processing graph. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Specify the Output unit, to be used as the second and final node of the graph
cd.componentType = kAudioUnitType_Output; // Output
cd.componentSubType = kAudioUnitSubType_RemoteIO; // Output to speakers
// Add the Output unit node to the graph
result = AUGraphAddNode (self.processingGraph, &cd, &ioNode);
NSCAssert (result == noErr, @"Unable to add the Output unit to the audio processing graph. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Open the graph
result = AUGraphOpen (self.processingGraph);
NSCAssert (result == noErr, @"Unable to open the audio processing graph. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Connect the Sampler unit to the output unit
result = AUGraphConnectNodeInput (self.processingGraph, samplerNode, 0, ioNode, 0);
NSCAssert (result == noErr, @"Unable to interconnect the nodes in the audio processing graph. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Obtain a reference to the Sampler unit from its node
result = AUGraphNodeInfo (self.processingGraph, samplerNode, 0, &_samplerUnit);
NSCAssert (result == noErr, @"Unable to obtain a reference to the Sampler unit. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Obtain a reference to the I/O unit from its node
result = AUGraphNodeInfo (self.processingGraph, ioNode, 0, &_ioUnit);
NSCAssert (result == noErr, @"Unable to obtain a reference to the I/O unit. Error code: %d '%.4s'", (int) result, (const char *)&result);
return YES;
}
// Starting with instantiated audio processing graph, configure its
// audio units, initialize it, and start it.
- (void) configureAndStartAudioProcessingGraph: (AUGraph) graph {
OSStatus result = noErr;
if (graph) {
// Initialize the audio processing graph.
result = AUGraphInitialize (graph);
NSAssert (result == noErr, @"Unable to initialze AUGraph object. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Start the graph
result = AUGraphStart (graph);
NSAssert (result == noErr, @"Unable to start audio processing graph. Error code: %d '%.4s'", (int) result, (const char *)&result);
// Print out the graph to the console
//CAShow (graph);
}
}
// Load a sound effect from a SoundFont file
-(OSStatus) loadFromDLSOrSoundFont: (NSURL *)bankURL withPatch: (int)presetNumber {
OSStatus result = noErr;
// fill out a bank preset data structure
AUSamplerBankPresetData bpdata;
bpdata.bankURL = (__bridge CFURLRef) bankURL;
bpdata.bankMSB = kAUSampler_DefaultMelodicBankMSB;
bpdata.bankLSB = kAUSampler_DefaultBankLSB;
bpdata.presetID = (UInt8) presetNumber;
// set the kAUSamplerProperty_LoadPresetFromBank property
result = AudioUnitSetProperty(self.samplerUnit,
kAUSamplerProperty_LoadPresetFromBank,
kAudioUnitScope_Global,
0,
&bpdata,
sizeof(bpdata));
// check for errors
NSCAssert (result == noErr,
@"Unable to set the preset property on the Sampler. Error code:%d '%.4s'",
(int) result,
(const char *)&result);
return result;
}
- (IBAction)playMidi:(id)sender {
// Create a new music sequence
MusicSequence s;
// Initialise the music sequence
NewMusicSequence(&s);
NSString *midiFilePath = [[NSBundle mainBundle]
pathForResource:@"Asimpletest"
ofType:@"mid"];
// Create a new URL which points to the MIDI file
NSURL * midiFileURL = [NSURL fileURLWithPath:midiFilePath];
MusicSequenceFileLoad(s, (__bridge CFURLRef)(midiFileURL), 0, 0);
// Create a new music player
MusicPlayer p;
// Initialise the music player
NewMusicPlayer(&p);
// ************* Tell the music sequence to output through our new AUGraph
MusicSequenceSetAUGraph(s, self.processingGraph);
// ************* Load the sound font from file
NSURL *presetURL = [[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Gorts_Filters" ofType:@"sf2"]];
// *************[B][U][COLOR="Red"] this is the preset value (int) 10 that seems to be the problem.[/COLOR][/U][/B]
[self loadFromDLSOrSoundFont: (NSURL *)presetURL withPatch: (int)10];
// Load the sequence into the music player
MusicPlayerSetSequence(p, s);
// Called to do some MusicPlayer setup. This just
// reduces latency when MusicPlayerStart is called
MusicPlayerPreroll(p);
// Starts the music playing
MusicPlayerStart(p);
// Get length of track so that we know how long to kill time for
MusicTrack t;
MusicTimeStamp len;
UInt32 sz = sizeof(MusicTimeStamp);
MusicSequenceGetIndTrack(s, 1, &t);
MusicTrackGetProperty(t, kSequenceTrackProperty_TrackLength, &len, &sz);
while (1) { // kill time until the music is over
usleep (3 * 1000 * 1000);
MusicTimeStamp now = 0;
MusicPlayerGetTime (p, &now);
if (now >= len)
break;
}
// Stop the player and dispose of the objects
MusicPlayerStop(p);
DisposeMusicSequence(s);
DisposeMusicPlayer(p);
}
@end