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 @@
-
-
-
+
+
+