1

Using Web MIDI andTeoria.JS I'm trying to build a web based a chords controller.

I found a way to generate chords for a scale thanks to teoria-chord-progression and then get the midi codes for it. Now I would like to get the midi notes for the inversions of the same chord.

What I have done so far is subtracting 12 from the original midi note for the fifth for the first inversion then for the third and the fifth for the second inversion but I'm sure there is a better way.

EDIT: here the code I have, it plays only the chord in its not inverted form:

'use strict';

const teoria = require('teoria');
const chordProgression = require('teoria-chord-progression');
const Combokeys = require("combokeys");

const document = global.document;

const cSharpHMinor = teoria.scale('c#', 'harmonicminor');
const chords = chordProgression(cSharpHMinor, [1, 2, 3, 4, 5, 6, 7], 3).chords;
const combokeys = new Combokeys(document.documentElement);


global.navigator.requestMIDIAccess()
    .then((midiAccess) => {
        return Array.from(midiAccess.outputs.values());
    })
    .then((midiOutputs)=> {
        chords.forEach((chord, index) => {
            buildPadForChord(index + 1, chord, midiOutputs);
        });
    });


function createPad(index, chordName, listener) {
    let button = document.createElement('button');
    button.setAttribute('type', 'button');
    button.textContent = `${chordName} (${index})`;
    button.addEventListener('click', listener);

    let autorepeat = false;
    combokeys.bind(index.toString(), () => {
        if (!autorepeat) {
            autorepeat = true;
            listener();
        }
    }, 'keydown');
    combokeys.bind(index.toString(), () => {
        autorepeat = false;
    }, 'keyup');
    document.documentElement.appendChild(button);
}

function buildPadForChord(index, chord, midiOutputs) {

    let listener = () => {
        midiOutputs.forEach((midiOutput) => {
            chord.notes().forEach((note)=> {
                midiOutput.send([0x90, note.midi(), 127]);
                midiOutput.send([0x80, note.midi(), 127], global.performance.now() + 1000.0);
            });
        });
    };

    createPad(index, chord.name, listener);
}
Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
Jonathan Raoult
  • 812
  • 7
  • 10

1 Answers1

0

According to this issue on git, inversions currently are not implemented in Teoria.js. At one point the developer was considering adding them, but nothing so far.

My implementation in my own code was this:

// Adds an "invert" function to the Teoria Chord class
teoria.Chord.prototype.invert = function(n){
  // Grabs the current chord voicing. Returns array of intervals.
  var voicing = this.voicing()
  // Reverse the array to work top-down when n is negative
  if(n < 0){
    voicing = voicing.reverse()
  }

  // Loop through each inversion
  var j = Math.abs(n);
  for(let i = 0; i < j; i++){
    // Find which interval we're modifying this loop.
    let index = i % voicing.length;
    if(n > 0){
        // Move the lowest note up a perfect 8th
        voicing[index] = voicing[index].add(teoria.interval('P8'))
      }else{
      // Move the highest note down a perfect 8th
      voicing[index] = voicing[index].add(teoria.interval('P-8'))
    }
  }
  // Change the array into a usable format
  var newVoicing = arrayToSimple(voicing)
  this.voicing(newVoicing)

  // Return the object for chaining
  return this;
}

The arrayToSimple function:

function arrayToSimple(array){
    var newArray = []
    for(let item of array){
        newArray.push(item.toString())
    }
    return newArray
}

Now, you can call Chord.invert(n) on any chord, where n is your inversion number. If n is negative, the chord will be inverted downwards, whereas if it is positive, it will be inverted upwards.

Note that the above invert() function needs a chord with a voicing of [lowest note, ..., highest note], in that order. Consequently, calling Chord.invert(1).invert(1) will not be the same as calling Chord.invert(2). If you need this functionality, you might detect which notes are lowest using Chord.bass() and/or Chord.notes(), and reorder the elements. That is probably overkill, though.

Aaa
  • 900
  • 3
  • 9
  • 22