Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

Kill Ugly Processor Architectures -- Karl Lehenbauer


devel / comp.lang.javascript / chord names to midi note numbers

SubjectAuthor
o chord names to midi note numbersluserdroog

1
chord names to midi note numbers

<11a69b13-dd8f-4042-b4a4-adfa9baf1fd9n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=17542&group=comp.lang.javascript#17542

  copy link   Newsgroups: comp.lang.javascript
X-Received: by 2002:a05:6214:c28:: with SMTP id a8mr41475492qvd.24.1639367228858;
Sun, 12 Dec 2021 19:47:08 -0800 (PST)
X-Received: by 2002:a9d:7a45:: with SMTP id z5mr23466249otm.209.1639367228498;
Sun, 12 Dec 2021 19:47:08 -0800 (PST)
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!news.misty.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.javascript
Date: Sun, 12 Dec 2021 19:47:08 -0800 (PST)
Injection-Info: google-groups.googlegroups.com; posting-host=97.87.183.68; posting-account=G1KGwgkAAAAyw4z0LxHH0fja6wAbo7Cz
NNTP-Posting-Host: 97.87.183.68
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <11a69b13-dd8f-4042-b4a4-adfa9baf1fd9n@googlegroups.com>
Subject: chord names to midi note numbers
From: luser.droog@gmail.com (luserdroog)
Injection-Date: Mon, 13 Dec 2021 03:47:08 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Lines: 152
 by: luserdroog - Mon, 13 Dec 2021 03:47 UTC

This is the same code from my previous thread, but with the sweet-
as-pie two liner *scan* function and copious pretentious comments.
Also, better variable names and more `const` everywhere.
I added a helper function `up()` to write the figured bass representation
of chord shapes with having to count up so high. OTOH seeing the
numbers up to 15 gives you a reasonable intuition about fancy chords
like 9-, 11-, 13- chords. It still looks prettier to me using `up()`.

//
//midi note number[s] for a note(name,octave) or chord(name,octave)
//a la luser droog la la la

//a note name is a case-insensitive note letter 'a'..'g', 'A'..'G'
// optionally followed by '#' for sharp or 'b' for flat

//a chord name is a case-insensitive note letter
// optionally followed by an accidental '#'|'b'
// optionally followed by 'm' for minor
// optionally followed by '7' for a 7th chord

const major_tetrachord = [ 2, 2, 1 ];
const minor_tetrachord = [ 2, 1, 2 ];
//there are 2 other ancient, weird tetrachords with odd intervals
//(enharmonic and chromatic) that don't fit with our schema here
//and cannot reasonably be accommodated in a system of linear half-steps IMO

//mode names according to Boethius
const ionian_mode = [ ...major_tetrachord, //defined by Nicomachus as two disjunct
2, //tetrachords separated by a tone
...major_tetrachord ];

//these are intervals between adjacent notes of the mode, ie.
//ionian_mode[0] is the interval between the root and the major second (2 half steps)
//ionian_mode[1] " " " " the second and the major third (2 more half steps)
//ionian_mode[2] " " " " the third and the fourth (1 half step)
//...
//use repeat() to make longer sequences of intervals
//use running_sum() to convert to a sequence of note numbers
// which can be indexed by scale degree, ie.
//running_sum(ionian_mode)[0] = 0 the root
//running_sum(ionian_mode)[1] = 2 the major second
//running_sum(ionian_mode)[2] = 4 the major third
//running_sum(ionian_mode)[3] = 5 the perfect fourth (note these are also fret numbers)
//...

const mixolydian_mode = [ ...major_tetrachord, //need this for 7th chords and stuff
...major_tetrachord, //like A/E and C/G chords
2 ]; //defined by Nicomachus as two conjoint tetrachords

const aeolian_mode = [ ...minor_tetrachord, //need this for decoding note names ['A'..'G']
...minor_tetrachord ]; //add another 2 to fill the octave if needed

const scan = (fn) => (init) => (xs) =>
xs.reduce( (ys,x)=> ( (ys.push( fn(ys.at(-1),x) )), ys ), [init] );
const running_sum = scan( (a,b)=> a+b )( 0 );
const long_scale = (scale)=> repeat( 4, scale );
const repeat = (n, scale)=>
n==0 ? [] :
n==1 ? scale :
n%2 ? [ ...repeat(n/2,scale), ...repeat(n/2,scale), ...scale ] :
[ ...repeat(n/2,scale), ...repeat(n/2,scale) ] ;
const up = (...x)=> x.map(x=> x+7);

console.log(running_sum(aeolian_mode));
console.log(running_sum(long_scale(mixolydian_mode)));

function note( str, octave=0 ){
const num = str.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
const accidental = (str.length > 1 ? (str[1]=='#' ? 1 : -1) : 0);
const fromA = running_sum(aeolian_mode)[ num ] + accidental;
const fromC = fromA + 9;
const thenote = (fromC >= 12 ? fromC - 12 : fromC);
return thenote + octave*12;
}

function chord( str, octave=0 ){
var accidental = 0;
var minor = 0;
var is7th = 0;
const midiA = -3; //+9 (midi number of 'A') -12 (lower octave)

const num = str.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
const root = running_sum(aeolian_mode)[ num ];
str = str.slice(1);

if( str.length > 0 ){
accidental = str[0]=='#' ? 1
: str[0]=='b' ? -1 : 0;
if( accidental ){ str = str.slice(1); }
}

if( str.length > 0 && str[0]=='m' ){
minor = 1;
str = str.slice(1);
}

if( str.length > 0 && str[0]=='7' ){
is7th = 1;
}

const template = is7th ? [ 1,5,7,8,...up(3,5,7,8) ] //figured bass for chord shape
: [ 1,5, 8,...up(3,5, 8) ];
var mode = [ ...mixolydian_mode ];
mode[1] -= minor; //minor chord uses a flat 3rd, ie. the 2nd interval
mode[2] += minor; //balance the adjacent interval
const scale = running_sum( long_scale( mode ) );
const chord = template.map( x=> scale[x-1]
+ root + accidental + midiA
+ octave*12 )
.filter( x=> x>=0 );
return chord;
}

console.log(note("a",0));
console.log(note("c#",0));
console.log(note("eb",0));
console.log(chord("a"));
console.log(chord("am"));
console.log(chord("a7"));
console.log(chord("ebm7",4));

Output (firefox console copy+paste):
Array(7) [ 0, 2, 3, 5, 7, 8, 10 ]
fim.js:56:9
Array(29) [ 0, 2, 4, 5, 7, 9, 10, 12, 14, 16, … ]
fim.js:57:9
9 fim.js:106:9
1 fim.js:107:9
3 fim.js:108:9
Array(5) [ 4, 9, 13, 16, 21 ]
fim.js:109:9
Array(5) [ 4, 9, 12, 16, 21 ]
fim.js:110:9
Array(7) [ 4, 7, 9, 13, 16, 19, 21 ]
fim.js:111:9
Array(8) [ 51, 58, 61, 63, 66, 70, 73, 75 ]
fim.js:112:9


devel / comp.lang.javascript / chord names to midi note numbers

1
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor