Skip to content

Commit

Permalink
Merge pull request #9 from holomorfo:holomorfo/issue7
Browse files Browse the repository at this point in the history
import universo tonal library from phd code
  • Loading branch information
holomorfo authored Jul 8, 2022
2 parents 4764858 + 522521a commit 05a5442
Show file tree
Hide file tree
Showing 19 changed files with 1,460 additions and 9 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"test": "jest"
"test": "jest",
"coverage": "npm test -- --coverage --watchAll=true"
},
"files": [
"/dist"
Expand Down
101 changes: 101 additions & 0 deletions src/Chord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { ChordDef, chordDictionary } from "./defs/DefAcordesJazz";
import { mod, equalArr, num2nota12 } from "./defs/Oper";

export class Chord {
notes: number[] = [];
notesReduced: number[] = [];
chordDefinition: ChordDef = { name: "*", notes: [] };
invertionValue: number;
fundamentalValue: number = -1;
isSeventh: boolean = false;

constructor(notes: number[] = []) {
this.notes = notes;
this.notesReduced = notes
// Modulo 12
.map(mod(12))
// Remove duplicates
.filter((v, i, mod12) => mod12.indexOf(v) === i);

let substract = 0;
const foundChord: ChordDef | undefined = chordDictionary
// Find if belongs in chord li>st
.find((e) => {
const { condition, minus } = this._belongsInList(e.notes);
substract = condition ? minus : 0;
return condition;
});
if (foundChord !== undefined) this.chordDefinition = foundChord;
this.fundamentalValue = this._calculateFundamental(substract);
this.invertionValue = this._calculateInversion(substract);
}

_belongsInList(notes: number[]) {
let minus = 0;
const foundChord = this.notesReduced
// Search in chords dabases
.find((note, _, ls) => {
// substract each of the components of note simplified
const substracted = ls.map((e) => mod(12)(e - note));
substracted.sort((a, b) => a - b);
minus = note;
return equalArr(notes, substracted);
});
return { condition: foundChord !== undefined, minus };
}

_calculateFundamental(substract: number) {
let index = -1;
this.notes.forEach((val, i) => {
if (mod(12)(val) === mod(12)(this.chordDefinition.notes[0] + substract))
index = i;
});

return index > -1 ? mod(12)(this.notes[index]) : -1;
}
_calculateInversion(substract: number) {
// Check which part of the structure the base note is is
// Only checks the fundamental
// TODO: set parts of other voices
let bass = mod(12)(this.notes[0]);
let index = -1;

this.chordDefinition.notes.find((val, i) => {
const cond = mod(12)(val + substract) === bass;
if (cond) index = i;
return cond;
});
return index;
}

_invertionString(invertion: number) {
return ["", "6", "64"][invertion];
}

// TODO: separate into two functions
invertion(isString: boolean = false) {
const fundNum = this.invertionValue;
return isString ? this._invertionString(fundNum) : fundNum;
}

isEquivalent(chord: Chord) {
// Change to compare fundamentaland string
return (
mod(12)(this.fundamental()) === mod(12)(chord.fundamental()) &&
this.chordDefinition.name === chord.chordDefinition.name
);
}

// TODO: separate into two functions
fundamentalString(accidental: string = "s") {
return num2nota12(this.fundamentalValue, accidental);
}

fundamental() {
return this.fundamentalValue;
}
chordName() {
// TODO: #8 add and check fundamental
return this.fundamentalString() + "" + this.chordDefinition.name;
}
}
26 changes: 26 additions & 0 deletions src/CoordenadaTonal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
*
* @author Cristian
*/
export default class CoordenadaTonal {
escala: number;
grado: number;
tipo: string;
// Los grados van del 1 al 7

constructor(esc: number = 0, tp: string = "", gra: number = 0) {
this.escala = esc;
this.tipo = tp;
this.grado = gra;
}

setReg(esc: any, tp: string, gra: number) {
this.escala = esc;
this.grado = gra;
this.tipo = tp;
}

stringify() {
return "Escala " + this.escala + " " + this.tipo + " grado " + this.grado;
}
}
176 changes: 176 additions & 0 deletions src/Tonality.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { calculateChords } from "./defs/DefEscalasAcordes";
import { Chord } from "./Chord";

export class Tonality {
notes: number[] = [];
base: number = 0;
kind: string = "";
defEscAcordes: number[][];

constructor(base: number = 0, kind: string = "M") {
// doMRef = new Tonalidad(0, "M");
let major = [0, 2, 4, 5, 7, 9, 11];
// float[] menArm = { 0, 2, 3, 5, 7, 8, 11 };
let minorHarmonic = [0, 2, 3, 5, 7, 8, 10];

//notasTonalidad = new float[12];
this.notes = [];
this.base = base;
switch (kind) {
case "M":
for (let i = 0; i < major.length; i++) {
// notasTonalidad[i] = (this.baseEsc + mayor[i]) % 12;
this.notes.push((this.base + major[i]) % 12);
}
break;

case "m":
for (let i = 0; i < minorHarmonic.length; i++) {
//notasTonalidad[i] = (this.baseEsc + menArm[i]) % 12;
this.notes.push((this.base + minorHarmonic[i]) % 12);
}
break;
}
this.kind = kind;
this.defEscAcordes = calculateChords(this.base, kind);
}

percentageNotes(listaNotas: number[]) {
let numNotas = 0;
for (let i = 0; i < listaNotas.length; i++)
if (this.noteBelongs(listaNotas[i])) numNotas++;

let reg = numNotas / listaNotas.length;
return reg;
}

noteBelongs(notaAc: number) {
return this.notes.indexOf(notaAc % 12) > -1;
}

degreeNote(notaAc: number) {
let reg = 0;
let grad = this.notes.indexOf(notaAc % 12);
if (grad > -1) reg = grad + 1;
return reg;
}

getTriadType(grado: number) {
let str = "";
let mayor = ["M", "m", "m", "M", "M", "m", "o"];
let menor = ["m", "o", "+", "m", "M", "M", "o"];
switch (this.kind) {
case "M":
str = mayor[grado % this.notes.length];
break;
case "m":
str = menor[grado % this.notes.length];
break;
}
return str;
}

distance(ton: Tonality) {
let cuantosIgual = 0;
if (this.notes.length == ton.notes.length) {
for (let i = 0; i < this.notes.length; i++) {
for (let j = 0; j < ton.notes.length; j++) {
if (this.notes[i] == ton.notes[j]) {
cuantosIgual++;
break;
}
}
}
}
return this.notes.length - cuantosIgual;
}

degreeChord(unArm: Chord) {
// Check degree of a harmony with respect a tonality
// Run through chords in tonality,

// TODO: optimize, to avoid creating lots of chords
let found:
| number[]
| undefined = this.defEscAcordes.find((notes: number[]) =>
unArm.isEquivalent(new Chord(notes))
);
// check if is o7
// check if neapolitan
// return degree of chord
let chord = new Chord(found);
return this.degreeNote(Number(chord.fundamental()));
}
}

// gradoAcordeRomSencillo(unAcorde: Chord, escala: Tonality) {
// let cor = this.gradoSecundario(unAcorde, escala);
// let grado = cor.grado;
// let es = cor.escala;
// // System.out.println(es+"Escala.gradoArodeRomano: " + grado);
// let gradStr = "";
// let graS = "",
// pertS = "";
// // let esS = "";
// if (grado > 0) {
// switch (grado) {
// case 1:
// if (unAcorde.invertion() == 2) {
// graS = "I"; // Aqui cambiar a K para cadencial
// } else {
// graS = "I";
// }
// break;
// case 2:
// if (
// mod(12)(Number(unAcorde.fundamental(false))) ==
// this.baseEsc + 1
// ) {
// // graS = "N";
// graS = "II";
// } else {
// graS = "II";
// }
// break;
// case 3:
// graS = "III";
// break;
// case 4:
// graS = "IV";
// break;
// case 5:
// if (unAcorde.chordDefinition.name === "D7") {
// // graS = "N";
// graS = "DV";
// } else {
// graS = "V";
// }
// break;
// case 6:
// graS = "VI";
// break;
// case 7:
// if (unAcorde.chordDefinition.name === "o7") {
// // graS = "N";
// graS = "Dvii";
// } else {
// graS = "VII";
// }
// // graS = "VII";
// break;
// }
// if (escala.perteneceListaNotas(unAcorde.notesReduced) == false) {
// // if (escala.perteneceArmonia(unAcorde) == false)
// pertS = "*";
// }
// if (es != 1) {
// // gradStr = pertS + graS + "" + unAcorde.inversionStr + "/"
// // + esS;
// } else {
// gradStr = pertS + "" + graS + "" + unAcorde.invertion(true);
// }
// } else {
// gradStr = "";
// }
// return gradStr;
// }
Loading

0 comments on commit 05a5442

Please sign in to comment.