mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-14 14:53:45 -04:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 39013c09ef | |||
| 9d425dfff6 |
@@ -1,4 +1,4 @@
|
||||
import { getCommonSampleInfo } from './util.mjs';
|
||||
import { getCommonSampleInfoFromBank } from './util.mjs';
|
||||
import { registerSound, registerWaveTable } from './index.mjs';
|
||||
import { getAudioContext } from './audioContext.mjs';
|
||||
import { getADSRValues, getParamADSR, getPitchEnvelope, getVibratoOscillator } from './helpers.mjs';
|
||||
@@ -23,35 +23,34 @@ function humanFileSize(bytes, si) {
|
||||
return bytes.toFixed(1) + ' ' + units[u];
|
||||
}
|
||||
|
||||
export function getSampleInfo(hapValue, bank) {
|
||||
const { speed = 1.0 } = hapValue;
|
||||
const { transpose, url, index, midi, label } = getCommonSampleInfo(hapValue, bank);
|
||||
let playbackRate = Math.abs(speed) * Math.pow(2, transpose / 12);
|
||||
return { transpose, url, index, midi, label, playbackRate };
|
||||
}
|
||||
|
||||
// takes hapValue and returns buffer + playbackRate.
|
||||
export const getSampleBuffer = async (hapValue, bank, resolveUrl) => {
|
||||
let { url: sampleUrl, label, playbackRate } = getSampleInfo(hapValue, bank);
|
||||
export const getSampleBuffer = async (label, sampleUrl, resolveUrl) => {
|
||||
if (resolveUrl) {
|
||||
sampleUrl = await resolveUrl(sampleUrl);
|
||||
}
|
||||
const ac = getAudioContext();
|
||||
const buffer = await loadBuffer(sampleUrl, ac, label);
|
||||
return buffer
|
||||
};
|
||||
|
||||
function getBufferPlaybackRate(hapValue, buffer, transpose) {
|
||||
const { speed = 1.0 } = hapValue;
|
||||
let playbackRate = Math.abs(speed) * Math.pow(2, transpose / 12);
|
||||
if (hapValue.unit === 'c') {
|
||||
playbackRate = playbackRate * buffer.duration;
|
||||
}
|
||||
return { buffer, playbackRate };
|
||||
};
|
||||
return playbackRate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// creates playback ready AudioBufferSourceNode from hapValue
|
||||
export const getSampleBufferSource = async (hapValue, bank, resolveUrl) => {
|
||||
let { buffer, playbackRate } = await getSampleBuffer(hapValue, bank, resolveUrl);
|
||||
export function getSampleBufferSource(hapValue, buffer,transpose) {
|
||||
if (hapValue.speed < 0) {
|
||||
// should this be cached?
|
||||
buffer = reverseBuffer(buffer);
|
||||
}
|
||||
const playbackRate = getBufferPlaybackRate(hapValue, buffer, transpose)
|
||||
const ac = getAudioContext();
|
||||
const bufferSource = ac.createBufferSource();
|
||||
bufferSource.buffer = buffer;
|
||||
@@ -264,7 +263,7 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option
|
||||
|
||||
const cutGroups = [];
|
||||
|
||||
export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
export async function onTriggerSample(t, value, onended, bufferSrc) {
|
||||
let {
|
||||
s,
|
||||
nudge = 0, // TODO: is this in seconds?
|
||||
@@ -286,7 +285,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
// destructure adsr here, because the default should be different for synths and samples
|
||||
let [attack, decay, sustain, release] = getADSRValues([value.attack, value.decay, value.sustain, value.release]);
|
||||
|
||||
const { bufferSource, sliceDuration, offset } = await getSampleBufferSource(value, bank, resolveUrl);
|
||||
const { bufferSource, sliceDuration, offset } = bufferSrc
|
||||
|
||||
// asny stuff above took too long?
|
||||
if (ac.currentTime > t) {
|
||||
@@ -348,14 +347,21 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
async function getBufferSrcFromBank(hapValue, bank, resolveUrl = undefined) {
|
||||
const { transpose, url, label } = getCommonSampleInfoFromBank(hapValue, bank)
|
||||
let buffer = await getSampleBuffer(label,url, resolveUrl);
|
||||
return getSampleBufferSource(hapValue, buffer, transpose)
|
||||
}
|
||||
|
||||
function registerSample(key, bank, params) {
|
||||
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, bank), {
|
||||
registerSound(key, async (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, await getBufferSrcFromBank(hapValue, bank, undefined)), {
|
||||
type: 'sample',
|
||||
samples: bank,
|
||||
...params,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function registerSampleSource(key, bank, params) {
|
||||
const isWavetable = key.startsWith('wt_');
|
||||
if (isWavetable) {
|
||||
|
||||
@@ -80,12 +80,13 @@ export function secondsToCycle(t, cps) {
|
||||
// deduces relevant info for sample loading from hap.value and sample definition
|
||||
// it encapsulates the core sampler logic into a pure and synchronous function
|
||||
// hapValue: Hap.value, bank: sample bank definition for sound "s" (values in strudel.json format)
|
||||
export function getCommonSampleInfo(hapValue, bank) {
|
||||
export function getCommonSampleInfoFromBank(hapValue, bank) {
|
||||
const { s, n = 0 } = hapValue;
|
||||
let midi = valueToMidi(hapValue, 36);
|
||||
let transpose = midi - 36; // C3 is middle C;
|
||||
let url;
|
||||
let index = 0;
|
||||
let {transpose, label} = getCommonSampleInfo(hapValue)
|
||||
|
||||
if (Array.isArray(bank)) {
|
||||
index = getSoundIndex(n, bank.length);
|
||||
url = bank[index];
|
||||
@@ -102,6 +103,20 @@ export function getCommonSampleInfo(hapValue, bank) {
|
||||
index = getSoundIndex(n, bank[closest].length);
|
||||
url = bank[closest][index];
|
||||
}
|
||||
const label = `${s}:${index}`;
|
||||
return { transpose, url, index, midi, label };
|
||||
label = `${s}:${index}`;
|
||||
return { transpose, url, label };
|
||||
}
|
||||
|
||||
|
||||
export function getCommonSampleInfo(hapValue) {
|
||||
const { s, n = 0 } = hapValue;
|
||||
let midi = valueToMidi(hapValue, 36);
|
||||
let transpose = midi - 36; // C3 is middle C;
|
||||
const label = `${s}:${n}`;
|
||||
return { transpose, label };
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getAudioContext, registerSound } from './index.mjs';
|
||||
import { getCommonSampleInfo } from './util.mjs';
|
||||
import { getCommonSampleInfoFromBank } from './util.mjs';
|
||||
import {
|
||||
applyFM,
|
||||
applyParameterModulators,
|
||||
@@ -216,7 +216,7 @@ export async function onTriggerSynth(t, value, onended, tables, cps, frameLen) {
|
||||
warpmode = Warpmode[warpmode.toUpperCase()] ?? Warpmode.NONE;
|
||||
}
|
||||
const frequency = getFrequencyFromValue(value);
|
||||
const { url, label } = getCommonSampleInfo(value, tables);
|
||||
const { url, label } = getCommonSampleInfoFromBank(value, tables);
|
||||
const payload = await getPayload(url, label, frameLen);
|
||||
let holdEnd = t + duration;
|
||||
if (clip !== undefined) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { registerSampleSource } from '@strudel/webaudio';
|
||||
import { getSampleBufferSource, onTriggerSample, registerSampleSource } from '@strudel/webaudio';
|
||||
import { isAudioFile } from './files.mjs';
|
||||
import { logger } from '@strudel/core';
|
||||
import { getSoundIndex, logger } from '@strudel/core';
|
||||
import { registerSound } from '@strudel/webaudio';
|
||||
import { getCommonSampleInfo } from '../../../packages/superdough/util.mjs';
|
||||
|
||||
//utilites for writing and reading to the indexdb
|
||||
|
||||
@@ -25,6 +27,15 @@ function clearAllIDB() {
|
||||
|
||||
export function clearIDB(dbName) {
|
||||
return window.indexedDB.deleteDatabase(dbName);
|
||||
}
|
||||
|
||||
|
||||
function registerSampleFromIdb(key, bank, params) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// queries the DB, and registers the sounds so they can be played
|
||||
@@ -52,31 +63,76 @@ export function registerSamplesFromDB(config = userSamplesDBConfig, onComplete =
|
||||
if (!isAudioFile(title)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const splitRelativePath = soundFile.id.split('/');
|
||||
let parentDirectory =
|
||||
//fallback to file name before period and seperator if no parent directory
|
||||
splitRelativePath[splitRelativePath.length - 2] ?? soundFile.id.split(/\W+/)[0] ?? 'user';
|
||||
const blob = soundFile.blob;
|
||||
|
||||
return blobToDataUrl(blob).then((soundPath) => {
|
||||
|
||||
// const blob = soundFile.blob;
|
||||
|
||||
const titlePathMap = sounds.get(parentDirectory) ?? new Map();
|
||||
|
||||
titlePathMap.set(title, soundPath);
|
||||
|
||||
titlePathMap.set(title, soundFile.id);
|
||||
sounds.set(parentDirectory, titlePathMap);
|
||||
return;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// return blobToDataUrl(blob).then((soundPath) => {
|
||||
// const titlePathMap = sounds.get(parentDirectory) ?? new Map();
|
||||
|
||||
// titlePathMap.set(title, soundPath);
|
||||
|
||||
// sounds.set(parentDirectory, titlePathMap);
|
||||
// return;
|
||||
// });
|
||||
}),
|
||||
)
|
||||
.then(() => {
|
||||
sounds.forEach((titlePathMap, key) => {
|
||||
const value = Array.from(titlePathMap.keys())
|
||||
const bank = Array.from(titlePathMap.keys())
|
||||
.sort((a, b) => {
|
||||
return a.localeCompare(b);
|
||||
})
|
||||
.map((title) => titlePathMap.get(title));
|
||||
|
||||
registerSampleSource(key, value, { prebake: false });
|
||||
|
||||
|
||||
|
||||
registerSound(key, async (t, hapValue, onended) => {
|
||||
const { s, n = 0 } = hapValue;
|
||||
const index = getSoundIndex(n, bank.length);
|
||||
let {transpose, label} = getCommonSampleInfo(hapValue)
|
||||
const storeKey = bank[index];
|
||||
|
||||
openDB(config, (objectStore) => {
|
||||
const getRequest = objectStore.get(storeKey);
|
||||
getRequest.onsuccess = async (event) => {
|
||||
const result = event.target.result;
|
||||
let buffer = result?.blob.arrayBuffer ? await result.blob.arrayBuffer() : null;
|
||||
console.info(buffer)
|
||||
if (buffer) {
|
||||
const bufferSource = getSampleBufferSource(hapValue,buffer,transpose)
|
||||
onTriggerSample(t, hapValue, onended, bufferSource)
|
||||
} else {
|
||||
logger(`Could not load sample for ${storeKey}`, 'error');
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
// const buffer = objectStore.getKey(key)
|
||||
// const bufferSource = getSampleBufferSource(hapValue,buffer,transpose)
|
||||
|
||||
// onTriggerSample(t, hapValue, onended, await getBufferSrcFromBank(hapValue, bank, undefined))
|
||||
|
||||
}, {
|
||||
type: 'sample',
|
||||
samples: bank,
|
||||
|
||||
});
|
||||
|
||||
// registerSampleSource(key, value, { prebake: false });
|
||||
});
|
||||
|
||||
logger('imported sounds registered!', 'success');
|
||||
|
||||
Reference in New Issue
Block a user