-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
248 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<script> | ||
import { createEventDispatcher } from "svelte" | ||
import { render_chord } from "../utils/Rendering" | ||
import { Note, Chord } from "../utils/VP" | ||
import Keyboard from "./Piano/Keyboard.svelte" | ||
let dispatch = createEventDispatcher() | ||
let firstNote = undefined | ||
// Stores the chord while it's being edited (not saved yet in case the user wants to cancel) | ||
let tempBuffer = undefined | ||
export let chord = undefined | ||
$: { | ||
if (chord?.notes?.length > 0) { | ||
firstNote = chord.notes[0] | ||
tempBuffer = JSON.parse(JSON.stringify(chord)) | ||
} | ||
} | ||
export let settings = undefined | ||
export let dialog = undefined | ||
let noteToAdd = undefined | ||
let removeNote = (i) => { | ||
if(i.detail) { | ||
// This is now a MIDI note value passed from the Keyboard | ||
i = tempBuffer.notes.findIndex(note => note.original === i.detail) | ||
} | ||
tempBuffer.notes.splice(i, 1) | ||
tempBuffer = new Chord(tempBuffer) // regen for correct sorting | ||
} | ||
let addNote = (event) => { | ||
let clone = JSON.parse(JSON.stringify(firstNote)) | ||
let transposition = clone.value - clone.original | ||
clone.original = event.detail | ||
clone.value = clone.original + transposition | ||
tempBuffer.notes.push(new Note(clone)) | ||
tempBuffer = new Chord(tempBuffer) // regen for correct sorting | ||
} | ||
let applyChanges = () => { | ||
let notes = tempBuffer.notes.map(n => new Note(n)) | ||
let newChord = new Chord(notes) | ||
dispatch('chordChanged', newChord) | ||
} | ||
</script> | ||
<!-- svelte-ignore a11y-click-events-have-key-events --> | ||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> | ||
<dialog bind:this={dialog} on:click|self={() => {dialog.close()}} class="rounded-lg overflow-hidden p-2"> | ||
<div class="flex flex-col items-center gap-2"> | ||
<div id="chord" style="background-color: #2D2A32" class="text-2xl p-1 rounded-md"> | ||
{@html render_chord(tempBuffer, undefined, settings, false)} | ||
</div> | ||
{#if tempBuffer} | ||
<div class="flex flex-col items-center justify-center gap-2"> | ||
<p>Remove a note:</p> | ||
<div class="flex flex-row"> | ||
{#each tempBuffer.notes as note, i} | ||
<div class="w-full"> | ||
<button on:click={() => { removeNote(i) }} | ||
class="text-2xl text-nowrap border-none"> | ||
{note.char ?? '[invalid]'} | ||
</button> | ||
</div> | ||
{/each} | ||
</div> | ||
<p>Toggle a note:</p> | ||
<Keyboard | ||
octaves=7 | ||
keysPressed={tempBuffer.notes.map(note => note.original)} | ||
on:noteon={addNote} | ||
on:noteoff={removeNote}/> | ||
<!-- Don't really need this I suppose? --> | ||
<!-- <div id="buttons"> | ||
<input type="text" class="w-12" bind:value={noteToAdd}> | ||
<button>Add from QWERTY (at {firstNote.transposition} transposition)</button> | ||
</div> --> | ||
<hr class="my-2 mx-1 border-black border-1 w-full"> | ||
<button on:click={() => { dialog.close(); applyChanges() }}>Apply</button> | ||
</div> | ||
{/if} | ||
</div> | ||
</dialog> | ||
<style> | ||
* { | ||
color: black | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<script> | ||
// Credits to https://github.com/danferns/svelte-piano | ||
export let noteNum; | ||
export let keyWidth = 8; | ||
export let pressed = false; | ||
import { createEventDispatcher } from "svelte"; | ||
const dispatch = createEventDispatcher(); | ||
let isNatural = ![1, 3, 6, 8, 10].includes(noteNum % 12); | ||
let bias = 0; | ||
// the accidental keys are not perfectly in center | ||
if (!isNatural) { | ||
if ([1, 6].includes(noteNum % 12)) bias = -keyWidth / 12; | ||
else if ([3, 10].includes(noteNum % 12)) bias = keyWidth / 12; | ||
} | ||
function keyPressed() { | ||
if (pressed) { | ||
dispatch("noteoff", noteNum) | ||
pressed = false | ||
return | ||
} | ||
dispatch("noteon", noteNum); | ||
pressed = true; | ||
} | ||
function keyReleased() { | ||
return | ||
if (!pressed) return; | ||
dispatch("noteoff", noteNum); | ||
pressed = false; | ||
} | ||
</script> | ||
|
||
<!-- svelte-ignore a11y-no-static-element-interactions --> | ||
<div | ||
class:accidental={!isNatural} | ||
class:natural={isNatural} | ||
class:pressed | ||
style="--width: {keyWidth - keyWidth * 0.47 * !isNatural}px; transform: translate({bias}px);" | ||
draggable="false" | ||
on:mousedown|preventDefault={keyPressed} | ||
on:mouseup|preventDefault={keyReleased} | ||
on:mouseenter={(e) => { if (e.buttons) keyPressed(); }} | ||
on:mouseleave={(e) => { if (e.buttons) keyReleased(); }} | ||
on:touchstart|preventDefault={keyPressed} | ||
on:touchend|preventDefault={keyReleased} | ||
/> | ||
|
||
<style> | ||
div { | ||
flex-shrink: 0; | ||
width: var(--width); | ||
min-width: min-content; | ||
border-radius: 0px 0px calc(var(--width) / 8) calc(var(--width) / 8); | ||
-webkit-user-drag: none; | ||
} | ||
.accidental { | ||
margin: 0px calc(var(--width) / -2) 0px calc(var(--width) / -2); | ||
z-index: 2; | ||
height: 60%; | ||
background: black; | ||
box-shadow: inset white 0px 0px 2px 0px; | ||
} | ||
.natural { | ||
height: 100%; | ||
box-shadow: inset black 0px 0px 2px 0px; | ||
} | ||
.accidental.pressed { | ||
background: #ff966d; | ||
} | ||
.natural.pressed { | ||
background: #ff966d; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<script> | ||
// Credits to https://github.com/danferns/svelte-piano | ||
export let octaves = 2; | ||
export let middleC = 60; | ||
export let keysPressed = []; | ||
import Key from "./Key.svelte"; | ||
let keys; | ||
$: keys = [...Array(octaves * 12 + 1).keys()].map( | ||
(i) => i + (middleC - Math.floor(octaves / 2) * 12) | ||
); | ||
</script> | ||
|
||
<div class="keyboard"> | ||
<div> | ||
{#each keys as note} | ||
<Key noteNum={note} on:noteon on:noteoff pressed={keysPressed.includes(note)}/> | ||
{/each} | ||
</div> | ||
</div> | ||
|
||
<style> | ||
.keyboard { | ||
display: flex; | ||
justify-content: center; | ||
} | ||
.keyboard > div { | ||
display: flex; | ||
overflow: auto; | ||
padding: 8px; | ||
height: 48px; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters