topaz
topaz copied to clipboard
possible bug in midi-eye/topaz/ffi-coremidi that causes progressive slowing down
Hello Ari,
First of all I want to thank you all your work and effort to make available the fantastic ruby gems you have developed: unimidi, topaz, midi-message, etc. I’m a admirer of your work.
I discovered your gems searching in google because i wanted to do my ruby dsl for music. Now you can find it in https://github.com/javier-sy/musa-dsl
A few days ago I’ve found a problem with my setup, that I ve simplified in order to find a possible bug. Using only your gems I’ve found a combination that causes a progressive slowing down of the topaz tempo.
My setup is: Ableton Live 9.7.3 as master, that sends MIDI sync to Ruby via a IAC Driver midi port. In Ruby I’m using a Topaz::Clock with input from Live midi output and interval 96 (I want to get each clock). In Ruby, I send some NoteOn and NoteOff back to Live to record them.
My computer is a MacBook Pro with 4 cores and 16gb RAM. My ruby is 2.4.1pl11. Your gems are the last available versions downloadable from standar repo with gem install.
For example, at tempo 120 bpm in my test, when we arrive at bar 64 the note is recorded starting on bar 65.1. The previous notes also are delayed, but not so much. You can see my test below.
The problem has been there since so much ago, but I’ve been aware of it after I updated all the gems and ffi-coremidi 0.4.1 was downloaded; on 0.3.9 the problem exists but is not as evident.
I’ve been partially debugging your code and I think I’ve found the problem is caused between midi-eye and ffi-coremidi. On the call to @device.buffer.slice on midi-eye Source.poll method it seems the buffer is being very big and slice is slower as it is bigger. I don’t understand why the last changes to ffi-coremidi make the problem worst, maybe in 0.3.9 the buffer is cleared so it doesn’t gets so big?
For my musa-dsl i’ve found a workaround making a simplfied and limited clock, but I want to let you know the problem. Maybe someone else already has found it.
require 'topaz'
require 'midi-message'
def t bars, beats
bars * 24 * 4 + beats * 24
end
puts "CoreMIDI = #{CoreMIDI::VERSION}"
puts "Topaz = #{Topaz::VERSION}"
puts "UniMIDI = #{UniMIDI::VERSION}"
@input = UniMIDI::Input.all.select { |x| x.name == 'Apple Inc. Driver IAC' }[1]
@output = UniMIDI::Output.all.select { |x| x.name == 'Apple Inc. Driver IAC' }[1]
@ticks = -1
@clock = Topaz::Clock.new(@input, interval: 96) do # Live is the master clock for Ruby
@ticks += 1
if @ticks == t(0, 0)
@output.puts MIDIMessage::NoteOn.new(0, 60, 64)
end
if @ticks == t(0, 0.5)
@output.puts MIDIMessage::NoteOff.new(0, 60, 64)
end
if @ticks == t(1, 0)
@output.puts MIDIMessage::NoteOn.new(0, 61, 64)
end
if @ticks == t(1, 0.5)
@output.puts MIDIMessage::NoteOff.new(0, 61, 64)
end
if @ticks == t(9, 0)
@output.puts MIDIMessage::NoteOn.new(0, 62, 64)
end
if @ticks == t(9, 0.5)
@output.puts MIDIMessage::NoteOff.new(0, 62, 64)
end
if @ticks == t(19, 0)
@output.puts MIDIMessage::NoteOn.new(0, 63, 64)
end
if @ticks == t(19, 0.5)
@output.puts MIDIMessage::NoteOff.new(0, 63, 64)
end
if @ticks == t(39, 0)
@output.puts MIDIMessage::NoteOn.new(0, 64, 64)
end
if @ticks == t(39, 0.5)
@output.puts MIDIMessage::NoteOff.new(0, 64, 64)
end
if @ticks == t(63, 0)
@output.puts MIDIMessage::NoteOn.new(0, 65, 64)
end
if @ticks == t(63, 0.5)
@output.puts MIDIMessage::NoteOff.new(0, 65, 64)
end
end
puts "Starting..."
@clock.start
Hi, thanks so much for the compliment and this detailed explanation of the issue
Will take me a couple of weeks to find time to dig into it but I will.
One immediate reaction is that truncating the ffi-coremidi buffer as it reaches a certain size limit is something I've already been toying with recently. I had originally intended to implement that back when I wrote the library but figured I'd wait until there was a problem before optimizing. Guess it took a while...
Thank you! It will be very useful! Maybe if you don't find the time to do it I can find myself and send you a patch.
@javier-sy
Would you be able to test to see if the problem is still there using an experimental branch of ffi-coremidi that I created for this?
You should be able to do so by adding this to your Gemfile
gem "ffi-coremidi", :git => "https://github.com/arirusso/ffi-coremidi.git", :branch => "bugs/input-latency"
Then run bundle update ffi-coremidi
Hello @arirusso, I will check your branch with my test code and one of my compositions in the next days. Thank you!