diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index 017ba763..2f214cad 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -1,6 +1,7 @@ -import { noteToMidi, freqToMidi } from '@strudel.cycles/core'; +import { noteToMidi, freqToMidi, _mod } from '@strudel.cycles/core'; import { getAudioContext, registerSound, getEnvelope } from '@strudel.cycles/webaudio'; import gm from './gm.mjs'; +import { getSoundIndex } from '../superdough/util.mjs'; let loadCache = {}; async function loadFont(name) { @@ -130,9 +131,9 @@ export function registerSoundfonts() { registerSound( name, async (time, value, onended) => { - const { n = 0 } = value; + const n = getSoundIndex(value.n, fonts.length); const { attack = 0.001, decay = 0.001, sustain = 1, release = 0.001 } = value; - const font = fonts[n % fonts.length]; + const font = fonts[n]; const ctx = getAudioContext(); const bufferSource = await getFontBufferSource(font, value, ctx); bufferSource.start(time); diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 39e5b548..9dd0d2f5 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -1,4 +1,4 @@ -import { noteToMidi, valueToMidi, nanFallback } from './util.mjs'; +import { noteToMidi, valueToMidi, getSoundIndex } from './util.mjs'; import { getAudioContext, registerSound } from './index.mjs'; import { getEnvelope } from './helpers.mjs'; import { logger } from './logger.mjs'; @@ -31,10 +31,11 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol transpose = midi - 36; // C3 is middle C const ac = getAudioContext(); + let sampleUrl; if (Array.isArray(bank)) { - n = nanFallback(n, 0); - sampleUrl = bank[n % bank.length]; + const index = getSoundIndex(n, bank.length); + sampleUrl = bank[index]; } else { const midiDiff = (noteA) => noteToMidi(noteA) - midi; // object format will expect keys as notes @@ -45,7 +46,8 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol null, ); transpose = -midiDiff(closest); // semitones to repitch - sampleUrl = bank[closest][n % bank[closest].length]; + const index = getSoundIndex(n, bank[closest].length); + sampleUrl = bank[closest][index]; } if (resolveUrl) { sampleUrl = await resolveUrl(sampleUrl); diff --git a/packages/superdough/util.mjs b/packages/superdough/util.mjs index d49ffd6b..29eaa7bc 100644 --- a/packages/superdough/util.mjs +++ b/packages/superdough/util.mjs @@ -61,3 +61,10 @@ export function nanFallback(value, fallback) { } return value; } +// modulo that works with negative numbers e.g. _mod(-1, 3) = 2. Works on numbers (rather than patterns of numbers, as @mod@ from pattern.mjs does) +export const _mod = (n, m) => ((n % m) + m) % m; + +// round to nearest int, negative numbers will output a subtracted index +export const getSoundIndex = (n, numSounds) => { + return _mod(Math.round(nanFallback(n, 0)), numSounds); +};