resolving merge conflict

This commit is contained in:
Mikayla Dobson
2022-05-12 14:46:17 -05:00
15 changed files with 338 additions and 81 deletions

6
app.ts
View File

@@ -17,8 +17,9 @@ export const audioTest = () => {
}
// allows a chord to be generated with input from another function
export const soundChord = (pitches: string[]) => {
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");
@@ -28,7 +29,6 @@ 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);

View File

@@ -119,13 +119,10 @@
<!-- Tone.js library -->
<script type="module" src="https://unpkg.com/tone@14.7.77/build/Tone.js"></script>
<!-- internal scripts -->
<script type="module" src="./built/app.js"></script>
<script type="module" src="./built/src/audioUtils.js"></script>
<script type="module" src="./built/src/harmonyUtil.js"></script>
<script type="module" src="./built/src/inputHandling.js"></script>
<script type="module" src="./built/src/styleUtils.js"></script>
<script type="module" src="./built/src/vector_logic/evaluateVector.js"></script>
<script type="module" src="./built/src/vector_logic/extractPitchset.js"></script>
<script type="module" src="./built/src/vector_logic/findVector.js"></script>
<script type="module" src="./src/styleUtils.js"></script>
<script type="module" src="./src/inputHandling.js"></script>
<script type="module" src="./src/harmonyUtil.js"></script>
<script type="module" src="./src/audioUtil.js"></script>
<script type="module" src="./app.js"></script>
</body>
</html>

21
src/audioUtil.js Normal file
View File

@@ -0,0 +1,21 @@
import { soundChord } from "../app.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 = () => {
let pitches = getRandomPitches();
soundChord(pitches);
let pitchset = extractPitchset(pitches);
return pitchset;
}
export const evaluatedChord = (prevPitches = ["C3", "G3", "C4", "G4"]) => {
let pitches = getProceduralPitches(prevPitches);
soundChord(pitches);
let pitchset = extractPitchset(pitches);
return pitchset;
}

27
src/harmonyUtil.js Normal file
View File

@@ -0,0 +1,27 @@
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 = [bassTones, tenorTones, altoTones, sopranoTones];
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;
}

View File

@@ -1,70 +0,0 @@
// 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
}
export const IntervalDefNames = {
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;
}
// quality-of-life tool for debugging
export const labelIntervals = (vector: number[]): [number, IntervalDef][] => {
let result: [number, IntervalDef][] = [];
for (let x of vector) {
result.push([x, IntervalDefNames[x]]);
}
return result;
}
// 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;
}

View File

@@ -1,5 +1,9 @@
import { audioTest } from '../app.js';
<<<<<<< HEAD:src/inputHandling.ts
import { evaluatedChord, fullRandomChord } from './audioUtils.js';
=======
import { fullRandomChord, evaluatedChord } from './audioUtil.js';
>>>>>>> backtrack:src/inputHandling.js
// slider variables referring to DOM
export const sopranoVol = document.getElementById('soprano-vol');

41
src/styleUtils.js Normal file
View File

@@ -0,0 +1,41 @@
export const startButton = document.getElementById("start-tone");
export const synthButton = document.getElementById("synth-button");
export const showStart = document.getElementsByClassName('show-on-start') as HTMLCollectionOf<HTMLElement>;
export const hideStart = document.getElementsByClassName('hide-on-start') as HTMLCollectionOf<HTMLElement>;
export const showMore = document.getElementById('info-button');
export const moreInfo = document.getElementsByClassName('more-info') as HTMLCollectionOf<HTMLElement>;
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 = async () => {
// @ts-expect-error - namespace again, failed import from Tone
await 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";
}
});
}

View File

@@ -0,0 +1,21 @@
import { getRandomPitches } from './getRandomPitches.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);
};
}

View File

@@ -0,0 +1,2 @@
const regex = /[A-Gb#]/g;
export const extractPitchName = (tonePitchName) => tonePitchName.match(regex).join('');

View File

@@ -0,0 +1,22 @@
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) => {
// 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 withoutNums = extractPitchName(str);
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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,54 @@
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.
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 = getRandomIndex(voice);
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)) {
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;
}
}
}
}
}
}
console.log(pitches);
return pitches;
}

View File

@@ -0,0 +1,32 @@
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 = [];
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 = getRandomIndex(voice);
formattedPitch = extractPitchName(voice[index]);
if (!formattedPitches.includes(formattedPitch)) {
formattedPitches.push(formattedPitch);
pitches.push(voice[index]);
}
}
}
console.log(formattedPitches);
console.log(pitches);
return pitches;
}

View File

@@ -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}`);
}
}
}

View File