Skip to content

Commit

Permalink
Add pretty icons!
Browse files Browse the repository at this point in the history
  • Loading branch information
crummy committed Aug 28, 2024
1 parent f620ee3 commit e57d75a
Show file tree
Hide file tree
Showing 10 changed files with 38 additions and 99 deletions.
Binary file added public/bird.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/drum.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/piano.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sparkle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/violin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/wave.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 2 additions & 6 deletions src/components/Instrument.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
theremax?.moveDraw(x, y, pointerId)
})
visualization.onNewClick(async (x, y, pointerId) => {
visualization.onNewClick(async (x, y, pointerId, instrumentName) => {
if (!isInitialized) {
theremax = new Theremax(visualization)
await theremax.init();
isInitialized = true
}
const inst = new SoundFont(theremax.getContext(), instrument)
const inst = new SoundFont(theremax.getContext(), instrumentName)
visualization.updateColumnCount(inst.getIntervals())
const {recordingId} = theremax.beginDraw(x, y, pointerId, inst)
visualization.createLine(x, y, recordingId)
Expand All @@ -41,8 +41,6 @@
visualization.onReset(reset)
visualization.onSelectInstrument(inst => instrument = inst)
visualization.onTick(() => {
if (!isInitialized) {
return
Expand All @@ -55,8 +53,6 @@
})
})
let instrument = soundFonts[Math.floor(Math.random() * soundFonts.length)];
function reset() {
theremax?.reset();
}
Expand Down
50 changes: 28 additions & 22 deletions src/components/VisualizationP5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,23 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {

let isInitialized = false
let drawListener: (x: number, y: number, pointerId: number) => void = () => null
let newClickListener: (x: number, y: number, pointerId: number) => void = () => null
let newClickListener: (x: number, y: number, pointerId: number, instrumentName: string) => void = () => null
let clickStopListener: (pointerId: number) => void = () => null
let tickListener: () => void = () => null
let resetListener: () => void = () => null
let selectInstrumentListener: (instrument: string) => void = () => null
let progress = 0
let resetIcon: p5.Image
let instrumentIcons: Map<string, p5.Image>
const resetButton = {x: screenPadding, y: screenPadding, width: 64, height: 64}
const instruments = soundFonts.map((sf, i) => ({
x: screenPadding,
y: screenPadding + 64 + 32 * (i),
width: 32,
height: 32,
icon: "🎹",
name: sf
y: screenPadding + 82 + 82 * (i),
width: 64,
height: 64,
name: sf.name
}))
let selectedInstrument: string
let selectedInstrument = soundFonts[Math.floor(Math.random() * soundFonts.length)].name;

const touchEffects = new TouchEffects()

p.setup = () => {
Expand All @@ -65,6 +65,7 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {

p.preload = () => {
resetIcon = p.loadImage("/theremax/reset.png")
instrumentIcons = new Map(soundFonts.map(s => [s.name, p.loadImage(`/theremax/${s.image}`)]))
}

p.draw = () => {
Expand All @@ -91,10 +92,21 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
p.textSize(32)
p.textAlign(p.CENTER)
for (let instrument of instruments) {
p.text(instrument.icon, instrument.x, instrument.y, instrument.width, instrument.height)
const icon = instrumentIcons.get(instrument.name)
if (!icon) {
throw new Error(`No icon found for ${instrument.name}`)
}
const padding = 4
if (selectedInstrument === instrument.name) {
p.fill(200, 200, 200)
} else {
p.fill(100, 100, 100)
}
p.strokeWeight(2)
p.stroke(255, 255, 255)
p.rect(instrument.x - padding, instrument.y - padding, instrument.width + padding * 2, instrument.height + padding * 2, 4)
p.image(icon, instrument.x, instrument.y, instrument.width, instrument.height)
}
p.textAlign(p.LEFT, p.TOP)
p.text(selectedInstrument, screenPadding + resetButton.width, screenPadding + 16)
p.stroke("white")
p.line(screenPadding, p.height - screenPadding, (p.width - screenPadding) * progress, p.height - screenPadding)
tickListener()
Expand All @@ -118,7 +130,6 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
}
for (let instrument of instruments) {
if (didClick(instrument)) {
selectInstrumentListener(instrument.name)
selectedInstrument = instrument.name
return true
}
Expand All @@ -129,7 +140,7 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
if (handleUI()) {
return
}
newClickListener(p.mouseX, p.mouseY, 0)
newClickListener(p.mouseX, p.mouseY, 0, selectedInstrument)
}

p.touchStarted = (event) => {
Expand All @@ -139,7 +150,7 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
}
if (event instanceof TouchEvent) {
for (let touch of event.changedTouches) {
newClickListener(touch.clientX, touch.clientY, touch.identifier)
newClickListener(touch.clientX, touch.clientY, touch.identifier, selectedInstrument)
}
}
}
Expand Down Expand Up @@ -202,7 +213,7 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
drawListener = callback
}

function onNewClick(callback: (x: number, y: number, pointerId: number) => void) {
function onNewClick(callback: (x: number, y: number, pointerId: number, instrumentName: string) => void) {
newClickListener = callback
}

Expand All @@ -218,10 +229,6 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
resetListener = callback
}

function onSelectInstrument(callback: (instrument: string) => void) {
selectInstrumentListener = callback
}

function updateColumnCount(columns: number) {
if (columns) {
// columns.count = columns
Expand All @@ -242,7 +249,6 @@ export const VisualizationP5 = (p: p5, element: HTMLElement) => {
onClickStop,
onTick,
onReset,
onSelectInstrument,
updateColumnCount,
updateProgress
}
Expand All @@ -257,7 +263,7 @@ class TouchEffects {
add(x: number, y: number) {
const now = Date.now();
if (!this.lastRippleMs || now - this.lastRippleMs >= this.msBetweenRipples) {
this.ripples.push({ x, y, timestamp: now })
this.ripples.push({x, y, timestamp: now})
this.lastRippleMs = now
}
}
Expand All @@ -271,7 +277,7 @@ class TouchEffects {
const white = p.color("white")
for (let ripple of this.ripples) {
const ageMs = now - ripple.timestamp
p.lerpColor(white, black, 1/(this.maxAgeMs - ageMs))
p.lerpColor(white, black, 1 / (this.maxAgeMs - ageMs))
p.circle(ripple.x, ripple.y, ageMs)
}
}
Expand Down
79 changes: 8 additions & 71 deletions src/components/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,64 +16,12 @@ export interface Instrument {
getIntervals(): number;
}

export class SplendidGrandPiano implements Instrument {
private readonly notes = [

"Mp-11", "Mp-15", "Mp-17", "Mp-19", "Mp-21", "Mp-23", "Mp-25", "Mp-26", "Mp-28", "Mp-29",
"Mp-31", "Mp-33", "Mp-35", "Mp-36", "Mp-38", "Mp-40", "Mp-41", "Mp-43", "Mp-44", "Mp-45",
"Mp-46", "Mp-47", "Mp-48", "Mp-50", "Mp-52", "Mp-53", "Mp-55", "Mp-57", "Mp-59", "Mp-60",
"Mp-62", "Mp-64", "Mp-65", "Mp-67", "Mp-68", "Mp-69", "Mp-70", "Mp-71", "Mp-73", "Mp-74",
"Mp-75", "Mp-76", "Mp-77", "Mp-78", "Mp-79", "Mp-80", "Mp-81", "Mp-82", "Mp-83", "Mp-84",
"Mp-85", "Mp-86", "Mp-87", "Mp-89", "Mp-90", "Mp-91", "Mp-92", "Mp-93", "Mp-94",
"pp-11", "pp-15", "pp-17", "pp-19", "pp-21", "pp-23", "pp-25", "pp-26", "pp-28", "pp-29",
"pp-31", "pp-33", "pp-35", "pp-36", "pp-38", "pp-40", "pp-41", "pp-43", "pp-44", "pp-45",
"pp-46", "pp-47", "pp-48", "pp-50", "pp-52", "pp-53", "pp-55", "pp-57", "pp-59", "pp-60",
"pp-62", "pp-64", "pp-65", "pp-67", "pp-68", "pp-69", "pp-70", "pp-71", "pp-73", "pp-74",
"pp-75", "pp-77", "pp-78", "pp-79", "pp-80", "pp-81", "pp-82", "pp-83", "pp-84", "pp-85",
"pp-86", "pp-87", "pp-88", "pp-89", "pp-90", "pp-91", "pp-92", "pp-93", "pp-94", "pp-95",
"pp-96",
"FF-11", "FF-15", "FF-17", "FF-19", "FF-21", "FF-23", "FF-25", "FF-26", "FF-28", "FF-29",
"FF-31", "FF-33", "FF-35", "FF-36", "FF-38", "FF-40", "FF-41", "FF-43", "FF-44",
]
private readonly piano: Piano
private playingNote: string | null = null
private isLoaded = false

constructor(context: AudioContext) {
this.piano = new Piano(context, {storage})
this.piano.load.then(() => this.isLoaded = true)
}

play(x: number, volume: number): void {
this.piano.output.setVolume(volume)
const noteIndex = Math.floor(lerp(x, 0, 1, 0, this.notes.length))
const note = this.notes[noteIndex];
if (note == this.playingNote) {
return
} else {
this.piano.start({note})
this.playingNote = note
}
}

stop() {
this.piano.stop()
this.playingNote = null;
}

getIntervals() {
return this.notes.length;
}
}

export class SoundFont implements Instrument {
private readonly notes = [
"C3", "D3", "E3", "F3", "G3", "A3", "B3",
"C4", "D4", "E4", "F4", "G4", "A4", "B4",
"C5", "D5", "E5", "F5", "G5", "A5", "B5",
"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
Expand Down Expand Up @@ -106,23 +54,12 @@ export class SoundFont implements Instrument {
}
}

export const soundFonts: string[] = [
"acoustic_grand_piano",
"alto_sax", // keep
"bird_tweet", // keep
"breath_noise",
"cello", // keep
"church_organ", // keep
"electric_bass_pick",
"fx_3_crystal", // keep
"fx_4_atmosphere",
"melodic_tom", // keep
"music_box",
"seashore",
"taiko_drum",
"tinkle_bell",
"viola",
"trombone",
"xylophone",
"voice_oohs",
export const soundFonts = [
{ name: "church_organ", image: "piano.png" },
{ name: "alto_sax", image: "sax.png" },
{ name: "taiko_drum", image: "drum.png" },
{ name: "cello", image: "violin.png" },
{ name: "fx_3_crystal", image: "sparkle.png" },
{ name: "bird_tweet", image: "bird.png" },
{ name: "seashore", image: "wave.png" },
]

0 comments on commit e57d75a

Please sign in to comment.