Skip to content

Commit

Permalink
query string parsing trick
Browse files Browse the repository at this point in the history
  • Loading branch information
marginalhours committed Nov 26, 2023
1 parent 9368f33 commit fd2356a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 25 deletions.
5 changes: 0 additions & 5 deletions src/lib/frettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import { unflatten, type Pitch, type PitchWithFlats, type Quality } from './musi
* pointing at arrays of frettings for that pitch and chord variant.
* This is a massive data entry task but also not that bad. GLHF!
*/

export const getFrettingForChord = ({ tonic, quality }: Chord, index: number = 0): number[] => {
return frettings[unflatten(tonic)][quality][index];
};

export const getFrettingsForChord = ({ tonic, quality }: Chord): number[][] => {
return frettings[unflatten(tonic)][quality];
};
Expand Down
4 changes: 4 additions & 0 deletions src/lib/music/relativeChord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,7 @@ export const parseRelativeChord = (intervalString: string): RelativeChord | null
export const progression = (strings: TemplateStringsArray, ...values: any): RelativeChord[] => {
return strings[0].split(/[\s-]/).map(parseRelativeChord) as RelativeChord[];
};

export const progressionFromString = (string: string): RelativeChord[] => {
return string.split(/[\s-]/).map(parseRelativeChord) as RelativeChord[];
};
59 changes: 49 additions & 10 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
progression,
chords,
randomizeApp,
randomizeTonic,
randomizeProgression,
setTonic,
previousProgression,
nextProgression
Expand All @@ -22,8 +24,21 @@
</script>

<svelte:head>
<title>Ukulele Chord Progression Generator</title>
<meta name="description" content="Ukulele Chord Progression Generator" />
<title>Ukulele Chord Progressions Toy</title>
<meta name="description" content="Ukulele Chord Progressions Toy" />

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@marginalhours" />
<meta name="twitter:creator" content="@marginalhours" />
<meta name="twitter:title" content="Ukulele Chord Progressions Toy" />
<meta name="twitter:description" content="Find your next favourite progression" />
<meta name="twitter:image" content="" />

<meta property="og:url" content="https:/marginalhours.net/ukulele-progressions" />
<meta property="og:type" content="article" />
<meta property="og:title" content="Ukulele Chord Progressions Toy" />
<meta property="og:description" content="Find your next favourite progression" />
<meta property="og:image" content="" />
</svelte:head>

<main>
Expand All @@ -36,7 +51,10 @@
{/each}
</section>
<section class="progression-section">
<h2 class="progression-title">Progression</h2>
<h2 class="progression-title">
progression
<button class="randomize-button" on:click={randomizeProgression}>randomize</button>
</h2>
<div class="progression-section-chords">
<button
on:click={previousProgression}
Expand All @@ -56,7 +74,10 @@
</div>
</section>
<section class="tonic-section">
<h2 class="tonic-title">Key</h2>
<h2 class="tonic-title">
key
<button class="randomize-button" on:click={randomizeTonic}>randomize</button>
</h2>
<div class="tonic-section-tonics">
{#each displayPitches as pitch}
<button
Expand Down Expand Up @@ -107,9 +128,9 @@
.progression-title {
font-weight: bold;
text-transform: lowercase;
margin: 0 auto;
margin-bottom: 1em;
position: relative;
}
.progression-control {
Expand All @@ -132,7 +153,6 @@
.progression-section-chords {
display: flex;
font-weight: medium;
}
.tonic-section {
Expand All @@ -145,9 +165,9 @@
.tonic-title {
font-weight: bold;
text-transform: lowercase;
margin: 0 auto;
margin-bottom: 1em;
position: relative;
}
.tonic-button {
Expand Down Expand Up @@ -179,16 +199,35 @@
}
.control-section {
margin-top: 4em;
margin: 4em 0;
}
.randomize-button {
font-size: x-small;
cursor: pointer;
outline: none;
border: none;
border-radius: 5em;
padding: 0.5em 1em;
background-color: rgba(155, 95, 224, 0.5);
position: absolute;
top: -80%;
}
.randomize-button:hover {
transform: translateY(-1px);
}
.randomize-button:active {
transform: translateY(2px);
}
.random-button {
font-weight: medium;
cursor: pointer;
outline: none;
border: none;
border-radius: 5em;
padding: 0.5em 2em;
padding: 0.5em 1.5em;
background-color: rgba(155, 95, 224, 0.5);
}
Expand Down
66 changes: 58 additions & 8 deletions src/routes/progressionStore.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,48 @@
import { writable, derived } from 'svelte/store';
import { chooseWithout } from '../lib/utilities';
import { progression as $, type RelativeChord } from '../lib/music/relativeChord';
import {
progression as $,
progressionFromString,
type RelativeChord
} from '../lib/music/relativeChord';
import { pitches, type Pitch, type PitchWithFlats, pitchesWithFlats } from '../lib/music/types';
import { intervalToChord } from '../lib/music/chords';
import { getFrettingForChord, getFrettingsForChord } from '../lib/frettings';
import { getFrettingsForChord } from '../lib/frettings';
import { browser } from '$app/environment';

const progressions = [
$`I-vi-IV-V`, // 1950s do-wop
$`vi-IV-I-V`, // 4 chords
$`I-V-vi-IV`, // the other 4 chords
$`I-V-vi-iii-IV-I-IV-V`, // hey pachelbel,
$`ii-V-I-vi`,
$`I-III7-IV-iv`, //
$`I-IIIdim-IV-V7`,
$`III7-vi-iv-I`,
$`i-iv-V7`, // spooky
$`I-III-IV-iv`, // creep
$`I-VI7-II7-V-I`, // circus cadence
$`IV-ii-v-I`, // more minor,
$`v-ii-IV-I`, // ditto but moved around,
$`v-ii-IV-I`, // ditto but moved around
$`i7-IV-bVII-v`,
$`i-V7-i-bVII-bIII-bVII-i`, // La Follia
$`i-iv-bVI-V`
$`i-iv-bVI-V`,
$`i-V7-v7-IV-bVI-bIII-IV-V7`, // hotel california
$`I-Imaj7-I7-IV-V6-VI7-ii-V`
];

// G-G5-D-Adim7(no3)-Adim7-Em-A-D-D75 This sounds good

const tonic = writable<PitchWithFlats>('C');
const progressionIndex = writable<number>(0);

const progression = derived(
[progressionIndex],
([$progressionIndex]) => progressions[$progressionIndex]
);
/**
* Update progression based on index... unless there's a location hash,
* in which case use that.
*/
const progression = derived([progressionIndex], ([$progressionIndex]) => {
return hasProgressionInUrlHash() ? progressionFromURLHash() : progressions[$progressionIndex];
});

const chords = derived([tonic, progression], ([$tonic, $progression]) =>
$progression.map((interval) => intervalToChord($tonic, interval))
Expand All @@ -46,7 +59,16 @@ const setTonic = (newTonic: Pitch) => {
};

const randomizeApp = () => {
randomizeTonic();
randomizeProgression();
};

const randomizeTonic = () => {
tonic.update((current) => chooseWithout(pitchesWithFlats, current));
};

const randomizeProgression = () => {
resetURLHashProgression();
progressionIndex.update((current) =>
chooseWithout(
progressions.map((_, index) => index),
Expand All @@ -56,20 +78,48 @@ const randomizeApp = () => {
};

const previousProgression = () => {
resetURLHashProgression();
progressionIndex.update((current) => (progressions.length + current - 1) % progressions.length);
};

const nextProgression = () => {
resetURLHashProgression();
progressionIndex.update((current) => (progressions.length + current + 1) % progressions.length);
};

// URL hash utilities

const hasProgressionInUrlHash = () => {
if (!(browser && window.location.hash)) {
return false;
}

try {
const _ = $`${window.location.hash.substring(1)}`;
} catch (err) {
return false;
}

return true;
};

const progressionFromURLHash = () => {
return progressionFromString(window.location.hash.substring(1));
};

const resetURLHashProgression = () => {
window.location.hash = '';
};

export {
tonic,
progression,
chords,
frettings,
setTonic,
randomizeApp,
randomizeTonic,
randomizeProgression,
previousProgression,
nextProgression
};
5 changes: 3 additions & 2 deletions svelte.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import adapter from '@sveltejs/adapter-static';
import staticAdapter from '@sveltejs/adapter-static';
import autoAdapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';

/** @type {import('@sveltejs/kit').Config} */
Expand All @@ -8,7 +9,7 @@ const config = {
preprocess: vitePreprocess(),

kit: {
adapter: adapter(),
adapter: process.env.NODE_ENV === 'production' ? staticAdapter() : autoAdapter(),
paths: {
base: process.env.NODE_ENV === 'production' ? '/ukulele-progressions' : ''
}
Expand Down

0 comments on commit fd2356a

Please sign in to comment.