使用CoreMIDI的MIDISend时会忽略MIDIPacket时间戳吗?

月亮的眼睛

我不清楚时间戳字段是否可用于将来安排MIDI事件,即在调用MIDISend之后发生。以下代码尝试每秒安排10个音符开和10个音符关。时间戳记应指定音符的音符在音符打开后的1/10秒内发生,但是在我尝试过的所有硬件或虚拟目标上,似乎所有事件都在调用MIDISend时立即发送。这是一般行为,还是某些MIDI硬件/某些虚拟MIDI目标是否使用时间戳值支持事件的正确调度?这是我的代码:

/* send_midi_port.c
 * Open connection with destination (rather than setting up MIDI source) and send
 * timestamped messages
 */

#include <stdlib.h>
#include <stdio.h>
#include <CoreMIDI.h> 
#include <HostTime.h> 
#include <string.h> 
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <unistd.h>

#define STR_BUFSIZE 200 

#define ERR_EXIT(x)\
    fprintf(stderr,"Error %s\n",x);\
return -1;

typedef void (*sig_t) (int);

static volatile int done = 0;

static mach_timebase_info_data_t sTimebaseInfo;

void int_handle(int signum)
{
    done = 1;
}

char *CFString_strncpy(char *dest,
        CFStringRef str,
        size_t n)
{
    CFStringEncoding encoding = kCFStringEncodingUTF8;
    if (!CFStringGetCString(str, dest, n, encoding)) {
        dest = NULL;
    }
    return dest;
}

int CFString_cstr_strncmp(CFStringRef s1, char *s2, size_t n)
{
    char buf[STR_BUFSIZE];
    if (CFString_strncpy(buf, s1, STR_BUFSIZE) == NULL) {
        return -2;
    }
    return strncmp(buf,s2,n);
}

/* Print CFString to stdout */
void CFString_printf(CFStringRef str)
{
    char buffer[STR_BUFSIZE];
    CFStringEncoding encoding = kCFStringEncodingUTF8;
    const char *ptr = CFStringGetCStringPtr(str, encoding);
    if (ptr == NULL) {
        if (CFStringGetCString(str, buffer, STR_BUFSIZE, encoding)) {
            ptr = buffer;
        }
    }
    if (ptr) {
        printf("%s",ptr);
    }
}

/* Get MIDI object's name as CFStringRef */
CFStringRef MIDIObjectRef_get_name(MIDIObjectRef obj)
{
    CFStringRef name = NULL;
    OSStatus err;
    err = MIDIObjectGetStringProperty(obj,kMIDIPropertyName,&name);
    if (err) {
        return NULL;
    }
    return name;
} 

UInt64 nano_to_absolute(UInt64 nano)
{
    return nano * sTimebaseInfo.denom / sTimebaseInfo.numer;
}

int main(int argc, char **argv)
{
    // Get Timebase info
    (void) mach_timebase_info(&sTimebaseInfo);

    char desired_dest_[] = "FastTrack Pro";
    char *desired_dest;
    if (argc < 2) {
        printf("No device specified, using default output %s.\n", desired_dest_);
        desired_dest = desired_dest_;
    } else {
        desired_dest = argv[1];
    }

    ItemCount n_dests = MIDIGetNumberOfDestinations();
    int found = 0;
    MIDIEndpointRef desired_epr;
    while (n_dests--) {
        MIDIEndpointRef dest = MIDIGetDestination(n_dests);
        CFStringRef name = MIDIObjectRef_get_name(dest);
        if (CFString_cstr_strncmp(name,desired_dest,strlen(desired_dest))
                == 0) {
            printf(" Name of destination %d: ",(int)n_dests);
            CFString_printf(name);
            printf("\n");
            found = 1;
            desired_epr = dest;
        }
    }
    if (!found) {
        printf("Destination %s not found.\n",desired_dest);
        return -1;
    }
    OSStatus result;
    MIDIClientRef clientref;
    result = MIDIClientCreate(CFSTR("default"),NULL,NULL,&clientref);
    if (result < 0 ) {
        ERR_EXIT("Creating client.");
    }
    MIDIPortRef portref;
    result = MIDIOutputPortCreate(clientref,CFSTR("hiports"),&portref);
    if (result < 0 ) {
        ERR_EXIT("Creating port.");
    }
    signal(SIGINT,int_handle);
    while (!done) {
        // With multiple and time stamps
        ByteCount mpdsize = sizeof(MIDIPacketList)+sizeof(MIDIPacket)*20;
        char mpdata[mpdsize];
        memset(mpdata,0,mpdsize);
        MIDIPacketList *midipackets;
        midipackets = (MIDIPacketList*)mpdata;
        MIDIPacket *mp;
        mp = MIDIPacketListInit(midipackets);
        int n;
        UInt64 timeNano, timeScale;
        for (n = 0; n < 20; n += 2) {
            Byte noteOnData[3] = {0x90,60+(n/2),100};
            Byte noteOffData[3] = {0x80,60+(n/2),0};
            // on all the devices I tried, the timestamps seem to be ignored
            mp = MIDIPacketListAdd(midipackets,mpdsize,mp,
                    nano_to_absolute(((UInt64)n/2) * 100ULL * 1000ULL * 1000ULL),
                    // seems equivalent to 0
//                    0,
                    3,noteOnData);
            if (!mp) {
                ERR_EXIT("Adding MIDI packet.\n");
            }
            mp = MIDIPacketListAdd(midipackets,mpdsize,mp,
                    nano_to_absolute((((UInt64)n/2)+1) * 100ULL * 1000ULL * 1000ULL),
                    // seems equivalent to 0
//                    0,
                    3,noteOffData);
            if (!mp) {
                ERR_EXIT("Adding MIDI packet.\n");
            }
        }
        // Check packets
        printf("Number of packets: %d\n",(int)midipackets->numPackets);
        MIDIPacket *__p = &midipackets->packet[0];
        int i;
        for (i = 0; i < midipackets->numPackets; ++i) {
            printf("Timestamp: %llu\n"
                    "Length: %d\n"
                    "Data : ",
                    __p->timeStamp,
                    (int)__p->length);
            int j;
            for (j = 0; j < __p->length; j++) {
                printf("%d ",(int)__p->data[j]);
            }
            printf("\n");
            __p = MIDIPacketNext(__p);
        }
        printf("Sending notes\n");
        MIDISend(portref,desired_epr,midipackets);
        sleep(1);
    }

    MIDIPortDispose(portref);
    MIDIClientDispose(clientref);

    return 0;
}

这可以使用命令构建(框架的路径在您的计算机上可能不同)

clang send_midi_port.c -o send_midi_port.bin - I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/CoreMIDI.framework/Headers -framework CoreMIDI -g -framework CoreFoundation -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/CoreAudio.framework/Headers -framework CoreAudio -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/CoreServices.framework/Headers -framework CoreServices
库尔特·里维斯(Kurt Revis)

致电时MIDIPacketListAdd,您没有提供正确的时间戳。您正在传递当前时间的偏移量,第一个事件从0开始,以后的事件增加。但是您不包括当前时间。

结果,CoreMIDI认为时间戳是过去的,因此它立即发送事件。

使用AudioGetCurrentHostTime以获取当前时间,并添加每个抵消了这一点。

    UInt64 now = AudioGetCurrentHostTime();
    for (n = 0; n < 20; n += 2) {
        Byte noteOnData[3] = {0x90,60+(n/2),100};
        Byte noteOffData[3] = {0x80,60+(n/2),0};
        mp = MIDIPacketListAdd(midipackets,mpdsize,mp,
                now + nano_to_absolute(((UInt64)n/2) * 100ULL * 1000ULL * 1000ULL),
                3,noteOnData);
        mp = MIDIPacketListAdd(midipackets,mpdsize,mp,
                now + nano_to_absolute((((UInt64)n/2)+1) * 100ULL * 1000ULL * 1000ULL),
                3,noteOffData);
    }

使用时MIDISend,无论最终设备是MIDI硬件还是其他某个应用程序拥有的虚拟MIDI目标,CoreMIDI都将处理调度。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用robocopy镜像源但忽略时间戳

来自分类Dev

OutputCache忽略时间戳

来自分类Dev

使用wget下载时会忽略“其他”域吗?

来自分类Dev

使用wget下载时会忽略“其他”域吗?

来自分类Dev

使用Datetime字段对象时,忽略created_at时间戳

来自分类Dev

使用Datetime字段对象时,忽略created_at时间戳

来自分类Dev

忽略时间戳postgres的秒数

来自分类Dev

使用NEST在索引上设置Elasticsearch时间戳路径吗?

来自分类Dev

使用时区格式化Unix时间戳吗?

来自分类Dev

在毫秒时间戳上使用 pd.datetime() 热吗?

来自分类Dev

如何告诉robocopy忽略时间戳?

来自分类Dev

在C#9记录上使用“ with”时会忽略特定字段吗?

来自分类Dev

PostgreSQL忽略时间戳列上的索引,即使使用索引查询速度更快

来自分类Dev

使用正则表达式提取时间戳并重新格式化时间戳是唯一的方法吗?

来自分类Dev

将 UTC 时间戳解析为本地时间,忽略时区

来自分类Dev

ActiveRecord截断时间戳精确吗?

来自分类Dev

我应该明确存储时间戳吗?

来自分类Dev

CMAccelerometerometerData事件时间戳UTC值吗?

来自分类Dev

它是Unix时间戳增量吗?

来自分类Dev

tcpdump可以按时间戳过滤吗?

来自分类Dev

Java 有天真的时间戳吗?

来自分类Dev

数据提取需要加时间戳吗?

来自分类Dev

使用Paramiko保留时间戳

来自分类Dev

distutils在构建扩展时会忽略对setup.py的更改吗?

来自分类Dev

Django在运行测试时会忽略路由器吗?

来自分类Dev

OpenGL在混合时会忽略对象吗?

来自分类Dev

调用函数时会忽略php静态变量重置吗?

来自分类Dev

将UILabel垂直居中时会忽略Ascender和Descender吗?

来自分类Dev

MongoDB在分片群集上运行MapReduce时会忽略readPreference吗?

Related 相关文章

  1. 1

    使用robocopy镜像源但忽略时间戳

  2. 2

    OutputCache忽略时间戳

  3. 3

    使用wget下载时会忽略“其他”域吗?

  4. 4

    使用wget下载时会忽略“其他”域吗?

  5. 5

    使用Datetime字段对象时,忽略created_at时间戳

  6. 6

    使用Datetime字段对象时,忽略created_at时间戳

  7. 7

    忽略时间戳postgres的秒数

  8. 8

    使用NEST在索引上设置Elasticsearch时间戳路径吗?

  9. 9

    使用时区格式化Unix时间戳吗?

  10. 10

    在毫秒时间戳上使用 pd.datetime() 热吗?

  11. 11

    如何告诉robocopy忽略时间戳?

  12. 12

    在C#9记录上使用“ with”时会忽略特定字段吗?

  13. 13

    PostgreSQL忽略时间戳列上的索引,即使使用索引查询速度更快

  14. 14

    使用正则表达式提取时间戳并重新格式化时间戳是唯一的方法吗?

  15. 15

    将 UTC 时间戳解析为本地时间,忽略时区

  16. 16

    ActiveRecord截断时间戳精确吗?

  17. 17

    我应该明确存储时间戳吗?

  18. 18

    CMAccelerometerometerData事件时间戳UTC值吗?

  19. 19

    它是Unix时间戳增量吗?

  20. 20

    tcpdump可以按时间戳过滤吗?

  21. 21

    Java 有天真的时间戳吗?

  22. 22

    数据提取需要加时间戳吗?

  23. 23

    使用Paramiko保留时间戳

  24. 24

    distutils在构建扩展时会忽略对setup.py的更改吗?

  25. 25

    Django在运行测试时会忽略路由器吗?

  26. 26

    OpenGL在混合时会忽略对象吗?

  27. 27

    调用函数时会忽略php静态变量重置吗?

  28. 28

    将UILabel垂直居中时会忽略Ascender和Descender吗?

  29. 29

    MongoDB在分片群集上运行MapReduce时会忽略readPreference吗?

热门标签

归档