【问题标题】:How can I set timestamps accurately for midi events?如何为 midi 事件准确设置时间戳?
【发布时间】:2015-09-15 03:23:08
【问题描述】:

我正在解析一个 midi 文件,然后使用 MIKMIDI 将 midi 事件发送到连接的合成器,但我将事件时间戳四舍五入到整数秒,而不是更具体的毫秒。我需要帮助准确计算时间。谢谢。 // 之前定义的 类注{ var 符号:字符串 var 八度:Int var midiValue:Int var 持续时间:浮动 }

let BPM:Double = 75
// Ode to joy simplified
var song:[Note] = [
  Note(symbol: "E", octave: 5),
  Note(symbol: "E", octave: 5),
  Note(symbol: "F", octave: 5),
  Note(symbol: "G", octave: 5),

  Note(symbol: "G", octave: 5),
  Note(symbol: "F", octave: 5),
  Note(symbol: "E", octave: 5),
  Note(symbol: "D", octave: 5),

  Note(symbol: "C", octave: 5),
  Note(symbol: "C", octave: 5),
  Note(symbol: "D", octave: 5),
  Note(symbol: "E", octave: 5),

  Note(symbol: "E", octave: 5, duration: 3/8),
  Note(symbol: "D", octave: 5, duration: 1/8),
  Note(symbol: "D", octave: 5, duration: 1/2)
]
let now = NSDate()
let totalDuration:Double = 0
for note:Note in song {
  let fullNoteValue:Double = (60000 / BPM) * 0.001 * 4
  let noteDuration:Double = fullNoteValue * Double(note.duration)
  let timestamp = now.dateByAddingTimeInterval(noteDuration + totalDuration)
  MidiDevice.sharedInstance().playNoteOn(note.midiValue, withTimestamp: timestamp)
  totalDuration += noteDuration
}

MidiDevice playNoteOn 定义

- (void)playNoteOn:(NSInteger)note withTimestamp:(MIDITimeStamp)timestamp {
  MIKMutableMIDINoteOnCommand *noteOn = [MIKMutableMIDINoteOnCommand commandForCommandType:MIKMIDICommandTypeNoteOn];
  noteOn.note = (NSUInteger) note;
  noteOn.velocity = 100;
  noteOn.timestamp = timestamp
  // noteOn.midiTimestamp = timestamp;

  NSMutableArray *destinations = [NSMutableArray array];

  for (MIKMIDIDevice *device in [[MIKMIDIDeviceManager sharedDeviceManager] availableDevices]) {
    for (MIKMIDIEntity *entity in [device.entities valueForKeyPath:@"@unionOfArrays.destinations"]) {
      [destinations addObject:entity];
    }
  }

  //  NSArray *destinations = [self.device.entities valueForKeyPath:@"@unionOfArrays.destinations"];
  if (![destinations count]) return;
  for (MIKMIDIDestinationEndpoint *destination in destinations) {
    NSError *error = nil;
    if(![self.deviceManager sendCommands:@[noteOn] toEndpoint:destination error:&error]) {
      NSLog(@"Unable to send command %@ to endpoint %@: %@", noteOn, destination, error);
    }
  }
}

如何将此时间戳更改为可以使用 MIDISend() 或 MIKMIDI 发送的准确时间戳?

【问题讨论】:

  • 嗨@matt 我想要简洁,但我想我的问题太含糊了。谢谢。
  • 你仍然没有显示真正的代码。例如,noteOn.timestamp = timestamp 行缺少分号,因此无法编译。只需复制您的代码并将其粘贴到您的问题中!不要惹它;只需显示实际代码。

标签: ios swift cocoa coremidi mikmidi


【解决方案1】:

您正在使用不兼容的时间测量。首先你说:

let now = NSDate()
let timestamp = now.dateByAddingTimeInterval(noteDuration + totalDuration)

然后你把它交给 MIDI 设备:

 MidiDevice.sharedInstance().playNoteOn(note.midiValue, withTimestamp: timestamp)

但事实证明,这里的时间戳应该是一个 MIDITimeStamp:

(void)playNoteOn:(NSInteger)note withTimestamp:(MIDITimeStamp)timestamp {

MIDITimeStamp 不是 NSDate! MIDITimeStamp 基于mach_absolute_time(),一种完全不同的度量。 NSDate 被测量为 NSTimeInterval,它是从某个固定的参考日期时间开始的 Double 计数秒数。马赫绝对时间是一个巨大的整数,从计算机开机时开始计算纳秒!

所以,要成功调用这个方法,你需要去掉NSDate,用MIDI时间来思考。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多