Swift3でMIDIファイルをパースする方法
Swift3 で MIDI ファイルのパースをしようとしたら意外に方法が見つからなくて苦労したのでメモです。 MusicEventIteratorGetEventInfo 関数で取得したデータを MIDINoteMessage オブジェクトに変換する方法がわからなくてハマりました。
import AudioToolbox public class MIDIParser { public static func parse(url midiFileUrl: URL) { var musicSequence: MusicSequence? var result = OSStatus(noErr) result = NewMusicSequence(&musicSequence) guard let sequence = musicSequence else { print("error creating sequence : \(result)") return } // MIDIファイルの読み込み MusicSequenceFileLoad(sequence, midiFileUrl as CFURL, .midiType, MusicSequenceLoadFlags.smf_ChannelsToTracks) var musicTrack: MusicTrack? = nil var sequenceLength: MusicTimeStamp = 0 var trackCount: UInt32 = 0 MusicSequenceGetTrackCount(sequence, &trackCount) for i in 0 ..< trackCount { var trackLength: MusicTimeStamp = 0 var trackLengthSize: UInt32 = 0 MusicSequenceGetIndTrack(sequence, i, & musicTrack) guard let track = musicTrack else { continue } MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &trackLength, &trackLengthSize) if sequenceLength < trackLength { sequenceLength = trackLength } var tmpIterator: MusicEventIterator? NewMusicEventIterator(track, &tmpIterator) guard let iterator = tempIterator else { continue } var hasNext: DarwinBoolean = false MusicEventIteratorHasCurrentEvent(iterator, &hasNext) var type: MusicEventType = 0 var stamp: MusicTimeStamp = -1 var data: UnsafeRawPointer? var size: UInt32 = 0 while hasNext.boolValue { MusicEventIteratorGetEventInfo(iterator, &stamp, &type, &data, &size) if type == kMusicEventType_MIDINoteMessage { let messagePtr = UnsafePointer<MIDINoteMessage>(data?.assumingMemoryBound(to: MIDINoteMessage.self)) guard let channel = messagePtr?.pointee.channel, let note = messagePtr?.pointee.note, let velocity = messagePtr?.pointee.velocity, let duration = messagePtr?.pointee.duration else { continue } let message = MIDINoteMessage(channel: channel, note: note, velocity: velocity, releaseVelocity: 0, duration: duration) print(message) } MusicEventIteratorNextEvent(iterator) MusicEventIteratorHasCurrentEvent(iterator, &hasNext) } DisposeMusicEventIterator(iterator) MusicSequenceDisposeTrack(sequence, track) } DisposeMusicSequence(sequence) } }
参考
Objc や Swift2の情報はそこそこありました。
Swift3 のポインタ型についてちゃんと理解してればハマらなかったのかなと反省してます。