arirusso / unimidi

Realtime MIDI IO for Ruby
Other
255 stars 28 forks source link

Latency when trying to play multiple notes at the same time #14

Closed samwho closed 10 years ago

samwho commented 12 years ago

Hey, me again ^_^

When I was using MIDIator, I could pass in an array of notes and it would play them all at exactly the same time. The code used in MIDIator looks a little like this:

# Note on for each note in the array.
notes.each do |note|
  output.puts 0x90, note, 100
end

# Sleep to ensure duration.
sleep(note.duration)

# Note off for each note in the array.
notes.each do |note|
  output.puts 0x80, note, 100
end

That's the code that I'm using but it's modelled from the MIDIator equivalent "play" method at: https://github.com/bleything/midiator/blob/master/lib/midiator/interface.rb

It worked perfectly in MIDIator but in unimidi I get these minuscule delays. So if I have a chord of 3 notes, I can hear each one start a split second after the previous. How do I fix this?

arirusso commented 12 years ago

is that the code you're actually using? if not, is it committed to github somewhere that I can look at it?

samwho commented 12 years ago

It is, yes.

Here's the code: https://github.com/samwho/jarvis/tree/unimidi

EDIT: Ignore the README when it talks about 1.8.7. That relates to MIDIator. All unimidi code has been written under 1.9.2 :)

arirusso commented 12 years ago

I would try and make a standalone program that JUST does that with unimidi-- to make sure the problem is actually with unimidi. I can tell you for a fact that I've done this before on linux and had the notes be (perceptibly) simultaneous

arirusso commented 12 years ago

There's a lot of stuff happening in your program, and the way 1.8 and 1.9 deal with threads is very different. So that could be the source of your problem

samwho commented 12 years ago

This following script has the exact same problem:

require 'unimidi'

notes = [
  [34, 36, 38],
  [36, 38, 40],
  [34, 36, 38],
  [36, 38, 40]
]

o = UniMIDI::Output.first

o.open do |o|
  notes.each do |notes|
    notes.each do |note|
      o.puts 0x90, note, 100
    end

    sleep(0.5)

    notes.each do |note|
      o.puts 0x80, note, 100
    end
  end
end

Sounds like someone is playing a piano and rolling their hand over the keys instead of playing a chord properly.

arirusso commented 12 years ago

Well, on OSX it's happening simultaneously as a chord... unfortunately that's all I can test until I get back to nyc.

I've definitely tested this particular thing on Linux though... what if you try a different program for generating sound... does it still happen?

samwho commented 12 years ago

Same happens when I use qsynth over timidity. Is that what you meant? :)

arirusso commented 12 years ago

Yep...

I mean, honestly, outputting notes like this works the same in midiator as it does in unimidi... my guess is that there's something going on with your environment. or maybe these virtual midi outputs are just faulty?

Obviously I don't know for sure but I've used this functionality on linux many times. I'm not saying this to try and score a point... I just think that you should be able to overcome this problem quickly.

maybe change the o.puts lines to: puts "0x90, note, 100" and see if they print to the screen simultaneously...

samwho commented 12 years ago

They appear to print out at the same time...

Don't worry, I believe you :) I'm painfully aware of bugs that come about due to the environment that people use.

The only thing I can think that has changed is the virtual midi devices, they weren't used with MIDIator.

Gotta shoot off for a few hours, I'll keep plugging at this to see if I can find an answer.

arirusso commented 10 years ago

Hi, I made another improvement that should help with reliability of multiple notes on OSX in case you're still using this