mirror of
https://codeberg.org/uzu/strudel
synced 2026-10-06 01:04:22 -04:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 34b10b6c84 | |||
| 450f9685f3 | |||
| 03090e399c | |||
| ed58d26da6 | |||
| e3605590e5 | |||
| d55ef8e843 | |||
| efc2333360 | |||
| 92626e7c20 | |||
| ad113b3888 | |||
| 39c45bc2b2 | |||
| 40ed7b5382 | |||
| 5d829419ba | |||
| e26da854c0 | |||
| a28b7a2d5a | |||
| 83c776d70f | |||
| 051efdc13b | |||
| ef3cd56b0d | |||
| 9017085fa3 | |||
| cdbbe079db | |||
| 973ae4c7da | |||
| 4d13b981f1 | |||
| 7691403fd0 | |||
| 3b6e3624be | |||
| dae1560c40 | |||
| 82f0dbb750 | |||
| fb7d76a2ab |
@@ -252,6 +252,20 @@ export const { fmenv } = registerControl('fmenv');
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const { fmattack } = registerControl('fmattack');
|
export const { fmattack } = registerControl('fmattack');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* waveform of the fm modulator
|
||||||
|
*
|
||||||
|
* @name fmwave
|
||||||
|
* @param {number | Pattern} wave waveform
|
||||||
|
* @example
|
||||||
|
* n("0 1 2 3".fast(4)).scale("d:minor").s("sine").fmwave("<sine square sawtooth crackle>").fm(4).fmh(2.01)
|
||||||
|
* @example
|
||||||
|
* n("0 1 2 3".fast(4)).chord("<Dm Am F G>").voicing().s("sawtooth").fmwave("brown").fm(.6)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const { fmwave } = registerControl('fmwave');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
|
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
|
||||||
*
|
*
|
||||||
@@ -306,6 +320,7 @@ export const { fft } = registerControl('fft');
|
|||||||
*
|
*
|
||||||
* @name decay
|
* @name decay
|
||||||
* @param {number | Pattern} time decay time in seconds
|
* @param {number | Pattern} time decay time in seconds
|
||||||
|
* @synonyms dec
|
||||||
* @example
|
* @example
|
||||||
* note("c3 e3 f3 g3").decay("<.1 .2 .3 .4>").sustain(0)
|
* note("c3 e3 f3 g3").decay("<.1 .2 .3 .4>").sustain(0)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ export * from './cyclist.mjs';
|
|||||||
export * from './logger.mjs';
|
export * from './logger.mjs';
|
||||||
export * from './time.mjs';
|
export * from './time.mjs';
|
||||||
export * from './ui.mjs';
|
export * from './ui.mjs';
|
||||||
export * from './ui.mjs';
|
|
||||||
export * from './idbutils.mjs'
|
|
||||||
export { default as drawLine } from './drawLine.mjs';
|
export { default as drawLine } from './drawLine.mjs';
|
||||||
// below won't work with runtime.mjs (json import fails)
|
// below won't work with runtime.mjs (json import fails)
|
||||||
/* import * as p from './package.json';
|
/* import * as p from './package.json';
|
||||||
|
|||||||
@@ -1569,7 +1569,7 @@ export const func = curry((a, b) => reify(b).func(a));
|
|||||||
/**
|
/**
|
||||||
* Registers a new pattern method. The method is added to the Pattern class + the standalone function is returned from register.
|
* Registers a new pattern method. The method is added to the Pattern class + the standalone function is returned from register.
|
||||||
*
|
*
|
||||||
* @param {string} name name of the function
|
* @param {string | string[]} name name of the function, or an array of names to be used as synonyms
|
||||||
* @param {function} func function with 1 or more params, where last is the current pattern
|
* @param {function} func function with 1 or more params, where last is the current pattern
|
||||||
* @noAutocomplete
|
* @noAutocomplete
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './repl-component.mjs';
|
export * from './repl-component.mjs';
|
||||||
export * from './prebake.mjs';
|
export * from './prebake.mjs';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { noteToMidi, valueToMidi, Pattern, evalScope,registerSamplesFromDB } from '@strudel/core';
|
import { noteToMidi, valueToMidi, Pattern, evalScope } from '@strudel/core';
|
||||||
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples, } from '@strudel/webaudio';
|
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
||||||
import * as core from '@strudel/core';
|
import * as core from '@strudel/core';
|
||||||
|
|
||||||
export async function prebake() {
|
export async function prebake() {
|
||||||
@@ -28,7 +28,6 @@ export async function prebake() {
|
|||||||
modulesLoading,
|
modulesLoading,
|
||||||
registerSynthSounds(),
|
registerSynthSounds(),
|
||||||
registerZZFXSounds(),
|
registerZZFXSounds(),
|
||||||
registerSamplesFromDB(),
|
|
||||||
//registerSoundfonts(),
|
//registerSoundfonts(),
|
||||||
// need dynamic import here, because importing @strudel/soundfonts fails on server:
|
// need dynamic import here, because importing @strudel/soundfonts fails on server:
|
||||||
// => getting "window is not defined", as soon as "@strudel/soundfonts" is imported statically
|
// => getting "window is not defined", as soon as "@strudel/soundfonts" is imported statically
|
||||||
@@ -37,10 +36,9 @@ export async function prebake() {
|
|||||||
samples(`${ds}/tidal-drum-machines.json`),
|
samples(`${ds}/tidal-drum-machines.json`),
|
||||||
samples(`${ds}/piano.json`),
|
samples(`${ds}/piano.json`),
|
||||||
samples(`${ds}/Dirt-Samples.json`),
|
samples(`${ds}/Dirt-Samples.json`),
|
||||||
samples(`https://raw.githubusercontent.com/tidalcycles/uzu-drumkit/main/strudel.json`),
|
samples(`${ds}/uzu-drumkit.json`),
|
||||||
samples(`${ds}/vcsl.json`),
|
samples(`${ds}/vcsl.json`),
|
||||||
samples(`${ds}/mridangam.json`),
|
samples(`${ds}/mridangam.json`),
|
||||||
registerSamplesFromDB(),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
aliasBank(`${ts}/tidal-drum-machines-alias.json`);
|
aliasBank(`${ts}/tidal-drum-machines-alias.json`);
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { getAudioContext } from './superdough.mjs';
|
import { getAudioContext } from './superdough.mjs';
|
||||||
import { clamp, nanFallback } from './util.mjs';
|
import { clamp, nanFallback } from './util.mjs';
|
||||||
|
import { getNoiseBuffer } from './noise.mjs';
|
||||||
|
|
||||||
|
export const noises = ['pink', 'white', 'brown', 'crackle'];
|
||||||
|
|
||||||
export function gainNode(value) {
|
export function gainNode(value) {
|
||||||
const node = getAudioContext().createGain();
|
const node = getAudioContext().createGain();
|
||||||
@@ -216,9 +219,17 @@ export function webAudioTimeout(audioContext, onComplete, startTime, stopTime) {
|
|||||||
}
|
}
|
||||||
const mod = (freq, range = 1, type = 'sine') => {
|
const mod = (freq, range = 1, type = 'sine') => {
|
||||||
const ctx = getAudioContext();
|
const ctx = getAudioContext();
|
||||||
const osc = ctx.createOscillator();
|
let osc;
|
||||||
osc.type = type;
|
if (noises.includes(type)) {
|
||||||
osc.frequency.value = freq;
|
osc = ctx.createBufferSource();
|
||||||
|
osc.buffer = getNoiseBuffer(type, 2);
|
||||||
|
osc.loop = true;
|
||||||
|
} else {
|
||||||
|
osc = ctx.createOscillator();
|
||||||
|
osc.type = type;
|
||||||
|
osc.frequency.value = freq;
|
||||||
|
}
|
||||||
|
|
||||||
osc.start();
|
osc.start();
|
||||||
const g = new GainNode(ctx, { gain: range });
|
const g = new GainNode(ctx, { gain: range });
|
||||||
osc.connect(g); // -range, range
|
osc.connect(g); // -range, range
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { getAudioContext } from './superdough.mjs';
|
|||||||
let noiseCache = {};
|
let noiseCache = {};
|
||||||
|
|
||||||
// lazy generates noise buffers and keeps them forever
|
// lazy generates noise buffers and keeps them forever
|
||||||
function getNoiseBuffer(type, density) {
|
export function getNoiseBuffer(type, density) {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
if (noiseCache[type]) {
|
if (noiseCache[type]) {
|
||||||
return noiseCache[type];
|
return noiseCache[type];
|
||||||
|
|||||||
@@ -216,63 +216,50 @@ function getSamplesPrefixHandler(url) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const samples = async (sampleMap, baseUrl = sampleMap._base || '', options = {}) => {
|
export const samples = async (sampleMap, baseUrl = sampleMap._base || '', options = {}) => {
|
||||||
|
|
||||||
if (typeof sampleMap === 'string') {
|
if (typeof sampleMap === 'string') {
|
||||||
const base = sampleMap.split('/').slice(0, -1).join('/');
|
// check if custom prefix handler
|
||||||
const savedJSON = localStorage.getItem(sampleMap)
|
const handler = getSamplesPrefixHandler(sampleMap);
|
||||||
if (savedJSON) {
|
if (handler) {
|
||||||
const json = JSON.parse(savedJSON)
|
return handler(sampleMap);
|
||||||
samples(json, baseUrl || json._base || base, options)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
|
||||||
// check if custom prefix handler
|
|
||||||
const handler = getSamplesPrefixHandler(sampleMap);
|
|
||||||
if (handler) {
|
|
||||||
return handler(sampleMap);
|
|
||||||
}
|
|
||||||
sampleMap = resolveSpecialPaths(sampleMap);
|
|
||||||
if (sampleMap.startsWith('github:')) {
|
|
||||||
sampleMap = githubPath(sampleMap, 'strudel.json');
|
|
||||||
}
|
|
||||||
if (sampleMap.startsWith('local:')) {
|
|
||||||
sampleMap = `http://localhost:5432`;
|
|
||||||
}
|
|
||||||
if (sampleMap.startsWith('shabda:')) {
|
|
||||||
let [_, path] = sampleMap.split('shabda:');
|
|
||||||
sampleMap = `https://shabda.ndre.gr/${path}.json?strudel=1`;
|
|
||||||
}
|
|
||||||
if (sampleMap.startsWith('shabda/speech')) {
|
|
||||||
let [_, path] = sampleMap.split('shabda/speech');
|
|
||||||
path = path.startsWith('/') ? path.substring(1) : path;
|
|
||||||
let [params, words] = path.split(':');
|
|
||||||
let gender = 'f';
|
|
||||||
let language = 'en-GB';
|
|
||||||
if (params) {
|
|
||||||
[language, gender] = params.split('/');
|
|
||||||
}
|
|
||||||
sampleMap = `https://shabda.ndre.gr/speech/${words}.json?gender=${gender}&language=${language}&strudel=1'`;
|
|
||||||
}
|
|
||||||
if (typeof fetch !== 'function') {
|
|
||||||
// not a browser
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof fetch === 'undefined') {
|
|
||||||
// skip fetch when in node / testing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return fetch(sampleMap)
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((json) => {
|
|
||||||
localStorage.setItem(sampleMap, JSON.stringify(json))
|
|
||||||
samples(json, baseUrl || json._base || base, options)
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
throw new Error(`error loading "${sampleMap}"`);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
sampleMap = resolveSpecialPaths(sampleMap);
|
||||||
|
if (sampleMap.startsWith('github:')) {
|
||||||
|
sampleMap = githubPath(sampleMap, 'strudel.json');
|
||||||
|
}
|
||||||
|
if (sampleMap.startsWith('local:')) {
|
||||||
|
sampleMap = `http://localhost:5432`;
|
||||||
|
}
|
||||||
|
if (sampleMap.startsWith('shabda:')) {
|
||||||
|
let [_, path] = sampleMap.split('shabda:');
|
||||||
|
sampleMap = `https://shabda.ndre.gr/${path}.json?strudel=1`;
|
||||||
|
}
|
||||||
|
if (sampleMap.startsWith('shabda/speech')) {
|
||||||
|
let [_, path] = sampleMap.split('shabda/speech');
|
||||||
|
path = path.startsWith('/') ? path.substring(1) : path;
|
||||||
|
let [params, words] = path.split(':');
|
||||||
|
let gender = 'f';
|
||||||
|
let language = 'en-GB';
|
||||||
|
if (params) {
|
||||||
|
[language, gender] = params.split('/');
|
||||||
|
}
|
||||||
|
sampleMap = `https://shabda.ndre.gr/speech/${words}.json?gender=${gender}&language=${language}&strudel=1'`;
|
||||||
|
}
|
||||||
|
if (typeof fetch !== 'function') {
|
||||||
|
// not a browser
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const base = sampleMap.split('/').slice(0, -1).join('/');
|
||||||
|
if (typeof fetch === 'undefined') {
|
||||||
|
// skip fetch when in node / testing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return fetch(sampleMap)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((json) => samples(json, baseUrl || json._base || base, options))
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
throw new Error(`error loading "${sampleMap}"`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const { prebake, tag } = options;
|
const { prebake, tag } = options;
|
||||||
processSampleMap(
|
processSampleMap(
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import {
|
|||||||
getVibratoOscillator,
|
getVibratoOscillator,
|
||||||
webAudioTimeout,
|
webAudioTimeout,
|
||||||
getWorklet,
|
getWorklet,
|
||||||
|
noises,
|
||||||
} from './helpers.mjs';
|
} from './helpers.mjs';
|
||||||
import { getNoiseMix, getNoiseOscillator } from './noise.mjs';
|
import { getNoiseMix, getNoiseOscillator } from './noise.mjs';
|
||||||
|
|
||||||
const getFrequencyFromValue = (value) => {
|
const getFrequencyFromValue = (value, defaultNote = 36) => {
|
||||||
let { note, freq } = value;
|
let { note, freq } = value;
|
||||||
note = note || 36;
|
note = note || defaultNote;
|
||||||
if (typeof note === 'string') {
|
if (typeof note === 'string') {
|
||||||
note = noteToMidi(note); // e.g. c3 => 48
|
note = noteToMidi(note); // e.g. c3 => 48
|
||||||
}
|
}
|
||||||
@@ -40,7 +41,17 @@ const waveformAliases = [
|
|||||||
['saw', 'sawtooth'],
|
['saw', 'sawtooth'],
|
||||||
['sin', 'sine'],
|
['sin', 'sine'],
|
||||||
];
|
];
|
||||||
const noises = ['pink', 'white', 'brown', 'crackle'];
|
|
||||||
|
function makeSaturationCurve(amount, n_samples) {
|
||||||
|
const k = typeof amount === 'number' ? amount : 50;
|
||||||
|
const curve = new Float32Array(n_samples);
|
||||||
|
|
||||||
|
for (let i = 0; i < n_samples; i++) {
|
||||||
|
const x = (i * 2) / n_samples - 1;
|
||||||
|
curve[i] = Math.tanh(x * k);
|
||||||
|
}
|
||||||
|
return curve;
|
||||||
|
}
|
||||||
|
|
||||||
export function registerSynthSounds() {
|
export function registerSynthSounds() {
|
||||||
[...waveforms].forEach((s) => {
|
[...waveforms].forEach((s) => {
|
||||||
@@ -84,6 +95,75 @@ export function registerSynthSounds() {
|
|||||||
{ type: 'synth', prebake: true },
|
{ type: 'synth', prebake: true },
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerSound(
|
||||||
|
'sbd',
|
||||||
|
(t, value, onended) => {
|
||||||
|
const { duration, decay = 0.5, pdecay = 0.5, penv = 36, clip } = value;
|
||||||
|
const ctx = getAudioContext();
|
||||||
|
const attackhold = 0.02;
|
||||||
|
const noiselvl = 1.2;
|
||||||
|
const noisedecay = 0.025;
|
||||||
|
const mixGain = 1;
|
||||||
|
|
||||||
|
const o = ctx.createOscillator();
|
||||||
|
o.type = 'triangle';
|
||||||
|
o.frequency.value = getFrequencyFromValue(value, 29);
|
||||||
|
o.detune.setValueAtTime(penv * 100, 0);
|
||||||
|
o.detune.setValueAtTime(penv * 100, t);
|
||||||
|
o.detune.exponentialRampToValueAtTime(0.001, t + pdecay);
|
||||||
|
const g = gainNode(1);
|
||||||
|
g.gain.setValueAtTime(1, t + attackhold);
|
||||||
|
g.gain.exponentialRampToValueAtTime(0.001, t + attackhold + decay);
|
||||||
|
o.start(t);
|
||||||
|
|
||||||
|
const noise = getNoiseOscillator('brown', t, 2);
|
||||||
|
const noiseGain = gainNode(1);
|
||||||
|
noiseGain.gain.setValueAtTime(noiselvl, t);
|
||||||
|
noiseGain.gain.exponentialRampToValueAtTime(0.001, t + noisedecay);
|
||||||
|
|
||||||
|
const sat = new WaveShaperNode(ctx);
|
||||||
|
// tri to sine diode shaper emulation
|
||||||
|
sat.curve = makeSaturationCurve(2, ctx.sampleRate);
|
||||||
|
|
||||||
|
const mix = gainNode(mixGain);
|
||||||
|
|
||||||
|
o.onended = () => {
|
||||||
|
o.disconnect();
|
||||||
|
g.disconnect();
|
||||||
|
sat.disconnect();
|
||||||
|
noise.node.disconnect();
|
||||||
|
noiseGain.disconnect();
|
||||||
|
mix.disconnect();
|
||||||
|
onended();
|
||||||
|
};
|
||||||
|
|
||||||
|
const node = o.connect(sat).connect(g).connect(mix);
|
||||||
|
noise.node.connect(noiseGain).connect(mix);
|
||||||
|
|
||||||
|
const holdEnd = t + decay;
|
||||||
|
let end = holdEnd + 0.01;
|
||||||
|
if (clip != null) {
|
||||||
|
end = Math.min(t + clip * duration, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent clicking
|
||||||
|
mix.gain.setValueAtTime(mixGain, end - 0.01);
|
||||||
|
mix.gain.linearRampToValueAtTime(0, end);
|
||||||
|
|
||||||
|
o.stop(end);
|
||||||
|
noise.stop(end);
|
||||||
|
|
||||||
|
return {
|
||||||
|
node,
|
||||||
|
stop: (endTime) => {
|
||||||
|
o.stop(endTime);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ type: 'synth', prebake: true },
|
||||||
|
);
|
||||||
|
|
||||||
registerSound(
|
registerSound(
|
||||||
'supersaw',
|
'supersaw',
|
||||||
(begin, value, onended) => {
|
(begin, value, onended) => {
|
||||||
|
|||||||
+22
-17
@@ -88,13 +88,14 @@ function scaleOffset(scale, offset, note) {
|
|||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
* @memberof Pattern
|
* @memberof Pattern
|
||||||
* @name transpose
|
* @name transpose
|
||||||
|
* @synonyms trans
|
||||||
* @example
|
* @example
|
||||||
* "c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()
|
* "c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()
|
||||||
* @example
|
* @example
|
||||||
* "c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()
|
* "c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const transpose = register('transpose', function (intervalOrSemitones, pat) {
|
export const { transpose, trans } = register(['transpose', 'trans'], function transposeFn(intervalOrSemitones, pat) {
|
||||||
return pat.withHap((hap) => {
|
return pat.withHap((hap) => {
|
||||||
const note = hap.value.note ?? hap.value;
|
const note = hap.value.note ?? hap.value;
|
||||||
if (typeof note === 'number') {
|
if (typeof note === 'number') {
|
||||||
@@ -142,6 +143,7 @@ export const transpose = register('transpose', function (intervalOrSemitones, pa
|
|||||||
* @name scaleTranspose
|
* @name scaleTranspose
|
||||||
* @param {offset} offset number of steps inside the scale
|
* @param {offset} offset number of steps inside the scale
|
||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
|
* @synonyms scaleTrans, strans
|
||||||
* @example
|
* @example
|
||||||
* "-8 [2,4,6]"
|
* "-8 [2,4,6]"
|
||||||
* .scale('C4 bebop major')
|
* .scale('C4 bebop major')
|
||||||
@@ -149,22 +151,25 @@ export const transpose = register('transpose', function (intervalOrSemitones, pa
|
|||||||
* .note()
|
* .note()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const scaleTranspose = register('scaleTranspose', function (offset /* : number | string */, pat) {
|
export const { scaleTranspose, scaleTrans, strans } = register(
|
||||||
return pat.withHap((hap) => {
|
['scaleTranspose', 'scaleTrans', 'strans'],
|
||||||
if (!hap.context.scale) {
|
function (offset /* : number | string */, pat) {
|
||||||
throw new Error('can only use scaleTranspose after .scale');
|
return pat.withHap((hap) => {
|
||||||
}
|
if (!hap.context.scale) {
|
||||||
if (typeof hap.value === 'object')
|
throw new Error('can only use scaleTranspose after .scale');
|
||||||
return hap.withValue(() => ({
|
}
|
||||||
...hap.value,
|
if (typeof hap.value === 'object')
|
||||||
note: scaleOffset(hap.context.scale, Number(offset), hap.value.note),
|
return hap.withValue(() => ({
|
||||||
}));
|
...hap.value,
|
||||||
if (typeof hap.value !== 'string') {
|
note: scaleOffset(hap.context.scale, Number(offset), hap.value.note),
|
||||||
throw new Error('can only use scaleTranspose with notes');
|
}));
|
||||||
}
|
if (typeof hap.value !== 'string') {
|
||||||
return hap.withValue(() => scaleOffset(hap.context.scale, Number(offset), hap.value));
|
throw new Error('can only use scaleTranspose with notes');
|
||||||
});
|
}
|
||||||
});
|
return hap.withValue(() => scaleOffset(hap.context.scale, Number(offset), hap.value));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.
|
* Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.
|
||||||
|
|||||||
@@ -3706,6 +3706,144 @@ exports[`runs examples > example "fmsustain" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "fmwave" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 1/16 → 1/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 1/8 → 3/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 3/16 → 1/4 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 1/4 → 5/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 5/16 → 3/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 3/8 → 7/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 7/16 → 1/2 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 1/2 → 9/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 9/16 → 5/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 5/8 → 11/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 11/16 → 3/4 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 3/4 → 13/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 13/16 → 7/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 7/8 → 15/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 15/16 → 1/1 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 1/1 → 17/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 17/16 → 9/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 9/8 → 19/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 19/16 → 5/4 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 5/4 → 21/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 21/16 → 11/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 11/8 → 23/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 23/16 → 3/2 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 3/2 → 25/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 25/16 → 13/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 13/8 → 27/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 27/16 → 7/4 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 7/4 → 29/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 29/16 → 15/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 15/8 → 31/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 31/16 → 2/1 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 2/1 → 33/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 33/16 → 17/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 17/8 → 35/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 35/16 → 9/4 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 9/4 → 37/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 37/16 → 19/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 19/8 → 39/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 39/16 → 5/2 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 5/2 → 41/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 41/16 → 21/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 21/8 → 43/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 43/16 → 11/4 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 11/4 → 45/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 45/16 → 23/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 23/8 → 47/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 47/16 → 3/1 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 3/1 → 49/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 49/16 → 25/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 25/8 → 51/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 51/16 → 13/4 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 13/4 → 53/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 53/16 → 27/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 27/8 → 55/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 55/16 → 7/2 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 7/2 → 57/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 57/16 → 29/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 29/8 → 59/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 59/16 → 15/4 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 15/4 → 61/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 61/16 → 31/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 31/8 → 63/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
"[ 63/16 → 4/1 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "fmwave" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 1/16 → 1/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 1/8 → 3/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 3/16 → 1/4 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 1/4 → 5/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 5/16 → 3/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 3/8 → 7/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 7/16 → 1/2 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 1/2 → 9/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 9/16 → 5/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 5/8 → 11/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 11/16 → 3/4 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 3/4 → 13/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 13/16 → 7/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 7/8 → 15/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 15/16 → 1/1 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 1/1 → 17/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 17/16 → 9/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 9/8 → 19/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 19/16 → 5/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 5/4 → 21/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 21/16 → 11/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 11/8 → 23/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 23/16 → 3/2 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 3/2 → 25/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 25/16 → 13/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 13/8 → 27/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 27/16 → 7/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 7/4 → 29/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 29/16 → 15/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 15/8 → 31/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 31/16 → 2/1 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 2/1 → 33/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 33/16 → 17/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 17/8 → 35/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 35/16 → 9/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 9/4 → 37/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 37/16 → 19/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 19/8 → 39/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 39/16 → 5/2 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 5/2 → 41/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 41/16 → 21/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 21/8 → 43/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 43/16 → 11/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 11/4 → 45/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 45/16 → 23/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 23/8 → 47/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 47/16 → 3/1 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 3/1 → 49/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 49/16 → 25/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 25/8 → 51/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 51/16 → 13/4 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 13/4 → 53/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 53/16 → 27/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 27/8 → 55/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 55/16 → 7/2 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 7/2 → 57/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 57/16 → 29/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 29/8 → 59/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 59/16 → 15/4 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 15/4 → 61/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 61/16 → 31/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 31/8 → 63/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
"[ 63/16 → 4/1 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "focus" example index 0 1`] = `
|
exports[`runs examples > example "focus" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | s:sd ]",
|
"[ 0/1 → 1/8 | s:sd ]",
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"_base": "https://raw.githubusercontent.com/tidalcycles/uzu-drumkit/main/",
|
||||||
|
"bd": [
|
||||||
|
"bd/10_bd_switchangel.wav",
|
||||||
|
"bd/11_bd_mot4i.wav",
|
||||||
|
"bd/12_bd_mot4i.wav",
|
||||||
|
"bd/13_bd_mot4i.wav",
|
||||||
|
"bd/14_bd_switchangel.wav",
|
||||||
|
"bd/15_bd_switchangel.wav",
|
||||||
|
"bd/16_bd_switchangel.wav",
|
||||||
|
"bd/17_bd_switchangel.wav"
|
||||||
|
],
|
||||||
|
"brk": [
|
||||||
|
"brk/10_break_amen_pprocessed.wav"
|
||||||
|
],
|
||||||
|
"cb": [
|
||||||
|
"cb/10_perc_switchangel.wav"
|
||||||
|
],
|
||||||
|
"cp": [
|
||||||
|
"cp/10_cp_switchangel.wav",
|
||||||
|
"cp/11_cp_mot4i.wav"
|
||||||
|
],
|
||||||
|
"cr": [
|
||||||
|
"cr/10_cr_switchangel.wav",
|
||||||
|
"cr/11_cr_mot4i.wav"
|
||||||
|
],
|
||||||
|
"hh": [
|
||||||
|
"hh/10_hh_switchangel.wav",
|
||||||
|
"hh/11_hh_mot4i.wav",
|
||||||
|
"hh/12_hh_switchangel.wav",
|
||||||
|
"hh/13_hh_switchangel.wav",
|
||||||
|
"hh/14_hh_mot4i.wav"
|
||||||
|
],
|
||||||
|
"ht": [
|
||||||
|
"ht/10_ht_mot4i.wav"
|
||||||
|
],
|
||||||
|
"lt": [
|
||||||
|
"lt/10_lt_mot4i.wav"
|
||||||
|
],
|
||||||
|
"misc": [
|
||||||
|
"misc/10_misc_switchangel_ludens.wav",
|
||||||
|
"misc/11_misc_switchangel_ludens.wav",
|
||||||
|
"misc/12_misc_switchangel_ludens.wav",
|
||||||
|
"misc/13_misc_switchangel_ludens.wav",
|
||||||
|
"misc/14_misc_switchangel_ludens.wav"
|
||||||
|
],
|
||||||
|
"mt": [
|
||||||
|
"mt/10_mt_mot4i.wav"
|
||||||
|
],
|
||||||
|
"oh": [
|
||||||
|
"oh/10_oh_switchangel.wav",
|
||||||
|
"oh/11_oh_switchangel.wav",
|
||||||
|
"oh/12_oh_switchangel.wav",
|
||||||
|
"oh/13_oh_switchangel.wav"
|
||||||
|
],
|
||||||
|
"rd": [
|
||||||
|
"rd/10_rd_switchangel.wav"
|
||||||
|
],
|
||||||
|
"rim": [
|
||||||
|
"rim/10_rim_switchangel.wav",
|
||||||
|
"rim/11_rim_switch_angel.wav"
|
||||||
|
],
|
||||||
|
"sd": [
|
||||||
|
"sd/10_sd_switchangel-bounce-2.wav",
|
||||||
|
"sd/11_sd_switchangel_3.wav",
|
||||||
|
"sd/12_sd_switchangel_2.wav",
|
||||||
|
"sd/13_sd_switchangel_2.wav",
|
||||||
|
"sd/14_sd.wav"
|
||||||
|
],
|
||||||
|
"sh": [
|
||||||
|
"sh/10_sh_switchangel.wav"
|
||||||
|
],
|
||||||
|
"tb": [
|
||||||
|
"tb/10_tb.wav"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Fragment, useEffect } from 'react';
|
import { Fragment, useEffect } from 'react';
|
||||||
import { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { readDir, dir, playFile } from '../../files.mjs';
|
import { isAudioFile, readDir, dir, playFile } from '../../files.mjs';
|
||||||
import { isAudioFile } from '@strudel/core';
|
|
||||||
export function FilesTab() {
|
export function FilesTab() {
|
||||||
const [path, setPath] = useState([]);
|
const [path, setPath] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { registerSamplesFromDB, uploadSamplesToDB, userSamplesDBConfig } from '@strudel/core';
|
import { registerSamplesFromDB, uploadSamplesToDB, userSamplesDBConfig } from '../../idbutils.mjs';
|
||||||
|
|
||||||
//choose a directory to locally import samples
|
//choose a directory to locally import samples
|
||||||
export default function ImportSoundsButton({ onComplete }) {
|
export default function ImportSoundsButton({ onComplete }) {
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ export const walkFileTree = (node, fn) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isAudioFile = (filename) =>
|
||||||
|
['wav', 'mp3', 'flac', 'ogg', 'm4a', 'aac'].includes(filename.split('.').slice(-1)[0]);
|
||||||
|
|
||||||
function uint8ArrayToDataURL(uint8Array) {
|
function uint8ArrayToDataURL(uint8Array) {
|
||||||
const blob = new Blob([uint8Array], { type: 'audio/*' });
|
const blob = new Blob([uint8Array], { type: 'audio/*' });
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { registerSound, onTriggerSample } from '@strudel/webaudio';
|
import { registerSound, onTriggerSample } from '@strudel/webaudio';
|
||||||
|
import { isAudioFile } from './files.mjs';
|
||||||
import { logger } from '@strudel/core';
|
import { logger } from '@strudel/core';
|
||||||
|
|
||||||
//utilites for writing and reading to the indexdb
|
//utilites for writing and reading to the indexdb
|
||||||
|
|
||||||
|
|
||||||
export const isAudioFile = (filename) =>
|
|
||||||
['wav', 'mp3', 'flac', 'ogg', 'm4a', 'aac'].includes(filename.split('.').slice(-1)[0]);
|
|
||||||
|
|
||||||
export const userSamplesDBConfig = {
|
export const userSamplesDBConfig = {
|
||||||
dbName: 'samples',
|
dbName: 'samples',
|
||||||
table: 'usersamples',
|
table: 'usersamples',
|
||||||
+144
-146
@@ -1,158 +1,156 @@
|
|||||||
import { Pattern, noteToMidi, valueToMidi } from '@strudel/core';
|
import { Pattern, noteToMidi, valueToMidi } from '@strudel/core';
|
||||||
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
import { aliasBank, registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
||||||
import { registerSamplesFromDB } from '@strudel/core'
|
import { registerSamplesFromDB } from './idbutils.mjs';
|
||||||
import './piano.mjs';
|
import './piano.mjs';
|
||||||
import './files.mjs';
|
import './files.mjs';
|
||||||
|
|
||||||
const { BASE_URL } = import.meta.env;
|
const { BASE_URL } = import.meta.env;
|
||||||
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
||||||
|
|
||||||
// export async function prebake() {
|
export async function prebake() {
|
||||||
// // https://archive.org/details/SalamanderGrandPianoV3
|
// https://archive.org/details/SalamanderGrandPianoV3
|
||||||
// // License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
|
// License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
|
||||||
|
await Promise.all([
|
||||||
|
registerSynthSounds(),
|
||||||
// await Promise.all([
|
registerZZFXSounds(),
|
||||||
// registerSynthSounds(),
|
registerSamplesFromDB(),
|
||||||
// registerZZFXSounds(),
|
//registerSoundfonts(),
|
||||||
// registerSamplesFromDB(),
|
// need dynamic import here, because importing @strudel/soundfonts fails on server:
|
||||||
// //registerSoundfonts(),
|
// => getting "window is not defined", as soon as "@strudel/soundfonts" is imported statically
|
||||||
// // need dynamic import here, because importing @strudel/soundfonts fails on server:
|
// seems to be a problem with soundfont2
|
||||||
// // => getting "window is not defined", as soon as "@strudel/soundfonts" is imported statically
|
import('@strudel/soundfonts').then(({ registerSoundfonts }) => registerSoundfonts()),
|
||||||
// // seems to be a problem with soundfont2
|
samples(`${baseNoTrailing}/piano.json`, undefined, { prebake: true }),
|
||||||
// import('@strudel/soundfonts').then(({ registerSoundfonts }) => registerSoundfonts()),
|
// https://github.com/sgossner/VCSL/
|
||||||
// samples(`${baseNoTrailing}/piano.json`, undefined, { prebake: true }),
|
// https://api.github.com/repositories/126427031/contents/
|
||||||
// // https://github.com/sgossner/VCSL/
|
// LICENSE: CC0 general-purpose
|
||||||
// // https://api.github.com/repositories/126427031/contents/
|
samples(`${baseNoTrailing}/vcsl.json`, 'github:sgossner/VCSL/master/', { prebake: true }),
|
||||||
// // LICENSE: CC0 general-purpose
|
samples(`${baseNoTrailing}/tidal-drum-machines.json`, 'github:ritchse/tidal-drum-machines/main/machines/', {
|
||||||
// samples(`${baseNoTrailing}/vcsl.json`, 'github:sgossner/VCSL/master/', { prebake: true }),
|
prebake: true,
|
||||||
// samples(`${baseNoTrailing}/tidal-drum-machines.json`, 'github:ritchse/tidal-drum-machines/main/machines/', {
|
tag: 'drum-machines',
|
||||||
// prebake: true,
|
}),
|
||||||
// tag: 'drum-machines',
|
samples(`${baseNoTrailing}/uzu-drumkit.json`, undefined, {
|
||||||
// }),
|
prebake: true,
|
||||||
// samples(`https://raw.githubusercontent.com/tidalcycles/uzu-drumkit/main/strudel.json`, undefined, {
|
tag: 'drum-machines',
|
||||||
// prebake: true,
|
}),
|
||||||
// tag: 'drum-machines',
|
samples(`${baseNoTrailing}/mridangam.json`, undefined, { prebake: true, tag: 'drum-machines' }),
|
||||||
// }),
|
samples(
|
||||||
// samples(`${baseNoTrailing}/mridangam.json`, undefined, { prebake: true, tag: 'drum-machines' }),
|
{
|
||||||
// samples(
|
casio: ['casio/high.wav', 'casio/low.wav', 'casio/noise.wav'],
|
||||||
// {
|
crow: ['crow/000_crow.wav', 'crow/001_crow2.wav', 'crow/002_crow3.wav', 'crow/003_crow4.wav'],
|
||||||
// casio: ['casio/high.wav', 'casio/low.wav', 'casio/noise.wav'],
|
insect: [
|
||||||
// crow: ['crow/000_crow.wav', 'crow/001_crow2.wav', 'crow/002_crow3.wav', 'crow/003_crow4.wav'],
|
'insect/000_everglades_conehead.wav',
|
||||||
// insect: [
|
'insect/001_robust_shieldback.wav',
|
||||||
// 'insect/000_everglades_conehead.wav',
|
'insect/002_seashore_meadow_katydid.wav',
|
||||||
// 'insect/001_robust_shieldback.wav',
|
],
|
||||||
// 'insect/002_seashore_meadow_katydid.wav',
|
wind: [
|
||||||
// ],
|
'wind/000_wind1.wav',
|
||||||
// wind: [
|
'wind/001_wind10.wav',
|
||||||
// 'wind/000_wind1.wav',
|
'wind/002_wind2.wav',
|
||||||
// 'wind/001_wind10.wav',
|
'wind/003_wind3.wav',
|
||||||
// 'wind/002_wind2.wav',
|
'wind/004_wind4.wav',
|
||||||
// 'wind/003_wind3.wav',
|
'wind/005_wind5.wav',
|
||||||
// 'wind/004_wind4.wav',
|
'wind/006_wind6.wav',
|
||||||
// 'wind/005_wind5.wav',
|
'wind/007_wind7.wav',
|
||||||
// 'wind/006_wind6.wav',
|
'wind/008_wind8.wav',
|
||||||
// 'wind/007_wind7.wav',
|
'wind/009_wind9.wav',
|
||||||
// 'wind/008_wind8.wav',
|
],
|
||||||
// 'wind/009_wind9.wav',
|
jazz: [
|
||||||
// ],
|
'jazz/000_BD.wav',
|
||||||
// jazz: [
|
'jazz/001_CB.wav',
|
||||||
// 'jazz/000_BD.wav',
|
'jazz/002_FX.wav',
|
||||||
// 'jazz/001_CB.wav',
|
'jazz/003_HH.wav',
|
||||||
// 'jazz/002_FX.wav',
|
'jazz/004_OH.wav',
|
||||||
// 'jazz/003_HH.wav',
|
'jazz/005_P1.wav',
|
||||||
// 'jazz/004_OH.wav',
|
'jazz/006_P2.wav',
|
||||||
// 'jazz/005_P1.wav',
|
'jazz/007_SN.wav',
|
||||||
// 'jazz/006_P2.wav',
|
],
|
||||||
// 'jazz/007_SN.wav',
|
metal: [
|
||||||
// ],
|
'metal/000_0.wav',
|
||||||
// metal: [
|
'metal/001_1.wav',
|
||||||
// 'metal/000_0.wav',
|
'metal/002_2.wav',
|
||||||
// 'metal/001_1.wav',
|
'metal/003_3.wav',
|
||||||
// 'metal/002_2.wav',
|
'metal/004_4.wav',
|
||||||
// 'metal/003_3.wav',
|
'metal/005_5.wav',
|
||||||
// 'metal/004_4.wav',
|
'metal/006_6.wav',
|
||||||
// 'metal/005_5.wav',
|
'metal/007_7.wav',
|
||||||
// 'metal/006_6.wav',
|
'metal/008_8.wav',
|
||||||
// 'metal/007_7.wav',
|
'metal/009_9.wav',
|
||||||
// 'metal/008_8.wav',
|
],
|
||||||
// 'metal/009_9.wav',
|
east: [
|
||||||
// ],
|
'east/000_nipon_wood_block.wav',
|
||||||
// east: [
|
'east/001_ohkawa_mute.wav',
|
||||||
// 'east/000_nipon_wood_block.wav',
|
'east/002_ohkawa_open.wav',
|
||||||
// 'east/001_ohkawa_mute.wav',
|
'east/003_shime_hi.wav',
|
||||||
// 'east/002_ohkawa_open.wav',
|
'east/004_shime_hi_2.wav',
|
||||||
// 'east/003_shime_hi.wav',
|
'east/005_shime_mute.wav',
|
||||||
// 'east/004_shime_hi_2.wav',
|
'east/006_taiko_1.wav',
|
||||||
// 'east/005_shime_mute.wav',
|
'east/007_taiko_2.wav',
|
||||||
// 'east/006_taiko_1.wav',
|
'east/008_taiko_3.wav',
|
||||||
// 'east/007_taiko_2.wav',
|
],
|
||||||
// 'east/008_taiko_3.wav',
|
space: [
|
||||||
// ],
|
'space/000_0.wav',
|
||||||
// space: [
|
'space/001_1.wav',
|
||||||
// 'space/000_0.wav',
|
'space/002_11.wav',
|
||||||
// 'space/001_1.wav',
|
'space/003_12.wav',
|
||||||
// 'space/002_11.wav',
|
'space/004_13.wav',
|
||||||
// 'space/003_12.wav',
|
'space/005_14.wav',
|
||||||
// 'space/004_13.wav',
|
'space/006_15.wav',
|
||||||
// 'space/005_14.wav',
|
'space/007_16.wav',
|
||||||
// 'space/006_15.wav',
|
'space/008_17.wav',
|
||||||
// 'space/007_16.wav',
|
'space/009_18.wav',
|
||||||
// 'space/008_17.wav',
|
'space/010_2.wav',
|
||||||
// 'space/009_18.wav',
|
'space/011_3.wav',
|
||||||
// 'space/010_2.wav',
|
'space/012_4.wav',
|
||||||
// 'space/011_3.wav',
|
'space/013_5.wav',
|
||||||
// 'space/012_4.wav',
|
'space/014_6.wav',
|
||||||
// 'space/013_5.wav',
|
'space/015_7.wav',
|
||||||
// 'space/014_6.wav',
|
'space/016_8.wav',
|
||||||
// 'space/015_7.wav',
|
'space/017_9.wav',
|
||||||
// 'space/016_8.wav',
|
],
|
||||||
// 'space/017_9.wav',
|
numbers: [
|
||||||
// ],
|
'numbers/0.wav',
|
||||||
// numbers: [
|
'numbers/1.wav',
|
||||||
// 'numbers/0.wav',
|
'numbers/2.wav',
|
||||||
// 'numbers/1.wav',
|
'numbers/3.wav',
|
||||||
// 'numbers/2.wav',
|
'numbers/4.wav',
|
||||||
// 'numbers/3.wav',
|
'numbers/5.wav',
|
||||||
// 'numbers/4.wav',
|
'numbers/6.wav',
|
||||||
// 'numbers/5.wav',
|
'numbers/7.wav',
|
||||||
// 'numbers/6.wav',
|
'numbers/8.wav',
|
||||||
// 'numbers/7.wav',
|
],
|
||||||
// 'numbers/8.wav',
|
num: [
|
||||||
// ],
|
'num/00.wav',
|
||||||
// num: [
|
'num/01.wav',
|
||||||
// 'num/00.wav',
|
'num/02.wav',
|
||||||
// 'num/01.wav',
|
'num/03.wav',
|
||||||
// 'num/02.wav',
|
'num/04.wav',
|
||||||
// 'num/03.wav',
|
'num/05.wav',
|
||||||
// 'num/04.wav',
|
'num/06.wav',
|
||||||
// 'num/05.wav',
|
'num/07.wav',
|
||||||
// 'num/06.wav',
|
'num/08.wav',
|
||||||
// 'num/07.wav',
|
'num/09.wav',
|
||||||
// 'num/08.wav',
|
'num/10.wav',
|
||||||
// 'num/09.wav',
|
'num/11.wav',
|
||||||
// 'num/10.wav',
|
'num/12.wav',
|
||||||
// 'num/11.wav',
|
'num/13.wav',
|
||||||
// 'num/12.wav',
|
'num/14.wav',
|
||||||
// 'num/13.wav',
|
'num/15.wav',
|
||||||
// 'num/14.wav',
|
'num/16.wav',
|
||||||
// 'num/15.wav',
|
'num/17.wav',
|
||||||
// 'num/16.wav',
|
'num/18.wav',
|
||||||
// 'num/17.wav',
|
'num/19.wav',
|
||||||
// 'num/18.wav',
|
'num/20.wav',
|
||||||
// 'num/19.wav',
|
],
|
||||||
// 'num/20.wav',
|
},
|
||||||
// ],
|
'github:tidalcycles/dirt-samples',
|
||||||
// },
|
{
|
||||||
// 'github:tidalcycles/dirt-samples',
|
prebake: true,
|
||||||
// {
|
},
|
||||||
// prebake: true,
|
),
|
||||||
// },
|
]);
|
||||||
// ),
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// aliasBank(`${baseNoTrailing}/tidal-drum-machines-alias.json`);
|
aliasBank(`${baseNoTrailing}/tidal-drum-machines-alias.json`);
|
||||||
// }
|
}
|
||||||
|
|
||||||
const maxPan = noteToMidi('C8');
|
const maxPan = noteToMidi('C8');
|
||||||
const panwidth = (pan, width) => pan * width + (1 - width) / 2;
|
const panwidth = (pan, width) => pan * width + (1 - width) / 2;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
import { superdirtOutput } from '@strudel/osc/superdirtoutput';
|
import { superdirtOutput } from '@strudel/osc/superdirtoutput';
|
||||||
import { audioEngineTargets } from '../settings.mjs';
|
import { audioEngineTargets } from '../settings.mjs';
|
||||||
import { useStore } from '@nanostores/react';
|
import { useStore } from '@nanostores/react';
|
||||||
import { prebake } from '../../../packages/repl/prebake.mjs'
|
import { prebake } from './prebake.mjs';
|
||||||
import { getRandomTune, initCode, loadModules, shareCode } from './util.mjs';
|
import { getRandomTune, initCode, loadModules, shareCode } from './util.mjs';
|
||||||
import './Repl.css';
|
import './Repl.css';
|
||||||
import { setInterval, clearInterval } from 'worker-timers';
|
import { setInterval, clearInterval } from 'worker-timers';
|
||||||
|
|||||||
Reference in New Issue
Block a user