如何增加 MIDI 合成器 volume/gain 而不会在 iOS 上失真?
How do I increase MIDI synth volume/gain without distortion on iOS?
我正在使用来自 this library 的 MIKMIDISynthesizer
在 iPhone 上播放 MIDI 文件。不幸的是,音量非常低,即使将 iPhone 的系统音量调到最大也是如此。为了进一步增加它,我尝试了这些东西:
- 修改所有 MIDI Note On 事件的速度 属性 到最大值 127。这略微但不足以提高音量。
- 按照 here 所述,将 混合器节点 添加到
AUGraph
。这足以提高音量,但会立即严重扭曲信号,以至于质量太差。
- 使用 Polyphone 等音色编辑器提高音色样本的音量。这没有明显的效果。
现在我 运行 别无选择。是否有任何其他参数或级别(例如 AVAudioSession
或 CoreMIDI
,可能)我错过了并提供了调整 volume/gain 的可能性?或执行相同操作的 MIDI 命令?
代码片段
1.使用混合器节点
这是我修改的 MIKMIDISynthesizer
部分,以便使用混音器节点控制音量。
- (BOOL)setupAUGraph
{
AUGraph graph;
OSStatus err = 0;
// 1. Create new AUGraph
if ((err = NewAUGraph(&graph))) {
NSLog(@"Unable to create AU graph: %@", @(err));
return NO;
}
// 2. Create output node
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_RemoteIO;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
AUNode outputNode;
if ((err = AUGraphAddNode(graph, &outputcd, &outputNode))) {
NSLog(@"Unable to add ouptput node to graph: %@", @(err));
return NO;
}
// 3. Create the instrument node
AudioComponentDescription instrumentcd = self.componentDescription;
AUNode instrumentNode;
if ((err = AUGraphAddNode(graph, &instrumentcd, &instrumentNode))) {
NSLog(@"Unable to add instrument node to AU graph: %@", @(err));
return NO;
}
if ((err = AUGraphOpen(graph))) {
NSLog(@"Unable to open AU graph: %@", @(err));
return NO;
}
AudioUnit instrumentUnit;
if ((err = AUGraphNodeInfo(graph, instrumentNode, NULL, &instrumentUnit))) {
NSLog(@"Unable to get instrument AU unit: %@", @(err));
return NO;
}
// 4. Create the mixer node
AUNode mixerNode;
AudioComponentDescription cd = {};
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
cd.componentType = kAudioUnitType_Mixer;
cd.componentSubType = kAudioUnitSubType_MultiChannelMixer;
if ((err = AUGraphAddNode(graph, &cd, &mixerNode))) {
NSLog(@"Unable to add mixer node to AU graph: %@", @(err));
return NO;
}
if ((err = AUGraphNodeInfo(graph, mixerNode, 0, &_mixerUnit))) {
NSLog(@"Unable to fetch mixer node reference from AU graph: %@", @(err));
return NO;
}
UInt32 busCount = 2;
err = AudioUnitSetProperty(_mixerUnit,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Input,
0,
&busCount,
sizeof (busCount)
);
if (err) {
NSLog(@"Unable to set mixer unit properties");
return NO;
}
// 5.1 Connect the instrument node as the mixer node's input
if ((err = AUGraphConnectNodeInput(graph, instrumentNode, 0, mixerNode, 0))) {
NSLog(@"Unable to connect input node and mixer node: %@", @(err));
return NO;
}
// 5.2 Connect the mixer node as the output node's input
if ((err = AUGraphConnectNodeInput(graph, mixerNode, 0, outputNode, 0))) {
NSLog(@"Unable to connect input node and mixer node: %@", @(err));
return NO;
}
if ((err = AUGraphInitialize(graph))) {
NSLog(@"Unable to initialize AU graph: %@", @(err));
return NO;
}
// 6. Finally, start the graph
if ((err = AUGraphStart(graph))) {
NSLog(@"Unable to start AU graph: %@", @(err));
return NO;
}
self.graph = graph;
self.instrumentUnit = instrumentUnit;
return YES;
}
设置混音器节点后,我可以像这样改变音量(引入削波!):
-(void) setVolume: (float) volume {
AudioUnitSetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, volume, 0);
}
2。更改 MIDI 事件
第二种方法将每个 Node On 事件的 velocity
属性 设置为最大值 127。它可以在没有任何噪音的情况下增加音量,但只能达到一定的水平。代码位于 MIKMIDINoteEvent
:
+ (MIKMIDINoteOnCommand *)noteOnCommandFromNoteEvent:(MIKMIDINoteEvent *)noteEvent clock:(MIKMIDIClock *)clock
{
MIKMutableMIDINoteOnCommand *noteOn = [MIKMutableMIDINoteOnCommand commandForCommandType:MIKMIDICommandTypeNoteOn];
noteOn.midiTimestamp = [clock midiTimeStampForMusicTimeStamp:noteEvent.timeStamp];
noteOn.channel = noteEvent.channel;
noteOn.note = noteEvent.note;
noteOn.velocity = 127; // <------- Here's the magic
return [noteOn copy];
}
MIDI 合成器使用的某些类型的采样波形可能会发生这种情况。采样波形的峰值音量可能已经包含接近或处于该格式可能的最大值的样本(例如,对于 16 位样本为 +-32767,对于浮点样本为 +-1.0),即使平均音量(能量总和)是太低。因此,任何简单的音量线性增加都会产生听起来很糟糕的削波噪声。
各种压缩器技术或滤波器可能能够在不削波的情况下增加平均音量,但这会增加其自身的质量降低(但比削波更不烦人)失真。
补充:使用另一个 midi 采样器、声音字体或具有接近恒定音量(较低的 PAPR、峰均功率比)的语音是另一种可能性。
您是否尝试设置采样率等于 44100.0 赫兹的 AVAudioSession?
我终于明白了。我的 AVSession
的类别设置为 AVAudioSessionCategoryPlayAndRecord
因为我还使用了麦克风,它会自动通过 iPhone 顶部的小耳机输出所有音频。这就是为什么它显得如此安静。为了将输出路由到主扬声器,您必须调用
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&err];
尽管如此,还是感谢大家的故障排除,我很感激。
我正在使用来自 this library 的 MIKMIDISynthesizer
在 iPhone 上播放 MIDI 文件。不幸的是,音量非常低,即使将 iPhone 的系统音量调到最大也是如此。为了进一步增加它,我尝试了这些东西:
- 修改所有 MIDI Note On 事件的速度 属性 到最大值 127。这略微但不足以提高音量。
- 按照 here 所述,将 混合器节点 添加到
AUGraph
。这足以提高音量,但会立即严重扭曲信号,以至于质量太差。 - 使用 Polyphone 等音色编辑器提高音色样本的音量。这没有明显的效果。
现在我 运行 别无选择。是否有任何其他参数或级别(例如 AVAudioSession
或 CoreMIDI
,可能)我错过了并提供了调整 volume/gain 的可能性?或执行相同操作的 MIDI 命令?
代码片段
1.使用混合器节点
这是我修改的 MIKMIDISynthesizer
部分,以便使用混音器节点控制音量。
- (BOOL)setupAUGraph
{
AUGraph graph;
OSStatus err = 0;
// 1. Create new AUGraph
if ((err = NewAUGraph(&graph))) {
NSLog(@"Unable to create AU graph: %@", @(err));
return NO;
}
// 2. Create output node
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_RemoteIO;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
AUNode outputNode;
if ((err = AUGraphAddNode(graph, &outputcd, &outputNode))) {
NSLog(@"Unable to add ouptput node to graph: %@", @(err));
return NO;
}
// 3. Create the instrument node
AudioComponentDescription instrumentcd = self.componentDescription;
AUNode instrumentNode;
if ((err = AUGraphAddNode(graph, &instrumentcd, &instrumentNode))) {
NSLog(@"Unable to add instrument node to AU graph: %@", @(err));
return NO;
}
if ((err = AUGraphOpen(graph))) {
NSLog(@"Unable to open AU graph: %@", @(err));
return NO;
}
AudioUnit instrumentUnit;
if ((err = AUGraphNodeInfo(graph, instrumentNode, NULL, &instrumentUnit))) {
NSLog(@"Unable to get instrument AU unit: %@", @(err));
return NO;
}
// 4. Create the mixer node
AUNode mixerNode;
AudioComponentDescription cd = {};
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
cd.componentType = kAudioUnitType_Mixer;
cd.componentSubType = kAudioUnitSubType_MultiChannelMixer;
if ((err = AUGraphAddNode(graph, &cd, &mixerNode))) {
NSLog(@"Unable to add mixer node to AU graph: %@", @(err));
return NO;
}
if ((err = AUGraphNodeInfo(graph, mixerNode, 0, &_mixerUnit))) {
NSLog(@"Unable to fetch mixer node reference from AU graph: %@", @(err));
return NO;
}
UInt32 busCount = 2;
err = AudioUnitSetProperty(_mixerUnit,
kAudioUnitProperty_ElementCount,
kAudioUnitScope_Input,
0,
&busCount,
sizeof (busCount)
);
if (err) {
NSLog(@"Unable to set mixer unit properties");
return NO;
}
// 5.1 Connect the instrument node as the mixer node's input
if ((err = AUGraphConnectNodeInput(graph, instrumentNode, 0, mixerNode, 0))) {
NSLog(@"Unable to connect input node and mixer node: %@", @(err));
return NO;
}
// 5.2 Connect the mixer node as the output node's input
if ((err = AUGraphConnectNodeInput(graph, mixerNode, 0, outputNode, 0))) {
NSLog(@"Unable to connect input node and mixer node: %@", @(err));
return NO;
}
if ((err = AUGraphInitialize(graph))) {
NSLog(@"Unable to initialize AU graph: %@", @(err));
return NO;
}
// 6. Finally, start the graph
if ((err = AUGraphStart(graph))) {
NSLog(@"Unable to start AU graph: %@", @(err));
return NO;
}
self.graph = graph;
self.instrumentUnit = instrumentUnit;
return YES;
}
设置混音器节点后,我可以像这样改变音量(引入削波!):
-(void) setVolume: (float) volume {
AudioUnitSetParameter(_mixerUnit, kMultiChannelMixerParam_Volume, kAudioUnitScope_Output, 0, volume, 0);
}
2。更改 MIDI 事件
第二种方法将每个 Node On 事件的 velocity
属性 设置为最大值 127。它可以在没有任何噪音的情况下增加音量,但只能达到一定的水平。代码位于 MIKMIDINoteEvent
:
+ (MIKMIDINoteOnCommand *)noteOnCommandFromNoteEvent:(MIKMIDINoteEvent *)noteEvent clock:(MIKMIDIClock *)clock
{
MIKMutableMIDINoteOnCommand *noteOn = [MIKMutableMIDINoteOnCommand commandForCommandType:MIKMIDICommandTypeNoteOn];
noteOn.midiTimestamp = [clock midiTimeStampForMusicTimeStamp:noteEvent.timeStamp];
noteOn.channel = noteEvent.channel;
noteOn.note = noteEvent.note;
noteOn.velocity = 127; // <------- Here's the magic
return [noteOn copy];
}
MIDI 合成器使用的某些类型的采样波形可能会发生这种情况。采样波形的峰值音量可能已经包含接近或处于该格式可能的最大值的样本(例如,对于 16 位样本为 +-32767,对于浮点样本为 +-1.0),即使平均音量(能量总和)是太低。因此,任何简单的音量线性增加都会产生听起来很糟糕的削波噪声。
各种压缩器技术或滤波器可能能够在不削波的情况下增加平均音量,但这会增加其自身的质量降低(但比削波更不烦人)失真。
补充:使用另一个 midi 采样器、声音字体或具有接近恒定音量(较低的 PAPR、峰均功率比)的语音是另一种可能性。
您是否尝试设置采样率等于 44100.0 赫兹的 AVAudioSession?
我终于明白了。我的 AVSession
的类别设置为 AVAudioSessionCategoryPlayAndRecord
因为我还使用了麦克风,它会自动通过 iPhone 顶部的小耳机输出所有音频。这就是为什么它显得如此安静。为了将输出路由到主扬声器,您必须调用
[session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&err];
尽管如此,还是感谢大家的故障排除,我很感激。