NSData 与 NSValue?如何在 sendMIDISysExEvent:(NSData *)midiData 中封装 C 结构
NSData vs NSValue ? how to encapsulate a C-structure in sendMIDISysExEvent:(NSData *)midiData
我正在尝试使用 sendMIDISysExEvent:(NSData *)midiData
来重新调整音乐应用程序中的一些 MIDI 音符。我希望 ViewController
向 Synth
class 发送 MIDI 消息以更改 10 个音符的调音。用于重新调整一个音符的标准 MIDI 系统专用消息格式如下所示
F0 7F <device ID> 08 02 tt ll [kk xx yy zz] F7.
legend: tt ll [kk xx yy zz]
(NB - 与 MIDI 1.0 详细规范 4.2,p.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;
并且还在 .h
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;
}
}
然而当我阅读 this answer I began to ask how I might go about preparing a MIDI data packet based on NSData
that sendMIDISysExEvent:(NSData *)midiData
will send. And this answer recommends NSValue
as the better way to encapsulate a C-structure like the one I'm trying to create so I'm confused. If that really is the case, I'm puzzled why Apple would introduce a method like sendMIDISysExEvent:(NSData *)midiData
.
我的问题是:根据消息格式 (在我上面的代码中概述),我将如何准备 midiData
以便使用此方法发送它?
结论
响应已接受的答案,"raw binary data" 的长度根据字节数而不是数据类型[=66]定义=],解释了 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)
NSData
和 NSValue
都是 "raw binary data" 的包装器,但具有不同的意图和不同的方式来定义二进制数据的长度。
NSValue
以装箱标量类型为目标,如 int
、float
(但也是 struct
),NSValue
的接口旨在通过类型传递 "data" 的长度。因此,不可能将可变长度的对象(如 VLA 或 C 字符串)封装在 NSValue 中,因为数据的大小无法从类型信息中导出 (cf. NSValue):
The type you specify must be of constant length. You cannot store C
strings, variable-length arrays and structures, and other data types
of indeterminate length in an NSValue—you should use NSString or
NSData objects for these types.
NSData
表示任意字节缓冲区的框。所以它有一个接口,通过它你可以根据字节定义 "raw binary data" 的长度(并且 而不是类型)。
关于您的问题,由于 sendMIDISysExEvent:(NSData *)midiData
中的 MIDI 接口需要一个 NSData
-对象,唯一(有意义的)方法是将您的对象作为 NSData
-对象传递.
希望对您有所帮助。
我正在尝试使用 sendMIDISysExEvent:(NSData *)midiData
来重新调整音乐应用程序中的一些 MIDI 音符。我希望 ViewController
向 Synth
class 发送 MIDI 消息以更改 10 个音符的调音。用于重新调整一个音符的标准 MIDI 系统专用消息格式如下所示
F0 7F <device ID> 08 02 tt ll [kk xx yy zz] F7.
legend: tt ll [kk xx yy zz]
(NB - 与 MIDI 1.0 详细规范 4.2,p.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;
并且还在 .h
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;
}
}
然而当我阅读 this answer I began to ask how I might go about preparing a MIDI data packet based on NSData
that sendMIDISysExEvent:(NSData *)midiData
will send. And this answer recommends NSValue
as the better way to encapsulate a C-structure like the one I'm trying to create so I'm confused. If that really is the case, I'm puzzled why Apple would introduce a method like sendMIDISysExEvent:(NSData *)midiData
.
我的问题是:根据消息格式 (在我上面的代码中概述),我将如何准备 midiData
以便使用此方法发送它?
结论
响应已接受的答案,"raw binary data" 的长度根据字节数而不是数据类型[=66]定义=],解释了 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)
NSData
和 NSValue
都是 "raw binary data" 的包装器,但具有不同的意图和不同的方式来定义二进制数据的长度。
NSValue
以装箱标量类型为目标,如 int
、float
(但也是 struct
),NSValue
的接口旨在通过类型传递 "data" 的长度。因此,不可能将可变长度的对象(如 VLA 或 C 字符串)封装在 NSValue 中,因为数据的大小无法从类型信息中导出 (cf. NSValue):
The type you specify must be of constant length. You cannot store C strings, variable-length arrays and structures, and other data types of indeterminate length in an NSValue—you should use NSString or NSData objects for these types.
NSData
表示任意字节缓冲区的框。所以它有一个接口,通过它你可以根据字节定义 "raw binary data" 的长度(并且 而不是类型)。
关于您的问题,由于 sendMIDISysExEvent:(NSData *)midiData
中的 MIDI 接口需要一个 NSData
-对象,唯一(有意义的)方法是将您的对象作为 NSData
-对象传递.
希望对您有所帮助。