diff --git a/packages/core/util.mjs b/packages/core/util.mjs index 2b190c82..f6223475 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -4,6 +4,8 @@ Copyright (C) 2022 Strudel contributors - see . */ +import { logger } from './logger.mjs'; + // returns true if the given string is a note export const isNoteWithOctave = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name); export const isNote = (name) => /^[a-gA-G][#bsf]*[0-9]?$/.test(name); @@ -84,6 +86,18 @@ export const midi2note = (n) => { // 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; +export function nanFallback(value, fallback) { + if (isNaN(Number(value))) { + logger(`"${value}" is not a number, falling back to ${fallback}`, 'warning'); + return fallback; + } + return value; +} +// round to nearest int, negative numbers will output a subtracted index +export const getSoundIndex = (n, numSounds) => { + return _mod(Math.round(nanFallback(n, 0)), numSounds); +}; + export const getPlayableNoteValue = (hap) => { let { value, context } = hap; let note = value; diff --git a/packages/soundfonts/fontloader.mjs b/packages/soundfonts/fontloader.mjs index 2f214cad..c2f6a19c 100644 --- a/packages/soundfonts/fontloader.mjs +++ b/packages/soundfonts/fontloader.mjs @@ -1,7 +1,6 @@ -import { noteToMidi, freqToMidi, _mod } from '@strudel.cycles/core'; +import { noteToMidi, freqToMidi, getSoundIndex } 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) { diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 9dd0d2f5..754ccf9b 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -33,8 +33,9 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol const ac = getAudioContext(); let sampleUrl; + let index = 0; if (Array.isArray(bank)) { - const index = getSoundIndex(n, bank.length); + index = getSoundIndex(n, bank.length); sampleUrl = bank[index]; } else { const midiDiff = (noteA) => noteToMidi(noteA) - midi; @@ -46,13 +47,13 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol null, ); transpose = -midiDiff(closest); // semitones to repitch - const index = getSoundIndex(n, bank[closest].length); + index = getSoundIndex(n, bank[closest].length); sampleUrl = bank[closest][index]; } if (resolveUrl) { sampleUrl = await resolveUrl(sampleUrl); } - let buffer = await loadBuffer(sampleUrl, ac, s, n); + let buffer = await loadBuffer(sampleUrl, ac, s, index); if (speed < 0) { // should this be cached? buffer = reverseBuffer(buffer);