Я пытаюсь найти способ использовать sendMIDISysExEvent:(NSData *)midiData
как способ перенастроить несколько нот MIDI в музыкальном приложении. Я хочу, чтобы ViewController
отправил MIDI-сообщение классу Synth
, чтобы изменить настройку 10 нот. Стандартный формат сообщений MIDI System Exclusive для перенастройки одной ноты выглядит следующим образом.
F0 7F <device ID> 08 02 tt ll [kk xx yy zz] F7.
legend: tt ll [kk xx yy zz]
(примечание - немного отличается от подробной спецификации MIDI 1.0 4.2, стр. 49)
С typedef struct
можно было бы использовать один float
вместо uint8_t
для представления частоты настройки, например.
PlayViewController.h
typedef struct
{
uint8_t SYSEX_SysexHeader; // oxF0h; // System Exclusive Header
uint8_t SYSEX_UniversalRealTimeHeader; // ox7Fh; // Universal RealTime Header
uint8_t SYSEX_myPhone; // ox00h; // ID of target device (e.g. iPhone)
uint8_t SYSEX_subID1; // ox08h; // sub-ID #1 (MIDI Tuning Standard)
uint8_t SYSEX_subID2; // ox02h; // sub-ID #2 (note change)
uint8_t SYSEX_tuningProgramNumber; // ox0h; // tuning program number (0 -127)
uint8_t SYSEX_numberOfKeys; // ox10h; // number of changes
uint8_t SYSEX_key0;
float TUNING_pitch_0;
uint8_t SYSEX_key1;
float TUNING_pitch_1;
uint8_t SYSEX_key2;
float TUNING_pitch_2;
uint8_t SYSEX_key3;
float TUNING_pitch_3;
uint8_t SYSEX_key4;
float TUNING_pitch_4;
uint8_t SYSEX_key5;
float TUNING_pitch_5;
uint8_t SYSEX_key6;
float TUNING_pitch_6;
uint8_t SYSEX_key7;
float TUNING_pitch_7;
uint8_t SYSEX_key8;
float TUNING_pitch_8;
uint8_t SYSEX_key9;
float TUNING_pitch_9;
uint8_t eox; // OxF7h; //
}
TuneEvent;
и еще в .ч
typedef NS_ENUM(NSInteger, SYSEX)
{
SYSEX_SysexHeader = 240,
SYSEX_UniversalRealTimeHeader = 127,
SYSEX_myPhone = 0,
SYSEX_subID1 = 8,
SYSEX_subID2 = 2,
SYSEX_tuningProgramNumber = 0,
SYSEX_numberOfKeysToBeChanged = 1,
SYSEX_key0 = 61,
SYSEX_key1 = 62,
SYSEX_key2 = 63,
SYSEX_key3 = 64,
SYSEX_key4 = 65,
SYSEX_key5 = 66,
SYSEX_key6 = 67,
SYSEX_key7 = 68,
SYSEX_key8 = 69,
SYSEX_key9 = 70,
SYSEX_eox = 247
};
typedef NS_ENUM(NSInteger, TUNING)
{
TUNING_pitch0,
TUNING_pitch1,
TUNING_pitch2,
TUNING_pitch3,
TUNING_pitch4,
TUNING_pitch5,
TUNING_pitch6,
TUNING_pitch7,
TUNING_pitch8,
TUNING_pitch9
};
float TUNING_float(TUNING micro);
и, наконец, для значений с плавающей запятой... (благодаря этому ответу)
PlayViewController.m
float TUNING_float(TUNING micro)
{
switch (micro)
{
case TUNING_pitch0:
return 579.4618f;
case TUNING_pitch1:
return 607.0552f;
case TUNING_pitch2:
return 662.2421f;
case TUNING_pitch3:
return 708.2311f;
case TUNING_pitch4:
return 772.6157f;
case TUNING_pitch5:
return 809.4070f;
case TUNING_pitch6:
return 882.9894f;
case TUNING_pitch7:
return 910.5828f;
case TUNING_pitch8:
return 993.3631f;
case TUNING_pitch9:
return 1030.1540f;
default:
return 0.0f;
}
}
Однако, когда я прочитал этот ответ, я начал спрашивать, как я могу подготовить пакет данных MIDI на основе NSData
, который sendMIDISysExEvent:(NSData *)midiData
будет Отправить. И этот ответ рекомендует NSValue
как лучший способ инкапсулировать C-структуру, подобную той, которую я пытаюсь создать, поэтому я я в замешательстве. Если это действительно так, я озадачен, почему Apple представила такой метод, как sendMIDISysExEvent:(NSData *)midiData
.
Мой вопрос: исходя из формата сообщения (изложенного в моем коде выше), как мне подготовить midiData
для отправки с помощью этого метода?
ЗАКЛЮЧЕНИЕ
В ответ на принятый ответ длина «необработанных двоичных данных», определяемая с точки зрения количества байтов, а не типа данных, объясняет существенную разницу между NSData
и NSValue
. Это также предполагает, что sendMIDISysExEvent:(NSData *)midiData
был разработан только для обработки байтов данных, то есть uint8_t
, а не float.
. Другими словами, разумным вариантом является выражение значений частоты с использованием байтов в соответствии со следующим отрывком из стандарта настройки MIDI.
yy = MSB of fractional part (1/128 semitone = 100/128 cents = .78125 cent units) zz = LSB of fractional part (1/16384 semitone = 100/16384 cents = .0061 cent units)