From 2facb3826b26d1c29ec09d9d0810bf8d1f64e561 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Mon, 9 May 2022 19:46:57 -0500 Subject: [PATCH 01/16] moving to typescript --- .gitignore | 3 +- app.js | 2 +- built/app.js | 54 +++++++++++++++++++++++++++ {js => built/src}/harmonyUtil.js | 29 +++++---------- built/src/inputHandling.js | 52 ++++++++++++++++++++++++++ built/src/styleUtils.js | 44 ++++++++++++++++++++++ built/src/toneGeneration.js | 28 ++++++++++++++ index.html | 6 +-- package-lock.json | 20 +++++++++- package.json | 6 ++- src/harmonyUtil.ts | 64 ++++++++++++++++++++++++++++++++ {js => src}/inputHandling.js | 0 {js => src}/styleUtils.js | 0 {js => src}/toneGeneration.js | 0 tsconfig.json | 8 ++++ 15 files changed, 288 insertions(+), 28 deletions(-) create mode 100644 built/app.js rename {js => built/src}/harmonyUtil.js (82%) create mode 100644 built/src/inputHandling.js create mode 100644 built/src/styleUtils.js create mode 100644 built/src/toneGeneration.js create mode 100644 src/harmonyUtil.ts rename {js => src}/inputHandling.js (100%) rename {js => src}/styleUtils.js (100%) rename {js => src}/toneGeneration.js (100%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 30bc162..08f01db 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/node_modules \ No newline at end of file +/node_modules +.gitignore \ No newline at end of file diff --git a/app.js b/app.js index 75cf0c8..cefddb8 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ import { sopranoTones, altoTones, tenorTones, bassTones, extractPitchset, -} from "./js/toneGeneration.js"; +} from "./src/toneGeneration.js"; const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; diff --git a/built/app.js b/built/app.js new file mode 100644 index 0000000..d03acf3 --- /dev/null +++ b/built/app.js @@ -0,0 +1,54 @@ +import { sopranoTones, altoTones, tenorTones, bassTones, extractPitchset, } from "./src/toneGeneration.js"; +const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; +// initialize four synth voices +const soprano = new Tone.Synth().toDestination(); +const alto = new Tone.Synth().toDestination(); +const tenor = new Tone.Synth().toDestination(); +const bass = new Tone.Synth().toDestination(); +// test function for audio is armed +export const audioTest = () => { + soprano.triggerAttackRelease("C5", "16n"); + alto.triggerAttackRelease("F4", "16n"); + tenor.triggerAttackRelease("E4", "16n"); + bass.triggerAttackRelease("G3", "16n"); +}; +// allows a chord to be generated with input from another function +export const soundChord = (pitches) => { + const [s, a, t, b] = pitches; + soprano.triggerAttackRelease(s, "8n"); + alto.triggerAttackRelease(a, "8n"); + tenor.triggerAttackRelease(t, "8n"); + bass.triggerAttackRelease(b, "8n"); +}; +// initial test: generate a single, random chord +export const fullRandomChord = () => { + let pitches = []; + for (let voice of pitchsets) { + // finds a random index, excluding any which may already exist in the array + let index; + do { + index = Math.floor(Math.random() * 100) % voice.length; + } while (pitches.includes(voice[index])); + pitches.push(voice[index]); + console.log(voice[index]); + } + for (let i = 0; i < pitches.length; i++) { + if (pitches[i] === pitches[i + 1]) { + console.log("CAUGHT"); + } + } + soundChord(pitches); + extractPitchset(pitches); +}; +// set up transport +let clock = 0; +let slowClock = 0; +const transportStart = document.getElementById('transport-start'); +let transport; +const loop = new Tone.Loop((time) => { + audioTest(); +}, "8n").start(0); +loop.probability = 0.8; +transportStart.onclick = () => { + Tone.Transport.start(); +}; diff --git a/js/harmonyUtil.js b/built/src/harmonyUtil.js similarity index 82% rename from js/harmonyUtil.js rename to built/src/harmonyUtil.js index f433593..71944c3 100644 --- a/js/harmonyUtil.js +++ b/built/src/harmonyUtil.js @@ -1,5 +1,4 @@ import { extractPitchset } from "./toneGeneration.js"; - // interval definitions: const intervals = { 0: "unison", @@ -10,55 +9,45 @@ const intervals = { 5: "perfect fourth", 6: "tritone" // all intervals beyond this invert to one of the previous intervals -} - +}; // helper functions const transposePitches = (pitchNames, interval) => { let transposed = []; pitchNames.forEach(pitch => transposed.push((pitch + interval) % 12)); return transposed; -} - +}; const findVector = (pitches) => { - let sorted = pitches.sort((x,y) => x - y); + let sorted = pitches.sort((x, y) => x - y); // sorted = sorted.filter((num, idx) => { // return sorted.indexOf(num) === idx; // }); - // finds each interval and logs it as a duple let intervalClasses = []; for (let i = 0; i < sorted.length; i++) { - let j = i+1; - + let j = i + 1; // does not allow out of range values in the proceeding loop if (j >= sorted.length) { break; } - do { - let thing = (sorted[j] - sorted[i]) % 6 + let thing = (sorted[j] - sorted[i]) % 6; if (!(intervalClasses.includes(thing))) { intervalClasses.push(thing); } j++; } while (j < sorted.length); } - - intervalClasses = intervalClasses.sort((x,y) => x-y); + intervalClasses = intervalClasses.sort((x, y) => x - y); return intervalClasses; -} - +}; // analysis let dMajor = extractPitchset(["D", "F#", "A", "D"]); const eMajor = transposePitches(dMajor, 2); console.log(eMajor); console.log(''); - let dMajVector = findVector(dMajor); console.log(dMajVector); - -let complexVector = findVector([0,3,4,7,8,11]); +let complexVector = findVector([0, 3, 4, 7, 8, 11]); console.log(complexVector); - -let splitThird = findVector([0,3,4,7]); +let splitThird = findVector([0, 3, 4, 7]); console.log(splitThird); diff --git a/built/src/inputHandling.js b/built/src/inputHandling.js new file mode 100644 index 0000000..7841d5a --- /dev/null +++ b/built/src/inputHandling.js @@ -0,0 +1,52 @@ +import { audioTest, fullRandomChord } from '../app.js'; +// slider variables referring to DOM +export const sopranoVol = document.getElementById('soprano-vol'); +const sopranoVolTarget = document.getElementById('soprano-vol-target'); +export const sopLFO = document.getElementById('sop-lfo'); +const sopLFOTarget = document.getElementById('sop-lfo-target'); +export const altoVol = document.getElementById('alto-vol'); +const altoVolTarget = document.getElementById('alto-vol-target'); +export const altoLFO = document.getElementById('alto-lfo'); +const altoLFOTarget = document.getElementById('alto-lfo-target'); +export const tenVol = document.getElementById('ten-vol'); +const tenVolTarget = document.getElementById('ten-vol-target'); +export const tenLFO = document.getElementById('ten-lfo'); +const tenLFOTarget = document.getElementById('ten-lfo-target'); +export const bassVol = document.getElementById('bass-vol'); +const bassVolTarget = document.getElementById('bass-vol-target'); +export const bassLFO = document.getElementById('bass-lfo'); +const bassLFOTarget = document.getElementById('bass-lfo-target'); +// logic for displaying values on HTML labels +// S +sopranoVol.oninput = (e) => { + sopranoVolTarget.innerHTML = e.target.value; +}; +sopLFO.oninput = (e) => { + sopLFOTarget.innerHTML = ` ${e.target.value} Hz.`; +}; +// A +altoVol.oninput = (e) => { + altoVolTarget.innerHTML = e.target.value; +}; +altoLFO.oninput = (e) => { + altoLFOTarget.innerHTML = ` ${e.target.value} Hz.`; +}; +// T +tenVol.oninput = (e) => { + tenVolTarget.innerHTML = e.target.value; +}; +tenLFO.oninput = (e) => { + tenLFOTarget.innerHTML = ` ${e.target.value} Hz.`; +}; +// B +bassVol.oninput = (e) => { + bassVolTarget.innerHTML = e.target.value; +}; +bassLFO.oninput = (e) => { + bassLFOTarget.innerHTML = ` ${e.target.value.toString()} Hz.`; +}; +// audio-adjacent input handling +const synthButton = document.getElementById('synth-button'); +synthButton.onclick = audioTest; +const randChord = document.getElementById('rand-chord'); +randChord.onclick = fullRandomChord; diff --git a/built/src/styleUtils.js b/built/src/styleUtils.js new file mode 100644 index 0000000..06f598b --- /dev/null +++ b/built/src/styleUtils.js @@ -0,0 +1,44 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +export const startButton = document.getElementById("start-tone"); +export const synthButton = document.getElementById("synth-button"); +export const showStart = document.getElementsByClassName('show-on-start'); +export const hideStart = document.getElementsByClassName('hide-on-start'); +export const showMore = document.getElementById('info-button'); +export const moreInfo = document.getElementsByClassName('more-info'); +export let appReady = false; +showMore.onclick = () => { + if (showMore.innerHTML === 'Show more info...') { + for (let element of moreInfo) { + element.style.display = 'block'; + document.querySelector('#info-button').innerHTML = "Hide info"; + } + } + else if (showMore.innerHTML === 'Hide info') { + for (let element of moreInfo) { + element.style.display = 'none'; + document.querySelector('#info-button').innerHTML = "Show more info..."; + } + } +}; +startButton.onclick = () => __awaiter(void 0, void 0, void 0, function* () { + yield Tone.start() + .then(() => { + appReady = true; + synthButton.style.display = "block"; + startButton.style.display = "none"; + for (let element of showStart) { + element.style.display = "flex"; + } + for (let element of hideStart) { + element.style.display = "none"; + } + }); +}); diff --git a/built/src/toneGeneration.js b/built/src/toneGeneration.js new file mode 100644 index 0000000..fbc809e --- /dev/null +++ b/built/src/toneGeneration.js @@ -0,0 +1,28 @@ +// we start with a selection of pitches that generally work okay together +export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; +export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; +export const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; +export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; +// now we define some rules to allow for the program to follow so it can some basic tenets of music theory +// we're going to include all pitches, so that it can use semitone-based pitch logic. +// this is focused on base-12, something computers understand quite well +const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; +export const extractPitchset = (pitches) => { + // 1) determine pitch set from given array of pitches + let pitchset = []; + for (let each of pitches) { + // filters numbers from above tones + const str = each; + const regex = /[0-9]/g; + const withoutNums = str.replace(regex, ''); + const pitchNumber = musicalPitches.indexOf(withoutNums); + // ... so that they may be mapped onto numbers corresponding to the chromatic scale + pitchset.push(pitchNumber); + } + // these are sorted from lowest to highest index (something like an interval vector) + pitchset.sort((a, b) => a < b); + console.log(pitchset); + return pitchset; +}; +// no tritones +// no minor 2nds or major 7ths diff --git a/index.html b/index.html index bb9cd11..d0f15eb 100644 --- a/index.html +++ b/index.html @@ -118,9 +118,9 @@ - - - + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index aee9800..9ea39a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "tone": "^14.7.77" + "tone": "^14.7.77", + "typescript": "^4.6.4" } }, "node_modules/@babel/runtime": { @@ -63,6 +64,18 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } } }, "dependencies": { @@ -111,6 +124,11 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "typescript": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==" } } } diff --git a/package.json b/package.json index b348265..8609a1d 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,14 @@ "description": "", "main": "app.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc -p ." }, "keywords": [], "author": "", "license": "ISC", "dependencies": { - "tone": "^14.7.77" + "tone": "^14.7.77", + "typescript": "^4.6.4" } } diff --git a/src/harmonyUtil.ts b/src/harmonyUtil.ts new file mode 100644 index 0000000..144f998 --- /dev/null +++ b/src/harmonyUtil.ts @@ -0,0 +1,64 @@ +import { extractPitchset } from "./toneGeneration.js"; + +// interval definitions: +const intervals = { + 0: "unison", + 1: "minor second", + 2: "major second", + 3: "minor third", + 4: "major third", + 5: "perfect fourth", + 6: "tritone" + // all intervals beyond this invert to one of the previous intervals +} + +// helper functions +const transposePitches = (pitches: number[], interval: number) => { + let transposed = []; + pitches.forEach(pitch => transposed.push((pitch + interval) % 12)); + return transposed; +} + +const findVector = (pitches: number[]) => { + let sorted = pitches.sort((x,y) => x - y); + // sorted = sorted.filter((num, idx) => { + // return sorted.indexOf(num) === idx; + // }); + + // finds each interval and logs it as a duple + let intervalClasses: number[] = []; + for (let i = 0; i < sorted.length; i++) { + let j = i+1; + + // does not allow out of range values in the proceeding loop + if (j >= sorted.length) { + break; + } + + do { + let thing: number = (sorted[j] - sorted[i]) % 6 + if (!(intervalClasses.includes(thing))) { + intervalClasses.push(thing); + } + j++; + } while (j < sorted.length); + } + + intervalClasses = intervalClasses.sort((x,y) => x-y); + return intervalClasses; +} + +// analysis +let dMajor = extractPitchset(["D", "F#", "A", "D"]); +const eMajor = transposePitches(dMajor, 2); +console.log(eMajor); +console.log(''); + +let dMajVector = findVector(dMajor); +console.log(dMajVector); + +let complexVector = findVector([0,3,4,7,8,11]); +console.log(complexVector); + +let splitThird = findVector([0,3,4,7]); +console.log(splitThird); diff --git a/js/inputHandling.js b/src/inputHandling.js similarity index 100% rename from js/inputHandling.js rename to src/inputHandling.js diff --git a/js/styleUtils.js b/src/styleUtils.js similarity index 100% rename from js/styleUtils.js rename to src/styleUtils.js diff --git a/js/toneGeneration.js b/src/toneGeneration.js similarity index 100% rename from js/toneGeneration.js rename to src/toneGeneration.js diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e583438 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "outDir": "./built", + "allowJs": true, + "target": "es2016" + }, + "include": ["./src/**/*"] +} \ No newline at end of file -- 2.49.1 From b84eb103102328529d1d9fb1acf31d56c2299bfb Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Mon, 9 May 2022 20:07:10 -0500 Subject: [PATCH 02/16] converting some html elements for ts compatibility --- built/src/harmonyUtil.js | 4 ++-- built/src/inputHandling.js | 24 ++++++++++++++-------- index.html | 6 +++--- src/{inputHandling.js => inputHandling.ts} | 24 ++++++++++++++-------- 4 files changed, 37 insertions(+), 21 deletions(-) rename src/{inputHandling.js => inputHandling.ts} (67%) diff --git a/built/src/harmonyUtil.js b/built/src/harmonyUtil.js index 71944c3..1ba6c6f 100644 --- a/built/src/harmonyUtil.js +++ b/built/src/harmonyUtil.js @@ -11,9 +11,9 @@ const intervals = { // all intervals beyond this invert to one of the previous intervals }; // helper functions -const transposePitches = (pitchNames, interval) => { +const transposePitches = (pitches, interval) => { let transposed = []; - pitchNames.forEach(pitch => transposed.push((pitch + interval) % 12)); + pitches.forEach(pitch => transposed.push((pitch + interval) % 12)); return transposed; }; const findVector = (pitches) => { diff --git a/built/src/inputHandling.js b/built/src/inputHandling.js index 7841d5a..4477d97 100644 --- a/built/src/inputHandling.js +++ b/built/src/inputHandling.js @@ -19,31 +19,39 @@ const bassLFOTarget = document.getElementById('bass-lfo-target'); // logic for displaying values on HTML labels // S sopranoVol.oninput = (e) => { - sopranoVolTarget.innerHTML = e.target.value; + const target = e.target; + sopranoVolTarget.innerHTML = target.value; }; sopLFO.oninput = (e) => { - sopLFOTarget.innerHTML = ` ${e.target.value} Hz.`; + const target = e.target; + sopLFOTarget.innerHTML = ` ${target.value} Hz.`; }; // A altoVol.oninput = (e) => { - altoVolTarget.innerHTML = e.target.value; + const target = e.target; + altoVolTarget.innerHTML = target.value; }; altoLFO.oninput = (e) => { - altoLFOTarget.innerHTML = ` ${e.target.value} Hz.`; + const target = e.target; + altoLFOTarget.innerHTML = ` ${target.value} Hz.`; }; // T tenVol.oninput = (e) => { - tenVolTarget.innerHTML = e.target.value; + const target = e.target; + tenVolTarget.innerHTML = target.value; }; tenLFO.oninput = (e) => { - tenLFOTarget.innerHTML = ` ${e.target.value} Hz.`; + const target = e.target; + tenLFOTarget.innerHTML = ` ${target.value} Hz.`; }; // B bassVol.oninput = (e) => { - bassVolTarget.innerHTML = e.target.value; + const target = e.target; + bassVolTarget.innerHTML = target.value; }; bassLFO.oninput = (e) => { - bassLFOTarget.innerHTML = ` ${e.target.value.toString()} Hz.`; + const target = e.target; + bassLFOTarget.innerHTML = ` ${target.value} Hz.`; }; // audio-adjacent input handling const synthButton = document.getElementById('synth-button'); diff --git a/index.html b/index.html index d0f15eb..5562843 100644 --- a/index.html +++ b/index.html @@ -118,9 +118,9 @@ - - - + + + \ No newline at end of file diff --git a/src/inputHandling.js b/src/inputHandling.ts similarity index 67% rename from src/inputHandling.js rename to src/inputHandling.ts index cb4ff7f..23a9c74 100644 --- a/src/inputHandling.js +++ b/src/inputHandling.ts @@ -24,38 +24,46 @@ const bassLFOTarget = document.getElementById('bass-lfo-target'); // logic for displaying values on HTML labels // S sopranoVol.oninput = (e) => { - sopranoVolTarget.innerHTML = e.target.value; + const target = e.target as HTMLInputElement; + sopranoVolTarget.innerHTML = target.value; } sopLFO.oninput = (e) => { - sopLFOTarget.innerHTML = ` ${e.target.value} Hz.`; + const target = e.target as HTMLInputElement; + sopLFOTarget.innerHTML = ` ${target.value} Hz.`; } // A altoVol.oninput = (e) => { - altoVolTarget.innerHTML = e.target.value; + const target = e.target as HTMLInputElement; + altoVolTarget.innerHTML = target.value; } altoLFO.oninput = (e) => { - altoLFOTarget.innerHTML = ` ${e.target.value} Hz.`; + const target = e.target as HTMLInputElement; + altoLFOTarget.innerHTML = ` ${target.value} Hz.`; } // T tenVol.oninput = (e) => { - tenVolTarget.innerHTML = e.target.value; + const target = e.target as HTMLInputElement; + tenVolTarget.innerHTML = target.value; } tenLFO.oninput = (e) => { - tenLFOTarget.innerHTML = ` ${e.target.value} Hz.`; + const target = e.target as HTMLInputElement; + tenLFOTarget.innerHTML = ` ${target.value} Hz.`; } // B bassVol.oninput = (e) => { - bassVolTarget.innerHTML = e.target.value; + const target = e.target as HTMLInputElement; + bassVolTarget.innerHTML = target.value; } bassLFO.oninput = (e) => { - bassLFOTarget.innerHTML = ` ${e.target.value.toString()} Hz.`; + const target = e.target as HTMLInputElement; + bassLFOTarget.innerHTML = ` ${target.value} Hz.`; } // audio-adjacent input handling -- 2.49.1 From 693a18c23f5e15df8c4bb760adf52388e07a1e35 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Tue, 10 May 2022 09:38:46 -0500 Subject: [PATCH 03/16] codebase retrofitted to typescript --- .gitignore | 2 +- app.js => app.ts | 1 + built/app.js | 1 + built/src/styleUtils.js | 1 + built/src/toneGeneration.js | 4 ++-- src/{styleUtils.js => styleUtils.ts} | 8 +++++--- src/{toneGeneration.js => toneGeneration.ts} | 6 +++--- tsconfig.json | 3 ++- 8 files changed, 16 insertions(+), 10 deletions(-) rename app.js => app.ts (98%) rename src/{styleUtils.js => styleUtils.ts} (89%) rename src/{toneGeneration.js => toneGeneration.ts} (92%) diff --git a/.gitignore b/.gitignore index 08f01db..273e392 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ /node_modules -.gitignore \ No newline at end of file +/built \ No newline at end of file diff --git a/app.js b/app.ts similarity index 98% rename from app.js rename to app.ts index cefddb8..c5cc0b2 100644 --- a/app.js +++ b/app.ts @@ -1,3 +1,4 @@ +import * as Tone from 'tone'; import { sopranoTones, altoTones, tenorTones, bassTones, extractPitchset, diff --git a/built/app.js b/built/app.js index d03acf3..d3bf093 100644 --- a/built/app.js +++ b/built/app.js @@ -1,3 +1,4 @@ +import * as Tone from 'tone'; import { sopranoTones, altoTones, tenorTones, bassTones, extractPitchset, } from "./src/toneGeneration.js"; const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; // initialize four synth voices diff --git a/built/src/styleUtils.js b/built/src/styleUtils.js index 06f598b..5f8712b 100644 --- a/built/src/styleUtils.js +++ b/built/src/styleUtils.js @@ -7,6 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; +import * as Tone from 'tone'; export const startButton = document.getElementById("start-tone"); export const synthButton = document.getElementById("synth-button"); export const showStart = document.getElementsByClassName('show-on-start'); diff --git a/built/src/toneGeneration.js b/built/src/toneGeneration.js index fbc809e..7c408fb 100644 --- a/built/src/toneGeneration.js +++ b/built/src/toneGeneration.js @@ -9,7 +9,7 @@ export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; export const extractPitchset = (pitches) => { // 1) determine pitch set from given array of pitches - let pitchset = []; + let pitchset; for (let each of pitches) { // filters numbers from above tones const str = each; @@ -20,7 +20,7 @@ export const extractPitchset = (pitches) => { pitchset.push(pitchNumber); } // these are sorted from lowest to highest index (something like an interval vector) - pitchset.sort((a, b) => a < b); + pitchset.sort((a, b) => a - b); console.log(pitchset); return pitchset; }; diff --git a/src/styleUtils.js b/src/styleUtils.ts similarity index 89% rename from src/styleUtils.js rename to src/styleUtils.ts index 3b7a4a0..8231e4c 100644 --- a/src/styleUtils.js +++ b/src/styleUtils.ts @@ -1,11 +1,13 @@ +import * as Tone from 'tone'; + export const startButton = document.getElementById("start-tone"); export const synthButton = document.getElementById("synth-button"); -export const showStart = document.getElementsByClassName('show-on-start'); -export const hideStart = document.getElementsByClassName('hide-on-start'); +export const showStart = document.getElementsByClassName('show-on-start') as HTMLCollectionOf; +export const hideStart = document.getElementsByClassName('hide-on-start') as HTMLCollectionOf; export const showMore = document.getElementById('info-button'); -export const moreInfo = document.getElementsByClassName('more-info'); +export const moreInfo = document.getElementsByClassName('more-info') as HTMLCollectionOf; export let appReady = false; diff --git a/src/toneGeneration.js b/src/toneGeneration.ts similarity index 92% rename from src/toneGeneration.js rename to src/toneGeneration.ts index 9787eaf..59224b6 100644 --- a/src/toneGeneration.js +++ b/src/toneGeneration.ts @@ -9,9 +9,9 @@ export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", // this is focused on base-12, something computers understand quite well const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; -export const extractPitchset = (pitches) => { +export const extractPitchset = (pitches: string[]) => { // 1) determine pitch set from given array of pitches - let pitchset = []; + let pitchset: number[]; for (let each of pitches) { // filters numbers from above tones @@ -25,7 +25,7 @@ export const extractPitchset = (pitches) => { } // these are sorted from lowest to highest index (something like an interval vector) - pitchset.sort((a,b) => a < b); + pitchset.sort((a,b) => a - b); console.log(pitchset); return pitchset; diff --git a/tsconfig.json b/tsconfig.json index e583438..5fd7e6a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "outDir": "./built", "allowJs": true, - "target": "es2016" + "target": "es2016", + "moduleResolution": "node" }, "include": ["./src/**/*"] } \ No newline at end of file -- 2.49.1 From 5cc6669815cab5f96a4fab45a566c267abdfe0a8 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Tue, 10 May 2022 09:44:08 -0500 Subject: [PATCH 04/16] changes to git --- app.ts | 2 -- built/app.js | 55 ---------------------------------- built/src/harmonyUtil.js | 53 -------------------------------- built/src/inputHandling.js | 60 ------------------------------------- built/src/styleUtils.js | 45 ---------------------------- built/src/toneGeneration.js | 28 ----------------- 6 files changed, 243 deletions(-) delete mode 100644 built/app.js delete mode 100644 built/src/harmonyUtil.js delete mode 100644 built/src/inputHandling.js delete mode 100644 built/src/styleUtils.js delete mode 100644 built/src/toneGeneration.js diff --git a/app.ts b/app.ts index c5cc0b2..e908bdc 100644 --- a/app.ts +++ b/app.ts @@ -60,8 +60,6 @@ let slowClock = 0; const transportStart = document.getElementById('transport-start'); -let transport; - const loop = new Tone.Loop((time) => { audioTest(); }, "8n").start(0); diff --git a/built/app.js b/built/app.js deleted file mode 100644 index d3bf093..0000000 --- a/built/app.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as Tone from 'tone'; -import { sopranoTones, altoTones, tenorTones, bassTones, extractPitchset, } from "./src/toneGeneration.js"; -const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; -// initialize four synth voices -const soprano = new Tone.Synth().toDestination(); -const alto = new Tone.Synth().toDestination(); -const tenor = new Tone.Synth().toDestination(); -const bass = new Tone.Synth().toDestination(); -// test function for audio is armed -export const audioTest = () => { - soprano.triggerAttackRelease("C5", "16n"); - alto.triggerAttackRelease("F4", "16n"); - tenor.triggerAttackRelease("E4", "16n"); - bass.triggerAttackRelease("G3", "16n"); -}; -// allows a chord to be generated with input from another function -export const soundChord = (pitches) => { - const [s, a, t, b] = pitches; - soprano.triggerAttackRelease(s, "8n"); - alto.triggerAttackRelease(a, "8n"); - tenor.triggerAttackRelease(t, "8n"); - bass.triggerAttackRelease(b, "8n"); -}; -// initial test: generate a single, random chord -export const fullRandomChord = () => { - let pitches = []; - for (let voice of pitchsets) { - // finds a random index, excluding any which may already exist in the array - let index; - do { - index = Math.floor(Math.random() * 100) % voice.length; - } while (pitches.includes(voice[index])); - pitches.push(voice[index]); - console.log(voice[index]); - } - for (let i = 0; i < pitches.length; i++) { - if (pitches[i] === pitches[i + 1]) { - console.log("CAUGHT"); - } - } - soundChord(pitches); - extractPitchset(pitches); -}; -// set up transport -let clock = 0; -let slowClock = 0; -const transportStart = document.getElementById('transport-start'); -let transport; -const loop = new Tone.Loop((time) => { - audioTest(); -}, "8n").start(0); -loop.probability = 0.8; -transportStart.onclick = () => { - Tone.Transport.start(); -}; diff --git a/built/src/harmonyUtil.js b/built/src/harmonyUtil.js deleted file mode 100644 index 1ba6c6f..0000000 --- a/built/src/harmonyUtil.js +++ /dev/null @@ -1,53 +0,0 @@ -import { extractPitchset } from "./toneGeneration.js"; -// interval definitions: -const intervals = { - 0: "unison", - 1: "minor second", - 2: "major second", - 3: "minor third", - 4: "major third", - 5: "perfect fourth", - 6: "tritone" - // all intervals beyond this invert to one of the previous intervals -}; -// helper functions -const transposePitches = (pitches, interval) => { - let transposed = []; - pitches.forEach(pitch => transposed.push((pitch + interval) % 12)); - return transposed; -}; -const findVector = (pitches) => { - let sorted = pitches.sort((x, y) => x - y); - // sorted = sorted.filter((num, idx) => { - // return sorted.indexOf(num) === idx; - // }); - // finds each interval and logs it as a duple - let intervalClasses = []; - for (let i = 0; i < sorted.length; i++) { - let j = i + 1; - // does not allow out of range values in the proceeding loop - if (j >= sorted.length) { - break; - } - do { - let thing = (sorted[j] - sorted[i]) % 6; - if (!(intervalClasses.includes(thing))) { - intervalClasses.push(thing); - } - j++; - } while (j < sorted.length); - } - intervalClasses = intervalClasses.sort((x, y) => x - y); - return intervalClasses; -}; -// analysis -let dMajor = extractPitchset(["D", "F#", "A", "D"]); -const eMajor = transposePitches(dMajor, 2); -console.log(eMajor); -console.log(''); -let dMajVector = findVector(dMajor); -console.log(dMajVector); -let complexVector = findVector([0, 3, 4, 7, 8, 11]); -console.log(complexVector); -let splitThird = findVector([0, 3, 4, 7]); -console.log(splitThird); diff --git a/built/src/inputHandling.js b/built/src/inputHandling.js deleted file mode 100644 index 4477d97..0000000 --- a/built/src/inputHandling.js +++ /dev/null @@ -1,60 +0,0 @@ -import { audioTest, fullRandomChord } from '../app.js'; -// slider variables referring to DOM -export const sopranoVol = document.getElementById('soprano-vol'); -const sopranoVolTarget = document.getElementById('soprano-vol-target'); -export const sopLFO = document.getElementById('sop-lfo'); -const sopLFOTarget = document.getElementById('sop-lfo-target'); -export const altoVol = document.getElementById('alto-vol'); -const altoVolTarget = document.getElementById('alto-vol-target'); -export const altoLFO = document.getElementById('alto-lfo'); -const altoLFOTarget = document.getElementById('alto-lfo-target'); -export const tenVol = document.getElementById('ten-vol'); -const tenVolTarget = document.getElementById('ten-vol-target'); -export const tenLFO = document.getElementById('ten-lfo'); -const tenLFOTarget = document.getElementById('ten-lfo-target'); -export const bassVol = document.getElementById('bass-vol'); -const bassVolTarget = document.getElementById('bass-vol-target'); -export const bassLFO = document.getElementById('bass-lfo'); -const bassLFOTarget = document.getElementById('bass-lfo-target'); -// logic for displaying values on HTML labels -// S -sopranoVol.oninput = (e) => { - const target = e.target; - sopranoVolTarget.innerHTML = target.value; -}; -sopLFO.oninput = (e) => { - const target = e.target; - sopLFOTarget.innerHTML = ` ${target.value} Hz.`; -}; -// A -altoVol.oninput = (e) => { - const target = e.target; - altoVolTarget.innerHTML = target.value; -}; -altoLFO.oninput = (e) => { - const target = e.target; - altoLFOTarget.innerHTML = ` ${target.value} Hz.`; -}; -// T -tenVol.oninput = (e) => { - const target = e.target; - tenVolTarget.innerHTML = target.value; -}; -tenLFO.oninput = (e) => { - const target = e.target; - tenLFOTarget.innerHTML = ` ${target.value} Hz.`; -}; -// B -bassVol.oninput = (e) => { - const target = e.target; - bassVolTarget.innerHTML = target.value; -}; -bassLFO.oninput = (e) => { - const target = e.target; - bassLFOTarget.innerHTML = ` ${target.value} Hz.`; -}; -// audio-adjacent input handling -const synthButton = document.getElementById('synth-button'); -synthButton.onclick = audioTest; -const randChord = document.getElementById('rand-chord'); -randChord.onclick = fullRandomChord; diff --git a/built/src/styleUtils.js b/built/src/styleUtils.js deleted file mode 100644 index 5f8712b..0000000 --- a/built/src/styleUtils.js +++ /dev/null @@ -1,45 +0,0 @@ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -import * as Tone from 'tone'; -export const startButton = document.getElementById("start-tone"); -export const synthButton = document.getElementById("synth-button"); -export const showStart = document.getElementsByClassName('show-on-start'); -export const hideStart = document.getElementsByClassName('hide-on-start'); -export const showMore = document.getElementById('info-button'); -export const moreInfo = document.getElementsByClassName('more-info'); -export let appReady = false; -showMore.onclick = () => { - if (showMore.innerHTML === 'Show more info...') { - for (let element of moreInfo) { - element.style.display = 'block'; - document.querySelector('#info-button').innerHTML = "Hide info"; - } - } - else if (showMore.innerHTML === 'Hide info') { - for (let element of moreInfo) { - element.style.display = 'none'; - document.querySelector('#info-button').innerHTML = "Show more info..."; - } - } -}; -startButton.onclick = () => __awaiter(void 0, void 0, void 0, function* () { - yield Tone.start() - .then(() => { - appReady = true; - synthButton.style.display = "block"; - startButton.style.display = "none"; - for (let element of showStart) { - element.style.display = "flex"; - } - for (let element of hideStart) { - element.style.display = "none"; - } - }); -}); diff --git a/built/src/toneGeneration.js b/built/src/toneGeneration.js deleted file mode 100644 index 7c408fb..0000000 --- a/built/src/toneGeneration.js +++ /dev/null @@ -1,28 +0,0 @@ -// we start with a selection of pitches that generally work okay together -export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; -export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; -export const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; -export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; -// now we define some rules to allow for the program to follow so it can some basic tenets of music theory -// we're going to include all pitches, so that it can use semitone-based pitch logic. -// this is focused on base-12, something computers understand quite well -const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; -export const extractPitchset = (pitches) => { - // 1) determine pitch set from given array of pitches - let pitchset; - for (let each of pitches) { - // filters numbers from above tones - const str = each; - const regex = /[0-9]/g; - const withoutNums = str.replace(regex, ''); - const pitchNumber = musicalPitches.indexOf(withoutNums); - // ... so that they may be mapped onto numbers corresponding to the chromatic scale - pitchset.push(pitchNumber); - } - // these are sorted from lowest to highest index (something like an interval vector) - pitchset.sort((a, b) => a - b); - console.log(pitchset); - return pitchset; -}; -// no tritones -// no minor 2nds or major 7ths -- 2.49.1 From 3515f9231605086f4938c283c26f219094baaae7 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Tue, 10 May 2022 10:48:33 -0500 Subject: [PATCH 05/16] defining some more harmony utils --- app.ts | 12 ++++-------- src/harmonyUtil.ts | 45 ++++++++++++++++++++++++++++++++++--------- src/toneGeneration.ts | 12 ++++++++++-- tsconfig.json | 2 +- 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/app.ts b/app.ts index e908bdc..1e8a9e7 100644 --- a/app.ts +++ b/app.ts @@ -4,7 +4,7 @@ import { extractPitchset, } from "./src/toneGeneration.js"; -const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; +const pitchsets: string[][] = [sopranoTones, altoTones, tenorTones, bassTones]; // initialize four synth voices const soprano = new Tone.Synth().toDestination(); @@ -21,7 +21,7 @@ export const audioTest = () => { } // allows a chord to be generated with input from another function -export const soundChord = (pitches) => { +export const soundChord = (pitches: string[]) => { const [s,a,t,b] = pitches; soprano.triggerAttackRelease(s, "8n"); alto.triggerAttackRelease(a, "8n"); @@ -31,10 +31,10 @@ export const soundChord = (pitches) => { // initial test: generate a single, random chord export const fullRandomChord = () => { - let pitches = []; + let pitches: string[]; for (let voice of pitchsets) { // finds a random index, excluding any which may already exist in the array - let index; + let index: number; do { index = Math.floor(Math.random() * 100) % voice.length; @@ -55,9 +55,6 @@ export const fullRandomChord = () => { } // set up transport -let clock = 0; -let slowClock = 0; - const transportStart = document.getElementById('transport-start'); const loop = new Tone.Loop((time) => { @@ -69,4 +66,3 @@ loop.probability = 0.8; transportStart.onclick = () => { Tone.Transport.start(); } - diff --git a/src/harmonyUtil.ts b/src/harmonyUtil.ts index 144f998..d8d1c77 100644 --- a/src/harmonyUtil.ts +++ b/src/harmonyUtil.ts @@ -1,7 +1,11 @@ import { extractPitchset } from "./toneGeneration.js"; // interval definitions: -const intervals = { +export interface IntervalDef { + number: string +} + +export const IntervalDefNames = { 0: "unison", 1: "minor second", 2: "major second", @@ -9,7 +13,7 @@ const intervals = { 4: "major third", 5: "perfect fourth", 6: "tritone" - // all intervals beyond this invert to one of the previous intervals + // ... all intervals beyond this invert to one of the previous intervals } // helper functions @@ -48,17 +52,40 @@ const findVector = (pitches: number[]) => { return intervalClasses; } +export const labelIntervals = (vector: number[]): [number, IntervalDef][] => { + let result: [number, IntervalDef][] = []; + + for (let x of vector) { + result.push([x, IntervalDefNames[x]]); + } + + return result; +} + // analysis let dMajor = extractPitchset(["D", "F#", "A", "D"]); const eMajor = transposePitches(dMajor, 2); console.log(eMajor); console.log(''); -let dMajVector = findVector(dMajor); -console.log(dMajVector); +/** + * sample uses of these functions detailed below: + * + * @var dMajVector = @function findVector(dMajor); + * @param dMajor number[] ( result of earlier call to @function extractPitchset ) + * ... @returns [0,3,4,5] + * this indicates this pitchset contains a unison, a minor third, a major third, + * and a perfect fourth (or a corresponding inversion) + * + * @var complexVector = @function findVector([0,3,4,7,8,11]); + * @returns [1,2,3,4,5] + * + * @var splitThird = @function findVector([0,3,4,7]); + * @returns [1,3,4] + * + * @function labelIntervals + * @param vector = number[] corresponding to sorted vector + * references @interface IntervalDef to select from @constant IntervalDefNames + * @returns an array of duples, each containing a number and an entry from IntervalDef + */ -let complexVector = findVector([0,3,4,7,8,11]); -console.log(complexVector); - -let splitThird = findVector([0,3,4,7]); -console.log(splitThird); diff --git a/src/toneGeneration.ts b/src/toneGeneration.ts index 59224b6..25a7de8 100644 --- a/src/toneGeneration.ts +++ b/src/toneGeneration.ts @@ -1,3 +1,5 @@ +import * as harmUtil from './harmonyUtil'; + // we start with a selection of pitches that generally work okay together export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; @@ -11,7 +13,7 @@ const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G export const extractPitchset = (pitches: string[]) => { // 1) determine pitch set from given array of pitches - let pitchset: number[]; + let pitchset: number[] = []; for (let each of pitches) { // filters numbers from above tones @@ -32,4 +34,10 @@ export const extractPitchset = (pitches: string[]) => { } // no tritones -// no minor 2nds or major 7ths \ No newline at end of file +// no minor 2nds or major 7ths + +const evaluateVector = (vector: number[]): boolean => { + + + return true; +} diff --git a/tsconfig.json b/tsconfig.json index 5fd7e6a..b7b0f55 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "outDir": "./built", "allowJs": true, - "target": "es2016", + "target": "es2017", "moduleResolution": "node" }, "include": ["./src/**/*"] -- 2.49.1 From d3c62d61b82f4d4b71dece9063994dd4139a9f7b Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Tue, 10 May 2022 11:14:47 -0500 Subject: [PATCH 06/16] can not push to undefined array --- app.ts | 10 +++----- index.html | 5 ++-- src/audioUtils.ts | 34 +++++++++++++++++++++++++ src/harmonyUtil.ts | 27 +++++++++++++++++--- src/toneGeneration.ts | 59 ++++++++++++++++++------------------------- 5 files changed, 87 insertions(+), 48 deletions(-) create mode 100644 src/audioUtils.ts diff --git a/app.ts b/app.ts index 1e8a9e7..7e2856f 100644 --- a/app.ts +++ b/app.ts @@ -1,10 +1,6 @@ import * as Tone from 'tone'; -import { - sopranoTones, altoTones, tenorTones, bassTones, - extractPitchset, -} from "./src/toneGeneration.js"; - -const pitchsets: string[][] = [sopranoTones, altoTones, tenorTones, bassTones]; +import { pitchsets } from "./src/toneGeneration.js"; +import { extractPitchset } from './src/harmonyUtil.js'; // initialize four synth voices const soprano = new Tone.Synth().toDestination(); @@ -31,7 +27,7 @@ export const soundChord = (pitches: string[]) => { // initial test: generate a single, random chord export const fullRandomChord = () => { - let pitches: string[]; + let pitches: string[] = []; for (let voice of pitchsets) { // finds a random index, excluding any which may already exist in the array let index: number; diff --git a/index.html b/index.html index 5562843..c99b8c0 100644 --- a/index.html +++ b/index.html @@ -118,9 +118,10 @@ - + + + - \ No newline at end of file diff --git a/src/audioUtils.ts b/src/audioUtils.ts new file mode 100644 index 0000000..325e69d --- /dev/null +++ b/src/audioUtils.ts @@ -0,0 +1,34 @@ +import { evaluateVector, pitchsets } from "./toneGeneration"; +import { extractPitchset, findVector } from "./harmonyUtil"; +import { soundChord } from '../app'; + +export const fullRandomChord = () => { + let pitches: string[]; + for (let voice of pitchsets) { + // finds a random index, excluding any which may already exist in the array + let index: number; + + do { + index = Math.floor(Math.random() * 100) % voice.length; + } while (pitches.includes(voice[index])); + + pitches.push(voice[index]); + console.log(voice[index]); + } + + for (let i = 0; i < pitches.length; i++) { + if (pitches[i] === pitches[i+1]) { + console.log("CAUGHT"); + } + } + + soundChord(pitches); + let pitchValues: number[] = extractPitchset(pitches); + pitchValues = findVector(pitchValues); + + let evaluated = evaluateVector(pitchValues); + + console.log(pitches); + console.log(evaluated); + return evaluated; +} \ No newline at end of file diff --git a/src/harmonyUtil.ts b/src/harmonyUtil.ts index d8d1c77..e5b7ae1 100644 --- a/src/harmonyUtil.ts +++ b/src/harmonyUtil.ts @@ -1,5 +1,3 @@ -import { extractPitchset } from "./toneGeneration.js"; - // interval definitions: export interface IntervalDef { number: string @@ -16,6 +14,8 @@ export const IntervalDefNames = { // ... all intervals beyond this invert to one of the previous intervals } +export const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; + // helper functions const transposePitches = (pitches: number[], interval: number) => { let transposed = []; @@ -23,7 +23,27 @@ const transposePitches = (pitches: number[], interval: number) => { return transposed; } -const findVector = (pitches: number[]) => { +export const extractPitchset = (pitches: string[]) => { + // 1) determine pitch set from given array of pitches + let pitchset: number[] = []; + + for (let each of pitches) { + // filters numbers from above tones + const str = each; + const regex = /[0-9]/g; + const withoutNums = str.replace(regex, ''); + const pitchNumber = musicalPitches.indexOf(withoutNums); + + // ... so that they may be mapped onto numbers corresponding to the chromatic scale + pitchset.push(pitchNumber); + } + + // these are sorted from lowest to highest index (something like an interval vector) + pitchset.sort((a,b) => a - b); + return pitchset; +} + +export const findVector = (pitches: number[]) => { let sorted = pitches.sort((x,y) => x - y); // sorted = sorted.filter((num, idx) => { // return sorted.indexOf(num) === idx; @@ -88,4 +108,3 @@ console.log(''); * references @interface IntervalDef to select from @constant IntervalDefNames * @returns an array of duples, each containing a number and an entry from IntervalDef */ - diff --git a/src/toneGeneration.ts b/src/toneGeneration.ts index 25a7de8..76a2cb7 100644 --- a/src/toneGeneration.ts +++ b/src/toneGeneration.ts @@ -1,43 +1,32 @@ -import * as harmUtil from './harmonyUtil'; +import { findVector, IntervalDefNames, musicalPitches } from './harmonyUtil'; // we start with a selection of pitches that generally work okay together -export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; -export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; -export const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; -export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; +const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; +const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; +const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; +const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; -// now we define some rules to allow for the program to follow so it can some basic tenets of music theory -// we're going to include all pitches, so that it can use semitone-based pitch logic. -// this is focused on base-12, something computers understand quite well -const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; +export const pitchsets: string[][] = [sopranoTones, altoTones, tenorTones, bassTones]; -export const extractPitchset = (pitches: string[]) => { - // 1) determine pitch set from given array of pitches - let pitchset: number[] = []; +/** + * now we define some rules to allow for the program to follow so it can some basic tenets of music theory + * we include all pitches, so that it can use semitone-based pitch logic focused on base-12 + * + * some basic rules: + * no tritones + * no minor 2nds or major 7ths +*/ - for (let each of pitches) { - // filters numbers from above tones - const str = each; - const regex = /[0-9]/g; - const withoutNums = str.replace(regex, ''); - const pitchNumber = musicalPitches.indexOf(withoutNums); +export const evaluateVector = (vector: number[]): boolean => { + let result: boolean; - // ... so that they may be mapped onto numbers corresponding to the chromatic scale - pitchset.push(pitchNumber); + for (let x of vector) { + if (x === 1 || x === 6) { + result = false; + return; + } else { + result = true; + } } - - // these are sorted from lowest to highest index (something like an interval vector) - pitchset.sort((a,b) => a - b); - console.log(pitchset); - - return pitchset; -} - -// no tritones -// no minor 2nds or major 7ths - -const evaluateVector = (vector: number[]): boolean => { - - - return true; + return result; } -- 2.49.1 From 04d26d852926e7d484bf5dc112eeb2f9122bbbd0 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Tue, 10 May 2022 11:47:45 -0500 Subject: [PATCH 07/16] defined a function which identifies dissonance in a vector --- app.ts | 25 ------------------------- index.html | 1 + src/audioUtils.ts | 5 +++-- src/inputHandling.ts | 3 ++- src/styleUtils.ts | 2 +- src/toneGeneration.ts | 16 +++------------- 6 files changed, 10 insertions(+), 42 deletions(-) diff --git a/app.ts b/app.ts index 7e2856f..c8b0f95 100644 --- a/app.ts +++ b/app.ts @@ -25,31 +25,6 @@ export const soundChord = (pitches: string[]) => { bass.triggerAttackRelease(b, "8n"); } -// initial test: generate a single, random chord -export const fullRandomChord = () => { - let pitches: string[] = []; - for (let voice of pitchsets) { - // finds a random index, excluding any which may already exist in the array - let index: number; - - do { - index = Math.floor(Math.random() * 100) % voice.length; - } while (pitches.includes(voice[index])); - - pitches.push(voice[index]); - console.log(voice[index]); - } - - for (let i = 0; i < pitches.length; i++) { - if (pitches[i] === pitches[i+1]) { - console.log("CAUGHT"); - } - } - - soundChord(pitches); - extractPitchset(pitches); -} - // set up transport const transportStart = document.getElementById('transport-start'); diff --git a/index.html b/index.html index c99b8c0..89ac1e5 100644 --- a/index.html +++ b/index.html @@ -123,5 +123,6 @@ + \ No newline at end of file diff --git a/src/audioUtils.ts b/src/audioUtils.ts index 325e69d..b8314f2 100644 --- a/src/audioUtils.ts +++ b/src/audioUtils.ts @@ -9,10 +9,11 @@ export const fullRandomChord = () => { let index: number; do { + if (!pitches) pitches = []; index = Math.floor(Math.random() * 100) % voice.length; - } while (pitches.includes(voice[index])); + } while (pitches.includes(voice[index]) ?? false); - pitches.push(voice[index]); + pitches ? pitches.push(voice[index]) : pitches = [voice[index]]; console.log(voice[index]); } diff --git a/src/inputHandling.ts b/src/inputHandling.ts index 23a9c74..6b31b0b 100644 --- a/src/inputHandling.ts +++ b/src/inputHandling.ts @@ -1,4 +1,5 @@ -import { audioTest, fullRandomChord } from '../app.js'; +import { audioTest } from '../app.js'; +import { fullRandomChord } from './audioUtils.js'; // slider variables referring to DOM export const sopranoVol = document.getElementById('soprano-vol'); diff --git a/src/styleUtils.ts b/src/styleUtils.ts index 8231e4c..94e17bb 100644 --- a/src/styleUtils.ts +++ b/src/styleUtils.ts @@ -1,4 +1,4 @@ -import * as Tone from 'tone'; +import * as Tone from "tone"; export const startButton = document.getElementById("start-tone"); export const synthButton = document.getElementById("synth-button"); diff --git a/src/toneGeneration.ts b/src/toneGeneration.ts index 76a2cb7..94959b3 100644 --- a/src/toneGeneration.ts +++ b/src/toneGeneration.ts @@ -1,5 +1,3 @@ -import { findVector, IntervalDefNames, musicalPitches } from './harmonyUtil'; - // we start with a selection of pitches that generally work okay together const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; @@ -17,16 +15,8 @@ export const pitchsets: string[][] = [sopranoTones, altoTones, tenorTones, bassT * no minor 2nds or major 7ths */ -export const evaluateVector = (vector: number[]): boolean => { - let result: boolean; +export const evaluateVector = (vector: number[]): boolean => ((vector.includes(1) || vector.includes(6))); - for (let x of vector) { - if (x === 1 || x === 6) { - result = false; - return; - } else { - result = true; - } - } - return result; +export const rejectDissonance = (vector: number[]) => { + } -- 2.49.1 From 6fa7760d0f3e1cad60ea512f14232c34a7377a4f Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Wed, 11 May 2022 10:28:25 -0500 Subject: [PATCH 08/16] module resolution problem --- app.ts | 2 - index.html | 5 --- package-lock.json | 15 +++++++ package.json | 3 ++ src/audioUtils.ts | 9 ++-- src/harmonyUtil.ts | 68 +++++------------------------ src/styleUtils.ts | 2 +- src/toneGeneration.ts | 22 ---------- src/vector_logic/evaluateVector.ts | 7 +++ src/vector_logic/extractPitchset.ts | 21 +++++++++ src/vector_logic/findVector.ts | 28 ++++++++++++ tsconfig.json | 5 ++- 12 files changed, 95 insertions(+), 92 deletions(-) delete mode 100644 src/toneGeneration.ts create mode 100644 src/vector_logic/evaluateVector.ts create mode 100644 src/vector_logic/extractPitchset.ts create mode 100644 src/vector_logic/findVector.ts diff --git a/app.ts b/app.ts index c8b0f95..6bfcda9 100644 --- a/app.ts +++ b/app.ts @@ -1,6 +1,4 @@ import * as Tone from 'tone'; -import { pitchsets } from "./src/toneGeneration.js"; -import { extractPitchset } from './src/harmonyUtil.js'; // initialize four synth voices const soprano = new Tone.Synth().toDestination(); diff --git a/index.html b/index.html index 89ac1e5..bdfb6df 100644 --- a/index.html +++ b/index.html @@ -119,10 +119,5 @@ - - - - - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9ea39a7..6855304 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,9 @@ "dependencies": { "tone": "^14.7.77", "typescript": "^4.6.4" + }, + "devDependencies": { + "@types/node": "^17.0.32" } }, "node_modules/@babel/runtime": { @@ -24,6 +27,12 @@ "node": ">=6.9.0" } }, + "node_modules/@types/node": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==", + "dev": true + }, "node_modules/automation-events": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-4.0.16.tgz", @@ -87,6 +96,12 @@ "regenerator-runtime": "^0.13.4" } }, + "@types/node": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==", + "dev": true + }, "automation-events": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-4.0.16.tgz", diff --git a/package.json b/package.json index 8609a1d..474ae86 100644 --- a/package.json +++ b/package.json @@ -14,5 +14,8 @@ "dependencies": { "tone": "^14.7.77", "typescript": "^4.6.4" + }, + "devDependencies": { + "@types/node": "^17.0.32" } } diff --git a/src/audioUtils.ts b/src/audioUtils.ts index b8314f2..568098e 100644 --- a/src/audioUtils.ts +++ b/src/audioUtils.ts @@ -1,6 +1,9 @@ -import { evaluateVector, pitchsets } from "./toneGeneration"; -import { extractPitchset, findVector } from "./harmonyUtil"; -import { soundChord } from '../app'; +import { soundChord } from '../app.js'; +import { pitchsets } from "./harmonyUtil.js"; + +import { evaluateVector } from "./vector_logic/evaluateVector.js"; +import { findVector } from "./vector_logic/findVector.js"; +import { extractPitchset } from "./vector_logic/extractPitchset.js"; export const fullRandomChord = () => { let pitches: string[]; diff --git a/src/harmonyUtil.ts b/src/harmonyUtil.ts index e5b7ae1..5ba32df 100644 --- a/src/harmonyUtil.ts +++ b/src/harmonyUtil.ts @@ -1,3 +1,14 @@ +// pitchset definitions, grouped into matrix before export +const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; +const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; +const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; +const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; + +export const pitchsets: string[][] = [sopranoTones, altoTones, tenorTones, bassTones]; + +// mapping of musical pitches, refer to this by index, maps onto base 12 +export const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; + // interval definitions: export interface IntervalDef { number: string @@ -14,8 +25,6 @@ export const IntervalDefNames = { // ... all intervals beyond this invert to one of the previous intervals } -export const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; - // helper functions const transposePitches = (pitches: number[], interval: number) => { let transposed = []; @@ -23,55 +32,6 @@ const transposePitches = (pitches: number[], interval: number) => { return transposed; } -export const extractPitchset = (pitches: string[]) => { - // 1) determine pitch set from given array of pitches - let pitchset: number[] = []; - - for (let each of pitches) { - // filters numbers from above tones - const str = each; - const regex = /[0-9]/g; - const withoutNums = str.replace(regex, ''); - const pitchNumber = musicalPitches.indexOf(withoutNums); - - // ... so that they may be mapped onto numbers corresponding to the chromatic scale - pitchset.push(pitchNumber); - } - - // these are sorted from lowest to highest index (something like an interval vector) - pitchset.sort((a,b) => a - b); - return pitchset; -} - -export const findVector = (pitches: number[]) => { - let sorted = pitches.sort((x,y) => x - y); - // sorted = sorted.filter((num, idx) => { - // return sorted.indexOf(num) === idx; - // }); - - // finds each interval and logs it as a duple - let intervalClasses: number[] = []; - for (let i = 0; i < sorted.length; i++) { - let j = i+1; - - // does not allow out of range values in the proceeding loop - if (j >= sorted.length) { - break; - } - - do { - let thing: number = (sorted[j] - sorted[i]) % 6 - if (!(intervalClasses.includes(thing))) { - intervalClasses.push(thing); - } - j++; - } while (j < sorted.length); - } - - intervalClasses = intervalClasses.sort((x,y) => x-y); - return intervalClasses; -} - export const labelIntervals = (vector: number[]): [number, IntervalDef][] => { let result: [number, IntervalDef][] = []; @@ -82,12 +42,6 @@ export const labelIntervals = (vector: number[]): [number, IntervalDef][] => { return result; } -// analysis -let dMajor = extractPitchset(["D", "F#", "A", "D"]); -const eMajor = transposePitches(dMajor, 2); -console.log(eMajor); -console.log(''); - /** * sample uses of these functions detailed below: * diff --git a/src/styleUtils.ts b/src/styleUtils.ts index 94e17bb..8231e4c 100644 --- a/src/styleUtils.ts +++ b/src/styleUtils.ts @@ -1,4 +1,4 @@ -import * as Tone from "tone"; +import * as Tone from 'tone'; export const startButton = document.getElementById("start-tone"); export const synthButton = document.getElementById("synth-button"); diff --git a/src/toneGeneration.ts b/src/toneGeneration.ts deleted file mode 100644 index 94959b3..0000000 --- a/src/toneGeneration.ts +++ /dev/null @@ -1,22 +0,0 @@ -// we start with a selection of pitches that generally work okay together -const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; -const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; -const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; -const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; - -export const pitchsets: string[][] = [sopranoTones, altoTones, tenorTones, bassTones]; - -/** - * now we define some rules to allow for the program to follow so it can some basic tenets of music theory - * we include all pitches, so that it can use semitone-based pitch logic focused on base-12 - * - * some basic rules: - * no tritones - * no minor 2nds or major 7ths -*/ - -export const evaluateVector = (vector: number[]): boolean => ((vector.includes(1) || vector.includes(6))); - -export const rejectDissonance = (vector: number[]) => { - -} diff --git a/src/vector_logic/evaluateVector.ts b/src/vector_logic/evaluateVector.ts new file mode 100644 index 0000000..3f11878 --- /dev/null +++ b/src/vector_logic/evaluateVector.ts @@ -0,0 +1,7 @@ +export const evaluateVector = (vector: number[]): boolean => { + return ((vector.includes(1) || vector.includes(6))); +} + +export const rejectDissonance = (vector: number[]) => { + return; +} \ No newline at end of file diff --git a/src/vector_logic/extractPitchset.ts b/src/vector_logic/extractPitchset.ts new file mode 100644 index 0000000..946a7e9 --- /dev/null +++ b/src/vector_logic/extractPitchset.ts @@ -0,0 +1,21 @@ +import { musicalPitches } from "../harmonyUtil"; + +export const extractPitchset = (pitches: string[]) => { + // 1) determine pitch set from given array of pitches + let pitchset: number[] = []; + + for (let each of pitches) { + // filters numbers from above tones + const str = each; + const regex = /[0-9]/g; + const withoutNums = str.replace(regex, ''); + const pitchNumber = musicalPitches.indexOf(withoutNums); + + // ... so that they may be mapped onto numbers corresponding to the chromatic scale + pitchset.push(pitchNumber); + } + + // these are sorted from lowest to highest index (something like an interval vector) + pitchset.sort((a,b) => a - b); + return pitchset; +} \ No newline at end of file diff --git a/src/vector_logic/findVector.ts b/src/vector_logic/findVector.ts new file mode 100644 index 0000000..2989244 --- /dev/null +++ b/src/vector_logic/findVector.ts @@ -0,0 +1,28 @@ +export const findVector = (pitches: number[]) => { + let sorted = pitches.sort((x,y) => x - y); + // sorted = sorted.filter((num, idx) => { + // return sorted.indexOf(num) === idx; + // }); + + // finds each interval and logs it as a duple + let intervalClasses: number[] = []; + for (let i = 0; i < sorted.length; i++) { + let j = i+1; + + // does not allow out of range values in the proceeding loop + if (j >= sorted.length) { + break; + } + + do { + let thing: number = (sorted[j] - sorted[i]) % 6 + if (!(intervalClasses.includes(thing))) { + intervalClasses.push(thing); + } + j++; + } while (j < sorted.length); + } + + intervalClasses = intervalClasses.sort((x,y) => x-y); + return intervalClasses; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b7b0f55..494906a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,8 @@ "outDir": "./built", "allowJs": true, "target": "es2017", - "moduleResolution": "node" + "module": "CommonJS", + "moduleResolution": "node", }, - "include": ["./src/**/*"] + "include": ["./src/**/*", "./app"] } \ No newline at end of file -- 2.49.1 From e28b2176eeb4918f71b801b4196e333120bb5f4e Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Wed, 11 May 2022 11:22:57 -0500 Subject: [PATCH 09/16] builds successfully, still messy around module import. bandaid fix --- .DS_Store | Bin 0 -> 6148 bytes app.ts | 8 ++++++-- index.html | 7 +++++++ src/styleUtils.ts | 3 +-- src/vector_logic/extractPitchset.ts | 2 +- tsconfig.json | 11 ++++++++--- 6 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3e391de0f729d619dabea1aac629bcd83153700f GIT binary patch literal 6148 zcmeHKyG{c^3>-s>NTf(fxxc_4tfKG*`G8O)q6rrX6zZ$^EAYi)7o2gx1*ci{^@MX*7=m@2@Q-+V z-@Oi}^YEPaU%x5vab1>=e=-D3_9~cC+cUwb&*MdzgFN2OO6(D literal 0 HcmV?d00001 diff --git a/app.ts b/app.ts index 6bfcda9..4cd4655 100644 --- a/app.ts +++ b/app.ts @@ -1,9 +1,11 @@ -import * as Tone from 'tone'; - // initialize four synth voices +// @ts-expect-error: namespace, Tone, for all of the following "expect-error calls" const soprano = new Tone.Synth().toDestination(); +// @ts-expect-error const alto = new Tone.Synth().toDestination(); +// @ts-expect-error const tenor = new Tone.Synth().toDestination(); +// @ts-expect-error const bass = new Tone.Synth().toDestination(); // test function for audio is armed @@ -26,6 +28,7 @@ export const soundChord = (pitches: string[]) => { // set up transport const transportStart = document.getElementById('transport-start'); +// @ts-expect-error const loop = new Tone.Loop((time) => { audioTest(); }, "8n").start(0); @@ -33,5 +36,6 @@ const loop = new Tone.Loop((time) => { loop.probability = 0.8; transportStart.onclick = () => { + // @ts-expect-error Tone.Transport.start(); } diff --git a/index.html b/index.html index bdfb6df..7388fb8 100644 --- a/index.html +++ b/index.html @@ -119,5 +119,12 @@ + + + + + + + \ No newline at end of file diff --git a/src/styleUtils.ts b/src/styleUtils.ts index 8231e4c..7f47476 100644 --- a/src/styleUtils.ts +++ b/src/styleUtils.ts @@ -1,5 +1,3 @@ -import * as Tone from 'tone'; - export const startButton = document.getElementById("start-tone"); export const synthButton = document.getElementById("synth-button"); @@ -26,6 +24,7 @@ showMore.onclick = () => { } startButton.onclick = async () => { + // @ts-expect-error - namespace again, failed import from Tone await Tone.start() .then(() => { appReady = true; diff --git a/src/vector_logic/extractPitchset.ts b/src/vector_logic/extractPitchset.ts index 946a7e9..4c63b80 100644 --- a/src/vector_logic/extractPitchset.ts +++ b/src/vector_logic/extractPitchset.ts @@ -1,4 +1,4 @@ -import { musicalPitches } from "../harmonyUtil"; +import { musicalPitches } from "../harmonyUtil.js"; export const extractPitchset = (pitches: string[]) => { // 1) determine pitch set from given array of pitches diff --git a/tsconfig.json b/tsconfig.json index 494906a..0de2996 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,9 +2,14 @@ "compilerOptions": { "outDir": "./built", "allowJs": true, - "target": "es2017", - "module": "CommonJS", + "target": "es2018", + "module": "ESNext", "moduleResolution": "node", }, - "include": ["./src/**/*", "./app"] + "include": [ + "./src/**/*", "./app" + ], + "exclude": [ + "/_tone" + ] } \ No newline at end of file -- 2.49.1 From e25324aec24e52c650e25e3d56ad44c9731456f8 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Wed, 11 May 2022 12:35:58 -0500 Subject: [PATCH 10/16] several problems to solve -- project structure better defined --- index.html | 1 + src/audioUtils.ts | 40 +++++++++--------------- src/harmonyUtil.ts | 46 ++++++++++++++++------------ src/inputHandling.ts | 5 ++- src/vector_logic/evaluateVector.ts | 18 +++++++++-- src/vector_logic/extractPitchset.ts | 2 +- src/vector_logic/findVector.ts | 4 +-- src/vector_logic/numbersToPitches.ts | 5 +++ 8 files changed, 69 insertions(+), 52 deletions(-) create mode 100644 src/vector_logic/numbersToPitches.ts diff --git a/index.html b/index.html index 7388fb8..931ca61 100644 --- a/index.html +++ b/index.html @@ -112,6 +112,7 @@ + diff --git a/src/audioUtils.ts b/src/audioUtils.ts index 568098e..6e75b36 100644 --- a/src/audioUtils.ts +++ b/src/audioUtils.ts @@ -1,38 +1,28 @@ import { soundChord } from '../app.js'; -import { pitchsets } from "./harmonyUtil.js"; +import { getRandomPitches } from "./harmonyUtil.js"; -import { evaluateVector } from "./vector_logic/evaluateVector.js"; +import { evaluateVector, rejectDissonance } from "./vector_logic/evaluateVector.js"; import { findVector } from "./vector_logic/findVector.js"; import { extractPitchset } from "./vector_logic/extractPitchset.js"; export const fullRandomChord = () => { - let pitches: string[]; - for (let voice of pitchsets) { - // finds a random index, excluding any which may already exist in the array - let index: number; - - do { - if (!pitches) pitches = []; - index = Math.floor(Math.random() * 100) % voice.length; - } while (pitches.includes(voice[index]) ?? false); - - pitches ? pitches.push(voice[index]) : pitches = [voice[index]]; - console.log(voice[index]); - } - - for (let i = 0; i < pitches.length; i++) { - if (pitches[i] === pitches[i+1]) { - console.log("CAUGHT"); - } - } - + let pitches: string[] = getRandomPitches(); soundChord(pitches); + let pitchValues: number[] = extractPitchset(pitches); pitchValues = findVector(pitchValues); let evaluated = evaluateVector(pitchValues); - - console.log(pitches); - console.log(evaluated); return evaluated; +} + +export const evaluatedChord = () => { + let pitches: string[] = getRandomPitches(); + let pitchNums: number[] = extractPitchset(pitches); + let firstVector = findVector(pitchNums); + let finalVector = rejectDissonance(firstVector); + + if (finalVector !== firstVector) console.log('caught'); + + soundChord(pitches); } \ No newline at end of file diff --git a/src/harmonyUtil.ts b/src/harmonyUtil.ts index 5ba32df..1642599 100644 --- a/src/harmonyUtil.ts +++ b/src/harmonyUtil.ts @@ -32,6 +32,7 @@ const transposePitches = (pitches: number[], interval: number) => { return transposed; } +// quality-of-life tool for debugging export const labelIntervals = (vector: number[]): [number, IntervalDef][] => { let result: [number, IntervalDef][] = []; @@ -42,23 +43,28 @@ export const labelIntervals = (vector: number[]): [number, IntervalDef][] => { return result; } -/** - * sample uses of these functions detailed below: - * - * @var dMajVector = @function findVector(dMajor); - * @param dMajor number[] ( result of earlier call to @function extractPitchset ) - * ... @returns [0,3,4,5] - * this indicates this pitchset contains a unison, a minor third, a major third, - * and a perfect fourth (or a corresponding inversion) - * - * @var complexVector = @function findVector([0,3,4,7,8,11]); - * @returns [1,2,3,4,5] - * - * @var splitThird = @function findVector([0,3,4,7]); - * @returns [1,3,4] - * - * @function labelIntervals - * @param vector = number[] corresponding to sorted vector - * references @interface IntervalDef to select from @constant IntervalDefNames - * @returns an array of duples, each containing a number and an entry from IntervalDef - */ +// iterates through each voice's pitchset, and selects a random pitch from each +export const getRandomPitches = (): string[] => { + let pitches: string[]; + for (let voice of pitchsets) { + // will store a random index + let index: number; + + const regex = /[0-9]/g; + + // repeat this iteration until it returns a number not already included in the list + do { + if (!pitches) pitches = []; + + index = Math.floor(Math.random() * 100) % voice.length; + + console.log(`${voice[0]}: ${index}`); + } while (pitches.includes(voice[index])); + + // if pitches is not already initialized to an empty array, do so; otherwise, push the received value + pitches ? pitches.push(voice[index]) : pitches = [voice[index]]; + console.log(voice[index]); + } + + return pitches; +} diff --git a/src/inputHandling.ts b/src/inputHandling.ts index 6b31b0b..0aa4e7c 100644 --- a/src/inputHandling.ts +++ b/src/inputHandling.ts @@ -1,5 +1,5 @@ import { audioTest } from '../app.js'; -import { fullRandomChord } from './audioUtils.js'; +import { evaluatedChord, fullRandomChord } from './audioUtils.js'; // slider variables referring to DOM export const sopranoVol = document.getElementById('soprano-vol'); @@ -73,3 +73,6 @@ synthButton.onclick = audioTest; const randChord = document.getElementById('rand-chord'); randChord.onclick = fullRandomChord; + +const evalChord = document.getElementById('eval-chord'); +evalChord.onclick = evaluatedChord; diff --git a/src/vector_logic/evaluateVector.ts b/src/vector_logic/evaluateVector.ts index 3f11878..7c10385 100644 --- a/src/vector_logic/evaluateVector.ts +++ b/src/vector_logic/evaluateVector.ts @@ -1,7 +1,21 @@ +import { getRandomPitches } from "../harmonyUtil.js"; +import { extractPitchset } from "./extractPitchset.js"; +import { findVector } from "./findVector.js"; + export const evaluateVector = (vector: number[]): boolean => { return ((vector.includes(1) || vector.includes(6))); } -export const rejectDissonance = (vector: number[]) => { - return; +export const rejectDissonance = (pitchset: number[]) => { + const vector = findVector(pitchset); + + // returns the pitchset and its vector if evaluateVector returns true, + if (evaluateVector(vector)) return vector; + + // and recursively calls the function otherwise. + if (!evaluateVector(vector)) { + let newPitches: string[] = getRandomPitches(); + let newPitchset: number[] = extractPitchset(newPitches); + rejectDissonance(newPitchset); + }; } \ No newline at end of file diff --git a/src/vector_logic/extractPitchset.ts b/src/vector_logic/extractPitchset.ts index 4c63b80..aed92b1 100644 --- a/src/vector_logic/extractPitchset.ts +++ b/src/vector_logic/extractPitchset.ts @@ -1,6 +1,6 @@ import { musicalPitches } from "../harmonyUtil.js"; -export const extractPitchset = (pitches: string[]) => { +export const extractPitchset = (pitches: string[]): number[] => { // 1) determine pitch set from given array of pitches let pitchset: number[] = []; diff --git a/src/vector_logic/findVector.ts b/src/vector_logic/findVector.ts index 2989244..bdd8109 100644 --- a/src/vector_logic/findVector.ts +++ b/src/vector_logic/findVector.ts @@ -1,8 +1,5 @@ export const findVector = (pitches: number[]) => { let sorted = pitches.sort((x,y) => x - y); - // sorted = sorted.filter((num, idx) => { - // return sorted.indexOf(num) === idx; - // }); // finds each interval and logs it as a duple let intervalClasses: number[] = []; @@ -24,5 +21,6 @@ export const findVector = (pitches: number[]) => { } intervalClasses = intervalClasses.sort((x,y) => x-y); + return intervalClasses; } \ No newline at end of file diff --git a/src/vector_logic/numbersToPitches.ts b/src/vector_logic/numbersToPitches.ts new file mode 100644 index 0000000..2be75b7 --- /dev/null +++ b/src/vector_logic/numbersToPitches.ts @@ -0,0 +1,5 @@ +export const vectorToPitches = (vector: number[]): string[] => { + + + return ['']; +} \ No newline at end of file -- 2.49.1 From 0106e80b5825c2409200ad79ec9f6b06d69e20bb Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Wed, 11 May 2022 12:42:04 -0500 Subject: [PATCH 11/16] working on gh pages issue --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 474ae86..e56ccc5 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "typescript": "^4.6.4" }, "devDependencies": { - "@types/node": "^17.0.32" + "@types/node": "^17.0.32", + "tone": "^14.7.77", + "typescript": "^4.6.4" } } -- 2.49.1 From abbb3c606876e05e5a406e7f715aacefe17b0733 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Thu, 12 May 2022 11:13:34 -0500 Subject: [PATCH 12/16] restoring to vanilla js --- app.js | 19 +++------ index.html | 14 ++++-- js/harmonyUtil.js | 64 ---------------------------- js/toneGeneration.js | 35 --------------- src/audioUtil.js | 10 +++++ src/harmonyUtil.js | 46 ++++++++++++++++++++ {js => src}/inputHandling.js | 0 {js => src}/styleUtils.js | 0 src/vector_logic/evaluateVector.js | 0 src/vector_logic/extractPitchset.js | 22 ++++++++++ src/vector_logic/findVector.js | 26 +++++++++++ src/vector_logic/numbersToPitches.js | 0 12 files changed, 119 insertions(+), 117 deletions(-) delete mode 100644 js/harmonyUtil.js delete mode 100644 js/toneGeneration.js create mode 100644 src/audioUtil.js create mode 100644 src/harmonyUtil.js rename {js => src}/inputHandling.js (100%) rename {js => src}/styleUtils.js (100%) create mode 100644 src/vector_logic/evaluateVector.js create mode 100644 src/vector_logic/extractPitchset.js create mode 100644 src/vector_logic/findVector.js create mode 100644 src/vector_logic/numbersToPitches.js diff --git a/app.js b/app.js index 75cf0c8..7ceae65 100644 --- a/app.js +++ b/app.js @@ -1,9 +1,5 @@ -import { - sopranoTones, altoTones, tenorTones, bassTones, - extractPitchset, -} from "./js/toneGeneration.js"; - -const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; +import { pitchsets } from "./src/harmonyUtil.js"; +import { extractPitchset } from "./src/vector_logic/extractPitchset.js"; // initialize four synth voices const soprano = new Tone.Synth().toDestination(); @@ -20,8 +16,9 @@ export const audioTest = () => { } // allows a chord to be generated with input from another function -export const soundChord = (pitches) => { - const [s,a,t,b] = pitches; +// pitchNames: array of strings +export const soundChord = (pitchNames) => { + const [s,a,t,b] = pitchNames; soprano.triggerAttackRelease(s, "8n"); alto.triggerAttackRelease(a, "8n"); tenor.triggerAttackRelease(t, "8n"); @@ -54,13 +51,8 @@ export const fullRandomChord = () => { } // set up transport -let clock = 0; -let slowClock = 0; - const transportStart = document.getElementById('transport-start'); -let transport; - const loop = new Tone.Loop((time) => { audioTest(); }, "8n").start(0); @@ -70,4 +62,3 @@ loop.probability = 0.8; transportStart.onclick = () => { Tone.Transport.start(); } - diff --git a/index.html b/index.html index bb9cd11..50c49fb 100644 --- a/index.html +++ b/index.html @@ -118,9 +118,15 @@ - - - - + + + + + + + + + + \ No newline at end of file diff --git a/js/harmonyUtil.js b/js/harmonyUtil.js deleted file mode 100644 index f433593..0000000 --- a/js/harmonyUtil.js +++ /dev/null @@ -1,64 +0,0 @@ -import { extractPitchset } from "./toneGeneration.js"; - -// interval definitions: -const intervals = { - 0: "unison", - 1: "minor second", - 2: "major second", - 3: "minor third", - 4: "major third", - 5: "perfect fourth", - 6: "tritone" - // all intervals beyond this invert to one of the previous intervals -} - -// helper functions -const transposePitches = (pitchNames, interval) => { - let transposed = []; - pitchNames.forEach(pitch => transposed.push((pitch + interval) % 12)); - return transposed; -} - -const findVector = (pitches) => { - let sorted = pitches.sort((x,y) => x - y); - // sorted = sorted.filter((num, idx) => { - // return sorted.indexOf(num) === idx; - // }); - - // finds each interval and logs it as a duple - let intervalClasses = []; - for (let i = 0; i < sorted.length; i++) { - let j = i+1; - - // does not allow out of range values in the proceeding loop - if (j >= sorted.length) { - break; - } - - do { - let thing = (sorted[j] - sorted[i]) % 6 - if (!(intervalClasses.includes(thing))) { - intervalClasses.push(thing); - } - j++; - } while (j < sorted.length); - } - - intervalClasses = intervalClasses.sort((x,y) => x-y); - return intervalClasses; -} - -// analysis -let dMajor = extractPitchset(["D", "F#", "A", "D"]); -const eMajor = transposePitches(dMajor, 2); -console.log(eMajor); -console.log(''); - -let dMajVector = findVector(dMajor); -console.log(dMajVector); - -let complexVector = findVector([0,3,4,7,8,11]); -console.log(complexVector); - -let splitThird = findVector([0,3,4,7]); -console.log(splitThird); diff --git a/js/toneGeneration.js b/js/toneGeneration.js deleted file mode 100644 index 9787eaf..0000000 --- a/js/toneGeneration.js +++ /dev/null @@ -1,35 +0,0 @@ -// we start with a selection of pitches that generally work okay together -export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; -export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; -export const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; -export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; - -// now we define some rules to allow for the program to follow so it can some basic tenets of music theory -// we're going to include all pitches, so that it can use semitone-based pitch logic. -// this is focused on base-12, something computers understand quite well -const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; - -export const extractPitchset = (pitches) => { - // 1) determine pitch set from given array of pitches - let pitchset = []; - - for (let each of pitches) { - // filters numbers from above tones - const str = each; - const regex = /[0-9]/g; - const withoutNums = str.replace(regex, ''); - const pitchNumber = musicalPitches.indexOf(withoutNums); - - // ... so that they may be mapped onto numbers corresponding to the chromatic scale - pitchset.push(pitchNumber); - } - - // these are sorted from lowest to highest index (something like an interval vector) - pitchset.sort((a,b) => a < b); - console.log(pitchset); - - return pitchset; -} - -// no tritones -// no minor 2nds or major 7ths \ No newline at end of file diff --git a/src/audioUtil.js b/src/audioUtil.js new file mode 100644 index 0000000..c88de0c --- /dev/null +++ b/src/audioUtil.js @@ -0,0 +1,10 @@ +import { soundChord } from "../app.js"; +import { getRandomPitches } from "./harmonyUtil.js"; + +// initial test: generate a single, random chord +export const fullRandomChord = () => { + let pitches = getRandomPitches(); + + soundChord(pitches); + extractPitchset(pitches); +} \ No newline at end of file diff --git a/src/harmonyUtil.js b/src/harmonyUtil.js new file mode 100644 index 0000000..6a72c77 --- /dev/null +++ b/src/harmonyUtil.js @@ -0,0 +1,46 @@ +import { extractPitchset } from "./vector_logic/extractPitchset.js"; + +export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; +export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; +export const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; +export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; + +export const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; + +export const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; + +// interval definitions: +export const intervalNames = { + 0: "unison", + 1: "minor second", + 2: "major second", + 3: "minor third", + 4: "major third", + 5: "perfect fourth", + 6: "tritone" + // all intervals beyond this invert to one of the previous intervals +} + +// helper functions +const transposePitches = (pitchNames, interval) => { + let transposed = []; + pitchNames.forEach(pitch => transposed.push((pitch + interval) % 12)); + return transposed; +} + +export const getRandomPitches = () => { + // pitches stored in Tone.js string format + let pitches = []; + for (let voice of pitchsets) { + // finds a random index, excluding any which may already exist in the array + let index; + + do { + index = Math.floor(Math.random() * 100) % voice.length; + } while (pitches.includes(voice[index])); + + pitches.push(voice[index]); + } + + return pitches; +} diff --git a/js/inputHandling.js b/src/inputHandling.js similarity index 100% rename from js/inputHandling.js rename to src/inputHandling.js diff --git a/js/styleUtils.js b/src/styleUtils.js similarity index 100% rename from js/styleUtils.js rename to src/styleUtils.js diff --git a/src/vector_logic/evaluateVector.js b/src/vector_logic/evaluateVector.js new file mode 100644 index 0000000..e69de29 diff --git a/src/vector_logic/extractPitchset.js b/src/vector_logic/extractPitchset.js new file mode 100644 index 0000000..33b74a8 --- /dev/null +++ b/src/vector_logic/extractPitchset.js @@ -0,0 +1,22 @@ +import { musicalPitches } from '../harmonyUtil.js'; + +// converts pitches in Tone.js string format to base-12 number pitchsets +export const extractPitchset = (pitches) => { + // 1) determine pitch set from given array of pitches + let pitchset = []; + + for (let each of pitches) { + // filters numbers from above tones + const str = each; + const regex = /[0-9]/g; + const withoutNums = str.replace(regex, ''); + const pitchNumber = musicalPitches.indexOf(withoutNums); + + // ... so that they may be mapped onto numbers corresponding to the chromatic scale + pitchset.push(pitchNumber); + } + + // these are sorted from lowest to highest index (something like an interval vector) + pitchset.sort((a,b) => a < b); + return pitchset; +} \ No newline at end of file diff --git a/src/vector_logic/findVector.js b/src/vector_logic/findVector.js new file mode 100644 index 0000000..2457b00 --- /dev/null +++ b/src/vector_logic/findVector.js @@ -0,0 +1,26 @@ +// takes pitches as numbers and converts them to a vector +export const findVector = (pitches) => { + let sorted = pitches.sort((x,y) => x - y); + + // finds each interval and logs it as a duple + let intervalClasses = []; + for (let i = 0; i < sorted.length; i++) { + let j = i+1; + + // does not allow out of range values in the proceeding loop + if (j >= sorted.length) { + break; + } + + do { + let thing = (sorted[j] - sorted[i]) % 6 + if (!(intervalClasses.includes(thing))) { + intervalClasses.push(thing); + } + j++; + } while (j < sorted.length); + } + + intervalClasses = intervalClasses.sort((x,y) => x-y); + return intervalClasses; +} diff --git a/src/vector_logic/numbersToPitches.js b/src/vector_logic/numbersToPitches.js new file mode 100644 index 0000000..e69de29 -- 2.49.1 From 65ce76411c231831afc2ad22807e1073506aaf59 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Thu, 12 May 2022 12:11:53 -0500 Subject: [PATCH 13/16] random chord method checks for distinct members --- app.js | 25 ------------------------- index.html | 1 + src/audioUtil.js | 6 ++++-- src/harmonyUtil.js | 22 +++++++++++++++++----- src/helper.js | 30 ++++++++++++++++++++++++++++++ src/inputHandling.js | 3 ++- src/vector_logic/evaluateVector.js | 21 +++++++++++++++++++++ 7 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 src/helper.js diff --git a/app.js b/app.js index 7ceae65..bbb610c 100644 --- a/app.js +++ b/app.js @@ -25,31 +25,6 @@ export const soundChord = (pitchNames) => { bass.triggerAttackRelease(b, "8n"); } -// initial test: generate a single, random chord -export const fullRandomChord = () => { - let pitches = []; - for (let voice of pitchsets) { - // finds a random index, excluding any which may already exist in the array - let index; - - do { - index = Math.floor(Math.random() * 100) % voice.length; - } while (pitches.includes(voice[index])); - - pitches.push(voice[index]); - console.log(voice[index]); - } - - for (let i = 0; i < pitches.length; i++) { - if (pitches[i] === pitches[i+1]) { - console.log("CAUGHT"); - } - } - - soundChord(pitches); - extractPitchset(pitches); -} - // set up transport const transportStart = document.getElementById('transport-start'); diff --git a/index.html b/index.html index 50c49fb..3a9dfbe 100644 --- a/index.html +++ b/index.html @@ -112,6 +112,7 @@ + diff --git a/src/audioUtil.js b/src/audioUtil.js index c88de0c..fb97911 100644 --- a/src/audioUtil.js +++ b/src/audioUtil.js @@ -1,10 +1,12 @@ import { soundChord } from "../app.js"; import { getRandomPitches } from "./harmonyUtil.js"; +import { extractPitchset } from "./vector_logic/extractPitchset.js"; // initial test: generate a single, random chord export const fullRandomChord = () => { let pitches = getRandomPitches(); - soundChord(pitches); - extractPitchset(pitches); + let pitchset = extractPitchset(pitches); + + return pitchset; } \ No newline at end of file diff --git a/src/harmonyUtil.js b/src/harmonyUtil.js index 6a72c77..eca3e0d 100644 --- a/src/harmonyUtil.js +++ b/src/harmonyUtil.js @@ -31,16 +31,28 @@ const transposePitches = (pitchNames, interval) => { export const getRandomPitches = () => { // pitches stored in Tone.js string format let pitches = []; + let formattedPitches = []; + for (let voice of pitchsets) { // finds a random index, excluding any which may already exist in the array let index; - - do { - index = Math.floor(Math.random() * 100) % voice.length; - } while (pitches.includes(voice[index])); + const regex = /[A-Gb#]/g; + let pitch; + let formattedPitch; - pitches.push(voice[index]); + // loops until four distinct chord members are received + while (formattedPitches.length < 4) { + index = Math.floor(Math.random() * 100) % voice.length; + pitch = voice[index]; + formattedPitch = pitch.match(regex).join(''); + if (!formattedPitches.includes(formattedPitch)) { + formattedPitches.push(formattedPitch); + pitches.push(pitch); + } + } } + console.log(formattedPitches); + console.log(pitches); return pitches; } diff --git a/src/helper.js b/src/helper.js new file mode 100644 index 0000000..f7a7b7e --- /dev/null +++ b/src/helper.js @@ -0,0 +1,30 @@ +import { pitchsets } from "./harmonyUtil.js"; + +let index; +let pitch; +let formattedPitch = 'caught'; +let regex = /[A-Gb#]/g; + +let pitches = []; +let formattedPitches = []; + +// index = Math.floor(Math.random() * 100) % pitchsets[0].length; + +// const toParse = pitchsets[0][index]; +// const parsed = toParse.match(regex).join(''); +// console.log(parsed); + +for (let voice of pitchsets) { + while (formattedPitches.length < 4) { + index = Math.floor(Math.random() * 100) % voice.length; + pitch = voice[index]; + formattedPitch = pitch.match(regex).join(''); + if (!formattedPitches.includes(formattedPitch)) { + formattedPitches.push(formattedPitch); + pitches.push(pitch); + } + } +} + +console.log(formattedPitches) +console.log(pitches); \ No newline at end of file diff --git a/src/inputHandling.js b/src/inputHandling.js index cb4ff7f..3effa91 100644 --- a/src/inputHandling.js +++ b/src/inputHandling.js @@ -1,4 +1,5 @@ -import { audioTest, fullRandomChord } from '../app.js'; +import { audioTest } from '../app.js'; +import { fullRandomChord } from './audioUtil.js'; // slider variables referring to DOM export const sopranoVol = document.getElementById('soprano-vol'); diff --git a/src/vector_logic/evaluateVector.js b/src/vector_logic/evaluateVector.js index e69de29..035c4b2 100644 --- a/src/vector_logic/evaluateVector.js +++ b/src/vector_logic/evaluateVector.js @@ -0,0 +1,21 @@ +import { getRandomPitches } from "../harmonyUtil.js"; +import { extractPitchset } from "./extractPitchset.js"; +import { findVector } from "./findVector.js"; + +export const evaluateVector = (vector) => { + return ((vector.includes(1) || vector.includes(6))); +} + +export const rejectDissonance = (pitchset) => { + const vector = findVector(pitchset); + + // returns the pitchset and its vector if evaluateVector returns true, + if (evaluateVector(vector)) return vector; + + // and recursively calls the function otherwise. + if (!evaluateVector(vector)) { + let newPitches = getRandomPitches(); + let newPitchset = extractPitchset(newPitches); + rejectDissonance(newPitchset); + }; +} \ No newline at end of file -- 2.49.1 From 998b0fb5be74f2e5bab9d7275917a964b591b5d3 Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Thu, 12 May 2022 12:26:22 -0500 Subject: [PATCH 14/16] separation of concerns --- src/audioUtil.js | 4 ++++ src/harmonyUtil.js | 21 ++++++++++++++++--- src/helper.js | 30 ---------------------------- src/inputHandling.js | 5 ++++- src/vector_logic/extractPitchName.js | 2 ++ src/vector_logic/extractPitchset.js | 4 ++-- 6 files changed, 30 insertions(+), 36 deletions(-) delete mode 100644 src/helper.js create mode 100644 src/vector_logic/extractPitchName.js diff --git a/src/audioUtil.js b/src/audioUtil.js index fb97911..97feba5 100644 --- a/src/audioUtil.js +++ b/src/audioUtil.js @@ -9,4 +9,8 @@ export const fullRandomChord = () => { let pitchset = extractPitchset(pitches); return pitchset; +} + +export const evaluatedChord = () => { + return fullRandomChord(); } \ No newline at end of file diff --git a/src/harmonyUtil.js b/src/harmonyUtil.js index eca3e0d..bd01f6b 100644 --- a/src/harmonyUtil.js +++ b/src/harmonyUtil.js @@ -1,4 +1,6 @@ import { extractPitchset } from "./vector_logic/extractPitchset.js"; +import { evaluateVector } from "./vector_logic/evaluateVector.js"; +import { extractPitchName } from "./vector_logic/extractPitchName.js"; export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; @@ -36,15 +38,15 @@ export const getRandomPitches = () => { for (let voice of pitchsets) { // finds a random index, excluding any which may already exist in the array let index; - const regex = /[A-Gb#]/g; let pitch; let formattedPitch; // loops until four distinct chord members are received - while (formattedPitches.length < 4) { + while (formattedPitches.length <= pitchsets.indexOf(voice)) { index = Math.floor(Math.random() * 100) % voice.length; pitch = voice[index]; - formattedPitch = pitch.match(regex).join(''); + + formattedPitch = extractPitchName(pitch); if (!formattedPitches.includes(formattedPitch)) { formattedPitches.push(formattedPitch); pitches.push(pitch); @@ -56,3 +58,16 @@ export const getRandomPitches = () => { console.log(pitches); return pitches; } + +// an additional method based on the structure of the method above, +// but taking principles of music theory into account. +export const getProceduralPitches = () => { + let pitches = []; + let formattedPitches = []; + + for (let voice of pitchsets) { + let index; + let pitch; + let formattedPitch; + } +} diff --git a/src/helper.js b/src/helper.js deleted file mode 100644 index f7a7b7e..0000000 --- a/src/helper.js +++ /dev/null @@ -1,30 +0,0 @@ -import { pitchsets } from "./harmonyUtil.js"; - -let index; -let pitch; -let formattedPitch = 'caught'; -let regex = /[A-Gb#]/g; - -let pitches = []; -let formattedPitches = []; - -// index = Math.floor(Math.random() * 100) % pitchsets[0].length; - -// const toParse = pitchsets[0][index]; -// const parsed = toParse.match(regex).join(''); -// console.log(parsed); - -for (let voice of pitchsets) { - while (formattedPitches.length < 4) { - index = Math.floor(Math.random() * 100) % voice.length; - pitch = voice[index]; - formattedPitch = pitch.match(regex).join(''); - if (!formattedPitches.includes(formattedPitch)) { - formattedPitches.push(formattedPitch); - pitches.push(pitch); - } - } -} - -console.log(formattedPitches) -console.log(pitches); \ No newline at end of file diff --git a/src/inputHandling.js b/src/inputHandling.js index 3effa91..d2dfaff 100644 --- a/src/inputHandling.js +++ b/src/inputHandling.js @@ -1,5 +1,5 @@ import { audioTest } from '../app.js'; -import { fullRandomChord } from './audioUtil.js'; +import { fullRandomChord, evaluatedChord } from './audioUtil.js'; // slider variables referring to DOM export const sopranoVol = document.getElementById('soprano-vol'); @@ -65,3 +65,6 @@ synthButton.onclick = audioTest; const randChord = document.getElementById('rand-chord'); randChord.onclick = fullRandomChord; + +const evalChord = document.getElementById('eval-chord'); +evalChord.onclick = evaluatedChord; diff --git a/src/vector_logic/extractPitchName.js b/src/vector_logic/extractPitchName.js new file mode 100644 index 0000000..016d63a --- /dev/null +++ b/src/vector_logic/extractPitchName.js @@ -0,0 +1,2 @@ +const regex = /[A-Gb#]/g; +export const extractPitchName = (tonePitchName) => tonePitchName.match(regex).join(''); diff --git a/src/vector_logic/extractPitchset.js b/src/vector_logic/extractPitchset.js index 33b74a8..62c9b1e 100644 --- a/src/vector_logic/extractPitchset.js +++ b/src/vector_logic/extractPitchset.js @@ -1,4 +1,5 @@ import { musicalPitches } from '../harmonyUtil.js'; +import { extractPitchName } from './extractPitchName.js'; // converts pitches in Tone.js string format to base-12 number pitchsets export const extractPitchset = (pitches) => { @@ -8,8 +9,7 @@ export const extractPitchset = (pitches) => { for (let each of pitches) { // filters numbers from above tones const str = each; - const regex = /[0-9]/g; - const withoutNums = str.replace(regex, ''); + const withoutNums = extractPitchName(str); const pitchNumber = musicalPitches.indexOf(withoutNums); // ... so that they may be mapped onto numbers corresponding to the chromatic scale -- 2.49.1 From 4b9fbdfa3663df975a76ef71b6078aa9e07b151d Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Thu, 12 May 2022 13:19:39 -0500 Subject: [PATCH 15/16] repairs to file system --- app.js | 3 -- index.html | 5 --- src/audioUtil.js | 11 ++++-- src/harmonyUtil.js | 48 +----------------------- src/vector_logic/evaluateVector.js | 2 +- src/vector_logic/getProceduralPitches.js | 34 +++++++++++++++++ src/vector_logic/getRandomPitches.js | 29 ++++++++++++++ 7 files changed, 73 insertions(+), 59 deletions(-) create mode 100644 src/vector_logic/getProceduralPitches.js create mode 100644 src/vector_logic/getRandomPitches.js diff --git a/app.js b/app.js index bbb610c..aab2115 100644 --- a/app.js +++ b/app.js @@ -1,6 +1,3 @@ -import { pitchsets } from "./src/harmonyUtil.js"; -import { extractPitchset } from "./src/vector_logic/extractPitchset.js"; - // initialize four synth voices const soprano = new Tone.Synth().toDestination(); const alto = new Tone.Synth().toDestination(); diff --git a/index.html b/index.html index 3a9dfbe..09e22de 100644 --- a/index.html +++ b/index.html @@ -124,10 +124,5 @@ - - - - - \ No newline at end of file diff --git a/src/audioUtil.js b/src/audioUtil.js index 97feba5..39c74c4 100644 --- a/src/audioUtil.js +++ b/src/audioUtil.js @@ -1,6 +1,7 @@ import { soundChord } from "../app.js"; -import { getRandomPitches } from "./harmonyUtil.js"; +import { getRandomPitches } from "./vector_logic/getRandomPitches.js"; import { extractPitchset } from "./vector_logic/extractPitchset.js"; +import { getProceduralPitches } from "./vector_logic/getProceduralPitches.js"; // initial test: generate a single, random chord export const fullRandomChord = () => { @@ -11,6 +12,10 @@ export const fullRandomChord = () => { return pitchset; } -export const evaluatedChord = () => { - return fullRandomChord(); +export const evaluatedChord = (prevPitches = ["C3", "G3", "C4", "G4"]) => { + let pitches = getProceduralPitches(prevPitches); + soundChord(pitches); + let pitchset = extractPitchset(pitches); + + return pitchset; } \ No newline at end of file diff --git a/src/harmonyUtil.js b/src/harmonyUtil.js index bd01f6b..696320b 100644 --- a/src/harmonyUtil.js +++ b/src/harmonyUtil.js @@ -1,13 +1,9 @@ -import { extractPitchset } from "./vector_logic/extractPitchset.js"; -import { evaluateVector } from "./vector_logic/evaluateVector.js"; -import { extractPitchName } from "./vector_logic/extractPitchName.js"; - export const sopranoTones = ["B5", "A5", "G5", "F#5", "F5", "E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4"]; export const altoTones = ["E5", "D5", "C5", "B4", "Bb4", "A4", "G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3"]; export const tenorTones = ["G4", "F#4", "F4", "E4", "D4", "C4", "B3", "Bb3", "A3", "G3", "F3", "E3", "D3", "C3"]; export const bassTones = ["C2", "D2", "E2", "F2", "G2", "A2", "Bb2", "B2", "C3", "D3", "E3", "F3", "G3"]; -export const pitchsets = [sopranoTones, altoTones, tenorTones, bassTones]; +export const pitchsets = [bassTones, tenorTones, altoTones, sopranoTones]; export const musicalPitches = ['A', "Bb", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; @@ -29,45 +25,3 @@ const transposePitches = (pitchNames, interval) => { pitchNames.forEach(pitch => transposed.push((pitch + interval) % 12)); return transposed; } - -export const getRandomPitches = () => { - // pitches stored in Tone.js string format - let pitches = []; - let formattedPitches = []; - - for (let voice of pitchsets) { - // finds a random index, excluding any which may already exist in the array - let index; - let pitch; - let formattedPitch; - - // loops until four distinct chord members are received - while (formattedPitches.length <= pitchsets.indexOf(voice)) { - index = Math.floor(Math.random() * 100) % voice.length; - pitch = voice[index]; - - formattedPitch = extractPitchName(pitch); - if (!formattedPitches.includes(formattedPitch)) { - formattedPitches.push(formattedPitch); - pitches.push(pitch); - } - } - } - - console.log(formattedPitches); - console.log(pitches); - return pitches; -} - -// an additional method based on the structure of the method above, -// but taking principles of music theory into account. -export const getProceduralPitches = () => { - let pitches = []; - let formattedPitches = []; - - for (let voice of pitchsets) { - let index; - let pitch; - let formattedPitch; - } -} diff --git a/src/vector_logic/evaluateVector.js b/src/vector_logic/evaluateVector.js index 035c4b2..db32ff6 100644 --- a/src/vector_logic/evaluateVector.js +++ b/src/vector_logic/evaluateVector.js @@ -1,4 +1,4 @@ -import { getRandomPitches } from "../harmonyUtil.js"; +import { getRandomPitches } from './getRandomPitches.js'; import { extractPitchset } from "./extractPitchset.js"; import { findVector } from "./findVector.js"; diff --git a/src/vector_logic/getProceduralPitches.js b/src/vector_logic/getProceduralPitches.js new file mode 100644 index 0000000..0a542f1 --- /dev/null +++ b/src/vector_logic/getProceduralPitches.js @@ -0,0 +1,34 @@ +import { pitchsets } from "../harmonyUtil.js"; +import { extractPitchName } from "./extractPitchName.js"; + +// an additional method based on the structure of getRandomPitches, +// but taking some principles of music theory into account. +export const getProceduralPitches = (prevPitches) => { + // prevPitches is passed in to ensure there is no linear dissonance within voices + let pitches = []; + let formattedPitches = []; + + for (let voice of pitchsets) { + let index; + let formattedPitch; + + while (pitches.length <= pitchsets.indexOf(voice)) { + // the first section of this while loop is more free. + index = Math.floor(Math.random() * 100) % voice.length; + formattedPitch = extractPitchName(voice[index]); + + // this initial condition will apply only to the bass voice, + if (!pitches.length) { + pitches.push(voice[index]); + } else { + // now we need some repeating logic for the remaining four voices + while (pitches.length !== (pitchsets.indexOf(voice) + 1)) { + pitches.push(pitchsets.indexOf(voice)); + } + } + } + } + + console.log(pitches); + return pitches; +} diff --git a/src/vector_logic/getRandomPitches.js b/src/vector_logic/getRandomPitches.js new file mode 100644 index 0000000..a041b44 --- /dev/null +++ b/src/vector_logic/getRandomPitches.js @@ -0,0 +1,29 @@ +import { pitchsets } from "../harmonyUtil.js"; +import { extractPitchName } from "./extractPitchName.js"; + +export const getRandomPitches = () => { + // pitches stored in Tone.js string format + let pitches = []; + let formattedPitches = []; + + for (let voice of pitchsets) { + // finds a random index, excluding any which may already exist in the array + let index; + let formattedPitch; + + // loops until four distinct chord members are received + while (formattedPitches.length <= pitchsets.indexOf(voice)) { + index = Math.floor(Math.random() * 100) % voice.length; + + formattedPitch = extractPitchName(voice[index]); + if (!formattedPitches.includes(formattedPitch)) { + formattedPitches.push(formattedPitch); + pitches.push(voice[index]); + } + } + } + + console.log(formattedPitches); + console.log(pitches); + return pitches; +} -- 2.49.1 From fa8a12128ba24bcbc77c9327ee37142fb3de815f Mon Sep 17 00:00:00 2001 From: Mikayla Dobson <93477693+innocuous-symmetry@users.noreply.github.com> Date: Thu, 12 May 2022 14:32:51 -0500 Subject: [PATCH 16/16] working on procedural gen --- src/vector_logic/getProceduralPitches.js | 26 +++++++- src/vector_logic/getRandomPitches.js | 5 +- src/vector_logic/helper.js | 80 ++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 src/vector_logic/helper.js diff --git a/src/vector_logic/getProceduralPitches.js b/src/vector_logic/getProceduralPitches.js index 0a542f1..bd9c5e6 100644 --- a/src/vector_logic/getProceduralPitches.js +++ b/src/vector_logic/getProceduralPitches.js @@ -1,5 +1,6 @@ -import { pitchsets } from "../harmonyUtil.js"; +import { pitchsets, musicalPitches } from "../harmonyUtil.js"; import { extractPitchName } from "./extractPitchName.js"; +import { getRandomIndex } from "./getRandomPitches.js"; // an additional method based on the structure of getRandomPitches, // but taking some principles of music theory into account. @@ -14,7 +15,7 @@ export const getProceduralPitches = (prevPitches) => { while (pitches.length <= pitchsets.indexOf(voice)) { // the first section of this while loop is more free. - index = Math.floor(Math.random() * 100) % voice.length; + index = getRandomIndex(voice); formattedPitch = extractPitchName(voice[index]); // this initial condition will apply only to the bass voice, @@ -23,7 +24,26 @@ export const getProceduralPitches = (prevPitches) => { } else { // now we need some repeating logic for the remaining four voices while (pitches.length !== (pitchsets.indexOf(voice) + 1)) { - pitches.push(pitchsets.indexOf(voice)); + index = getRandomIndex(voice); + pitches.push(voice[index]); + + + for (let i = 0; i < pitches.length; i++) { + let numVals = []; + + for (let j = i; j < i + 2; j++) { + console.log(pitches[j]); + let extracted = extractPitchName(pitches[j]); + numVals.push(musicalPitches.indexOf(extracted) + 1); + } + + let difference = Math.abs(numVals.reduce((x,y) => x - y)); + if (difference === 1 || difference === 6) { + pitches.pop(); + } else { + continue; + } + } } } } diff --git a/src/vector_logic/getRandomPitches.js b/src/vector_logic/getRandomPitches.js index a041b44..fb31de6 100644 --- a/src/vector_logic/getRandomPitches.js +++ b/src/vector_logic/getRandomPitches.js @@ -1,6 +1,9 @@ import { pitchsets } from "../harmonyUtil.js"; import { extractPitchName } from "./extractPitchName.js"; +// helper function for assigning a random index for a given voice's pitchset +export const getRandomIndex = (voice) => Math.floor(Math.random() * 100) % voice.length; + export const getRandomPitches = () => { // pitches stored in Tone.js string format let pitches = []; @@ -13,7 +16,7 @@ export const getRandomPitches = () => { // loops until four distinct chord members are received while (formattedPitches.length <= pitchsets.indexOf(voice)) { - index = Math.floor(Math.random() * 100) % voice.length; + index = getRandomIndex(voice); formattedPitch = extractPitchName(voice[index]); if (!formattedPitches.includes(formattedPitch)) { diff --git a/src/vector_logic/helper.js b/src/vector_logic/helper.js new file mode 100644 index 0000000..77fd2d9 --- /dev/null +++ b/src/vector_logic/helper.js @@ -0,0 +1,80 @@ +import { pitchsets, musicalPitches } from '../harmonyUtil.js'; +import { extractPitchName } from './extractPitchName.js'; +import { getRandomIndex } from './getRandomPitches.js'; + +const iteratePitchsets = () => { + let pitches = []; + let result = []; + + const tryNewPitch = () => { + result = []; + + for (let voice of pitchsets) { + let idx = getRandomIndex(voice); + let pitchNum = musicalPitches.indexOf(extractPitchName(voice[idx])); + + pitches.push([pitchNum, voice[idx]]); + } + + console.log(pitches); + + for (let i = 0; i < pitches.length; i++) { + for (let j = i; j < pitches.length; j++) { + let difference = Math.abs(pitches[i][0] - pitches[j][0]); + if (difference === 1 || difference === 6) { + result.push(["BAD", [i, j], pitches[i], pitches[j]]); + } else { + result.push(["GOOD", [i, j], pitches[i], pitches[j]]); + } + } + } + console.log(result); + } + + tryNewPitch(); + + for (let entry in result) { + if (entry[0] === "BAD") { + iteratePitchsets(); + } + } + + console.log(pitches); +} + +iteratePitchsets(); + + + +function twoPointIteration() { + let caught = false; + let data = [1,2,3,4,5,6]; + + for (let i = 0; i < data.length; i++) { + console.log(data[i]); + for (let j = 0; j < data.length; j++) { + if (data[i] === data[j]) continue; + + let difference = Math.abs(data[j] - data[i]); + + if (difference === 3) { + difference = "caught: 3"; + } + + console.log([difference, [data[i], data[j]]]); + } + + console.log('next'); + } + + return caught; +} + +function selfReferentialPointer() { + for (let i = 0; i < 5; i++) { + console.log(`i: ${i}`); + for (let j = i; j < i+2; j++) { + console.log(`jjjjjjj: ${j % 3}`); + } + } +} -- 2.49.1