Skip to content

Commit

Permalink
Limit instruments. Lines, not dots. Fewer notes.
Browse files Browse the repository at this point in the history
  • Loading branch information
crummy committed Aug 24, 2024
1 parent 9ac4624 commit d136123
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 44 deletions.
48 changes: 27 additions & 21 deletions src/components/Instrument.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
<script lang="ts">
import {
type Instrument, SoundFont,
SplendidGrandPiano
} from "./player.ts";
import {SoundFont} from "./player.ts";
import {Visualization} from "./Visualization.ts";
import {Theremax} from "./Theremax.ts";
import {getSoundfontNames} from "smplr";
let instrument = "SplendidGrandPiano"
let isInitialized = false;
const visualization = new Visualization();
const theremax = new Theremax(visualization)
let soundFonts: string[] = getSoundfontNames();
let soundFonts: string[] = [
"acoustic_grand_piano",
"alto_sax",
"bird_tweet",
"breath_noise",
"cello",
"church_organ",
"electric_bass_pick",
"flute",
"fx_3_crystal",
"fx_4_atmosphere",
"melodic_tom",
"music_box",
"seashore",
"taiko_drum",
"tinkle_bell",
"viola",
"trombone",
"xylophone",
"voice_oohs",
]
let instrument = soundFonts[Math.floor(Math.random() * soundFonts.length)];
function reset() {
theremax.reset();
Expand All @@ -30,19 +45,13 @@
visualization.onDraw((x, y, pointerId) => {
theremax.moveDraw(x, y, pointerId)
const intervals = theremax.getIntervals()
visualization.highlight(x, intervals);
if (intervals) {
visualization.highlightColumn(x, intervals);
}
})
visualization.onNewClick((x, y, pointerId) => {
let inst: Instrument;
switch (instrument) {
case "SplendidGrandPiano":
inst = new SplendidGrandPiano(theremax.context)
break;
default:
inst = new SoundFont(theremax.context, instrument)
break;
}
const inst = new SoundFont(theremax.getContext(), instrument)
theremax.beginDraw(x, y, pointerId, inst)
})
Expand Down Expand Up @@ -106,9 +115,6 @@
{/if}
{#if isInitialized}
<ul class="instruments">
<li class:selectedInstrument={instrument === "SplendidGrandPiano"}>
<button on:click={() => instrument = "SplendidGrandPiano"}>Grand Piano</button>
</li>
{#each soundFonts as font}
<li class:selectedInstrument={instrument === font}>
<button on:click={() => instrument = font}>{font}</button>
Expand Down
41 changes: 29 additions & 12 deletions src/components/Theremax.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Timer} from "./Timer.ts";
import type {Instrument} from "./player.ts";
import {getContext} from "svelte";

interface Instant {
millis: number
Expand Down Expand Up @@ -39,24 +40,34 @@ function lerp(value: number, sourceRangeMin: number, sourceRangeMax: number, tar
export interface TheremaxVisualization {
clearLines(): void

drawPoint(x: number, y: number, recordingId: number): void
createLine(x: number, y: number, recordingId: number): void

getDimensions(): { width: number, height: number }

connectPoints(points: { x: number, y: number}[], recordingId: number): void
}

export class Theremax {
private recordings: Recording[] = []
private timer = new Timer();
private isInitialized = false;
private readonly volume = {min: -40, max: 0}
private readonly volume = {min: -30, max: 100}
private readonly loopTimeMs = 10 * 1000;
readonly context = new AudioContext();
private context: AudioContext | undefined

constructor(private vis: TheremaxVisualization) {
}

getContext() {
if (!this.context) {
this.context = new AudioContext();
}
return this.context
}


async init() {
await this.context.resume()
await this.getContext().resume()
this.isInitialized = true
}

Expand All @@ -75,6 +86,7 @@ export class Theremax {
const millis = this.timer.getElapsedMs();
const recording = new Recording(instrument, x, y, millis, pointerId);
this.recordings.push(recording);
this.vis.createLine(x, y, recording.id)
}

moveDraw(x: number, y: number, pointerId: number) {
Expand Down Expand Up @@ -108,30 +120,35 @@ export class Theremax {
if (!this.isInitialized) {
return
}
if (this.timer.getElapsedMs() > this.loopTimeMs) {
const now = this.timer.getElapsedMs();
if (now > this.loopTimeMs) {
this.timer.reset();
this.vis.clearLines();
for (let recording of this.recordings) {
recording.lastPlayed = undefined;
recording.instrument.stop()
this.vis.createLine(recording.start.x, recording.start.y, recording.id)
}
return
}
const now = this.timer.getElapsedMs();
for (let recording of this.recordings) {
let noteToPlay: { x: number, y: number } | undefined = undefined
let pointsToDraw: { x: number, y: number }[] = []
if (recording.lastPlayed === undefined && recording.start.millis <= now) {
const {x, y} = recording.start
this.playScaled(x, y, recording.instrument);
this.vis.drawPoint(x, y, recording.id);
noteToPlay = recording.start
pointsToDraw.push(recording.start)
recording.lastPlayed = recording.start
}
while (recording.lastPlayed?.next !== undefined && recording.lastPlayed.millis < now) {
const {x, y} = recording.lastPlayed
this.playScaled(x, y, recording.instrument);
this.vis.drawPoint(x, y, recording.id);
noteToPlay = recording.lastPlayed
pointsToDraw.push(recording.lastPlayed)
recording.lastPlayed = recording.lastPlayed.next;
}
this.vis.connectPoints(pointsToDraw, recording.id);
if (recording.end.millis < now && !recording.activelyRecording) {
recording.instrument.stop()
} else if (noteToPlay !== undefined) {
this.playScaled(noteToPlay.x, noteToPlay.y, recording.instrument);
}
}
}
Expand Down
30 changes: 20 additions & 10 deletions src/components/Visualization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ export class Visualization implements TheremaxVisualization {
private clickStopListener: (pointerId: number) => void = () => null
private tickListener: (millis: number) => void = () => null
private columns: Graphics[] = []
private dots: Graphics[] = []
private lines: Graphics[] = []
private progress = new Graphics();


async init(element: HTMLElement) {
await this.app.init({ width: element.clientWidth, height: element.clientHeight})
await this.app.init({width: element.clientWidth, height: element.clientHeight})
// The application will create a canvas element for you that you
// can then insert into the DOM
element.appendChild(this.app.canvas);
Expand Down Expand Up @@ -98,7 +98,7 @@ export class Visualization implements TheremaxVisualization {
this.tickListener = callback
}

highlight(x: number, columns: number) {
highlightColumn(x: number, columns: number) {
if (columns !== this.columns.length) {
this.columns.forEach(c => c.destroy())
this.app.stage.removeChild(...this.columns)
Expand All @@ -116,17 +116,27 @@ export class Visualization implements TheremaxVisualization {
}

clearLines(): void {
for (let dot of this.dots) {
for (let dot of this.lines) {
dot.destroy()
}
this.app.stage.removeChild(...this.dots)
this.dots = []
this.app.stage.removeChild(...this.lines)
this.lines = []
}

drawPoint(x: number, y: number, recordingId: number): void {
const dot = new Graphics().circle(x, y, 4).fill(colours[recordingId % colours.length]);
this.dots.push(dot)
this.app.stage.addChild(dot)
createLine(x: number, y: number, recordingId: number): void {
const graphics = new Graphics()
graphics.moveTo(x, y)
this.lines[recordingId] = graphics
this.app.stage.addChild(graphics)
}

connectPoints(points: { x: number, y: number }[], recordingId: number) {
const graphics = this.lines[recordingId]
for (let i = 0; i < points.length; i++) {
const {x, y} = points[i]
graphics.lineTo(x, y)
}
graphics.stroke({width: 4, color: colours[recordingId % colours.length]});
}

getDimensions(): { width: number; height: number } {
Expand Down
2 changes: 1 addition & 1 deletion src/components/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class SoundFont implements Instrument {
"C6", "D6", "E6", "F6", "G6", "A6", "B6",
// "C7", "D7", "E7", "F7", "G7", "A7", "B7",
// "C8", "D8", "E8", "F8", "G8", "A8", "B8",
]
].filter((_, i) => i % 2 == 0)
private readonly marimba: Soundfont
private playingNote: string | null = null
private stopLastNote: () => void = () => null
Expand Down

0 comments on commit d136123

Please sign in to comment.