diff --git a/repl/src/tone.ts b/repl/src/tone.ts index 37c96f76..7b23fe17 100644 --- a/repl/src/tone.ts +++ b/repl/src/tone.ts @@ -16,9 +16,10 @@ import { NoiseSynth, PluckSynth, Sampler, - getDestination + getDestination, } from 'tone'; import { Piano } from '@tonejs/piano'; +import { getPlayableNoteValue } from '../../util.mjs'; // what about // https://www.charlie-roberts.com/gibberish/playground/ @@ -30,13 +31,15 @@ Pattern.prototype.tone = function (instrument) { // instrument.toDestination(); return this._withEvent((event) => { const onTrigger = (time, event) => { + const note = getPlayableNoteValue(event); + // TODO: test if all tonejs instruments can handle freqs if (instrument.constructor.name === 'PluckSynth') { - instrument.triggerAttack(event.value, time); + instrument.triggerAttack(note, time); } else if (instrument.constructor.name === 'NoiseSynth') { instrument.triggerAttackRelease(event.duration, time); // noise has no value } else if (instrument.constructor.name === 'Piano') { - instrument.keyDown({ note: event.value, time, velocity: 0.5 }); - instrument.keyUp({ note: event.value, time: time + event.duration }); + instrument.keyDown({ note, time, velocity: 0.5 }); + instrument.keyUp({ note, time: time + event.duration }); } else { instrument.triggerAttackRelease(event.value, event.duration, time); } diff --git a/repl/src/useRepl.ts b/repl/src/useRepl.ts index 22d98515..0772b21e 100644 --- a/repl/src/useRepl.ts +++ b/repl/src/useRepl.ts @@ -1,6 +1,5 @@ import { useCallback, useState, useMemo } from 'react'; -import { isNote } from 'tone'; -import { fromMidi } from '../../util.mjs'; +import { getPlayableNoteValue } from '../../util.mjs'; import { evaluate } from './evaluate'; import type { Pattern } from './types'; import useCycle from './useCycle'; @@ -64,15 +63,8 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }: any) onEvent?.(event); const { onTrigger } = event.context; if (!onTrigger) { - let note = event.value; - // if value is number => interpret as midi number... - // TODO: what if value is meant as frequency? => check context - if (typeof event.value === 'number') { - note = fromMidi(event.value); - } else if (!isNote(note)) { - throw new Error('not a note: ' + note); - } if (defaultSynth) { + const note = getPlayableNoteValue(event); defaultSynth.triggerAttackRelease(note, event.duration, time); } else { throw new Error('no defaultSynth passed to useRepl.'); diff --git a/util.mjs b/util.mjs index 0b357e69..0ecd4306 100644 --- a/util.mjs +++ b/util.mjs @@ -28,3 +28,14 @@ export const fromMidi = (n) => { // modulo that works with negative numbers e.g. mod(-1, 3) = 2 // const mod = (n: number, m: number): number => (n < 0 ? mod(n + m, m) : n % m); export const mod = (n, m) => (n < 0 ? mod(n + m, m) : n % m); + +export const getPlayableNoteValue = (event) => { + let { value: note, context } = event; + // if value is number => interpret as midi number as long as its not marked as frequency + if (typeof note === 'number' && context.type !== 'frequency') { + note = fromMidi(event.value); + } else if (typeof note === 'string' && !isNote(note)) { + throw new Error('not a note: ' + note); + } + return note; +};