4

Apple の MIDI シンセシス コードに重大なバグがあるか、何か間違ったことをしている可能性があります。これが私の理解です。ピッチ ベンド MIDI コマンドを送信すると、ベンドの範囲は -8192 ~ 8191 で、0 までトランスポーズされます (したがって、実際の範囲は 0 ~ 16383 です)。この数値は 2 つの 7 ビット フィールドに分割されるため、実際にはこれが意味することは、128 の値の粗調整と 128 の微調整の値があるということです。

Apple のLoadPresetDemoのコマンドに似た、私が書いたピッチ ベンドのサンプルを次に示します。

// 'ratio' is the % amount to bend in current pitch range, from -1.0 to 1.0
// 'note' is the MIDI note to bend

NSUInteger bendValue = 8191 + 1 + (8191 * ratio);
NSUInteger bendMSB = (bendValue >> 7) & 0x7F;
NSUInteger bendLSB = bendValue & 0x7F;

UInt32 noteNum = note;
UInt32 noteCommand = kMIDIMessage_PitchBend << 4 | 0;

OSStatus result = MusicDeviceMIDIEvent(self.samplerUnit, noteCommand, noteNum, bendMSB, bendLSB);

ベンドMSB(コースコントロール)が変わるとピッチベンドがきっちりします。しかし、bendLSB (微調整) が変更されると、何も起こりません。言い換えれば、Apple の MIDI シンセサイザーは LSB を無視しているように見えます。つまり、ノートは醜い音の離散チャンクでのみ曲がっています。

同じことを行う別の方法を次に示します。

// 'ratio' is the % amount to bend in current pitch range, from -1.0 to 1.0

AudioUnitParameterValue bendValue = 63 + 1 + (63 * ratio); // this is a CGFloat under the hood

AudioUnitSetParameter(self.samplerUnit,
                      kAUGroupParameterID_PitchBend,
                      kAudioUnitScope_Group,
                      0,
                      bendValue,
                      0);

これは、前の例と同じ動作を示します。この方法でさらに面白いのは、kAUGroupParameterID_PitchBend のドキュメントで値の範囲が -8192 から 8191 であると指定されていることですが、これはまったく機能しません。実際の範囲は 0 ~ 127 のように見え、浮動小数点 (微調整) は無視されます。

最後に、ピッチベンド範囲を調整するために次の呼び出しを行うと:

// 'semitones' is the number of semitones (100 cents) to set the pitch bend range to
// 'cents' is the additional number of cents to set the pitch bend range to

UInt32 status = 0xB0 | 0;

MusicDeviceMIDIEvent(self.samplerUnit, status, 0x64, 0x00, 0);        // RPN pitch bend range.
MusicDeviceMIDIEvent(self.samplerUnit, status, 0x65, 0x00, 0);
MusicDeviceMIDIEvent(self.samplerUnit, status, 0x06, semitones, 0);   // Data entry MSB
MusicDeviceMIDIEvent(self.samplerUnit, status, 0x26, cents, 0);       // Data entry LSB (optional)
MusicDeviceMIDIEvent(self.samplerUnit, status, 0x64, 0x7F, 0);        // RPN reset
MusicDeviceMIDIEvent(self.samplerUnit, status, 0x65, 0x7F, 0);

何が起こるか推測できますか?そうです、LSB メッセージは無視され、ピッチ ホイールの範囲は指定された半音数だけ変化します。

何が起きてる?これは Apple のバグですか、それとも何か不足していますか? (おそらく設定パラメータ?) それともバグではないのでしょうか? もしかしたら、Apple のシンセは設計上、そのレベルの詳細を持っていないのでしょうか? そういうのってMIDI規格で合法なの!? ヘルプ!


編集:

ピッチ ベンド レンジが 40 半音に設定されている場合、粗い変化ごとに聞き取れる違いが生じます。ピッチベンド範囲が 10 半音に設定されている場合、1 秒ごとの粗い変化だけが違いを生みます。2 半音 (デフォルト) では、違いを生むには 4 回以上の粗い変更が必要です。

言い換えれば、LSB が無視されているように見えるだけでなく、ピッチが変化する最小セント数があるように見えます。これらの制限のいずれかを修正できますか? そうでない場合、曲げの解像度が高い iOS 用のソフトウェア シンセ フレームワークはありますか?

うーん... kAudioUnitSubType_Varispeed または kAudioUnitSubType_NewTimePitch を適用すると、より良い結果が得られるかもしれません...

4

1 に答える 1

6

ピッチベンドメッセージが正しくありません。これの代わりに:

UInt32 noteCommand = kMIDIMessage_PitchBend << 4 | 0;

OSStatus result = MusicDeviceMIDIEvent(self.samplerUnit, noteCommand, noteNum, bendMSB, bendLSB);

これを行う:

UInt32 bendCommand = kMIDIMessage_PitchBend << 4 | 0;

OSStatus result = MusicDeviceMIDIEvent(self.samplerUnit, bendCommand, bendLSB, bendMSB, 0);

音価はピッチベンドコマンドの一部ではありません。(また、変数の名前を、その目的をより正確に反映するように変更しnoteCommandましbendCommandた。)

LoadPresetDemoで、プロパティをMainViewController.m次のように追加しました。

@property (readwrite) NSInteger bendValue;

そしてこのコード:

- (void)sendBendValue:(NSInteger)bendValue {
    //bendValue in the range [-8192, 8191]
    const UInt32 bendCommand = kMIDIMessage_PitchBend << 4 | 0;
    bendValue += 8192;
    UInt32 bendMSB = (bendValue >> 7) & 0x7F;
    UInt32 bendLSB = bendValue & 0x7F;
    NSLog(@"MSB=%d, LSB=%d", (unsigned int)bendMSB, (unsigned int)bendLSB);
    OSStatus result = MusicDeviceMIDIEvent(self.samplerUnit, bendCommand, bendLSB, bendMSB, 0);
    NSAssert (result == noErr, @"Unable to send pitch bend message. Error code: %d '%.4s'", (int) result, (const char *)&result);
}

- (IBAction)bendDown:(id)sender {
    self.bendValue = MAX(-8192, self.bendValue - 0x20);
    [self sendBendValue:self.bendValue];
}

- (IBAction)bendCenter:(id)sender {
    self.bendValue = 0;
    [self setBendRange:50 cents:0];
    [self sendBendValue:self.bendValue];
}

- (IBAction)bendUp:(id)sender {
    self.bendValue = MIN(8191, self.bendValue + 0x20);
    [self sendBendValue:self.bendValue];
}

-(void)setBendRange:(UInt32)semitones cents:(UInt32)cents {
    MusicDeviceMIDIEvent(self.samplerUnit, 0xB0, 0x64, 0, 0);
    MusicDeviceMIDIEvent(self.samplerUnit, 0xB0, 0x65, 0, 0);
    MusicDeviceMIDIEvent(self.samplerUnit, 0xB0, 0x06, semitones, 0);
    MusicDeviceMIDIEvent(self.samplerUnit, 0xB0, 0x26, cents, 0);
    //The following two lines are not really necessary. They only matter if additional controller 0x06 or 0x26 messages are sent
    //MusicDeviceMIDIEvent(self.samplerUnit, 0xB0, 0x64, 0x7F, 0);
    //MusicDeviceMIDIEvent(self.samplerUnit, 0xB0, 0x65, 0x7F, 0);  
}

bendDown:3つのボタンを作成し、それらを、、、bendCenter:およびに割り当てましたbendUp:

プログラムを実行し、bendCenterボタンを押します。次に、トロンボーンサウンドを選択した状態で、「ミッドノート」ボタンを押し続けます。それを押しながら、bendUpまたはbendDownボタンを押します。LSBが変化し、MSBが同じままであると、ピッチの変化が聞こえます。

于 2013-03-19T06:47:34.203 に答える