1

I'm building a small web app powered by Tone.js to train yourself to play the piano in key (and maybe some other exercises along the way). So far, you can pick the root note and scale type and click play and it will loop that scale. There's also a keyboard/synth that I took from one of the tone.js examples that you can click on the piano keys, use the keys on your querty keyboard, or select a midi keyboard connected to your computer to use and play sound.

The next step I'm trying to do is create a bar that lights up green when a note in the scale is played and red when a note outside of the scale is played, and maybe record how many notes in a row are played correctly or something like that. The problem I'm running into is that there seems to be no way to get the notes being played by the user directly from tone.js. I can convert the keypresses on the keyboard to notes, but that's about it. I cannot capture any event from someone clicking on the keyboard. I also cannot get the selected midi input device from tone.js to be able to interpret the piano keys being played alongside the tone.js synth.

I have tried attaching event listeners using jquery, since the virtual piano keys are just buttons, but they are inaccessible in the shadow DOM.

Has anyone worked with tone.js and tonejs/ui and know if this is possible or do I have to code that outside of code.js somehow? Any ideas for workarounds?

Edit: I have completed my v1.0.0. I was able to listen to midi devices alongside Tone.js and convert them to the notes being played. This is a decent solution, but as I've mentioned it would be better to get the notes being played directly from the Tone.js synth to simplify the code, allow the trainer bar to work with notes being clicked with the mouse, and so that notes being played can be displayed with their octave number on the trainer bar.

git Repo: https://github.com/erikstagg/music-theory

erikstagg
  • 79
  • 7
  • it will be really hard to help you without showing us the relevant code you're having trouble with. – Andrew Lohr Oct 21 '19 at 19:00
  • sorry https://github.com/erikstagg/music-theory – erikstagg Oct 21 '19 at 22:10
  • You should add only the relevant code in a code snippet (preferably a working one) to your question here instead. People are less likely to go code diving in your github repo to help you. – Andrew Lohr Oct 22 '19 at 14:12
  • I'm not sure what code snippet to include since my question revolves around how to do something in a framework (tone.js) rather than "why won't my code work". You can google tone.js to find their API, and if you go to my github.com link you'll see that there is now a readme with a link to view it via github pages, so you can just inspect the page to see what's going on. – erikstagg Oct 22 '19 at 15:59

1 Answers1

1

You can listen to the mousedown event for example on the main document.

Then check in the Event.path array property (it exposes the path of the target element) to check if its a click inside the keyboard note (which should be at the index 3). You can aslo find the octave at the index 7.

document.addEventListener( 'mousedown', ev => {
  if ( ev.path[3].localName == 'tone-keyboard-note' ) {
    console.log( 'note #' + ev.path[3].getAttribute( 'note' ) )
    console.log( 'octave ', ev.path[7].getAttribute( 'octave' ) )
  }
} )

NB: on Firefox you should use composedPath instead of path.

Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • Cool! I'll have to figure out how to support both path and composedPath but I don't think that will be hard. Maybe I could also modify this code and use it to set my midi intercept to use the same midi device as the synthesiser. Right now it just picks it up from any midi input. Thanks! – erikstagg Oct 22 '19 at 18:22
  • 1
    @erikstagg about composedPath see https://stackoverflow.com/a/39245638 – Supersharp Oct 22 '19 at 20:05