Web Midi Linnstrument Projekt – Beginner question

Hello together, I have a JavaScript-Question for my Web Midi Linnstrument Projekt.

https://)https://codepen.io/jonasxjonas/pen/gOMZzvghttps://codepen.io/jonasxjonas/pen/gOMZzvg)

If I press on of my Buttons on my Midi-Controller I want to light up all Buttons that correspond to the specific Note. Because its a Isomorphic musical Keyboard Grid there are more than one. For example midi key80 should trigger button 2 and 21

This is my current Javascript code (Line 37-51).

var sampleMap = {
  key79: 1,
  key80: 2 && 21,
  key81: 3,
  key82: 4,
  key83: 5,
  key84: 6,
  key85: 7,
  key86: 8,
  key87: 9,
  key88: 10,
  key89: 11,
  key90: 12,
  key91: 13,
  key92: 14,  
};

I just started with coding – I guess its a easy question for somebody else :slight_smile:

Greatings from Berlin
Jonas

That looks horribly interesting but I haven’t the slightest clue what an isomorphic keyboard is (except for a 5 minutes google session). From that, I’m guessing that when you press the key for, say, C-4, you want all the other C-4 keys to light up?

If that’s the case, the easiest way would be to give all your buttons a data attribute (or class). Right now, all your keys have an identical data-key=s. I don’t know what the s is for, but if you store the name of the note instead, it would be one line of JavaScript to let all identical notes light up simultaneously when a key is pressed.

@jsdisco Thank you for your reply. Yes, that is exactly what I want (all other C-4 keys light up) Like in this video: https://www.youtube.com/watch?v=MTE6vwGpy0I&t=1637s

Here is a great example somebody playing the Linnstrument: https://www.youtube.com/watch?v=PWlOIDxkAO0&list=PLx1lI0FKr5C49UhQIemx6vqBwPfryNstO&index=21

I now have dinner with my girlfriend, but after that I will have a look what you suggest.

Thanks for the videos, I found it difficult to get good resources on this.

Assuming that the order of the buttons follows a repeating pattern of notes, it should be relatively uncomplicated to loop over them and give them their data-note attributes. I wouldn’t add those manually unless you have too much time on your hands.

@jdisco I think I unterstand what you mean, and probably I could implement that with a lot of research of how to do that (even manually) :man_shrugging::slight_smile:

If you have some spare time to help me, I would be really thankfull. Here is the way the original code. I think the data-key=s is for the option of typing with your pc-keyboard and not with a midi-keyboard.


Can you give me a code-example, how you would do it, if you want to light up two of the buttons by pressing (or midi-trigger) one?

Maybe I can do something like that in CSS:

if(btnC1.active){
  btnC2 {
  background-color: #0600ff;
}

But it doesn’t work at the moment… :thinking:

Sure, let’s say you press the key for C-3. If they all have a data-note attribute, you’d just select them all and give them a light-up class for example:

Array.from(document.querySelectorAll('[C-3]')).forEach(btn => btn.classList.add('light-up')

The current issue is that your buttons don’t have any attributes yet to select them. Looking at the problem, I’d actually suggest to delete all buttons from the HTML and instead add them with JavaScript, and give them all necessary attributes in the process. There’s an obvious pattern in how they are arranged (looks like you’re building a similar keyboard like the one in the first video you linked).

I find this thing interesting enough to develop a solution, it’s not much work. It’s late though so I’ll keep that for tomorrow.

One thing about your current implementation - there’s a little bug when you click on a button and drag the mouse while still holding the mouse button, the active class doesn’t get removed in that case. But no need to worry about that now, it’s not hard to fix.

Okay, I think I unterstand the problem with the missing attributes. Great that you want to help me.

I want to use that WebMidi Project for Youtube-Tutorials how to play such a Isomorphic-Keyboard-Grid. This is by the way my Sensel Morph Midi Controller Mod:


Its made out of 2 Sensel Morphs with Custom Midi-Mapping

Alright I couldn’t help myself, this keyboard is absolutely intriguing. I play piano (or at least know in theory how to play it), and this layout makes it so much easier to master the instrument. I really wonder why the traditional layout is still so famous.

Anyway, back to code. Here’s a function that will add all buttons and give them their data-attributes:

function addButtons() {
    const content = document.querySelector('#content');

    const notes = ['C', 'Csharp', 'D', 'Dsharp', 'E', 'F', 'Fsharp', 'G', 'Gsharp', 'A', 'Asharp', 'B'];

    const cols = 14;
    const rows = 12;
    const startOctave = 0;
    let allRows = [];

    for (let i = 0; i < rows; i++) {
        const row = document.createElement('DIV');
        row.classList.add('button-row');
        let currOctave = startOctave + Math.floor((i * 5) / 12);
        for (let j = 0; j < cols; j++) {
            const btn = document.createElement('DIV');
            const currNote = notes[j + (i * 5) - Math.floor((j + i * 5) / 12) * 12];
            if (currNote === 'C' && j !== 0) {
                currOctave++;
            }
            btn.classList.add('button');
            if (currNote === 'C') {
                btn.classList.add('btnC');
            }
            btn.dataset.note = `${currNote}-${currOctave}`;
            row.appendChild(btn);
        }
        allRows.push(row);
    }

    allRows.reverse().forEach(row => content.appendChild(row));
}
addButtons();

Pretty sure there’s a more elegant solution, but well this works. You’d also have to delete all the buttons in your HTML first, so you only have an empty div with class=“content”.

Bit of CSS because the structure is now different:

.button-row {
    display: flex;
}

Modifying the event listeners so that all buttons light up:

function clickPlayOn(e) {
  const note = e.target.dataset.note;
  document.querySelectorAll(`[data-note="${note}"]`).forEach(b => b.classList.add('active'));
  e.target.play();
}

function clickPlayOff(e) {
  document.querySelectorAll('.button').forEach(b => b.classList.remove('active'))
}

Not sure if that messes up any of the audio functions, I heard no sound so I guess it’s not yet implemented anyway.

@jsdisco Wow, thank you very much :slight_smile:
I have made a copy of my Project to implement your code:

With mouse-input the multiple-button light up works great. Unfortunately not with midi-input. The Buttons still light up, but not multiple at the same time.

I think it cause I still map every single key to a specific button. But without that code midi-in doesn’t work anymore

var sampleMap = {
  key79: 1,
  key80: 2, 
  key81: 3,
  key82: 4,
}

Do you have an idea how to fix that?

Yeah, there are a lot of benefits of a isomorphic keyboard. In this youtube-playlist I have collected a lot of cool videos about that topic: https://www.youtube.com/playlist?list=PLx1lI0FKr5C49UhQIemx6vqBwPfryNstO

In your keyController function, you can get access to the note that was clicked through the button’s data-note attribute, see example for one key below:

function keyController(e) {
  if (e.type == "keydown") {
    switch (e.keyCode) {

      ...

      case 87:
        btn[1].classList.add('active');
        btn[1].play();

        console.log(btn[1].dataset.note); // Gsharp-4

        break;
    ...

Knowing which note was played, you can now let all other buttons light up - in the same way as with the mouse-function:

const note = btn[1].dataset.note;
document.querySelectorAll(`[data-note="${note}"]`).forEach(b => b.classList.add('active'));

You probably don’t want to write 168 switch cases for 168 buttons, though. You’d need a look-up-map (like your sample map) to define which keyCode triggers which button, something like this (keyCode left, button right):

const keyButtonMap = {
    78: 0,
    79: 1
}

Then, in your keyDown event listener, you grab the button with

const button = keyButtonMap[e.keyCode]

Having the button, you then access its data-note-attribute as described above.

Hope that makes sense.

@jsdisco Thank you for all your help

I’m sure that make sense for someone who have a bit of basic coding knowledge –
unfortunately don’t really have enough of that :man_shrugging::pensive:

I have tried to figure out where your code have to placed:
https://codepen.io/jonasxjonas/pen/oNLmyVw

I think the problem is, that I have no Idea what of the code I have to keep and which I don’t need anymore. Would it be a great request to ask you to copy the project and change the code there? That would be a huge help for me.

In return I would love to offer something in my profession, Graphic Design & Illustration – like to design a logo or a cartoon-character for you :slight_smile: