首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSData对NSValue?如何在sendMIDISysExEvent中封装C-结构:(NSData *)midiData

NSData对NSValue?如何在sendMIDISysExEvent中封装C-结构:(NSData *)midiData
EN

Stack Overflow用户
提问于 2017-07-06 09:09:01
回答 1查看 178关注 0票数 1

我正在尝试如何使用sendMIDISysExEvent:(NSData *)midiData作为在音乐应用程序中调整一些MIDI音符的方法。我希望ViewControllerSynth类发送MIDI消息,以更改10个音符的调优。用于调整一个音符的MIDI系统独占消息格式如下所示

代码语言:javascript
复制
                 F0 7F <device ID> 08 02 tt ll [kk xx yy zz] F7.

http://www.microtonal-synthesis.com/MIDItuning.html (NB -slightly不同于MIDI 1.0详细规范4.2,p.49)

使用typedef struct,可以使用单个float而不是uint8_t来表示调谐频率。

PlayViewController.h

代码语言:javascript
复制
    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

代码语言:javascript
复制
    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);

最后,对于浮点值. https://stackoverflow.com/a/44252396/2348597

PlayViewController.m

代码语言:javascript
复制
    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;
        }
    }

然而,当我阅读这个答案时,我开始问我如何准备一个基于NSData的MIDI数据包,由sendMIDISysExEvent:(NSData *)midiData发送。这个答案推荐NSValue作为封装C结构的更好方法,就像我试图创建的那样,所以我很困惑。如果果真如此的话,我不明白为什么苹果会引入像sendMIDISysExEvent:(NSData *)midiData这样的方法。

我的问题是:基于消息格式(在我上面的代码中概述),我将如何准备midiData以便使用此方法发送?

结论

根据公认的答案,以字节数而不是数据类型定义的“原始二进制数据”的长度解释了NSDataNSValue之间的显著差异。这也意味着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)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-06 09:58:47

NSDataNSValue都是“原始二进制数据”的包装器,但是在定义二进制数据长度方面有着不同的意图和不同的方式。

NSValue目标在装箱标量类型中,如intfloat (也包括struct),NSValue的接口设计为通过类型传递“数据”的长度。因此,不可能将可变长度的对象(如VLA或C-字符串)封装在NSValue中,因为数据的大小不能从类型信息(请参阅NSValue)派生出来:

您指定的类型必须具有常量长度。您不能在NSValue中存储C字符串、可变长度数组和结构以及其他不确定长度的数据类型--对于这些类型,您应该使用NSString或NSData对象。

NSData是指用于任意字节缓冲区的框。因此它有一个接口,您可以通过它定义“原始二进制数据”的字节长度(而不是类型)。

关于您的问题,正如sendMIDISysExEvent:(NSData *)midiData中的MIDI接口所期望的NSData-object一样,唯一(有意义的)方法是将对象作为NSData-object传递。

希望能帮上忙。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44944503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档