mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-16 07:36:55 -04:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bd7b66228 | |||
| 5c3501caa4 | |||
| 1341bd9c92 | |||
| 760d1abec0 | |||
| 2b44fc48a4 | |||
| 99779171f5 | |||
| 64ebfb57c3 | |||
| 099d321dbd | |||
| 59bdfd2cb8 | |||
| 56d3436fda | |||
| 440ce0cd3b | |||
| 98346261ed | |||
| 38e4718826 | |||
| 38908baccd |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/codemirror",
|
"name": "@strudel/codemirror",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Codemirror Extensions for Strudel",
|
"description": "Codemirror Extensions for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name Cutie Pi
|
* Cutie Pi
|
||||||
* by Switch Angel
|
* by Switch Angel
|
||||||
*/
|
*/
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name androidstudio
|
* androidstudio
|
||||||
*/
|
*/
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
import { createTheme } from './theme-helper.mjs';
|
import { createTheme } from './theme-helper.mjs';
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name Atom One
|
* Atom One
|
||||||
* Atom One dark syntax theme
|
* Atom One dark syntax theme
|
||||||
*
|
*
|
||||||
* https://github.com/atom/one-dark-syntax
|
* https://github.com/atom/one-dark-syntax
|
||||||
|
|||||||
+2
-3
@@ -1,6 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name darcula
|
* darcula
|
||||||
* @author darcula
|
|
||||||
* Name: IntelliJ IDEA darcula theme
|
* Name: IntelliJ IDEA darcula theme
|
||||||
* From IntelliJ IDEA by JetBrains
|
* From IntelliJ IDEA by JetBrains
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name dracula
|
* @name dracula
|
||||||
* @author dracula
|
|
||||||
* Michael Kaminsky (http://github.com/mkaminsky11)
|
* Michael Kaminsky (http://github.com/mkaminsky11)
|
||||||
* Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)
|
* Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* @name duotone
|
* duotone
|
||||||
* @author Bram de Haan
|
* author Bram de Haan
|
||||||
* by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
|
* by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
|
||||||
*/
|
*/
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* @name duotone
|
* duotone
|
||||||
* @author Bram de Haan
|
* author Bram de Haan
|
||||||
* by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
|
* by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
|
||||||
*/
|
*/
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
|
|||||||
-3
@@ -1,6 +1,3 @@
|
|||||||
/**
|
|
||||||
* @name github
|
|
||||||
*/
|
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
import { createTheme } from './theme-helper.mjs';
|
import { createTheme } from './theme-helper.mjs';
|
||||||
|
|
||||||
|
|||||||
-3
@@ -1,6 +1,3 @@
|
|||||||
/**
|
|
||||||
* @name github
|
|
||||||
*/
|
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
import { createTheme } from './theme-helper.mjs';
|
import { createTheme } from './theme-helper.mjs';
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name Atom One
|
* Atom One
|
||||||
* Atom One dark syntax theme
|
* Atom One dark syntax theme
|
||||||
*
|
*
|
||||||
* https://github.com/atom/one-dark-syntax
|
* https://github.com/atom/one-dark-syntax
|
||||||
|
|||||||
+3
-4
@@ -1,7 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* @name gruvbox-dark
|
* gruvbox-dark
|
||||||
* @author morhetz
|
* author morhetz
|
||||||
* Name: Gruvbox
|
|
||||||
* From github.com/codemirror/codemirror5/blob/master/theme/gruvbox-dark.css
|
* From github.com/codemirror/codemirror5/blob/master/theme/gruvbox-dark.css
|
||||||
*/
|
*/
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
|
|||||||
+3
-4
@@ -1,7 +1,6 @@
|
|||||||
/**
|
/*
|
||||||
* @name gruvbox-light
|
* gruvbox-light
|
||||||
* @author morhetz
|
* author morhetz
|
||||||
* Name: Gruvbox
|
|
||||||
* From github.com/codemirror/codemirror5/blob/master/theme/gruvbox-light.css
|
* From github.com/codemirror/codemirror5/blob/master/theme/gruvbox-light.css
|
||||||
*/
|
*/
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name Atom One
|
* Atom One
|
||||||
* Atom One dark syntax theme
|
* Atom One dark syntax theme
|
||||||
*
|
*
|
||||||
* https://github.com/atom/one-dark-syntax
|
* https://github.com/atom/one-dark-syntax
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/*
|
||||||
* @name Atom One
|
* Atom One
|
||||||
* Atom One dark syntax theme
|
* Atom One dark syntax theme
|
||||||
*
|
*
|
||||||
* https://github.com/atom/one-dark-syntax
|
* https://github.com/atom/one-dark-syntax
|
||||||
|
|||||||
@@ -458,6 +458,41 @@ export const { drive } = registerControl('drive');
|
|||||||
*/
|
*/
|
||||||
export const { channels, ch } = registerControl('channels', 'ch');
|
export const { channels, ch } = registerControl('channels', 'ch');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* controls the pulsewidth of the pulse oscillator
|
||||||
|
*
|
||||||
|
* @name pw
|
||||||
|
* @param {number | Pattern} pulsewidth
|
||||||
|
* @example
|
||||||
|
* note("{f a c e}%16").s("pulse").pw(".8:1:.2")
|
||||||
|
* @example
|
||||||
|
* n(run(8)).scale("D:pentatonic").s("pulse").pw("0 .75 .5 1")
|
||||||
|
*/
|
||||||
|
export const { pw } = registerControl(['pw', 'pwrate', 'pwsweep']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* controls the lfo rate for the pulsewidth of the pulse oscillator
|
||||||
|
*
|
||||||
|
* @name pwrate
|
||||||
|
* @param {number | Pattern} rate
|
||||||
|
* @example
|
||||||
|
* n(run(8)).scale("D:pentatonic").s("pulse").pw("0.5").pwrate("<5 .1 25>").pwsweep("<0.3 .8>")
|
||||||
|
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const { pwrate } = registerControl('pwrate');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* controls the lfo sweep for the pulsewidth of the pulse oscillator
|
||||||
|
*
|
||||||
|
* @name pwsweep
|
||||||
|
* @param {number | Pattern} sweep
|
||||||
|
* @example
|
||||||
|
* n(run(8)).scale("D:pentatonic").s("pulse").pw("0.5").pwrate("<5 .1 25>").pwsweep("<0.3 .8>")
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const { pwsweep } = registerControl('pwsweep');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Phaser audio effect that approximates popular guitar pedals.
|
* Phaser audio effect that approximates popular guitar pedals.
|
||||||
*
|
*
|
||||||
@@ -1461,7 +1496,7 @@ export const { vowel } = registerControl('vowel');
|
|||||||
* @name waveloss
|
* @name waveloss
|
||||||
*/
|
*/
|
||||||
export const { waveloss } = registerControl('waveloss');
|
export const { waveloss } = registerControl('waveloss');
|
||||||
/*
|
/**
|
||||||
* Noise crackle density
|
* Noise crackle density
|
||||||
*
|
*
|
||||||
* @name density
|
* @name density
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/core",
|
"name": "@strudel/core",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Port of Tidal Cycles to JavaScript",
|
"description": "Port of Tidal Cycles to JavaScript",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -156,8 +156,7 @@ export const pickmodReset = register('pickmodReset', function (lookup, pat) {
|
|||||||
return _pick(lookup, pat, true).resetJoin();
|
return _pick(lookup, pat, true).resetJoin();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/** Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
|
||||||
/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
|
|
||||||
* Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern.
|
* Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern.
|
||||||
* @name inhabit
|
* @name inhabit
|
||||||
* @synonyms pickSqueeze
|
* @synonyms pickSqueeze
|
||||||
|
|||||||
@@ -279,9 +279,9 @@ const _rearrangeWith = (ipat, n, pat) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name shuffle
|
|
||||||
* Slices a pattern into the given number of parts, then plays those parts in random order.
|
* Slices a pattern into the given number of parts, then plays those parts in random order.
|
||||||
* Each part will be played exactly once per cycle.
|
* Each part will be played exactly once per cycle.
|
||||||
|
* @name shuffle
|
||||||
* @example
|
* @example
|
||||||
* note("c d e f").sound("piano").shuffle(4)
|
* note("c d e f").sound("piano").shuffle(4)
|
||||||
* @example
|
* @example
|
||||||
@@ -292,9 +292,9 @@ export const shuffle = register('shuffle', (n, pat) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name scramble
|
|
||||||
* Slices a pattern into the given number of parts, then plays those parts at random. Similar to `shuffle`,
|
* Slices a pattern into the given number of parts, then plays those parts at random. Similar to `shuffle`,
|
||||||
* but parts might be played more than once, or not at all, per cycle.
|
* but parts might be played more than once, or not at all, per cycle.
|
||||||
|
* @name scramble
|
||||||
* @example
|
* @example
|
||||||
* note("c d e f").sound("piano").scramble(4)
|
* note("c d e f").sound("piano").scramble(4)
|
||||||
* @example
|
* @example
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/csound",
|
"name": "@strudel/csound",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "csound bindings for strudel",
|
"description": "csound bindings for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/draw",
|
"name": "@strudel/draw",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Helpers for drawing with Strudel",
|
"description": "Helpers for drawing with Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/gamepad",
|
"name": "@strudel/gamepad",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Gamepad Inputs for strudel",
|
"description": "Gamepad Inputs for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/hydra",
|
"name": "@strudel/hydra",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Hydra integration for strudel",
|
"description": "Hydra integration for strudel",
|
||||||
"main": "hydra.mjs",
|
"main": "hydra.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/midi",
|
"name": "@strudel/midi",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "Midi API for strudel",
|
"description": "Midi API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mini",
|
"name": "@strudel/mini",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Mini notation for strudel",
|
"description": "Mini notation for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/motion",
|
"name": "@strudel/motion",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "DeviceMotion API for strudel",
|
"description": "DeviceMotion API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mqtt",
|
"name": "@strudel/mqtt",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "MQTT API for strudel",
|
"description": "MQTT API for strudel",
|
||||||
"main": "mqtt.mjs",
|
"main": "mqtt.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/osc",
|
"name": "@strudel/osc",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "OSC messaging for strudel",
|
"description": "OSC messaging for strudel",
|
||||||
"main": "osc.mjs",
|
"main": "osc.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/repl",
|
"name": "@strudel/repl",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "Strudel REPL as a Web Component",
|
"description": "Strudel REPL as a Web Component",
|
||||||
"module": "index.mjs",
|
"module": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/serial",
|
"name": "@strudel/serial",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Webserial API for strudel",
|
"description": "Webserial API for strudel",
|
||||||
"main": "serial.mjs",
|
"main": "serial.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/soundfonts",
|
"name": "@strudel/soundfonts",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "Soundsfont support for strudel",
|
"description": "Soundsfont support for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "superdough",
|
"name": "superdough",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ let maxPolyphony = DEFAULT_MAX_POLYPHONY;
|
|||||||
export function setMaxPolyphony(polyphony) {
|
export function setMaxPolyphony(polyphony) {
|
||||||
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
|
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let multiChannelOrbits = false;
|
||||||
|
export function setMultiChannelOrbits(bool) {
|
||||||
|
multiChannelOrbits = bool == true;
|
||||||
|
}
|
||||||
|
|
||||||
export const soundMap = map();
|
export const soundMap = map();
|
||||||
|
|
||||||
export function registerSound(key, onTrigger, data = {}) {
|
export function registerSound(key, onTrigger, data = {}) {
|
||||||
@@ -195,8 +201,15 @@ function loadWorklets() {
|
|||||||
|
|
||||||
// this function should be called on first user interaction (to avoid console warning)
|
// this function should be called on first user interaction (to avoid console warning)
|
||||||
export async function initAudio(options = {}) {
|
export async function initAudio(options = {}) {
|
||||||
const { disableWorklets = false, maxPolyphony, audioDeviceName = DEFAULT_AUDIO_DEVICE_NAME } = options;
|
const {
|
||||||
|
disableWorklets = false,
|
||||||
|
maxPolyphony,
|
||||||
|
audioDeviceName = DEFAULT_AUDIO_DEVICE_NAME,
|
||||||
|
multiChannelOrbits = false,
|
||||||
|
} = options;
|
||||||
|
|
||||||
setMaxPolyphony(maxPolyphony);
|
setMaxPolyphony(maxPolyphony);
|
||||||
|
setMultiChannelOrbits(multiChannelOrbits);
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -277,7 +290,7 @@ export const connectToDestination = (input, channels = [0, 1]) => {
|
|||||||
});
|
});
|
||||||
stereoMix.connect(splitter);
|
stereoMix.connect(splitter);
|
||||||
channels.forEach((ch, i) => {
|
channels.forEach((ch, i) => {
|
||||||
splitter.connect(channelMerger, i % stereoMix.channelCount, clamp(ch, 0, ctx.destination.channelCount - 1));
|
splitter.connect(channelMerger, i % stereoMix.channelCount, ch % ctx.destination.channelCount);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -290,7 +303,7 @@ export const panic = () => {
|
|||||||
channelMerger == null;
|
channelMerger == null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getDelay(orbit, delaytime, delayfeedback, t) {
|
function getDelay(orbit, delaytime, delayfeedback, t, channels) {
|
||||||
if (delayfeedback > maxfeedback) {
|
if (delayfeedback > maxfeedback) {
|
||||||
//logger(`delayfeedback was clamped to ${maxfeedback} to save your ears`);
|
//logger(`delayfeedback was clamped to ${maxfeedback} to save your ears`);
|
||||||
}
|
}
|
||||||
@@ -299,7 +312,7 @@ function getDelay(orbit, delaytime, delayfeedback, t) {
|
|||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const dly = ac.createFeedbackDelay(1, delaytime, delayfeedback);
|
const dly = ac.createFeedbackDelay(1, delaytime, delayfeedback);
|
||||||
dly.start?.(t); // for some reason, this throws when audion extension is installed..
|
dly.start?.(t); // for some reason, this throws when audion extension is installed..
|
||||||
connectToDestination(dly, [0, 1]);
|
connectToDestination(dly, channels);
|
||||||
delays[orbit] = dly;
|
delays[orbit] = dly;
|
||||||
}
|
}
|
||||||
delays[orbit].delayTime.value !== delaytime && delays[orbit].delayTime.setValueAtTime(delaytime, t);
|
delays[orbit].delayTime.value !== delaytime && delays[orbit].delayTime.setValueAtTime(delaytime, t);
|
||||||
@@ -307,16 +320,9 @@ function getDelay(orbit, delaytime, delayfeedback, t) {
|
|||||||
return delays[orbit];
|
return delays[orbit];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) {
|
export function getLfo(audioContext, time, end, properties = {}) {
|
||||||
//gain
|
return getWorklet(audioContext, 'lfo-processor', {
|
||||||
const ac = getAudioContext();
|
frequency: 1,
|
||||||
const lfoGain = ac.createGain();
|
|
||||||
lfoGain.gain.value = sweep * 2;
|
|
||||||
// centerFrequency = centerFrequency * 2;
|
|
||||||
// sweep = sweep * 1.5;
|
|
||||||
|
|
||||||
const lfo = getWorklet(ac, 'lfo-processor', {
|
|
||||||
frequency,
|
|
||||||
depth: 1,
|
depth: 1,
|
||||||
skew: 0,
|
skew: 0,
|
||||||
phaseoffset: 0,
|
phaseoffset: 0,
|
||||||
@@ -324,8 +330,13 @@ function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000
|
|||||||
end,
|
end,
|
||||||
shape: 1,
|
shape: 1,
|
||||||
dcoffset: -0.5,
|
dcoffset: -0.5,
|
||||||
|
...properties,
|
||||||
});
|
});
|
||||||
lfo.connect(lfoGain);
|
}
|
||||||
|
|
||||||
|
function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) {
|
||||||
|
const ac = getAudioContext();
|
||||||
|
const lfoGain = getLfo(ac, time, end, { frequency, depth: sweep * 2 });
|
||||||
|
|
||||||
//filters
|
//filters
|
||||||
const numStages = 2; //num of filters in series
|
const numStages = 2; //num of filters in series
|
||||||
@@ -356,12 +367,12 @@ function getFilterType(ftype) {
|
|||||||
|
|
||||||
let reverbs = {};
|
let reverbs = {};
|
||||||
let hasChanged = (now, before) => now !== undefined && now !== before;
|
let hasChanged = (now, before) => now !== undefined && now !== before;
|
||||||
function getReverb(orbit, duration, fade, lp, dim, ir) {
|
function getReverb(orbit, duration, fade, lp, dim, ir, channels) {
|
||||||
// If no reverb has been created for a given orbit, create one
|
// If no reverb has been created for a given orbit, create one
|
||||||
if (!reverbs[orbit]) {
|
if (!reverbs[orbit]) {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const reverb = ac.createReverb(duration, fade, lp, dim, ir);
|
const reverb = ac.createReverb(duration, fade, lp, dim, ir);
|
||||||
connectToDestination(reverb, [0, 1]);
|
connectToDestination(reverb, channels);
|
||||||
reverbs[orbit] = reverb;
|
reverbs[orbit] = reverb;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -428,6 +439,11 @@ export function resetGlobalEffects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let activeSoundSources = new Map();
|
let activeSoundSources = new Map();
|
||||||
|
//music programs/audio gear usually increments inputs/outputs from 1, we need to subtract 1 from the input because the webaudio API channels start at 0
|
||||||
|
|
||||||
|
function mapChannelNumbers(channels) {
|
||||||
|
return (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
||||||
|
}
|
||||||
|
|
||||||
export const superdough = async (value, t, hapDuration) => {
|
export const superdough = async (value, t, hapDuration) => {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
@@ -490,7 +506,7 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
bpsustain,
|
bpsustain,
|
||||||
bprelease,
|
bprelease,
|
||||||
bandq = getDefaultValue('bandq'),
|
bandq = getDefaultValue('bandq'),
|
||||||
channels = getDefaultValue('channels'),
|
|
||||||
//phaser
|
//phaser
|
||||||
phaserrate: phaser,
|
phaserrate: phaser,
|
||||||
phaserdepth = getDefaultValue('phaserdepth'),
|
phaserdepth = getDefaultValue('phaserdepth'),
|
||||||
@@ -526,6 +542,11 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
compressorRelease,
|
compressorRelease,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
|
const orbitChannels = mapChannelNumbers(
|
||||||
|
multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels'),
|
||||||
|
);
|
||||||
|
const channels = value.channels != null ? mapChannelNumbers(value.channels) : orbitChannels;
|
||||||
|
|
||||||
gain = applyGainCurve(nanFallback(gain, 1));
|
gain = applyGainCurve(nanFallback(gain, 1));
|
||||||
postgain = applyGainCurve(postgain);
|
postgain = applyGainCurve(postgain);
|
||||||
shapevol = applyGainCurve(shapevol);
|
shapevol = applyGainCurve(shapevol);
|
||||||
@@ -547,9 +568,6 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
activeSoundSources.delete(chainID);
|
activeSoundSources.delete(chainID);
|
||||||
}
|
}
|
||||||
|
|
||||||
//music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior
|
|
||||||
channels = (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
|
||||||
|
|
||||||
let audioNodes = [];
|
let audioNodes = [];
|
||||||
|
|
||||||
if (bank && s) {
|
if (bank && s) {
|
||||||
@@ -699,7 +717,7 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
// delay
|
// delay
|
||||||
let delaySend;
|
let delaySend;
|
||||||
if (delay > 0 && delaytime > 0 && delayfeedback > 0) {
|
if (delay > 0 && delaytime > 0 && delayfeedback > 0) {
|
||||||
const delyNode = getDelay(orbit, delaytime, delayfeedback, t);
|
const delyNode = getDelay(orbit, delaytime, delayfeedback, t, orbitChannels);
|
||||||
delaySend = effectSend(post, delyNode, delay);
|
delaySend = effectSend(post, delyNode, delay);
|
||||||
audioNodes.push(delaySend);
|
audioNodes.push(delaySend);
|
||||||
}
|
}
|
||||||
@@ -717,7 +735,7 @@ export const superdough = async (value, t, hapDuration) => {
|
|||||||
}
|
}
|
||||||
roomIR = await loadBuffer(url, ac, ir, 0);
|
roomIR = await loadBuffer(url, ac, ir, 0);
|
||||||
}
|
}
|
||||||
const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim, roomIR);
|
const reverbNode = getReverb(orbit, roomsize, roomfade, roomlp, roomdim, roomIR, orbitChannels);
|
||||||
reverbSend = effectSend(post, reverbNode, room);
|
reverbSend = effectSend(post, reverbNode, room);
|
||||||
audioNodes.push(reverbSend);
|
audioNodes.push(reverbSend);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { clamp, midiToFreq, noteToMidi } from './util.mjs';
|
import { clamp, midiToFreq, noteToMidi } from './util.mjs';
|
||||||
import { registerSound, getAudioContext } from './superdough.mjs';
|
import { registerSound, getAudioContext, getLfo } from './superdough.mjs';
|
||||||
import {
|
import {
|
||||||
applyFM,
|
applyFM,
|
||||||
gainNode,
|
gainNode,
|
||||||
@@ -26,6 +26,9 @@ const getFrequencyFromValue = (value) => {
|
|||||||
return Number(freq);
|
return Number(freq);
|
||||||
};
|
};
|
||||||
function destroyAudioWorkletNode(node) {
|
function destroyAudioWorkletNode(node) {
|
||||||
|
if (node == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
node.disconnect();
|
node.disconnect();
|
||||||
node.parameters.get('end')?.setValueAtTime(0, 0);
|
node.parameters.get('end')?.setValueAtTime(0, 0);
|
||||||
}
|
}
|
||||||
@@ -145,7 +148,20 @@ export function registerSynthSounds() {
|
|||||||
'pulse',
|
'pulse',
|
||||||
(begin, value, onended) => {
|
(begin, value, onended) => {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
let { duration, n: pulsewidth = 0.5 } = value;
|
let { pwrate, pwsweep } = value;
|
||||||
|
if (pwsweep == null) {
|
||||||
|
if (pwrate != null) {
|
||||||
|
pwsweep = 0.3;
|
||||||
|
} else {
|
||||||
|
pwsweep = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwrate == null && pwsweep != null) {
|
||||||
|
pwrate = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { duration, pw: pulsewidth = 0.5 } = value;
|
||||||
const frequency = getFrequencyFromValue(value);
|
const frequency = getFrequencyFromValue(value);
|
||||||
|
|
||||||
const [attack, decay, sustain, release] = getADSRValues(
|
const [attack, decay, sustain, release] = getADSRValues(
|
||||||
@@ -153,10 +169,8 @@ export function registerSynthSounds() {
|
|||||||
'linear',
|
'linear',
|
||||||
[0.001, 0.05, 0.6, 0.01],
|
[0.001, 0.05, 0.6, 0.01],
|
||||||
);
|
);
|
||||||
|
|
||||||
const holdend = begin + duration;
|
const holdend = begin + duration;
|
||||||
const end = holdend + release + 0.01;
|
const end = holdend + release + 0.01;
|
||||||
|
|
||||||
let o = getWorklet(
|
let o = getWorklet(
|
||||||
ac,
|
ac,
|
||||||
'pulse-oscillator',
|
'pulse-oscillator',
|
||||||
@@ -178,11 +192,16 @@ export function registerSynthSounds() {
|
|||||||
envGain = o.connect(envGain);
|
envGain = o.connect(envGain);
|
||||||
|
|
||||||
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear');
|
getParamADSR(envGain.gain, attack, decay, sustain, release, 0, 1, begin, holdend, 'linear');
|
||||||
|
let lfo;
|
||||||
|
if (pwsweep != 0) {
|
||||||
|
lfo = getLfo(ac, begin, end, { frequency: pwrate, depth: pwsweep });
|
||||||
|
lfo.connect(o.parameters.get('pulsewidth'));
|
||||||
|
}
|
||||||
let timeoutNode = webAudioTimeout(
|
let timeoutNode = webAudioTimeout(
|
||||||
ac,
|
ac,
|
||||||
() => {
|
() => {
|
||||||
destroyAudioWorkletNode(o);
|
destroyAudioWorkletNode(o);
|
||||||
|
destroyAudioWorkletNode(lfo);
|
||||||
envGain.disconnect();
|
envGain.disconnect();
|
||||||
onended();
|
onended();
|
||||||
fm?.stop();
|
fm?.stop();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/tonal",
|
"name": "@strudel/tonal",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Tonal functions for strudel",
|
"description": "Tonal functions for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/transpiler",
|
"name": "@strudel/transpiler",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/web",
|
"name": "@strudel/web",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
||||||
"module": "web.mjs",
|
"module": "web.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/webaudio",
|
"name": "@strudel/webaudio",
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"description": "Web Audio helpers for Strudel",
|
"description": "Web Audio helpers for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/xen",
|
"name": "@strudel/xen",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "Xenharmonic API for strudel",
|
"description": "Xenharmonic API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -2403,6 +2403,27 @@ exports[`runs examples > example "delaytime" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "density" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 1/4 → 1/2 | s:crackle density:0.01 ]",
|
||||||
|
"[ 1/2 → 3/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 3/4 → 1/1 | s:crackle density:0.01 ]",
|
||||||
|
"[ 1/1 → 5/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 5/4 → 3/2 | s:crackle density:0.01 ]",
|
||||||
|
"[ 3/2 → 7/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 7/4 → 2/1 | s:crackle density:0.01 ]",
|
||||||
|
"[ 2/1 → 9/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 9/4 → 5/2 | s:crackle density:0.01 ]",
|
||||||
|
"[ 5/2 → 11/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 11/4 → 3/1 | s:crackle density:0.01 ]",
|
||||||
|
"[ 3/1 → 13/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 13/4 → 7/2 | s:crackle density:0.01 ]",
|
||||||
|
"[ 7/2 → 15/4 | s:crackle density:0.01 ]",
|
||||||
|
"[ 15/4 → 4/1 | s:crackle density:0.01 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "detune" example index 0 1`] = `
|
exports[`runs examples > example "detune" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/12 | note:d s:supersaw detune:0.1 ]",
|
"[ 0/1 → 1/12 | note:d s:supersaw detune:0.1 ]",
|
||||||
@@ -6721,6 +6742,186 @@ exports[`runs examples > example "pure" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "pw" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 1/16 → 1/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 1/8 → 3/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 3/16 → 1/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 1/4 → 5/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 5/16 → 3/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 3/8 → 7/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 7/16 → 1/2 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 1/2 → 9/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 9/16 → 5/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 5/8 → 11/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 11/16 → 3/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 3/4 → 13/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 13/16 → 7/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 7/8 → 15/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 15/16 → 1/1 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 1/1 → 17/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 17/16 → 9/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 9/8 → 19/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 19/16 → 5/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 5/4 → 21/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 21/16 → 11/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 11/8 → 23/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 23/16 → 3/2 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 3/2 → 25/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 25/16 → 13/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 13/8 → 27/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 27/16 → 7/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 7/4 → 29/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 29/16 → 15/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 15/8 → 31/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 31/16 → 2/1 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 2/1 → 33/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 33/16 → 17/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 17/8 → 35/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 35/16 → 9/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 9/4 → 37/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 37/16 → 19/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 19/8 → 39/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 39/16 → 5/2 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 5/2 → 41/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 41/16 → 21/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 21/8 → 43/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 43/16 → 11/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 11/4 → 45/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 45/16 → 23/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 23/8 → 47/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 47/16 → 3/1 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 3/1 → 49/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 49/16 → 25/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 25/8 → 51/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 51/16 → 13/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 13/4 → 53/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 53/16 → 27/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 27/8 → 55/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 55/16 → 7/2 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 7/2 → 57/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 57/16 → 29/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 29/8 → 59/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 59/16 → 15/4 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 15/4 → 61/16 | note:f s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 61/16 → 31/8 | note:a s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 31/8 → 63/16 | note:c s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
"[ 63/16 → 4/1 | note:e s:pulse pw:0.8 pwrate:1 pwsweep:0.2 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "pw" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | note:D3 s:pulse pw:0 ]",
|
||||||
|
"[ 1/8 → 1/4 | note:E3 s:pulse pw:0 ]",
|
||||||
|
"[ 1/4 → 3/8 | note:F#3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 3/8 → 1/2 | note:A3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 1/2 → 5/8 | note:B3 s:pulse pw:0.5 ]",
|
||||||
|
"[ 5/8 → 3/4 | note:D4 s:pulse pw:0.5 ]",
|
||||||
|
"[ 3/4 → 7/8 | note:E4 s:pulse pw:1 ]",
|
||||||
|
"[ 7/8 → 1/1 | note:F#4 s:pulse pw:1 ]",
|
||||||
|
"[ 1/1 → 9/8 | note:D3 s:pulse pw:0 ]",
|
||||||
|
"[ 9/8 → 5/4 | note:E3 s:pulse pw:0 ]",
|
||||||
|
"[ 5/4 → 11/8 | note:F#3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 11/8 → 3/2 | note:A3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 3/2 → 13/8 | note:B3 s:pulse pw:0.5 ]",
|
||||||
|
"[ 13/8 → 7/4 | note:D4 s:pulse pw:0.5 ]",
|
||||||
|
"[ 7/4 → 15/8 | note:E4 s:pulse pw:1 ]",
|
||||||
|
"[ 15/8 → 2/1 | note:F#4 s:pulse pw:1 ]",
|
||||||
|
"[ 2/1 → 17/8 | note:D3 s:pulse pw:0 ]",
|
||||||
|
"[ 17/8 → 9/4 | note:E3 s:pulse pw:0 ]",
|
||||||
|
"[ 9/4 → 19/8 | note:F#3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 19/8 → 5/2 | note:A3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 5/2 → 21/8 | note:B3 s:pulse pw:0.5 ]",
|
||||||
|
"[ 21/8 → 11/4 | note:D4 s:pulse pw:0.5 ]",
|
||||||
|
"[ 11/4 → 23/8 | note:E4 s:pulse pw:1 ]",
|
||||||
|
"[ 23/8 → 3/1 | note:F#4 s:pulse pw:1 ]",
|
||||||
|
"[ 3/1 → 25/8 | note:D3 s:pulse pw:0 ]",
|
||||||
|
"[ 25/8 → 13/4 | note:E3 s:pulse pw:0 ]",
|
||||||
|
"[ 13/4 → 27/8 | note:F#3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 27/8 → 7/2 | note:A3 s:pulse pw:0.75 ]",
|
||||||
|
"[ 7/2 → 29/8 | note:B3 s:pulse pw:0.5 ]",
|
||||||
|
"[ 29/8 → 15/4 | note:D4 s:pulse pw:0.5 ]",
|
||||||
|
"[ 15/4 → 31/8 | note:E4 s:pulse pw:1 ]",
|
||||||
|
"[ 31/8 → 4/1 | note:F#4 s:pulse pw:1 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "pwrate" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | note:D3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/8 → 1/4 | note:E3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/4 → 3/8 | note:F#3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 3/8 → 1/2 | note:A3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/2 → 5/8 | note:B3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 5/8 → 3/4 | note:D4 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 3/4 → 7/8 | note:E4 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 7/8 → 1/1 | note:F#4 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/1 → 9/8 | note:D3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 9/8 → 5/4 | note:E3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 5/4 → 11/8 | note:F#3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 11/8 → 3/2 | note:A3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 3/2 → 13/8 | note:B3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 13/8 → 7/4 | note:D4 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 7/4 → 15/8 | note:E4 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 15/8 → 2/1 | note:F#4 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 2/1 → 17/8 | note:D3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 17/8 → 9/4 | note:E3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 9/4 → 19/8 | note:F#3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 19/8 → 5/2 | note:A3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 5/2 → 21/8 | note:B3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 21/8 → 11/4 | note:D4 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 11/4 → 23/8 | note:E4 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 23/8 → 3/1 | note:F#4 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 3/1 → 25/8 | note:D3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 25/8 → 13/4 | note:E3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 13/4 → 27/8 | note:F#3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 27/8 → 7/2 | note:A3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 7/2 → 29/8 | note:B3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 29/8 → 15/4 | note:D4 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 15/4 → 31/8 | note:E4 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 31/8 → 4/1 | note:F#4 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "pwsweep" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | note:D3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/8 → 1/4 | note:E3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/4 → 3/8 | note:F#3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 3/8 → 1/2 | note:A3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/2 → 5/8 | note:B3 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 5/8 → 3/4 | note:D4 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 3/4 → 7/8 | note:E4 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 7/8 → 1/1 | note:F#4 s:pulse pw:0.5 pwrate:5 pwsweep:0.3 ]",
|
||||||
|
"[ 1/1 → 9/8 | note:D3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 9/8 → 5/4 | note:E3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 5/4 → 11/8 | note:F#3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 11/8 → 3/2 | note:A3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 3/2 → 13/8 | note:B3 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 13/8 → 7/4 | note:D4 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 7/4 → 15/8 | note:E4 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 15/8 → 2/1 | note:F#4 s:pulse pw:0.5 pwrate:0.1 pwsweep:0.8 ]",
|
||||||
|
"[ 2/1 → 17/8 | note:D3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 17/8 → 9/4 | note:E3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 9/4 → 19/8 | note:F#3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 19/8 → 5/2 | note:A3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 5/2 → 21/8 | note:B3 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 21/8 → 11/4 | note:D4 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 11/4 → 23/8 | note:E4 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 23/8 → 3/1 | note:F#4 s:pulse pw:0.5 pwrate:25 pwsweep:0.3 ]",
|
||||||
|
"[ 3/1 → 25/8 | note:D3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 25/8 → 13/4 | note:E3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 13/4 → 27/8 | note:F#3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 27/8 → 7/2 | note:A3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 7/2 → 29/8 | note:B3 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 29/8 → 15/4 | note:D4 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 15/4 → 31/8 | note:E4 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
"[ 31/8 → 4/1 | note:F#4 s:pulse pw:0.5 pwrate:5 pwsweep:0.8 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "queryArc" example index 0 1`] = `[]`;
|
exports[`runs examples > example "queryArc" example index 0 1`] = `[]`;
|
||||||
|
|
||||||
exports[`runs examples > example "rand" example index 0 1`] = `
|
exports[`runs examples > example "rand" example index 0 1`] = `
|
||||||
@@ -7871,6 +8072,52 @@ but parts might be played more than once, or not at all, per cycle." example ind
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "scramble" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/4 | note:c s:piano ]",
|
||||||
|
"[ 1/4 → 1/2 | note:d s:piano ]",
|
||||||
|
"[ 1/2 → 3/4 | note:d s:piano ]",
|
||||||
|
"[ 3/4 → 1/1 | note:c s:piano ]",
|
||||||
|
"[ 1/1 → 5/4 | note:e s:piano ]",
|
||||||
|
"[ 5/4 → 3/2 | note:e s:piano ]",
|
||||||
|
"[ 3/2 → 7/4 | note:e s:piano ]",
|
||||||
|
"[ 7/4 → 2/1 | note:c s:piano ]",
|
||||||
|
"[ 2/1 → 9/4 | note:f s:piano ]",
|
||||||
|
"[ 9/4 → 5/2 | note:d s:piano ]",
|
||||||
|
"[ 5/2 → 11/4 | note:d s:piano ]",
|
||||||
|
"[ 11/4 → 3/1 | note:e s:piano ]",
|
||||||
|
"[ 3/1 → 13/4 | note:c s:piano ]",
|
||||||
|
"[ 13/4 → 7/2 | note:f s:piano ]",
|
||||||
|
"[ 7/2 → 15/4 | note:d s:piano ]",
|
||||||
|
"[ 15/4 → 4/1 | note:f s:piano ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "scramble" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | note:c s:piano ]",
|
||||||
|
"[ 1/8 → 1/4 | note:d s:piano ]",
|
||||||
|
"[ 1/4 → 3/8 | note:d s:piano ]",
|
||||||
|
"[ 3/8 → 1/2 | note:c s:piano ]",
|
||||||
|
"[ 1/2 → 1/1 | note:g s:piano ]",
|
||||||
|
"[ 1/1 → 9/8 | note:e s:piano ]",
|
||||||
|
"[ 9/8 → 5/4 | note:e s:piano ]",
|
||||||
|
"[ 5/4 → 11/8 | note:e s:piano ]",
|
||||||
|
"[ 11/8 → 3/2 | note:c s:piano ]",
|
||||||
|
"[ 3/2 → 2/1 | note:g s:piano ]",
|
||||||
|
"[ 2/1 → 17/8 | note:f s:piano ]",
|
||||||
|
"[ 17/8 → 9/4 | note:d s:piano ]",
|
||||||
|
"[ 9/4 → 19/8 | note:d s:piano ]",
|
||||||
|
"[ 19/8 → 5/2 | note:e s:piano ]",
|
||||||
|
"[ 5/2 → 3/1 | note:g s:piano ]",
|
||||||
|
"[ 3/1 → 25/8 | note:c s:piano ]",
|
||||||
|
"[ 25/8 → 13/4 | note:f s:piano ]",
|
||||||
|
"[ 13/4 → 27/8 | note:d s:piano ]",
|
||||||
|
"[ 27/8 → 7/2 | note:f s:piano ]",
|
||||||
|
"[ 7/2 → 4/1 | note:g s:piano ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "scrub" example index 0 1`] = `
|
exports[`runs examples > example "scrub" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | s:swpad n:0 begin:0.1 speed:1 clip:1 ]",
|
"[ 0/1 → 1/8 | s:swpad n:0 begin:0.1 speed:1 clip:1 ]",
|
||||||
@@ -8301,9 +8548,7 @@ exports[`runs examples > example "shrink" example index 3 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "shuffle
|
exports[`runs examples > example "shuffle" example index 0 1`] = `
|
||||||
Slices a pattern into the given number of parts, then plays those parts in random order.
|
|
||||||
Each part will be played exactly once per cycle." example index 0 1`] = `
|
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:c s:piano ]",
|
"[ 0/1 → 1/4 | note:c s:piano ]",
|
||||||
"[ 1/4 → 1/2 | note:d s:piano ]",
|
"[ 1/4 → 1/2 | note:d s:piano ]",
|
||||||
@@ -8324,9 +8569,7 @@ Each part will be played exactly once per cycle." example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "shuffle
|
exports[`runs examples > example "shuffle" example index 1 1`] = `
|
||||||
Slices a pattern into the given number of parts, then plays those parts in random order.
|
|
||||||
Each part will be played exactly once per cycle." example index 1 1`] = `
|
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | note:c s:piano ]",
|
"[ 0/1 → 1/8 | note:c s:piano ]",
|
||||||
"[ 1/8 → 1/4 | note:d s:piano ]",
|
"[ 1/8 → 1/4 | note:d s:piano ]",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ is equivalent to this Pattern without Mini Notation:
|
|||||||
Similarly, there is an equivalent function for every aspect of the mini notation.
|
Similarly, there is an equivalent function for every aspect of the mini notation.
|
||||||
|
|
||||||
Which representation to use is a matter of context. As a rule of thumb, functions
|
Which representation to use is a matter of context. As a rule of thumb, functions
|
||||||
are better suited in a larger context, while mini notation is more practical for individiual rhythms.
|
are better suited in a larger context, while mini notation is more practical for individual rhythms.
|
||||||
|
|
||||||
## Limits of Mini Notation
|
## Limits of Mini Notation
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ButtonGroup } from './Forms.jsx';
|
|||||||
import { AudioDeviceSelector } from './AudioDeviceSelector.jsx';
|
import { AudioDeviceSelector } from './AudioDeviceSelector.jsx';
|
||||||
import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx';
|
import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx';
|
||||||
import { confirmDialog } from '../../util.mjs';
|
import { confirmDialog } from '../../util.mjs';
|
||||||
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony } from '@strudel/webaudio';
|
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio';
|
||||||
|
|
||||||
function Checkbox({ label, value, onChange, disabled = false }) {
|
function Checkbox({ label, value, onChange, disabled = false }) {
|
||||||
return (
|
return (
|
||||||
@@ -108,6 +108,7 @@ export function SettingsTab({ started }) {
|
|||||||
audioEngineTarget,
|
audioEngineTarget,
|
||||||
togglePanelTrigger,
|
togglePanelTrigger,
|
||||||
maxPolyphony,
|
maxPolyphony,
|
||||||
|
multiChannelOrbits,
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const shouldAlwaysSync = isUdels();
|
const shouldAlwaysSync = isUdels();
|
||||||
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
||||||
@@ -162,6 +163,22 @@ export function SettingsTab({ started }) {
|
|||||||
value={maxPolyphony ?? ''}
|
value={maxPolyphony ?? ''}
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
<FormItem>
|
||||||
|
<Checkbox
|
||||||
|
label="Multi Channel Orbits"
|
||||||
|
onChange={(cbEvent) => {
|
||||||
|
const val = cbEvent.target.checked;
|
||||||
|
confirmDialog(RELOAD_MSG).then((r) => {
|
||||||
|
if (r == true) {
|
||||||
|
settingsMap.setKey('multiChannelOrbits', val);
|
||||||
|
setMultiChannelOrbits(val);
|
||||||
|
return window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
value={multiChannelOrbits}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
<FormItem label="Theme">
|
<FormItem label="Theme">
|
||||||
<SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} />
|
<SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { setVersionDefaultsFrom } from './util.mjs';
|
|||||||
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
|
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
|
||||||
import { clearHydra } from '@strudel/hydra';
|
import { clearHydra } from '@strudel/hydra';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { settingsMap, useSettings } from '../settings.mjs';
|
import { parseBoolean, settingsMap, useSettings } from '../settings.mjs';
|
||||||
import {
|
import {
|
||||||
setActivePattern,
|
setActivePattern,
|
||||||
setLatestCode,
|
setLatestCode,
|
||||||
@@ -36,11 +36,15 @@ import './Repl.css';
|
|||||||
import { setInterval, clearInterval } from 'worker-timers';
|
import { setInterval, clearInterval } from 'worker-timers';
|
||||||
import { getMetadata } from '../metadata_parser';
|
import { getMetadata } from '../metadata_parser';
|
||||||
|
|
||||||
const { latestCode, maxPolyphony, audioDeviceName } = settingsMap.get();
|
const { latestCode, maxPolyphony, audioDeviceName, multiChannelOrbits } = settingsMap.get();
|
||||||
let modulesLoading, presets, drawContext, clearCanvas, audioReady;
|
let modulesLoading, presets, drawContext, clearCanvas, audioReady;
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
audioReady = initAudioOnFirstClick({ maxPolyphony, audioDeviceName });
|
audioReady = initAudioOnFirstClick({
|
||||||
|
maxPolyphony,
|
||||||
|
audioDeviceName,
|
||||||
|
multiChannelOrbits: parseBoolean(multiChannelOrbits),
|
||||||
|
});
|
||||||
modulesLoading = loadModules();
|
modulesLoading = loadModules();
|
||||||
presets = prebake();
|
presets = prebake();
|
||||||
drawContext = getDrawContext();
|
drawContext = getDrawContext();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export const defaultSettings = {
|
|||||||
isButtonRowHidden: false,
|
isButtonRowHidden: false,
|
||||||
isCSSAnimationDisabled: false,
|
isCSSAnimationDisabled: false,
|
||||||
maxPolyphony: 128,
|
maxPolyphony: 128,
|
||||||
|
multiChannelOrbits: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let search = null;
|
let search = null;
|
||||||
@@ -50,7 +51,7 @@ const settings_key = `strudel-settings${instance > 0 ? instance : ''}`;
|
|||||||
|
|
||||||
export const settingsMap = persistentMap(settings_key, defaultSettings);
|
export const settingsMap = persistentMap(settings_key, defaultSettings);
|
||||||
|
|
||||||
const parseBoolean = (booleanlike) => ([true, 'true'].includes(booleanlike) ? true : false);
|
export const parseBoolean = (booleanlike) => ([true, 'true'].includes(booleanlike) ? true : false);
|
||||||
|
|
||||||
export function useSettings() {
|
export function useSettings() {
|
||||||
const state = useStore(settingsMap);
|
const state = useStore(settingsMap);
|
||||||
@@ -81,6 +82,7 @@ export function useSettings() {
|
|||||||
isPanelPinned: parseBoolean(state.isPanelPinned),
|
isPanelPinned: parseBoolean(state.isPanelPinned),
|
||||||
isPanelOpen: parseBoolean(state.isPanelOpen),
|
isPanelOpen: parseBoolean(state.isPanelOpen),
|
||||||
userPatterns: userPatterns,
|
userPatterns: userPatterns,
|
||||||
|
multiChannelOrbits: parseBoolean(state.multiChannelOrbits),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user