mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-22 13:13:10 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 912f755d03 |
@@ -150,7 +150,6 @@ Important: Always publish with `pnpm`, as `npm` does not support overriding main
|
|||||||
|
|
||||||
|
|
||||||
## useful commands
|
## useful commands
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
#regenerate the test snapshots (ex: when updating or creating new pattern functions)
|
#regenerate the test snapshots (ex: when updating or creating new pattern functions)
|
||||||
pnpm snapshot
|
pnpm snapshot
|
||||||
@@ -161,81 +160,6 @@ pnpm run osc
|
|||||||
#build the standalone version
|
#build the standalone version
|
||||||
pnpm tauri build
|
pnpm tauri build
|
||||||
```
|
```
|
||||||
|
|
||||||
## version tag patching
|
|
||||||
|
|
||||||
here's a little guide on how to patch patterns in the database to prevent breaking old patterns due to breaking changes in newer versions.
|
|
||||||
|
|
||||||
the general tactic is to use `// @version x.y` to tag a pattern with a specific strudel version. when a pattern is evaluated, this metadata will de-activate any breaking changes that came after the specified version.
|
|
||||||
for example, in version 1.1, the default value for `fanchor` was changed from `0.5` to `0`.
|
|
||||||
if play a pattern that was made before that change, sounds that use filter evenlopes can sound very different, so by adding `// @version 1.0` will make it sound like it used to.
|
|
||||||
before releasing a new version with breaking changes, we can edit all patterns in the database, inserting the version tag they were created under:
|
|
||||||
|
|
||||||
as an example, to release version 1.2, do the following:
|
|
||||||
|
|
||||||
1. get date range
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# get date of last version:
|
|
||||||
git log -1 --format=%aI @strudel/core@1.1.0
|
|
||||||
# 2024-05-31T23:07:26+02:00
|
|
||||||
|
|
||||||
# get date of current version:
|
|
||||||
git log -1 --format=%aI @strudel/core@1.2.0
|
|
||||||
# 2025-05-01T12:39:24+02:00
|
|
||||||
# might also use todays timestamp if version is not yet released
|
|
||||||
```
|
|
||||||
|
|
||||||
now we know, all patterns between these 2 dates have to receive a version tag (unless they already have one).
|
|
||||||
|
|
||||||
2. get patterns in question
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT *
|
|
||||||
FROM code_v1
|
|
||||||
WHERE code NOT LIKE '%@version%'
|
|
||||||
AND created_at > '2024-05-31T23:07:26+02:00'
|
|
||||||
AND created_at < '2025-05-01T12:39:24+02:00'
|
|
||||||
ORDER BY created_at ASC;
|
|
||||||
```
|
|
||||||
|
|
||||||
this gives us all unversioned patterns that were saved between 1.1.0 and 1.2.0. in this case, it's 9373 patterns!
|
|
||||||
|
|
||||||
3. insert version tags
|
|
||||||
|
|
||||||
we are now ready to insert the version tag to these patterns.
|
|
||||||
before updating thousands of patterns, it's probably a good idea to test if a single one gets udpated:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
UPDATE code_v1
|
|
||||||
SET code = code || E'\n// @version 1.1'
|
|
||||||
WHERE hash = 'Ns2sMB40yIw4';
|
|
||||||
```
|
|
||||||
|
|
||||||
after [verifying](https://strudel.cc/?Ns2sMB40yIw4) that the version tag has been added, let's insert it everywhere:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
UPDATE code_v1
|
|
||||||
SET code = code || E'\n// @version 1.1'
|
|
||||||
WHERE code NOT LIKE '%@version%'
|
|
||||||
AND created_at > '2024-05-31T23:07:26+02:00'
|
|
||||||
AND created_at < '2025-05-01T12:39:24+02:00'
|
|
||||||
```
|
|
||||||
|
|
||||||
4. verify
|
|
||||||
|
|
||||||
we can verify that the edits worked by querying all patterns that contain the new version tag:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT *
|
|
||||||
FROM code_v1
|
|
||||||
WHERE code LIKE '%@version 1.1%'
|
|
||||||
AND created_at > '2024-05-31T23:07:26+02:00'
|
|
||||||
AND created_at < '2025-05-01T12:39:24+02:00'
|
|
||||||
ORDER BY created_at ASC;
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Have Fun
|
## Have Fun
|
||||||
|
|
||||||
Remember to have fun, and that this project is driven by the passion of volunteers!
|
Remember to have fun, and that this project is driven by the passion of volunteers!
|
||||||
|
|||||||
@@ -38,7 +38,13 @@ Licensing info for the default sound banks can be found over on the [dough-sampl
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
There are many ways to contribute to this project! See [contribution guide](./CONTRIBUTING.md). You can find the full list of contributors [here](https://codeberg.org/uzu/strudel/activity/contributors).
|
There are many ways to contribute to this project! See [contribution guide](./CONTRIBUTING.md).
|
||||||
|
|
||||||
|
<a href="https://codeberg.org/uzu/strudel/activity/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=tidalcycles/strudel" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
Made with [contrib.rocks](https://contrib.rocks).
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
|
|||||||
@@ -83,14 +83,4 @@ export default [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// Properties provided by AudioWorkletGlobalScope
|
|
||||||
files: ['packages/superdough/worklets.mjs'],
|
|
||||||
languageOptions: {
|
|
||||||
globals: {
|
|
||||||
currentTime: 'readonly',
|
|
||||||
sampleRate: 'readonly',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
jsdoc-synonyms.js - Add support for @synonyms tag
|
jsdoc-synonyms.js - Add support for @synonym tag
|
||||||
Copyright (C) 2023 Strudel contributors - see <https://codeberg.org/uzu/strudel/activity/contributors>
|
Copyright (C) 2023 Strudel contributors - see <https://codeberg.org/uzu/strudel/activity/contributors>
|
||||||
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/>.
|
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/>.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,91 +1,68 @@
|
|||||||
import jsdoc from '../../doc.json';
|
import jsdoc from '../../doc.json';
|
||||||
|
// import { javascriptLanguage } from '@codemirror/lang-javascript';
|
||||||
import { autocompletion } from '@codemirror/autocomplete';
|
import { autocompletion } from '@codemirror/autocomplete';
|
||||||
import { h } from './html';
|
import { h } from './html';
|
||||||
|
|
||||||
const escapeHtml = (str) => {
|
function plaintext(str) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.innerText = str;
|
div.innerText = str;
|
||||||
return div.innerHTML;
|
return div.innerHTML;
|
||||||
};
|
}
|
||||||
|
|
||||||
const stripHtml = (html) => {
|
const getDocLabel = (doc) => doc.name || doc.longname;
|
||||||
const div = document.createElement('div');
|
const getInnerText = (html) => {
|
||||||
|
var div = document.createElement('div');
|
||||||
div.innerHTML = html;
|
div.innerHTML = html;
|
||||||
return div.textContent || div.innerText || '';
|
return div.textContent || div.innerText || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDocLabel = (doc) => doc.name || doc.longname;
|
export function Autocomplete({ doc, label }) {
|
||||||
|
return h`<div class="prose dark:prose-invert max-h-[400px] overflow-auto p-2">
|
||||||
const buildParamsList = (params) =>
|
<h1 class="pt-0 mt-0">${label || getDocLabel(doc)}</h1>
|
||||||
params?.length
|
${doc.description}
|
||||||
? `
|
<ul>
|
||||||
<div class="autocomplete-info-params-section">
|
${doc.params?.map(
|
||||||
<h4 class="autocomplete-info-section-title">Parameters</h4>
|
({ name, type, description }) =>
|
||||||
<ul class="autocomplete-info-params-list">
|
`<li>${name} : ${type.names?.join(' | ')} ${description ? ` - ${getInnerText(description)}` : ''}</li>`,
|
||||||
${params
|
)}
|
||||||
.map(
|
|
||||||
({ name, type, description }) => `
|
|
||||||
<li class="autocomplete-info-param-item">
|
|
||||||
<span class="autocomplete-info-param-name">${name}</span>
|
|
||||||
<span class="autocomplete-info-param-type">${type.names?.join(' | ')}</span>
|
|
||||||
${description ? `<div class="autocomplete-info-param-desc">${stripHtml(description)}</div>` : ''}
|
|
||||||
</li>
|
|
||||||
`,
|
|
||||||
)
|
|
||||||
.join('')}
|
|
||||||
</ul>
|
</ul>
|
||||||
|
<div>
|
||||||
|
${doc.examples?.map((example) => `<div><pre>${plaintext(example)}</pre></div>`)}
|
||||||
</div>
|
</div>
|
||||||
`
|
</div>`[0];
|
||||||
: '';
|
/*
|
||||||
|
<pre
|
||||||
const buildExamples = (examples) =>
|
className="cursor-pointer"
|
||||||
examples?.length
|
onMouseDown={(e) => {
|
||||||
? `
|
console.log('ola!');
|
||||||
<div class="autocomplete-info-examples-section">
|
navigator.clipboard.writeText(example);
|
||||||
<h4 class="autocomplete-info-section-title">Examples</h4>
|
e.stopPropagation();
|
||||||
${examples
|
}}
|
||||||
.map(
|
>
|
||||||
(example) => `
|
{example}
|
||||||
<pre class="autocomplete-info-example-code">${escapeHtml(example)}</pre>
|
</pre>
|
||||||
`,
|
*/
|
||||||
)
|
}
|
||||||
.join('')}
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: '';
|
|
||||||
|
|
||||||
export const Autocomplete = ({ doc, label }) =>
|
|
||||||
h`
|
|
||||||
<div class="autocomplete-info-tooltip">
|
|
||||||
<h3 class="autocomplete-info-function-name">${label || getDocLabel(doc)}</h3>
|
|
||||||
${doc.description ? `<p class="autocomplete-info-function-description">${doc.description}</p>` : ''}
|
|
||||||
${buildParamsList(doc.params)}
|
|
||||||
${buildExamples(doc.examples)}
|
|
||||||
</div>
|
|
||||||
`[0];
|
|
||||||
|
|
||||||
const isValidDoc = (doc) => {
|
|
||||||
const label = getDocLabel(doc);
|
|
||||||
return label && !label.startsWith('_') && !['package'].includes(doc.kind);
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasExcludedTags = (doc) =>
|
|
||||||
['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag));
|
|
||||||
|
|
||||||
const jsdocCompletions = jsdoc.docs
|
const jsdocCompletions = jsdoc.docs
|
||||||
.filter((doc) => isValidDoc(doc) && !hasExcludedTags(doc))
|
.filter(
|
||||||
|
(doc) =>
|
||||||
|
getDocLabel(doc) &&
|
||||||
|
!getDocLabel(doc).startsWith('_') &&
|
||||||
|
!['package'].includes(doc.kind) &&
|
||||||
|
!['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)),
|
||||||
|
)
|
||||||
// https://codemirror.net/docs/ref/#autocomplete.Completion
|
// https://codemirror.net/docs/ref/#autocomplete.Completion
|
||||||
.map((doc) => ({
|
.map((doc) /*: Completion */ => ({
|
||||||
label: getDocLabel(doc),
|
label: getDocLabel(doc),
|
||||||
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
|
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
|
||||||
info: () => Autocomplete({ doc }),
|
info: () => Autocomplete({ doc }),
|
||||||
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
|
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const strudelAutocomplete = (context) => {
|
export const strudelAutocomplete = (context /* : CompletionContext */) => {
|
||||||
const word = context.matchBefore(/\w*/);
|
let word = context.matchBefore(/\w*/);
|
||||||
if (word.from === word.to && !context.explicit) return null;
|
if (word.from == word.to && !context.explicit) return null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
from: word.from,
|
from: word.from,
|
||||||
options: jsdocCompletions,
|
options: jsdocCompletions,
|
||||||
@@ -97,5 +74,11 @@ export const strudelAutocomplete = (context) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isAutoCompletionEnabled = (enabled) =>
|
export function isAutoCompletionEnabled(on) {
|
||||||
enabled ? [autocompletion({ override: [strudelAutocomplete] })] : [];
|
return on
|
||||||
|
? [
|
||||||
|
autocompletion({ override: [strudelAutocomplete] }),
|
||||||
|
//javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }),
|
||||||
|
]
|
||||||
|
: []; // autocompletion({ override: [] })
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { closeBrackets } from '@codemirror/autocomplete';
|
import { closeBrackets } from '@codemirror/autocomplete';
|
||||||
export { toggleComment, toggleBlockComment, toggleLineComment, toggleBlockCommentByLine } from '@codemirror/commands';
|
export { toggleComment, toggleBlockComment, toggleLineComment, toggleBlockCommentByLine } from '@codemirror/commands';
|
||||||
// import { search, highlightSelectionMatches } from '@codemirror/search';
|
// import { search, highlightSelectionMatches } from '@codemirror/search';
|
||||||
import { history, indentWithTab } from '@codemirror/commands';
|
import { history } from '@codemirror/commands';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { defaultHighlightStyle, syntaxHighlighting, bracketMatching } from '@codemirror/language';
|
import { defaultHighlightStyle, syntaxHighlighting, bracketMatching } from '@codemirror/language';
|
||||||
import { Compartment, EditorState, Prec } from '@codemirror/state';
|
import { Compartment, EditorState, Prec } from '@codemirror/state';
|
||||||
@@ -37,14 +37,6 @@ const extensions = {
|
|||||||
isActiveLineHighlighted: (on) => (on ? [highlightActiveLine(), highlightActiveLineGutter()] : []),
|
isActiveLineHighlighted: (on) => (on ? [highlightActiveLine(), highlightActiveLineGutter()] : []),
|
||||||
isFlashEnabled,
|
isFlashEnabled,
|
||||||
keybindings,
|
keybindings,
|
||||||
isTabIndentationEnabled: (on) => (on ? keymap.of([indentWithTab]) : []),
|
|
||||||
isMultiCursorEnabled: (on) =>
|
|
||||||
on
|
|
||||||
? [
|
|
||||||
EditorState.allowMultipleSelections.of(true),
|
|
||||||
EditorView.clickAddsSelectionRange.of((ev) => ev.metaKey || ev.ctrlKey),
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
};
|
};
|
||||||
const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
|
const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
|
||||||
|
|
||||||
@@ -59,8 +51,6 @@ export const defaultSettings = {
|
|||||||
isFlashEnabled: true,
|
isFlashEnabled: true,
|
||||||
isTooltipEnabled: false,
|
isTooltipEnabled: false,
|
||||||
isLineWrappingEnabled: false,
|
isLineWrappingEnabled: false,
|
||||||
isTabIndentationEnabled: false,
|
|
||||||
isMultiCursorEnabled: false,
|
|
||||||
theme: 'strudelTheme',
|
theme: 'strudelTheme',
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ const vscodeExtension = (options) => [vscodePlugin].concat(options ?? []);
|
|||||||
const keymaps = {
|
const keymaps = {
|
||||||
vim,
|
vim,
|
||||||
emacs,
|
emacs,
|
||||||
codemirror: () => keymap.of(defaultKeymap),
|
|
||||||
vscode: vscodeExtension,
|
vscode: vscodeExtension,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function keybindings(name) {
|
export function keybindings(name) {
|
||||||
const active = keymaps[name];
|
const active = keymaps[name];
|
||||||
return [active ? active() : [], keymap.of(historyKeymap)];
|
return [keymap.of(defaultKeymap), keymap.of(historyKeymap), active ? active() : []];
|
||||||
|
// keymap.of(searchKeymap),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/codemirror",
|
"name": "@strudel/codemirror",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Codemirror Extensions for Strudel",
|
"description": "Codemirror Extensions for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
+13
-123
@@ -252,20 +252,6 @@ export const { fmenv } = registerControl('fmenv');
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const { fmattack } = registerControl('fmattack');
|
export const { fmattack } = registerControl('fmattack');
|
||||||
|
|
||||||
/**
|
|
||||||
* waveform of the fm modulator
|
|
||||||
*
|
|
||||||
* @name fmwave
|
|
||||||
* @param {number | Pattern} wave waveform
|
|
||||||
* @example
|
|
||||||
* n("0 1 2 3".fast(4)).scale("d:minor").s("sine").fmwave("<sine square sawtooth crackle>").fm(4).fmh(2.01)
|
|
||||||
* @example
|
|
||||||
* n("0 1 2 3".fast(4)).chord("<Dm Am F G>").voicing().s("sawtooth").fmwave("brown").fm(.6)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { fmwave } = registerControl('fmwave');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
|
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
|
||||||
*
|
*
|
||||||
@@ -320,7 +306,6 @@ export const { fft } = registerControl('fft');
|
|||||||
*
|
*
|
||||||
* @name decay
|
* @name decay
|
||||||
* @param {number | Pattern} time decay time in seconds
|
* @param {number | Pattern} time decay time in seconds
|
||||||
* @synonyms dec
|
|
||||||
* @example
|
* @example
|
||||||
* note("c3 e3 f3 g3").decay("<.1 .2 .3 .4>").sustain(0)
|
* note("c3 e3 f3 g3").decay("<.1 .2 .3 .4>").sustain(0)
|
||||||
*
|
*
|
||||||
@@ -459,78 +444,6 @@ export const { crush } = registerControl('crush');
|
|||||||
*/
|
*/
|
||||||
export const { coarse } = registerControl('coarse');
|
export const { coarse } = registerControl('coarse');
|
||||||
|
|
||||||
/**
|
|
||||||
* modulate the amplitude of a sound with a continuous waveform
|
|
||||||
*
|
|
||||||
* @name tremolo
|
|
||||||
* @synonyms trem
|
|
||||||
* @param {number | Pattern} speed modulation speed in HZ
|
|
||||||
* @example
|
|
||||||
* note("d d d# d".fast(4)).s("supersaw").tremolo("<3 2 100> ").tremoloskew("<.5>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { tremolo } = registerControl(['tremolo', 'tremolodepth', 'tremoloskew', 'tremolophase'], 'trem');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* modulate the amplitude of a sound with a continuous waveform
|
|
||||||
*
|
|
||||||
* @name tremolosync
|
|
||||||
* @synonyms tremsync
|
|
||||||
* @param {number | Pattern} cycles modulation speed in cycles
|
|
||||||
* @example
|
|
||||||
* note("d d d# d".fast(4)).s("supersaw").tremolosync("4").tremoloskew("<1 .5 0>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { tremolosync } = registerControl(
|
|
||||||
['tremolosync', 'tremolodepth', 'tremoloskew', 'tremolophase'],
|
|
||||||
'tremsync',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* depth of amplitude modulation
|
|
||||||
*
|
|
||||||
* @name tremolodepth
|
|
||||||
* @synonyms tremdepth
|
|
||||||
* @param {number | Pattern} depth
|
|
||||||
* @example
|
|
||||||
* note("a1 a1 a#1 a1".fast(4)).s("pulse").tremsync(4).tremolodepth("<1 2 .7>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { tremolodepth } = registerControl('tremolodepth', 'tremdepth');
|
|
||||||
/**
|
|
||||||
* alter the shape of the modulation waveform
|
|
||||||
*
|
|
||||||
* @name tremoloskew
|
|
||||||
* @synonyms tremskew
|
|
||||||
* @param {number | Pattern} amount between 0 & 1, the shape of the waveform
|
|
||||||
* @example
|
|
||||||
* note("{f a c e}%16").s("sawtooth").tremsync(4).tremoloskew("<.5 0 1>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { tremoloskew } = registerControl('tremoloskew', 'tremskew');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* alter the phase of the modulation waveform
|
|
||||||
*
|
|
||||||
* @name tremolophase
|
|
||||||
* @synonyms tremphase
|
|
||||||
* @param {number | Pattern} offset the offset in cycles of the modulation
|
|
||||||
* @example
|
|
||||||
* note("{f a c e}%16").s("sawtooth").tremsync(4).tremolophase("<0 .25 .66>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { tremolophase } = registerControl('tremolophase', 'tremphase');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* shape of amplitude modulation
|
|
||||||
*
|
|
||||||
* @name tremoloshape
|
|
||||||
* @param {number | Pattern} shape tri | square | sine | saw | ramp
|
|
||||||
* @example
|
|
||||||
* note("{f g c d}%16").tremsync(4).tremoloshape("<sine tri square>").s("sawtooth")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { tremoloshape } = registerControl('tremoloshape', 'tremshape');
|
|
||||||
/**
|
/**
|
||||||
* filter overdrive for supported filter types
|
* filter overdrive for supported filter types
|
||||||
*
|
*
|
||||||
@@ -540,42 +453,6 @@ export const { tremoloshape } = registerControl('tremoloshape', 'tremshape');
|
|||||||
* note("{f g g c d a a#}%16".sub(17)).s("supersaw").lpenv(8).lpf(150).lpq(.8).ftype('ladder').drive("<.5 4>")
|
* note("{f g g c d a a#}%16".sub(17)).s("supersaw").lpenv(8).lpf(150).lpq(.8).ftype('ladder').drive("<.5 4>")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* modulate the amplitude of an orbit to create a "sidechain" like effect
|
|
||||||
*
|
|
||||||
* @name duckorbit
|
|
||||||
* @param {number | Pattern} orbit target orbit
|
|
||||||
* @example
|
|
||||||
* $: n(run(16)).scale("c:minor:pentatonic").s("sawtooth").delay(.7).orbit(2)
|
|
||||||
* $: s("bd:4!4").beat("0,4,8,11,14",16).duckorbit(2).duckattack(0.2).duckdepth(1)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { duck } = registerControl('duckorbit', 'duck');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the amount of ducking applied to target orbit
|
|
||||||
*
|
|
||||||
* @name duckdepth
|
|
||||||
* @param {number | Pattern} depth depth of modulation from 0 to 1
|
|
||||||
* @example
|
|
||||||
* stack( n(run(8)).scale("c:minor").s("sawtooth").delay(.7).orbit(2), s("bd:4!4").beat("0,4,8,11,14",16).duckorbit(2).duckattack(0.2).duckdepth("<1 .9 .6 0>"))
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const { duckdepth } = registerControl('duckdepth');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the attack time of the duck effect
|
|
||||||
*
|
|
||||||
* @name duckattack
|
|
||||||
* @param {number | Pattern} time
|
|
||||||
* @example
|
|
||||||
* stack( n(run(8)).scale("c:minor").s("sawtooth").delay(.7).orbit(2), s("bd:4!4").beat("0,4,8,11,14",16).duckorbit(2).duckattack("<0.2 0 0.4>").duckdepth(1))
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const { duckattack } = registerControl('duckattack', 'duckatt');
|
|
||||||
|
|
||||||
export const { drive } = registerControl('drive');
|
export const { drive } = registerControl('drive');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1684,6 +1561,18 @@ export const { density } = registerControl('density');
|
|||||||
// ['modwheel'],
|
// ['modwheel'],
|
||||||
export const { expression } = registerControl('expression');
|
export const { expression } = registerControl('expression');
|
||||||
export const { sustainpedal } = registerControl('sustainpedal');
|
export const { sustainpedal } = registerControl('sustainpedal');
|
||||||
|
/* // TODO: doesn't seem to do anything
|
||||||
|
*
|
||||||
|
* Tremolo Audio DSP effect
|
||||||
|
*
|
||||||
|
* @name tremolodepth
|
||||||
|
* @param {number | Pattern} depth between 0 and 1
|
||||||
|
* @example
|
||||||
|
* n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const { tremolodepth, tremdp } = registerControl('tremolodepth', 'tremdp');
|
||||||
|
export const { tremolorate, tremr } = registerControl('tremolorate', 'tremr');
|
||||||
|
|
||||||
export const { fshift } = registerControl('fshift');
|
export const { fshift } = registerControl('fshift');
|
||||||
export const { fshiftnote } = registerControl('fshiftnote');
|
export const { fshiftnote } = registerControl('fshiftnote');
|
||||||
@@ -1760,6 +1649,7 @@ export const { zmod } = registerControl('zmod');
|
|||||||
// like crush but scaled differently
|
// like crush but scaled differently
|
||||||
export const { zcrush } = registerControl('zcrush');
|
export const { zcrush } = registerControl('zcrush');
|
||||||
export const { zdelay } = registerControl('zdelay');
|
export const { zdelay } = registerControl('zdelay');
|
||||||
|
export const { tremolo } = registerControl('tremolo');
|
||||||
export const { zzfx } = registerControl('zzfx');
|
export const { zzfx } = registerControl('zzfx');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import createClock from './zyklus.mjs';
|
import createClock from './zyklus.mjs';
|
||||||
import { errorLogger, logger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
|
|
||||||
export class Cyclist {
|
export class Cyclist {
|
||||||
constructor({
|
constructor({
|
||||||
@@ -67,7 +67,6 @@ export class Cyclist {
|
|||||||
// the following line is dumb and only here for backwards compatibility
|
// the following line is dumb and only here for backwards compatibility
|
||||||
// see https://codeberg.org/uzu/strudel/pulls/1004
|
// see https://codeberg.org/uzu/strudel/pulls/1004
|
||||||
const deadline = targetTime - phase;
|
const deadline = targetTime - phase;
|
||||||
// this onTrigger has another signature
|
|
||||||
onTrigger?.(hap, deadline, duration, this.cps, targetTime);
|
onTrigger?.(hap, deadline, duration, this.cps, targetTime);
|
||||||
if (hap.value.cps !== undefined && this.cps != hap.value.cps) {
|
if (hap.value.cps !== undefined && this.cps != hap.value.cps) {
|
||||||
this.cps = hap.value.cps;
|
this.cps = hap.value.cps;
|
||||||
@@ -76,7 +75,7 @@ export class Cyclist {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorLogger(e);
|
logger(`[cyclist] error: ${e.message}`);
|
||||||
onError?.(e);
|
onError?.(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ https://rohandrape.net/?t=hmt
|
|||||||
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/>.
|
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/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { timeCat, register, silence, stack, pure, _morph } from './pattern.mjs';
|
import { timeCat, register, silence } from './pattern.mjs';
|
||||||
import { rotate, flatten, splitAt, zipWith } from './util.mjs';
|
import { rotate, flatten, splitAt, zipWith } from './util.mjs';
|
||||||
import Fraction, { lcm } from './fraction.mjs';
|
import Fraction, { lcm } from './fraction.mjs';
|
||||||
|
|
||||||
@@ -196,26 +196,3 @@ export const euclidLegato = register(['euclidLegato'], function (pulses, steps,
|
|||||||
export const euclidLegatoRot = register(['euclidLegatoRot'], function (pulses, steps, rotation, pat) {
|
export const euclidLegatoRot = register(['euclidLegatoRot'], function (pulses, steps, rotation, pat) {
|
||||||
return _euclidLegato(pulses, steps, rotation, pat);
|
return _euclidLegato(pulses, steps, rotation, pat);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* A 'euclid' variant with an additional parameter that morphs the resulting
|
|
||||||
* rhythm from 0 (no morphing) to 1 (completely 'even'). For example
|
|
||||||
* `sound("bd").euclidish(3,8,0)` would be the same as
|
|
||||||
* `sound("bd").euclid(3,8)`, and `sound("bd").euclidish(3,8,1)` would be the
|
|
||||||
* same as `sound("bd bd bd")`. `sound("bd").euclidish(3,8,0.5)` would have a
|
|
||||||
* groove somewhere between.
|
|
||||||
* Inspired by the work of Malcom Braff.
|
|
||||||
* @name euclidish
|
|
||||||
* @synonyms eish
|
|
||||||
* @memberof Pattern
|
|
||||||
* @param {number} pulses the number of onsets
|
|
||||||
* @param {number} steps the number of steps to fill
|
|
||||||
* @param {number} groove exists between the extremes of 0 (straight euclidian) and 1 (straight pulse)
|
|
||||||
* @example
|
|
||||||
* sound("hh").euclidish(7,12,sine.slow(8))
|
|
||||||
* .pan(sine.slow(8))
|
|
||||||
*/
|
|
||||||
export const { euclidish, eish } = register(['euclidish', 'eish'], function (pulses, steps, perc, pat) {
|
|
||||||
const morphed = _morph(bjork(pulses, steps), new Array(pulses).fill(1), perc);
|
|
||||||
return pat.struct(morphed).setSteps(steps);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/
|
|||||||
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/>.
|
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/>.
|
||||||
*/
|
*/
|
||||||
import Fraction from './fraction.mjs';
|
import Fraction from './fraction.mjs';
|
||||||
import { stringifyValues } from './util.mjs';
|
|
||||||
|
|
||||||
export class Hap {
|
export class Hap {
|
||||||
/*
|
/*
|
||||||
@@ -149,7 +148,13 @@ export class Hap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showWhole(compact = false) {
|
showWhole(compact = false) {
|
||||||
return `${this.whole == undefined ? '~' : this.whole.show()}: ${stringifyValues(this.value, compact)}`;
|
return `${this.whole == undefined ? '~' : this.whole.show()}: ${
|
||||||
|
typeof this.value === 'object'
|
||||||
|
? compact
|
||||||
|
? JSON.stringify(this.value).slice(1, -1).replaceAll('"', '').replaceAll(',', ' ')
|
||||||
|
: JSON.stringify(this.value)
|
||||||
|
: this.value
|
||||||
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
combineContext(b) {
|
combineContext(b) {
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ let debounce = 1000,
|
|||||||
lastMessage,
|
lastMessage,
|
||||||
lastTime;
|
lastTime;
|
||||||
|
|
||||||
export function errorLogger(e, origin = 'cyclist') {
|
|
||||||
//TODO: add some kind of debug flag that enables this while in dev mode
|
|
||||||
// console.error(e);
|
|
||||||
logger(`[${origin}] error: ${e.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function logger(message, type, data = {}) {
|
export function logger(message, type, data = {}) {
|
||||||
let t = performance.now();
|
let t = performance.now();
|
||||||
if (lastMessage === message && t - lastTime < debounce) {
|
if (lastMessage === message && t - lastTime < debounce) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export class NeoCyclist {
|
|||||||
constructor({ onTrigger, onToggle, getTime }) {
|
constructor({ onTrigger, onToggle, getTime }) {
|
||||||
this.started = false;
|
this.started = false;
|
||||||
this.cps = 0.5;
|
this.cps = 0.5;
|
||||||
|
this.lastTick = 0; // absolute time when last tick (clock callback) happened
|
||||||
this.getTime = getTime; // get absolute time
|
this.getTime = getTime; // get absolute time
|
||||||
this.time_at_last_tick_message = 0;
|
this.time_at_last_tick_message = 0;
|
||||||
// the clock of the worker and the audio context clock can drift apart over time
|
// the clock of the worker and the audio context clock can drift apart over time
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/core",
|
"name": "@strudel/core",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Port of Tidal Cycles to JavaScript",
|
"description": "Port of Tidal Cycles to JavaScript",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
+23
-95
@@ -21,8 +21,6 @@ import {
|
|||||||
numeralArgs,
|
numeralArgs,
|
||||||
parseNumeral,
|
parseNumeral,
|
||||||
pairs,
|
pairs,
|
||||||
zipWith,
|
|
||||||
stringifyValues,
|
|
||||||
} from './util.mjs';
|
} from './util.mjs';
|
||||||
import drawLine from './drawLine.mjs';
|
import drawLine from './drawLine.mjs';
|
||||||
import { logger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
@@ -48,10 +46,11 @@ export class Pattern {
|
|||||||
* @param {function} query - The function that maps a `State` to an array of `Hap`.
|
* @param {function} query - The function that maps a `State` to an array of `Hap`.
|
||||||
* @noAutocomplete
|
* @noAutocomplete
|
||||||
*/
|
*/
|
||||||
constructor(query, steps = undefined) {
|
constructor(query, steps = undefined, alignment = undefined) {
|
||||||
this.query = query;
|
this.query = query;
|
||||||
this._Pattern = true; // this property is used to detectinstance of another Pattern
|
this._Pattern = true; // this property is used to detectinstance of another Pattern
|
||||||
this._steps = steps; // in terms of number of steps per cycle
|
this._steps = steps; // in terms of number of steps per cycle
|
||||||
|
this._alignment = alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _steps() {
|
get _steps() {
|
||||||
@@ -78,6 +77,11 @@ export class Pattern {
|
|||||||
return this._steps !== undefined;
|
return this._steps !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAlignment(alignment) {
|
||||||
|
this._alignment = alignment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Haskell-style functor, applicative and monadic operations
|
// Haskell-style functor, applicative and monadic operations
|
||||||
|
|
||||||
@@ -854,29 +858,14 @@ export class Pattern {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
log(func = (_, hap) => `[hap] ${hap.showWhole(true)}`, getData = (_, hap) => ({ hap })) {
|
||||||
* Writes the content of the current event to the console (visible in the side menu).
|
|
||||||
* @name log
|
|
||||||
* @memberof Pattern
|
|
||||||
* @example
|
|
||||||
* s("bd sd").log()
|
|
||||||
*/
|
|
||||||
log(func = (hap) => `[hap] ${hap.showWhole(true)}`, getData = (hap) => ({ hap })) {
|
|
||||||
return this.onTrigger((...args) => {
|
return this.onTrigger((...args) => {
|
||||||
logger(func(...args), undefined, getData(...args));
|
logger(func(...args), undefined, getData(...args));
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
logValues(func = id) {
|
||||||
* A simplified version of `log` which writes all "values" (various configurable parameters)
|
return this.log((_, hap) => func(hap.value));
|
||||||
* within the event to the console (visible in the side menu).
|
|
||||||
* @name logValues
|
|
||||||
* @memberof Pattern
|
|
||||||
* @example
|
|
||||||
* s("bd sd").gain("0.25 0.5 1").n("2 1 0").logValues()
|
|
||||||
*/
|
|
||||||
logValues(func = (value) => `[hap] ${stringifyValues(value, true)}`) {
|
|
||||||
return this.log((hap) => func(hap.value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
@@ -1305,7 +1294,7 @@ export function sequenceP(pats) {
|
|||||||
* @synonyms polyrhythm, pr
|
* @synonyms polyrhythm, pr
|
||||||
* @example
|
* @example
|
||||||
* stack("g3", "b3", ["e4", "d4"]).note()
|
* stack("g3", "b3", ["e4", "d4"]).note()
|
||||||
* // "g3,b3,[e4 d4]".note()
|
* // "g3,b3,[e4,d4]".note()
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // As a chained function:
|
* // As a chained function:
|
||||||
@@ -1586,7 +1575,7 @@ export const func = curry((a, b) => reify(b).func(a));
|
|||||||
/**
|
/**
|
||||||
* Registers a new pattern method. The method is added to the Pattern class + the standalone function is returned from register.
|
* Registers a new pattern method. The method is added to the Pattern class + the standalone function is returned from register.
|
||||||
*
|
*
|
||||||
* @param {string | string[]} name name of the function, or an array of names to be used as synonyms
|
* @param {string} name name of the function
|
||||||
* @param {function} func function with 1 or more params, where last is the current pattern
|
* @param {function} func function with 1 or more params, where last is the current pattern
|
||||||
* @noAutocomplete
|
* @noAutocomplete
|
||||||
*
|
*
|
||||||
@@ -1627,8 +1616,13 @@ export function register(name, func, patternify = true, preserveSteps = false, j
|
|||||||
let mapFn = (...args) => {
|
let mapFn = (...args) => {
|
||||||
return func(...args, pat);
|
return func(...args, pat);
|
||||||
};
|
};
|
||||||
mapFn = curry(mapFn, null, arity - 1);
|
// mapFn = curry(mapFn, null, arity - 1);
|
||||||
result = join(right.reduce((acc, p) => acc.appLeft(p), left.fmap(mapFn)));
|
// result = join(right.reduce((acc, p) => acc.appLeft(p), left.fmap(mapFn)));
|
||||||
|
// patternify2 f pata patb patc = pata >>= \a -> patb >>= \b -> f a b patc
|
||||||
|
function bindArgs(argv, pat, ...pats) {
|
||||||
|
return pat.innerBind((x) => (pats.length ? bindArgs([...argv, x], ...pats) : mapFn(...argv, x)));
|
||||||
|
}
|
||||||
|
result = bindArgs([], ...firstArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (preserveSteps) {
|
if (preserveSteps) {
|
||||||
@@ -2539,7 +2533,7 @@ export const { fastchunk, fastChunk } = register(
|
|||||||
/**
|
/**
|
||||||
* Like `chunk`, but the function is applied to a looped subcycle of the source pattern.
|
* Like `chunk`, but the function is applied to a looped subcycle of the source pattern.
|
||||||
* @name chunkInto
|
* @name chunkInto
|
||||||
* @synonyms chunkinto
|
* @synonym chunkinto
|
||||||
* @memberof Pattern
|
* @memberof Pattern
|
||||||
* @example
|
* @example
|
||||||
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
|
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
|
||||||
@@ -2552,7 +2546,7 @@ export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], fun
|
|||||||
/**
|
/**
|
||||||
* Like `chunkInto`, but moves backwards through the chunks.
|
* Like `chunkInto`, but moves backwards through the chunks.
|
||||||
* @name chunkBackInto
|
* @name chunkBackInto
|
||||||
* @synonyms chunkbackinto
|
* @synonym chunkbackinto
|
||||||
* @memberof Pattern
|
* @memberof Pattern
|
||||||
* @example
|
* @example
|
||||||
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
|
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
|
||||||
@@ -2582,7 +2576,7 @@ export const bypass = register(
|
|||||||
* Loops the pattern inside an `offset` for `cycles`.
|
* Loops the pattern inside an `offset` for `cycles`.
|
||||||
* If you think of the entire span of time in cycles as a ribbon, you can cut a single piece and loop it.
|
* If you think of the entire span of time in cycles as a ribbon, you can cut a single piece and loop it.
|
||||||
* @name ribbon
|
* @name ribbon
|
||||||
* @synonyms rib
|
* @synonym rib
|
||||||
* @param {number} offset start point of loop in cycles
|
* @param {number} offset start point of loop in cycles
|
||||||
* @param {number} cycles loop length in cycles
|
* @param {number} cycles loop length in cycles
|
||||||
* @example
|
* @example
|
||||||
@@ -3280,7 +3274,7 @@ export const slice = register(
|
|||||||
* s("bd!8").onTriggerTime((hap) => {console.info(hap)})
|
* s("bd!8").onTriggerTime((hap) => {console.info(hap)})
|
||||||
*/
|
*/
|
||||||
Pattern.prototype.onTriggerTime = function (func) {
|
Pattern.prototype.onTriggerTime = function (func) {
|
||||||
return this.onTrigger((hap, currentTime, _cps, targetTime) => {
|
return this.onTrigger((t_deprecate, hap, currentTime, cps = 1, targetTime) => {
|
||||||
const diff = targetTime - currentTime;
|
const diff = targetTime - currentTime;
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
func(hap);
|
func(hap);
|
||||||
@@ -3417,69 +3411,3 @@ export const { beat } = register(
|
|||||||
['beat'],
|
['beat'],
|
||||||
__beat((x) => x.innerJoin()),
|
__beat((x) => x.innerJoin()),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const _morph = (from, to, by) => {
|
|
||||||
by = Fraction(by);
|
|
||||||
const dur = Fraction(1).div(from.length);
|
|
||||||
const positions = (list) => {
|
|
||||||
const result = [];
|
|
||||||
for (const [pos, value] of list.entries()) {
|
|
||||||
if (value) {
|
|
||||||
result.push([Fraction(pos).div(list.length), value]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
const arcs = zipWith(
|
|
||||||
([posa, valuea], [posb, valueb]) => {
|
|
||||||
const b = by.mul(posb - posa).add(posa);
|
|
||||||
const e = b.add(dur);
|
|
||||||
return new TimeSpan(b, e);
|
|
||||||
},
|
|
||||||
positions(from),
|
|
||||||
positions(to),
|
|
||||||
);
|
|
||||||
function query(state) {
|
|
||||||
const cycle = state.span.begin.sam();
|
|
||||||
const cycleArc = state.span.cycleArc();
|
|
||||||
const result = [];
|
|
||||||
for (const whole of arcs) {
|
|
||||||
const part = whole.intersection(cycleArc);
|
|
||||||
if (part !== undefined) {
|
|
||||||
result.push(
|
|
||||||
new Hap(
|
|
||||||
whole.withTime((x) => x.add(cycle)),
|
|
||||||
part.withTime((x) => x.add(cycle)),
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return new Pattern(query).splitQueries();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes two binary rhythms represented as lists of 1s and 0s, and a number
|
|
||||||
* between 0 and 1 that morphs between them. The two lists should contain the same
|
|
||||||
* number of true values.
|
|
||||||
* @example
|
|
||||||
* sound("hh").struct(morph([1,0,1,0,1,0,1,0], // straight rhythm
|
|
||||||
* [1,1,0,1,0,1,0], // wonky rhythm
|
|
||||||
* 0.25 // creates a slightly wonky rhythm
|
|
||||||
* )
|
|
||||||
* )
|
|
||||||
* @example
|
|
||||||
* sound("hh").struct(morph("1:0:1:0:1:0:1:0", // straight rhythm
|
|
||||||
* "1:1:0:1:0:1:0", // wonky rhythm
|
|
||||||
* sine.slow(8) // slowly morph between the rhythms
|
|
||||||
* )
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
export const morph = (frompat, topat, bypat) => {
|
|
||||||
frompat = reify(frompat);
|
|
||||||
topat = reify(topat);
|
|
||||||
bypat = reify(bypat);
|
|
||||||
return frompat.innerBind((from) => topat.innerBind((to) => bypat.innerBind((by) => _morph(from, to, by))));
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { NeoCyclist } from './neocyclist.mjs';
|
import { NeoCyclist } from './neocyclist.mjs';
|
||||||
import { Cyclist } from './cyclist.mjs';
|
import { Cyclist } from './cyclist.mjs';
|
||||||
import { evaluate as _evaluate } from './evaluate.mjs';
|
import { evaluate as _evaluate } from './evaluate.mjs';
|
||||||
import { errorLogger, logger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
import { setTime } from './time.mjs';
|
import { setTime } from './time.mjs';
|
||||||
import { evalScope } from './evaluate.mjs';
|
import { evalScope } from './evaluate.mjs';
|
||||||
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
||||||
@@ -245,7 +245,6 @@ export function repl({
|
|||||||
export const getTrigger =
|
export const getTrigger =
|
||||||
({ getTime, defaultOutput }) =>
|
({ getTime, defaultOutput }) =>
|
||||||
async (hap, deadline, duration, cps, t) => {
|
async (hap, deadline, duration, cps, t) => {
|
||||||
// ^ this signature is different from hap.context.onTrigger, as set by Pattern.onTrigger(onTrigger)
|
|
||||||
// TODO: get rid of deadline after https://codeberg.org/uzu/strudel/pulls/1004
|
// TODO: get rid of deadline after https://codeberg.org/uzu/strudel/pulls/1004
|
||||||
try {
|
try {
|
||||||
if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
|
if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
|
||||||
@@ -253,9 +252,9 @@ export const getTrigger =
|
|||||||
}
|
}
|
||||||
if (hap.context.onTrigger) {
|
if (hap.context.onTrigger) {
|
||||||
// call signature of output / onTrigger is different...
|
// call signature of output / onTrigger is different...
|
||||||
await hap.context.onTrigger(hap, getTime(), cps, t);
|
await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps, t);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
errorLogger(err, 'getTrigger');
|
logger(`[cyclist] error: ${err.message}`, 'error');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ export const randrun = (n) => {
|
|||||||
const rands = timeToRands(t.floor().add(0.5), n);
|
const rands = timeToRands(t.floor().add(0.5), n);
|
||||||
const nums = rands
|
const nums = rands
|
||||||
.map((n, i) => [n, i])
|
.map((n, i) => [n, i])
|
||||||
.sort((a, b) => (a[0] > b[0]) - (a[0] < b[0]))
|
.sort((a, b) => a[0] > b[0] - a[0] < b[0])
|
||||||
.map((x) => x[1]);
|
.map((x) => x[1]);
|
||||||
const i = t.cyclePos().mul(n).floor() % n;
|
const i = t.cyclePos().mul(n).floor() % n;
|
||||||
return nums[i];
|
return nums[i];
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function triggerSpeech(words, lang, voice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const speak = register('speak', function (lang, voice, pat) {
|
export const speak = register('speak', function (lang, voice, pat) {
|
||||||
return pat.onTrigger((hap) => {
|
return pat.onTrigger((_, hap) => {
|
||||||
triggerSpeech(hap.value, lang, voice);
|
triggerSpeech(hap.value, lang, voice);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
|
|
||||||
import Fraction from 'fraction.js';
|
import Fraction from 'fraction.js';
|
||||||
|
|
||||||
import { describe, it, expect, vi } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TimeSpan,
|
TimeSpan,
|
||||||
@@ -55,8 +55,6 @@ import {
|
|||||||
expand,
|
expand,
|
||||||
} from '../index.mjs';
|
} from '../index.mjs';
|
||||||
|
|
||||||
import { log, logValues } from '../pattern.mjs';
|
|
||||||
|
|
||||||
import { steady } from '../signal.mjs';
|
import { steady } from '../signal.mjs';
|
||||||
|
|
||||||
import { n, s } from '../controls.mjs';
|
import { n, s } from '../controls.mjs';
|
||||||
@@ -1308,40 +1306,4 @@ describe('Pattern', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('log', () => {
|
|
||||||
it('logs to console', () => {
|
|
||||||
const mockConsoleLog = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
||||||
const pattern = pure('a').log();
|
|
||||||
const haps = pattern.queryArc(0, 1);
|
|
||||||
|
|
||||||
// Force a trigger
|
|
||||||
haps.forEach((hap) => {
|
|
||||||
hap.context?.onTrigger?.(hap);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockConsoleLog).toHaveBeenCalledWith(
|
|
||||||
'%c[hap] 0/1 → 1/1: a',
|
|
||||||
'background-color: black;color:white;border-radius:15px',
|
|
||||||
);
|
|
||||||
mockConsoleLog.mockRestore();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('logValues', () => {
|
|
||||||
it('logs values to console', () => {
|
|
||||||
const mockConsoleLog = vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
||||||
const pattern = pure('a').note('c#').logValues();
|
|
||||||
const haps = pattern.queryArc(0, 1);
|
|
||||||
|
|
||||||
// Force a trigger
|
|
||||||
haps.forEach((hap) => {
|
|
||||||
hap.context?.onTrigger?.(hap);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockConsoleLog).toHaveBeenCalledWith(
|
|
||||||
'%c[hap] value:a note:c#',
|
|
||||||
'background-color: black;color:white;border-radius:15px',
|
|
||||||
);
|
|
||||||
mockConsoleLog.mockRestore();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export class TimeSpan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
intersection(other) {
|
intersection(other) {
|
||||||
// Intersection of two timespans, returns undefined if they don't intersect.
|
// Intersection of two timespans, returns None if they don't intersect.
|
||||||
const intersect_begin = this.begin.max(other.begin);
|
const intersect_begin = this.begin.max(other.begin);
|
||||||
const intersect_end = this.end.min(other.end);
|
const intersect_end = this.end.min(other.end);
|
||||||
|
|
||||||
|
|||||||
@@ -487,13 +487,3 @@ export function getCurrentKeyboardState() {
|
|||||||
// }
|
// }
|
||||||
// return lcm((x * y) / gcd(x, y), ...z);
|
// return lcm((x * y) / gcd(x, y), ...z);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// Takes values -- typically derived from events, i.e. `hap`s -- and renders them
|
|
||||||
// into a readable format
|
|
||||||
export function stringifyValues(value, compact = false) {
|
|
||||||
return typeof value === 'object'
|
|
||||||
? compact
|
|
||||||
? JSON.stringify(value).slice(1, -1).replaceAll('"', '').replaceAll(',', ' ')
|
|
||||||
: JSON.stringify(value)
|
|
||||||
: value;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const csound = register('csound', (instrument, pat) => {
|
|||||||
instrument = instrument || 'triangle';
|
instrument = instrument || 'triangle';
|
||||||
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
|
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
|
||||||
// TODO: find a alternative way to wait for csound to load (to wait with first time playback)
|
// TODO: find a alternative way to wait for csound to load (to wait with first time playback)
|
||||||
return pat.onTrigger((hap, currentTime, _cps, targetTime) => {
|
return pat.onTrigger((time_deprecate, hap, currentTime, _cps, targetTime) => {
|
||||||
if (!_csound) {
|
if (!_csound) {
|
||||||
logger('[csound] not loaded yet', 'warning');
|
logger('[csound] not loaded yet', 'warning');
|
||||||
return;
|
return;
|
||||||
@@ -142,7 +142,7 @@ export const csoundm = register('csoundm', (instrument, pat) => {
|
|||||||
p1 = `"${instrument}"`;
|
p1 = `"${instrument}"`;
|
||||||
}
|
}
|
||||||
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
|
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
|
||||||
return pat.onTrigger((hap, currentTime, _cps, targetTime) => {
|
return pat.onTrigger((tidal_time, hap) => {
|
||||||
if (!_csound) {
|
if (!_csound) {
|
||||||
logger('[csound] not loaded yet', 'warning');
|
logger('[csound] not loaded yet', 'warning');
|
||||||
return;
|
return;
|
||||||
@@ -151,7 +151,7 @@ export const csoundm = register('csoundm', (instrument, pat) => {
|
|||||||
throw new Error('csound only support objects as hap values');
|
throw new Error('csound only support objects as hap values');
|
||||||
}
|
}
|
||||||
// Time in seconds counting from now.
|
// Time in seconds counting from now.
|
||||||
const p2 = targetTime - currentTime;
|
const p2 = tidal_time - getAudioContext().currentTime;
|
||||||
const p3 = hap.duration.valueOf() + 0;
|
const p3 = hap.duration.valueOf() + 0;
|
||||||
const frequency = getFrequency(hap);
|
const frequency = getFrequency(hap);
|
||||||
let { gain = 1, velocity = 0.9 } = hap.value;
|
let { gain = 1, velocity = 0.9 } = hap.value;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/csound",
|
"name": "@strudel/csound",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "csound bindings for strudel",
|
"description": "csound bindings for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const OFF_MESSAGE = 0x80;
|
|||||||
const CC_MESSAGE = 0xb0;
|
const CC_MESSAGE = 0xb0;
|
||||||
|
|
||||||
Pattern.prototype.midi = function (output) {
|
Pattern.prototype.midi = function (output) {
|
||||||
return this.onTrigger((hap, currentTime, cps, targetTime) => {
|
return this.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => {
|
||||||
let { note, nrpnn, nrpv, ccn, ccv, velocity = 0.9, gain = 1 } = hap.value;
|
let { note, nrpnn, nrpv, ccn, ccv, velocity = 0.9, gain = 1 } = hap.value;
|
||||||
//magic number to get audio engine to line up, can probably be calculated somehow
|
//magic number to get audio engine to line up, can probably be calculated somehow
|
||||||
const latencyMs = 34;
|
const latencyMs = 34;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Invoke } from './utils.mjs';
|
|||||||
|
|
||||||
const collator = new ClockCollator({});
|
const collator = new ClockCollator({});
|
||||||
|
|
||||||
export async function oscTriggerTauri(hap, currentTime, cps = 1, targetTime) {
|
export async function oscTriggerTauri(t_deprecate, hap, currentTime, cps = 1, targetTime) {
|
||||||
const controls = parseControlsFromHap(hap, cps);
|
const controls = parseControlsFromHap(hap, cps);
|
||||||
const params = [];
|
const params = [];
|
||||||
const timestamp = collator.calculateTimestamp(currentTime, targetTime);
|
const timestamp = collator.calculateTimestamp(currentTime, targetTime);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/draw",
|
"name": "@strudel/draw",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Helpers for drawing with Strudel",
|
"description": "Helpers for drawing with Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/embed",
|
"name": "@strudel/embed",
|
||||||
"version": "1.1.1",
|
"version": "1.1.0",
|
||||||
"description": "Embeddable Web Component to load a Strudel REPL into an iframe",
|
"description": "Embeddable Web Component to load a Strudel REPL into an iframe",
|
||||||
"main": "embed.js",
|
"main": "embed.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/gamepad",
|
"name": "@strudel/gamepad",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Gamepad Inputs for strudel",
|
"description": "Gamepad Inputs for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/hydra",
|
"name": "@strudel/hydra",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Hydra integration for strudel",
|
"description": "Hydra integration for strudel",
|
||||||
"main": "hydra.mjs",
|
"main": "hydra.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ Pattern.prototype.midi = function (midiport, options = {}) {
|
|||||||
logger(`Midi device disconnected! Available: ${getMidiDeviceNamesString(outputs)}`),
|
logger(`Midi device disconnected! Available: ${getMidiDeviceNamesString(outputs)}`),
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.onTrigger((hap, currentTime, cps, targetTime) => {
|
return this.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => {
|
||||||
if (!WebMidi.enabled) {
|
if (!WebMidi.enabled) {
|
||||||
logger('Midi not enabled');
|
logger('Midi not enabled');
|
||||||
return;
|
return;
|
||||||
@@ -493,9 +493,6 @@ export async function midin(input) {
|
|||||||
otherInputs?.length ? `Also available: ${getMidiDeviceNamesString(otherInputs)}` : ''
|
otherInputs?.length ? `Also available: ${getMidiDeviceNamesString(otherInputs)}` : ''
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
// ensure refs for this input are initialized
|
|
||||||
if (!refs[input]) {
|
|
||||||
refs[input] = {};
|
refs[input] = {};
|
||||||
}
|
}
|
||||||
const cc = (cc) => ref(() => refs[input][cc] || 0);
|
const cc = (cc) => ref(() => refs[input][cc] || 0);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/midi",
|
"name": "@strudel/midi",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "Midi API for strudel",
|
"description": "Midi API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mini",
|
"name": "@strudel/mini",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Mini notation for strudel",
|
"description": "Mini notation for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mondolang",
|
"name": "mondolang",
|
||||||
"version": "1.1.1",
|
"version": "1.1.0",
|
||||||
"description": "a language for functional composition that translates to js",
|
"description": "a language for functional composition that translates to js",
|
||||||
"main": "mondo.mjs",
|
"main": "mondo.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ lib['%'] = pace;
|
|||||||
lib['?'] = degradeBy; // todo: default 0.5 not working..
|
lib['?'] = degradeBy; // todo: default 0.5 not working..
|
||||||
lib[':'] = tail;
|
lib[':'] = tail;
|
||||||
lib['..'] = range;
|
lib['..'] = range;
|
||||||
lib['def'] = () => silence;
|
|
||||||
lib['or'] = (...children) => chooseIn(...children); // always has structure but is cyclewise.. e.g. "s oh*8.dec[.04 | .5]"
|
lib['or'] = (...children) => chooseIn(...children); // always has structure but is cyclewise.. e.g. "s oh*8.dec[.04 | .5]"
|
||||||
//lib['or'] = (...children) => chooseOut(...children); // "s oh*8.dec[.04 | .5]" is better but "dec[.04 | .5].s oh*8" has no struct
|
//lib['or'] = (...children) => chooseOut(...children); // "s oh*8.dec[.04 | .5]" is better but "dec[.04 | .5].s oh*8" has no struct
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mondo",
|
"name": "@strudel/mondo",
|
||||||
"version": "1.1.1",
|
"version": "1.1.0",
|
||||||
"description": "mondo notation for strudel",
|
"description": "mondo notation for strudel",
|
||||||
"main": "mondough.mjs",
|
"main": "mondough.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/motion",
|
"name": "@strudel/motion",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "DeviceMotion API for strudel",
|
"description": "DeviceMotion API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mqtt",
|
"name": "@strudel/mqtt",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "MQTT API for strudel",
|
"description": "MQTT API for strudel",
|
||||||
"main": "mqtt.mjs",
|
"main": "mqtt.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function parseControlsFromHap(hap, cps) {
|
|||||||
|
|
||||||
const collator = new ClockCollator({});
|
const collator = new ClockCollator({});
|
||||||
|
|
||||||
export async function oscTrigger(hap, currentTime, cps = 1, targetTime) {
|
export async function oscTrigger(t_deprecate, hap, currentTime, cps = 1, targetTime) {
|
||||||
const osc = await connect();
|
const osc = await connect();
|
||||||
const controls = parseControlsFromHap(hap, cps);
|
const controls = parseControlsFromHap(hap, cps);
|
||||||
const keyvals = Object.entries(controls).flat();
|
const keyvals = Object.entries(controls).flat();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/osc",
|
"name": "@strudel/osc",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "OSC messaging for strudel",
|
"description": "OSC messaging for strudel",
|
||||||
"main": "osc.mjs",
|
"main": "osc.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/reference",
|
"name": "@strudel/reference",
|
||||||
"version": "1.2.1",
|
"version": "1.2.0",
|
||||||
"description": "Headless reference of all strudel functions",
|
"description": "Headless reference of all strudel functions",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/repl",
|
"name": "@strudel/repl",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "Strudel REPL as a Web Component",
|
"description": "Strudel REPL as a Web Component",
|
||||||
"module": "index.mjs",
|
"module": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export async function prebake() {
|
|||||||
samples(`${ds}/tidal-drum-machines.json`),
|
samples(`${ds}/tidal-drum-machines.json`),
|
||||||
samples(`${ds}/piano.json`),
|
samples(`${ds}/piano.json`),
|
||||||
samples(`${ds}/Dirt-Samples.json`),
|
samples(`${ds}/Dirt-Samples.json`),
|
||||||
samples(`${ds}/uzu-drumkit.json`),
|
samples(`${ds}/EmuSP12.json`),
|
||||||
samples(`${ds}/vcsl.json`),
|
samples(`${ds}/vcsl.json`),
|
||||||
samples(`${ds}/mridangam.json`),
|
samples(`${ds}/mridangam.json`),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/serial",
|
"name": "@strudel/serial",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Webserial API for strudel",
|
"description": "Webserial API for strudel",
|
||||||
"main": "serial.mjs",
|
"main": "serial.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ export default {
|
|||||||
],
|
],
|
||||||
gm_synth_bass_1: [
|
gm_synth_bass_1: [
|
||||||
// Synth Bass 1: Bass
|
// Synth Bass 1: Bass
|
||||||
// '0380_Aspirin_sf2_file', // broken in safari https://codeberg.org/uzu/strudel/issues/1384
|
'0380_Aspirin_sf2_file',
|
||||||
'0380_Chaos_sf2_file',
|
'0380_Chaos_sf2_file',
|
||||||
'0380_FluidR3_GM_sf2_file',
|
'0380_FluidR3_GM_sf2_file',
|
||||||
// 0380_GeneralUserGS_sf2_file // laut
|
// 0380_GeneralUserGS_sf2_file // laut
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/soundfonts",
|
"name": "@strudel/soundfonts",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "Soundsfont support for strudel",
|
"description": "Soundsfont support for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { getAudioContext, registerSound } from '@strudel/webaudio';
|
|||||||
import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato';
|
import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato';
|
||||||
|
|
||||||
Pattern.prototype.soundfont = function (sf, n = 0) {
|
Pattern.prototype.soundfont = function (sf, n = 0) {
|
||||||
return this.onTrigger((h, ct, cps, targetTime) => {
|
return this.onTrigger((time_deprecate, h, ct, cps, targetTime) => {
|
||||||
const ctx = getAudioContext();
|
const ctx = getAudioContext();
|
||||||
const note = getPlayableNoteValue(h);
|
const note = getPlayableNoteValue(h);
|
||||||
const preset = sf.presets[n % sf.presets.length];
|
const preset = sf.presets[n % sf.presets.length];
|
||||||
|
|||||||
@@ -74,6 +74,6 @@ export const dough = async (code) => {
|
|||||||
worklet.node.connect(ac.destination);
|
worklet.node.connect(ac.destination);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function doughTrigger(hap, currentTime, cps, targetTime) {
|
export function doughTrigger(time_deprecate, hap, currentTime, cps, targetTime) {
|
||||||
window.postMessage({ time: targetTime, dough: hap.value, currentTime, duration: hap.duration, cps });
|
window.postMessage({ time: targetTime, dough: hap.value, currentTime, duration: hap.duration, cps });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { getAudioContext } from './superdough.mjs';
|
import { getAudioContext } from './superdough.mjs';
|
||||||
import { clamp, nanFallback } from './util.mjs';
|
import { clamp, nanFallback } from './util.mjs';
|
||||||
import { getNoiseBuffer } from './noise.mjs';
|
|
||||||
|
|
||||||
export const noises = ['pink', 'white', 'brown', 'crackle'];
|
|
||||||
|
|
||||||
export function gainNode(value) {
|
export function gainNode(value) {
|
||||||
const node = getAudioContext().createGain();
|
const node = getAudioContext().createGain();
|
||||||
@@ -209,8 +206,7 @@ export function getVibratoOscillator(param, value, t) {
|
|||||||
// ConstantSource inherits AudioScheduledSourceNode, which has scheduling abilities
|
// ConstantSource inherits AudioScheduledSourceNode, which has scheduling abilities
|
||||||
// a bit of a hack, but it works very well :)
|
// a bit of a hack, but it works very well :)
|
||||||
export function webAudioTimeout(audioContext, onComplete, startTime, stopTime) {
|
export function webAudioTimeout(audioContext, onComplete, startTime, stopTime) {
|
||||||
const constantNode = new ConstantSourceNode(audioContext);
|
const constantNode = audioContext.createConstantSource();
|
||||||
|
|
||||||
constantNode.start(startTime);
|
constantNode.start(startTime);
|
||||||
constantNode.stop(stopTime);
|
constantNode.stop(stopTime);
|
||||||
constantNode.onended = () => {
|
constantNode.onended = () => {
|
||||||
@@ -220,17 +216,9 @@ export function webAudioTimeout(audioContext, onComplete, startTime, stopTime) {
|
|||||||
}
|
}
|
||||||
const mod = (freq, range = 1, type = 'sine') => {
|
const mod = (freq, range = 1, type = 'sine') => {
|
||||||
const ctx = getAudioContext();
|
const ctx = getAudioContext();
|
||||||
let osc;
|
const osc = ctx.createOscillator();
|
||||||
if (noises.includes(type)) {
|
|
||||||
osc = ctx.createBufferSource();
|
|
||||||
osc.buffer = getNoiseBuffer(type, 2);
|
|
||||||
osc.loop = true;
|
|
||||||
} else {
|
|
||||||
osc = ctx.createOscillator();
|
|
||||||
osc.type = type;
|
osc.type = type;
|
||||||
osc.frequency.value = freq;
|
osc.frequency.value = freq;
|
||||||
}
|
|
||||||
|
|
||||||
osc.start();
|
osc.start();
|
||||||
const g = new GainNode(ctx, { gain: range });
|
const g = new GainNode(ctx, { gain: range });
|
||||||
osc.connect(g); // -range, range
|
osc.connect(g); // -range, range
|
||||||
@@ -265,7 +253,7 @@ export function applyFM(param, value, begin) {
|
|||||||
|
|
||||||
modulator = fmmod.node;
|
modulator = fmmod.node;
|
||||||
stop = fmmod.stop;
|
stop = fmmod.stop;
|
||||||
if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].some((v) => v !== undefined)) {
|
if (![fmAttack, fmDecay, fmSustain, fmRelease, fmVelocity].find((v) => v !== undefined)) {
|
||||||
// no envelope by default
|
// no envelope by default
|
||||||
modulator.connect(param);
|
modulator.connect(param);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
let log = (msg) => console.log(msg);
|
let log = (msg) => console.log(msg);
|
||||||
|
|
||||||
export function errorLogger(e, origin = 'cyclist') {
|
|
||||||
//TODO: add some kind of debug flag that enables this while in dev mode
|
|
||||||
// console.error(e);
|
|
||||||
logger(`[${origin}] error: ${e.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const logger = (...args) => log(...args);
|
export const logger = (...args) => log(...args);
|
||||||
|
|
||||||
export const setLogger = (fn) => {
|
export const setLogger = (fn) => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { getAudioContext } from './superdough.mjs';
|
|||||||
let noiseCache = {};
|
let noiseCache = {};
|
||||||
|
|
||||||
// lazy generates noise buffers and keeps them forever
|
// lazy generates noise buffers and keeps them forever
|
||||||
export function getNoiseBuffer(type, density) {
|
function getNoiseBuffer(type, density) {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
if (noiseCache[type]) {
|
if (noiseCache[type]) {
|
||||||
return noiseCache[type];
|
return noiseCache[type];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "superdough",
|
"name": "superdough",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
import './feedbackdelay.mjs';
|
import './feedbackdelay.mjs';
|
||||||
import './reverb.mjs';
|
import './reverb.mjs';
|
||||||
import './vowel.mjs';
|
import './vowel.mjs';
|
||||||
import { clamp, nanFallback, _mod, cycleToSeconds, secondsToCycle } from './util.mjs';
|
import { clamp, nanFallback, _mod, cycleToSeconds } from './util.mjs';
|
||||||
import workletsUrl from './worklets.mjs?audioworklet';
|
import workletsUrl from './worklets.mjs?audioworklet';
|
||||||
import { createFilter, gainNode, getCompressor, getWorklet, webAudioTimeout } from './helpers.mjs';
|
import { createFilter, gainNode, getCompressor, getWorklet } from './helpers.mjs';
|
||||||
import { map } from 'nanostores';
|
import { map } from 'nanostores';
|
||||||
import { logger, errorLogger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
import { loadBuffer } from './sampler.mjs';
|
import { loadBuffer } from './sampler.mjs';
|
||||||
|
|
||||||
export const DEFAULT_MAX_POLYPHONY = 128;
|
export const DEFAULT_MAX_POLYPHONY = 128;
|
||||||
@@ -28,13 +28,6 @@ export function setMultiChannelOrbits(bool) {
|
|||||||
multiChannelOrbits = bool == true;
|
multiChannelOrbits = bool == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getModulationShapeInput(val) {
|
|
||||||
if (typeof val === 'number') {
|
|
||||||
return val % 5;
|
|
||||||
}
|
|
||||||
return { tri: 0, triangle: 0, sine: 1, ramp: 2, saw: 3, square: 4 }[val] ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const soundMap = map();
|
export const soundMap = map();
|
||||||
|
|
||||||
export function registerSound(key, onTrigger, data = {}) {
|
export function registerSound(key, onTrigger, data = {}) {
|
||||||
@@ -133,7 +126,7 @@ export const getAudioDevices = async () => {
|
|||||||
return devicesMap;
|
return devicesMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
let defaultDefaultValues = {
|
const defaultDefaultValues = {
|
||||||
s: 'triangle',
|
s: 'triangle',
|
||||||
gain: 0.8,
|
gain: 0.8,
|
||||||
postgain: 1,
|
postgain: 1,
|
||||||
@@ -157,17 +150,6 @@ let defaultDefaultValues = {
|
|||||||
fft: 8,
|
fft: 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultDefaultDefaultValues = Object.freeze({ ...defaultDefaultValues });
|
|
||||||
|
|
||||||
export function setDefault(control, value) {
|
|
||||||
// const main = getControlName(control); // we cant do this because superdough is independent of strudel/core
|
|
||||||
defaultDefaultValues[control] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetDefaults() {
|
|
||||||
defaultDefaultValues = { ...defaultDefaultDefaultValues };
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultControls = new Map(Object.entries(defaultDefaultValues));
|
let defaultControls = new Map(Object.entries(defaultDefaultValues));
|
||||||
|
|
||||||
export function setDefaultValue(key, value) {
|
export function setDefaultValue(key, value) {
|
||||||
@@ -331,40 +313,30 @@ function getDelay(orbit, delaytime, delayfeedback, t, channels) {
|
|||||||
//logger(`delayfeedback was clamped to ${maxfeedback} to save your ears`);
|
//logger(`delayfeedback was clamped to ${maxfeedback} to save your ears`);
|
||||||
}
|
}
|
||||||
delayfeedback = clamp(delayfeedback, 0, 0.98);
|
delayfeedback = clamp(delayfeedback, 0, 0.98);
|
||||||
if (!orbits[orbit].delayNode) {
|
if (!delays[orbit]) {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const dly = ac.createFeedbackDelay(1, delaytime, delayfeedback);
|
const dly = ac.createFeedbackDelay(1, delaytime, delayfeedback);
|
||||||
dly.start?.(t); // for some reason, this throws when audion extension is installed..
|
dly.start?.(t); // for some reason, this throws when audion extension is installed..
|
||||||
connectToOrbit(dly, orbit);
|
connectToDestination(dly, channels);
|
||||||
orbits[orbit].delayNode = dly;
|
delays[orbit] = dly;
|
||||||
}
|
}
|
||||||
orbits[orbit].delayNode.delayTime.value !== delaytime &&
|
delays[orbit].delayTime.value !== delaytime && delays[orbit].delayTime.setValueAtTime(delaytime, t);
|
||||||
orbits[orbit].delayNode.delayTime.setValueAtTime(delaytime, t);
|
delays[orbit].feedback.value !== delayfeedback && delays[orbit].feedback.setValueAtTime(delayfeedback, t);
|
||||||
orbits[orbit].delayNode.feedback.value !== delayfeedback &&
|
return delays[orbit];
|
||||||
orbits[orbit].delayNode.feedback.setValueAtTime(delayfeedback, t);
|
|
||||||
return orbits[orbit].delayNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLfo(audioContext, begin, end, properties = {}) {
|
export function getLfo(audioContext, time, end, properties = {}) {
|
||||||
const { shape = 0, ...props } = properties;
|
return getWorklet(audioContext, 'lfo-processor', {
|
||||||
const { dcoffset = -0.5, depth = 1 } = properties;
|
|
||||||
const lfoprops = {
|
|
||||||
frequency: 1,
|
frequency: 1,
|
||||||
depth,
|
depth: 1,
|
||||||
skew: 0.5,
|
skew: 0,
|
||||||
phaseoffset: 0,
|
phaseoffset: 0,
|
||||||
time: begin,
|
time,
|
||||||
begin,
|
|
||||||
end,
|
end,
|
||||||
shape: getModulationShapeInput(shape),
|
shape: 1,
|
||||||
dcoffset,
|
dcoffset: -0.5,
|
||||||
min: dcoffset * depth,
|
...properties,
|
||||||
max: dcoffset * depth + depth,
|
});
|
||||||
curve: 1,
|
|
||||||
...props,
|
|
||||||
};
|
|
||||||
|
|
||||||
return getWorklet(audioContext, 'lfo-processor', lfoprops);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) {
|
function getPhaser(time, end, frequency = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) {
|
||||||
@@ -398,73 +370,31 @@ function getFilterType(ftype) {
|
|||||||
return typeof ftype === 'number' ? filterTypes[Math.floor(_mod(ftype, filterTypes.length))] : ftype;
|
return typeof ftype === 'number' ? filterTypes[Math.floor(_mod(ftype, filterTypes.length))] : ftype;
|
||||||
}
|
}
|
||||||
|
|
||||||
//type orbit {
|
let reverbs = {};
|
||||||
// gain: number,
|
|
||||||
// reverbNode: reverbNode
|
|
||||||
// delayNode: delayNode
|
|
||||||
//}
|
|
||||||
let orbits = {};
|
|
||||||
function connectToOrbit(node, orbit) {
|
|
||||||
if (orbits[orbit] == null) {
|
|
||||||
errorLogger(new Error('target orbit does not exist'), 'superdough');
|
|
||||||
}
|
|
||||||
node.connect(orbits[orbit].gain);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setOrbit(audioContext, orbit, channels) {
|
|
||||||
if (orbits[orbit] == null) {
|
|
||||||
orbits[orbit] = {
|
|
||||||
gain: new GainNode(audioContext, { gain: 1 }),
|
|
||||||
};
|
|
||||||
connectToDestination(orbits[orbit].gain, channels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function duckOrbit(audioContext, targetOrbit, t, attacktime = 0.1, duckdepth = 1) {
|
|
||||||
const targetArr = [targetOrbit].flat();
|
|
||||||
|
|
||||||
targetArr.forEach((target) => {
|
|
||||||
if (orbits[target] == null) {
|
|
||||||
errorLogger(new Error(`duck target orbit ${target} does not exist`), 'superdough');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
webAudioTimeout(
|
|
||||||
audioContext,
|
|
||||||
() => {
|
|
||||||
orbits[target].gain.gain.cancelScheduledValues(t);
|
|
||||||
const currVal = orbits[target].gain.gain.value;
|
|
||||||
orbits[target].gain.gain.linearRampToValueAtTime(clamp(1 - Math.pow(duckdepth, 0.5), 0.01, currVal), t);
|
|
||||||
orbits[target].gain.gain.exponentialRampToValueAtTime(1, t + Math.max(0.002, attacktime));
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
t - 0.01,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasChanged = (now, before) => now !== undefined && now !== before;
|
let hasChanged = (now, before) => now !== undefined && now !== before;
|
||||||
function getReverb(orbit, duration, fade, lp, dim, ir) {
|
function getReverb(orbit, duration, fade, lp, dim, ir, channels) {
|
||||||
// If no reverb has been created for a given orbit, create one
|
// If no reverb has been created for a given orbit, create one
|
||||||
if (!orbits[orbit].reverbNode) {
|
if (!reverbs[orbit]) {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
const reverb = ac.createReverb(duration, fade, lp, dim, ir);
|
const reverb = ac.createReverb(duration, fade, lp, dim, ir);
|
||||||
connectToOrbit(reverb, orbit);
|
connectToDestination(reverb, channels);
|
||||||
orbits[orbit].reverbNode = reverb;
|
reverbs[orbit] = reverb;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
hasChanged(duration, orbits[orbit].reverbNode.duration) ||
|
hasChanged(duration, reverbs[orbit].duration) ||
|
||||||
hasChanged(fade, orbits[orbit].reverbNode.fade) ||
|
hasChanged(fade, reverbs[orbit].fade) ||
|
||||||
hasChanged(lp, orbits[orbit].reverbNode.lp) ||
|
hasChanged(lp, reverbs[orbit].lp) ||
|
||||||
hasChanged(dim, orbits[orbit].reverbNode.dim) ||
|
hasChanged(dim, reverbs[orbit].dim) ||
|
||||||
orbits[orbit].reverbNode.ir !== ir
|
reverbs[orbit].ir !== ir
|
||||||
) {
|
) {
|
||||||
// only regenerate when something has changed
|
// only regenerate when something has changed
|
||||||
// avoids endless regeneration on things like
|
// avoids endless regeneration on things like
|
||||||
// stack(s("a"), s("b").rsize(8)).room(.5)
|
// stack(s("a"), s("b").rsize(8)).room(.5)
|
||||||
// this only works when args may stay undefined until here
|
// this only works when args may stay undefined until here
|
||||||
// setting default values breaks this
|
// setting default values breaks this
|
||||||
orbits[orbit].reverbNode.generate(duration, fade, lp, dim, ir);
|
reverbs[orbit].generate(duration, fade, lp, dim, ir);
|
||||||
}
|
}
|
||||||
return orbits[orbit].reverbNode;
|
return reverbs[orbit];
|
||||||
}
|
}
|
||||||
|
|
||||||
export let analysers = {},
|
export let analysers = {},
|
||||||
@@ -507,7 +437,8 @@ function effectSend(input, effect, wet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function resetGlobalEffects() {
|
export function resetGlobalEffects() {
|
||||||
orbits = {};
|
delays = {};
|
||||||
|
reverbs = {};
|
||||||
analysers = {};
|
analysers = {};
|
||||||
analysersData = {};
|
analysersData = {};
|
||||||
}
|
}
|
||||||
@@ -519,10 +450,9 @@ function mapChannelNumbers(channels) {
|
|||||||
return (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
return (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5) => {
|
export const superdough = async (value, t, hapDuration, cps = 0.5) => {
|
||||||
// new: t is always expected to be the absolute target onset time
|
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
|
t = typeof t === 'string' && t.startsWith('=') ? Number(t.slice(1)) : ac.currentTime + t;
|
||||||
let { stretch } = value;
|
let { stretch } = value;
|
||||||
if (stretch != null) {
|
if (stretch != null) {
|
||||||
//account for phase vocoder latency
|
//account for phase vocoder latency
|
||||||
@@ -548,25 +478,15 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
}
|
}
|
||||||
// destructure
|
// destructure
|
||||||
let {
|
let {
|
||||||
tremolo,
|
|
||||||
tremolosync,
|
|
||||||
tremolodepth = 1,
|
|
||||||
tremoloskew,
|
|
||||||
tremolophase = 0,
|
|
||||||
tremoloshape,
|
|
||||||
s = getDefaultValue('s'),
|
s = getDefaultValue('s'),
|
||||||
bank,
|
bank,
|
||||||
source,
|
source,
|
||||||
gain = getDefaultValue('gain'),
|
gain = getDefaultValue('gain'),
|
||||||
postgain = getDefaultValue('postgain'),
|
postgain = getDefaultValue('postgain'),
|
||||||
density = getDefaultValue('density'),
|
density = getDefaultValue('density'),
|
||||||
duckorbit,
|
|
||||||
duckattack,
|
|
||||||
duckdepth,
|
|
||||||
// filters
|
// filters
|
||||||
fanchor = getDefaultValue('fanchor'),
|
fanchor = getDefaultValue('fanchor'),
|
||||||
drive = 0.69,
|
drive = 0.69,
|
||||||
release = 0,
|
|
||||||
// low pass
|
// low pass
|
||||||
cutoff,
|
cutoff,
|
||||||
lpenv,
|
lpenv,
|
||||||
@@ -599,9 +519,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
phasercenter,
|
phasercenter,
|
||||||
//
|
//
|
||||||
coarse,
|
coarse,
|
||||||
|
|
||||||
crush,
|
crush,
|
||||||
dry,
|
|
||||||
shape,
|
shape,
|
||||||
shapevol = getDefaultValue('shapevol'),
|
shapevol = getDefaultValue('shapevol'),
|
||||||
distort,
|
distort,
|
||||||
@@ -635,13 +553,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
const orbitChannels = mapChannelNumbers(
|
const orbitChannels = mapChannelNumbers(
|
||||||
multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels'),
|
multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels'),
|
||||||
);
|
);
|
||||||
|
|
||||||
const channels = value.channels != null ? mapChannelNumbers(value.channels) : orbitChannels;
|
const channels = value.channels != null ? mapChannelNumbers(value.channels) : orbitChannels;
|
||||||
setOrbit(ac, orbit, channels, t, cycle, cps);
|
|
||||||
|
|
||||||
if (duckorbit != null) {
|
|
||||||
duckOrbit(ac, duckorbit, t, duckattack, duckdepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
gain = applyGainCurve(nanFallback(gain, 1));
|
gain = applyGainCurve(nanFallback(gain, 1));
|
||||||
postgain = applyGainCurve(postgain);
|
postgain = applyGainCurve(postgain);
|
||||||
@@ -649,11 +561,8 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
distortvol = applyGainCurve(distortvol);
|
distortvol = applyGainCurve(distortvol);
|
||||||
delay = applyGainCurve(delay);
|
delay = applyGainCurve(delay);
|
||||||
velocity = applyGainCurve(velocity);
|
velocity = applyGainCurve(velocity);
|
||||||
tremolodepth = applyGainCurve(tremolodepth);
|
|
||||||
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
|
gain *= velocity; // velocity currently only multiplies with gain. it might do other things in the future
|
||||||
|
|
||||||
const end = t + hapDuration;
|
|
||||||
const endWithRelease = end + release;
|
|
||||||
const chainID = Math.round(Math.random() * 1000000);
|
const chainID = Math.round(Math.random() * 1000000);
|
||||||
|
|
||||||
// oldest audio nodes will be destroyed if maximum polyphony is exceeded
|
// oldest audio nodes will be destroyed if maximum polyphony is exceeded
|
||||||
@@ -728,7 +637,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
lprelease,
|
lprelease,
|
||||||
lpenv,
|
lpenv,
|
||||||
t,
|
t,
|
||||||
end,
|
t + hapDuration,
|
||||||
fanchor,
|
fanchor,
|
||||||
ftype,
|
ftype,
|
||||||
drive,
|
drive,
|
||||||
@@ -752,7 +661,7 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
hprelease,
|
hprelease,
|
||||||
hpenv,
|
hpenv,
|
||||||
t,
|
t,
|
||||||
end,
|
t + hapDuration,
|
||||||
fanchor,
|
fanchor,
|
||||||
);
|
);
|
||||||
chain.push(hp());
|
chain.push(hp());
|
||||||
@@ -763,7 +672,20 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
|
|
||||||
if (bandf !== undefined) {
|
if (bandf !== undefined) {
|
||||||
let bp = () =>
|
let bp = () =>
|
||||||
createFilter(ac, 'bandpass', bandf, bandq, bpattack, bpdecay, bpsustain, bprelease, bpenv, t, end, fanchor);
|
createFilter(
|
||||||
|
ac,
|
||||||
|
'bandpass',
|
||||||
|
bandf,
|
||||||
|
bandq,
|
||||||
|
bpattack,
|
||||||
|
bpdecay,
|
||||||
|
bpsustain,
|
||||||
|
bprelease,
|
||||||
|
bpenv,
|
||||||
|
t,
|
||||||
|
t + hapDuration,
|
||||||
|
fanchor,
|
||||||
|
);
|
||||||
chain.push(bp());
|
chain.push(bp());
|
||||||
if (ftype === '24db') {
|
if (ftype === '24db') {
|
||||||
chain.push(bp());
|
chain.push(bp());
|
||||||
@@ -781,33 +703,6 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape, postgain: shapevol }));
|
shape !== undefined && chain.push(getWorklet(ac, 'shape-processor', { shape, postgain: shapevol }));
|
||||||
distort !== undefined && chain.push(getWorklet(ac, 'distort-processor', { distort, postgain: distortvol }));
|
distort !== undefined && chain.push(getWorklet(ac, 'distort-processor', { distort, postgain: distortvol }));
|
||||||
|
|
||||||
if (tremolosync != null) {
|
|
||||||
tremolo = cps * tremolosync;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tremolo !== undefined) {
|
|
||||||
// Allow clipping of modulator for more dynamic possiblities, and to prevent speaker overload
|
|
||||||
// EX: a triangle waveform will clip like this /-\ when the depth is above 1
|
|
||||||
const gain = Math.max(1 - tremolodepth, 0);
|
|
||||||
const amGain = new GainNode(ac, { gain });
|
|
||||||
|
|
||||||
const time = cycle / cps;
|
|
||||||
const lfo = getLfo(ac, t, endWithRelease, {
|
|
||||||
skew: tremoloskew ?? (tremoloshape != null ? 0.5 : 1),
|
|
||||||
frequency: tremolo,
|
|
||||||
depth: tremolodepth,
|
|
||||||
time,
|
|
||||||
dcoffset: 0,
|
|
||||||
shape: tremoloshape,
|
|
||||||
phaseoffset: tremolophase,
|
|
||||||
min: 0,
|
|
||||||
max: 1,
|
|
||||||
curve: 1.5,
|
|
||||||
});
|
|
||||||
lfo.connect(amGain.gain);
|
|
||||||
chain.push(amGain);
|
|
||||||
}
|
|
||||||
|
|
||||||
compressorThreshold !== undefined &&
|
compressorThreshold !== undefined &&
|
||||||
chain.push(
|
chain.push(
|
||||||
getCompressor(ac, compressorThreshold, compressorRatio, compressorKnee, compressorAttack, compressorRelease),
|
getCompressor(ac, compressorThreshold, compressorRatio, compressorKnee, compressorAttack, compressorRelease),
|
||||||
@@ -821,13 +716,14 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
}
|
}
|
||||||
// phaser
|
// phaser
|
||||||
if (phaser !== undefined && phaserdepth > 0) {
|
if (phaser !== undefined && phaserdepth > 0) {
|
||||||
const phaserFX = getPhaser(t, endWithRelease, phaser, phaserdepth, phasercenter, phasersweep);
|
const phaserFX = getPhaser(t, t + hapDuration, phaser, phaserdepth, phasercenter, phasersweep);
|
||||||
chain.push(phaserFX);
|
chain.push(phaserFX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// last gain
|
// last gain
|
||||||
const post = new GainNode(ac, { gain: postgain });
|
const post = new GainNode(ac, { gain: postgain });
|
||||||
chain.push(post);
|
chain.push(post);
|
||||||
|
connectToDestination(post, channels);
|
||||||
|
|
||||||
// delay
|
// delay
|
||||||
let delaySend;
|
let delaySend;
|
||||||
@@ -862,14 +758,6 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
|
|||||||
analyserSend = effectSend(post, analyserNode, 1);
|
analyserSend = effectSend(post, analyserNode, 1);
|
||||||
audioNodes.push(analyserSend);
|
audioNodes.push(analyserSend);
|
||||||
}
|
}
|
||||||
if (dry != null) {
|
|
||||||
dry = applyGainCurve(dry);
|
|
||||||
const dryGain = new GainNode(ac, { gain: dry });
|
|
||||||
chain.push(dryGain);
|
|
||||||
connectToOrbit(dryGain, orbit);
|
|
||||||
} else {
|
|
||||||
connectToOrbit(post, orbit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect chain elements together
|
// connect chain elements together
|
||||||
chain.slice(1).reduce((last, current) => last.connect(current), chain[0]);
|
chain.slice(1).reduce((last, current) => last.connect(current), chain[0]);
|
||||||
|
|||||||
@@ -9,13 +9,12 @@ import {
|
|||||||
getVibratoOscillator,
|
getVibratoOscillator,
|
||||||
webAudioTimeout,
|
webAudioTimeout,
|
||||||
getWorklet,
|
getWorklet,
|
||||||
noises,
|
|
||||||
} from './helpers.mjs';
|
} from './helpers.mjs';
|
||||||
import { getNoiseMix, getNoiseOscillator } from './noise.mjs';
|
import { getNoiseMix, getNoiseOscillator } from './noise.mjs';
|
||||||
|
|
||||||
const getFrequencyFromValue = (value, defaultNote = 36) => {
|
const getFrequencyFromValue = (value) => {
|
||||||
let { note, freq } = value;
|
let { note, freq } = value;
|
||||||
note = note || defaultNote;
|
note = note || 36;
|
||||||
if (typeof note === 'string') {
|
if (typeof note === 'string') {
|
||||||
note = noteToMidi(note); // e.g. c3 => 48
|
note = noteToMidi(note); // e.g. c3 => 48
|
||||||
}
|
}
|
||||||
@@ -41,17 +40,7 @@ const waveformAliases = [
|
|||||||
['saw', 'sawtooth'],
|
['saw', 'sawtooth'],
|
||||||
['sin', 'sine'],
|
['sin', 'sine'],
|
||||||
];
|
];
|
||||||
|
const noises = ['pink', 'white', 'brown', 'crackle'];
|
||||||
function makeSaturationCurve(amount, n_samples) {
|
|
||||||
const k = typeof amount === 'number' ? amount : 50;
|
|
||||||
const curve = new Float32Array(n_samples);
|
|
||||||
|
|
||||||
for (let i = 0; i < n_samples; i++) {
|
|
||||||
const x = (i * 2) / n_samples - 1;
|
|
||||||
curve[i] = Math.tanh(x * k);
|
|
||||||
}
|
|
||||||
return curve;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerSynthSounds() {
|
export function registerSynthSounds() {
|
||||||
[...waveforms].forEach((s) => {
|
[...waveforms].forEach((s) => {
|
||||||
@@ -95,75 +84,6 @@ export function registerSynthSounds() {
|
|||||||
{ type: 'synth', prebake: true },
|
{ type: 'synth', prebake: true },
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
registerSound(
|
|
||||||
'sbd',
|
|
||||||
(t, value, onended) => {
|
|
||||||
const { duration, decay = 0.5, pdecay = 0.5, penv = 36, clip } = value;
|
|
||||||
const ctx = getAudioContext();
|
|
||||||
const attackhold = 0.02;
|
|
||||||
const noiselvl = 1.2;
|
|
||||||
const noisedecay = 0.025;
|
|
||||||
const mixGain = 1;
|
|
||||||
|
|
||||||
const o = ctx.createOscillator();
|
|
||||||
o.type = 'triangle';
|
|
||||||
o.frequency.value = getFrequencyFromValue(value, 29);
|
|
||||||
o.detune.setValueAtTime(penv * 100, 0);
|
|
||||||
o.detune.setValueAtTime(penv * 100, t);
|
|
||||||
o.detune.exponentialRampToValueAtTime(0.001, t + pdecay);
|
|
||||||
const g = gainNode(1);
|
|
||||||
g.gain.setValueAtTime(1, t + attackhold);
|
|
||||||
g.gain.exponentialRampToValueAtTime(0.001, t + attackhold + decay);
|
|
||||||
o.start(t);
|
|
||||||
|
|
||||||
const noise = getNoiseOscillator('brown', t, 2);
|
|
||||||
const noiseGain = gainNode(1);
|
|
||||||
noiseGain.gain.setValueAtTime(noiselvl, t);
|
|
||||||
noiseGain.gain.exponentialRampToValueAtTime(0.001, t + noisedecay);
|
|
||||||
|
|
||||||
const sat = new WaveShaperNode(ctx);
|
|
||||||
// tri to sine diode shaper emulation
|
|
||||||
sat.curve = makeSaturationCurve(2, ctx.sampleRate);
|
|
||||||
|
|
||||||
const mix = gainNode(mixGain);
|
|
||||||
|
|
||||||
o.onended = () => {
|
|
||||||
o.disconnect();
|
|
||||||
g.disconnect();
|
|
||||||
sat.disconnect();
|
|
||||||
noise.node.disconnect();
|
|
||||||
noiseGain.disconnect();
|
|
||||||
mix.disconnect();
|
|
||||||
onended();
|
|
||||||
};
|
|
||||||
|
|
||||||
const node = o.connect(sat).connect(g).connect(mix);
|
|
||||||
noise.node.connect(noiseGain).connect(mix);
|
|
||||||
|
|
||||||
const holdEnd = t + decay;
|
|
||||||
let end = holdEnd + 0.01;
|
|
||||||
if (clip != null) {
|
|
||||||
end = Math.min(t + clip * duration, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent clicking
|
|
||||||
mix.gain.setValueAtTime(mixGain, end - 0.01);
|
|
||||||
mix.gain.linearRampToValueAtTime(0, end);
|
|
||||||
|
|
||||||
o.stop(end);
|
|
||||||
noise.stop(end);
|
|
||||||
|
|
||||||
return {
|
|
||||||
node,
|
|
||||||
stop: (endTime) => {
|
|
||||||
o.stop(endTime);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{ type: 'synth', prebake: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
registerSound(
|
registerSound(
|
||||||
'supersaw',
|
'supersaw',
|
||||||
(begin, value, onended) => {
|
(begin, value, onended) => {
|
||||||
|
|||||||
@@ -72,7 +72,3 @@ export const getSoundIndex = (n, numSounds) => {
|
|||||||
export function cycleToSeconds(cycle, cps) {
|
export function cycleToSeconds(cycle, cps) {
|
||||||
return cycle / cps;
|
return cycle / cps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function secondsToCycle(t, cps) {
|
|
||||||
return t * cps;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,28 +8,18 @@ import FFT from './fft.js';
|
|||||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||||
const _mod = (n, m) => ((n % m) + m) % m;
|
const _mod = (n, m) => ((n % m) + m) % m;
|
||||||
|
|
||||||
// Restrict phase to the range [0, maxPhase) via wrapping
|
|
||||||
function wrapPhase(phase, maxPhase = 1) {
|
|
||||||
if (phase >= maxPhase) {
|
|
||||||
phase -= maxPhase;
|
|
||||||
} else if (phase < 0) {
|
|
||||||
phase += maxPhase;
|
|
||||||
}
|
|
||||||
return phase;
|
|
||||||
}
|
|
||||||
const blockSize = 128;
|
const blockSize = 128;
|
||||||
// Smooth waveshape near discontinuities to remove frequencies above Nyquist and prevent aliasing
|
// adjust waveshape to remove frequencies above nyquist to prevent aliasing
|
||||||
// referenced from https://www.kvraudio.com/forum/viewtopic.php?t=375517
|
// referenced from https://www.kvraudio.com/forum/viewtopic.php?t=375517
|
||||||
function polyBlep(phase, dt) {
|
function polyBlep(phase, dt) {
|
||||||
dt = Math.min(dt, 1 - dt);
|
// 0 <= phase < 1
|
||||||
// Start of cycle
|
|
||||||
if (phase < dt) {
|
if (phase < dt) {
|
||||||
phase /= dt;
|
phase /= dt;
|
||||||
// 2 * (phase - phase^2/2 - 0.5)
|
// 2 * (phase - phase^2/2 - 0.5)
|
||||||
return phase + phase - phase * phase - 1;
|
return phase + phase - phase * phase - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of cycle
|
// -1 < phase < 0
|
||||||
else if (phase > 1 - dt) {
|
else if (phase > 1 - dt) {
|
||||||
phase = (phase - 1) / dt;
|
phase = (phase - 1) / dt;
|
||||||
// 2 * (phase^2/2 + phase + 0.5)
|
// 2 * (phase^2/2 + phase + 0.5)
|
||||||
@@ -41,7 +31,7 @@ function polyBlep(phase, dt) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The order is important for dough integration
|
|
||||||
const waveshapes = {
|
const waveshapes = {
|
||||||
tri(phase, skew = 0.5) {
|
tri(phase, skew = 0.5) {
|
||||||
const x = 1 - skew;
|
const x = 1 - skew;
|
||||||
@@ -91,12 +81,10 @@ function getParamValue(block, param) {
|
|||||||
}
|
}
|
||||||
return param[0];
|
return param[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
const waveShapeNames = Object.keys(waveshapes);
|
const waveShapeNames = Object.keys(waveshapes);
|
||||||
class LFOProcessor extends AudioWorkletProcessor {
|
class LFOProcessor extends AudioWorkletProcessor {
|
||||||
static get parameterDescriptors() {
|
static get parameterDescriptors() {
|
||||||
return [
|
return [
|
||||||
{ name: 'begin', defaultValue: 0 },
|
|
||||||
{ name: 'time', defaultValue: 0 },
|
{ name: 'time', defaultValue: 0 },
|
||||||
{ name: 'end', defaultValue: 0 },
|
{ name: 'end', defaultValue: 0 },
|
||||||
{ name: 'frequency', defaultValue: 0.5 },
|
{ name: 'frequency', defaultValue: 0.5 },
|
||||||
@@ -104,10 +92,7 @@ class LFOProcessor extends AudioWorkletProcessor {
|
|||||||
{ name: 'depth', defaultValue: 1 },
|
{ name: 'depth', defaultValue: 1 },
|
||||||
{ name: 'phaseoffset', defaultValue: 0 },
|
{ name: 'phaseoffset', defaultValue: 0 },
|
||||||
{ name: 'shape', defaultValue: 0 },
|
{ name: 'shape', defaultValue: 0 },
|
||||||
{ name: 'curve', defaultValue: 1 },
|
|
||||||
{ name: 'dcoffset', defaultValue: 0 },
|
{ name: 'dcoffset', defaultValue: 0 },
|
||||||
{ name: 'min', defaultValue: 0 },
|
|
||||||
{ name: 'max', defaultValue: 1 },
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,13 +109,10 @@ class LFOProcessor extends AudioWorkletProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
process(inputs, outputs, parameters) {
|
process(inputs, outputs, parameters) {
|
||||||
const begin = parameters['begin'][0];
|
// eslint-disable-next-line no-undef
|
||||||
if (currentTime >= parameters.end[0]) {
|
if (currentTime >= parameters.end[0]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (currentTime <= begin) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = outputs[0];
|
const output = outputs[0];
|
||||||
const frequency = parameters['frequency'][0];
|
const frequency = parameters['frequency'][0];
|
||||||
@@ -140,11 +122,7 @@ class LFOProcessor extends AudioWorkletProcessor {
|
|||||||
const skew = parameters['skew'][0];
|
const skew = parameters['skew'][0];
|
||||||
const phaseoffset = parameters['phaseoffset'][0];
|
const phaseoffset = parameters['phaseoffset'][0];
|
||||||
|
|
||||||
const curve = parameters['curve'][0];
|
|
||||||
|
|
||||||
const dcoffset = parameters['dcoffset'][0];
|
const dcoffset = parameters['dcoffset'][0];
|
||||||
const min = parameters['min'][0];
|
|
||||||
const max = parameters['max'][0];
|
|
||||||
const shape = waveShapeNames[parameters['shape'][0]];
|
const shape = waveShapeNames[parameters['shape'][0]];
|
||||||
|
|
||||||
const blockSize = output[0].length ?? 0;
|
const blockSize = output[0].length ?? 0;
|
||||||
@@ -152,12 +130,12 @@ class LFOProcessor extends AudioWorkletProcessor {
|
|||||||
if (this.phase == null) {
|
if (this.phase == null) {
|
||||||
this.phase = _mod(time * frequency + phaseoffset, 1);
|
this.phase = _mod(time * frequency + phaseoffset, 1);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const dt = frequency / sampleRate;
|
const dt = frequency / sampleRate;
|
||||||
for (let n = 0; n < blockSize; n++) {
|
for (let n = 0; n < blockSize; n++) {
|
||||||
for (let i = 0; i < output.length; i++) {
|
for (let i = 0; i < output.length; i++) {
|
||||||
let modval = (waveshapes[shape](this.phase, skew) + dcoffset) * depth;
|
const modval = (waveshapes[shape](this.phase, skew) + dcoffset) * depth;
|
||||||
modval = Math.pow(modval, curve);
|
output[i][n] = modval;
|
||||||
output[i][n] = clamp(modval, min, max);
|
|
||||||
}
|
}
|
||||||
this.incrementPhase(dt);
|
this.incrementPhase(dt);
|
||||||
}
|
}
|
||||||
@@ -313,6 +291,7 @@ class LadderProcessor extends AudioWorkletProcessor {
|
|||||||
const drive = clamp(Math.exp(parameters.drive[0]), 0.1, 2000);
|
const drive = clamp(Math.exp(parameters.drive[0]), 0.1, 2000);
|
||||||
|
|
||||||
let cutoff = parameters.frequency[0];
|
let cutoff = parameters.frequency[0];
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
cutoff = (cutoff * 2 * _PI) / sampleRate;
|
cutoff = (cutoff * 2 * _PI) / sampleRate;
|
||||||
cutoff = cutoff > 1 ? 1 : cutoff;
|
cutoff = cutoff > 1 ? 1 : cutoff;
|
||||||
|
|
||||||
@@ -445,13 +424,18 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
process(input, outputs, params) {
|
process(input, outputs, params) {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
if (currentTime <= params.begin[0]) {
|
if (currentTime <= params.begin[0]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
if (currentTime >= params.end[0]) {
|
if (currentTime >= params.end[0]) {
|
||||||
// this.port.postMessage({ type: 'onended' });
|
// this.port.postMessage({ type: 'onended' });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
let frequency = params.frequency[0];
|
||||||
|
//apply detune in cents
|
||||||
|
frequency = frequency * Math.pow(2, params.detune[0] / 1200);
|
||||||
|
|
||||||
const output = outputs[0];
|
const output = outputs[0];
|
||||||
const voices = params.voices[0];
|
const voices = params.voices[0];
|
||||||
@@ -462,6 +446,9 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
|||||||
|
|
||||||
for (let n = 0; n < voices; n++) {
|
for (let n = 0; n < voices; n++) {
|
||||||
const isOdd = (n & 1) == 1;
|
const isOdd = (n & 1) == 1;
|
||||||
|
|
||||||
|
//applies unison "spread" detune in semitones
|
||||||
|
const freq = applySemitoneDetuneToFrequency(frequency, getUnisonDetune(voices, freqspread, n));
|
||||||
let gainL = gain1;
|
let gainL = gain1;
|
||||||
let gainR = gain2;
|
let gainR = gain2;
|
||||||
// invert right and left gain
|
// invert right and left gain
|
||||||
@@ -469,21 +456,21 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
|||||||
gainL = gain2;
|
gainL = gain2;
|
||||||
gainR = gain1;
|
gainR = gain1;
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const dt = freq / sampleRate;
|
||||||
|
|
||||||
for (let i = 0; i < output[0].length; i++) {
|
for (let i = 0; i < output[0].length; i++) {
|
||||||
// Main detuning
|
|
||||||
let freq = applySemitoneDetuneToFrequency(params.frequency[i] ?? params.frequency[0], params.detune[0] / 100);
|
|
||||||
// Individual voice detuning
|
|
||||||
freq = applySemitoneDetuneToFrequency(freq, getUnisonDetune(voices, freqspread, n));
|
|
||||||
// We must wrap this here because it is passed into sawblep below which
|
|
||||||
// has domain [0, 1]
|
|
||||||
const dt = _mod(freq / sampleRate, 1);
|
|
||||||
this.phase[n] = this.phase[n] ?? Math.random();
|
this.phase[n] = this.phase[n] ?? Math.random();
|
||||||
const v = waveshapes.sawblep(this.phase[n], dt);
|
const v = waveshapes.sawblep(this.phase[n], dt);
|
||||||
|
|
||||||
output[0][i] = output[0][i] + v * gainL;
|
output[0][i] = output[0][i] + v * gainL;
|
||||||
output[1][i] = output[1][i] + v * gainR;
|
output[1][i] = output[1][i] + v * gainR;
|
||||||
|
|
||||||
this.phase[n] = wrapPhase(this.phase[n] + dt);
|
this.phase[n] += dt;
|
||||||
|
|
||||||
|
if (this.phase[n] > 1.0) {
|
||||||
|
this.phase[n] = this.phase[n] - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -492,7 +479,7 @@ class SuperSawOscillatorProcessor extends AudioWorkletProcessor {
|
|||||||
|
|
||||||
registerProcessor('supersaw-oscillator', SuperSawOscillatorProcessor);
|
registerProcessor('supersaw-oscillator', SuperSawOscillatorProcessor);
|
||||||
|
|
||||||
// Phase Vocoder sourced from https://github.com/olvb/phaze/tree/master?tab=readme-ov-file
|
// Phase Vocoder sourced from // sourced from https://github.com/olvb/phaze/tree/master?tab=readme-ov-file
|
||||||
const BUFFERED_BLOCK_SIZE = 2048;
|
const BUFFERED_BLOCK_SIZE = 2048;
|
||||||
|
|
||||||
function genHannWindow(length) {
|
function genHannWindow(length) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/tonal",
|
"name": "@strudel/tonal",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Tonal functions for strudel",
|
"description": "Tonal functions for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -88,14 +88,13 @@ function scaleOffset(scale, offset, note) {
|
|||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
* @memberof Pattern
|
* @memberof Pattern
|
||||||
* @name transpose
|
* @name transpose
|
||||||
* @synonyms trans
|
|
||||||
* @example
|
* @example
|
||||||
* "c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()
|
* "c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()
|
||||||
* @example
|
* @example
|
||||||
* "c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()
|
* "c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const { transpose, trans } = register(['transpose', 'trans'], function transposeFn(intervalOrSemitones, pat) {
|
export const transpose = register('transpose', function (intervalOrSemitones, pat) {
|
||||||
return pat.withHap((hap) => {
|
return pat.withHap((hap) => {
|
||||||
const note = hap.value.note ?? hap.value;
|
const note = hap.value.note ?? hap.value;
|
||||||
if (typeof note === 'number') {
|
if (typeof note === 'number') {
|
||||||
@@ -143,7 +142,6 @@ export const { transpose, trans } = register(['transpose', 'trans'], function tr
|
|||||||
* @name scaleTranspose
|
* @name scaleTranspose
|
||||||
* @param {offset} offset number of steps inside the scale
|
* @param {offset} offset number of steps inside the scale
|
||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
* @synonyms scaleTrans, strans
|
|
||||||
* @example
|
* @example
|
||||||
* "-8 [2,4,6]"
|
* "-8 [2,4,6]"
|
||||||
* .scale('C4 bebop major')
|
* .scale('C4 bebop major')
|
||||||
@@ -151,9 +149,7 @@ export const { transpose, trans } = register(['transpose', 'trans'], function tr
|
|||||||
* .note()
|
* .note()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const { scaleTranspose, scaleTrans, strans } = register(
|
export const scaleTranspose = register('scaleTranspose', function (offset /* : number | string */, pat) {
|
||||||
['scaleTranspose', 'scaleTrans', 'strans'],
|
|
||||||
function (offset /* : number | string */, pat) {
|
|
||||||
return pat.withHap((hap) => {
|
return pat.withHap((hap) => {
|
||||||
if (!hap.context.scale) {
|
if (!hap.context.scale) {
|
||||||
throw new Error('can only use scaleTranspose after .scale');
|
throw new Error('can only use scaleTranspose after .scale');
|
||||||
@@ -168,8 +164,7 @@ export const { scaleTranspose, scaleTrans, strans } = register(
|
|||||||
}
|
}
|
||||||
return hap.withValue(() => scaleOffset(hap.context.scale, Number(offset), hap.value));
|
return hap.withValue(() => scaleOffset(hap.context.scale, Number(offset), hap.value));
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.
|
* Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/transpiler",
|
"name": "@strudel/transpiler",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/web",
|
"name": "@strudel/web",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
||||||
"module": "web.mjs",
|
"module": "web.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/webaudio",
|
"name": "@strudel/webaudio",
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"description": "Web Audio helpers for Strudel",
|
"description": "Web Audio helpers for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -15,10 +15,14 @@ const hap2value = (hap) => {
|
|||||||
return hap.value;
|
return hap.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const webaudioOutputTrigger = (t, hap, ct, cps) => superdough(hap2value(hap), t - ct, hap.duration / cps, cps);
|
||||||
// uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004
|
// uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004
|
||||||
// TODO: refactor output callbacks to eliminate deadline
|
export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => {
|
||||||
export const webaudioOutput = (hap, _deadline, hapDuration, cps, t) => {
|
return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration, cps);
|
||||||
return superdough(hap2value(hap), t, hapDuration, cps, hap.whole?.begin.valueOf());
|
};
|
||||||
|
|
||||||
|
Pattern.prototype.webaudio = function () {
|
||||||
|
return this.onTrigger(webaudioOutputTrigger);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function webaudioRepl(options = {}) {
|
export function webaudioRepl(options = {}) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/xen",
|
"name": "@strudel/xen",
|
||||||
"version": "1.2.3",
|
"version": "1.2.2",
|
||||||
"description": "Xenharmonic API for strudel",
|
"description": "Xenharmonic API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -3036,145 +3036,6 @@ exports[`runs examples > example "dry" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "duckattack" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 0/1 → 1/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/8 → 1/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/4 → 5/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/4 → 3/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 3/8 → 1/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/2 → 9/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/2 → 5/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 5/8 → 3/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 11/16 → 3/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 3/4 → 7/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 7/8 → 15/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 7/8 → 1/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/1 → 17/16 | s:bd n:4 duckorbit:2 duckattack:0 duckdepth:1 ]",
|
|
||||||
"[ 1/1 → 9/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 9/8 → 5/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 5/4 → 21/16 | s:bd n:4 duckorbit:2 duckattack:0 duckdepth:1 ]",
|
|
||||||
"[ 5/4 → 11/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 11/8 → 3/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 3/2 → 25/16 | s:bd n:4 duckorbit:2 duckattack:0 duckdepth:1 ]",
|
|
||||||
"[ 3/2 → 13/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 13/8 → 7/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 27/16 → 7/4 | s:bd n:4 duckorbit:2 duckattack:0 duckdepth:1 ]",
|
|
||||||
"[ 7/4 → 15/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 15/8 → 31/16 | s:bd n:4 duckorbit:2 duckattack:0 duckdepth:1 ]",
|
|
||||||
"[ 15/8 → 2/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 2/1 → 33/16 | s:bd n:4 duckorbit:2 duckattack:0.4 duckdepth:1 ]",
|
|
||||||
"[ 2/1 → 17/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 17/8 → 9/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 9/4 → 37/16 | s:bd n:4 duckorbit:2 duckattack:0.4 duckdepth:1 ]",
|
|
||||||
"[ 9/4 → 19/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 19/8 → 5/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 5/2 → 41/16 | s:bd n:4 duckorbit:2 duckattack:0.4 duckdepth:1 ]",
|
|
||||||
"[ 5/2 → 21/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 21/8 → 11/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 43/16 → 11/4 | s:bd n:4 duckorbit:2 duckattack:0.4 duckdepth:1 ]",
|
|
||||||
"[ 11/4 → 23/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 23/8 → 47/16 | s:bd n:4 duckorbit:2 duckattack:0.4 duckdepth:1 ]",
|
|
||||||
"[ 23/8 → 3/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 3/1 → 49/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 3/1 → 25/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 25/8 → 13/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 13/4 → 53/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 13/4 → 27/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 27/8 → 7/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 7/2 → 57/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 7/2 → 29/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 29/8 → 15/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 59/16 → 15/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 15/4 → 31/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 31/8 → 63/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 31/8 → 4/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "duckdepth" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 0/1 → 1/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/8 → 1/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/4 → 5/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/4 → 3/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 3/8 → 1/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/2 → 9/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/2 → 5/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 5/8 → 3/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 11/16 → 3/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 3/4 → 7/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 7/8 → 15/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 7/8 → 1/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 1/1 → 17/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.9 ]",
|
|
||||||
"[ 1/1 → 9/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 9/8 → 5/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 5/4 → 21/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.9 ]",
|
|
||||||
"[ 5/4 → 11/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 11/8 → 3/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 3/2 → 25/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.9 ]",
|
|
||||||
"[ 3/2 → 13/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 13/8 → 7/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 27/16 → 7/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.9 ]",
|
|
||||||
"[ 7/4 → 15/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 15/8 → 31/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.9 ]",
|
|
||||||
"[ 15/8 → 2/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 2/1 → 33/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.6 ]",
|
|
||||||
"[ 2/1 → 17/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 17/8 → 9/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 9/4 → 37/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.6 ]",
|
|
||||||
"[ 9/4 → 19/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 19/8 → 5/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 5/2 → 41/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.6 ]",
|
|
||||||
"[ 5/2 → 21/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 21/8 → 11/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 43/16 → 11/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.6 ]",
|
|
||||||
"[ 11/4 → 23/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 23/8 → 47/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0.6 ]",
|
|
||||||
"[ 23/8 → 3/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 3/1 → 49/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0 ]",
|
|
||||||
"[ 3/1 → 25/8 | note:C3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 25/8 → 13/4 | note:D3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 13/4 → 53/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0 ]",
|
|
||||||
"[ 13/4 → 27/8 | note:Eb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 27/8 → 7/2 | note:F3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 7/2 → 57/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0 ]",
|
|
||||||
"[ 7/2 → 29/8 | note:G3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 29/8 → 15/4 | note:Ab3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 59/16 → 15/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0 ]",
|
|
||||||
"[ 15/4 → 31/8 | note:Bb3 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
"[ 31/8 → 63/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:0 ]",
|
|
||||||
"[ 31/8 → 4/1 | note:C4 s:sawtooth delay:0.7 orbit:2 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "duckorbit" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/4 → 5/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/2 → 9/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 11/16 → 3/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 7/8 → 15/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 1/1 → 17/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 5/4 → 21/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 3/2 → 25/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 27/16 → 7/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 15/8 → 31/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 2/1 → 33/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 9/4 → 37/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 5/2 → 41/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 43/16 → 11/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 23/8 → 47/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 3/1 → 49/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 13/4 → 53/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 7/2 → 57/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 59/16 → 15/4 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
"[ 31/8 → 63/16 | s:bd n:4 duckorbit:2 duckattack:0.2 duckdepth:1 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "duration" example index 0 1`] = `
|
exports[`runs examples > example "duration" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:c s:piano duration:0.5 ]",
|
"[ 0/1 → 1/4 | note:c s:piano duration:0.5 ]",
|
||||||
@@ -3410,39 +3271,6 @@ exports[`runs examples > example "euclidRot" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "euclidish" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/12 | s:hh pan:0.5 ]",
|
|
||||||
"[ 13/84 → 5/21 | s:hh pan:0.5606253170575308 ]",
|
|
||||||
"[ 15/56 → 59/168 | s:hh pan:0.604413082836085 ]",
|
|
||||||
"[ 71/168 → 85/168 | s:hh pan:0.6629314122869361 ]",
|
|
||||||
"[ 97/168 → 37/56 | s:hh pan:0.7190455010067492 ]",
|
|
||||||
"[ 29/42 → 65/84 | s:hh pan:0.7580531369037533 ]",
|
|
||||||
"[ 71/84 → 13/14 | s:hh pan:0.8080762739548087 ]",
|
|
||||||
"[ 1/1 → 13/12 | s:hh pan:0.8535533905932737 ]",
|
|
||||||
"[ 451099417/393511398 → 322594689/262340932 | s:hh pan:0.891768001805729 ]",
|
|
||||||
"[ 335923379/262340932 → 536677685/393511398 | s:hh pan:0.9222657853371297 ]",
|
|
||||||
"[ 1122946175/787022796 → 99044284/65585233 | s:hh pan:0.9501869591788796 ]",
|
|
||||||
"[ 1238122213/787022796 → 651853723/393511398 | s:hh pan:0.9721673436944069 ]",
|
|
||||||
"[ 335923379/196755699 → 469759583/262340932 | s:hh pan:0.9868472639237561 ]",
|
|
||||||
"[ 729434777/393511398 → 1524454787/787022796 | s:hh pan:0.9967009321321423 ]",
|
|
||||||
"[ 2/1 → 25/12 | s:hh pan:1 ]",
|
|
||||||
"[ 15/7 → 187/84 | s:hh pan:0.9968561049466214 ]",
|
|
||||||
"[ 16/7 → 199/84 | s:hh pan:0.9874639560909118 ]",
|
|
||||||
"[ 17/7 → 211/84 | s:hh pan:0.9719416651541839 ]",
|
|
||||||
"[ 18/7 → 223/84 | s:hh pan:0.9504844339512095 ]",
|
|
||||||
"[ 19/7 → 235/84 | s:hh pan:0.9233620996141421 ]",
|
|
||||||
"[ 20/7 → 247/84 | s:hh pan:0.890915741234015 ]",
|
|
||||||
"[ 3/1 → 37/12 | s:hh pan:0.8535533905932737 ]",
|
|
||||||
"[ 1238122213/393511398 → 847276553/262340932 | s:hh pan:0.8106731928589048 ]",
|
|
||||||
"[ 860605243/262340932 → 1323700481/393511398 | s:hh pan:0.7677528833339 ]",
|
|
||||||
"[ 2696991767/787022796 → 230214750/65585233 | s:hh pan:0.7175585019834292 ]",
|
|
||||||
"[ 2812167805/787022796 → 1438876519/393511398 | s:hh pan:0.6644931595798675 ]",
|
|
||||||
"[ 729434777/196755699 → 994441447/262340932 | s:hh pan:0.6139286689554151 ]",
|
|
||||||
"[ 1516457573/393511398 → 3098500379/787022796 | s:hh pan:0.557342689325327 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "every" example index 0 1`] = `
|
exports[`runs examples > example "every" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:g3 ]",
|
"[ 0/1 → 1/4 | note:g3 ]",
|
||||||
@@ -3878,144 +3706,6 @@ exports[`runs examples > example "fmsustain" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "fmwave" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:D3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:E3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:F3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:G3 s:sine fmwave:sine fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:D3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:E3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:F3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:G3 s:sine fmwave:square fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:D3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:E3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:F3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:G3 s:sine fmwave:sawtooth fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:D3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:E3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:F3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:G3 s:sine fmwave:crackle fmi:4 fmh:2.01 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "fmwave" example index 1 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:50 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:57 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:64 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:53 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:60 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:65 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:69 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:55 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:62 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:67 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:71 s:sawtooth fmwave:brown fmi:0.6 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "focus" example index 0 1`] = `
|
exports[`runs examples > example "focus" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | s:sd ]",
|
"[ 0/1 → 1/8 | s:sd ]",
|
||||||
@@ -5457,40 +5147,6 @@ exports[`runs examples > example "lock" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "log" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/2 | s:bd ]",
|
|
||||||
"[ 1/2 → 1/1 | s:sd ]",
|
|
||||||
"[ 1/1 → 3/2 | s:bd ]",
|
|
||||||
"[ 3/2 → 2/1 | s:sd ]",
|
|
||||||
"[ 2/1 → 5/2 | s:bd ]",
|
|
||||||
"[ 5/2 → 3/1 | s:sd ]",
|
|
||||||
"[ 3/1 → 7/2 | s:bd ]",
|
|
||||||
"[ 7/2 → 4/1 | s:sd ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "logValues" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ (0/1 → 1/3) ⇝ 1/2 | s:bd gain:0.25 n:2 ]",
|
|
||||||
"[ 0/1 ⇜ (1/3 → 1/2) | s:bd gain:0.5 n:1 ]",
|
|
||||||
"[ (1/2 → 2/3) ⇝ 1/1 | s:sd gain:0.5 n:1 ]",
|
|
||||||
"[ 1/2 ⇜ (2/3 → 1/1) | s:sd gain:1 n:0 ]",
|
|
||||||
"[ (1/1 → 4/3) ⇝ 3/2 | s:bd gain:0.25 n:2 ]",
|
|
||||||
"[ 1/1 ⇜ (4/3 → 3/2) | s:bd gain:0.5 n:1 ]",
|
|
||||||
"[ (3/2 → 5/3) ⇝ 2/1 | s:sd gain:0.5 n:1 ]",
|
|
||||||
"[ 3/2 ⇜ (5/3 → 2/1) | s:sd gain:1 n:0 ]",
|
|
||||||
"[ (2/1 → 7/3) ⇝ 5/2 | s:bd gain:0.25 n:2 ]",
|
|
||||||
"[ 2/1 ⇜ (7/3 → 5/2) | s:bd gain:0.5 n:1 ]",
|
|
||||||
"[ (5/2 → 8/3) ⇝ 3/1 | s:sd gain:0.5 n:1 ]",
|
|
||||||
"[ 5/2 ⇜ (8/3 → 3/1) | s:sd gain:1 n:0 ]",
|
|
||||||
"[ (3/1 → 10/3) ⇝ 7/2 | s:bd gain:0.25 n:2 ]",
|
|
||||||
"[ 3/1 ⇜ (10/3 → 7/2) | s:bd gain:0.5 n:1 ]",
|
|
||||||
"[ (7/2 → 11/3) ⇝ 4/1 | s:sd gain:0.5 n:1 ]",
|
|
||||||
"[ 7/2 ⇜ (11/3 → 4/1) | s:sd gain:1 n:0 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "loop" example index 0 1`] = `
|
exports[`runs examples > example "loop" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/1 | s:casio loop:1 ]",
|
"[ 0/1 → 1/1 | s:casio loop:1 ]",
|
||||||
@@ -6170,48 +5826,6 @@ exports[`runs examples > example "miditouch" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "morph" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/8 | s:hh ]",
|
|
||||||
"[ 25/112 → 39/112 | s:hh ]",
|
|
||||||
"[ 27/56 → 17/28 | s:hh ]",
|
|
||||||
"[ 83/112 → 97/112 | s:hh ]",
|
|
||||||
"[ 1/1 → 9/8 | s:hh ]",
|
|
||||||
"[ 137/112 → 151/112 | s:hh ]",
|
|
||||||
"[ 83/56 → 45/28 | s:hh ]",
|
|
||||||
"[ 195/112 → 209/112 | s:hh ]",
|
|
||||||
"[ 2/1 → 17/8 | s:hh ]",
|
|
||||||
"[ 249/112 → 263/112 | s:hh ]",
|
|
||||||
"[ 139/56 → 73/28 | s:hh ]",
|
|
||||||
"[ 307/112 → 321/112 | s:hh ]",
|
|
||||||
"[ 3/1 → 25/8 | s:hh ]",
|
|
||||||
"[ 361/112 → 375/112 | s:hh ]",
|
|
||||||
"[ 195/56 → 101/28 | s:hh ]",
|
|
||||||
"[ 419/112 → 433/112 | s:hh ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "morph" example index 1 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/8 | s:hh ]",
|
|
||||||
"[ 11/56 → 9/28 | s:hh ]",
|
|
||||||
"[ 13/28 → 33/56 | s:hh ]",
|
|
||||||
"[ 41/56 → 6/7 | s:hh ]",
|
|
||||||
"[ 1/1 → 9/8 | s:hh ]",
|
|
||||||
"[ 303934523/262340932 → 673454279/524681864 | s:hh ]",
|
|
||||||
"[ 188758485/131170466 → 820619173/524681864 | s:hh ]",
|
|
||||||
"[ 451099417/262340932 → 967784067/524681864 | s:hh ]",
|
|
||||||
"[ 2/1 → 17/8 | s:hh ]",
|
|
||||||
"[ 15/7 → 127/56 | s:hh ]",
|
|
||||||
"[ 17/7 → 143/56 | s:hh ]",
|
|
||||||
"[ 19/7 → 159/56 | s:hh ]",
|
|
||||||
"[ 3/1 → 25/8 | s:hh ]",
|
|
||||||
"[ 828616387/262340932 → 1722818007/524681864 | s:hh ]",
|
|
||||||
"[ 451099417/131170466 → 1869982901/524681864 | s:hh ]",
|
|
||||||
"[ 975781281/262340932 → 2017147795/524681864 | s:hh ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "mousex" example index 0 1`] = `
|
exports[`runs examples > example "mousex" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:C3 ]",
|
"[ 0/1 → 1/4 | note:C3 ]",
|
||||||
@@ -9199,46 +8813,46 @@ exports[`runs examples > example "shrink" example index 3 1`] = `
|
|||||||
|
|
||||||
exports[`runs examples > example "shuffle" example index 0 1`] = `
|
exports[`runs examples > example "shuffle" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | note:e s:piano ]",
|
"[ 0/1 → 1/4 | note:c s:piano ]",
|
||||||
"[ 1/4 → 1/2 | note:d s:piano ]",
|
"[ 1/4 → 1/2 | note:d s:piano ]",
|
||||||
"[ 1/2 → 3/4 | note:f s:piano ]",
|
"[ 1/2 → 3/4 | note:e s:piano ]",
|
||||||
"[ 3/4 → 1/1 | note:c s:piano ]",
|
"[ 3/4 → 1/1 | note:f s:piano ]",
|
||||||
"[ 1/1 → 5/4 | note:e s:piano ]",
|
"[ 1/1 → 5/4 | note:c s:piano ]",
|
||||||
"[ 5/4 → 3/2 | note:c s:piano ]",
|
"[ 5/4 → 3/2 | note:d s:piano ]",
|
||||||
"[ 3/2 → 7/4 | note:f s:piano ]",
|
"[ 3/2 → 7/4 | note:e s:piano ]",
|
||||||
"[ 7/4 → 2/1 | note:d s:piano ]",
|
"[ 7/4 → 2/1 | note:f s:piano ]",
|
||||||
"[ 2/1 → 9/4 | note:d s:piano ]",
|
"[ 2/1 → 9/4 | note:c s:piano ]",
|
||||||
"[ 9/4 → 5/2 | note:c s:piano ]",
|
"[ 9/4 → 5/2 | note:d s:piano ]",
|
||||||
"[ 5/2 → 11/4 | note:e s:piano ]",
|
"[ 5/2 → 11/4 | note:e s:piano ]",
|
||||||
"[ 11/4 → 3/1 | note:f s:piano ]",
|
"[ 11/4 → 3/1 | note:f s:piano ]",
|
||||||
"[ 3/1 → 13/4 | note:c s:piano ]",
|
"[ 3/1 → 13/4 | note:c s:piano ]",
|
||||||
"[ 13/4 → 7/2 | note:e s:piano ]",
|
"[ 13/4 → 7/2 | note:d s:piano ]",
|
||||||
"[ 7/2 → 15/4 | note:f s:piano ]",
|
"[ 7/2 → 15/4 | note:e s:piano ]",
|
||||||
"[ 15/4 → 4/1 | note:d s:piano ]",
|
"[ 15/4 → 4/1 | note:f s:piano ]",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "shuffle" example index 1 1`] = `
|
exports[`runs examples > example "shuffle" example index 1 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | note:e s:piano ]",
|
"[ 0/1 → 1/8 | note:c s:piano ]",
|
||||||
"[ 1/8 → 1/4 | note:d s:piano ]",
|
"[ 1/8 → 1/4 | note:d s:piano ]",
|
||||||
"[ 1/4 → 3/8 | note:f s:piano ]",
|
"[ 1/4 → 3/8 | note:e s:piano ]",
|
||||||
"[ 3/8 → 1/2 | note:c s:piano ]",
|
"[ 3/8 → 1/2 | note:f s:piano ]",
|
||||||
"[ 1/2 → 1/1 | note:g s:piano ]",
|
"[ 1/2 → 1/1 | note:g s:piano ]",
|
||||||
"[ 1/1 → 9/8 | note:e s:piano ]",
|
"[ 1/1 → 9/8 | note:c s:piano ]",
|
||||||
"[ 9/8 → 5/4 | note:c s:piano ]",
|
"[ 9/8 → 5/4 | note:d s:piano ]",
|
||||||
"[ 5/4 → 11/8 | note:f s:piano ]",
|
"[ 5/4 → 11/8 | note:e s:piano ]",
|
||||||
"[ 11/8 → 3/2 | note:d s:piano ]",
|
"[ 11/8 → 3/2 | note:f s:piano ]",
|
||||||
"[ 3/2 → 2/1 | note:g s:piano ]",
|
"[ 3/2 → 2/1 | note:g s:piano ]",
|
||||||
"[ 2/1 → 17/8 | note:d s:piano ]",
|
"[ 2/1 → 17/8 | note:c s:piano ]",
|
||||||
"[ 17/8 → 9/4 | note:c s:piano ]",
|
"[ 17/8 → 9/4 | note:d s:piano ]",
|
||||||
"[ 9/4 → 19/8 | note:e s:piano ]",
|
"[ 9/4 → 19/8 | note:e s:piano ]",
|
||||||
"[ 19/8 → 5/2 | note:f s:piano ]",
|
"[ 19/8 → 5/2 | note:f s:piano ]",
|
||||||
"[ 5/2 → 3/1 | note:g s:piano ]",
|
"[ 5/2 → 3/1 | note:g s:piano ]",
|
||||||
"[ 3/1 → 25/8 | note:c s:piano ]",
|
"[ 3/1 → 25/8 | note:c s:piano ]",
|
||||||
"[ 25/8 → 13/4 | note:e s:piano ]",
|
"[ 25/8 → 13/4 | note:d s:piano ]",
|
||||||
"[ 13/4 → 27/8 | note:f s:piano ]",
|
"[ 13/4 → 27/8 | note:e s:piano ]",
|
||||||
"[ 27/8 → 7/2 | note:d s:piano ]",
|
"[ 27/8 → 7/2 | note:f s:piano ]",
|
||||||
"[ 7/2 → 4/1 | note:g s:piano ]",
|
"[ 7/2 → 4/1 | note:g s:piano ]",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
@@ -10496,420 +10110,6 @@ exports[`runs examples > example "transpose" example index 1 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "tremolo" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:d# s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:d# s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:d# s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:d# s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:d s:supersaw tremolo:2 tremoloskew:0.5 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:d# s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:d# s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:d# s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:d# s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:d s:supersaw tremolo:100 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:d# s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:d s:supersaw tremolo:3 tremoloskew:0.5 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "tremolodepth" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:a1 s:pulse tremolosync:4 tremolodepth:2 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:a1 s:pulse tremolosync:4 tremolodepth:0.7 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:a#1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:a1 s:pulse tremolosync:4 tremolodepth:1 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "tremolophase" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:e s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:e s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:e s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:e s:sawtooth tremolosync:4 tremolophase:0.25 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:e s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:e s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:e s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:f s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:a s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:c s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:e s:sawtooth tremolosync:4 tremolophase:0.66 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:f s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:a s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:c s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:e s:sawtooth tremolosync:4 tremolophase:0 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "tremoloshape" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 1/16 → 1/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 1/8 → 3/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 3/16 → 1/4 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 1/4 → 5/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 5/16 → 3/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 3/8 → 7/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 7/16 → 1/2 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 1/2 → 9/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 9/16 → 5/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 5/8 → 11/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 11/16 → 3/4 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 3/4 → 13/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 13/16 → 7/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 7/8 → 15/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 15/16 → 1/1 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 1/1 → 17/16 | note:f tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 17/16 → 9/8 | note:g tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 9/8 → 19/16 | note:c tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 19/16 → 5/4 | note:d tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 5/4 → 21/16 | note:f tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 21/16 → 11/8 | note:g tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 11/8 → 23/16 | note:c tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 23/16 → 3/2 | note:d tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 3/2 → 25/16 | note:f tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 25/16 → 13/8 | note:g tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 13/8 → 27/16 | note:c tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 27/16 → 7/4 | note:d tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 7/4 → 29/16 | note:f tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 29/16 → 15/8 | note:g tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 15/8 → 31/16 | note:c tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 31/16 → 2/1 | note:d tremolosync:4 tremoloshape:tri s:sawtooth ]",
|
|
||||||
"[ 2/1 → 33/16 | note:f tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 33/16 → 17/8 | note:g tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 17/8 → 35/16 | note:c tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 35/16 → 9/4 | note:d tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 9/4 → 37/16 | note:f tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 37/16 → 19/8 | note:g tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 19/8 → 39/16 | note:c tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 39/16 → 5/2 | note:d tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 5/2 → 41/16 | note:f tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 41/16 → 21/8 | note:g tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 21/8 → 43/16 | note:c tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 43/16 → 11/4 | note:d tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 11/4 → 45/16 | note:f tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 45/16 → 23/8 | note:g tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 23/8 → 47/16 | note:c tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 47/16 → 3/1 | note:d tremolosync:4 tremoloshape:square s:sawtooth ]",
|
|
||||||
"[ 3/1 → 49/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 49/16 → 25/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 25/8 → 51/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 51/16 → 13/4 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 13/4 → 53/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 53/16 → 27/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 27/8 → 55/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 55/16 → 7/2 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 7/2 → 57/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 57/16 → 29/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 29/8 → 59/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 59/16 → 15/4 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 15/4 → 61/16 | note:f tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 61/16 → 31/8 | note:g tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 31/8 → 63/16 | note:c tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
"[ 63/16 → 4/1 | note:d tremolosync:4 tremoloshape:sine s:sawtooth ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "tremoloskew" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:e s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:e s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:e s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:e s:sawtooth tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:f s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:a s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:c s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:e s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:f s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:a s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:c s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:e s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:f s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:a s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:c s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:e s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:f s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:a s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:c s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:e s:sawtooth tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:f s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:a s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:c s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:e s:sawtooth tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "tremolosync" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 1/16 → 1/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 1/8 → 3/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 3/16 → 1/4 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 1/4 → 5/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 5/16 → 3/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 3/8 → 7/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 7/16 → 1/2 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 1/2 → 9/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 9/16 → 5/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 5/8 → 11/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 11/16 → 3/4 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 3/4 → 13/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 13/16 → 7/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 7/8 → 15/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 15/16 → 1/1 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 1/1 → 17/16 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 17/16 → 9/8 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 9/8 → 19/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 19/16 → 5/4 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 5/4 → 21/16 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 21/16 → 11/8 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 11/8 → 23/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 23/16 → 3/2 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 3/2 → 25/16 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 25/16 → 13/8 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 13/8 → 27/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 27/16 → 7/4 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 7/4 → 29/16 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 29/16 → 15/8 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 15/8 → 31/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 31/16 → 2/1 | note:d s:supersaw tremolosync:4 tremoloskew:0.5 ]",
|
|
||||||
"[ 2/1 → 33/16 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 33/16 → 17/8 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 17/8 → 35/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 35/16 → 9/4 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 9/4 → 37/16 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 37/16 → 19/8 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 19/8 → 39/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 39/16 → 5/2 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 5/2 → 41/16 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 41/16 → 21/8 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 21/8 → 43/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 43/16 → 11/4 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 11/4 → 45/16 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 45/16 → 23/8 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 23/8 → 47/16 | note:d# s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 47/16 → 3/1 | note:d s:supersaw tremolosync:4 tremoloskew:0 ]",
|
|
||||||
"[ 3/1 → 49/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 49/16 → 25/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 25/8 → 51/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 51/16 → 13/4 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 13/4 → 53/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 53/16 → 27/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 27/8 → 55/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 55/16 → 7/2 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 7/2 → 57/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 57/16 → 29/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 29/8 → 59/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 59/16 → 15/4 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 15/4 → 61/16 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 61/16 → 31/8 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 31/8 → 63/16 | note:d# s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
"[ 63/16 → 4/1 | note:d s:supersaw tremolosync:4 tremoloskew:1 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "tri" example index 0 1`] = `
|
exports[`runs examples > example "tri" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/8 | note:C3 ]",
|
"[ 0/1 → 1/8 | note:C3 ]",
|
||||||
|
|||||||
@@ -359,6 +359,28 @@ stack(
|
|||||||
"[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25)
|
"[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25)
|
||||||
).note().piano().slow(2)`;
|
).note().piano().slow(2)`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
// by Felix Roos
|
||||||
|
stack(
|
||||||
|
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
|
||||||
|
freq("440(5,8)".clip(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
|
||||||
|
).s("<sawtooth square>/2")
|
||||||
|
.onTrigger((t,hap,ct)=>{
|
||||||
|
const ac = Tone.getContext().rawContext;
|
||||||
|
t = ac.currentTime + t - ct;
|
||||||
|
const { freq, s, gain = 1 } = hap.value;
|
||||||
|
const master = ac.createGain();
|
||||||
|
master.gain.value = 0.1 * gain;
|
||||||
|
master.connect(ac.destination);
|
||||||
|
const o = ac.createOscillator();
|
||||||
|
o.type = s || 'triangle';
|
||||||
|
o.frequency.value = Number(freq);
|
||||||
|
o.connect(master);
|
||||||
|
o.start(t);
|
||||||
|
o.stop(t + hap.duration);
|
||||||
|
}).stack(s("bd(3,8),hh*4,~ sd").webdirt())`; */
|
||||||
|
|
||||||
export const swimmingWithSoundfonts = `// Koji Kondo - Swimming (Super Mario World)
|
export const swimmingWithSoundfonts = `// Koji Kondo - Swimming (Super Mario World)
|
||||||
stack(
|
stack(
|
||||||
n(
|
n(
|
||||||
|
|||||||
@@ -647,6 +647,7 @@
|
|||||||
"evaluate"
|
"evaluate"
|
||||||
],
|
],
|
||||||
"/packages/webaudio/webaudio.mjs": [
|
"/packages/webaudio/webaudio.mjs": [
|
||||||
|
"webaudioOutputTrigger",
|
||||||
"webaudioOutput",
|
"webaudioOutput",
|
||||||
"webaudioRepl"
|
"webaudioRepl"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview --port 3009 --host 0.0.0.0",
|
"preview": "astro preview --port 3009 --host 0.0.0.0",
|
||||||
"astro": "astro"
|
"astro": "astro",
|
||||||
|
"postinstall": "cp node_modules/hs2js/dist/tree-sitter.wasm public && cp node_modules/hs2js/dist/tree-sitter-haskell.wasm public"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@algolia/client-search": "^5.20.0",
|
"@algolia/client-search": "^5.20.0",
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"_base": "https://raw.githubusercontent.com/ritchse/tidal-drum-machines/main/machines/EmuSP12/",
|
||||||
|
"bd": ["emusp12-bd/Bassdrum-01.wav","emusp12-bd/Bassdrum-02.wav","emusp12-bd/Bassdrum-03.wav","emusp12-bd/Bassdrum-04.wav","emusp12-bd/Bassdrum-05.wav","emusp12-bd/Bassdrum-06.wav","emusp12-bd/Bassdrum-07.wav","emusp12-bd/Bassdrum-08.wav","emusp12-bd/Bassdrum-09.wav","emusp12-bd/Bassdrum-10.wav","emusp12-bd/Bassdrum-11.wav","emusp12-bd/Bassdrum-12.wav","emusp12-bd/Bassdrum-13.wav","emusp12-bd/Bassdrum-14.wav"],
|
||||||
|
"cb": ["emusp12-cb/Cowbell.wav"],
|
||||||
|
"cp": ["emusp12-cp/Clap.wav"],
|
||||||
|
"cr": ["emusp12-cr/Crash.wav"],
|
||||||
|
"hh": ["emusp12-hh/Hat Closed-01.wav","emusp12-hh/Hat Closed-02.wav"],
|
||||||
|
"ht": ["emusp12-ht/Tom H-01.wav","emusp12-ht/Tom H-02.wav","emusp12-ht/Tom H-03.wav","emusp12-ht/Tom H-04.wav","emusp12-ht/Tom H-05.wav","emusp12-ht/Tom H-06.wav"],
|
||||||
|
"lt": ["emusp12-lt/Tom L-01.wav","emusp12-lt/Tom L-02.wav","emusp12-lt/Tom L-03.wav","emusp12-lt/Tom L-04.wav","emusp12-lt/Tom L-05.wav","emusp12-lt/Tom L-06.wav"],
|
||||||
|
"misc": ["emusp12-misc/Metal-01.wav","emusp12-misc/Metal-02.wav","emusp12-misc/Metal-03.wav","emusp12-misc/Scratch.wav","emusp12-misc/Shot-01.wav","emusp12-misc/Shot-02.wav","emusp12-misc/Shot-03.wav"],
|
||||||
|
"mt": ["emusp12-mt/Tom M-01.wav","emusp12-mt/Tom M-02.wav","emusp12-mt/Tom M-03.wav","emusp12-mt/Tom M-05.wav"],
|
||||||
|
"oh": ["emusp12-oh/Hhopen1.wav"],
|
||||||
|
"perc": ["emusp12-perc/Blow1.wav"],
|
||||||
|
"rd": ["emusp12-rd/Ride.wav"],
|
||||||
|
"rim": ["emusp12-rim/zRim Shot-01.wav","emusp12-rim/zRim Shot-02.wav"],
|
||||||
|
"sd": ["emusp12-sd/Snaredrum-01.wav","emusp12-sd/Snaredrum-02.wav","emusp12-sd/Snaredrum-03.wav","emusp12-sd/Snaredrum-04.wav","emusp12-sd/Snaredrum-05.wav","emusp12-sd/Snaredrum-06.wav","emusp12-sd/Snaredrum-07.wav","emusp12-sd/Snaredrum-08.wav","emusp12-sd/Snaredrum-09.wav","emusp12-sd/Snaredrum-10.wav","emusp12-sd/Snaredrum-11.wav","emusp12-sd/Snaredrum-12.wav","emusp12-sd/Snaredrum-13.wav","emusp12-sd/Snaredrum-14.wav","emusp12-sd/Snaredrum-15.wav","emusp12-sd/Snaredrum-16.wav","emusp12-sd/Snaredrum-17.wav","emusp12-sd/Snaredrum-18.wav","emusp12-sd/Snaredrum-19.wav","emusp12-sd/Snaredrum-20.wav","emusp12-sd/Snaredrum-21.wav"]
|
||||||
|
}
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
{
|
|
||||||
"_base": "https://raw.githubusercontent.com/tidalcycles/uzu-drumkit/main/",
|
|
||||||
"bd": [
|
|
||||||
"bd/10_bd_switchangel.wav",
|
|
||||||
"bd/11_bd_mot4i.wav",
|
|
||||||
"bd/12_bd_mot4i.wav",
|
|
||||||
"bd/13_bd_mot4i.wav",
|
|
||||||
"bd/14_bd_switchangel.wav",
|
|
||||||
"bd/15_bd_switchangel.wav",
|
|
||||||
"bd/16_bd_switchangel.wav",
|
|
||||||
"bd/17_bd_switchangel.wav"
|
|
||||||
],
|
|
||||||
"brk": [
|
|
||||||
"brk/10_break_amen_pprocessed.wav"
|
|
||||||
],
|
|
||||||
"cb": [
|
|
||||||
"cb/10_perc_switchangel.wav"
|
|
||||||
],
|
|
||||||
"cp": [
|
|
||||||
"cp/10_cp_switchangel.wav",
|
|
||||||
"cp/11_cp_mot4i.wav"
|
|
||||||
],
|
|
||||||
"cr": [
|
|
||||||
"cr/10_cr_switchangel.wav",
|
|
||||||
"cr/11_cr_mot4i.wav"
|
|
||||||
],
|
|
||||||
"hh": [
|
|
||||||
"hh/10_hh_switchangel.wav",
|
|
||||||
"hh/11_hh_mot4i.wav",
|
|
||||||
"hh/12_hh_switchangel.wav",
|
|
||||||
"hh/13_hh_switchangel.wav",
|
|
||||||
"hh/14_hh_mot4i.wav"
|
|
||||||
],
|
|
||||||
"ht": [
|
|
||||||
"ht/10_ht_mot4i.wav"
|
|
||||||
],
|
|
||||||
"lt": [
|
|
||||||
"lt/10_lt_mot4i.wav"
|
|
||||||
],
|
|
||||||
"misc": [
|
|
||||||
"misc/10_misc_switchangel_ludens.wav",
|
|
||||||
"misc/11_misc_switchangel_ludens.wav",
|
|
||||||
"misc/12_misc_switchangel_ludens.wav",
|
|
||||||
"misc/13_misc_switchangel_ludens.wav",
|
|
||||||
"misc/14_misc_switchangel_ludens.wav"
|
|
||||||
],
|
|
||||||
"mt": [
|
|
||||||
"mt/10_mt_mot4i.wav"
|
|
||||||
],
|
|
||||||
"oh": [
|
|
||||||
"oh/10_oh_switchangel.wav",
|
|
||||||
"oh/11_oh_switchangel.wav",
|
|
||||||
"oh/12_oh_switchangel.wav",
|
|
||||||
"oh/13_oh_switchangel.wav"
|
|
||||||
],
|
|
||||||
"rd": [
|
|
||||||
"rd/10_rd_switchangel.wav"
|
|
||||||
],
|
|
||||||
"rim": [
|
|
||||||
"rim/10_rim_switchangel.wav",
|
|
||||||
"rim/11_rim_switch_angel.wav"
|
|
||||||
],
|
|
||||||
"sd": [
|
|
||||||
"sd/10_sd_switchangel-bounce-2.wav",
|
|
||||||
"sd/11_sd_switchangel_3.wav",
|
|
||||||
"sd/12_sd_switchangel_2.wav",
|
|
||||||
"sd/13_sd_switchangel_2.wav",
|
|
||||||
"sd/14_sd.wav"
|
|
||||||
],
|
|
||||||
"sh": [
|
|
||||||
"sh/10_sh_switchangel.wav"
|
|
||||||
],
|
|
||||||
"tb": [
|
|
||||||
"tb/10_tb.wav"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,317 +0,0 @@
|
|||||||
---
|
|
||||||
title: 'Release Notes v1.1.0'
|
|
||||||
description: ''
|
|
||||||
date: '2024-06-02'
|
|
||||||
tags: ['meta']
|
|
||||||
author: froos
|
|
||||||
---
|
|
||||||
|
|
||||||
These are the release notes for Strudel 1.1.0 aka "Bananensplit".
|
|
||||||
|
|
||||||
The last release was over 19 weeks ago, so a lot of things have happened!
|
|
||||||
|
|
||||||
First, here's a little demo, teasing some of the new features:
|
|
||||||
|
|
||||||
import { Youtube } from '@src/components/Youtube';
|
|
||||||
|
|
||||||
<Youtube client:only="react" id="2Qu5lMHruio" />
|
|
||||||
|
|
||||||
Let's write up some of the highlights:
|
|
||||||
|
|
||||||
## New DSP Features
|
|
||||||
|
|
||||||
### Stereo Supersaw
|
|
||||||
|
|
||||||
with spread, unison, and detune parameters
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
note("d f a a# a d3").fast(2)
|
|
||||||
.s("supersaw").spread(".8").detune(.3).unison("2 7")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Analog "ladder" filter type
|
|
||||||
|
|
||||||
works great for acid basslines and vibey tones
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
note("{d d d a a# d3 f4}%16".sub(12)).gain(1).s("sawtooth")
|
|
||||||
.lpf(200).lpenv(slider(1.36,0,8)).lpq(7).distort("1.5:.7")`
|
|
||||||
.ftype('ladder')
|
|
||||||
```
|
|
||||||
|
|
||||||
### stereo distortion effect
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
note("{g g a# g g4}%8".add("{0 7 12 0}%8")).lpf(500)
|
|
||||||
.s("supersaw").dist("4:.2")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Editor Features
|
|
||||||
|
|
||||||
### inline viz
|
|
||||||
|
|
||||||
The editor now supports multiple visuals within the code, using the `_` prefix for viz functions:
|
|
||||||
|
|
||||||
<img
|
|
||||||
width="595"
|
|
||||||
alt="Screenshot 2024-06-01 at 01 23 51"
|
|
||||||
src="https://codeberg.org/uzu/strudel/assets/12023032/978fee85-e533-4da6-a245-d20d0083f57e"
|
|
||||||
/>
|
|
||||||
|
|
||||||
- `._pianoroll()`: inline pianoroll
|
|
||||||
- `._punchcard()`: inline punchcard
|
|
||||||
- `._scope()`: inline scope
|
|
||||||
- `._pitchwheel()`: inline pitchwheel
|
|
||||||
|
|
||||||
For more info, check out the new [Visual Feedback Page](https://strudel.cc/learn/visual-feedback/)
|
|
||||||
|
|
||||||
### label notation
|
|
||||||
|
|
||||||
This new notation simplifies writing patterns at the top level:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
d1: s("bd*4")
|
|
||||||
d2: s("[- hh]*4")
|
|
||||||
```
|
|
||||||
|
|
||||||
This is equivalent to:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
stack(
|
|
||||||
s("bd*4"),
|
|
||||||
s("[- hh]*4")
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
The labels you choose are arbitrary, the above `d1` and `d2` are a typical thing you'd write in tidal, for example `d1 $ s "bd*4"`.
|
|
||||||
If the same label is used multiple times, the last one wins:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
d1: s("bd*4")
|
|
||||||
d1: s("[- hh]*4") // <-- only this plays
|
|
||||||
```
|
|
||||||
|
|
||||||
There is a special label anonymous label `$`, which can appear multiple times without overriding itself:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
// both of these will play:
|
|
||||||
$: s("bd*4")
|
|
||||||
$: s("[- hh]*4")
|
|
||||||
```
|
|
||||||
|
|
||||||
You can mute a pattern by prefixing `_`:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
_$: s("bd*4") // <-- this one is muted
|
|
||||||
$: s("[- hh]*4")
|
|
||||||
```
|
|
||||||
|
|
||||||
To run a transformation on all patterns, you can use `all`:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
$: s("bd*4")
|
|
||||||
$: s("[- hh]*4")
|
|
||||||
all(x=>x.room(.5))
|
|
||||||
```
|
|
||||||
|
|
||||||
This notation is now the recommended way to [play patterns in parallel](https://strudel.cc/workshop/first-notes/#playing-multiple-patterns)
|
|
||||||
|
|
||||||
### Clock sync between multiple instances
|
|
||||||
|
|
||||||
timing has received a major overhaul, and is now much more accurate on all browsers. Additionally, you can now sync timing across multiple windows.
|
|
||||||

|
|
||||||
|
|
||||||
### Better sample upload support
|
|
||||||
|
|
||||||
you can now upload large amounts of samples much faster across all browsers including on IOS devices. supported filetypes now include: ogg flac mp3 wav aac m4a
|
|
||||||
|
|
||||||
### experimental tidal syntax
|
|
||||||
|
|
||||||
The new `tidal` function allows you to write strudel patterns in tidal syntax:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
await initTidal()
|
|
||||||
|
|
||||||
tidal`
|
|
||||||
d1 $ s "bd*4"
|
|
||||||
|
|
||||||
d2 $ s "[- hh]*4"
|
|
||||||
`
|
|
||||||
```
|
|
||||||
|
|
||||||
As we're looking to improve compatibility with tidal, we're happy to hear feedback.
|
|
||||||
|
|
||||||
## breaking changes
|
|
||||||
|
|
||||||
This release comes with a bunch of breaking changes. If you find your patterns to sound different, check out the PRs below for guidance on how to update them. Most of these changes shouldn't affect a lot of patterns.
|
|
||||||
In case of doubt, add the line `// @version 1.0` to your old pattern.
|
|
||||||
If you're having problems, please let us know!
|
|
||||||
|
|
||||||
- remove legacy legato + duration implementations by @felixroos in https://codeberg.org/uzu/strudel/pull/965
|
|
||||||
- Velocity in value by @felixroos in https://codeberg.org/uzu/strudel/pull/974
|
|
||||||
- use ireal as default voicing dict by @felixroos https://codeberg.org/uzu/strudel/pull/967
|
|
||||||
- Color in hap value by @felixroos https://codeberg.org/uzu/strudel/pull/1007
|
|
||||||
- rename trig -> reset, trigzero -> restart by @felixroos https://codeberg.org/uzu/strudel/pull/1010
|
|
||||||
- remove dangerous arithmetic feature by @felixroos https://codeberg.org/uzu/strudel/pull/1030
|
|
||||||
- change fanchor to 0 by @daslyfe https://codeberg.org/uzu/strudel/pull/1107
|
|
||||||
|
|
||||||
## superdough features
|
|
||||||
|
|
||||||
- replace shape with distort in learn doc by @daslyfe https://codeberg.org/uzu/strudel/pull/982
|
|
||||||
- Worklet Improvents / fixes by @daslyfe https://codeberg.org/uzu/strudel/pull/963
|
|
||||||
- supersaw oscillator by @daslyfe https://codeberg.org/uzu/strudel/pull/978
|
|
||||||
- Add analog-style ladder filter by @daslyfe https://codeberg.org/uzu/strudel/pull/1103
|
|
||||||
- Calculate phaser modulation phase based on time by @daslyfe https://codeberg.org/uzu/strudel/pull/1110
|
|
||||||
- rollback phaser by @daslyfe https://codeberg.org/uzu/strudel/pull/1113
|
|
||||||
|
|
||||||
## editor / ui features
|
|
||||||
|
|
||||||
- 'Enable Bracket Matching' option in Codemirror by @eefano https://codeberg.org/uzu/strudel/pull/956
|
|
||||||
- REPL sync between windows by @daslyfe https://codeberg.org/uzu/strudel/pull/900
|
|
||||||
- inline viz / widgets package by @felixroos https://codeberg.org/uzu/strudel/pull/989
|
|
||||||
- Inline punchcard + spiral by @felixroos https://codeberg.org/uzu/strudel/pull/1008
|
|
||||||
- More fonts by @felixroos https://codeberg.org/uzu/strudel/pull/1023
|
|
||||||
- better theme integration for visuals + various fixes by @felixroos https://codeberg.org/uzu/strudel/pull/1024
|
|
||||||
- add setting for sync flag by @felixroos https://codeberg.org/uzu/strudel/pull/1025
|
|
||||||
- add closeBrackets setting by @felixroos https://codeberg.org/uzu/strudel/pull/1031
|
|
||||||
- add font file types to offline cache by @felixroos https://codeberg.org/uzu/strudel/pull/1032
|
|
||||||
- pitchwheel visual by @felixroos https://codeberg.org/uzu/strudel/pull/1041
|
|
||||||
- repl: set document.title from @title by @kasparsj https://codeberg.org/uzu/strudel/pull/1090
|
|
||||||
- Samples tab improvements by @daslyfe https://codeberg.org/uzu/strudel/pull/1102
|
|
||||||
|
|
||||||
## language features
|
|
||||||
|
|
||||||
- pickOut(), pickRestart(), pickReset() by @eefano https://codeberg.org/uzu/strudel/pull/950
|
|
||||||
- Auto await samples by @felixroos https://codeberg.org/uzu/strudel/pull/955
|
|
||||||
- feat: can now invert euclid pulses with negative numbers by @felixroos https://codeberg.org/uzu/strudel/pull/959
|
|
||||||
- Nested controls by @felixroos https://codeberg.org/uzu/strudel/pull/973
|
|
||||||
- alias - for ~ by @yaxu https://codeberg.org/uzu/strudel/pull/981
|
|
||||||
- Beat-oriented functionality by @yaxu https://codeberg.org/uzu/strudel/pull/976
|
|
||||||
- Labeled statements by @felixroos https://codeberg.org/uzu/strudel/pull/991
|
|
||||||
- accidentals in scale degrees by @eefano https://codeberg.org/uzu/strudel/pull/1000
|
|
||||||
- Feature: tactus marking by @yaxu https://codeberg.org/uzu/strudel/pull/1021
|
|
||||||
- Tactus tidy by @yaxu https://codeberg.org/uzu/strudel/pull/1027
|
|
||||||
- Wax, wane, taper and taperlist by @yaxu https://codeberg.org/uzu/strudel/pull/1042
|
|
||||||
- transpose: support all combinations of numbers and strings for notes and intervals by @felixroos https://codeberg.org/uzu/strudel/pull/1048
|
|
||||||
- anonymous patterns + muting by @felixroos https://codeberg.org/uzu/strudel/pull/1059
|
|
||||||
- add swing + swingBy by @felixroos https://codeberg.org/uzu/strudel/pull/1038
|
|
||||||
- Stepwise functions from Tidal by @yaxu https://codeberg.org/uzu/strudel/pull/1060
|
|
||||||
- Tactus tweaks - fixes for maintaining tactus and highlight locations by @yaxu https://codeberg.org/uzu/strudel/pull/1065
|
|
||||||
- Fix stepjoin by @yaxu https://codeberg.org/uzu/strudel/pull/1067
|
|
||||||
- More tactus tidying by @yaxu https://codeberg.org/uzu/strudel/pull/1071
|
|
||||||
- Tactus calculation toggle and breaking change to tactus calculation in fast/slow/hurry by @yaxu https://codeberg.org/uzu/strudel/pull/1081
|
|
||||||
- hs2js package / tidal parser by @felixroos https://codeberg.org/uzu/strudel/pull/870
|
|
||||||
- Add the mousex and mousey signal by @Enelg52 https://codeberg.org/uzu/strudel/pull/1112
|
|
||||||
- can now access strudelMirror from repl by @felixroos https://codeberg.org/uzu/strudel/pull/1117
|
|
||||||
|
|
||||||
## sampler
|
|
||||||
|
|
||||||
If you have nodejs installed on your system, you can now use [@strudel/sampler](https://www.npmjs.com/package/@strudel/sampler) to serve samples from disk to the REPL or flok.
|
|
||||||
|
|
||||||
- local sample server cli by @felixroos https://codeberg.org/uzu/strudel/pull/1033
|
|
||||||
- Fix sampler paths by @felixroos https://codeberg.org/uzu/strudel/pull/1034
|
|
||||||
- Fix sampler windows by @felixroos https://codeberg.org/uzu/strudel/pull/1108
|
|
||||||
- fix sampler on windows by @geikha https://codeberg.org/uzu/strudel/pull/1109
|
|
||||||
|
|
||||||
## docs
|
|
||||||
|
|
||||||
- V1 release notes by @felixroos https://codeberg.org/uzu/strudel/pull/935
|
|
||||||
- Minor documentation error: Update first-sounds.mdx by @mhetrick https://codeberg.org/uzu/strudel/pull/941
|
|
||||||
- Update synths.mdx by @andresgottlieb https://codeberg.org/uzu/strudel/pull/984
|
|
||||||
- using strudel in your project guide + cleanup examples by @felixroos https://codeberg.org/uzu/strudel/pull/1006
|
|
||||||
- Document signals by @ilesinge https://codeberg.org/uzu/strudel/pull/1015
|
|
||||||
- improve tutorial + custom samples doc by @felixroos https://codeberg.org/uzu/strudel/pull/1053
|
|
||||||
- fix cr typo on first-sounds.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1068
|
|
||||||
- fix first sounds typo by @cleary https://codeberg.org/uzu/strudel/pull/1069
|
|
||||||
- add `<...>` to first-sounds.mdx recap by @cleary https://codeberg.org/uzu/strudel/pull/1070
|
|
||||||
- add nesting to `off` example variation in pattern-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1075
|
|
||||||
- fix translation issue in first-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1072
|
|
||||||
- add signals to recap in first-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1073
|
|
||||||
- fix docs on alignment.mdx by @diegodorado https://codeberg.org/uzu/strudel/pull/1076
|
|
||||||
- fix little dub tune example by @lukad https://codeberg.org/uzu/strudel/pull/1104
|
|
||||||
- clarify `off` in pattern-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1074
|
|
||||||
- Fixes drawPianoroll import in codemirror example by @giohappy https://codeberg.org/uzu/strudel/pull/1116
|
|
||||||
- Migrate tutorial fanchor by @felixroos https://codeberg.org/uzu/strudel/pull/1122
|
|
||||||
|
|
||||||
## internals
|
|
||||||
|
|
||||||
- remove cjs builds by @felixroos https://codeberg.org/uzu/strudel/pull/945
|
|
||||||
- controls refactoring: simplify exports by @felixroos https://codeberg.org/uzu/strudel/pull/962
|
|
||||||
- move canvas related helpers from core to new draw package by @felixroos https://codeberg.org/uzu/strudel/pull/971
|
|
||||||
- remove canvas, externalize samples, delete junk by @felixroos https://codeberg.org/uzu/strudel/pull/1003
|
|
||||||
- Improve performance of ! (replicate) by @yaxu https://codeberg.org/uzu/strudel/pull/1084
|
|
||||||
- Benchmarks by @yaxu https://codeberg.org/uzu/strudel/pull/1079
|
|
||||||
|
|
||||||
## fixes
|
|
||||||
|
|
||||||
- fix midi issue on firefox and added quote error by @Enelg52 https://codeberg.org/uzu/strudel/pull/936
|
|
||||||
- fix: pianoroll sorting by @felixroos https://codeberg.org/uzu/strudel/pull/938
|
|
||||||
- account for cps in midi time duration by @daslyfe https://codeberg.org/uzu/strudel/pull/954
|
|
||||||
- fix script importable packages (web + repl) by @felixroos https://codeberg.org/uzu/strudel/pull/957
|
|
||||||
- fix: reset global fx on pattern change by @felixroos https://codeberg.org/uzu/strudel/pull/960
|
|
||||||
- add debounce to logger by @felixroos https://codeberg.org/uzu/strudel/pull/968
|
|
||||||
- fix for transpose(): preserve hap value object structure by @eefano https://codeberg.org/uzu/strudel/pull/966
|
|
||||||
- fix: clear hydra on reset by @felixroos https://codeberg.org/uzu/strudel/pull/983
|
|
||||||
- little fix for withVal by @eefano https://codeberg.org/uzu/strudel/pull/980
|
|
||||||
- fix: share now shares what's visible instead of active by @felixroos https://codeberg.org/uzu/strudel/pull/985
|
|
||||||
- Fix pure mini highlight by @yaxu https://codeberg.org/uzu/strudel/pull/994
|
|
||||||
- fix: await injectPatternMethods by @felixroos https://codeberg.org/uzu/strudel/pull/1012
|
|
||||||
- update undocumented script by @felixroos https://codeberg.org/uzu/strudel/pull/1013
|
|
||||||
- eliminate chromium clock jitter by @felixroos https://codeberg.org/uzu/strudel/pull/1004
|
|
||||||
- Repl sync fixes by @daslyfe https://codeberg.org/uzu/strudel/pull/1014
|
|
||||||
- hotfix for 1017 by @daslyfe https://codeberg.org/uzu/strudel/pull/1020
|
|
||||||
- fix cyclist fizzling out by @felixroos https://codeberg.org/uzu/strudel/pull/1046
|
|
||||||
- Midi Time hotfix for scheduler updates by @daslyfe https://codeberg.org/uzu/strudel/pull/1047
|
|
||||||
- fix: do not reset cc input values on each eval by @felixroos https://codeberg.org/uzu/strudel/pull/1054
|
|
||||||
- Fix wchooseCycles not picking the whole pattern by @ilesinge https://codeberg.org/uzu/strudel/pull/1061
|
|
||||||
- fix OSC timing for recent scheduler updates by @daslyfe https://codeberg.org/uzu/strudel/pull/1062
|
|
||||||
- clarify license by @yaxu https://codeberg.org/uzu/strudel/pull/1064
|
|
||||||
- fix failing format test by @daslyfe https://codeberg.org/uzu/strudel/pull/1077
|
|
||||||
- fix: url parsing with extra params by @felixroos https://codeberg.org/uzu/strudel/pull/1083
|
|
||||||
- fix: csound + dough timing by @felixroos https://codeberg.org/uzu/strudel/pull/1086
|
|
||||||
- fix: missing events due to premature worklet cleanup by @felixroos https://codeberg.org/uzu/strudel/pull/1089
|
|
||||||
- Use sessionStorage for viewingPatternData and activePattern by @kasparsj https://codeberg.org/uzu/strudel/pull/1091
|
|
||||||
- osc: couple of fixes by @kasparsj https://codeberg.org/uzu/strudel/pull/1093
|
|
||||||
- web package fixes by @felixroos https://codeberg.org/uzu/strudel/pull/1044
|
|
||||||
- Fix audio worklets by @daslyfe https://codeberg.org/uzu/strudel/pull/1114
|
|
||||||
- fix: use full repl in web package by @felixroos https://codeberg.org/uzu/strudel/pull/1119
|
|
||||||
- [BUG FIX] Audio worklets sometimes dont load by @daslyfe https://codeberg.org/uzu/strudel/pull/1121
|
|
||||||
|
|
||||||
## New Contributors
|
|
||||||
|
|
||||||
- @mhetrick made their first contribution https://codeberg.org/uzu/strudel/pull/941
|
|
||||||
- @eefano made their first contribution https://codeberg.org/uzu/strudel/pull/956
|
|
||||||
- @Enelg52 made their first contribution https://codeberg.org/uzu/strudel/pull/936
|
|
||||||
- @andresgottlieb made their first contribution https://codeberg.org/uzu/strudel/pull/984
|
|
||||||
- @cleary made their first contribution https://codeberg.org/uzu/strudel/pull/1068
|
|
||||||
- @diegodorado made their first contribution https://codeberg.org/uzu/strudel/pull/1076
|
|
||||||
- @lukad made their first contribution https://codeberg.org/uzu/strudel/pull/1104
|
|
||||||
- @giohappy made their first contribution https://codeberg.org/uzu/strudel/pull/1116
|
|
||||||
|
|
||||||
A huge thanks to all contributors!!!
|
|
||||||
|
|
||||||
## Packages
|
|
||||||
|
|
||||||
- @strudel/codemirror@1.1.0
|
|
||||||
- @strudel/core@1.1.0
|
|
||||||
- @strudel/csound@1.1.0
|
|
||||||
- @strudel/draw@1.1.0
|
|
||||||
- @strudel/embed@1.1.0
|
|
||||||
- hs2js@0.1.0
|
|
||||||
- @strudel/hydra@1.1.0
|
|
||||||
- @strudel/midi@1.1.0
|
|
||||||
- @strudel/mini@1.1.0
|
|
||||||
- @strudel/osc@1.1.0
|
|
||||||
- @strudel/repl@1.1.0
|
|
||||||
- @strudel/sampler@0.1.0
|
|
||||||
- @strudel/serial@1.1.0
|
|
||||||
- @strudel/soundfonts@1.1.0
|
|
||||||
- superdough@1.1.0
|
|
||||||
- @strudel/tidal@0.1.0
|
|
||||||
- @strudel/tonal@1.1.0
|
|
||||||
- @strudel/transpiler@1.1.0
|
|
||||||
- @strudel/web@1.1.0
|
|
||||||
- @strudel/webaudio@1.1.0
|
|
||||||
- @strudel/xen@1.1.0
|
|
||||||
|
|
||||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v1.0.0...v1.1.0
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
---
|
|
||||||
title: 'Release Notes v1.2.0'
|
|
||||||
description: ''
|
|
||||||
date: '2025-05-01'
|
|
||||||
tags: ['meta']
|
|
||||||
author: froos
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's Changed
|
|
||||||
|
|
||||||
## highlights
|
|
||||||
|
|
||||||
- [stepwise functions](https://strudel.cc/learn/stepwise/) ([PR](https://github.com/tidalcycles/strudel/pull/1262))
|
|
||||||
- [midimaps](https://strudel.cc/learn/input-output/#midimaps) ([PR](https://github.com/tidalcycles/strudel/pull/1274))
|
|
||||||
- [spectrum](https://strudel.cc/learn/visual-feedback/#spectrum) ([PR](https://github.com/tidalcycles/strudel/pull/1213))
|
|
||||||
- [mqtt](https://strudel.cc/learn/input-output/#mqtt) ([PR](https://github.com/tidalcycles/strudel/pull/1224))
|
|
||||||
- pulse oscillator (todo: https://github.com/tidalcycles/strudel/issues/1336) ([PR](https://github.com/tidalcycles/strudel/pull/1304))
|
|
||||||
- theme improvements
|
|
||||||
|
|
||||||
## breaking changes
|
|
||||||
|
|
||||||
- [breaking change] Sample signals from query onset, rather than midpoint by @yaxu in https://github.com/tidalcycles/strudel/pull/1278
|
|
||||||
- change behaviour of polymeter, and remove polymeterSteps by @yaxu in https://github.com/tidalcycles/strudel/pull/1302
|
|
||||||
- Polish, rename, and document stepwise functions by @yaxu in https://github.com/tidalcycles/strudel/pull/1262
|
|
||||||
|
|
||||||
### superdough
|
|
||||||
|
|
||||||
- feat: Create Pulse Oscillator with variable PWM by @daslyfe in https://github.com/tidalcycles/strudel/pull/1304
|
|
||||||
- add num samples (edited numbers) by @yaxu in https://github.com/tidalcycles/strudel/pull/1309
|
|
||||||
- Add num samples from 0 up to 20 by @yaxu in https://github.com/tidalcycles/strudel/pull/1310
|
|
||||||
- feat: add max polyphony feature for superdough by @daslyfe in https://github.com/tidalcycles/strudel/pull/1317
|
|
||||||
|
|
||||||
### docs
|
|
||||||
|
|
||||||
- doc: visual functions + refactor onPaint by @felixroos in https://github.com/tidalcycles/strudel/pull/1125
|
|
||||||
- Labeled statements doc by @felixroos in https://github.com/tidalcycles/strudel/pull/1126
|
|
||||||
- Correct spelling mistakes by @EdwardBetts in https://github.com/tidalcycles/strudel/pull/1183
|
|
||||||
- remove redundant example for cat, update snapshot by @kdiab in https://github.com/tidalcycles/strudel/pull/1189
|
|
||||||
- chore: Edit run locally instructions in README.md by @ChinoUkaegbu in https://github.com/tidalcycles/strudel/pull/1206
|
|
||||||
- suggested changes to voicings.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/1231
|
|
||||||
- Documentation for all/each, and bugfix for each by @yaxu in https://github.com/tidalcycles/strudel/pull/1233
|
|
||||||
- Update documentation for param value modification by @gillespi314 in https://github.com/tidalcycles/strudel/pull/1238
|
|
||||||
- fix docs for beat function by @daslyfe in https://github.com/tidalcycles/strudel/pull/1248
|
|
||||||
- understand voicings page by @felixroos in https://github.com/tidalcycles/strudel/pull/1230
|
|
||||||
- add reference package by @felixroos in https://github.com/tidalcycles/strudel/pull/1252
|
|
||||||
- Stepwise documentation tweaks, with mridangam samples by @yaxu in https://github.com/tidalcycles/strudel/pull/1275
|
|
||||||
- showcase tweaks by @yaxu in https://github.com/tidalcycles/strudel/pull/1291
|
|
||||||
- Signpost licenses for source code and samples a bit more, ref #1277 by @yaxu in https://github.com/tidalcycles/strudel/pull/1289
|
|
||||||
- Fix misplaced ending sentence by @makmanalp in https://github.com/tidalcycles/strudel/pull/1296
|
|
||||||
- Fix typo pattnr by @ReneNyffenegger in https://github.com/tidalcycles/strudel/pull/1316
|
|
||||||
- update docs to reflect import sounds tab change by @hpunq in https://github.com/tidalcycles/strudel/pull/1332
|
|
||||||
|
|
||||||
### ui improvements
|
|
||||||
|
|
||||||
- Udels (MultiFrame Strudel) Revisited by @daslyfe in https://github.com/tidalcycles/strudel/pull/1132
|
|
||||||
- Create audio target selector for OSC/Superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1160
|
|
||||||
- Add a search bar to the REPL Reference tab by @netux in https://github.com/tidalcycles/strudel/pull/1165
|
|
||||||
- Adding search bar (soundtab.jsx) by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/1185
|
|
||||||
- add 2 new ui settings by @felixroos in https://github.com/tidalcycles/strudel/pull/1200
|
|
||||||
- Theme glowup by @felixroos in https://github.com/tidalcycles/strudel/pull/1268
|
|
||||||
- Create Pattern Page Pagination by @daslyfe in https://github.com/tidalcycles/strudel/pull/1287
|
|
||||||
- feat: Theme improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/1295
|
|
||||||
- feat: new themes + theme improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/1326
|
|
||||||
- Add new "import-sounds" tab with explanation on folder import by @hpunq in https://github.com/tidalcycles/strudel/pull/1329
|
|
||||||
- Add Icon to import sample button by @daslyfe in https://github.com/tidalcycles/strudel/pull/1331
|
|
||||||
- better spacing in zen mode by @felixroos in https://github.com/tidalcycles/strudel/pull/1147
|
|
||||||
- Screenreader improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/1158
|
|
||||||
- colorize console + tweak header by @felixroos in https://github.com/tidalcycles/strudel/pull/1203
|
|
||||||
- Menu Panel Improvements! by @daslyfe in https://github.com/tidalcycles/strudel/pull/1193
|
|
||||||
- Make panel hover behavior optional by @daslyfe in https://github.com/tidalcycles/strudel/pull/1199
|
|
||||||
- REPL: solo and sync configuration by @bthj in https://github.com/tidalcycles/strudel/pull/1214
|
|
||||||
- enhancement: make error messages easier to read by @daslyfe in https://github.com/tidalcycles/strudel/pull/1315
|
|
||||||
|
|
||||||
### mqtt
|
|
||||||
|
|
||||||
- MQTT support by @yaxu in https://github.com/tidalcycles/strudel/pull/1224
|
|
||||||
- MQTT - if password isn't provided, prompt for one by @yaxu in https://github.com/tidalcycles/strudel/pull/1249
|
|
||||||
- MQTT - support adding hap duration and cps metadata to JSON messages by @yaxu in https://github.com/tidalcycles/strudel/pull/1279
|
|
||||||
- make mqtt topic patternable by @yaxu in https://github.com/tidalcycles/strudel/pull/1280
|
|
||||||
- Bugfix: update mqtt connections dictionary by @yaxu in https://github.com/tidalcycles/strudel/pull/1281
|
|
||||||
- mqtt bugfix - connection check by @yaxu in https://github.com/tidalcycles/strudel/pull/1282
|
|
||||||
|
|
||||||
### new functions
|
|
||||||
|
|
||||||
- Add scramble and shuffle by @yaxu in https://github.com/tidalcycles/strudel/pull/1167
|
|
||||||
- polyJoin by @yaxu in https://github.com/tidalcycles/strudel/pull/1168
|
|
||||||
- Add seqPLoop from Tidal by @yaxu in https://github.com/tidalcycles/strudel/pull/1182
|
|
||||||
- add filter + filterWhen + within by @felixroos in https://github.com/tidalcycles/strudel/pull/1039
|
|
||||||
- Add bite function by @yaxu in https://github.com/tidalcycles/strudel/pull/1187
|
|
||||||
- markcss by @felixroos in https://github.com/tidalcycles/strudel/pull/1202
|
|
||||||
- "beat" function for "step sequencer" style rhythm notation by @daslyfe in https://github.com/tidalcycles/strudel/pull/1237
|
|
||||||
- Add s_zip for 'cat'-ing patterns together step-by-step, bugfix `steps` by @yaxu in https://github.com/tidalcycles/strudel/pull/1208
|
|
||||||
- "stretch" function (phase vocoder) by @daslyfe in https://github.com/tidalcycles/strudel/pull/1130
|
|
||||||
- add basic spectrum function by @felixroos in https://github.com/tidalcycles/strudel/pull/1213
|
|
||||||
- Add onKey function for custom key commands for patterns by @daslyfe in https://github.com/tidalcycles/strudel/pull/1235
|
|
||||||
- Add binary and binaryN by @heerman in https://github.com/tidalcycles/strudel/pull/1226
|
|
||||||
- midimaps by @felixroos in https://github.com/tidalcycles/strudel/pull/1274
|
|
||||||
- small feat: Add alias for segment and ribbon by @daslyfe in https://github.com/tidalcycles/strudel/pull/1314
|
|
||||||
- feat: Create scrub function for scrubbing an audio file by @daslyfe in https://github.com/tidalcycles/strudel/pull/1321
|
|
||||||
- feat: Improve gain curve by @daslyfe in https://github.com/tidalcycles/strudel/pull/1318
|
|
||||||
- Chop chop by @yaxu in https://github.com/tidalcycles/strudel/pull/1078
|
|
||||||
|
|
||||||
### more
|
|
||||||
|
|
||||||
- Make `all()` post-stack again, and add `each()` for pre-stack by @yaxu in https://github.com/tidalcycles/strudel/pull/1229
|
|
||||||
- Add stepBind, and some toplevel aliases for binds and withValue by @yaxu in https://github.com/tidalcycles/strudel/pull/1241
|
|
||||||
- Make cps patternable by @eefano in https://github.com/tidalcycles/strudel/pull/1001
|
|
||||||
- Allow wchooseCycles probabilities to be patterned by @yaxu in https://github.com/tidalcycles/strudel/pull/1292
|
|
||||||
- @strudel/sampler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/1288
|
|
||||||
|
|
||||||
### refactor
|
|
||||||
|
|
||||||
- expose comment commands by @felixroos in https://github.com/tidalcycles/strudel/pull/1136
|
|
||||||
- containerize/seperate out boolean checks for repl types/Repl logic into bespoke components. by @daslyfe in https://github.com/tidalcycles/strudel/pull/1163
|
|
||||||
- Improve + simplify neocyclist timing by @daslyfe in https://github.com/tidalcycles/strudel/pull/1164
|
|
||||||
- Make phaser control consistent with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1178
|
|
||||||
- Revert "Make phaser control consistent with superdirt" by @daslyfe in https://github.com/tidalcycles/strudel/pull/1179
|
|
||||||
- make phaser control match superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1180
|
|
||||||
- refactor sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/1101
|
|
||||||
- update lockfile + minor versions by @felixroos in https://github.com/tidalcycles/strudel/pull/1198
|
|
||||||
- Preserve tactus for 'degrade' and friends, and tidy up 'pick' and friends by @yaxu in https://github.com/tidalcycles/strudel/pull/1205
|
|
||||||
- Apply `all` function to individual patterns rather than final stack by @yaxu in https://github.com/tidalcycles/strudel/pull/1209
|
|
||||||
- Revert "Fix sometimes" by @yaxu in https://github.com/tidalcycles/strudel/pull/1267
|
|
||||||
- patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/1264
|
|
||||||
- Rename repeat back to extend by @yaxu in https://github.com/tidalcycles/strudel/pull/1285
|
|
||||||
- Send delta in OSC message in seconds, to match tidal/superdirt by @yaxu in https://github.com/tidalcycles/strudel/pull/1323
|
|
||||||
|
|
||||||
### fixes
|
|
||||||
|
|
||||||
- Fix clock worker dependency path in module builds by @matthewkaney in https://github.com/tidalcycles/strudel/pull/1129
|
|
||||||
- Fix bug in Fraction.lcm by @yaxu in https://github.com/tidalcycles/strudel/pull/1133
|
|
||||||
- Fix tactus marking in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/1144
|
|
||||||
- Fix loopAt tactus by @yaxu in https://github.com/tidalcycles/strudel/pull/1145
|
|
||||||
- Fix OSC clock jitter by @daslyfe in https://github.com/tidalcycles/strudel/pull/1157
|
|
||||||
- [CORS HOTFIX] by @daslyfe in https://github.com/tidalcycles/strudel/pull/1162
|
|
||||||
- Fixes fit so it works after a chop or slice by @yaxu in https://github.com/tidalcycles/strudel/pull/1171
|
|
||||||
- fix sample speed when using splice and fit with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1172
|
|
||||||
- handle midin device not found error by @felixroos in https://github.com/tidalcycles/strudel/pull/1146
|
|
||||||
- Fix serial timing by @yaxu in https://github.com/tidalcycles/strudel/pull/1188
|
|
||||||
- Fix regression for d1, p1, p(n) by @yaxu in https://github.com/tidalcycles/strudel/pull/1227
|
|
||||||
- Fix sometimes by @yaxu in https://github.com/tidalcycles/strudel/pull/1243
|
|
||||||
- Fix sf2 timing by @felixroos in https://github.com/tidalcycles/strudel/pull/1272
|
|
||||||
- Fix "squeezejoin" and functions using it, including "bite" by @yaxu in https://github.com/tidalcycles/strudel/pull/1286
|
|
||||||
- Fixes inverted triangle wave by renaming it to "itri", making non-inverted "tri" by @yaxu in https://github.com/tidalcycles/strudel/pull/1283
|
|
||||||
- Hotfix: prevent undefined pattern code from crashing strudel on load by @daslyfe in https://github.com/tidalcycles/strudel/pull/1297
|
|
||||||
- Fix test error #1297 by @nkymut in https://github.com/tidalcycles/strudel/pull/1298
|
|
||||||
- bugfix zoom stepcount by @yaxu in https://github.com/tidalcycles/strudel/pull/1301
|
|
||||||
- bugfix: Allow single param to be used in the as function by @daslyfe in https://github.com/tidalcycles/strudel/pull/1312
|
|
||||||
- fix: replace empty spaces in registered sound keys by @daslyfe in https://github.com/tidalcycles/strudel/pull/1319
|
|
||||||
- FIX: Multichannel Audio by @daslyfe in https://github.com/tidalcycles/strudel/pull/1322
|
|
||||||
- fix: udels header by @daslyfe in https://github.com/tidalcycles/strudel/pull/1325
|
|
||||||
- fix: disable astro toolbar by default by @daslyfe in https://github.com/tidalcycles/strudel/pull/1324
|
|
||||||
- FIX: sound import order by @daslyfe in https://github.com/tidalcycles/strudel/pull/1333`
|
|
||||||
|
|
||||||
## New Contributors
|
|
||||||
|
|
||||||
- @EdwardBetts made their first contribution in https://github.com/tidalcycles/strudel/pull/1183
|
|
||||||
- @netux made their first contribution in https://github.com/tidalcycles/strudel/pull/1165
|
|
||||||
- @kdiab made their first contribution in https://github.com/tidalcycles/strudel/pull/1189
|
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v1.1.0...v1.1.1
|
|
||||||
|
|
||||||
## packages
|
|
||||||
|
|
||||||
- @strudel/codemirror@1.2.0
|
|
||||||
- @strudel/core@1.2.0
|
|
||||||
- @strudel/csound@1.2.0
|
|
||||||
- @strudel/draw@1.2.0
|
|
||||||
- @strudel/gamepad@1.2.0
|
|
||||||
- @strudel/hydra@1.2.0
|
|
||||||
- @strudel/midi@1.2.0
|
|
||||||
- @strudel/mini@1.2.0
|
|
||||||
- @strudel/motion@1.2.0
|
|
||||||
- @strudel/mqtt@1.2.0
|
|
||||||
- @strudel/osc@1.2.0
|
|
||||||
- @strudel/reference@1.2.0
|
|
||||||
- @strudel/repl@1.2.0
|
|
||||||
- @strudel/sampler@0.2.0
|
|
||||||
- @strudel/serial@1.2.0
|
|
||||||
- @strudel/soundfonts@1.2.0
|
|
||||||
- superdough@1.2.0
|
|
||||||
- @strudel/tonal@1.2.0
|
|
||||||
- @strudel/transpiler@1.2.0
|
|
||||||
- @strudel/web@1.2.0
|
|
||||||
- @strudel/webaudio@1.2.0
|
|
||||||
- @strudel/xen@1.2.0
|
|
||||||
@@ -95,7 +95,7 @@ Diese Kombinationen von Buchstaben stehen für verschiedene Teile eines Schlagze
|
|||||||
- `mt` = **m**iddle tom
|
- `mt` = **m**iddle tom
|
||||||
- `ht` = **h**igh tom
|
- `ht` = **h**igh tom
|
||||||
- `rd` = **r**i**d**e cymbal
|
- `rd` = **r**i**d**e cymbal
|
||||||
- `cr` = **cr**ash cymbal
|
- `rd` = **cr**ash cymbal
|
||||||
|
|
||||||
Probier verschiedene Sounds aus!
|
Probier verschiedene Sounds aus!
|
||||||
|
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ import { JsDoc } from '../../docs/JsDoc';
|
|||||||
|
|
||||||
## arp
|
## arp
|
||||||
|
|
||||||
<JsDoc client:idle name="arp" h={0} />
|
<JsDoc client:idle name="Pattern#arp" h={0} />
|
||||||
|
|
||||||
## arpWith 🧪
|
## arpWith 🧪
|
||||||
|
|
||||||
<JsDoc client:idle name="arpWith" h={0} />
|
<JsDoc client:idle name="Pattern#arpWith" h={0} />
|
||||||
|
|
||||||
## struct
|
## struct
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ import { JsDoc } from '../../docs/JsDoc';
|
|||||||
|
|
||||||
## hush
|
## hush
|
||||||
|
|
||||||
<JsDoc client:idle name="Pattern#hush" h={0} />
|
<JsDoc client:idle name="hush" h={0} />
|
||||||
|
|
||||||
## invert
|
## invert
|
||||||
|
|
||||||
|
|||||||
@@ -57,34 +57,6 @@ Each filter has 2 parameters:
|
|||||||
|
|
||||||
<JsDoc client:idle name="vowel" h={0} />
|
<JsDoc client:idle name="vowel" h={0} />
|
||||||
|
|
||||||
# Amplitude Modulation
|
|
||||||
|
|
||||||
Amplitude modulation changes the amplitude (gain) periodically over time.
|
|
||||||
|
|
||||||
## am
|
|
||||||
|
|
||||||
<JsDoc client:idle name="am" h={0} />
|
|
||||||
|
|
||||||
## tremolosync
|
|
||||||
|
|
||||||
<JsDoc client:idle name="tremolosync" h={0} />
|
|
||||||
|
|
||||||
## tremolodepth
|
|
||||||
|
|
||||||
<JsDoc client:idle name="tremolodepth" h={0} />
|
|
||||||
|
|
||||||
## tremoloskew
|
|
||||||
|
|
||||||
<JsDoc client:idle name="tremoloskew" h={0} />
|
|
||||||
|
|
||||||
## tremolophase
|
|
||||||
|
|
||||||
<JsDoc client:idle name="tremolophase" h={0} />
|
|
||||||
|
|
||||||
## tremoloshape
|
|
||||||
|
|
||||||
<JsDoc client:idle name="tremoloshape" h={0} />
|
|
||||||
|
|
||||||
# Amplitude Envelope
|
# Amplitude Envelope
|
||||||
|
|
||||||
The amplitude [envelope](<https://en.wikipedia.org/wiki/Envelope_(music)>) controls the dynamic contour of a sound.
|
The amplitude [envelope](<https://en.wikipedia.org/wiki/Envelope_(music)>) controls the dynamic contour of a sound.
|
||||||
@@ -339,18 +311,4 @@ global effects use the same chain for all events of the same orbit:
|
|||||||
|
|
||||||
<JsDoc client:idle name="phasersweep" h={0} />
|
<JsDoc client:idle name="phasersweep" h={0} />
|
||||||
|
|
||||||
## Duck
|
|
||||||
|
|
||||||
### duckorbit
|
|
||||||
|
|
||||||
<JsDoc client:idle name="duckorbit" h={0} />
|
|
||||||
|
|
||||||
### duckattack
|
|
||||||
|
|
||||||
<JsDoc client:idle name="duckattack" h={0} />
|
|
||||||
|
|
||||||
### duckdepth
|
|
||||||
|
|
||||||
<JsDoc client:idle name="duckdepth" h={0} />
|
|
||||||
|
|
||||||
Next, we'll look at input / output via [MIDI, OSC and other methods](/learn/input-output).
|
Next, we'll look at input / output via [MIDI, OSC and other methods](/learn/input-output).
|
||||||
|
|||||||
@@ -176,16 +176,3 @@ $ chord <Dm9!3 Db7> # voicing
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
The `$` sign is an alias for `,` so it will create a stack behind the scenes.
|
The `$` sign is an alias for `,` so it will create a stack behind the scenes.
|
||||||
|
|
||||||
## variables
|
|
||||||
|
|
||||||
using the `def` keyword, you can define variables:
|
|
||||||
|
|
||||||
<MiniRepl
|
|
||||||
client:idle
|
|
||||||
mondo
|
|
||||||
tune={`
|
|
||||||
$ def melody [0 1 2 3]
|
|
||||||
$ n melody # scale C:minor
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
|
|||||||
@@ -163,21 +163,6 @@ The last section could be written as:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Please note that browsers will often cache `strudel.json` on first load, and keep using the cached
|
|
||||||
version even if the orginal has been updated. If this bites you (for example while developing a new
|
|
||||||
sample pack), you can force the browser to download a new copy by i.e. changing capitalization of one
|
|
||||||
character in the URL, or adding a URL attribute, such as:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json?version=2');
|
|
||||||
```
|
|
||||||
|
|
||||||
that gets ignored by GitHub (but changes the URL, forcing the browser to reload every time we increase
|
|
||||||
the version number).
|
|
||||||
|
|
||||||
It is also possible, of course, to just remove it from cache (deleting cache in browser Privacy settings,
|
|
||||||
or from the dev console if you're technically minded, or by using a cache deleting extension).
|
|
||||||
|
|
||||||
## Github Shortcut
|
## Github Shortcut
|
||||||
|
|
||||||
Because loading samples from github is common, there is a shortcut:
|
Because loading samples from github is common, there is a shortcut:
|
||||||
@@ -361,10 +346,6 @@ Sampler effects are functions that can be used to change the behaviour of sample
|
|||||||
|
|
||||||
<JsDoc client:idle name="splice" h={0} />
|
<JsDoc client:idle name="splice" h={0} />
|
||||||
|
|
||||||
### scrub
|
|
||||||
|
|
||||||
<JsDoc client:idle name="Pattern.scrub" h={0} />{' '}
|
|
||||||
|
|
||||||
### speed
|
### speed
|
||||||
|
|
||||||
<JsDoc client:idle name="speed" h={0} />
|
<JsDoc client:idle name="speed" h={0} />
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ Or using 2 beats per cycle:
|
|||||||
s("bd sd, hh*4")`}
|
s("bd sd, hh*4")`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
You can use the `setcps` method to set the global tempo in cycles per second. `setcpm(x)` is the same as `setcps(x / 60)`.
|
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
|
|
||||||
To set a specific bpm, use `setcpm(bpm/bpc)`
|
To set a specific bpm, use `setcpm(bpm/bpc)`
|
||||||
|
|||||||
@@ -69,133 +69,3 @@
|
|||||||
text-decoration: underline 0.18rem;
|
text-decoration: underline 0.18rem;
|
||||||
text-underline-offset: 0.22rem;
|
text-underline-offset: 0.22rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Override default styles from the codemirror inline css for autocomplete info tooltip*/
|
|
||||||
.cm-tooltip.cm-completionInfo {
|
|
||||||
padding: 12px !important;
|
|
||||||
padding-bottom: 12px !important;
|
|
||||||
border: 1px solid var(--foreground) !important;
|
|
||||||
border-radius: 4px !important;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
|
|
||||||
max-width: 500px !important;
|
|
||||||
min-width: 300px !important;
|
|
||||||
max-height: 400px !important;
|
|
||||||
white-space: normal !important;
|
|
||||||
overflow: auto !important;
|
|
||||||
background-color: var(--lineHighlight) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Main tooltip container */
|
|
||||||
.autocomplete-info-tooltip {
|
|
||||||
border-radius: 4px !important;
|
|
||||||
color: var(--foreground);
|
|
||||||
font-family: var(--font-family, 'SF Mono', 'Monaco', monospace);
|
|
||||||
font-size: var(--font-size, 13px);
|
|
||||||
line-height: 1.4;
|
|
||||||
max-width: 600px;
|
|
||||||
max-height: 400px;
|
|
||||||
min-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-function-name {
|
|
||||||
font-size: 15px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--foreground);
|
|
||||||
margin: 0 0 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-function-description {
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
color: var(--foreground);
|
|
||||||
line-height: 1.5;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-section-title {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--foreground);
|
|
||||||
margin: 16px 0 6px 0;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-section-title:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-params-section {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-params-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-param-item {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
padding: 8px;
|
|
||||||
background-color: var(--lineBackground);
|
|
||||||
border-radius: 3px;
|
|
||||||
border-left: 2px solid var(--foreground, #555);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-param-item:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-param-name {
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--variable, var(--foreground));
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-param-type {
|
|
||||||
color: var(--comment);
|
|
||||||
font-size: 12px;
|
|
||||||
background-color: var(--gutterForeground);
|
|
||||||
padding: 1px 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-param-desc {
|
|
||||||
color: var(--foreground);
|
|
||||||
font-size: 10px;
|
|
||||||
margin-top: 4px;
|
|
||||||
line-height: 1.4;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-examples-section {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-example-code {
|
|
||||||
background: var(--lineBackground);
|
|
||||||
color: var(--foreground);
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-family: var(--font-family, 'SF Mono', 'Monaco', monospace);
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.5;
|
|
||||||
margin: 4px 0;
|
|
||||||
overflow-x: auto;
|
|
||||||
white-space: pre;
|
|
||||||
border: 1px solid var(--foreground, #3a3a3a);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-tooltip::-webkit-scrollbar {
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-tooltip::-webkit-scrollbar-track {
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-tooltip::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-info-tooltip::-webkit-scrollbar-thumb:hover {
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ function UserPatterns({ context }) {
|
|||||||
style={{ display: 'none' }}
|
style={{ display: 'none' }}
|
||||||
type="file"
|
type="file"
|
||||||
multiple
|
multiple
|
||||||
accept="text/plain,text/x-markdown,application/json"
|
accept="text/plain,application/json"
|
||||||
onChange={(e) => importPatterns(e.target.files)}
|
onChange={(e) => importPatterns(e.target.files)}
|
||||||
/>
|
/>
|
||||||
import
|
import
|
||||||
|
|||||||
@@ -109,8 +109,6 @@ export function SettingsTab({ started }) {
|
|||||||
togglePanelTrigger,
|
togglePanelTrigger,
|
||||||
maxPolyphony,
|
maxPolyphony,
|
||||||
multiChannelOrbits,
|
multiChannelOrbits,
|
||||||
isTabIndentationEnabled,
|
|
||||||
isMultiCursorEnabled,
|
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
const shouldAlwaysSync = isUdels();
|
const shouldAlwaysSync = isUdels();
|
||||||
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
||||||
@@ -264,16 +262,6 @@ export function SettingsTab({ started }) {
|
|||||||
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
|
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
|
||||||
value={isLineWrappingEnabled}
|
value={isLineWrappingEnabled}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
|
||||||
label="Enable Tab indentation"
|
|
||||||
onChange={(cbEvent) => settingsMap.setKey('isTabIndentationEnabled', cbEvent.target.checked)}
|
|
||||||
value={isTabIndentationEnabled}
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
label="Enable Multi-Cursor (Cmd/Ctrl+Click)"
|
|
||||||
onChange={(cbEvent) => settingsMap.setKey('isMultiCursorEnabled', cbEvent.target.checked)}
|
|
||||||
value={isMultiCursorEnabled}
|
|
||||||
/>
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Enable flashing on evaluation"
|
label="Enable flashing on evaluation"
|
||||||
onChange={(cbEvent) => settingsMap.setKey('isFlashEnabled', cbEvent.target.checked)}
|
onChange={(cbEvent) => settingsMap.setKey('isFlashEnabled', cbEvent.target.checked)}
|
||||||
|
|||||||
@@ -28,10 +28,7 @@ export async function prebake() {
|
|||||||
prebake: true,
|
prebake: true,
|
||||||
tag: 'drum-machines',
|
tag: 'drum-machines',
|
||||||
}),
|
}),
|
||||||
samples(`${baseNoTrailing}/uzu-drumkit.json`, undefined, {
|
samples(`${baseNoTrailing}/EmuSP12.json`, undefined, { prebake: true, tag: 'drum-machines' }),
|
||||||
prebake: true,
|
|
||||||
tag: 'drum-machines',
|
|
||||||
}),
|
|
||||||
samples(`${baseNoTrailing}/mridangam.json`, undefined, { prebake: true, tag: 'drum-machines' }),
|
samples(`${baseNoTrailing}/mridangam.json`, undefined, { prebake: true, tag: 'drum-machines' }),
|
||||||
samples(
|
samples(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
resetGlobalEffects,
|
resetGlobalEffects,
|
||||||
resetLoadedSounds,
|
resetLoadedSounds,
|
||||||
initAudioOnFirstClick,
|
initAudioOnFirstClick,
|
||||||
resetDefaults,
|
|
||||||
} from '@strudel/webaudio';
|
} from '@strudel/webaudio';
|
||||||
import { setVersionDefaultsFrom } from './util.mjs';
|
import { setVersionDefaultsFrom } from './util.mjs';
|
||||||
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
|
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
|
||||||
@@ -182,7 +181,6 @@ export function useReplContext() {
|
|||||||
|
|
||||||
const resetEditor = async () => {
|
const resetEditor = async () => {
|
||||||
(await getModule('@strudel/tonal'))?.resetVoicings();
|
(await getModule('@strudel/tonal'))?.resetVoicings();
|
||||||
resetDefaults();
|
|
||||||
resetGlobalEffects();
|
resetGlobalEffects();
|
||||||
clearCanvas();
|
clearCanvas();
|
||||||
clearHydra();
|
clearHydra();
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ export const defaultSettings = {
|
|||||||
isSyncEnabled: false,
|
isSyncEnabled: false,
|
||||||
isLineWrappingEnabled: false,
|
isLineWrappingEnabled: false,
|
||||||
isPatternHighlightingEnabled: true,
|
isPatternHighlightingEnabled: true,
|
||||||
isTabIndentationEnabled: false,
|
|
||||||
isMultiCursorEnabled: false,
|
|
||||||
theme: 'strudelTheme',
|
theme: 'strudelTheme',
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
@@ -79,8 +77,6 @@ export function useSettings() {
|
|||||||
isLineWrappingEnabled: parseBoolean(state.isLineWrappingEnabled),
|
isLineWrappingEnabled: parseBoolean(state.isLineWrappingEnabled),
|
||||||
isFlashEnabled: parseBoolean(state.isFlashEnabled),
|
isFlashEnabled: parseBoolean(state.isFlashEnabled),
|
||||||
isSyncEnabled: isUdels() ? true : parseBoolean(state.isSyncEnabled),
|
isSyncEnabled: isUdels() ? true : parseBoolean(state.isSyncEnabled),
|
||||||
isTabIndentationEnabled: parseBoolean(state.isTabIndentationEnabled),
|
|
||||||
isMultiCursorEnabled: parseBoolean(state.isMultiCursorEnabled),
|
|
||||||
fontSize: Number(state.fontSize),
|
fontSize: Number(state.fontSize),
|
||||||
panelPosition: state.activeFooter !== '' && !isUdels() ? state.panelPosition : 'bottom', // <-- keep this 'bottom' where it is!
|
panelPosition: state.activeFooter !== '' && !isUdels() ? state.panelPosition : 'bottom', // <-- keep this 'bottom' where it is!
|
||||||
isPanelPinned: parseBoolean(state.isPanelPinned),
|
isPanelPinned: parseBoolean(state.isPanelPinned),
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ export async function importPatterns(fileList) {
|
|||||||
if (file.type === 'application/json') {
|
if (file.type === 'application/json') {
|
||||||
const userPatterns = userPattern.getAll();
|
const userPatterns = userPattern.getAll();
|
||||||
setUserPatterns({ ...userPatterns, ...parseJSON(content) });
|
setUserPatterns({ ...userPatterns, ...parseJSON(content) });
|
||||||
} else if (['text/x-markdown', 'text/plain'].includes(file.type)) {
|
} else if (file.type === 'text/plain') {
|
||||||
const id = file.name.replace(/\.[^/.]+$/, '');
|
const id = file.name.replace(/\.[^/.]+$/, '');
|
||||||
userPattern.update(id, { code: content });
|
userPattern.update(id, { code: content });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user