Skip to content

Commit

Permalink
♻️ Fix even more typing and bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
superbuggy committed Nov 5, 2024
1 parent 7b2b462 commit aaa2c26
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 117 deletions.
3 changes: 1 addition & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script setup>
<script setup lang="ts">
import { RouterView } from "vue-router";
</script>

<template>
<h1>microtab</h1>
<RouterView />
</template>
92 changes: 55 additions & 37 deletions src/components/FretBoard.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<script setup>
<script setup lang="ts">
import FretBoardControls from "./FretBoardControls.vue";
import PopOver from "./PopOver.vue";
Expand Down Expand Up @@ -44,19 +44,19 @@ const y = VIEWBOX_Y_MAX / 8;
const width = VIEWBOX_X_MAX / 2;
const fretboardHeight = VIEWBOX_Y_MAX / 2;
const popUpX = ref(null);
const popUpY = ref(null);
const popUpNote = ref(null);
const popUpX = ref<number>(NaN);
const popUpY = ref<number>(NaN);
const popUpNote = ref<{pitch: string, } | null>(null);
const SCALE_LENGTH = 25.5;
const stringEnergy = (stringRootFrequency) => 2 * SCALE_LENGTH * stringRootFrequency;
const stringEnergy = (stringRootFrequency: number) => 2 * SCALE_LENGTH * stringRootFrequency;
// Frequency = 1 / 2L * stringEnergy //sqrt(T/m)
// From a note frequency for a string, find the position on the string for that note frequency
const distanceForFrequency = (stringRootFrequency, noteFrequency) =>
const distanceForFrequency = (stringRootFrequency: number, noteFrequency: number) =>
stringEnergy(stringRootFrequency) / (noteFrequency * 2);
const stringY = (stringRootFrequency, noteFrequency) =>
const stringY = (stringRootFrequency: number, noteFrequency: number) =>
// whyyyyy
1.775 *
(fretboardHeight -
Expand All @@ -68,12 +68,12 @@ const stringY = (stringRootFrequency, noteFrequency) =>
fretboardHeight
));
const stringNotes = computed(() => {
const stringNotes = computed((): Record<string, Record<string, any>> => {
const guideLineDivisions = shouldShow12TETFrets.value ? 12 : divisionsPerOctave.value;
const dict = notesDictionaryFor(guideLineDivisions);
const stringRootFrequencies = objectMap(
tuning.value,
(string, pitchName) => dict[pitchName].frequency
(_, pitchName) => dict[pitchName].frequency
);
console.log(stringRootFrequencies);
const notesWithDistances = objectMap(stringRootFrequencies, (string, rootFrequency) =>
Expand All @@ -89,8 +89,6 @@ const stringNotes = computed(() => {
return notesWithDistances;
});
console.log(stringNotes.value);
// Assumes an equal step temperament
const fretDistancesFromNut = (divisions = divisionsPerOctave.value) => {
// TODO: Add True Temperament Mode
Expand All @@ -113,29 +111,29 @@ const reachableFrets = computed(() =>
shouldShow12TETFrets.value ? range(0, 24) : range(startingFret, endingFret.value)
);
const fretDistances = computed(() =>
// TODO: Fix this
//@ts-expect-error - Argument of type '12 | SupportedEDOs' is not assignable to parameter of type 'SupportedEDOs | undefined'.
fretDistancesFromNut(shouldShow12TETFrets.value ? 12 : divisionsPerOctave.value)
);
const fretSpacing = computed(() => fretDistances.value.slice(1));
const fretHeights = computed(() =>
fretSpacing.value.reduce((distances, length, index) => {
distances.push(length - fretDistances.value[index]);
return distances;
}, [])
}, [] as number[])
);
function handleHover(event, note) {
popUpX.value = Number(event.target.attributes.cx.value);
popUpY.value = Number(event.target.attributes.cy.value);
function handleHover(event: Event, note: {pitch: string}) {
const target = event.target as SVGElement;
popUpX.value = Number(target.getAttribute('cx'));
popUpY.value = Number(target.getAttribute('cy'));
popUpNote.value = note;
console.log(popUpX.value);
console.log(popUpY.value);
console.log(popUpNote.value);
}
function resetPopUp() {
popUpNote.value = null;
popUpX.value = null;
popUpY.value = null;
popUpX.value = NaN;
popUpY.value = NaN;
}
const fretDots = computed(() =>
Expand All @@ -153,11 +151,11 @@ const fretDots = computed(() =>
// ? (fretSpacing[fretDot - 1] + fretSpacing[fretDot - 2]) / 2 + y
// : fretSpacing[fretDot - 1] + y
const hue = (degree, upperBound) => (360 * degree) / upperBound;
const hsl = (degree, upperBound, l = 75) =>
const hue = (degree: number, upperBound: number) => (360 * degree) / upperBound;
const hsl = (degree: number, upperBound: number, l = 75) =>
`hsl(${hue(degree, upperBound)}, 100%, ${l}%)`;
const hslForNote = (note, l = 50) => {
const hslForNote = (note: { pitchClassNumber: number }, l = 50) => {
// if (!note) return;
const degree = selectedScale.value.pitchClassNumbers
.map((pitchClassNumber) => pitchClassNumber % selectedScale.value.period)
Expand Down Expand Up @@ -189,8 +187,7 @@ const textOffsetY = fontSize;
12
)};`"
>
{{ noteName }}&nbsp;</span
>
{{ noteName }}&nbsp;</span>
</div>
<div class="svg-container">
<svg
Expand All @@ -216,10 +213,19 @@ const textOffsetY = fontSize;
>
{{ endingFret }}
</text>
<rect :x="x" :y="y" :width="width" :height="fretboardHeight" class="tab" />
<rect
:x="x"
:y="y"
:width="width"
:height="fretboardHeight"
class="tab"
/>

<g class="frets-group">
<g v-for="fret in reachableFrets" :key="fret">
<g
v-for="fret in reachableFrets"
:key="fret"
>
<rect
v-if="divisionsPerOctave === 24 && isOdd(fret + 1)"
:key="fret"
Expand All @@ -231,8 +237,8 @@ const textOffsetY = fontSize;
/>
<line
v-if="fretSpacing[fret]"
class="fret"
:key="fret"
class="fret"
:x1="x"
:y1="fretSpacing[fret] + y"
:x2="x + width"
Expand All @@ -242,8 +248,8 @@ const textOffsetY = fontSize;
<g v-if="shouldShow12TETFrets">
<line
v-for="fret in reachableFrets"
class="tet-12-overlay fret"
:key="fret"
class="tet-12-overlay fret"
:x1="x"
:y1="fretSpacing[fret] + y"
:x2="x + width"
Expand All @@ -263,7 +269,10 @@ const textOffsetY = fontSize;
/>
</g>
<g class="fret-dots-group">
<g v-for="fretDot in fretDots" :key="fretDot">
<g
v-for="fretDot in fretDots"
:key="fretDot"
>
<circle
:cx="
fretDot % (shouldShow12TETFrets ? 12 : divisionsPerOctave) === 0
Expand Down Expand Up @@ -294,28 +303,37 @@ const textOffsetY = fontSize;
</g>
</g>
<g class="fretted-notes-group">
<g v-for="fret in reachableFrets" :key="fret">
<g v-for="(string, index) in Object.keys(stringNotes)" :key="string">
<g
v-for="fret in reachableFrets"
:key="fret"
>
<g
v-for="(string, index) in Object.keys(stringNotes)"
:key="string"
>
<circle
@mouseover="handleHover($event, note)"
@mouseout="resetPopUp"
v-for="{ note, fretNumber, noteY } in stringNotes[string]"
:id="`note-${note.frequency}-hz`"
:key="`${string}-${fretNumber}`"
class="fretted-note active"
:cx="index * stringSpacing + x"
:cy="noteY + y"
:r="Math.min(stringSpacing / 5)"
:fill="hslForNote(note)"
@click="playNote(note.frequency)"
:id="`note-${note.frequency}-hz`"
stroke-width="4"
@mouseover="handleHover($event, note)"
@mouseout="resetPopUp"
@click="playNote(note.frequency)"
>
<title>{{ fretNumber }}</title>
</circle>
</g>
</g>
</g>
<PopOver :x="popUpX" :y="popUpY">
<PopOver
:x="popUpX"
:y="popUpY"
>
<p v-if="popUpNote">Frequency: {{ popUpNote.pitch }}</p>
</PopOver>
</svg>
Expand Down
51 changes: 37 additions & 14 deletions src/components/FretBoardControls.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<section>
<select name="" id="" @input="selectScale($event.target.value)">
<select @input="selectScale(($event.target as HTMLSelectElement).value)">
<option
v-for="scaleName in scaleNames"
:key="scaleName"
Expand All @@ -10,7 +10,7 @@
{{ scaleName }}
</option>
</select>
<select @change="selectNotesPerString($event.target.value)">
<select @change="selectNotesPerString(($event.target as HTMLSelectElement).value)">
<option
v-for="notesPerStringSelection in ['All', 3, 4, 5]"
:key="notesPerStringSelection"
Expand All @@ -24,39 +24,62 @@
}}
</option>
</select>
<input type="number" name="" id="" v-model="startingFromFret" />
<input
id=""
v-model="startingFromFret"
type="number"
name=""
>
</section>
<section>
<button v-if="!isPlayingSequence" @click="playScale">Play Scale</button>
<button v-else @click="stopPlayingScale">Stop Playing</button>
<button
v-if="!isPlayingSequence"
@click="playScale"
>
Play Scale
</button>
<button
v-else
@click="stopPlayingScale"
>
Stop Playing
</button>
<label for="tempo">
<span>{{ tempo }}</span> BPM
<input type="range" min="30" max="180" :value="tempo" @input="changeTempo" />
<input
type="range"
min="30"
max="180"
:value="tempo"
@input="changeTempo"
>
</label>
<label for="loop">
Loop?
<input type="checkbox" v-model="isLooped" />
<input
v-model="isLooped"
type="checkbox"
>
</label>
</section>
<section>
<label for="">
12Tet guides
<input type="checkbox" v-model="shouldShow12TETFrets" />
</label>
<label for="" v-if="shouldShow12TETFrets">
Invert fret colors
<input type="checkbox" v-model="areFretColorsInverted" />
<input
v-model="shouldShow12TETFrets"
type="checkbox"
>
</label>
</section>
</template>

<script setup>
<script setup lang="ts">
import { useGuitar } from "../state/guitar";
import { useTone } from "../effects/tone";
import { useFretBoardControls } from "../state/fretboard-controls";
import { ref } from "vue";
const { shouldShow12TETFrets, areFretColorsInverted } = useFretBoardControls();
const { shouldShow12TETFrets } = useFretBoardControls();
// import * as Tone from "tone";
Expand Down
54 changes: 54 additions & 0 deletions src/components/PitchDetector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script setup lang="ts">
import { PitchDetector } from "pitchy";
import { ref, onMounted } from "vue";
const pitch = ref<number | null>(null);
const clarity = ref<number | null>(null);
const button = ref<HTMLElement | null>(null);
function updatePitch(analyserNode: AnalyserNode, detector: PitchDetector<Float32Array>, input: Float32Array, sampleRate: number) {
analyserNode.getFloatTimeDomainData(input);
const [_pitch, _clarity] = detector.findPitch(input, sampleRate);
// pitchDisplay.value.textContent = `${
pitch.value = Math.round(_pitch * 10) / 10
// } Hz`;
// document.getElementById("clarity").textContent = `${Math.round(
clarity.value= _clarity * 100;
// )} %`;
window.setTimeout(
() => updatePitch(analyserNode, detector, input, sampleRate),
100,
);
}
onMounted(() => {
const audioContext = new window.AudioContext();
const analyserNode = audioContext.createAnalyser();
button.value?.addEventListener("click", () => audioContext.resume());
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
audioContext.createMediaStreamSource(stream).connect(analyserNode);
const detector = PitchDetector.forFloat32Array(analyserNode.fftSize);
detector.minVolumeDecibels = -30;
const input = new Float32Array(detector.inputLength);
updatePitch(analyserNode, detector, input, audioContext.sampleRate);
});
});
</script>
<template>
<div>
<h1>Pitch Detector</h1>
<button ref="button">
listen
</button>
<p>
<strong>Pitch:</strong> {{ pitch }} Hz
</p>
<p>
<strong>Clarity:</strong> {{ clarity }} %
</p>
</div>
</template>
Loading

0 comments on commit aaa2c26

Please sign in to comment.