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