以编程方式获取 AVAudioEngineGraph
Get AVAudioEngineGraph programmatically
在我的应用程序中,我创建了一个 AVAudioEngine 并在其上附加了 AVAudioNodes。
- 是否可以通过编程方式获取附加节点?
- 是否可以让节点连接到给定的 AVAudioNode?
当我记录引擎的描述时,我可以看到所有的 AVAudioEngineGraph,但是我找不到以编程方式获取这些信息的方法,有人能给我一个解决方案吗?
(lldb) po _engine
________ GraphDescription ________
AVAudioEngineGraph 0x7fb04541ac60: initialized = 1, running = 1, number of nodes = 4
******** output chain ********
node 0x600002448c00 {'auou' 'rioc' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x60000244cd00 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x600002448c00, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002473680 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus1) 0x600002462580, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002462580 {'auou' 'rioc' 'appl'}, 'I'
outputs = 2
(bus0, en0) -> (bus0) 0x0, {}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
(bus1, en1) -> (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
******** input chain ********
node 0x600002462580 {'auou' 'rioc' 'appl'}, 'I'
outputs = 2
(bus0, en0) -> (bus0) 0x0, {}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
(bus1, en1) -> (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002473680 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus1) 0x600002462580, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x60000244cd00 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x600002448c00, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002448c00 {'auou' 'rioc' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
为了管理自定义初始化,我为我要加载的每个类别(或特定)audioUnit 创建了 audioUnit 包装器。这些包装器由工厂提供并由我的应用程序的业务对象引用。
到目前为止我主要使用的包装器是所谓的 AUMIDISynth
componentType = kAudioUnitType_MusicDevice;
componentSubType = kAudioUnitSubType_MIDISynth;
componentManufacturer = kAudioUnitManufacturer_Apple;
允许同时加载和播放来自 soundBank 文件的不同音色。
AUMIDISynth 的子类包装器公开了一个名为
的方法
-(NSError*)loadProgramChange:(uint8_t)programChange channel:(uint8_t)channel;
其他对象(SynthPlayers)观察到从AudioEngine开始发送的通知,并通过调用上述方法响应此通知到自己的audioUnit wrapper实现如下
-(NSError*)loadProgramChange:(uint8_t)programChange channel:(uint8_t)channel{
NSError *error;
if (!self.audioUnit.engine || !self.audioUnit.engine.isRunning) {
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
uint32_t enabled = 1;
OSStatus status = AudioUnitSetProperty(
self.audioUnit.audioUnit,
kAUMIDISynthProperty_EnablePreload,
kAudioUnitScope_Global,
0,
&enabled,
sizeof(enabled));
if (status != noErr) {
NSLog(@"error %d",status);
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
uint8_t pcCommand = 0xC0 | channel;
status = MusicDeviceMIDIEvent(self.audioUnit.audioUnit, pcCommand, programChange, 0, 0);
if (status != noErr) {
NSLog(@"error %d",status);
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
enabled = 0;
status = AudioUnitSetProperty(
self.audioUnit.audioUnit,
kAUMIDISynthProperty_EnablePreload,
kAudioUnitScope_Global,
0,
&enabled,
sizeof(enabled));
if (status != noErr) {
NSLog(@"error %d",status);
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
return error;
}
在我的应用程序中,我创建了一个 AVAudioEngine 并在其上附加了 AVAudioNodes。
- 是否可以通过编程方式获取附加节点?
- 是否可以让节点连接到给定的 AVAudioNode?
当我记录引擎的描述时,我可以看到所有的 AVAudioEngineGraph,但是我找不到以编程方式获取这些信息的方法,有人能给我一个解决方案吗?
(lldb) po _engine
________ GraphDescription ________
AVAudioEngineGraph 0x7fb04541ac60: initialized = 1, running = 1, number of nodes = 4
******** output chain ********
node 0x600002448c00 {'auou' 'rioc' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x60000244cd00 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x600002448c00, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002473680 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus1) 0x600002462580, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002462580 {'auou' 'rioc' 'appl'}, 'I'
outputs = 2
(bus0, en0) -> (bus0) 0x0, {}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
(bus1, en1) -> (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
******** input chain ********
node 0x600002462580 {'auou' 'rioc' 'appl'}, 'I'
outputs = 2
(bus0, en0) -> (bus0) 0x0, {}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
(bus1, en1) -> (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002473680 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus1) 0x600002462580, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x60000244cd00 {'aumx' 'mcmx' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x600002473680, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
outputs = 1
(bus0, en1) -> (bus0) 0x600002448c00, {'auou' 'rioc' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
node 0x600002448c00 {'auou' 'rioc' 'appl'}, 'I'
inputs = 1
(bus0, en1) <- (bus0) 0x60000244cd00, {'aumx' 'mcmx' 'appl'}, [ 2 ch, 44100 Hz, 'lpcm' (0x00000029) 32-bit little-endian float, deinterleaved]
为了管理自定义初始化,我为我要加载的每个类别(或特定)audioUnit 创建了 audioUnit 包装器。这些包装器由工厂提供并由我的应用程序的业务对象引用。
到目前为止我主要使用的包装器是所谓的 AUMIDISynth
componentType = kAudioUnitType_MusicDevice;
componentSubType = kAudioUnitSubType_MIDISynth;
componentManufacturer = kAudioUnitManufacturer_Apple;
允许同时加载和播放来自 soundBank 文件的不同音色。
AUMIDISynth 的子类包装器公开了一个名为
的方法-(NSError*)loadProgramChange:(uint8_t)programChange channel:(uint8_t)channel;
其他对象(SynthPlayers)观察到从AudioEngine开始发送的通知,并通过调用上述方法响应此通知到自己的audioUnit wrapper实现如下
-(NSError*)loadProgramChange:(uint8_t)programChange channel:(uint8_t)channel{
NSError *error;
if (!self.audioUnit.engine || !self.audioUnit.engine.isRunning) {
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
uint32_t enabled = 1;
OSStatus status = AudioUnitSetProperty(
self.audioUnit.audioUnit,
kAUMIDISynthProperty_EnablePreload,
kAudioUnitScope_Global,
0,
&enabled,
sizeof(enabled));
if (status != noErr) {
NSLog(@"error %d",status);
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
uint8_t pcCommand = 0xC0 | channel;
status = MusicDeviceMIDIEvent(self.audioUnit.audioUnit, pcCommand, programChange, 0, 0);
if (status != noErr) {
NSLog(@"error %d",status);
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
enabled = 0;
status = AudioUnitSetProperty(
self.audioUnit.audioUnit,
kAUMIDISynthProperty_EnablePreload,
kAudioUnitScope_Global,
0,
&enabled,
sizeof(enabled));
if (status != noErr) {
NSLog(@"error %d",status);
error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:nil];
}
return error;
}