mirror of
https://github.com/eliasstepanik/strudel.git
synced 2026-01-11 13:48:40 +00:00
Merge branch 'main' into atfornesmain
This commit is contained in:
commit
71b4e14dd3
@ -20,4 +20,5 @@ vite.config.js
|
||||
**/dist
|
||||
/src-tauri/target/**/*
|
||||
reverbGen.mjs
|
||||
hydra.mjs
|
||||
hydra.mjs
|
||||
jsdoc-synonyms.js
|
||||
17
jsdoc/jsdoc-synonyms.js
Normal file
17
jsdoc/jsdoc-synonyms.js
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
jsdoc-synonyms.js - Add support for @synonym tag
|
||||
Copyright (C) 2023 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/midi/midi.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
function defineTags(dictionary) {
|
||||
dictionary.defineTag('synonyms', {
|
||||
mustHaveValue: true,
|
||||
onTagged: function (doclet, tag) {
|
||||
doclet.synonyms_text = tag.value;
|
||||
doclet.synonyms = doclet.synonyms_text.split(/[ ,]+/);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { defineTags: defineTags };
|
||||
@ -3,7 +3,7 @@
|
||||
"includePattern": ".+\\.(js(doc|x)?|mjs)$",
|
||||
"excludePattern": "node_modules|shift-parser|shift-reducer|shift-traverser|dist"
|
||||
},
|
||||
"plugins": ["plugins/markdown"],
|
||||
"plugins": ["plugins/markdown", "jsdoc/jsdoc-synonyms"],
|
||||
"opts": {
|
||||
"destination": "./out/",
|
||||
"recurse": true
|
||||
@ -65,7 +65,7 @@ async function getUndocumented(path, docs) {
|
||||
}
|
||||
|
||||
// read doc.json file
|
||||
const { docs } = JSON.parse(await readFile(resolve(__dirname, 'doc.json'), 'utf8'));
|
||||
const { docs } = JSON.parse(await readFile(resolve(__dirname, '..', 'doc.json'), 'utf8'));
|
||||
|
||||
const paths = dependencyTree.toList({
|
||||
filename: 'index.mjs',
|
||||
@ -76,7 +76,9 @@ const paths = dependencyTree.toList({
|
||||
// const paths = ['../packages/core/pattern.mjs', '../packages/core/hap.mjs'].map((rel) => resolve(__dirname, rel));
|
||||
|
||||
const undocumented = Object.fromEntries(
|
||||
await Promise.all(paths.map(async (path) => [path, await getUndocumented(path, docs)])),
|
||||
await Promise.all(
|
||||
paths.map(async (path) => [path.replace(resolve(__dirname, '..'), ''), await getUndocumented(path, docs)]),
|
||||
),
|
||||
);
|
||||
|
||||
console.log(JSON.stringify(undocumented, null, 2));
|
||||
@ -18,12 +18,12 @@
|
||||
"build": "npm run prebuild && cd website && npm run build",
|
||||
"preview": "cd website && npm run preview",
|
||||
"osc": "cd packages/osc && npm run server",
|
||||
"jsdoc": "jsdoc packages/ -c jsdoc.config.json",
|
||||
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc.config.json",
|
||||
"jsdoc": "jsdoc packages/ -c jsdoc/jsdoc.config.json",
|
||||
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc/jsdoc.config.json",
|
||||
"lint": "eslint . --ext mjs,js --quiet",
|
||||
"codeformat": "prettier --write .",
|
||||
"format-check": "prettier --check .",
|
||||
"report-undocumented": "npm run jsdoc-json && node undocumented.mjs > undocumented.json",
|
||||
"report-undocumented": "npm run jsdoc-json && node jsdoc/undocumented.mjs > undocumented.json",
|
||||
"check": "npm run format-check && npm run lint && npm run test",
|
||||
"iclc": "cd paper && pandoc --template=pandoc/iclc.html --citeproc --number-sections iclc2023.md -o iclc2023.html && pandoc --template=pandoc/iclc.latex --citeproc --number-sections iclc2023.md -o iclc2023.pdf"
|
||||
},
|
||||
|
||||
@ -1214,6 +1214,16 @@ const generic_params = [
|
||||
* @name waveloss
|
||||
*/
|
||||
['waveloss'],
|
||||
/*
|
||||
* Noise crackle density
|
||||
*
|
||||
* @name density
|
||||
* @param {number | Pattern} density between 0 and x
|
||||
* @example
|
||||
* s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4))
|
||||
*
|
||||
*/
|
||||
['density'],
|
||||
// TODO: midi effects?
|
||||
['dur'],
|
||||
// ['modwheel'],
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
import { getDrawContext } from '@strudel.cycles/core';
|
||||
|
||||
let audio = false;
|
||||
let hydra;
|
||||
|
||||
function appendCanvas(c) {
|
||||
const { canvas: testCanvas } = getDrawContext();
|
||||
c.canvas.id = 'hydra-canvas';
|
||||
c.canvas.style.position = 'absolute';
|
||||
c.canvas.style.position = 'fixed';
|
||||
c.canvas.style.top = '0px';
|
||||
testCanvas.after(c.canvas);
|
||||
return testCanvas;
|
||||
}
|
||||
|
||||
export async function initHydra(config) {
|
||||
audio = config?.audio || false;
|
||||
export async function initHydra(options = {}) {
|
||||
//load and init hydra
|
||||
if (!document.getElementById('hydra-canvas')) {
|
||||
await import('https://unpkg.com/hydra-synth');
|
||||
hydra = new Hydra({ detectAudio: audio });
|
||||
const { src = 'https://unpkg.com/hydra-synth', ...opts } = options;
|
||||
await import(src);
|
||||
|
||||
hydra = new Hydra(opts);
|
||||
appendCanvas(hydra);
|
||||
// s0.init({ src: hydraCanvas }); // whats that?
|
||||
}
|
||||
|
||||
// if config.audio is true
|
||||
// if options.detectAudio is true
|
||||
// and current canvas des not detect audio
|
||||
if (config?.audio && !hydra.detectAudio) {
|
||||
if (options?.detectAudio && !hydra?.detectAudio) {
|
||||
//remove previous canvas without audio detection
|
||||
document.getElementById('hydra-canvas').remove();
|
||||
// create and append a new audio responsive canvas
|
||||
hydra = new Hydra({ detectAudio: audio });
|
||||
appendCanvas(hydra);
|
||||
return initHydra(options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,16 +2,23 @@ import { createRoot } from 'react-dom/client';
|
||||
import jsdoc from '../../../../doc.json';
|
||||
|
||||
const getDocLabel = (doc) => doc.name || doc.longname;
|
||||
const getDocSynonyms = (doc) => [getDocLabel(doc), ...(doc.synonyms || [])];
|
||||
const getInnerText = (html) => {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = html;
|
||||
return div.textContent || div.innerText || '';
|
||||
};
|
||||
|
||||
export function Autocomplete({ doc }) {
|
||||
export function Autocomplete({ doc, label = getDocLabel(doc) }) {
|
||||
const synonyms = getDocSynonyms(doc).filter((a) => a !== label);
|
||||
return (
|
||||
<div className="prose dark:prose-invert max-h-[400px] overflow-auto">
|
||||
<h3 className="pt-0 mt-0">{getDocLabel(doc)}</h3>
|
||||
<h3 className="pt-0 mt-0">{label}</h3>{' '}
|
||||
{!!synonyms.length && (
|
||||
<span>
|
||||
Synonyms: <code>{synonyms.join(', ')}</code>
|
||||
</span>
|
||||
)}
|
||||
<div dangerouslySetInnerHTML={{ __html: doc.description }} />
|
||||
<ul>
|
||||
{doc.params?.map(({ name, type, description }, i) => (
|
||||
@ -48,18 +55,24 @@ const jsdocCompletions = jsdoc.docs
|
||||
!['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)),
|
||||
)
|
||||
// https://codemirror.net/docs/ref/#autocomplete.Completion
|
||||
.map((doc) /*: Completion */ => ({
|
||||
label: getDocLabel(doc),
|
||||
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
|
||||
info: () => {
|
||||
const node = document.createElement('div');
|
||||
// if Autocomplete is non-interactive, it could also be rendered at build time..
|
||||
// .. using renderToStaticMarkup
|
||||
createRoot(node).render(<Autocomplete doc={doc} />);
|
||||
return node;
|
||||
},
|
||||
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
|
||||
}));
|
||||
.reduce(
|
||||
(acc, doc) /*: Completion */ =>
|
||||
acc.concat(
|
||||
[getDocLabel(doc), ...(doc.synonyms || [])].map((label) => ({
|
||||
label,
|
||||
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
|
||||
info: () => {
|
||||
const node = document.createElement('div');
|
||||
// if Autocomplete is non-interactive, it could also be rendered at build time..
|
||||
// .. using renderToStaticMarkup
|
||||
createRoot(node).render(<Autocomplete doc={doc} label={label} />);
|
||||
return node;
|
||||
},
|
||||
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
|
||||
})),
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
export const strudelAutocomplete = (context /* : CompletionContext */) => {
|
||||
let word = context.matchBefore(/\w*/);
|
||||
|
||||
@ -31,6 +31,9 @@ window.addEventListener(
|
||||
export const strudelTooltip = hoverTooltip(
|
||||
(view, pos, side) => {
|
||||
// Word selection from CodeMirror Hover Tooltip example https://codemirror.net/examples/tooltip/#hover-tooltips
|
||||
if (!ctrlDown) {
|
||||
return null;
|
||||
}
|
||||
let { from, to, text } = view.state.doc.lineAt(pos);
|
||||
let start = pos,
|
||||
end = pos;
|
||||
@ -47,11 +50,13 @@ export const strudelTooltip = hoverTooltip(
|
||||
// Get entry from Strudel documentation
|
||||
let entry = jsdoc.docs.filter((doc) => getDocLabel(doc) === word)[0];
|
||||
if (!entry) {
|
||||
return null;
|
||||
}
|
||||
if (!ctrlDown) {
|
||||
return null;
|
||||
// Try for synonyms
|
||||
entry = jsdoc.docs.filter((doc) => doc.synonyms && doc.synonyms.includes(word))[0];
|
||||
if (!entry) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pos: start,
|
||||
end,
|
||||
@ -60,7 +65,7 @@ export const strudelTooltip = hoverTooltip(
|
||||
create(view) {
|
||||
let dom = document.createElement('div');
|
||||
dom.className = 'strudel-tooltip';
|
||||
createRoot(dom).render(<Autocomplete doc={entry} />);
|
||||
createRoot(dom).render(<Autocomplete doc={entry} label={word} />);
|
||||
return { dom };
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,7 +4,7 @@ import { getAudioContext } from './superdough.mjs';
|
||||
let noiseCache = {};
|
||||
|
||||
// lazy generates noise buffers and keeps them forever
|
||||
function getNoiseBuffer(type) {
|
||||
function getNoiseBuffer(type, density) {
|
||||
const ac = getAudioContext();
|
||||
if (noiseCache[type]) {
|
||||
return noiseCache[type];
|
||||
@ -34,17 +34,26 @@ function getNoiseBuffer(type) {
|
||||
output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
|
||||
output[i] *= 0.11;
|
||||
b6 = white * 0.115926;
|
||||
} else if (type === 'crackle') {
|
||||
const probability = density * 0.01;
|
||||
if (Math.random() < probability) {
|
||||
output[i] = Math.random() * 2 - 1;
|
||||
} else {
|
||||
output[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
noiseCache[type] = noiseBuffer;
|
||||
|
||||
// Prevent caching to randomize crackles
|
||||
if (type !== 'crackle') noiseCache[type] = noiseBuffer;
|
||||
return noiseBuffer;
|
||||
}
|
||||
|
||||
// expects one of noises as type
|
||||
export function getNoiseOscillator(type = 'white', t) {
|
||||
export function getNoiseOscillator(type = 'white', t, density = 0.02) {
|
||||
const ac = getAudioContext();
|
||||
const o = ac.createBufferSource();
|
||||
o.buffer = getNoiseBuffer(type);
|
||||
o.buffer = getNoiseBuffer(type, density);
|
||||
o.loop = true;
|
||||
o.start(t);
|
||||
return {
|
||||
|
||||
@ -241,6 +241,7 @@ export const superdough = async (value, deadline, hapDuration) => {
|
||||
source,
|
||||
gain = 0.8,
|
||||
postgain = 1,
|
||||
density = 0.03,
|
||||
// filters
|
||||
ftype = '12db',
|
||||
fanchor = 0.5,
|
||||
|
||||
@ -22,7 +22,7 @@ const fm = (osc, harmonicityRatio, modulationIndex, wave = 'sine') => {
|
||||
};
|
||||
|
||||
const waveforms = ['sine', 'square', 'triangle', 'sawtooth'];
|
||||
const noises = ['pink', 'white', 'brown'];
|
||||
const noises = ['pink', 'white', 'brown', 'crackle'];
|
||||
|
||||
export function registerSynthSounds() {
|
||||
[...waveforms, ...noises].forEach((s) => {
|
||||
@ -36,7 +36,8 @@ export function registerSynthSounds() {
|
||||
if (waveforms.includes(s)) {
|
||||
sound = getOscillator(s, t, value);
|
||||
} else {
|
||||
sound = getNoiseOscillator(s, t);
|
||||
let { density } = value;
|
||||
sound = getNoiseOscillator(s, t, density);
|
||||
}
|
||||
|
||||
let { node: o, stop, triggerRelease } = sound;
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
{
|
||||
"/home/felix/projects/strudel/packages/core/fraction.mjs": [
|
||||
"/packages/core/fraction.mjs": [
|
||||
"gcd"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/timespan.mjs": [
|
||||
"/packages/core/timespan.mjs": [
|
||||
"TimeSpan"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/hap.mjs": [
|
||||
"/packages/core/hap.mjs": [
|
||||
"Hap"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/state.mjs": [
|
||||
"/packages/core/state.mjs": [
|
||||
"State"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/util.mjs": [
|
||||
"/packages/core/util.mjs": [
|
||||
"isNoteWithOctave",
|
||||
"isNote",
|
||||
"tokenizeNote",
|
||||
@ -34,23 +34,31 @@
|
||||
"mapArgs",
|
||||
"numeralArgs",
|
||||
"parseFractional",
|
||||
"fractionalArgs"
|
||||
"fractionalArgs",
|
||||
"splitAt",
|
||||
"zipWith",
|
||||
"clamp",
|
||||
"sol2note"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/value.mjs": [
|
||||
"/packages/core/value.mjs": [
|
||||
"unionWithObj",
|
||||
"valued",
|
||||
"Value",
|
||||
"map"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/drawLine.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/core/logger.mjs": [
|
||||
"/packages/core/drawLine.mjs": [],
|
||||
"/packages/core/logger.mjs": [
|
||||
"logKey",
|
||||
"logger"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/pattern.mjs": [
|
||||
"/packages/core/pattern.mjs": [
|
||||
"setStringParser",
|
||||
"polyrhythm",
|
||||
"pr",
|
||||
"pm",
|
||||
"isPattern",
|
||||
"reify",
|
||||
"fastcat",
|
||||
"set",
|
||||
"keep",
|
||||
"keepif",
|
||||
@ -74,22 +82,33 @@
|
||||
"func",
|
||||
"compressSpan",
|
||||
"compressspan",
|
||||
"fastgap",
|
||||
"focusSpan",
|
||||
"focusspan",
|
||||
"density",
|
||||
"sparsity",
|
||||
"zoomArc",
|
||||
"zoomarc",
|
||||
"inv",
|
||||
"juxby",
|
||||
"echowith",
|
||||
"stutWith",
|
||||
"stutwith",
|
||||
"iterback",
|
||||
"chunkback",
|
||||
"bypass",
|
||||
"duration",
|
||||
"color",
|
||||
"colour",
|
||||
"striate"
|
||||
"loopat",
|
||||
"loopatcps"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/controls.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/core/euclid.mjs": [
|
||||
"/packages/core/controls.mjs": [],
|
||||
"/packages/core/euclid.mjs": [
|
||||
"bjork",
|
||||
"euclidrot",
|
||||
"euclidLegatoRot"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/signal.mjs": [
|
||||
"/packages/core/signal.mjs": [
|
||||
"steady",
|
||||
"signal",
|
||||
"isaw",
|
||||
@ -112,34 +131,37 @@
|
||||
"degradeByWith",
|
||||
"undegrade"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/speak.mjs": [
|
||||
"/packages/core/speak.mjs": [
|
||||
"speak"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/evaluate.mjs": [
|
||||
"/packages/core/evaluate.mjs": [
|
||||
"evalScope",
|
||||
"evaluate"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/zyklus.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/core/cyclist.mjs": [
|
||||
"/packages/core/zyklus.mjs": [],
|
||||
"/packages/core/cyclist.mjs": [
|
||||
"Cyclist"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/time.mjs": [
|
||||
"/packages/core/time.mjs": [
|
||||
"getTime",
|
||||
"setTime"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/repl.mjs": [
|
||||
"repl"
|
||||
"/packages/core/repl.mjs": [
|
||||
"repl",
|
||||
"getTrigger"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/draw.mjs": [
|
||||
"/packages/core/draw.mjs": [
|
||||
"getDrawContext",
|
||||
"cleanupDraw"
|
||||
"cleanupDraw",
|
||||
"Framer",
|
||||
"Drawer"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/animate.mjs": [
|
||||
"/packages/core/animate.mjs": [
|
||||
"x",
|
||||
"y",
|
||||
"w",
|
||||
"h",
|
||||
"a",
|
||||
"angle",
|
||||
"r",
|
||||
"fill",
|
||||
"smear",
|
||||
@ -147,85 +169,121 @@
|
||||
"moveXY",
|
||||
"zoomIn"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/pianoroll.mjs": [
|
||||
"pianoroll"
|
||||
"/packages/core/pianoroll.mjs": [
|
||||
"getDrawOptions",
|
||||
"drawPianoroll"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/ui.mjs": [
|
||||
"/packages/core/spiral.mjs": [],
|
||||
"/packages/core/ui.mjs": [
|
||||
"backgroundImage",
|
||||
"cleanupUi"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/core/gist.js": [],
|
||||
"/home/felix/projects/strudel/packages/core/index.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/midi/midi.mjs": [
|
||||
"/packages/core/gist.js": [],
|
||||
"/packages/core/index.mjs": [],
|
||||
"/packages/csound/index.mjs": [
|
||||
"loadCSound",
|
||||
"loadcsound",
|
||||
"loadCsound",
|
||||
"csound",
|
||||
"loadOrc"
|
||||
],
|
||||
"/packages/desktopbridge/utils.mjs": [
|
||||
"Invoke",
|
||||
"isTauri"
|
||||
],
|
||||
"/packages/desktopbridge/midibridge.mjs": [],
|
||||
"/packages/desktopbridge/oscbridge.mjs": [],
|
||||
"/packages/desktopbridge/index.mjs": [],
|
||||
"/packages/midi/midi.mjs": [
|
||||
"WebMidi",
|
||||
"enableWebMidi"
|
||||
"enableWebMidi",
|
||||
"midin"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/midi/index.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/mini/krill-parser.js": [],
|
||||
"/home/felix/projects/strudel/packages/mini/mini.mjs": [
|
||||
"/packages/midi/index.mjs": [],
|
||||
"/packages/mini/krill-parser.js": [],
|
||||
"/packages/mini/mini.mjs": [
|
||||
"patternifyAST",
|
||||
"getLeafLocation",
|
||||
"mini2ast",
|
||||
"getLeaves",
|
||||
"getLeafLocations",
|
||||
"mini",
|
||||
"m",
|
||||
"h",
|
||||
"minify"
|
||||
"minify",
|
||||
"miniAllStrings"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/mini/index.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/soundfonts/fontloader.mjs": [
|
||||
"/packages/mini/index.mjs": [],
|
||||
"/packages/soundfonts/gm.mjs": [],
|
||||
"/packages/soundfonts/fontloader.mjs": [
|
||||
"getFontBufferSource",
|
||||
"getFontPitch"
|
||||
"getFontPitch",
|
||||
"registerSoundfonts"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/soundfonts/list.mjs": [
|
||||
"/packages/soundfonts/list.mjs": [
|
||||
"instruments",
|
||||
"drums",
|
||||
"instrumentNames"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/soundfonts/sfumato.mjs": [
|
||||
"/packages/soundfonts/sfumato.mjs": [
|
||||
"loadSoundfont"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/soundfonts/index.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/tonal/tonal.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/tonal/voicings.mjs": [
|
||||
"voicingRegistry",
|
||||
"setVoicingRange"
|
||||
"/packages/soundfonts/index.mjs": [],
|
||||
"/packages/tonal/tonal.mjs": [],
|
||||
"/packages/tonal/tonleiter.mjs": [
|
||||
"pc2chroma",
|
||||
"rotateChroma",
|
||||
"chroma2pc",
|
||||
"tokenizeChord",
|
||||
"note2pc",
|
||||
"note2oct",
|
||||
"note2chroma",
|
||||
"midi2chroma",
|
||||
"pitch2chroma",
|
||||
"step2semitones",
|
||||
"x2midi",
|
||||
"scaleStep",
|
||||
"renderVoicing",
|
||||
"accidentalOffset",
|
||||
"Step",
|
||||
"Note"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/tonal/index.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/transpiler/transpiler.mjs": [
|
||||
"/packages/tonal/ireal.mjs": [
|
||||
"simple",
|
||||
"complex"
|
||||
],
|
||||
"/packages/tonal/voicings.mjs": [
|
||||
"voicingRegistry",
|
||||
"setVoicingRange",
|
||||
"registerVoicings",
|
||||
"voicingAlias"
|
||||
],
|
||||
"/packages/tonal/index.mjs": [],
|
||||
"/packages/transpiler/transpiler.mjs": [
|
||||
"transpiler"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/transpiler/index.mjs": [
|
||||
"/packages/transpiler/index.mjs": [
|
||||
"evaluate"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/webaudio/feedbackdelay.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/webaudio/reverb.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/webaudio/sampler.mjs": [
|
||||
"getCachedBuffer",
|
||||
"getSampleBufferSource",
|
||||
"loadBuffer",
|
||||
"reverseBuffer",
|
||||
"getLoadedBuffer",
|
||||
"resetLoadedSamples",
|
||||
"getLoadedSamples"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/webaudio/vowel.mjs": [
|
||||
"vowelFormant"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/webaudio/webaudio.mjs": [
|
||||
"getAudioContext",
|
||||
"panic",
|
||||
"initAudio",
|
||||
"initAudioOnFirstClick",
|
||||
"/packages/webaudio/webaudio.mjs": [
|
||||
"webaudioOutputTrigger",
|
||||
"webaudioOutput",
|
||||
"webaudioOutputTrigger"
|
||||
"webaudioScheduler"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/webaudio/index.mjs": [],
|
||||
"/home/felix/projects/strudel/packages/xen/xen.mjs": [
|
||||
"/packages/webaudio/scope.mjs": [
|
||||
"drawTimeScope",
|
||||
"drawFrequencyScope"
|
||||
],
|
||||
"/packages/webaudio/index.mjs": [],
|
||||
"/packages/xen/xen.mjs": [
|
||||
"edo",
|
||||
"xen",
|
||||
"tuning"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/xen/tunejs.js": [],
|
||||
"/home/felix/projects/strudel/packages/xen/tune.mjs": [
|
||||
"/packages/xen/tunejs.js": [],
|
||||
"/packages/xen/tune.mjs": [
|
||||
"tune"
|
||||
],
|
||||
"/home/felix/projects/strudel/packages/xen/index.mjs": [],
|
||||
"/home/felix/projects/strudel/index.mjs": []
|
||||
"/packages/xen/index.mjs": [],
|
||||
"/index.mjs": []
|
||||
}
|
||||
|
||||
@ -2,19 +2,15 @@ import jsdoc from '../../../doc.json'; // doc.json is built with `npm run jsdoc-
|
||||
const docs = jsdoc.docs.reduce((acc, obj) => Object.assign(acc, { [obj.longname]: obj }), {});
|
||||
import { MiniRepl } from './MiniRepl';
|
||||
|
||||
const getTag = (title, item) => item.tags?.find((t) => t.title === title)?.text;
|
||||
|
||||
export function JsDoc({ name, h = 3, hideDescription, punchcard, canvasHeight }) {
|
||||
const item = docs[name];
|
||||
if (!item) {
|
||||
console.warn('Not found: ' + name);
|
||||
return <div />;
|
||||
}
|
||||
const synonyms = getTag('synonyms', item)?.split(', ') || [];
|
||||
const CustomHeading = `h${h}`;
|
||||
const description =
|
||||
item.description?.replaceAll(/\{@link ([a-zA-Z\.]+)?#?([a-zA-Z]*)\}/g, (_, a, b) => {
|
||||
// console.log(_, 'a', a, 'b', b);
|
||||
return `<a href="#${a.replaceAll('.', '').toLowerCase()}${b ? `-${b}` : ''}">${a}${b ? `#${b}` : ''}</a>`;
|
||||
}) || '';
|
||||
return (
|
||||
@ -22,9 +18,9 @@ export function JsDoc({ name, h = 3, hideDescription, punchcard, canvasHeight })
|
||||
{!!h && <CustomHeading>{item.longname}</CustomHeading>}
|
||||
{!hideDescription && (
|
||||
<>
|
||||
{!!synonyms.length && (
|
||||
{!!item.synonyms_text && (
|
||||
<span>
|
||||
Synonyms: <code>{synonyms.join(', ')}</code>
|
||||
Synonyms: <code>{item.synonyms_text}</code>
|
||||
</span>
|
||||
)}
|
||||
<div dangerouslySetInnerHTML={{ __html: description }} />
|
||||
|
||||
@ -52,11 +52,11 @@ n(pattern).scale("A:minor").piano().room(1)
|
||||
`}
|
||||
/>
|
||||
|
||||
To use hydra audio capture, call `initHydra` with `{audio:true}` configuration param:
|
||||
To use hydra audio capture, call `initHydra` with `{detectAudio:true}` configuration param:
|
||||
|
||||
<MiniRepl
|
||||
client:only="react"
|
||||
tune={`await initHydra({audio:true})
|
||||
tune={`await initHydra({detectAudio:true})
|
||||
let pattern = "<3 4 5 [6 7]*2>"
|
||||
shape(H(pattern)).repeat()
|
||||
.scrollY(
|
||||
|
||||
@ -42,6 +42,10 @@ Some amount of pink noise can also be added to any oscillator by using the `nois
|
||||
|
||||
<MiniRepl client:idle tune={`note("c3").noise("<0.1 0.25 0.5>").scope()`} />
|
||||
|
||||
You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter:
|
||||
|
||||
<MiniRepl client:idle tune={`s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4)).scope()`} />
|
||||
|
||||
### Additive Synthesis
|
||||
|
||||
To tame the harsh sound of the basic waveforms, we can set the `n` control to limit the overtones of the waveform:
|
||||
|
||||
@ -37,6 +37,11 @@ export function Reference() {
|
||||
{visibleFunctions.map((entry, i) => (
|
||||
<section key={i}>
|
||||
<h3 id={`doc-${i}`}>{entry.name}</h3>
|
||||
{!!entry.synonyms_text && (
|
||||
<p>
|
||||
Synonyms: <code>{entry.synonyms_text}</code>
|
||||
</p>
|
||||
)}
|
||||
{/* <small>{entry.meta.filename}</small> */}
|
||||
<p dangerouslySetInnerHTML={{ __html: entry.description }}></p>
|
||||
<ul>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user