diff --git a/package-lock.json b/package-lock.json index 502b8114..609cffed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10093,6 +10093,14 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "node_modules/sfumato": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/sfumato/-/sfumato-0.1.2.tgz", + "integrity": "sha512-j2s5BLUS5VUNtaK1l+v+yal3XjjV7JXCQIwE5Xs4yiQ3HJ+2Fc/dd3IkkrVHn0AJO2epShSWVoP3GnE0TvPdMg==", + "dependencies": { + "soundfont2": "^0.4.0" + } + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -12251,7 +12259,8 @@ "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "*", - "@strudel.cycles/webaudio": "^0.1.4" + "@strudel.cycles/webaudio": "^0.1.4", + "sfumato": "^0.1.2" }, "devDependencies": { "node-fetch": "^3.2.6" @@ -14150,7 +14159,8 @@ "requires": { "@strudel.cycles/core": "*", "@strudel.cycles/webaudio": "^0.1.4", - "node-fetch": "^3.2.6" + "node-fetch": "^3.2.6", + "sfumato": "^0.1.2" }, "dependencies": { "node-fetch": { @@ -20352,6 +20362,14 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, + "sfumato": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/sfumato/-/sfumato-0.1.2.tgz", + "integrity": "sha512-j2s5BLUS5VUNtaK1l+v+yal3XjjV7JXCQIwE5Xs4yiQ3HJ+2Fc/dd3IkkrVHn0AJO2epShSWVoP3GnE0TvPdMg==", + "requires": { + "soundfont2": "^0.4.0" + } + }, "shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", diff --git a/packages/core/util.mjs b/packages/core/util.mjs index c98da8fc..728fa92b 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -50,6 +50,9 @@ export const mod = (n, m) => ((n % m) + m) % m; export const getPlayableNoteValue = (hap) => { let { value: note, context } = hap; + if (typeof note === 'object' && !Array.isArray(note)) { + note = note.note || note.n || note.value; + } // 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(hap.value); diff --git a/packages/soundfonts/index.mjs b/packages/soundfonts/index.mjs index f5156cf1..3c5c226c 100644 --- a/packages/soundfonts/index.mjs +++ b/packages/soundfonts/index.mjs @@ -1,6 +1,6 @@ import { getFontBufferSource } from './fontloader.mjs'; import * as soundfontList from './list.mjs'; +import { startPresetNote } from 'sfumato'; +import { loadSoundfont } from './sfumato.mjs'; -globalThis.getFontBufferSource = getFontBufferSource; -globalThis.soundfontList = soundfontList; -globalThis.soundfontList = soundfontList; +export { loadSoundfont, startPresetNote, getFontBufferSource, soundfontList }; diff --git a/packages/soundfonts/package.json b/packages/soundfonts/package.json index edad7daf..020cfe79 100644 --- a/packages/soundfonts/package.json +++ b/packages/soundfonts/package.json @@ -23,7 +23,8 @@ "homepage": "https://github.com/tidalcycles/strudel#readme", "dependencies": { "@strudel.cycles/core": "*", - "@strudel.cycles/webaudio": "^0.1.4" + "@strudel.cycles/webaudio": "^0.1.4", + "sfumato": "^0.1.2" }, "devDependencies": { "node-fetch": "^3.2.6" diff --git a/packages/soundfonts/sfumato.mjs b/packages/soundfonts/sfumato.mjs new file mode 100644 index 00000000..1cca2ffe --- /dev/null +++ b/packages/soundfonts/sfumato.mjs @@ -0,0 +1,24 @@ +import { Pattern } from '@strudel.cycles/core'; +import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato'; + +Pattern.prototype.soundfont = function (sf, n = 0) { + return this.onTrigger((t, h, ct) => { + const ctx = getAudioContext(); + const note = getPlayableNoteValue(h); + const preset = sf.presets[n % sf.presets.length]; + const deadline = ctx.currentTime + t - ct; + const args = [ctx, preset, toMidi(note), deadline]; + const stop = startPresetNote(...args); + stop(deadline + h.duration); + }); +}; + +const soundfontCache = new Map(); +export function loadSoundfont(url) { + if (soundfontCache.get(url)) { + return soundfontCache.get(url); + } + const sf = _loadSoundfont(url); + soundfontCache.set(url, sf); + return sf; +}