Hands-free Scrolling Of Sheet Music With Makey Makey And The Piano’s Middle Pedal

It’s always been a bit awkward for me to play from sheet music that is being displayed on a laptop on top of the piano. I’ve been doing this for a long time, but advancing to the next page is pretty inconvenient. The other day however, I put two and two together and came up with a solution.

DSC02034sFor Christmas last year, I got something called “Makey Makey”, a small printed circuit board that acts as a (USB) keyboard (or mouse). You attach two cables to the board, one to ground and the other to a “pin” on the circuit board. When you create a circuit by e.g. letting the other ends of these cables touch one another, a key stroke or click (depending on the selected pin) is sent to the computer. The board has left, right, up, and down, as well as space and click, though if I remember correctly, you can get it to output other key codes too. The idea is that you can use anything to complete the circuit: bananas, Play-Doh, water, or your own body.

Maybe check out this video to get a better idea:

DSC02035sDSC02039sSo when playing the piano, your feet, especially your left foot, aren’t very busy. You may have three pedals, but only need one all the time. So can we maybe use the middle pedal to advance our score? Yes, we can! My Clavinova has pedals that are made of metal. (This probably contributed to my idea a bit.) All you have to do is attach one cable from ground on the circuit board to your body (my belt buckle is made of metal and touches my skin). The other cable is attached to the middle pedal. (The cables that come with the kit have alligator clips, which makes this very easy.) Now just take off your left sock (or wear a sock with a hole in it :p). Awesome, by touching the middle pedal, you can scroll down. If you’re lucky, that’s the end of it. But in my case, the other pedals scrolled down too! Apparently my piano’s pedals are all connected to another. Hrm.

DSC02037sDSC02038sAnd that’s where you do not give up, but see how you might be able to MacGyver the situation. If you e.g. have sticky tape and a coin, that would work. I didn’t have any tape, but I had plastic wrap and aluminum foil. I first wrapped the pedal with the plastic wrap for electrical insulation, and wrapped the result with the aluminum foil. Then I attached the alligator clip to the aluminum foil, and everything works as planned. Make sure to make a thick bulb of aluminum foil to attach the alligator clip to. Otherwise the alligator clip will just cut through the foil.

There are times when you would also like to be able to scroll back up. I haven’t implemented that yet, but it wouldn’t be hard to divide the middle pedal into an up button and a down button depending on where it was touched.

Using Rails Routes Right After Startup

In a new Rails application I am developing at the moment, I have a background job that kicks in every few minutes that may need to send emails to users. This background job is started off in config/initializers/start_something.rb. I had multiple problems with this, but the main one is described in the title of this blog post.

First of all, I originally used FooMailer.foo_email(foo, bar).deliver_later. This would just silently do nothing. Mails just didn’t work. Nothing in /var/mail/maillog either. Drop the _later, and you get a stack trace and finally know why emails aren’t being sent: there is a problem rendering the template, in my case, link_to and url_for weren’t working.

The second problem is the main problem. You get a long stack trace like this:

from /home/.../.rvm/gems/ruby-2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:629:in `generate'
from /home/.../.rvm/gems/ruby-2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:660:in `generate'
from /home/.../.rvm/gems/ruby-2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/route_set.rb:707:in `url_for'
from /home/.../.rvm/gems/ruby-2.3.0/gems/actionpack-5.0.0.1/lib/action_dispatch/routing/url_for.rb:172:in `url_for'
from /home/.../.rvm/gems/ruby-2.3.0/gems/actionview-5.0.0.1/lib/action_view/routing_url_for.rb:90:in `url_for'
from /home/.../.rvm/gems/ruby-2.3.0/gems/actionview-5.0.0.1/lib/action_view/helpers/url_helper.rb:196:in `link_to'
from /home/.../kifu-kun/kifukun/app/views/..._mailer/..._email.html.erb:16:in `_app_views_..._mailer_..._html_erb__3955141667319229348_25724800'

And if you place <% byebug %> right before that line 16 in the template, and copy and paste the link_to line into the debugger, you get something like:

*** ActionController::UrlGenerationError Exception: No route matches {:action=>"...", :controller=>"...", :id=>...}

What? After you double and triple-checked the syntax and names of everything, you maybe decide to check the output of Rails.application.routes.routes:

#<ActionDispatch::Journey::Routes:0x00000004a5d940 @routes=[], @ast=nil, @anchored_routes=[], @custom_routes=[], @simulator=nil>

Um, that looks very empty! No routes? (Normally you get a couple screenfuls of stuff.) As stated earlier, we’re using a config/initializers/start….rb file, and I suspected that the routes just aren’t available yet at this point.

Rails.application.config.after_initialize do
  if defined?(Rails::Server) # don't perform job when running rails c
    FooJob.perform_now
  end
end

Sorry, tangent: this job is running every two minutes, so it performs itself later at the end of the perform method:

FooJob.set(wait: 2.minutes).perform_later # why does self. not work?

Yeah, self.set(…).perform_later doesn’t seem to work, so just use the full class name. (There are cron gems around, but I opted to skip those to cut down on dependencies. And that’s what got me into this mess. :p)

And we’re back to our after_initialize thing. I found this page titled “Rails initialization and configuration order” and thought stuff run here would be able to take advantage of most or all of Rails’ capabilities. Well, it turns out that routes are special in that regard. Here’s something I found after searching for a while: “Rails initializer that runs *after* routes are loaded?” So the answer to my problem is:

Rails.application.config.after_initialize do
  if defined?(Rails::Server) # don't perform job when running rails c
    Rails.application.reload_routes!
    FooJob.perform_now
  end
end

The third problem is really simple. This is the message:

*** ArgumentError Exception: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true

That’s a pretty clear message. In other words, you just have to add (e.g.) host: ‘example.com’ (or something from the config) to the (perhaps implicit) options hash ({controller: ‘…’, action: ‘…’}) and you’re set.