diff --git a/.gitignore b/.gitignore index 9b964d3..a7944aa 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,6 @@ pnpm-debug.log* lerna-debug.log* # Editor directories and files -.vscode/* .idea *.suo *.ntvs* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..78be5f0 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "svelte.svelte-vscode", + "bradlc.vscode-tailwindcss" + ] +} \ No newline at end of file diff --git a/src/lib/device/metronome/MetronomeBeats.svelte b/src/lib/device/metronome/MetronomeBeats.svelte index 97b3a21..442c27e 100644 --- a/src/lib/device/metronome/MetronomeBeats.svelte +++ b/src/lib/device/metronome/MetronomeBeats.svelte @@ -1,26 +1,21 @@
{#each new Array(beatPerBar) as _, i} {#if i === 0} diff --git a/src/lib/device/metronome/MetronomeOptions.svelte b/src/lib/device/metronome/MetronomeOptions.svelte index 6130b77..04ffb53 100644 --- a/src/lib/device/metronome/MetronomeOptions.svelte +++ b/src/lib/device/metronome/MetronomeOptions.svelte @@ -3,14 +3,19 @@ import { getMetronomeContext } from './context'; const metronome = getMetronomeContext(); - export let bpm = metronome.bpm; - export let beatPerBar = metronome.beatPerBar; + export let bpm = metronome.timer.bpm; + export let beatPerBar = metronome.timer.beatPerBar; + + metronome.timer.onTempoChanged((state) => { + bpm = state.bpm; + beatPerBar = state.beatPerBar; + }); let lastTapTimestamp = -1; let tapIntervalStore: number[] = []; - $: metronome.bpm = bpm; - $: metronome.beatPerBar = beatPerBar; + $: metronome.timer.bpm = bpm; + $: metronome.timer.beatPerBar = beatPerBar;
diff --git a/src/lib/device/metronome/MetronomePlayButton.svelte b/src/lib/device/metronome/MetronomePlayButton.svelte index dc7af10..6003405 100644 --- a/src/lib/device/metronome/MetronomePlayButton.svelte +++ b/src/lib/device/metronome/MetronomePlayButton.svelte @@ -1,17 +1,30 @@
- + +
diff --git a/src/routes/tools/render-sample/+layout.svelte b/src/routes/tools/render-sample/+layout.svelte deleted file mode 100644 index f84bd4f..0000000 --- a/src/routes/tools/render-sample/+layout.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - diff --git a/src/routes/tools/render-sample/+page.svelte b/src/routes/tools/render-sample/+page.svelte deleted file mode 100644 index 7f2fbe0..0000000 --- a/src/routes/tools/render-sample/+page.svelte +++ /dev/null @@ -1,152 +0,0 @@ - - -
-
-
-
- - -
-
-
- - - -
-
-
diff --git a/src/routes/tools/render-sample/data.ts b/src/routes/tools/render-sample/data.ts deleted file mode 100644 index 002816d..0000000 --- a/src/routes/tools/render-sample/data.ts +++ /dev/null @@ -1,325 +0,0 @@ -import type { Practice } from '$/lib/practice/types'; -import { TUNE } from '$/utils/music/pitch'; - -const practices: Record = { - // root: { - // tempo: { - // bpm: 120, - // beatPerBar: 6, - // signatureUnit: 8 - // }, - // guitar: { - // tuning: TUNE.standard, - // fretRange: { - // start: 0, - // end: 12, - // visibility: 'end' - // } - // }, - // scores: [ - // { - // notes: [ - // { position: { fret: 'open', line: 6 }, time: { start: 0, duration: 1 / 8 } }, - // { position: { fret: 7, line: 5 }, time: { start: 1 / 8, duration: 1 / 8 } }, - // { position: { fret: 2, line: 4 }, time: { start: 2 / 8, duration: 1 / 8 } }, - // { position: { fret: 9, line: 3 }, time: { start: 3 / 8, duration: 1 / 8 } }, - // { position: { fret: 5, line: 2 }, time: { start: 4 / 8, duration: 1 / 8 } }, - // { position: { fret: 'open', line: 1 }, time: { start: 5 / 8, duration: 1 / 8 } } - // ], - // boards: [ - // { - // title: 'E', - // fingers: [0, 1, 2, 3, 4, 5], - // time: { start: 0 } - // } - // ] - // }, - // { - // notes: [ - // { position: { fret: 1, line: 6 }, time: { start: 0, duration: 1 / 8 } }, - // { position: { fret: 8, line: 5 }, time: { start: 1 / 8, duration: 1 / 8 } }, - // { position: { fret: 3, line: 4 }, time: { start: 2 / 8, duration: 1 / 8 } }, - // { position: { fret: 10, line: 3 }, time: { start: 3 / 8, duration: 1 / 8 } }, - // { position: { fret: 6, line: 2 }, time: { start: 4 / 8, duration: 1 / 8 } }, - // { position: { fret: 1, line: 1 }, time: { start: 5 / 8, duration: 1 / 8 } } - // ], - // boards: [ - // { - // title: 'E', - // fingers: [0, 1, 2, 3, 4, 5], - // time: { start: 0, duration: 6 / 8 } - // } - // ] - // } - // ] - // }, - 'major-scale': { - tempo: { - bpm: 120, - beatPerBar: 4, - signatureUnit: 4 - }, - guitar: { - tuning: TUNE.standard - }, - scores: [ - { - positions: [ - { line: 6, fret: 8 }, - { line: 6, fret: 10 }, - { line: 5, fret: 7 }, - { line: 5, fret: 8 }, - { line: 5, fret: 10 }, - { line: 4, fret: 7 }, - { line: 4, fret: 9 }, - { line: 4, fret: 10 }, - { line: 3, fret: 7 }, - { line: 3, fret: 9 }, - { line: 3, fret: 10 }, - { line: 2, fret: 8 }, - { line: 2, fret: 10 }, - { line: 1, fret: 7 }, - { line: 1, fret: 8 }, - { line: 1, fret: 10 }, - { line: 6, fret: 7 } - ], - notes: [ - { position: 0, time: { start: 0, duration: 0.0625 } }, - { position: 1, time: { start: 0.0625, duration: 0.0625 } }, - { position: 2, time: { start: 0.125, duration: 0.0625 } }, - { position: 3, time: { start: 0.1875, duration: 0.0625 } }, - { position: 4, time: { start: 0.25, duration: 0.0625 } }, - { position: 5, time: { start: 0.3125, duration: 0.0625 } }, - { position: 6, time: { start: 0.375, duration: 0.0625 } }, - { position: 7, time: { start: 0.4375, duration: 0.0625 } }, - { position: 8, time: { start: 0.5, duration: 0.0625 } }, - { position: 9, time: { start: 0.5625, duration: 0.0625 } }, - { position: 10, time: { start: 0.625, duration: 0.0625 } }, - { position: 11, time: { start: 0.6875, duration: 0.0625 } }, - { position: 12, time: { start: 0.75, duration: 0.0625 } }, - { position: 13, time: { start: 0.8125, duration: 0.0625 } }, - { position: 14, time: { start: 0.875, duration: 0.0625 } }, - { position: 15, time: { start: 0.9375, duration: 0.0625 } }, - { position: 14, time: { start: 1, duration: 0.0625 } }, - { position: 13, time: { start: 1.0625, duration: 0.0625 } }, - { position: 12, time: { start: 1.125, duration: 0.0625 } }, - { position: 11, time: { start: 1.1875, duration: 0.0625 } }, - { position: 10, time: { start: 1.25, duration: 0.0625 } }, - { position: 9, time: { start: 1.3125, duration: 0.0625 } }, - { position: 8, time: { start: 1.375, duration: 0.0625 } }, - { position: 7, time: { start: 1.4375, duration: 0.0625 } }, - { position: 6, time: { start: 1.5, duration: 0.0625 } }, - { position: 5, time: { start: 1.5625, duration: 0.0625 } }, - { position: 4, time: { start: 1.625, duration: 0.0625 } }, - { position: 3, time: { start: 1.6875, duration: 0.0625 } }, - { position: 2, time: { start: 1.75, duration: 0.0625 } }, - { position: 1, time: { start: 1.8125, duration: 0.0625 } }, - { position: 0, time: { start: 1.875, duration: 0.0625 } }, - { position: 16, time: { start: 1.9375, duration: 0.0625 } }, - { position: 0, time: { start: 2, duration: 0.0625 } } - ], - boards: [ - { - title: 'C line 1', - fingers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - time: { start: 0 } - }, - { - title: 'C line 2', - fingers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], - time: { start: 15 / 16 } - } - ], - fretRange: { - start: 5, - end: 11, - visibility: 'all' - } - } - ] - }, - 'rhythm-test': { - tempo: { - bpm: 120, - beatPerBar: 4, - signatureUnit: 4 - }, - guitar: { - tuning: TUNE.standard - }, - scores: [ - { - positions: [ - { line: 5, fret: 3 }, - { line: 6, fret: 3 }, - { line: 1, fret: 'open' }, - { line: 2, fret: 1 }, - { line: 3, fret: 'open' } - ], - notes: [ - { position: 0, time: { start: 0, duration: 1 / 4 } }, - { position: 2, time: { start: 1 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 1 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 1 / 4, duration: 1 / 4 } }, - { position: 1, time: { start: 2 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 3 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 3 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 3 / 4, duration: 1 / 4 } }, - { position: 0, time: { start: 4 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 5 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 5 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 5 / 4, duration: 1 / 4 } }, - { position: 1, time: { start: 6 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 7 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 7 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 7 / 4, duration: 1 / 4 } }, - { position: 0, time: { start: 8 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 9 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 9 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 9 / 4, duration: 1 / 4 } }, - { position: 1, time: { start: 10 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 11 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 11 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 11 / 4, duration: 1 / 4 } }, - { position: 0, time: { start: 12 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 13 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 13 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 13 / 4, duration: 1 / 4 } }, - { position: 1, time: { start: 14 / 4, duration: 1 / 4 } }, - { position: 2, time: { start: 15 / 4, duration: 1 / 4 } }, - { position: 3, time: { start: 15 / 4, duration: 1 / 4 } }, - { position: 4, time: { start: 15 / 4, duration: 1 / 4 } } - ], - boards: [ - { - title: 'C line 1', - fingers: [0, 2, 3, 4], - time: { start: 0 } - }, - { - title: 'C line 1', - fingers: [1, 2, 3, 4], - time: { start: 1 / 2 } - }, - { - title: 'C line 1', - fingers: [0, 2, 3, 4], - time: { start: 2 / 2 } - }, - { - title: 'C line 1', - fingers: [1, 2, 3, 4], - time: { start: 3 / 2 } - }, - { - title: 'C line 1', - fingers: [0, 2, 3, 4], - time: { start: 4 / 2 } - }, - { - title: 'C line 1', - fingers: [1, 2, 3, 4], - time: { start: 5 / 2 } - }, - { - title: 'C line 1', - fingers: [0, 2, 3, 4], - time: { start: 6 / 2 } - }, - { - title: 'C line 1', - fingers: [1, 2, 3, 4], - time: { start: 7 / 2 } - } - ], - fretRange: { - start: 0, - end: 12, - visibility: 'all' - } - } - ] - } -}; - -export const practice: Practice = practices['rhythm-test']; - -export const items = [ - { - title: 'E', - fingers: [ - { position: { fret: 'open', line: 6 }, text: 'E' }, - { position: { fret: 7, line: 5 }, text: 'E' }, - { position: { fret: 2, line: 4 }, text: 'E' }, - { position: { fret: 9, line: 3 }, text: 'E' }, - { position: { fret: 5, line: 2 }, text: 'E' }, - { position: { fret: 'open', line: 1 }, text: 'E' } - ] - }, - { - title: 'F', - fingers: [ - { position: { fret: 1, line: 6 } }, - { position: { fret: 1, line: 1 } }, - { position: { fret: 3, line: 4 } }, - { position: { fret: 6, line: 2 } }, - { position: { fret: 8, line: 5 } }, - { position: { fret: 10, line: 3 } } - ] - }, - { - title: 'G', - fingers: [ - { position: { fret: 3, line: 6 } }, - { position: { fret: 5, line: 4 } }, - { position: { fret: 8, line: 2 } }, - { position: { fret: 10, line: 5 } }, - { position: { fret: 'open', line: 3 } }, - { position: { fret: 3, line: 1 } } - ] - }, - { - title: 'A', - fingers: [ - { position: { fret: 5, line: 6 } }, - { position: { fret: 7, line: 4 } }, - { position: { fret: 10, line: 2 } }, - { position: { fret: 'open', line: 5 } }, - { position: { fret: 2, line: 3 } }, - { position: { fret: 5, line: 1 } } - ] - }, - { - title: 'B', - fingers: [ - { position: { fret: 2, line: 5 } }, - { position: { fret: 4, line: 3 } }, - { position: { fret: 7, line: 1 } }, - { position: { fret: 7, line: 6 } }, - { position: { fret: 9, line: 4 } }, - { position: { fret: 'open', line: 2 } } - ] - }, - { - title: 'C', - fingers: [ - { position: { fret: 3, line: 5 } }, - { position: { fret: 5, line: 3 } }, - { position: { fret: 8, line: 1 } }, - { position: { fret: 8, line: 6 } }, - { position: { fret: 10, line: 4 } }, - { position: { fret: 1, line: 2 } } - ] - }, - { - title: 'D', - fingers: [ - { position: { fret: 'open', line: 4 } }, - { position: { fret: 2, line: 2 } }, - { position: { fret: 5, line: 5 } }, - { position: { fret: 7, line: 3 } }, - { position: { fret: 10, line: 1 } }, - { position: { fret: 10, line: 6 } } - ] - } -]; diff --git a/src/utils/multimap.ts b/src/utils/multimap.ts new file mode 100644 index 0000000..e50d4bb --- /dev/null +++ b/src/utils/multimap.ts @@ -0,0 +1,60 @@ +export class MultiMap extends Map { + clear(): void { + super.clear(); + } + delete(key: K): boolean { + return super.delete(key); + } + getAll(key: K): V[] | undefined { + return super.get(key); + } + getFirst(key: K): V | undefined { + const values = super.get(key); + return values ? values[0] : undefined; + } + has(key: K): boolean { + return super.has(key); + } + set(key: K, value: V): this { + let values = super.get(key); + if (values === undefined) { + values = []; + super.set(key, values); + } + values.push(value); + return this; + } + *[Symbol.iterator](): IterableIterator<[K, V]> { + for (const [k, values] of super[Symbol.iterator]()) { + for (const v of values) { + yield [k, v]; + } + } + } + *keys(): IterableIterator { + for (const k of super.keys()) { + yield k; + } + } + *values(): IterableIterator { + for (const values of super.values()) { + for (const v of values) { + yield v; + } + } + } + *entries(): IterableIterator<[K, V[]]> { + for (const [k, values] of super[Symbol.iterator]()) { + for (const v of values) { + yield [k, v]; + } + } + } + forEach(callbackfn: (value: V, key: K, map: Map) => void, thisArg?: any): void { + super.forEach((k, values, map) => { + values.forEach((v: V) => { + callbackfn(v, k, map); + }); + }, thisArg); + } +}