From 1170ff58ee0b91de8e2578bd00f52f45345c0f74 Mon Sep 17 00:00:00 2001 From: gogins Date: Thu, 10 Aug 2023 20:26:37 -0400 Subject: [PATCH 01/44] Fix for #1. --- packages/csound/index.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/csound/index.mjs b/packages/csound/index.mjs index 31ffa83a5..3063febc1 100644 --- a/packages/csound/index.mjs +++ b/packages/csound/index.mjs @@ -137,7 +137,7 @@ export async function loadOrc(url) { export const csoundm = register('csoundm', (instrument, pat) => { let p1 = instrument; if (typeof instrument === 'string') { - p1 = `"{instrument}"`; + p1 = `"${instrument}"`; } init(); // not async to support csound inside other patterns + to be able to call pattern methods after it return pat.onTrigger((tidal_time, hap) => { From 08aab9d4d80099d4330549ee732c0ba9ec701297 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Wed, 20 Sep 2023 19:44:32 +0200 Subject: [PATCH 02/44] Adding vibrato to Superdough sampler Modulating the `playbackRate` to simulate a vibrato! --- packages/superdough/sampler.mjs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 76b6a542c..365d397c2 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -22,7 +22,7 @@ function humanFileSize(bytes, si) { return bytes.toFixed(1) + ' ' + units[u]; } -export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resolveUrl) => { +export const getSampleBufferSource = async (s, n, note, speed, freq, vib, vibmod, bank, resolveUrl) => { let transpose = 0; if (freq !== undefined && note !== undefined) { logger('[sampler] hap has note and freq. ignoring note', 'warning'); @@ -57,8 +57,20 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol const bufferSource = ac.createBufferSource(); bufferSource.buffer = buffer; const playbackRate = 1.0 * Math.pow(2, transpose / 12); - // bufferSource.playbackRate.value = Math.pow(2, transpose / 12); - bufferSource.playbackRate.value = playbackRate; + if (vib > 0) { + let vibrato_oscillator = getAudioContext().createOscillator(); + vibrato_oscillator.frequency.value = vib; + const gain = getAudioContext().createGain(); + // Vibmod is the amount of vibrato, in semitones + bufferSource.playbackRate.value = Math.pow(2, transpose / 12); + gain.gain.value = vibmod / 4; + vibrato_oscillator.connect(gain); + gain.connect(bufferSource.playbackRate); + vibrato_oscillator.start(0); + } else { + bufferSource.playbackRate.value = Math.pow(2, transpose / 12); + bufferSource.playbackRate.value = playbackRate; + } return bufferSource; }; @@ -211,6 +223,8 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { begin = 0, loopEnd = 1, end = 1, + vib, + vibmod = 0.5, } = value; // load sample if (speed === 0) { @@ -224,7 +238,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { //const soundfont = getSoundfontKey(s); const time = t + nudge; - const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl); + const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, vib, vibmod, bank, resolveUrl); // asny stuff above took too long? if (ac.currentTime > t) { @@ -255,7 +269,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { bufferSource.connect(envelope); const out = ac.createGain(); // we need a separate gain for the cutgroups because firefox... envelope.connect(out); - bufferSource.onended = function () { + bufferSource.onended = function() { bufferSource.disconnect(); envelope.disconnect(); out.disconnect(); From b3f8df17838cabb2a0c78bff529a2bdf03421341 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Sat, 4 Nov 2023 20:20:25 -0400 Subject: [PATCH 03/44] initial commit --- packages/core/controls.mjs | 11 ++++ packages/superdough/phaser.mjs | 88 ++++++++++++++++++++++++++++++ packages/superdough/superdough.mjs | 10 ++++ packages/superdough/worklets.mjs | 33 +++++++++++ 4 files changed, 142 insertions(+) create mode 100644 packages/superdough/phaser.mjs diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 8841b4bca..a616ce068 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -380,6 +380,17 @@ const generic_params = [ * */ ['coarse'], + + /** + * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers + * + * @name phaser + * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. + * @example + * s("bd sd,hh*4").coarse("<1 4 8 16 32>") + * + */ + ['phaser'], /** * choose the channel the pattern is sent to in superdirt * diff --git a/packages/superdough/phaser.mjs b/packages/superdough/phaser.mjs new file mode 100644 index 000000000..62771df3f --- /dev/null +++ b/packages/superdough/phaser.mjs @@ -0,0 +1,88 @@ +// credits to webdirt: https://github.com/dktr0/WebDirt/blob/41342e81d6ad694a2310d491fef7b7e8b0929efe/js-src/Graph.js#L597 +export var vowelFormant = { + 0: { freqs: [660, 1120, 2750, 3000, 3350], gains: [1, 0.5012, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, + 1: { freqs: [440, 1800, 2700, 3000, 3300], gains: [1, 0.1995, 0.1259, 0.1, 0.1], qs: [70, 80, 100, 120, 120] }, + 2: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, + 3: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, + 4: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, +}; + +var createFilter = function (ctx, cutoff, Q) { + var lowpassFilter = ctx.createBiquadFilter(); + lowpassFilter.type = 'notch'; + lowpassFilter.gain.value = 1; + lowpassFilter.frequency.value = cutoff; + lowpassFilter.Q.value = Q; + return lowpassFilter; +}; + +// var createTriOscillator = function (freq) { +// var osc = ctx.createOscillator(); +// osc.type = 'triangle'; +// osc.frequency.value = freq * 1.0; +// osc.detune.value = 0; +// return osc; +// }; + +var createLFO = function (ctx, freq) { + var osc = ctx.createOscillator(); + osc.frequency.value = freq; + osc.type = 'sine'; + osc.start(); + return osc; +}; +var createLFOGain = function (ctx, gain) { + var gainNode = ctx.createGain(); + gainNode.gain.value = gain; + return gainNode; +}; +let lfo, lfoGain; +if (typeof GainNode !== 'undefined') { + class PhaserNode extends GainNode { + constructor(ac, speed) { + super(ac); + console.log('speed', speed); + + if (!vowelFormant[speed]) { + throw new Error('phaser: unknown phaser ' + speed); + } + const { gains, qs, freqs } = vowelFormant[speed]; + const makeupGain = ac.createGain(); + + // var sine = ac.createOscillator(), + // sineGain = ac.createGain(); + + // //set up our oscillator types + // sine.type = sine.SINE; + + // //set the amplitude of the modulation + // sineGain.gain.value = 100; + + // //connect the dots + // sine.connect(sineGain); + if (lfo == null) { + lfo = createLFO(ac, 0.25); + lfoGain = createLFOGain(ac, 4000); + + lfo.connect(lfoGain); + } + // sineGain.connect(saw.frequency); + for (let i = 0; i < 6; i++) { + const gain = ac.createGain(); + gain.gain.value = 0.5; + const filter = createFilter(ac, 1000 + i * 20, 1); + this.connect(filter); + lfoGain.connect(filter.detune); + filter.connect(gain); + gain.connect(makeupGain); + } + makeupGain.gain.value = 1; // how much makeup gain to add? + this.connect = (target) => makeupGain.connect(target); + return this; + } + } + + AudioContext.prototype.createPhaser = function (speed) { + return new PhaserNode(this, speed); + }; +} diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index e3033afe1..3a2156041 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -7,6 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th import './feedbackdelay.mjs'; import './reverb.mjs'; import './vowel.mjs'; +import './phaser.mjs'; import { clamp } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; import { createFilter, gainNode, getCompressor } from './helpers.mjs'; @@ -226,6 +227,9 @@ export const superdough = async (value, deadline, hapDuration) => { bpsustain = 1, bprelease = 0.01, bandq = 1, + + //phaser + phaser, // coarse, crush, @@ -361,10 +365,16 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(vowelFilter); } + if (phaser !== undefined) { + const phaserFX = ac.createPhaser(phaser); + chain.push(phaserFX); + } + // effects coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush })); shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape })); + // phaser !== undefined && chain.push(getWorklet(ac, 'phaser-processor', { phaser })); compressorThreshold !== undefined && chain.push( diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index 7bb43f876..cce524538 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -106,3 +106,36 @@ class ShapeProcessor extends AudioWorkletProcessor { } registerProcessor('shape-processor', ShapeProcessor); + +// class PhaseProcessor extends AudioWorkletProcessor { +// static get parameterDescriptors() { +// return [{ name: 'phaser', defaultValue: 0 }]; +// } + +// constructor() { +// super(); +// this.notStarted = true; +// } + +// process(inputs, outputs, parameters) { +// const input = inputs[0]; +// const output = outputs[0]; +// const phaser0 = parameters.phaser[0]; +// const phaser1 = phaser0 < 1 ? phaser0 : 1.0 - 4e-10; +// const phaser = (2.0 * phaser1) / (1.0 - phaser1); +// const blockSize = 128; +// const hasInput = !(input[0] === undefined); +// if (hasInput) { +// this.notStarted = false; +// for (let n = 0; n < blockSize; n++) { +// const value = ((1 + phaser) * input[0][n]) / (1 + phaser * Math.abs(input[0][n])); +// for (let o = 0; o < output.length; o++) { +// output[o][n] = value; +// } +// } +// } +// return this.notStarted || hasInput; +// } +// } + +// registerProcessor('phaser-processor', PhaseProcessor); From 8c5837e78a7bcd8c13663552f17dbc07578637be Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 5 Nov 2023 12:11:17 +0100 Subject: [PATCH 04/44] add xfade + docs --- packages/core/pattern.mjs | 26 ++++++++++++++++++++++++++ website/src/pages/learn/effects.mdx | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index dcf5da1b5..370776f30 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2392,3 +2392,29 @@ export const ref = (accessor) => pure(1) .withValue(() => reify(accessor())) .innerJoin(); + +let fadeGain = (p) => (p < 0.5 ? 1 : 1 - (p - 0.5) / 0.5); + +/** + * Cross-fades between left and right from 0 to 1: + * - 0 = (full left, no right) + * - .5 = (both equal) + * - 1 = (no left, full right) + * + * @name xfade + * @example + * xfade(s("bd*2"), "<0 .25 .5 .75 1>", s("hh*8")) + */ +export let xfade = (a, pos, b) => { + pos = reify(pos); + a = reify(a); + b = reify(b); + let gaina = pos.fmap((v) => ({ gain: fadeGain(v) })); + let gainb = pos.fmap((v) => ({ gain: fadeGain(1 - v) })); + return stack(a.mul(gaina), b.mul(gainb)); +}; + +// the prototype version is actually flipped so left/right makes sense +Pattern.prototype.xfade = function (pos, b) { + return xfade(this, pos, b); +}; diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index 308042409..b1323a8eb 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -156,6 +156,10 @@ There is one filter envelope for each filter type and thus one set of envelope f +## xfade + + + # Panning ## jux From d7752961b808ce11ec3cfc3de07844c37bfea476 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 5 Nov 2023 12:12:25 +0100 Subject: [PATCH 05/44] snapshot --- test/__snapshots__/examples.test.mjs.snap | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 0963638f8..e920d931b 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -5235,6 +5235,51 @@ exports[`runs examples > example "withValue" example index 0 1`] = ` ] `; +exports[`runs examples > example "xfade" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | s:hh gain:0 ]", + "[ 0/1 → 1/2 | s:bd gain:1 ]", + "[ 1/8 → 1/4 | s:hh gain:0 ]", + "[ 1/4 → 3/8 | s:hh gain:0 ]", + "[ 3/8 → 1/2 | s:hh gain:0 ]", + "[ 1/2 → 5/8 | s:hh gain:0 ]", + "[ 1/2 → 1/1 | s:bd gain:1 ]", + "[ 5/8 → 3/4 | s:hh gain:0 ]", + "[ 3/4 → 7/8 | s:hh gain:0 ]", + "[ 7/8 → 1/1 | s:hh gain:0 ]", + "[ 1/1 → 9/8 | s:hh gain:0.5 ]", + "[ 1/1 → 3/2 | s:bd gain:1 ]", + "[ 9/8 → 5/4 | s:hh gain:0.5 ]", + "[ 5/4 → 11/8 | s:hh gain:0.5 ]", + "[ 11/8 → 3/2 | s:hh gain:0.5 ]", + "[ 3/2 → 13/8 | s:hh gain:0.5 ]", + "[ 3/2 → 2/1 | s:bd gain:1 ]", + "[ 13/8 → 7/4 | s:hh gain:0.5 ]", + "[ 7/4 → 15/8 | s:hh gain:0.5 ]", + "[ 15/8 → 2/1 | s:hh gain:0.5 ]", + "[ 2/1 → 17/8 | s:hh gain:1 ]", + "[ 2/1 → 5/2 | s:bd gain:1 ]", + "[ 17/8 → 9/4 | s:hh gain:1 ]", + "[ 9/4 → 19/8 | s:hh gain:1 ]", + "[ 19/8 → 5/2 | s:hh gain:1 ]", + "[ 5/2 → 21/8 | s:hh gain:1 ]", + "[ 5/2 → 3/1 | s:bd gain:1 ]", + "[ 21/8 → 11/4 | s:hh gain:1 ]", + "[ 11/4 → 23/8 | s:hh gain:1 ]", + "[ 23/8 → 3/1 | s:hh gain:1 ]", + "[ 3/1 → 25/8 | s:hh gain:1 ]", + "[ 3/1 → 7/2 | s:bd gain:0.5 ]", + "[ 25/8 → 13/4 | s:hh gain:1 ]", + "[ 13/4 → 27/8 | s:hh gain:1 ]", + "[ 27/8 → 7/2 | s:hh gain:1 ]", + "[ 7/2 → 29/8 | s:hh gain:1 ]", + "[ 7/2 → 4/1 | s:bd gain:0.5 ]", + "[ 29/8 → 15/4 | s:hh gain:1 ]", + "[ 15/4 → 31/8 | s:hh gain:1 ]", + "[ 31/8 → 4/1 | s:hh gain:1 ]", +] +`; + exports[`runs examples > example "zoom" example index 0 1`] = ` [ "[ 0/1 → 1/6 | s:hh ]", From 7ad0ec1600c5ef6fa7991a7a8116c19f6c03e482 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 5 Nov 2023 12:35:49 +0100 Subject: [PATCH 06/44] fix: namespace mini-repl styles --- website/src/docs/MiniRepl.css | 14 +++++++------- website/src/docs/MiniRepl.jsx | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/website/src/docs/MiniRepl.css b/website/src/docs/MiniRepl.css index 84927a883..c46110b79 100644 --- a/website/src/docs/MiniRepl.css +++ b/website/src/docs/MiniRepl.css @@ -1,26 +1,26 @@ -.cm-activeLine, -.cm-activeLineGutter { +.mini-repl .cm-activeLine, +.mini-repl .cm-activeLineGutter { background-color: transparent !important; } -.cm-theme { +.mini-repl .cm-theme { background-color: var(--background); border: 1px solid var(--lineHighlight); padding: 2px; } -.cm-scroller { +.mini-repl .cm-scroller { font-family: inherit !important; } -.cm-gutters { +.mini-repl .cm-gutters { display: none !important; } -.cm-cursorLayer { +.mini-repl .cm-cursorLayer { animation-name: inherit !important; } -.cm-cursor { +.mini-repl .cm-cursor { border-left: 2px solid currentcolor !important; } diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 251410c5e..4b2fcfa88 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -51,7 +51,7 @@ export function MiniRepl({ .catch((err) => console.error(err)); }, []); return Repl ? ( -
+
Date: Sun, 5 Nov 2023 13:00:54 +0100 Subject: [PATCH 07/44] Implement optional hover tooltip with function documentation --- .../react/src/components/Autocomplete.jsx | 1 - packages/react/src/components/CodeMirror6.jsx | 8 ++- packages/react/src/components/Tooltip.jsx | 69 +++++++++++++++++++ packages/react/src/components/style.css | 4 ++ website/src/repl/Footer.jsx | 6 ++ website/src/repl/Repl.jsx | 2 + website/src/settings.mjs | 2 + 7 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 packages/react/src/components/Tooltip.jsx diff --git a/packages/react/src/components/Autocomplete.jsx b/packages/react/src/components/Autocomplete.jsx index 7ec81d2d1..677baa6e7 100644 --- a/packages/react/src/components/Autocomplete.jsx +++ b/packages/react/src/components/Autocomplete.jsx @@ -26,7 +26,6 @@ export function Autocomplete({ doc }) {
 {
-                console.log('ola!');
                 navigator.clipboard.writeText(example);
                 e.stopPropagation();
               }}
diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx
index 63d4d5a13..667cd7e6b 100644
--- a/packages/react/src/components/CodeMirror6.jsx
+++ b/packages/react/src/components/CodeMirror6.jsx
@@ -9,6 +9,7 @@ import _CodeMirror from '@uiw/react-codemirror';
 import React, { useCallback, useMemo } from 'react';
 import strudelTheme from '../themes/strudel-theme';
 import { strudelAutocomplete } from './Autocomplete';
+import { strudelTooltip } from './Tooltip';
 import {
   highlightExtension,
   flashField,
@@ -33,6 +34,7 @@ export default function CodeMirror({
   keybindings,
   isLineNumbersDisplayed,
   isAutoCompletionEnabled,
+  isTooltipEnabled,
   isLineWrappingEnabled,
   fontSize = 18,
   fontFamily = 'monospace',
@@ -94,6 +96,10 @@ export default function CodeMirror({
       _extensions.push(autocompletion({ override: [] }));
     }
 
+    if (isTooltipEnabled) {
+      _extensions.push(strudelTooltip);
+    }
+
     _extensions.push([keymap.of({})]);
 
     if (isLineWrappingEnabled) {
@@ -101,7 +107,7 @@ export default function CodeMirror({
     }
 
     return _extensions;
-  }, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]);
+  }, [keybindings, isAutoCompletionEnabled, isTooltipEnabled, isLineWrappingEnabled]);
 
   const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
 
diff --git a/packages/react/src/components/Tooltip.jsx b/packages/react/src/components/Tooltip.jsx
new file mode 100644
index 000000000..a443c1231
--- /dev/null
+++ b/packages/react/src/components/Tooltip.jsx
@@ -0,0 +1,69 @@
+import { createRoot } from 'react-dom/client';
+import { hoverTooltip } from '@codemirror/view';
+import jsdoc from '../../../../doc.json';
+import { Autocomplete } from './Autocomplete';
+
+const getDocLabel = (doc) => doc.name || doc.longname;
+
+let ctrlDown = false;
+
+// Record Control key event to trigger or block the tooltip depending on the state
+window.addEventListener(
+  'keyup',
+  function (e) {
+    if (e.key == 'Control') {
+      ctrlDown = false;
+    }
+  },
+  true,
+);
+
+window.addEventListener(
+  'keydown',
+  function (e) {
+    if (e.key == 'Control') {
+      ctrlDown = true;
+    }
+  },
+  true,
+);
+
+export const strudelTooltip = hoverTooltip(
+  (view, pos, side) => {
+    // Word selection from CodeMirror Hover Tooltip example https://codemirror.net/examples/tooltip/#hover-tooltips
+    let { from, to, text } = view.state.doc.lineAt(pos);
+    let start = pos,
+      end = pos;
+    while (start > from && /\w/.test(text[start - from - 1])) {
+      start--;
+    }
+    while (end < to && /\w/.test(text[end - from])) {
+      end++;
+    }
+    if ((start == pos && side < 0) || (end == pos && side > 0)) {
+      return null;
+    }
+    let word = text.slice(start - from, end - from);
+    // Get entry from Strudel documentation
+    let entry = jsdoc.docs.filter((doc) => getDocLabel(doc) === word)[0];
+    if (!entry) {
+      return null;
+    }
+    if (!ctrlDown) {
+      return null;
+    }
+    return {
+      pos: start,
+      end,
+      above: false,
+      arrow: true,
+      create(view) {
+        let dom = document.createElement('div');
+        dom.className = 'strudel-tooltip';
+        createRoot(dom).render();
+        return { dom };
+      },
+    };
+  },
+  { hoverTime: 10 },
+);
diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css
index d61c66190..6336bba32 100644
--- a/packages/react/src/components/style.css
+++ b/packages/react/src/components/style.css
@@ -28,3 +28,7 @@
 footer {
   z-index: 0 !important;
 }
+
+.strudel-tooltip {
+  padding: 5px;
+}
diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx
index 9fb783a49..62dcbcdf4 100644
--- a/website/src/repl/Footer.jsx
+++ b/website/src/repl/Footer.jsx
@@ -385,6 +385,7 @@ function SettingsTab({ scheduler }) {
     keybindings,
     isLineNumbersDisplayed,
     isAutoCompletionEnabled,
+    isTooltipEnabled,
     isLineWrappingEnabled,
     fontSize,
     fontFamily,
@@ -457,6 +458,11 @@ function SettingsTab({ scheduler }) {
           onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
           value={isAutoCompletionEnabled}
         />
+         settingsMap.setKey('isTooltipEnabled', cbEvent.target.checked)}
+          value={isTooltipEnabled}
+        />
          settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx
index d9eb7001e..41d4a35f0 100644
--- a/website/src/repl/Repl.jsx
+++ b/website/src/repl/Repl.jsx
@@ -126,6 +126,7 @@ export function Repl({ embedded = false }) {
     fontFamily,
     isLineNumbersDisplayed,
     isAutoCompletionEnabled,
+    isTooltipEnabled,
     isLineWrappingEnabled,
     panelPosition,
     isZen,
@@ -335,6 +336,7 @@ export function Repl({ embedded = false }) {
               keybindings={keybindings}
               isLineNumbersDisplayed={isLineNumbersDisplayed}
               isAutoCompletionEnabled={isAutoCompletionEnabled}
+              isTooltipEnabled={isTooltipEnabled}
               isLineWrappingEnabled={isLineWrappingEnabled}
               fontSize={fontSize}
               fontFamily={fontFamily}
diff --git a/website/src/settings.mjs b/website/src/settings.mjs
index 5608b8943..ab58494cb 100644
--- a/website/src/settings.mjs
+++ b/website/src/settings.mjs
@@ -7,6 +7,7 @@ export const defaultSettings = {
   keybindings: 'codemirror',
   isLineNumbersDisplayed: true,
   isAutoCompletionEnabled: false,
+  isTooltipEnabled: false,
   isLineWrappingEnabled: false,
   theme: 'strudelTheme',
   fontFamily: 'monospace',
@@ -26,6 +27,7 @@ export function useSettings() {
     isZen: [true, 'true'].includes(state.isZen) ? true : false,
     isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
     isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
+    isTooltipEnabled: [true, 'true'].includes(state.isTooltipEnabled) ? true : false,
     isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false,
     fontSize: Number(state.fontSize),
     panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom',

From 624e540cb4a6b85cc3f8464bc96dcb1b40ae8ba1 Mon Sep 17 00:00:00 2001
From: "Alexandre G.-Raymond" 
Date: Sun, 5 Nov 2023 16:23:00 +0100
Subject: [PATCH 08/44] Add pianoroll function documentation

---
 packages/core/pianoroll.mjs               | 34 +++++++++++++++++++++++
 test/__snapshots__/examples.test.mjs.snap | 33 ++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/packages/core/pianoroll.mjs b/packages/core/pianoroll.mjs
index f3d2c38a2..2ea5727ba 100644
--- a/packages/core/pianoroll.mjs
+++ b/packages/core/pianoroll.mjs
@@ -56,6 +56,40 @@ Pattern.prototype.pianoroll = function (options = {}) {
 
 // this function allows drawing a pianoroll without ties to Pattern.prototype
 // it will probably replace the above in the future
+
+/**
+ * Displays a midi-style piano roll
+ *
+ * @name pianoroll
+ * @param {Object} options Object containing all the optional following parameters as key value pairs:
+ * @param {integer} cycles defaults to 4 - number of cycles to be displayed at the same time
+ * @param {number} playhead 0 to 1, defaults to 0.5 - location of the active notes on the time axis
+ * @param {integer} vertical 0 (default) or 1 - displays the roll vertically
+ * @param {boolean} labels false (default) or true - displays labels on individual notes (see the label function)
+ * @param {integer} flipTime 0 (default) or 1 - reverse the direction of the roll
+ * @param {integer} flipValues 0 (default) or 1 - reverse the relative location of notes on the value axis
+ * @param {number} overscan 1 (default) - lookup X cycles outside of the cycles window to display notes in advance
+ * @param {boolean} hideNegative false (default) or true - hide notes with negative time (before starting playing the pattern)
+ * @param {integer} smear 0 (default) or 1 - notes leave a solid trace
+ * @param {integer} fold 0 (default) or 1 - notes takes the full value axis width
+ * @param {string} active hexadecimal or CSS color (defaults to #FFCA28) - color of the active notes
+ * @param {string} inactive hexadecimal or CSS color (defaults to #7491D2) - color of the inactive notes
+ * @param {string} background hexadecimal or CSS color (defaults to transparent) - color of the background
+ * @param {string} playheadColor hexadecimal or CSS color (defaults to transparent) - color of the line representing the play head
+ * @param {integer} fill 1 (default) or 0 - notes are filled with color (otherwise only the label is displayed)
+ * @param {boolean} fillActive: false (default) or true - active notes are filled with color
+ * @param {integer} stroke 0 (default) or 1 - notes are shown with colored borders
+ * @param {boolean} strokeActive: false (default) or true - active notes are shown with colored borders
+ * @param {integer} hideInactive 0 (default) or 1 - only active notes are shown
+ * @param {integer} colorizeInactive 1 (default) or 0 - use note color for inactive notes
+ * @param {string} fontFamily: defaults to 'monospace' - define the font used by notes labels
+ * @param {integer} minMidi integer, defaults to 10 - minimum note value to display on the value axis
+ * @param {integer} maxMidi integer, defaults to 90 - maximum note value to display on the value axis
+ * @param {integer} autorange 0 (default) or 1 - automatically calculate the minMidi and maxMidi parameters
+ *
+ * @example
+ * note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1})
+ */
 export function pianoroll({
   time,
   haps,
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 0963638f8..5d485210e 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -3297,6 +3297,39 @@ exports[`runs examples > example "perlin" example index 0 1`] = `
 ]
 `;
 
+exports[`runs examples > example "pianoroll" example index 0 1`] = `
+[
+  "[ 0/1 → 1/8 | note:C2 s:piano clip:1 ]",
+  "[ (1/4 → 1/3) ⇝ 3/8 | note:C2 s:piano clip:1 ]",
+  "[ 1/4 ⇜ (1/3 → 3/8) | note:A2 s:piano clip:1 ]",
+  "[ 3/8 → 1/2 | note:A2 s:piano clip:1 ]",
+  "[ (5/8 → 2/3) ⇝ 3/4 | note:A2 s:piano clip:1 ]",
+  "[ 5/8 ⇜ (2/3 → 3/4) | note:G2 s:piano clip:1 ]",
+  "[ 3/4 → 7/8 | note:G2 s:piano clip:1 ]",
+  "[ 1/1 → 9/8 | note:C2 s:piano clip:1 ]",
+  "[ (5/4 → 4/3) ⇝ 11/8 | note:C2 s:piano clip:1 ]",
+  "[ 5/4 ⇜ (4/3 → 11/8) | note:A2 s:piano clip:1 ]",
+  "[ 11/8 → 3/2 | note:A2 s:piano clip:1 ]",
+  "[ (13/8 → 5/3) ⇝ 7/4 | note:A2 s:piano clip:1 ]",
+  "[ 13/8 ⇜ (5/3 → 7/4) | note:G2 s:piano clip:1 ]",
+  "[ 7/4 → 15/8 | note:G2 s:piano clip:1 ]",
+  "[ 2/1 → 17/8 | note:C2 s:piano clip:1 ]",
+  "[ (9/4 → 7/3) ⇝ 19/8 | note:C2 s:piano clip:1 ]",
+  "[ 9/4 ⇜ (7/3 → 19/8) | note:A2 s:piano clip:1 ]",
+  "[ 19/8 → 5/2 | note:A2 s:piano clip:1 ]",
+  "[ (21/8 → 8/3) ⇝ 11/4 | note:A2 s:piano clip:1 ]",
+  "[ 21/8 ⇜ (8/3 → 11/4) | note:G2 s:piano clip:1 ]",
+  "[ 11/4 → 23/8 | note:G2 s:piano clip:1 ]",
+  "[ 3/1 → 25/8 | note:C2 s:piano clip:1 ]",
+  "[ (13/4 → 10/3) ⇝ 27/8 | note:C2 s:piano clip:1 ]",
+  "[ 13/4 ⇜ (10/3 → 27/8) | note:A2 s:piano clip:1 ]",
+  "[ 27/8 → 7/2 | note:A2 s:piano clip:1 ]",
+  "[ (29/8 → 11/3) ⇝ 15/4 | note:A2 s:piano clip:1 ]",
+  "[ 29/8 ⇜ (11/3 → 15/4) | note:G2 s:piano clip:1 ]",
+  "[ 15/4 → 31/8 | note:G2 s:piano clip:1 ]",
+]
+`;
+
 exports[`runs examples > example "pick" example index 0 1`] = `
 [
   "[ 0/1 → 1/2 | note:g ]",

From 0d06840a1bc496b9c50c280ec88340193854d73c Mon Sep 17 00:00:00 2001
From: "Alexandre G.-Raymond" 
Date: Sun, 5 Nov 2023 16:23:21 +0100
Subject: [PATCH 09/44] Add label function documentation

---
 packages/core/controls.mjs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 1ca49bb6a..866be4fb1 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -867,7 +867,12 @@ const generic_params = [
    *
    */
   ['lsize'],
-  // label for pianoroll
+  /**
+   * Sets the displayed text for an event on the pianoroll
+   *
+   * @name label
+   * @param {string} label text to display
+   */
   ['activeLabel'],
   [['label', 'activeLabel']],
   // ['lfo'],

From f045fb44de8dfc3b0e23d131d3fe33f69ef35114 Mon Sep 17 00:00:00 2001
From: "Alexandre G.-Raymond" 
Date: Sun, 5 Nov 2023 16:23:36 +0100
Subject: [PATCH 10/44] Add color function documentation

---
 packages/core/pattern.mjs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index dcf5da1b5..f09b89b94 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -2191,6 +2191,9 @@ export const duration = register('duration', function (value, pat) {
 
 /**
  * Sets the color of the hap in visualizations like pianoroll or highlighting.
+ * @name color
+ * @synonyms colour
+ * @param {string} color Hexadecimal or CSS color name
  */
 // TODO: move this to controls https://github.com/tidalcycles/strudel/issues/288
 export const { color, colour } = register(['color', 'colour'], function (color, pat) {

From 8fa7bf795a6760a23defb33ee69c3fd824807298 Mon Sep 17 00:00:00 2001
From: "Alexandre G.-Raymond" 
Date: Sun, 5 Nov 2023 16:25:10 +0100
Subject: [PATCH 11/44] Fix pianoroll documentation

---
 packages/core/pianoroll.mjs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/core/pianoroll.mjs b/packages/core/pianoroll.mjs
index 2ea5727ba..60cab07c2 100644
--- a/packages/core/pianoroll.mjs
+++ b/packages/core/pianoroll.mjs
@@ -77,12 +77,12 @@ Pattern.prototype.pianoroll = function (options = {}) {
  * @param {string} background hexadecimal or CSS color (defaults to transparent) - color of the background
  * @param {string} playheadColor hexadecimal or CSS color (defaults to transparent) - color of the line representing the play head
  * @param {integer} fill 1 (default) or 0 - notes are filled with color (otherwise only the label is displayed)
- * @param {boolean} fillActive: false (default) or true - active notes are filled with color
+ * @param {boolean} fillActive false (default) or true - active notes are filled with color
  * @param {integer} stroke 0 (default) or 1 - notes are shown with colored borders
- * @param {boolean} strokeActive: false (default) or true - active notes are shown with colored borders
+ * @param {boolean} strokeActive false (default) or true - active notes are shown with colored borders
  * @param {integer} hideInactive 0 (default) or 1 - only active notes are shown
  * @param {integer} colorizeInactive 1 (default) or 0 - use note color for inactive notes
- * @param {string} fontFamily: defaults to 'monospace' - define the font used by notes labels
+ * @param {string} fontFamily defaults to 'monospace' - define the font used by notes labels
  * @param {integer} minMidi integer, defaults to 10 - minimum note value to display on the value axis
  * @param {integer} maxMidi integer, defaults to 90 - maximum note value to display on the value axis
  * @param {integer} autorange 0 (default) or 1 - automatically calculate the minMidi and maxMidi parameters

From e9265eff35a02a90c4bfe526b2a94a4c0e1fc66c Mon Sep 17 00:00:00 2001
From: "Alexandre G.-Raymond" 
Date: Sun, 5 Nov 2023 16:40:46 +0100
Subject: [PATCH 12/44] Add function params in reference tab

---
 website/src/repl/Reference.jsx | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/website/src/repl/Reference.jsx b/website/src/repl/Reference.jsx
index de52982e9..001166233 100644
--- a/website/src/repl/Reference.jsx
+++ b/website/src/repl/Reference.jsx
@@ -3,6 +3,12 @@ const visibleFunctions = jsdocJson.docs
   .filter(({ name, description }) => name && !name.startsWith('_') && !!description)
   .sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) +  */ a.name.localeCompare(b.name));
 
+const getInnerText = (html) => {
+  var div = document.createElement('div');
+  div.innerHTML = html;
+  return div.textContent || div.innerText || '';
+};
+
 export function Reference() {
   return (
     
@@ -24,8 +30,14 @@ export function Reference() {

{entry.name}

{/* {entry.meta.filename} */} -

+
    + {entry.params?.map(({ name, type, description }, i) => ( +
  • + {name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)} : ''} +
  • + ))} +
{entry.examples?.map((example, j) => (
{example}
))} From 8fe4dca4c21a7c8544a979a87807531a9b77d30f Mon Sep 17 00:00:00 2001 From: "Alexandre G.-Raymond" Date: Sun, 5 Nov 2023 18:07:42 +0100 Subject: [PATCH 13/44] Update pianoroll documentation --- packages/core/pianoroll.mjs | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/core/pianoroll.mjs b/packages/core/pianoroll.mjs index 60cab07c2..c10460a49 100644 --- a/packages/core/pianoroll.mjs +++ b/packages/core/pianoroll.mjs @@ -62,30 +62,30 @@ Pattern.prototype.pianoroll = function (options = {}) { * * @name pianoroll * @param {Object} options Object containing all the optional following parameters as key value pairs: - * @param {integer} cycles defaults to 4 - number of cycles to be displayed at the same time - * @param {number} playhead 0 to 1, defaults to 0.5 - location of the active notes on the time axis - * @param {integer} vertical 0 (default) or 1 - displays the roll vertically - * @param {boolean} labels false (default) or true - displays labels on individual notes (see the label function) - * @param {integer} flipTime 0 (default) or 1 - reverse the direction of the roll - * @param {integer} flipValues 0 (default) or 1 - reverse the relative location of notes on the value axis - * @param {number} overscan 1 (default) - lookup X cycles outside of the cycles window to display notes in advance - * @param {boolean} hideNegative false (default) or true - hide notes with negative time (before starting playing the pattern) - * @param {integer} smear 0 (default) or 1 - notes leave a solid trace - * @param {integer} fold 0 (default) or 1 - notes takes the full value axis width - * @param {string} active hexadecimal or CSS color (defaults to #FFCA28) - color of the active notes - * @param {string} inactive hexadecimal or CSS color (defaults to #7491D2) - color of the inactive notes - * @param {string} background hexadecimal or CSS color (defaults to transparent) - color of the background - * @param {string} playheadColor hexadecimal or CSS color (defaults to transparent) - color of the line representing the play head - * @param {integer} fill 1 (default) or 0 - notes are filled with color (otherwise only the label is displayed) - * @param {boolean} fillActive false (default) or true - active notes are filled with color - * @param {integer} stroke 0 (default) or 1 - notes are shown with colored borders - * @param {boolean} strokeActive false (default) or true - active notes are shown with colored borders - * @param {integer} hideInactive 0 (default) or 1 - only active notes are shown - * @param {integer} colorizeInactive 1 (default) or 0 - use note color for inactive notes - * @param {string} fontFamily defaults to 'monospace' - define the font used by notes labels - * @param {integer} minMidi integer, defaults to 10 - minimum note value to display on the value axis - * @param {integer} maxMidi integer, defaults to 90 - maximum note value to display on the value axis - * @param {integer} autorange 0 (default) or 1 - automatically calculate the minMidi and maxMidi parameters + * @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4 + * @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5 + * @param {boolean} vertical displays the roll vertically - 0 by default + * @param {boolean} labels displays labels on individual notes (see the label function) - 0 by default + * @param {boolean} flipTime reverse the direction of the roll - 0 by default + * @param {boolean} flipValues reverse the relative location of notes on the value axis - 0 by default + * @param {number} overscan lookup X cycles outside of the cycles window to display notes in advance - 1 by default + * @param {boolean} hideNegative hide notes with negative time (before starting playing the pattern) - 0 by default + * @param {boolean} smear notes leave a solid trace - 0 by default + * @param {boolean} fold notes takes the full value axis width - 0 by default + * @param {string} active hexadecimal or CSS color of the active notes - defaults to #FFCA28 + * @param {string} inactive hexadecimal or CSS color of the inactive notes - defaults to #7491D2 + * @param {string} background hexadecimal or CSS color of the background - defaults to transparent + * @param {string} playheadColor hexadecimal or CSS color of the line representing the play head - defaults to white + * @param {boolean} fill notes are filled with color (otherwise only the label is displayed) - 0 by default + * @param {boolean} fillActive active notes are filled with color - 0 by default + * @param {boolean} stroke notes are shown with colored borders - 0 by default + * @param {boolean} strokeActive active notes are shown with colored borders - 0 by default + * @param {boolean} hideInactive only active notes are shown - 0 by default + * @param {boolean} colorizeInactive use note color for inactive notes - 1 by default + * @param {string} fontFamily define the font used by notes labels - defaults to 'monospace' + * @param {integer} minMidi minimum note value to display on the value axis - defaults to 10 + * @param {integer} maxMidi maximum note value to display on the value axis - defaults to 90 + * @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default * * @example * note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1}) From a9efda3bc36619ec005aab5f9a7bb02b2f33e4f9 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Sun, 5 Nov 2023 15:40:02 -0500 Subject: [PATCH 14/44] tweaking to make it sound good --- packages/superdough/phaser.mjs | 78 ++++++++++-------------------- packages/superdough/superdough.mjs | 2 +- 2 files changed, 27 insertions(+), 53 deletions(-) diff --git a/packages/superdough/phaser.mjs b/packages/superdough/phaser.mjs index 62771df3f..bdb64c401 100644 --- a/packages/superdough/phaser.mjs +++ b/packages/superdough/phaser.mjs @@ -1,14 +1,5 @@ -// credits to webdirt: https://github.com/dktr0/WebDirt/blob/41342e81d6ad694a2310d491fef7b7e8b0929efe/js-src/Graph.js#L597 -export var vowelFormant = { - 0: { freqs: [660, 1120, 2750, 3000, 3350], gains: [1, 0.5012, 0.0708, 0.0631, 0.0126], qs: [80, 90, 120, 130, 140] }, - 1: { freqs: [440, 1800, 2700, 3000, 3300], gains: [1, 0.1995, 0.1259, 0.1, 0.1], qs: [70, 80, 100, 120, 120] }, - 2: { freqs: [270, 1850, 2900, 3350, 3590], gains: [1, 0.0631, 0.0631, 0.0158, 0.0158], qs: [40, 90, 100, 120, 120] }, - 3: { freqs: [430, 820, 2700, 3000, 3300], gains: [1, 0.3162, 0.0501, 0.0794, 0.01995], qs: [40, 80, 100, 120, 120] }, - 4: { freqs: [370, 630, 2750, 3000, 3400], gains: [1, 0.1, 0.0708, 0.0316, 0.01995], qs: [40, 60, 100, 120, 120] }, -}; - -var createFilter = function (ctx, cutoff, Q) { - var lowpassFilter = ctx.createBiquadFilter(); +const createFilter = (ctx, cutoff, Q) => { + const lowpassFilter = ctx.createBiquadFilter(); lowpassFilter.type = 'notch'; lowpassFilter.gain.value = 1; lowpassFilter.frequency.value = cutoff; @@ -16,65 +7,48 @@ var createFilter = function (ctx, cutoff, Q) { return lowpassFilter; }; -// var createTriOscillator = function (freq) { -// var osc = ctx.createOscillator(); -// osc.type = 'triangle'; -// osc.frequency.value = freq * 1.0; -// osc.detune.value = 0; -// return osc; -// }; - -var createLFO = function (ctx, freq) { - var osc = ctx.createOscillator(); +const createOscillator = (ctx, freq) => { + const osc = ctx.createOscillator(); osc.frequency.value = freq; osc.type = 'sine'; - osc.start(); return osc; }; -var createLFOGain = function (ctx, gain) { - var gainNode = ctx.createGain(); +const createGain = (ctx, gain) => { + const gainNode = ctx.createGain(); gainNode.gain.value = gain; return gainNode; }; -let lfo, lfoGain; + +const createLFO = (ctx, freq, gain) => { + const osc = createOscillator(ctx, freq); + const gainNode = createGain(ctx, gain); + osc.start(); + osc.connect(gainNode); + return gainNode; +}; if (typeof GainNode !== 'undefined') { class PhaserNode extends GainNode { - constructor(ac, speed) { + constructor(ac, speed, cps) { super(ac); - console.log('speed', speed); + this.lfo; + console.log(cps); - if (!vowelFormant[speed]) { - throw new Error('phaser: unknown phaser ' + speed); - } - const { gains, qs, freqs } = vowelFormant[speed]; const makeupGain = ac.createGain(); - // var sine = ac.createOscillator(), - // sineGain = ac.createGain(); - - // //set up our oscillator types - // sine.type = sine.SINE; - - // //set the amplitude of the modulation - // sineGain.gain.value = 100; - - // //connect the dots - // sine.connect(sineGain); - if (lfo == null) { - lfo = createLFO(ac, 0.25); - lfoGain = createLFOGain(ac, 4000); - - lfo.connect(lfoGain); + if (this.lfo == null) { + this.lfo = createLFO(ac, speed, 2000); } - // sineGain.connect(saw.frequency); - for (let i = 0; i < 6; i++) { + const numStages = 2; + let fOffset = 0; + for (let i = 0; i < numStages; i++) { const gain = ac.createGain(); - gain.gain.value = 0.5; - const filter = createFilter(ac, 1000 + i * 20, 1); + gain.gain.value = 1 / numStages; + const filter = createFilter(ac, 1000 + fOffset, 0.5); this.connect(filter); - lfoGain.connect(filter.detune); + this.lfo.connect(filter.detune); filter.connect(gain); gain.connect(makeupGain); + fOffset += 200 + Math.pow(i, 2); } makeupGain.gain.value = 1; // how much makeup gain to add? this.connect = (target) => makeupGain.connect(target); diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 3a2156041..5473cc12e 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -366,7 +366,7 @@ export const superdough = async (value, deadline, hapDuration) => { } if (phaser !== undefined) { - const phaserFX = ac.createPhaser(phaser); + const phaserFX = ac.createPhaser(phaser, hapDuration); chain.push(phaserFX); } From 52e2b90eefa68ea3ba56ab299b55d0725f66656a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 5 Nov 2023 22:22:35 +0100 Subject: [PATCH 15/44] fix: scope pos --- packages/webaudio/scope.mjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/webaudio/scope.mjs b/packages/webaudio/scope.mjs index 9f052e8ee..3fce64d5b 100644 --- a/packages/webaudio/scope.mjs +++ b/packages/webaudio/scope.mjs @@ -22,10 +22,9 @@ export function drawTimeScope( const sliceWidth = (canvas.width * 1.0) / bufferSize; let x = 0; - for (let i = triggerIndex; i < bufferSize; i++) { const v = dataArray[i] + 1; - const y = (1 - (scale * (v - 1) + pos)) * canvas.height; + const y = (pos - scale * (v - 1)) * canvas.height; if (i === 0) { ctx.moveTo(x, y); From 26d87b691cbb19c9c308bb8fb0a94bb85a2abdbe Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 5 Nov 2023 22:43:37 +0100 Subject: [PATCH 16/44] document scope functions --- packages/webaudio/scope.mjs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/webaudio/scope.mjs b/packages/webaudio/scope.mjs index 3fce64d5b..1affd2624 100644 --- a/packages/webaudio/scope.mjs +++ b/packages/webaudio/scope.mjs @@ -3,7 +3,7 @@ import { analyser, getAnalyzerData } from 'superdough'; export function drawTimeScope( analyser, - { align = true, color = 'white', thickness = 3, scale = 0.25, pos = 0.75, next = 1, trigger = 0 } = {}, + { align = true, color = 'white', thickness = 3, scale = 0.25, pos = 0.75, trigger = 0 } = {}, ) { const ctx = getDrawContext(); const dataArray = getAnalyzerData('time'); @@ -70,6 +70,18 @@ function clearScreen(smear = 0, smearRGB = `0,0,0`) { } } +/** + * Renders an oscilloscope for the frequency domain of the audio signal. + * @name fscope + * @param {string} color line color as hex or color name. defaults to white. + * @param {number} scale scales the y-axis. Defaults to 0.25 + * @param {number} pos y-position relative to screen height. 0 = top, 1 = bottom of screen + * @param {number} lean y-axis alignment where 0 = top and 1 = bottom + * @param {number} min min value + * @param {number} max max value + * @example + * s("sawtooth").fscope() + */ Pattern.prototype.fscope = function (config = {}) { return this.analyze(1).draw(() => { clearScreen(config.smear); @@ -77,6 +89,20 @@ Pattern.prototype.fscope = function (config = {}) { }); }; +/** + * Renders an oscilloscope for the time domain of the audio signal. + * @name scope + * @synonyms tscope + * @param {object} config optional config with options: + * @param {boolean} align if 1, the scope will be aligned to the first zero crossing. defaults to 1 + * @param {string} color line color as hex or color name. defaults to white. + * @param {number} thickness line thickness. defaults to 3 + * @param {number} scale scales the y-axis. Defaults to 0.25 + * @param {number} pos y-position relative to screen height. 0 = top, 1 = bottom of screen + * @param {number} trigger amplitude value that is used to align the scope. defaults to 0. + * @example + * s("sawtooth").scope() + */ Pattern.prototype.tscope = function (config = {}) { return this.analyze(1).draw(() => { clearScreen(config.smear); From c4f26c3cadd462749a3acc9577ed73d10d0f7566 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 5 Nov 2023 22:46:16 +0100 Subject: [PATCH 17/44] snapshot --- test/__snapshots__/examples.test.mjs.snap | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index e920d931b..39b9456f3 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2143,6 +2143,15 @@ exports[`runs examples > example "freq" example index 1 1`] = ` ] `; +exports[`runs examples > example "fscope" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | s:sawtooth analyze:1 ]", + "[ 1/1 → 2/1 | s:sawtooth analyze:1 ]", + "[ 2/1 → 3/1 | s:sawtooth analyze:1 ]", + "[ 3/1 → 4/1 | s:sawtooth analyze:1 ]", +] +`; + exports[`runs examples > example "ftype" example index 0 1`] = ` [ "[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 bpenv:4 ftype:12db ]", @@ -4235,6 +4244,15 @@ exports[`runs examples > example "scaleTranspose" example index 0 1`] = ` ] `; +exports[`runs examples > example "scope" example index 0 1`] = ` +[ + "[ 0/1 → 1/1 | s:sawtooth analyze:1 ]", + "[ 1/1 → 2/1 | s:sawtooth analyze:1 ]", + "[ 2/1 → 3/1 | s:sawtooth analyze:1 ]", + "[ 3/1 → 4/1 | s:sawtooth analyze:1 ]", +] +`; + exports[`runs examples > example "segment" example index 0 1`] = ` [ "[ 0/1 → 1/24 | note:40.25 ]", From 2ef35a8583eb3c462b2ece709110ae2e50baad87 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 6 Nov 2023 22:17:33 +0100 Subject: [PATCH 18/44] samples loading shortcuts: - use main branch by default in github shortcut - add bubo shortcut --- packages/superdough/sampler.mjs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index d0733b148..cbc591fb0 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -162,9 +162,17 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option if (handler) { return handler(sampleMap); } + if (sampleMap.startsWith('bubo:')) { + const [_, repo] = sampleMap.split(':'); + sampleMap = `github:Bubobubobubobubo/dough-${repo}`; + } if (sampleMap.startsWith('github:')) { let [_, path] = sampleMap.split('github:'); path = path.endsWith('/') ? path.slice(0, -1) : path; + if (path.split('/').length === 2) { + // assume main as default branch if none set + path += '/main'; + } sampleMap = `https://raw.githubusercontent.com/${path}/strudel.json`; } if (sampleMap.startsWith('shabda:')) { From 07da9a9dd28d75971173a0ef20c7647d4ee1b27e Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Mon, 6 Nov 2023 23:13:10 +0100 Subject: [PATCH 19/44] don't use anchor links for reference --- website/src/repl/Reference.jsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/website/src/repl/Reference.jsx b/website/src/repl/Reference.jsx index 001166233..cf6fd5b12 100644 --- a/website/src/repl/Reference.jsx +++ b/website/src/repl/Reference.jsx @@ -14,12 +14,20 @@ export function Reference() {
-
+

API Reference

From 9cbf3079f3bca2bc7cb2ee2192d86c883514a369 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Mon, 6 Nov 2023 19:02:09 -0500 Subject: [PATCH 20/44] change to bus effect experiment --- packages/core/controls.mjs | 16 ++++-- packages/superdough/phaser.mjs | 21 ++++---- packages/superdough/superdough.mjs | 82 ++++++++++++++++++++++++++++-- 3 files changed, 102 insertions(+), 17 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index a616ce068..e3fa8be1f 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -382,15 +382,25 @@ const generic_params = [ ['coarse'], /** - * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers + * Phaser audio effect that approximates popular guitar pedals. * * @name phaser - * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. + * @param {number | Pattern} speed speed of modulation * @example - * s("bd sd,hh*4").coarse("<1 4 8 16 32>") + * run(8).scale("D:pentatonic").note().sound("sawtooth").phaser("2 8").release(0.5) * */ ['phaser'], + /** + * + * + * @name phaserDepth + * @param {number | Pattern} depth number between 0 and 1 + * @example + * run(8).scale("D:pentatonic").note().sound("sawtooth").phaser("2 8").phaserDepth(0.5).release(0.5) + * + */ + ['phaserDepth'], /** * choose the channel the pattern is sent to in superdirt * diff --git a/packages/superdough/phaser.mjs b/packages/superdough/phaser.mjs index bdb64c401..9aadc5328 100644 --- a/packages/superdough/phaser.mjs +++ b/packages/superdough/phaser.mjs @@ -1,10 +1,10 @@ const createFilter = (ctx, cutoff, Q) => { - const lowpassFilter = ctx.createBiquadFilter(); - lowpassFilter.type = 'notch'; - lowpassFilter.gain.value = 1; - lowpassFilter.frequency.value = cutoff; - lowpassFilter.Q.value = Q; - return lowpassFilter; + const filter = ctx.createBiquadFilter(); + filter.type = 'notch'; + filter.gain.value = 1; + filter.frequency.value = cutoff; + filter.Q.value = Q; + return filter; }; const createOscillator = (ctx, freq) => { @@ -26,12 +26,15 @@ const createLFO = (ctx, freq, gain) => { osc.connect(gainNode); return gainNode; }; + if (typeof GainNode !== 'undefined') { class PhaserNode extends GainNode { - constructor(ac, speed, cps) { + constructor(ac, input) { super(ac); this.lfo; - console.log(cps); + + const { speed, depth = 0.5 } = input; + console.log(depth); const makeupGain = ac.createGain(); @@ -43,7 +46,7 @@ if (typeof GainNode !== 'undefined') { for (let i = 0; i < numStages; i++) { const gain = ac.createGain(); gain.gain.value = 1 / numStages; - const filter = createFilter(ac, 1000 + fOffset, 0.5); + const filter = createFilter(ac, 1000 + fOffset, 2 - Math.min(Math.max(depth * 2, 0), 1.9)); this.connect(filter); this.lfo.connect(filter.detune); filter.connect(gain); diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 5473cc12e..8ea283401 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -113,6 +113,71 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } +const createFilter2 = (ctx, cutoff, Q) => { + const filter = ctx.createBiquadFilter(); + filter.type = 'notch'; + filter.gain.value = 1; + filter.frequency.value = cutoff; + filter.Q.value = Q; + return filter; +}; + +const createOscillator = (ctx, freq) => { + const osc = ctx.createOscillator(); + osc.frequency.value = freq; + osc.type = 'sine'; + return osc; +}; +const createGain = (ctx, gain) => { + const gainNode = ctx.createGain(); + gainNode.gain.value = gain; + return gainNode; +}; + +const createLFO = (ctx, freq, gain) => { + const osc = createOscillator(ctx, freq); + const gainNode = createGain(ctx, gain); + osc.start(); + osc.connect(gainNode); + return gainNode; +}; + +let phasers = {}; + +function getPhaser(orbit, speed = 1, depth = 0.5) { + if (!delays[orbit]) { + const ac = getAudioContext(); + + let lfo; + + const makeupGain = ac.createGain(); + + if (lfo == null) { + lfo = createLFO(ac, speed, 2000); + } + const numStages = 2; + let fOffset = 0; + for (let i = 0; i < numStages; i++) { + const gain = ac.createGain(); + gain.gain.value = 1 / numStages; + const filter = createFilter2(ac, 1000 + fOffset, 2 - Math.min(Math.max(depth * 2, 0), 1.9)); + makeupGain.connect(filter); + lfo.connect(filter.detune); + filter.connect(gain); + gain.connect(makeupGain); + fOffset += 200 + Math.pow(i, 2); + } + makeupGain.gain.value = 1; // how much makeup gain to add? + + makeupGain.connect(getDestination()); + phasers[orbit] = makeupGain; + } + console.log(phasers); + // delays[orbit].delayTime.value !== delaytime && delays[orbit].delayTime.setValueAtTime(delaytime, t); + // delays[orbit].feedback.value !== delayfeedback && delays[orbit].feedback.setValueAtTime(delayfeedback, t); + return phasers[orbit]; +} + let reverbs = {}; let hasChanged = (now, before) => now !== undefined && now !== before; @@ -230,6 +295,7 @@ export const superdough = async (value, deadline, hapDuration) => { //phaser phaser, + phaserDepth, // coarse, crush, @@ -365,10 +431,10 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(vowelFilter); } - if (phaser !== undefined) { - const phaserFX = ac.createPhaser(phaser, hapDuration); - chain.push(phaserFX); - } + // if (phaser !== undefined) { + // const phaserFX = ac.createPhaser({ speed: phaser, depth: phaserDepth }); + // chain.push(phaserFX); + // } // effects coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); @@ -393,6 +459,12 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(post); post.connect(getDestination()); + let phaserSend; + if (phaser != null) { + const phaserFX = getPhaser(orbit, phaser, phaserDepth); + + phaserSend = effectSend(post, phaserFX, 0.99); + } // delay let delaySend; if (delay > 0 && delaytime > 0 && delayfeedback > 0) { @@ -429,7 +501,7 @@ export const superdough = async (value, deadline, hapDuration) => { // toDisconnect = all the node that should be disconnected in onended callback // this is crucial for performance - toDisconnect = chain.concat([delaySend, reverbSend, analyserSend]); + toDisconnect = chain.concat([phaserSend, delaySend, reverbSend, analyserSend]); }; export const superdoughTrigger = (t, hap, ct, cps) => superdough(hap, t - ct, hap.duration / cps, cps); From b88f58cc211e67dfc226282882aba65449a5eed2 Mon Sep 17 00:00:00 2001 From: Bernhard Wagner Date: Tue, 7 Nov 2023 11:38:13 +0100 Subject: [PATCH 21/44] Update first-sounds.mdx in eine sogenannte Funktion -> in einer sogenannten Funktion --- website/src/pages/de/workshop/first-sounds.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/pages/de/workshop/first-sounds.mdx b/website/src/pages/de/workshop/first-sounds.mdx index fea64cbd4..a689add80 100644 --- a/website/src/pages/de/workshop/first-sounds.mdx +++ b/website/src/pages/de/workshop/first-sounds.mdx @@ -277,7 +277,7 @@ Das haben wir bisher gelernt: | Schneller | \* | | | Parallel | , | | -Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in eine sogenannten Funktion. +Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in einer sogenannten Funktion. Die folgenden Funktionen haben wir bereits gesehen: | Name | Description | Example | From eed2c304e483f4f920163565b90b7b7cc123fcba Mon Sep 17 00:00:00 2001 From: Bernhard Wagner Date: Tue, 7 Nov 2023 15:57:31 +0100 Subject: [PATCH 22/44] Update first-effects.mdx grammatical amendments --- .../src/pages/de/workshop/first-effects.mdx | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/website/src/pages/de/workshop/first-effects.mdx b/website/src/pages/de/workshop/first-effects.mdx index 7719249aa..b408a343e 100644 --- a/website/src/pages/de/workshop/first-effects.mdx +++ b/website/src/pages/de/workshop/first-effects.mdx @@ -25,7 +25,7 @@ import Box from '@components/Box.astro'; lpf = **l**ow **p**ass **f**ilter -- Ändere `lpf` in 200. Hörst du wie der Bass dumpfer klingt? Es klingt so ähnlich als würde die Musik hinter einer geschlossenen Tür laufen 🚪 +- Ändere `lpf` in 200. Hörst du, wie der Bass dumpfer klingt? Es klingt so, als würde die Musik hinter einer geschlossenen Tür spielen 🚪 - Lass uns nun die Tür öffnen: Ändere `lpf` in 5000. Der Klang wird dadurch viel heller und schärfer ✨🪩 @@ -42,9 +42,9 @@ lpf = **l**ow **p**ass **f**ilter - Füg noch mehr `lpf` Werte hinzu -- Das pattern in `lpf` ändert nicht den Rhythmus der Bassline +- Das Pattern in `lpf` ändert nicht den Rhythmus der Basslinie -Später sehen wir wie man mit Wellenformen Dinge automatisieren kann. +Später sehen wir, wie man mit Wellenformen Dinge automatisieren kann. @@ -73,7 +73,7 @@ Später sehen wir wie man mit Wellenformen Dinge automatisieren kann. Bei Rhythmen ist die Dynamik (= Veränderungen der Lautstärke) sehr wichtig. -- Entferne `.gain(...)` und achte darauf wie es viel flacher klingt. +- Entferne `.gain(...)` und achte darauf, wie es viel flacher klingt. - Mach es rückgängig (strg+z dann strg+enter) @@ -99,13 +99,13 @@ Lass uns die obigen Beispiele kombinieren: -Versuche die einzelnen Teile innerhalb `stack` zu erkennen, schau dir an wie die Kommas gesetzt sind. +Versuche die einzelnen Teile innerhalb von `stack` zu erkennen. Schau dir an wie die Kommas gesetzt sind. -Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`, getrennt durch Kommas +Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`, getrennt durch Kommas. -**Den Sound formen mit ADSR Hüllkurve** +**Den Sound formen mit ADSR-Hüllkurve** -Versuche herauszufinden was die Zahlen machen. Probier folgendes: +Versuche herauszufinden, was die Zahlen machen. Probier folgendes: - attack: `.5` vs `0` - decay: `.5` vs `0` - sustain: `1` vs `.25` vs `0` - release: `0` vs `.5` vs `1` -Kannst du erraten was die einzelnen Werte machen? +Kannst du erraten, was die einzelnen Werte machen? @@ -142,7 +142,7 @@ Kannst du erraten was die einzelnen Werte machen? -**adsr Kurznotation** +**adsr-Kurznotation** @@ -181,7 +181,7 @@ Was passiert wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten was die - a: Lautstärke des Delays - b: Verzögerungszeit -- c: Feedback (je kleiner desto schneller verschwindet das Delay) +- c: Feedback (je kleiner, desto schneller verschwindet das Delay) @@ -203,7 +203,7 @@ Füg auch ein Delay hinzu! -**kleiner dub tune** +**kleiner Dub-Tune** -Füg `.hush()` ans ende eines Patterns im stack... +Füg `.hush()` ans Ende eines Patterns im stack... @@ -258,25 +258,25 @@ Füg `.hush()` ans ende eines Patterns im stack... **fast and slow = schnell und langsam** -Mit `fast` und `slow` kann man das tempo eines patterns außerhalb der Mini-Notation ändern: +Mit `fast` und `slow` kann man das Tempo eines Patterns außerhalb der Mini-Notation ändern: -Ändere den `slow` Wert. Tausche `slow` durch `fast`. +Ändere den `slow`-Wert. Ersetze `slow` durch `fast`. -Was passiert wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ? +Was passiert, wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ? -Übrigens, innerhalb der Mini-Notation, `fast` ist `*` und `slow` ist `/`. +Übrigens, innerhalb der Mini-Notation: `fast` ist `*` und `slow` ist `/`. ")`} /> ## Automation mit Signalen -Anstatt Werte schrittweise zu automatisieren können wir auch sogenannte Signale benutzen: +Anstatt Werte schrittweise zu automatisieren, können wir auch sogenannte Signale benutzen: @@ -296,7 +296,7 @@ Signale bewegen sich standardmäßig zwischen 0 und 1. Wir können das mit `rang -`range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. lpf) +`range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. `lpf`) @@ -322,7 +322,7 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt. ## Rückblick -| name | example | +| Name | Beispiel | | ----- | -------------------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | @@ -333,4 +333,4 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt. | speed | ")`} /> | | range | | -Lass uns nun die für Tidal typischen [Pattern Effekte anschauen](/de/workshop/pattern-effects). +Lass uns nun die für Tidal typischen [Pattern-Effekte anschauen](/de/workshop/pattern-effects). From df277d6b7b66147563a64d4fe561d93a099328ba Mon Sep 17 00:00:00 2001 From: Bernhard Wagner Date: Tue, 7 Nov 2023 16:10:57 +0100 Subject: [PATCH 23/44] Update pattern-effects.mdx grammatical amendments --- .../src/pages/de/workshop/pattern-effects.mdx | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/website/src/pages/de/workshop/pattern-effects.mdx b/website/src/pages/de/workshop/pattern-effects.mdx index b701958a8..6603db065 100644 --- a/website/src/pages/de/workshop/pattern-effects.mdx +++ b/website/src/pages/de/workshop/pattern-effects.mdx @@ -1,5 +1,5 @@ --- -title: Pattern Effekte +title: Pattern-Effekte layout: ../../../layouts/MainLayout.astro --- @@ -7,11 +7,11 @@ import { MiniRepl } from '@src/docs/MiniRepl'; import Box from '@components/Box.astro'; import QA from '@components/QA'; -# Pattern Effekte +# Pattern-Effekte -Bis jetzt sind die meisten Funktionen die wir kennengelernt haben ähnlich wie Funktionen in anderen Musik Programmen: Sequencing von Sounds, Noten und Effekten. +Bis jetzt sind die meisten Funktionen, die wir kennengelernt haben, ähnlich wie Funktionen in anderen Musik Programmen: Sequencing von Sounds, Noten und Effekten. -In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich oder auch enzigartig sind. +In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich oder auch einzigartig sind. **rev = rückwärts abspielen** @@ -21,7 +21,7 @@ In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich -So würde man das ohne jux schreiben: +So würde man das ohne `jux` schreiben: -Lass uns visualisieren was hier passiert: +Lass uns visualisieren, was hier passiert: -Das hat den gleichen Effekt wie: +Das hat den gleichen Effekt, wie: "` -In der notation `x=>x.`, das `x` ist das Pattern das wir bearbeiten. +In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten. -`off` ist auch nützlich für sounds: +`off` ist auch nützlich für Sounds: x.`, das `x` ist das Pattern das wir bearbeiten. .off(1/8, x=>x.speed(1.5).gain(.25))`} /> -| name | description | example | -| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | -| rev | rückwärts | | -| jux | ein stereo-kanal modifizieren | | -| add | addiert zahlen oder noten | ")).scale("C:minor")`} /> | -| ply | multipliziert jedes element x mal | ")`} /> | -| off | verzögert eine modifizierte kopie | x.speed(2))`} /> | +| Name | Beschreibung | Beispiel | +| ---- | ----------------------------------- | ---------------------------------------------------------------------------------------------- | +| rev | rückwärts | | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | multipliziert jedes Element x mal | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | From 23dd9d4c01e52c42f02fd494df290e1efe431700 Mon Sep 17 00:00:00 2001 From: Bernhard Wagner Date: Tue, 7 Nov 2023 16:16:46 +0100 Subject: [PATCH 24/44] Update recap.mdx Adds a few missing translations --- website/src/pages/de/workshop/recap.mdx | 50 ++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/website/src/pages/de/workshop/recap.mdx b/website/src/pages/de/workshop/recap.mdx index db392b8b0..c0d577d16 100644 --- a/website/src/pages/de/workshop/recap.mdx +++ b/website/src/pages/de/workshop/recap.mdx @@ -7,19 +7,19 @@ import { MiniRepl } from '../../../docs/MiniRepl'; # Workshop Rückblick -Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen. +Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen. ## Mini Notation -| Concept | Syntax | Example | +| Konzept | Syntax | Beispiel | | --------------------- | -------- | -------------------------------------------------------------------------------- | -| Sequence | space | | -| Sample Nummer | :x | | +| Sequenz | space | | +| Sample-Nummer | :x | | | Pausen | ~ | | -| Unter-Sequences | \[\] | | -| Unter-Unter-Sequences | \[\[\]\] | | +| Unter-Sequenzen | \[\] | | +| Unter-Unter-Sequenzen | \[\[\]\] | | | Schneller | \* | | -| Slow down | \/ | | +| Verlangsamen | \/ | | | Parallel | , | | | Alternieren | \<\> | ")`} /> | | Verlängern | @ | | @@ -27,23 +27,23 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen. ## Sounds -| Name | Description | Example | +| Name | Beschreibung | Beispiel | | ----- | -------------------------- | ---------------------------------------------------------------------------------- | -| sound | spielt den sound mit namen | | -| bank | wählt die soundbank | | -| n | wählt sample mit nummer | | +| sound | spielt den Sound mit Namen | | +| bank | wählt die Soundbank | | +| n | wählt Sample mit Nummer | | -## Notes +## Noten -| Name | Description | Example | +| Name | Beschreibung | Beispiel | | --------- | ---------------------------------- | -------------------------------------------------------------------------------------------- | -| note | wählt note per zahl oder buchstabe | | -| n + scale | wählt note n in skala | | -| stack | spielt mehrere patterns parallel | | +| note | wählt Note per Zahl oder Buchstabe | | +| n + scale | wählt Note n in Skala | | +| stack | spielt mehrere Patterns parallel | | -## Audio Effekte +## Audio-Effekte -| name | example | +| Name | Beispiele | | ----- | -------------------------------------------------------------------------------------------------- | | lpf | ")`} /> | | vowel | ")`} /> | @@ -54,15 +54,15 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen. | speed | ")`} /> | | range | | -## Pattern Effects +## Pattern-Effekte -| name | description | example | +| Name | Beschreibung | Beispiel | | ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | -| cpm | tempo in cycles pro minute | | +| cpm | Tempo in Cycles pro Minute | | | fast | schneller | | | slow | langsamer | | | rev | rückwärts | | -| jux | ein stereo-kanal modifizieren | | -| add | addiert zahlen oder noten | ")).scale("C:minor")`} /> | -| ply | jedes element schneller machen | ")`} /> | -| off | verzögert eine modifizierte kopie | x.speed(2))`} /> | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | jedes Element schneller machen | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | From 4a16cd891f771165ee4f2f3fd4cc0126fe8e5d2e Mon Sep 17 00:00:00 2001 From: Bernhard Wagner Date: Tue, 7 Nov 2023 18:55:35 +0100 Subject: [PATCH 25/44] FIXES: table --- website/src/pages/de/workshop/pattern-effects.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/src/pages/de/workshop/pattern-effects.mdx b/website/src/pages/de/workshop/pattern-effects.mdx index 6603db065..703358819 100644 --- a/website/src/pages/de/workshop/pattern-effects.mdx +++ b/website/src/pages/de/workshop/pattern-effects.mdx @@ -174,10 +174,10 @@ In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten. .off(1/8, x=>x.speed(1.5).gain(.25))`} /> -| Name | Beschreibung | Beispiel | -| ---- | ----------------------------------- | ---------------------------------------------------------------------------------------------- | -| rev | rückwärts | | -| jux | einen Stereo-Kanal modifizieren | | -| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | -| ply | multipliziert jedes Element x mal | ")`} /> | -| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | +| Name | Beschreibung | Beispiel | +| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- | +| rev | rückwärts | | +| jux | einen Stereo-Kanal modifizieren | | +| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> | +| ply | multipliziert jedes Element x mal | ")`} /> | +| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> | From 0edd54dee331f12d80d6fa98b12222330e732558 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 20:23:45 -0500 Subject: [PATCH 26/44] cleaning up --- packages/superdough/superdough.mjs | 110 +++++++++++------------------ 1 file changed, 43 insertions(+), 67 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 8ea283401..2dc560d96 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -113,69 +113,46 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } -const createFilter2 = (ctx, cutoff, Q) => { - const filter = ctx.createBiquadFilter(); - filter.type = 'notch'; - filter.gain.value = 1; - filter.frequency.value = cutoff; - filter.Q.value = Q; - return filter; -}; +let phaserLFOs = {}; -const createOscillator = (ctx, freq) => { - const osc = ctx.createOscillator(); - osc.frequency.value = freq; - osc.type = 'sine'; - return osc; -}; -const createGain = (ctx, gain) => { - const gainNode = ctx.createGain(); - gainNode.gain.value = gain; - return gainNode; -}; +function getPhaser(orbit, speed = 1, depth = 0.5, t) { + //gain + const ac = getAudioContext(); + const lfoGain = ac.createGain(); + lfoGain.gain.value = 2000; -const createLFO = (ctx, freq, gain) => { - const osc = createOscillator(ctx, freq); - const gainNode = createGain(ctx, gain); - osc.start(); - osc.connect(gainNode); - return gainNode; -}; - -let phasers = {}; - -function getPhaser(orbit, speed = 1, depth = 0.5) { - if (!delays[orbit]) { - const ac = getAudioContext(); - - let lfo; - - const makeupGain = ac.createGain(); - - if (lfo == null) { - lfo = createLFO(ac, speed, 2000); - } - const numStages = 2; - let fOffset = 0; - for (let i = 0; i < numStages; i++) { - const gain = ac.createGain(); - gain.gain.value = 1 / numStages; - const filter = createFilter2(ac, 1000 + fOffset, 2 - Math.min(Math.max(depth * 2, 0), 1.9)); - makeupGain.connect(filter); - lfo.connect(filter.detune); - filter.connect(gain); - gain.connect(makeupGain); - fOffset += 200 + Math.pow(i, 2); - } - makeupGain.gain.value = 1; // how much makeup gain to add? - - makeupGain.connect(getDestination()); - phasers[orbit] = makeupGain; + //lfo + if (phaserLFOs[orbit] == null) { + const lfo = ac.createOscillator(); + lfo.frequency.value = speed; + lfo.type = 'sine'; + lfo.start(); + phaserLFOs[orbit] = lfo; } - console.log(phasers); - // delays[orbit].delayTime.value !== delaytime && delays[orbit].delayTime.setValueAtTime(delaytime, t); - // delays[orbit].feedback.value !== delayfeedback && delays[orbit].feedback.setValueAtTime(delayfeedback, t); - return phasers[orbit]; + if (phaserLFOs[orbit].frequency.value !== speed) { + phaserLFOs[orbit].frequency.setValueAtTime(speed, t); + } + phaserLFOs[orbit].connect(lfoGain); + + //filters + const numStages = 2; //num of filters in series + let fOffset = 0; + const filterChain = []; + for (let i = 0; i < numStages; i++) { + const filter = ac.createBiquadFilter(); + filter.type = 'notch'; + filter.gain.value = 1; + filter.frequency.value = 1000 + fOffset; + filter.Q.value = 2 - Math.min(Math.max(depth * 2, 0), 1.9); + + lfoGain.connect(filter.detune); + fOffset += 282; + if (i > 0) { + filterChain[i - 1].connect(filter); + } + filterChain.push(filter); + } + return filterChain[filterChain.length - 1]; } let reverbs = {}; @@ -453,18 +430,17 @@ export const superdough = async (value, deadline, hapDuration) => { panner.pan.value = 2 * pan - 1; chain.push(panner); } + // phaser + if (phaser !== undefined) { + const phaserFX = getPhaser(orbit, phaser, phaserDepth, t); + chain.push(phaserFX); + } // last gain const post = gainNode(postgain); chain.push(post); post.connect(getDestination()); - let phaserSend; - if (phaser != null) { - const phaserFX = getPhaser(orbit, phaser, phaserDepth); - - phaserSend = effectSend(post, phaserFX, 0.99); - } // delay let delaySend; if (delay > 0 && delaytime > 0 && delayfeedback > 0) { @@ -501,7 +477,7 @@ export const superdough = async (value, deadline, hapDuration) => { // toDisconnect = all the node that should be disconnected in onended callback // this is crucial for performance - toDisconnect = chain.concat([phaserSend, delaySend, reverbSend, analyserSend]); + toDisconnect = chain.concat([delaySend, reverbSend, analyserSend]); }; export const superdoughTrigger = (t, hap, ct, cps) => superdough(hap, t - ct, hap.duration / cps, cps); From bee36a7a4f89b3e8fd873fabaf7d0fbe82880887 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 20:25:31 -0500 Subject: [PATCH 27/44] cleaning up --- packages/superdough/phaser.mjs | 65 ------------------------------ packages/superdough/superdough.mjs | 1 - 2 files changed, 66 deletions(-) delete mode 100644 packages/superdough/phaser.mjs diff --git a/packages/superdough/phaser.mjs b/packages/superdough/phaser.mjs deleted file mode 100644 index 9aadc5328..000000000 --- a/packages/superdough/phaser.mjs +++ /dev/null @@ -1,65 +0,0 @@ -const createFilter = (ctx, cutoff, Q) => { - const filter = ctx.createBiquadFilter(); - filter.type = 'notch'; - filter.gain.value = 1; - filter.frequency.value = cutoff; - filter.Q.value = Q; - return filter; -}; - -const createOscillator = (ctx, freq) => { - const osc = ctx.createOscillator(); - osc.frequency.value = freq; - osc.type = 'sine'; - return osc; -}; -const createGain = (ctx, gain) => { - const gainNode = ctx.createGain(); - gainNode.gain.value = gain; - return gainNode; -}; - -const createLFO = (ctx, freq, gain) => { - const osc = createOscillator(ctx, freq); - const gainNode = createGain(ctx, gain); - osc.start(); - osc.connect(gainNode); - return gainNode; -}; - -if (typeof GainNode !== 'undefined') { - class PhaserNode extends GainNode { - constructor(ac, input) { - super(ac); - this.lfo; - - const { speed, depth = 0.5 } = input; - console.log(depth); - - const makeupGain = ac.createGain(); - - if (this.lfo == null) { - this.lfo = createLFO(ac, speed, 2000); - } - const numStages = 2; - let fOffset = 0; - for (let i = 0; i < numStages; i++) { - const gain = ac.createGain(); - gain.gain.value = 1 / numStages; - const filter = createFilter(ac, 1000 + fOffset, 2 - Math.min(Math.max(depth * 2, 0), 1.9)); - this.connect(filter); - this.lfo.connect(filter.detune); - filter.connect(gain); - gain.connect(makeupGain); - fOffset += 200 + Math.pow(i, 2); - } - makeupGain.gain.value = 1; // how much makeup gain to add? - this.connect = (target) => makeupGain.connect(target); - return this; - } - } - - AudioContext.prototype.createPhaser = function (speed) { - return new PhaserNode(this, speed); - }; -} diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 2dc560d96..9721c5c87 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -7,7 +7,6 @@ This program is free software: you can redistribute it and/or modify it under th import './feedbackdelay.mjs'; import './reverb.mjs'; import './vowel.mjs'; -import './phaser.mjs'; import { clamp } from './util.mjs'; import workletsUrl from './worklets.mjs?url'; import { createFilter, gainNode, getCompressor } from './helpers.mjs'; From f0a582dc926d91bec904ea71a4060d3d177a8158 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 21:10:12 -0500 Subject: [PATCH 28/44] cleaning up --- packages/core/controls.mjs | 13 ++++++------ packages/superdough/README.md | 2 ++ packages/superdough/superdough.mjs | 32 +++++++++-------------------- packages/superdough/worklets.mjs | 33 ------------------------------ 4 files changed, 19 insertions(+), 61 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index e3fa8be1f..ab1bea69b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -387,20 +387,21 @@ const generic_params = [ * @name phaser * @param {number | Pattern} speed speed of modulation * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").phaser("2 8").release(0.5) + * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8") * */ ['phaser'], /** + * The depth of modulation for phaser * - * - * @name phaserDepth + * @name phaserdepth * @param {number | Pattern} depth number between 0 and 1 * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").phaser("2 8").phaserDepth(0.5).release(0.5) + * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phaserdepth(0.5) * */ - ['phaserDepth'], + ['phaserdepth'], + /** * choose the channel the pattern is sent to in superdirt * @@ -1191,7 +1192,7 @@ const generic_params = [ ['tremolodepth', 'tremdp'], ['tremolorate', 'tremr'], // TODO: doesn't seem to do anything - ['phaserdepth', 'phasdp'], + ['phasdp'], ['phaserrate', 'phasr'], ['fshift'], diff --git a/packages/superdough/README.md b/packages/superdough/README.md index c5950dbfa..7c199debd 100644 --- a/packages/superdough/README.md +++ b/packages/superdough/README.md @@ -67,6 +67,8 @@ superdough({ s: 'bd', delay: 0.5 }, 0, 1); - `crush`: amplitude bit crusher using given number of bits - `shape`: distortion effect from 0 (none) to 1 (full). might get loud! - `pan`: stereo panning from 0 (left) to 1 (right) + - `phaser`: sets the speed of the modulation + - `phaserdepth` - `vowel`: vowel filter. possible values: "a", "e", "i", "o", "u" - `delay`: delay mix - `delayfeedback`: delay feedback diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 9721c5c87..31537642d 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -112,26 +112,18 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } -let phaserLFOs = {}; - -function getPhaser(orbit, speed = 1, depth = 0.5, t) { +function getPhaser(speed = 1, depth = 0.5) { //gain const ac = getAudioContext(); const lfoGain = ac.createGain(); lfoGain.gain.value = 2000; - //lfo - if (phaserLFOs[orbit] == null) { - const lfo = ac.createOscillator(); - lfo.frequency.value = speed; - lfo.type = 'sine'; - lfo.start(); - phaserLFOs[orbit] = lfo; - } - if (phaserLFOs[orbit].frequency.value !== speed) { - phaserLFOs[orbit].frequency.setValueAtTime(speed, t); - } - phaserLFOs[orbit].connect(lfoGain); + //lfo TODO: set the lfo phase relative to current cycle to create "free running" effect + const lfo = ac.createOscillator(); + lfo.frequency.value = speed; + lfo.type = 'sine'; + lfo.start(); + lfo.connect(lfoGain); //filters const numStages = 2; //num of filters in series @@ -271,7 +263,7 @@ export const superdough = async (value, deadline, hapDuration) => { //phaser phaser, - phaserDepth, + phaserdepth, // coarse, crush, @@ -306,6 +298,7 @@ export const superdough = async (value, deadline, hapDuration) => { if (bank && s) { s = `${bank}_${s}`; } + // get source AudioNode let sourceNode; if (source) { @@ -407,11 +400,6 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(vowelFilter); } - // if (phaser !== undefined) { - // const phaserFX = ac.createPhaser({ speed: phaser, depth: phaserDepth }); - // chain.push(phaserFX); - // } - // effects coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush })); @@ -431,7 +419,7 @@ export const superdough = async (value, deadline, hapDuration) => { } // phaser if (phaser !== undefined) { - const phaserFX = getPhaser(orbit, phaser, phaserDepth, t); + const phaserFX = getPhaser(phaser, phaserdepth); chain.push(phaserFX); } diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs index cce524538..7bb43f876 100644 --- a/packages/superdough/worklets.mjs +++ b/packages/superdough/worklets.mjs @@ -106,36 +106,3 @@ class ShapeProcessor extends AudioWorkletProcessor { } registerProcessor('shape-processor', ShapeProcessor); - -// class PhaseProcessor extends AudioWorkletProcessor { -// static get parameterDescriptors() { -// return [{ name: 'phaser', defaultValue: 0 }]; -// } - -// constructor() { -// super(); -// this.notStarted = true; -// } - -// process(inputs, outputs, parameters) { -// const input = inputs[0]; -// const output = outputs[0]; -// const phaser0 = parameters.phaser[0]; -// const phaser1 = phaser0 < 1 ? phaser0 : 1.0 - 4e-10; -// const phaser = (2.0 * phaser1) / (1.0 - phaser1); -// const blockSize = 128; -// const hasInput = !(input[0] === undefined); -// if (hasInput) { -// this.notStarted = false; -// for (let n = 0; n < blockSize; n++) { -// const value = ((1 + phaser) * input[0][n]) / (1 + phaser * Math.abs(input[0][n])); -// for (let o = 0; o < output.length; o++) { -// output[o][n] = value; -// } -// } -// } -// return this.notStarted || hasInput; -// } -// } - -// registerProcessor('phaser-processor', PhaseProcessor); From 51c63fa996f63991e0136fe922f6f21d37ea6197 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 21:44:57 -0500 Subject: [PATCH 29/44] turn off of depth is 0 --- packages/superdough/superdough.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 31537642d..4d0f2e239 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -263,7 +263,7 @@ export const superdough = async (value, deadline, hapDuration) => { //phaser phaser, - phaserdepth, + phaserdepth = 0.75, // coarse, crush, @@ -418,7 +418,7 @@ export const superdough = async (value, deadline, hapDuration) => { chain.push(panner); } // phaser - if (phaser !== undefined) { + if (phaser !== undefined && phaserdepth > 0) { const phaserFX = getPhaser(phaser, phaserdepth); chain.push(phaserFX); } From 2e4d28b9100e460c3c9c6787417dc5f3bb7b1053 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 21:49:56 -0500 Subject: [PATCH 30/44] update doc --- packages/core/controls.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index ab1bea69b..1374f25cf 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -392,7 +392,7 @@ const generic_params = [ */ ['phaser'], /** - * The depth of modulation for phaser + * The amount the signal is affected by the phaser effect * * @name phaserdepth * @param {number | Pattern} depth number between 0 and 1 From 65d07dbff22eaf35511af1b6b457a19e75832756 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 22:09:53 -0500 Subject: [PATCH 31/44] create free running lfos for different orbits --- packages/superdough/superdough.mjs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 4d0f2e239..3e63a55ac 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -112,18 +112,25 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } -function getPhaser(speed = 1, depth = 0.5) { +const phaserLFOs = {}; +function getPhaser(orbit, t, speed = 1, depth = 0.5) { //gain const ac = getAudioContext(); const lfoGain = ac.createGain(); lfoGain.gain.value = 2000; - //lfo TODO: set the lfo phase relative to current cycle to create "free running" effect - const lfo = ac.createOscillator(); - lfo.frequency.value = speed; - lfo.type = 'sine'; - lfo.start(); - lfo.connect(lfoGain); + //LFO + if (phaserLFOs[orbit] == null) { + phaserLFOs[orbit] = ac.createOscillator(); + phaserLFOs[orbit].frequency.value = speed; + phaserLFOs[orbit].type = 'sine'; + phaserLFOs[orbit].start(); + } + + phaserLFOs[orbit].connect(lfoGain); + if (phaserLFOs[orbit].frequency.value != speed) { + phaserLFOs[orbit].frequency.setValueAtTime(speed, t); + } //filters const numStages = 2; //num of filters in series @@ -419,7 +426,7 @@ export const superdough = async (value, deadline, hapDuration) => { } // phaser if (phaser !== undefined && phaserdepth > 0) { - const phaserFX = getPhaser(phaser, phaserdepth); + const phaserFX = getPhaser(orbit, t, phaser, phaserdepth); chain.push(phaserFX); } From 4b4290e0871eab7f83828d26644dc9c1d47c7f92 Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 22:52:39 -0500 Subject: [PATCH 32/44] add more parameters --- packages/core/controls.mjs | 26 +++++++++++++++++++++++++- packages/superdough/superdough.mjs | 12 +++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 58b027bab..4414219ed 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -391,13 +391,37 @@ const generic_params = [ * */ ['phaser'], + + /** + * The frequency sweep range of the lfo for the phaser effect + * + * @name phasersweep + * @param {number | Pattern} phasersweep most useful values are between 0 and 4000 + * @example + * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasersweep(800) + * + */ + ['phasersweep'], + + /** + * The center frequency of the phaser in HZ + * + * @name phasercenter + * @param {number | Pattern} centerfrequency most useful values are between 0 and 1 + * @example + * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(2000) + * + */ + + ['phasercenter'], + /** * The amount the signal is affected by the phaser effect * * @name phaserdepth * @param {number | Pattern} depth number between 0 and 1 * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phaserdepth(0.5) + * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(200) * */ ['phaserdepth'], diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 3e63a55ac..00e2f42ca 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -112,12 +112,13 @@ function getDelay(orbit, delaytime, delayfeedback, t) { return delays[orbit]; } +// each orbit will have its own lfo const phaserLFOs = {}; -function getPhaser(orbit, t, speed = 1, depth = 0.5) { +function getPhaser(orbit, t, speed = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) { //gain const ac = getAudioContext(); const lfoGain = ac.createGain(); - lfoGain.gain.value = 2000; + lfoGain.gain.value = sweep; //LFO if (phaserLFOs[orbit] == null) { @@ -140,7 +141,7 @@ function getPhaser(orbit, t, speed = 1, depth = 0.5) { const filter = ac.createBiquadFilter(); filter.type = 'notch'; filter.gain.value = 1; - filter.frequency.value = 1000 + fOffset; + filter.frequency.value = centerFrequency + fOffset; filter.Q.value = 2 - Math.min(Math.max(depth * 2, 0), 1.9); lfoGain.connect(filter.detune); @@ -271,6 +272,8 @@ export const superdough = async (value, deadline, hapDuration) => { //phaser phaser, phaserdepth = 0.75, + phasersweep, + phasercenter, // coarse, crush, @@ -411,7 +414,6 @@ export const superdough = async (value, deadline, hapDuration) => { coarse !== undefined && chain.push(getWorklet(ac, 'coarse-processor', { coarse })); crush !== undefined && chain.push(getWorklet(ac, 'crush-processor', { crush })); shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape })); - // phaser !== undefined && chain.push(getWorklet(ac, 'phaser-processor', { phaser })); compressorThreshold !== undefined && chain.push( @@ -426,7 +428,7 @@ export const superdough = async (value, deadline, hapDuration) => { } // phaser if (phaser !== undefined && phaserdepth > 0) { - const phaserFX = getPhaser(orbit, t, phaser, phaserdepth); + const phaserFX = getPhaser(orbit, t, phaser, phaserdepth, phasercenter, phasersweep); chain.push(phaserFX); } From 06eb8b5be814139f5c3087e8a9f40b568ab3467b Mon Sep 17 00:00:00 2001 From: Jade Rowland Date: Tue, 7 Nov 2023 22:57:00 -0500 Subject: [PATCH 33/44] fixed doc --- packages/core/controls.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 4414219ed..cdd1b4db8 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -407,7 +407,7 @@ const generic_params = [ * The center frequency of the phaser in HZ * * @name phasercenter - * @param {number | Pattern} centerfrequency most useful values are between 0 and 1 + * @param {number | Pattern} centerfrequency in HZ * @example * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(2000) * From 791a363694f598dac01429e349a4d5da229730e2 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 8 Nov 2023 23:33:46 +0100 Subject: [PATCH 34/44] snapshots --- test/__snapshots__/examples.test.mjs.snap | 148 ++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 39b9456f3..9b59e78e4 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -3306,6 +3306,154 @@ exports[`runs examples > example "perlin" example index 0 1`] = ` ] `; +exports[`runs examples > example "phaser" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", + "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", + "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", + "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", + "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", +] +`; + +exports[`runs examples > example "phasercenter" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", +] +`; + +exports[`runs examples > example "phaserdepth" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", +] +`; + +exports[`runs examples > example "phasersweep" example index 0 1`] = ` +[ + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", +] +`; + exports[`runs examples > example "pick" example index 0 1`] = ` [ "[ 0/1 → 1/2 | note:g ]", From df636cf4f699512a0e19b7dfc37dee31ac0d5ae6 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:16:17 +0100 Subject: [PATCH 35/44] phaser shortcuts --- packages/core/controls.mjs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index cdd1b4db8..871ec18dc 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -390,10 +390,10 @@ const generic_params = [ * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8") * */ - ['phaser'], + [['phaser', 'phaserdepth', 'phasercenter', 'phasersweep'], 'ph'], /** - * The frequency sweep range of the lfo for the phaser effect + * The frequency sweep range of the lfo for the phaser effect. Defaults to 2000 * * @name phasersweep * @param {number | Pattern} phasersweep most useful values are between 0 and 4000 @@ -401,10 +401,10 @@ const generic_params = [ * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasersweep(800) * */ - ['phasersweep'], + ['phasersweep', 'phs'], /** - * The center frequency of the phaser in HZ + * The center frequency of the phaser in HZ. Defaults to 1000 * * @name phasercenter * @param {number | Pattern} centerfrequency in HZ @@ -413,10 +413,10 @@ const generic_params = [ * */ - ['phasercenter'], + ['phasercenter', 'phc'], /** - * The amount the signal is affected by the phaser effect + * The amount the signal is affected by the phaser effect. Defaults to 0.75 * * @name phaserdepth * @param {number | Pattern} depth number between 0 and 1 @@ -424,7 +424,7 @@ const generic_params = [ * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(200) * */ - ['phaserdepth'], + ['phaserdepth', 'phd'], /** * choose the channel the pattern is sent to in superdirt From ac359a0e9e66b872a8bde93220351fe9d4248148 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:17:16 +0100 Subject: [PATCH 36/44] doc: phaser synonyms --- packages/core/controls.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 871ec18dc..6bba41315 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -385,6 +385,7 @@ const generic_params = [ * Phaser audio effect that approximates popular guitar pedals. * * @name phaser + * @synonyms ph * @param {number | Pattern} speed speed of modulation * @example * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8") @@ -396,6 +397,7 @@ const generic_params = [ * The frequency sweep range of the lfo for the phaser effect. Defaults to 2000 * * @name phasersweep + * @synonyms phs * @param {number | Pattern} phasersweep most useful values are between 0 and 4000 * @example * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasersweep(800) @@ -407,6 +409,7 @@ const generic_params = [ * The center frequency of the phaser in HZ. Defaults to 1000 * * @name phasercenter + * @synonyms phc * @param {number | Pattern} centerfrequency in HZ * @example * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(2000) @@ -419,6 +422,7 @@ const generic_params = [ * The amount the signal is affected by the phaser effect. Defaults to 0.75 * * @name phaserdepth + * @synonyms phd * @param {number | Pattern} depth number between 0 and 1 * @example * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(200) From 3ecb701504c662f67f8f2d3048cec7c30733d7bc Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:19:04 +0100 Subject: [PATCH 37/44] add params to superdough readme --- packages/superdough/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/superdough/README.md b/packages/superdough/README.md index 7c199debd..f32aa32d4 100644 --- a/packages/superdough/README.md +++ b/packages/superdough/README.md @@ -68,7 +68,9 @@ superdough({ s: 'bd', delay: 0.5 }, 0, 1); - `shape`: distortion effect from 0 (none) to 1 (full). might get loud! - `pan`: stereo panning from 0 (left) to 1 (right) - `phaser`: sets the speed of the modulation - - `phaserdepth` + - `phaserdepth`: the amount the signal is affected by the phaser effect. + - `phasersweep`: the frequency sweep range of the lfo for the phaser effect. + - `phasercenter`: the amount the signal is affected by the phaser effect. - `vowel`: vowel filter. possible values: "a", "e", "i", "o", "u" - `delay`: delay mix - `delayfeedback`: delay feedback From 2682fd38f8e3fa21531927f424db4a72dd7c3e7d Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:29:21 +0100 Subject: [PATCH 38/44] add to doc page --- packages/core/controls.mjs | 15 +- test/__snapshots__/examples.test.mjs.snap | 229 ++++++++++++---------- website/src/pages/learn/effects.mdx | 18 ++ 3 files changed, 149 insertions(+), 113 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 6bba41315..d69b44845 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -388,7 +388,8 @@ const generic_params = [ * @synonyms ph * @param {number | Pattern} speed speed of modulation * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8") + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser("<1 2 4 8>") * */ [['phaser', 'phaserdepth', 'phasercenter', 'phasersweep'], 'ph'], @@ -400,7 +401,8 @@ const generic_params = [ * @synonyms phs * @param {number | Pattern} phasersweep most useful values are between 0 and 4000 * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasersweep(800) + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser(2).phasersweep("<800 2000 4000>") * */ ['phasersweep', 'phs'], @@ -412,7 +414,8 @@ const generic_params = [ * @synonyms phc * @param {number | Pattern} centerfrequency in HZ * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(2000) + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser(2).phasercenter("<800 2000 4000>") * */ @@ -425,7 +428,8 @@ const generic_params = [ * @synonyms phd * @param {number | Pattern} depth number between 0 and 1 * @example - * run(8).scale("D:pentatonic").note().sound("sawtooth").release(0.5).phaser("2 8").phasercenter(200) + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser(2).phaserdepth("<0 .5 .75 1>") * */ ['phaserdepth', 'phd'], @@ -1081,7 +1085,8 @@ const generic_params = [ */ ['roomfade', 'rfade'], /** - * Sets the sample to use as an impulse response for the reverb. * * @name iresponse + * Sets the sample to use as an impulse response for the reverb. + * @name iresponse * @param {string | Pattern} sample to use as an impulse response * @synonyms ir * @example diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap index 9b59e78e4..8c49000a2 100644 --- a/test/__snapshots__/examples.test.mjs.snap +++ b/test/__snapshots__/examples.test.mjs.snap @@ -2439,6 +2439,19 @@ exports[`runs examples > example "irand" example index 0 1`] = ` ] `; +exports[`runs examples > example "iresponse" example index 0 1`] = ` +[ + "[ 0/1 → 1/2 | s:bd room:0.8 ir:shaker_large i:0 ]", + "[ 1/2 → 1/1 | s:sd room:0.8 ir:shaker_large i:0 ]", + "[ 1/1 → 3/2 | s:bd room:0.8 ir:shaker_large i:2 ]", + "[ 3/2 → 2/1 | s:sd room:0.8 ir:shaker_large i:2 ]", + "[ 2/1 → 5/2 | s:bd room:0.8 ir:shaker_large i:0 ]", + "[ 5/2 → 3/1 | s:sd room:0.8 ir:shaker_large i:0 ]", + "[ 3/1 → 7/2 | s:bd room:0.8 ir:shaker_large i:2 ]", + "[ 7/2 → 4/1 | s:sd room:0.8 ir:shaker_large i:2 ]", +] +`; + exports[`runs examples > example "iter" example index 0 1`] = ` [ "[ 0/1 → 1/4 | note:A3 ]", @@ -3308,34 +3321,34 @@ exports[`runs examples > example "perlin" example index 0 1`] = ` exports[`runs examples > example "phaser" example index 0 1`] = ` [ - "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", - "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", - "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", - "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", - "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", - "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", - "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", - "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:1 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:1 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:1 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:1 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:1 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:1 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:1 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:1 ]", "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", - "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", - "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", - "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", - "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", - "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", - "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", - "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", - "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", - "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", - "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", - "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", - "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]", - "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]", - "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]", - "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]", - "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:4 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:4 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:4 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:4 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:4 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:4 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:4 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:4 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:8 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:8 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:8 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:8 ]", "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]", "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]", "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]", @@ -3345,75 +3358,75 @@ exports[`runs examples > example "phaser" example index 0 1`] = ` exports[`runs examples > example "phasercenter" example index 0 1`] = ` [ - "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", - "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", - "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:2000 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]", ] `; exports[`runs examples > example "phaserdepth" example index 0 1`] = ` [ - "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:200 ]", - "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", - "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasercenter:200 ]", + "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]", + "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]", + "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]", ] `; @@ -3423,34 +3436,34 @@ exports[`runs examples > example "phasersweep" example index 0 1`] = ` "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]", + "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", + "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]", "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", - "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", - "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 phasersweep:800 ]", + "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", + "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]", ] `; diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx index b1323a8eb..a3ae91d79 100644 --- a/website/src/pages/learn/effects.mdx +++ b/website/src/pages/learn/effects.mdx @@ -240,3 +240,21 @@ global effects use the same chain for all events of the same orbit: Next, we'll look at strudel's support for [Csound](/learn/csound). + +## Phaser + +### phaser + + + +### phaserdepth + + + +### phasercenter + + + +### phasersweep + + From 858a02634e29e72ef35905c50dfeccc85e43d9ee Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:40:21 +0100 Subject: [PATCH 39/44] dedupe / move supertdirt phaser controls --- packages/core/controls.mjs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index d69b44845..8779c4a9b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -381,6 +381,8 @@ const generic_params = [ */ ['coarse'], + ['phaserrate', 'phasr'], // superdirt only + /** * Phaser audio effect that approximates popular guitar pedals. * @@ -432,7 +434,7 @@ const generic_params = [ * .phaser(2).phaserdepth("<0 .5 .75 1>") * */ - ['phaserdepth', 'phd'], + ['phaserdepth', 'phd', 'phasdp'], // also a superdirt control /** * choose the channel the pattern is sent to in superdirt @@ -1224,9 +1226,6 @@ const generic_params = [ */ ['tremolodepth', 'tremdp'], ['tremolorate', 'tremr'], - // TODO: doesn't seem to do anything - ['phasdp'], - ['phaserrate', 'phasr'], ['fshift'], ['fshiftnote'], From 85835087ba0c55ac6e028de6c76812c20bb26018 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:48:23 +0100 Subject: [PATCH 40/44] format --- packages/superdough/sampler.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index ed73eeb8a..d278913a3 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -298,7 +298,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { bufferSource.connect(envelope); const out = ac.createGain(); // we need a separate gain for the cutgroups because firefox... envelope.connect(out); - bufferSource.onended = function() { + bufferSource.onended = function () { bufferSource.disconnect(); envelope.disconnect(); out.disconnect(); From 7c8a8b8b7044b8a3e422717bd6a928486940dbb3 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 08:59:23 +0100 Subject: [PATCH 41/44] simplify --- packages/superdough/sampler.mjs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index d278913a3..7127d891a 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -57,19 +57,16 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, vib, vibmod const bufferSource = ac.createBufferSource(); bufferSource.buffer = buffer; const playbackRate = 1.0 * Math.pow(2, transpose / 12); + bufferSource.playbackRate.value = playbackRate; if (vib > 0) { let vibrato_oscillator = getAudioContext().createOscillator(); vibrato_oscillator.frequency.value = vib; const gain = getAudioContext().createGain(); // Vibmod is the amount of vibrato, in semitones - bufferSource.playbackRate.value = Math.pow(2, transpose / 12); gain.gain.value = vibmod / 4; vibrato_oscillator.connect(gain); gain.connect(bufferSource.playbackRate); vibrato_oscillator.start(0); - } else { - bufferSource.playbackRate.value = Math.pow(2, transpose / 12); - bufferSource.playbackRate.value = playbackRate; } return bufferSource; }; From 0052d349d925275e5f14d89bf49e01c4629b952f Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 09:06:50 +0100 Subject: [PATCH 42/44] refactor: move vibrato up + cleanup oscillator --- packages/superdough/sampler.mjs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 7127d891a..6da8b1d12 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -22,7 +22,7 @@ function humanFileSize(bytes, si) { return bytes.toFixed(1) + ' ' + units[u]; } -export const getSampleBufferSource = async (s, n, note, speed, freq, vib, vibmod, bank, resolveUrl) => { +export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resolveUrl) => { let transpose = 0; if (freq !== undefined && note !== undefined) { logger('[sampler] hap has note and freq. ignoring note', 'warning'); @@ -58,16 +58,6 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, vib, vibmod bufferSource.buffer = buffer; const playbackRate = 1.0 * Math.pow(2, transpose / 12); bufferSource.playbackRate.value = playbackRate; - if (vib > 0) { - let vibrato_oscillator = getAudioContext().createOscillator(); - vibrato_oscillator.frequency.value = vib; - const gain = getAudioContext().createGain(); - // Vibmod is the amount of vibrato, in semitones - gain.gain.value = vibmod / 4; - vibrato_oscillator.connect(gain); - gain.connect(bufferSource.playbackRate); - vibrato_oscillator.start(0); - } return bufferSource; }; @@ -264,7 +254,20 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { //const soundfont = getSoundfontKey(s); const time = t + nudge; - const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, vib, vibmod, bank, resolveUrl); + const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl); + + // vibrato + let vibratoOscillator; + if (vib > 0) { + vibratoOscillator = getAudioContext().createOscillator(); + vibratoOscillator.frequency.value = vib; + const gain = getAudioContext().createGain(); + // Vibmod is the amount of vibrato, in semitones + gain.gain.value = vibmod * 100; + vibratoOscillator.connect(gain); + gain.connect(bufferSource.detune); + vibratoOscillator.start(0); + } // asny stuff above took too long? if (ac.currentTime > t) { @@ -297,6 +300,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { envelope.connect(out); bufferSource.onended = function () { bufferSource.disconnect(); + vibratoOscillator.stop(); envelope.disconnect(); out.disconnect(); onended(); From 2a09f9ef0b51a8006efd745275eb48ac128516ba Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 9 Nov 2023 09:21:40 +0100 Subject: [PATCH 43/44] fix: sampler broke without vibrato --- packages/superdough/sampler.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs index 6da8b1d12..b8f10d5da 100644 --- a/packages/superdough/sampler.mjs +++ b/packages/superdough/sampler.mjs @@ -300,7 +300,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) { envelope.connect(out); bufferSource.onended = function () { bufferSource.disconnect(); - vibratoOscillator.stop(); + vibratoOscillator?.stop(); envelope.disconnect(); out.disconnect(); onended(); From d25851ac1761064d646188dacc1ef65ad9301772 Mon Sep 17 00:00:00 2001 From: Alex McLean Date: Fri, 10 Nov 2023 11:17:35 +0000 Subject: [PATCH 44/44] support multiple named serial connections, change default baudrate to 115200 (#551) --- packages/serial/serial.mjs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/serial/serial.mjs b/packages/serial/serial.mjs index c4e52d4d2..652b60546 100644 --- a/packages/serial/serial.mjs +++ b/packages/serial/serial.mjs @@ -6,23 +6,23 @@ This program is free software: you can redistribute it and/or modify it under th import { Pattern, isPattern } from '@strudel.cycles/core'; -var writeMessage; +var writeMessagers = {}; var choosing = false; -export async function getWriter(br = 38400) { +export async function getWriter(name, br) { if (choosing) { return; } choosing = true; - if (writeMessage) { - return writeMessage; + if (name in writeMessagers) { + return writeMessagers[name]; } if ('serial' in navigator) { const port = await navigator.serial.requestPort(); await port.open({ baudRate: br }); const encoder = new TextEncoder(); const writer = port.writable.getWriter(); - writeMessage = function (message, chk) { + writeMessagers[name] = function (message, chk) { const encoded = encoder.encode(message); if (!chk) { writer.write(encoded); @@ -63,10 +63,10 @@ function crc16(data) { return crc & 0xffff; } -Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids = false) { +Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids = false, name = 'default') { return this.withHap((hap) => { - if (!writeMessage) { - getWriter(br); + if (!(name in writeMessagers)) { + getWriter(name, br); } const onTrigger = (time, hap, currentTime) => { var message = ''; @@ -108,7 +108,7 @@ Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids const offset = (time - currentTime + latency) * 1000; window.setTimeout(function () { - writeMessage(message, chk); + writeMessagers[name](message, chk); }, offset); }; return hap.setContext({ ...hap.context, onTrigger, dominantTrigger: true });