ios - 获取使用 Logic 生成的 midi 序列 (MusicSequence) 标记

标签 ios logic midi

我正在开发一款应用程序,该应用程序使用音频单元播放 MIDI 序列 (.mid)。 midi 文件是使用 Logic 创建的,它提供了在时间轴上添加标记的可能性。

在代码中,我使用 MusicSequence MusicPlayer 读取文件,使用 MIDIClientCreate MIDIDestinationCreate 解析 MIDI 数据包。

主要方法

    OSStatus result = noErr;


// Initialise the music sequence
NewMusicSequence(&_s);

// Get a string to the path of the MIDI file which
// should be located in the Resources folder
NSString *midiFilePath = [[NSBundle mainBundle]
                          pathForResource:@"mymidifile"
                          ofType:@"mid"];

// Create a new URL which points to the MIDI file
NSURL * midiFileURL = [NSURL fileURLWithPath:midiFilePath];

// Load the file
MusicSequenceFileLoad(_s, (__bridge CFURLRef) midiFileURL, 0, 0);



// Initialise the music player
NewMusicPlayer(&_p);


// Load the sound from EXS file
[self loadFromEXS:@"Grand Piano" withSampler:_samplerUnit];

//Load Click
[self loadFromSoundFont:@"hit set" withSampler:_samplerUnit2];


//Assign channel to tracks
MusicTrack track = NULL;
MusicTrack track2 = NULL;
MusicSequenceGetIndTrack(_s, 1, &track);
MusicSequenceGetIndTrack(_s, 2, &track2);

//Assign tracks to audio units
MusicTrackSetDestNode(track, _samplerNode);
MusicTrackSetDestNode(track2, _samplerNode2);


// Create a client
result = MIDIClientCreate(CFSTR("Virtual Client"),MyMIDINotifyProc,(__bridge void *)(self),&_virtualMidi);
NSAssert( result == noErr, @"MIDIClientCreate failed. Error code: %d '%.4s'", (int) result, (const char *)&result);


// Create an endpoint
result = MIDIDestinationCreate(_virtualMidi, (CFStringRef)@"Virtual Destination", MyMIDIReadProc, (__bridge void *)(self), &_virtualEndPoint);

NSAssert( result == noErr, @"MIDIDestinationCreate failed. Error code: %d '%.4s'", (int) result, (const char *)&result);


// ************* Set the endpoint of the sequence to be our virtual endpoint
MusicSequenceSetMIDIEndpoint(_s, _virtualEndPoint);




// Load the sequence into the music player
MusicPlayerSetSequence(_p, _s);
// Called to do some MusicPlayer setup. This just
// reduces latency when MusicPlayerStart is called
MusicPlayerPreroll(_p);
// Starts the music playing
MusicPlayerStart(_p);

还有我的 readProc 函数

void MyMIDIReadProc(const MIDIPacketList *pktlist,
                AudioProcessor *refCon,
                void *connRefCon) {


AudioUnit *player = nil;

MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
NSString *messageType;

for (int i=0; i < pktlist->numPackets; i++) {


    Byte midiStatus = packet->data[0];
    Byte midiCommand = midiStatus >> 4;// mask off all but top 4 bits
    Byte note = packet->data[1] & 0x7F;
    Byte velocity = packet->data[2] & 0x7F;

    // find the channel by masking off all but the low 4 bits
    NSInteger midiChannel = midiStatus & 0x0F;


    switch (midiStatus & 0xF0) {
        case 0x80:
            messageType = @"Note Off";
            break;

        case 0x90:
            messageType = @"Note On";
            break;

        case 0xA0:
            messageType = @"Aftertouch";
            break;

        case 0xB0:
            messageType = @"Control change";
            break;

        case 0xC0:
            messageType = @"Program Change";
            break;

        case 0xD0:
            messageType = @"Channel Pressure";
            break;

        case 0xE0:
            messageType = @"Pitch Wheel";
            break;

        default:
            messageType = @"Unk";
            break;
    }
    NSLog(@"%@",messageType);
    int noteNumber = ((int) note) % 12;
    NSString *noteType;
    switch (noteNumber) {
        case 0:
            noteType = @"C";
            break;
        case 1:
            noteType = @"C#/Db";
            break;
        case 2:
            noteType = @"D";
            break;
        case 3:
            noteType = @"D#/Eb";
            break;
        case 4:
            noteType = @"E";
            break;
        case 5:
            noteType = @"F";
            break;
        case 6:
            noteType = @"F#/Gb";
            break;
        case 7:
            noteType = @"G";
            break;
        case 8:
            noteType = @"G#/Ab";
            break;
        case 9:
            noteType = @"A";
            break;
        case 10:
            noteType = @"A#/Bb";
            break;
        case 11:
            noteType = @"B";
            break;
        default:
            break;
    }




    if( velocity == 0 ){

        UInt32 noteOff =    kMIDIMessage_NoteOff << 4 | 0;
        if( midiChannel == 0 ){
            MusicDeviceMIDIEvent (refCon.samplerUnit, noteOff, note, 0, 0);
        }else if( midiChannel == 1 ){
            MusicDeviceMIDIEvent (refCon.samplerUnit2, noteOff, note, 0, 0);
        }

    }else{

        if( midiChannel == 0 ){
            MusicDeviceMIDIEvent (refCon.samplerUnit, midiStatus, note, velocity, 0);
        }else if( midiChannel == 1 ){
            MusicDeviceMIDIEvent (refCon.samplerUnit2, midiStatus, note, velocity, 0);
        }

    }

    packet = MIDIPacketNext(packet);
}

通过我的 readProc 函数,我可以看到所有的 MIDI 消息,但看不到标记...

如果我在 Logic 中重新打开 midi 文件,标记在文件中,但是在哪里...我如何在代码中获取它?

最佳答案

标记作为标记元事件包含在 MIDI 文件中。所以你需要扩展你的解析来支持元事件。元事件的状态为 0xFF。对于标记,下一个字节是 0x06,然后是长度和字符数。

关于ios - 获取使用 Logic 生成的 midi 序列 (MusicSequence) 标记,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18275924/

相关文章:

swift - 在 Swift 中不大于运算符!>

c++ - 编译 RtMidi - Qt 项目、mingw

c# - 损坏的 MIDI 文件输出

javascript - 慢速键盘/选择器在 cordova 4 iOS 中响应

ios - 更改突出显示的 UIButton BG 颜色,但保留层角半径?

algorithm - 用特定规则分割矩形

controls - iPad/iPhone CoreMidi - Mackie 控制仿真(停止、播放按钮)

ios - RxSwift - onError 发出两次

iphone - 从后台返回时重新加载 View

php - 存储 - 逻辑/性能 - PHP/MySQL