我正在开发一个应用程序,它可以播放带有音频单元的 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 文件,标记在文件中,但是在哪里......我怎样才能在代码中得到它?