我正在使用 this library 中的 MIKMIDISynthesizer 在 iPhone 上播放 MIDI 文件。不幸的是,音量非常低,即使将 iPhone 的系统音量一直调高。为了进一步增加它,我尝试了以下方法:

  • 将所有 MIDI Note On 事件的速度属性修改为最大 127。这略微但不足以提高音量。
  • here 所述,向 AUGraph 添加一个混合器节点。这足以提高音量,但会立即严重扭曲信号,以至于质量太差。
  • 使用诸如 Polyphone 之类的声音字体编辑器提高声音字体样本的音量。这没有明显的影响。

  • 现在我的选择不多了。是否有我遗漏的任何其他参数或级别(例如 AVAudioSessionCoreMIDI ,也许)并提供调整音量/增益的可能性?或执行相同操作的 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 合成器使用的某些类型的采样波形,可能会发生这种情况。采样波形的峰值音量可能已经包含接近或处于最大可能格式的样本(例如,+-32767 表示 16 位样本,或 +-1.0 表示浮点样本),即使平均音量(能量总和)是太低。因此,音量的任何简单线性增加都会产生削波噪声,这听起来很糟糕。

    各种压缩器技术或滤波器可能能够在不削波的情况下增加平均音量,但这可以增加质量减少(但不如削波更烦人)其自身的失真。

    补充:使用另一个 midi 采样器、声音字体或具有接近恒定音量的声音(较低的 PAPR,峰均功率比)是另一种可能性。

    10-07 19:08
    查看更多