Merge pull request #871 from daslyfe/bugfix_sample_select

bugfix: sound select indexes out of bounds
This commit is contained in:
Felix Roos 2023-12-31 10:06:24 +01:00 committed by GitHub
commit 3760f51c3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 8 deletions

View file

@ -4,6 +4,8 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { logger } from './logger.mjs';
// returns true if the given string is a note // returns true if the given string is a note
export const isNoteWithOctave = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name); export const isNoteWithOctave = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name);
export const isNote = (name) => /^[a-gA-G][#bsf]*[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) // 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 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) => { export const getPlayableNoteValue = (hap) => {
let { value, context } = hap; let { value, context } = hap;
let note = value; let note = value;

View file

@ -1,4 +1,4 @@
import { noteToMidi, freqToMidi } from '@strudel.cycles/core'; import { noteToMidi, freqToMidi, getSoundIndex } from '@strudel.cycles/core';
import { getAudioContext, registerSound, getEnvelope } from '@strudel.cycles/webaudio'; import { getAudioContext, registerSound, getEnvelope } from '@strudel.cycles/webaudio';
import gm from './gm.mjs'; import gm from './gm.mjs';
@ -130,9 +130,9 @@ export function registerSoundfonts() {
registerSound( registerSound(
name, name,
async (time, value, onended) => { 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 { 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 ctx = getAudioContext();
const bufferSource = await getFontBufferSource(font, value, ctx); const bufferSource = await getFontBufferSource(font, value, ctx);
bufferSource.start(time); bufferSource.start(time);

View file

@ -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 { getAudioContext, registerSound } from './index.mjs';
import { getEnvelope } from './helpers.mjs'; import { getEnvelope } from './helpers.mjs';
import { logger } from './logger.mjs'; import { logger } from './logger.mjs';
@ -31,10 +31,12 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol
transpose = midi - 36; // C3 is middle C transpose = midi - 36; // C3 is middle C
const ac = getAudioContext(); const ac = getAudioContext();
let sampleUrl; let sampleUrl;
let index = 0;
if (Array.isArray(bank)) { if (Array.isArray(bank)) {
n = nanFallback(n, 0); index = getSoundIndex(n, bank.length);
sampleUrl = bank[n % bank.length]; sampleUrl = bank[index];
} else { } else {
const midiDiff = (noteA) => noteToMidi(noteA) - midi; const midiDiff = (noteA) => noteToMidi(noteA) - midi;
// object format will expect keys as notes // object format will expect keys as notes
@ -45,12 +47,13 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol
null, null,
); );
transpose = -midiDiff(closest); // semitones to repitch transpose = -midiDiff(closest); // semitones to repitch
sampleUrl = bank[closest][n % bank[closest].length]; index = getSoundIndex(n, bank[closest].length);
sampleUrl = bank[closest][index];
} }
if (resolveUrl) { if (resolveUrl) {
sampleUrl = await resolveUrl(sampleUrl); sampleUrl = await resolveUrl(sampleUrl);
} }
let buffer = await loadBuffer(sampleUrl, ac, s, n); let buffer = await loadBuffer(sampleUrl, ac, s, index);
if (speed < 0) { if (speed < 0) {
// should this be cached? // should this be cached?
buffer = reverseBuffer(buffer); buffer = reverseBuffer(buffer);

View file

@ -61,3 +61,10 @@ export function nanFallback(value, fallback) {
} }
return value; 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);
};