Либо в коде синтеза MIDI от Apple есть серьезная ошибка, либо я делаю что-то не так. Вот мое понимание этого. Когда вы отправляете MIDI-команду изменения высоты тона, диапазон изменения составляет от -8192 до 8191, транспонированный до 0. (Так что фактический диапазон составляет от 0 до 16383.) Это число разделено на два 7-битных поля, так что на самом деле это означает, что у вас есть 128 значений грубого управления и 128 значений точного управления.
Вот пример изменения высоты тона, который я написал, аналогичный командам в Apple ЗагрузитьPresetDemo.
// '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 (точное управление) ничего не происходит. Другими словами, кажется, что MIDI-синтезатор Apple игнорирует 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 полутонов, только каждое второе грубое изменение имеет значение. При 2 полутонах (по умолчанию) требуется 4 или более грубых изменений, чтобы изменить ситуацию.
Другими словами, мало того, что LSB очевидно игнорируется, но также, кажется, есть минимальное количество центов для изменения высоты тона. Можно ли устранить любое из этих ограничений? И если нет, то существуют ли программные синтезаторы для iOS с более высоким разрешением?
Хм... возможно, применение kAudioUnitSubType_Varispeed или kAudioUnitSubType_NewTimePitch даст лучшие результаты...