Apple 的 MIDI 合成代码中存在严重错误,或者我做错了什么。这是我的理解。当您发送弯音 MIDI 命令时,弯音的范围是 -8192 到 8191,移调到 0。(所以实际范围是 0 到 16383。)这个数字被分成两个 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);
当 bendMSB(粗略控制)发生变化时,音高弯曲得很好。但是当 bendLSB(精细控制)发生变化时,什么也没有发生。换句话说,Apple 的 MIDI 合成器似乎忽略了 LSB,这意味着音符仅在听起来难听的离散 block 中弯曲。
这是做同样事情的另一种方法:
// '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, float (精细控制)被忽略。
最后,如果您进行以下调用以调整弯音范围:
// '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 个半音时,只有每秒的粗略变化才会有所不同。在 2 个半音(默认值)下,需要 4 次或更多次粗略更改才能产生差异。
换句话说,不仅 LSB 显然被忽略了,而且音调似乎也至少有 # 美分可以改变。这些限制中的任何一个都可以修复吗?如果没有,是否有任何适用于 iOS 的软件合成器框架具有更高的弯曲分辨率?
嗯...也许应用 kAudioUnitSubType_Varispeed 或 kAudioUnitSubType_NewTimePitch 会产生更好的结果...
最佳答案
您的弯音信息不正确。而不是这个:
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
以更准确地反射(reflect)其用途。)
在 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:
、bendCenter:
和 bendUp:
。
运行程序并按下 bendCenter
按钮。然后,在选择长号声音的情况下,按住“中音”按钮。按住它的同时,按 bendUp
或 bendDown
按钮。当 LSB 改变而 MSB 保持不变时,我可以听到音高的变化。
关于ios - iOS 中的 MIDI 合成行为不当 WRT 弯音 : LSB ignored,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15468558/