mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-27 05:28:41 +00:00
Merge branch 'tidalcycles:main' into worklet_improvements
This commit is contained in:
commit
57e1c1bd89
@ -6,7 +6,7 @@
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import { initStrudel } from 'https://cdn.skypack.dev/@strudel/web@0.8.2';
|
import { initStrudel } from 'https://cdn.skypack.dev/@strudel/web@0.8.2';
|
||||||
initStrudel({
|
initStrudel({
|
||||||
prebake: () => samples('github:tidalcycles/Dirt-Samples/master'),
|
prebake: () => samples('github:tidalcycles/dirt-samples'),
|
||||||
});
|
});
|
||||||
const click = (id, action) => document.getElementById(id).addEventListener('click', action);
|
const click = (id, action) => document.getElementById(id).addEventListener('click', action);
|
||||||
click('a', () => evaluate(`s('bd,jvbass(3,8)').jux(rev)`));
|
click('a', () => evaluate(`s('bd,jvbass(3,8)').jux(rev)`));
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="output"></div>
|
<div id="output"></div>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
|
// TODO: refactor to use newer version without controls import
|
||||||
import { controls, repl, evalScope } from 'https://cdn.skypack.dev/@strudel/core@0.11.0';
|
import { controls, repl, evalScope } from 'https://cdn.skypack.dev/@strudel/core@0.11.0';
|
||||||
import { mini } from 'https://cdn.skypack.dev/@strudel/mini@0.11.0';
|
import { mini } from 'https://cdn.skypack.dev/@strudel/mini@0.11.0';
|
||||||
import { transpiler } from 'https://cdn.skypack.dev/@strudel/transpiler@0.11.0';
|
import { transpiler } from 'https://cdn.skypack.dev/@strudel/transpiler@0.11.0';
|
||||||
@ -52,8 +53,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getTune() {
|
function getTune() {
|
||||||
return `await samples('github:tidalcycles/Dirt-Samples/master')
|
return `samples('github:tidalcycles/dirt-samples')
|
||||||
|
setcps(1);
|
||||||
stack(
|
stack(
|
||||||
// amen
|
// amen
|
||||||
n("0 1 2 3 4 5 6 7")
|
n("0 1 2 3 4 5 6 7")
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<script src="https://unpkg.com/@strudel/repl@0.9.4"></script>
|
<script src="https://unpkg.com/@strudel/repl@1.0.2"></script>
|
||||||
<strudel-editor>
|
<strudel-editor>
|
||||||
<!--
|
<!--
|
||||||
// @date 23-08-15
|
// @date 23-08-15
|
||||||
|
|||||||
8
examples/buildless/web.html
Normal file
8
examples/buildless/web.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
|
||||||
|
<button id="play">PLAY</button>
|
||||||
|
<script>
|
||||||
|
initStrudel({
|
||||||
|
prebake: () => samples('github:tidalcycles/dirt-samples'),
|
||||||
|
});
|
||||||
|
document.getElementById('play').addEventListener('click', () => s('bd sd').play());
|
||||||
|
</script>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { StrudelMirror } from '@strudel/codemirror';
|
import { StrudelMirror } from '@strudel/codemirror';
|
||||||
import { funk42 } from './tunes';
|
import { funk42 } from './tunes';
|
||||||
import { drawPianoroll, evalScope, controls } from '@strudel/core';
|
import { drawPianoroll, evalScope } from '@strudel/core';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import { initAudioOnFirstClick } from '@strudel/webaudio';
|
import { initAudioOnFirstClick } from '@strudel/webaudio';
|
||||||
import { transpiler } from '@strudel/transpiler';
|
import { transpiler } from '@strudel/transpiler';
|
||||||
@ -25,7 +25,6 @@ const editor = new StrudelMirror({
|
|||||||
prebake: async () => {
|
prebake: async () => {
|
||||||
initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..)
|
initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..)
|
||||||
const loadModules = evalScope(
|
const loadModules = evalScope(
|
||||||
controls,
|
|
||||||
import('@strudel/core'),
|
import('@strudel/core'),
|
||||||
import('@strudel/mini'),
|
import('@strudel/mini'),
|
||||||
import('@strudel/tonal'),
|
import('@strudel/tonal'),
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export const bumpStreet = `// froos - "22 bump street", licensed with CC BY-NC-SA 4.0
|
export const bumpStreet = `// froos - "22 bump street", licensed with CC BY-NC-SA 4.0
|
||||||
await samples('github:felixroos/samples/main')
|
samples('github:felixroos/samples')
|
||||||
await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
|
samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
|
||||||
|
|
||||||
"<[0,<6 7 9>,13,<17 20 22 26>]!2>/2"
|
"<[0,<6 7 9>,13,<17 20 22 26>]!2>/2"
|
||||||
// make it 22 edo
|
// make it 22 edo
|
||||||
@ -33,8 +33,8 @@ await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tid
|
|||||||
|
|
||||||
export const trafficFlam = `// froos - "traffic flam", licensed with CC BY-NC-SA 4.0
|
export const trafficFlam = `// froos - "traffic flam", licensed with CC BY-NC-SA 4.0
|
||||||
|
|
||||||
await samples('github:felixroos/samples/main')
|
samples('github:felixroos/samples')
|
||||||
await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
|
samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
|
||||||
|
|
||||||
addVoicings('hip', {
|
addVoicings('hip', {
|
||||||
m11: ['2M 3m 4P 7m'],
|
m11: ['2M 3m 4P 7m'],
|
||||||
@ -69,8 +69,8 @@ export const funk42 = `// froos - how to funk in 42 lines of code
|
|||||||
// adapted from "how to funk in two minutes" by marc rebillet https://www.youtube.com/watch?v=3vBwRfQbXkg
|
// adapted from "how to funk in two minutes" by marc rebillet https://www.youtube.com/watch?v=3vBwRfQbXkg
|
||||||
// thanks to peach for the transcription: https://www.youtube.com/watch?v=8eiPXvIgda4
|
// thanks to peach for the transcription: https://www.youtube.com/watch?v=8eiPXvIgda4
|
||||||
|
|
||||||
await samples('github:felixroos/samples/main')
|
samples('github:felixroos/samples')
|
||||||
await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
|
samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
|
||||||
|
|
||||||
setcps(.5)
|
setcps(.5)
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import { initStrudel } from '@strudel/web';
|
import { initStrudel } from '@strudel/web';
|
||||||
initStrudel({
|
initStrudel({
|
||||||
prebake: () => samples('github:tidalcycles/Dirt-Samples/master'),
|
prebake: () => samples('github:tidalcycles/dirt-samples'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const click = (id, action) => document.getElementById(id).addEventListener('click', action);
|
const click = (id, action) => document.getElementById(id).addEventListener('click', action);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { controls, repl, evalScope } from '@strudel/core';
|
import { repl, evalScope } from '@strudel/core';
|
||||||
import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio';
|
import { getAudioContext, webaudioOutput, initAudioOnFirstClick, registerSynthSounds } from '@strudel/webaudio';
|
||||||
import { transpiler } from '@strudel/transpiler';
|
import { transpiler } from '@strudel/transpiler';
|
||||||
import tune from './tune.mjs';
|
import tune from './tune.mjs';
|
||||||
|
|
||||||
@ -7,14 +7,9 @@ const ctx = getAudioContext();
|
|||||||
const input = document.getElementById('text');
|
const input = document.getElementById('text');
|
||||||
input.innerHTML = tune;
|
input.innerHTML = tune;
|
||||||
initAudioOnFirstClick();
|
initAudioOnFirstClick();
|
||||||
|
registerSynthSounds();
|
||||||
|
|
||||||
evalScope(
|
evalScope(import('@strudel/core'), import('@strudel/mini'), import('@strudel/webaudio'), import('@strudel/tonal'));
|
||||||
controls,
|
|
||||||
import('@strudel/core'),
|
|
||||||
import('@strudel/mini'),
|
|
||||||
import('@strudel/webaudio'),
|
|
||||||
import('@strudel/tonal'),
|
|
||||||
);
|
|
||||||
|
|
||||||
const { evaluate } = repl({
|
const { evaluate } = repl({
|
||||||
defaultOutput: webaudioOutput,
|
defaultOutput: webaudioOutput,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export default `await samples('github:tidalcycles/Dirt-Samples/master')
|
export default `samples('github:tidalcycles/dirt-samples')
|
||||||
|
setcps(1)
|
||||||
stack(
|
stack(
|
||||||
// amen
|
// amen
|
||||||
n("0 1 2 3 4 5 6 7")
|
n("0 1 2 3 4 5 6 7")
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
const init = Promise.all([
|
const init = Promise.all([
|
||||||
initAudioOnFirstClick(),
|
initAudioOnFirstClick(),
|
||||||
samples('github:tidalcycles/Dirt-Samples/master'),
|
samples('github:tidalcycles/dirt-samples'),
|
||||||
registerSynthSounds(),
|
registerSynthSounds(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { closeBrackets } from '@codemirror/autocomplete';
|
|||||||
// import { search, highlightSelectionMatches } from '@codemirror/search';
|
// import { search, highlightSelectionMatches } from '@codemirror/search';
|
||||||
import { history } from '@codemirror/commands';
|
import { history } from '@codemirror/commands';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
import { defaultHighlightStyle, syntaxHighlighting, bracketMatching } from '@codemirror/language';
|
||||||
import { Compartment, EditorState, Prec } from '@codemirror/state';
|
import { Compartment, EditorState, Prec } from '@codemirror/state';
|
||||||
import {
|
import {
|
||||||
EditorView,
|
EditorView,
|
||||||
@ -24,6 +24,7 @@ import { persistentAtom } from '@nanostores/persistent';
|
|||||||
|
|
||||||
const extensions = {
|
const extensions = {
|
||||||
isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []),
|
isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []),
|
||||||
|
isBracketMatchingEnabled: (on) => (on ? bracketMatching({ brackets: '()[]{}<>' }) : []),
|
||||||
isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
|
isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
|
||||||
theme,
|
theme,
|
||||||
isAutoCompletionEnabled,
|
isAutoCompletionEnabled,
|
||||||
@ -37,6 +38,7 @@ const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [ke
|
|||||||
|
|
||||||
export const defaultSettings = {
|
export const defaultSettings = {
|
||||||
keybindings: 'codemirror',
|
keybindings: 'codemirror',
|
||||||
|
isBracketMatchingEnabled: false,
|
||||||
isLineNumbersDisplayed: true,
|
isLineNumbersDisplayed: true,
|
||||||
isActiveLineHighlighted: false,
|
isActiveLineHighlighted: false,
|
||||||
isAutoCompletionEnabled: false,
|
isAutoCompletionEnabled: false,
|
||||||
@ -290,6 +292,9 @@ export class StrudelMirror {
|
|||||||
setLineWrappingEnabled(enabled) {
|
setLineWrappingEnabled(enabled) {
|
||||||
this.reconfigureExtension('isLineWrappingEnabled', enabled);
|
this.reconfigureExtension('isLineWrappingEnabled', enabled);
|
||||||
}
|
}
|
||||||
|
setBracketMatchingEnabled(enabled) {
|
||||||
|
this.reconfigureExtension('isBracketMatchingEnabled', enabled);
|
||||||
|
}
|
||||||
setLineNumbersDisplayed(enabled) {
|
setLineNumbersDisplayed(enabled) {
|
||||||
this.reconfigureExtension('isLineNumbersDisplayed', enabled);
|
this.reconfigureExtension('isLineNumbersDisplayed', enabled);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/codemirror",
|
"name": "@strudel/codemirror",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Codemirror Extensions for Strudel",
|
"description": "Codemirror Extensions for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
import { Pattern, getDrawContext, silence, register, pure } from './index.mjs';
|
import { Pattern, getDrawContext, silence, register, pure, createParams } from './index.mjs';
|
||||||
import controls from './controls.mjs'; // do not import from index.mjs as it breaks for some reason..
|
|
||||||
const { createParams } = controls;
|
|
||||||
|
|
||||||
let clearColor = '#22222210';
|
let clearColor = '#22222210';
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,12 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
|
|||||||
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 controls from './controls.mjs';
|
import * as controls from './controls.mjs'; // legacy
|
||||||
export * from './euclid.mjs';
|
export * from './euclid.mjs';
|
||||||
import Fraction from './fraction.mjs';
|
import Fraction from './fraction.mjs';
|
||||||
import { logger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
export { Fraction, controls };
|
export { Fraction, controls };
|
||||||
|
export * from './controls.mjs';
|
||||||
export * from './hap.mjs';
|
export * from './hap.mjs';
|
||||||
export * from './pattern.mjs';
|
export * from './pattern.mjs';
|
||||||
export * from './signal.mjs';
|
export * from './signal.mjs';
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/core",
|
"name": "@strudel/core",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Port of Tidal Cycles to JavaScript",
|
"description": "Port of Tidal Cycles to JavaScript",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
|
|||||||
@ -2322,10 +2322,10 @@ const _loopAt = function (factor, pat, cps = 0.5) {
|
|||||||
* @memberof Pattern
|
* @memberof Pattern
|
||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
* @example
|
* @example
|
||||||
* await samples('github:tidalcycles/Dirt-Samples/master')
|
* samples('github:tidalcycles/dirt-samples')
|
||||||
* s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(0.75)
|
* s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(0.75)
|
||||||
* @example
|
* @example
|
||||||
* await samples('github:tidalcycles/Dirt-Samples/master')
|
* samples('github:tidalcycles/dirt-samples')
|
||||||
* s("breaks125").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>")
|
* s("breaks125").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>")
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -2351,7 +2351,7 @@ export const slice = register(
|
|||||||
* Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
|
* Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
|
||||||
* @name splice
|
* @name splice
|
||||||
* @example
|
* @example
|
||||||
* await samples('github:tidalcycles/Dirt-Samples/master')
|
* samples('github:tidalcycles/dirt-samples')
|
||||||
* s("breaks165")
|
* s("breaks165")
|
||||||
* .splice(8, "0 1 [2 3 0]@2 3 0@2 7")
|
* .splice(8, "0 1 [2 3 0]@2 3 0@2 7")
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -4,23 +4,23 @@ Copyright (C) 2023 Strudel contributors - see <https://github.com/tidalcycles/st
|
|||||||
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 controls from '../controls.mjs';
|
import { s } from '../controls.mjs';
|
||||||
import { mini } from '../../mini/mini.mjs';
|
import { mini } from '../../mini/mini.mjs';
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
describe('controls', () => {
|
describe('controls', () => {
|
||||||
it('should support controls', () => {
|
it('should support controls', () => {
|
||||||
expect(controls.s('bd').firstCycleValues).toEqual([{ s: 'bd' }]);
|
expect(s('bd').firstCycleValues).toEqual([{ s: 'bd' }]);
|
||||||
});
|
});
|
||||||
it('should support compound controls', () => {
|
it('should support compound controls', () => {
|
||||||
expect(controls.s(mini('bd:3')).firstCycleValues).toEqual([{ s: 'bd', n: 3 }]);
|
expect(s(mini('bd:3')).firstCycleValues).toEqual([{ s: 'bd', n: 3 }]);
|
||||||
expect(controls.s(mini('bd:3 sd:4:1.4')).firstCycleValues).toEqual([
|
expect(s(mini('bd:3 sd:4:1.4')).firstCycleValues).toEqual([
|
||||||
{ s: 'bd', n: 3 },
|
{ s: 'bd', n: 3 },
|
||||||
{ s: 'sd', n: 4, gain: 1.4 },
|
{ s: 'sd', n: 4, gain: 1.4 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('should support ignore extra elements in compound controls', () => {
|
it('should support ignore extra elements in compound controls', () => {
|
||||||
expect(controls.s(mini('bd:3:0.4 sd:4:0.5:3:17')).firstCycleValues).toEqual([
|
expect(s(mini('bd:3:0.4 sd:4:0.5:3:17')).firstCycleValues).toEqual([
|
||||||
{ s: 'bd', n: 3, gain: 0.4 },
|
{ s: 'bd', n: 3, gain: 0.4 },
|
||||||
{ s: 'sd', n: 4, gain: 0.5 },
|
{ s: 'sd', n: 4, gain: 0.5 },
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -51,9 +51,8 @@ import {
|
|||||||
|
|
||||||
import { steady } from '../signal.mjs';
|
import { steady } from '../signal.mjs';
|
||||||
|
|
||||||
import controls from '../controls.mjs';
|
import { n, s } from '../controls.mjs';
|
||||||
|
|
||||||
const { n, s } = controls;
|
|
||||||
const st = (begin, end) => new State(ts(begin, end));
|
const st = (begin, end) => new State(ts(begin, end));
|
||||||
const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end));
|
const ts = (begin, end) => new TimeSpan(Fraction(begin), Fraction(end));
|
||||||
const hap = (whole, part, value, context = {}) => new Hap(whole, part, value, context);
|
const hap = (whole, part, value, context = {}) => new Hap(whole, part, value, context);
|
||||||
|
|||||||
@ -6,8 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
|
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { map, valued, mul } from '../value.mjs';
|
import { map, valued, mul } from '../value.mjs';
|
||||||
import controls from '../controls.mjs';
|
import { n } from '../controls.mjs';
|
||||||
const { n } = controls;
|
|
||||||
|
|
||||||
describe('Value', () => {
|
describe('Value', () => {
|
||||||
it('unionWith', () => {
|
it('unionWith', () => {
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/csound",
|
"name": "@strudel/csound",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "csound bindings for strudel",
|
"description": "csound bindings for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -6,11 +6,11 @@ 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((time, hap, currentTime) => {
|
return this.onTrigger((time, hap, currentTime, cps) => {
|
||||||
const { note, nrpnn, nrpv, ccn, ccv } = hap.value;
|
const { note, nrpnn, nrpv, ccn, ccv } = hap.value;
|
||||||
const offset = (time - currentTime) * 1000;
|
const offset = (time - currentTime) * 1000;
|
||||||
const velocity = Math.floor((hap.context?.velocity ?? 0.9) * 100); // TODO: refactor velocity
|
const velocity = Math.floor((hap.context?.velocity ?? 0.9) * 100); // TODO: refactor velocity
|
||||||
const duration = Math.floor(hap.duration.valueOf() * 1000 - 10);
|
const duration = Math.floor((hap.duration.valueOf() / cps) * 1000 - 10);
|
||||||
const roundedOffset = Math.round(offset);
|
const roundedOffset = Math.round(offset);
|
||||||
const midichan = (hap.value.midichan ?? 1) - 1;
|
const midichan = (hap.value.midichan ?? 1) - 1;
|
||||||
const requestedport = output ?? 'IAC';
|
const requestedport = output ?? 'IAC';
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/hydra",
|
"name": "@strudel/hydra",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Hydra integration for strudel",
|
"description": "Hydra integration for strudel",
|
||||||
"main": "hydra.mjs",
|
"main": "hydra.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"server": "node server.js",
|
"server": "node server.js",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'hydra.mjs'),
|
entry: resolve(__dirname, 'hydra.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -129,7 +129,7 @@ Pattern.prototype.midi = function (output) {
|
|||||||
const velocity = hap.context?.velocity ?? 0.9; // TODO: refactor velocity
|
const velocity = hap.context?.velocity ?? 0.9; // TODO: refactor velocity
|
||||||
|
|
||||||
// note off messages will often a few ms arrive late, try to prevent glitching by subtracting from the duration length
|
// note off messages will often a few ms arrive late, try to prevent glitching by subtracting from the duration length
|
||||||
const duration = Math.floor(hap.duration.valueOf() * 1000 - 10);
|
const duration = Math.floor((hap.duration.valueOf() / cps) * 1000 - 10);
|
||||||
if (note != null) {
|
if (note != null) {
|
||||||
const midiNumber = typeof note === 'number' ? note : noteToMidi(note);
|
const midiNumber = typeof note === 'number' ? note : noteToMidi(note);
|
||||||
const midiNote = new Note(midiNumber, { attack: velocity, duration });
|
const midiNote = new Note(midiNumber, { attack: velocity, duration });
|
||||||
@ -167,10 +167,16 @@ let listeners = {};
|
|||||||
const refs = {};
|
const refs = {};
|
||||||
|
|
||||||
export async function midin(input) {
|
export async function midin(input) {
|
||||||
|
if (isPattern(input)) {
|
||||||
|
throw new Error(
|
||||||
|
`.midi does not accept Pattern input. Make sure to pass device name with single quotes. Example: .midi('${
|
||||||
|
WebMidi.outputs?.[0]?.name || 'IAC Driver Bus 1'
|
||||||
|
}')`,
|
||||||
|
);
|
||||||
|
}
|
||||||
const initial = await enableWebMidi(); // only returns on first init
|
const initial = await enableWebMidi(); // only returns on first init
|
||||||
const device = getDevice(input, WebMidi.inputs);
|
const device = getDevice(input, WebMidi.inputs);
|
||||||
|
if (initial || WebMidi.enabled) {
|
||||||
if (initial) {
|
|
||||||
const otherInputs = WebMidi.inputs.filter((o) => o.name !== device.name);
|
const otherInputs = WebMidi.inputs.filter((o) => o.name !== device.name);
|
||||||
logger(
|
logger(
|
||||||
`Midi enabled! Using "${device.name}". ${
|
`Midi enabled! Using "${device.name}". ${
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/midi",
|
"name": "@strudel/midi",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Midi API for strudel",
|
"description": "Midi API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/mini",
|
"name": "@strudel/mini",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Mini notation for strudel",
|
"description": "Mini notation for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/osc",
|
"name": "@strudel/osc",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "OSC messaging for strudel",
|
"description": "OSC messaging for strudel",
|
||||||
"main": "osc.mjs",
|
"main": "osc.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"server": "node server.js",
|
"server": "node server.js",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'osc.mjs'),
|
entry: resolve(__dirname, 'osc.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
# @strudel/repl
|
# @strudel/repl
|
||||||
|
|
||||||
The Strudel REPL as a web component.
|
The Strudel REPL as a web component.
|
||||||
|
|
||||||
|
[Usage example](https://github.com/tidalcycles/strudel/blob/main/examples/buildless/web-component-no-iframe.html)
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/repl",
|
"name": "@strudel/repl",
|
||||||
"version": "1.0.0",
|
"version": "1.0.2",
|
||||||
"description": "Strudel REPL as a Web Component",
|
"description": "Strudel REPL as a Web Component",
|
||||||
"main": "index.mjs",
|
"module": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.mjs"
|
"module": "dist/index.mjs"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { controls, noteToMidi, valueToMidi, Pattern, evalScope } from '@strudel/core';
|
import { noteToMidi, valueToMidi, Pattern, evalScope } from '@strudel/core';
|
||||||
import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
|
||||||
import * as core from '@strudel/core';
|
import * as core from '@strudel/core';
|
||||||
|
|
||||||
@ -17,7 +17,6 @@ export async function prebake() {
|
|||||||
// import('@strudel/serial'),
|
// import('@strudel/serial'),
|
||||||
// import('@strudel/csound'),
|
// import('@strudel/csound'),
|
||||||
// import('@strudel/osc'),
|
// import('@strudel/osc'),
|
||||||
controls, // sadly, this cannot be exported from core directly (yet)
|
|
||||||
);
|
);
|
||||||
// load samples
|
// load samples
|
||||||
const ds = 'https://raw.githubusercontent.com/felixroos/dough-samples/main/';
|
const ds = 'https://raw.githubusercontent.com/felixroos/dough-samples/main/';
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/serial",
|
"name": "@strudel/serial",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Webserial API for strudel",
|
"description": "Webserial API for strudel",
|
||||||
"main": "serial.mjs",
|
"main": "serial.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'serial.mjs'),
|
entry: resolve(__dirname, 'serial.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/soundfonts",
|
"name": "@strudel/soundfonts",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Soundsfont support for strudel",
|
"description": "Soundsfont support for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import { superdough, samples, initAudioOnFirstClick, registerSynthSounds } from
|
|||||||
|
|
||||||
const init = Promise.all([
|
const init = Promise.all([
|
||||||
initAudioOnFirstClick(),
|
initAudioOnFirstClick(),
|
||||||
samples('github:tidalcycles/Dirt-Samples/master'),
|
samples('github:tidalcycles/dirt-samples'),
|
||||||
registerSynthSounds(),
|
registerSynthSounds(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ The json file is expected to have the same format as described above.
|
|||||||
Because it is common to use github for samples, there is a short way to load a sample map from github:
|
Because it is common to use github for samples, there is a short way to load a sample map from github:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
samples('github:tidalcycles/Dirt-Samples/master')
|
samples('github:tidalcycles/dirt-samples')
|
||||||
```
|
```
|
||||||
|
|
||||||
The format is `github:<user>/<repo>/<branch>`.
|
The format is `github:<user>/<repo>/<branch>`.
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "superdough",
|
"name": "superdough",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"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",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.cjs",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"directories": {
|
"directories": {
|
||||||
"example": "examples"
|
"example": "examples"
|
||||||
|
|||||||
@ -99,6 +99,27 @@ export const getLoadedBuffer = (url) => {
|
|||||||
return bufferCache[url];
|
return bufferCache[url];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function resolveSpecialPaths(base) {
|
||||||
|
if (base.startsWith('bubo:')) {
|
||||||
|
const [_, repo] = base.split(':');
|
||||||
|
base = `github:Bubobubobubobubo/dough-${repo}`;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
function githubPath(base, subpath = '') {
|
||||||
|
if (!base.startsWith('github:')) {
|
||||||
|
throw new Error('expected "github:" at the start of pseudoUrl');
|
||||||
|
}
|
||||||
|
let [_, path] = base.split('github:');
|
||||||
|
path = path.endsWith('/') ? path.slice(0, -1) : path;
|
||||||
|
if (path.split('/').length === 2) {
|
||||||
|
// assume main as default branch if none set
|
||||||
|
path += '/main';
|
||||||
|
}
|
||||||
|
return `https://raw.githubusercontent.com/${path}/${subpath}`;
|
||||||
|
}
|
||||||
|
|
||||||
export const processSampleMap = (sampleMap, fn, baseUrl = sampleMap._base || '') => {
|
export const processSampleMap = (sampleMap, fn, baseUrl = sampleMap._base || '') => {
|
||||||
return Object.entries(sampleMap).forEach(([key, value]) => {
|
return Object.entries(sampleMap).forEach(([key, value]) => {
|
||||||
if (typeof value === 'string') {
|
if (typeof value === 'string') {
|
||||||
@ -108,15 +129,19 @@ export const processSampleMap = (sampleMap, fn, baseUrl = sampleMap._base || '')
|
|||||||
throw new Error('wrong sample map format for ' + key);
|
throw new Error('wrong sample map format for ' + key);
|
||||||
}
|
}
|
||||||
baseUrl = value._base || baseUrl;
|
baseUrl = value._base || baseUrl;
|
||||||
const replaceUrl = (v) => (baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/');
|
baseUrl = resolveSpecialPaths(baseUrl);
|
||||||
|
if (baseUrl.startsWith('github:')) {
|
||||||
|
baseUrl = githubPath(baseUrl, '');
|
||||||
|
}
|
||||||
|
const fullUrl = (v) => baseUrl + v;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
//return [key, value.map(replaceUrl)];
|
//return [key, value.map(replaceUrl)];
|
||||||
value = value.map(replaceUrl);
|
value = value.map(fullUrl);
|
||||||
} else {
|
} else {
|
||||||
// must be object
|
// must be object
|
||||||
value = Object.fromEntries(
|
value = Object.fromEntries(
|
||||||
Object.entries(value).map(([note, samples]) => {
|
Object.entries(value).map(([note, samples]) => {
|
||||||
return [note, (typeof samples === 'string' ? [samples] : samples).map(replaceUrl)];
|
return [note, (typeof samples === 'string' ? [samples] : samples).map(fullUrl)];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -142,7 +167,7 @@ function getSamplesPrefixHandler(url) {
|
|||||||
/**
|
/**
|
||||||
* Loads a collection of samples to use with `s`
|
* Loads a collection of samples to use with `s`
|
||||||
* @example
|
* @example
|
||||||
* samples('github:tidalcycles/Dirt-Samples/master');
|
* samples('github:tidalcycles/dirt-samples');
|
||||||
* s("[bd ~]*2, [~ hh]*2, ~ sd")
|
* s("[bd ~]*2, [~ hh]*2, ~ sd")
|
||||||
* @example
|
* @example
|
||||||
* samples({
|
* samples({
|
||||||
@ -165,18 +190,9 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option
|
|||||||
if (handler) {
|
if (handler) {
|
||||||
return handler(sampleMap);
|
return handler(sampleMap);
|
||||||
}
|
}
|
||||||
if (sampleMap.startsWith('bubo:')) {
|
sampleMap = resolveSpecialPaths(sampleMap);
|
||||||
const [_, repo] = sampleMap.split(':');
|
|
||||||
sampleMap = `github:Bubobubobubobubo/dough-${repo}`;
|
|
||||||
}
|
|
||||||
if (sampleMap.startsWith('github:')) {
|
if (sampleMap.startsWith('github:')) {
|
||||||
let [_, path] = sampleMap.split('github:');
|
sampleMap = githubPath(sampleMap, 'strudel.json');
|
||||||
path = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
||||||
if (path.split('/').length === 2) {
|
|
||||||
// assume main as default branch if none set
|
|
||||||
path += '/main';
|
|
||||||
}
|
|
||||||
sampleMap = `https://raw.githubusercontent.com/${path}/strudel.json`;
|
|
||||||
}
|
}
|
||||||
if (sampleMap.startsWith('shabda:')) {
|
if (sampleMap.startsWith('shabda:')) {
|
||||||
let [_, path] = sampleMap.split('shabda:');
|
let [_, path] = sampleMap.split('shabda:');
|
||||||
|
|||||||
@ -253,6 +253,11 @@ function effectSend(input, effect, wet) {
|
|||||||
return send;
|
return send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resetGlobalEffects() {
|
||||||
|
delays = {};
|
||||||
|
reverbs = {};
|
||||||
|
}
|
||||||
|
|
||||||
export const superdough = async (value, deadline, hapDuration) => {
|
export const superdough = async (value, deadline, hapDuration) => {
|
||||||
const ac = getAudioContext();
|
const ac = getAudioContext();
|
||||||
if (typeof value !== 'object') {
|
if (typeof value !== 'object') {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.cjs' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.cjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/tonal",
|
"name": "@strudel/tonal",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Tonal functions for strudel",
|
"description": "Tonal functions for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -7,10 +7,9 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
// import { strict as assert } from 'assert';
|
// import { strict as assert } from 'assert';
|
||||||
|
|
||||||
import '../tonal.mjs'; // need to import this to add prototypes
|
import '../tonal.mjs'; // need to import this to add prototypes
|
||||||
import { pure, controls, seq } from '@strudel/core';
|
import { pure, n, seq } from '@strudel/core';
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { mini } from '../../mini/mini.mjs';
|
import { mini } from '../../mini/mini.mjs';
|
||||||
const { n } = controls;
|
|
||||||
|
|
||||||
describe('tonal', () => {
|
describe('tonal', () => {
|
||||||
it('Should run tonal functions ', () => {
|
it('Should run tonal functions ', () => {
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/transpiler",
|
"name": "@strudel/transpiler",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -23,6 +23,9 @@ describe('transpiler', () => {
|
|||||||
it('supports top level await', () => {
|
it('supports top level await', () => {
|
||||||
expect(transpiler("await samples('xxx');", simple).output).toEqual("await samples('xxx');");
|
expect(transpiler("await samples('xxx');", simple).output).toEqual("await samples('xxx');");
|
||||||
});
|
});
|
||||||
|
it('adds await to bare samples call', () => {
|
||||||
|
expect(transpiler("samples('xxx');", simple).output).toEqual("await samples('xxx');");
|
||||||
|
});
|
||||||
/* it('parses dynamic imports', () => {
|
/* it('parses dynamic imports', () => {
|
||||||
expect(
|
expect(
|
||||||
transpiler("const { default: foo } = await import('https://bar.com/foo.js');", {
|
transpiler("const { default: foo } = await import('https://bar.com/foo.js');", {
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import escodegen from 'escodegen';
|
|
||||||
import { parse } from 'acorn';
|
|
||||||
import { walk } from 'estree-walker';
|
|
||||||
import { isNoteWithOctave } from '@strudel/core';
|
|
||||||
import { getLeafLocations } from '@strudel/mini';
|
import { getLeafLocations } from '@strudel/mini';
|
||||||
|
import { parse } from 'acorn';
|
||||||
|
import escodegen from 'escodegen';
|
||||||
|
import { walk } from 'estree-walker';
|
||||||
|
|
||||||
export function transpiler(input, options = {}) {
|
export function transpiler(input, options = {}) {
|
||||||
const { wrapAsync = false, addReturn = true, emitMiniLocations = true, emitWidgets = true } = options;
|
const { wrapAsync = false, addReturn = true, emitMiniLocations = true, emitWidgets = true } = options;
|
||||||
@ -47,6 +46,9 @@ export function transpiler(input, options = {}) {
|
|||||||
});
|
});
|
||||||
return this.replace(widgetWithLocation(node));
|
return this.replace(widgetWithLocation(node));
|
||||||
}
|
}
|
||||||
|
if (isBareSamplesCall(node, parent)) {
|
||||||
|
return this.replace(withAwait(node));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
leave(node, parent, prop, index) {},
|
leave(node, parent, prop, index) {},
|
||||||
});
|
});
|
||||||
@ -119,3 +121,14 @@ function widgetWithLocation(node) {
|
|||||||
node.callee.name = 'sliderWithID';
|
node.callee.name = 'sliderWithID';
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isBareSamplesCall(node, parent) {
|
||||||
|
return node.type === 'CallExpression' && node.callee.name === 'samples' && parent.type !== 'AwaitExpression';
|
||||||
|
}
|
||||||
|
|
||||||
|
function withAwait(node) {
|
||||||
|
return {
|
||||||
|
type: 'AwaitExpression',
|
||||||
|
argument: node,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -43,7 +43,7 @@ By default, no external samples are loaded, but you can add them like this:
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
initStrudel({
|
initStrudel({
|
||||||
prebake: () => samples('github:tidalcycles/Dirt-Samples/master'),
|
prebake: () => samples('github:tidalcycles/dirt-samples'),
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('play').addEventListener('click',
|
document.getElementById('play').addEventListener('click',
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/web",
|
"name": "@strudel/web",
|
||||||
"version": "1.0.0",
|
"version": "1.0.3",
|
||||||
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
||||||
"main": "web.mjs",
|
"module": "web.mjs",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.mjs"
|
"module": "dist/index.mjs"
|
||||||
@ -37,7 +37,8 @@
|
|||||||
"@strudel/mini": "workspace:*",
|
"@strudel/mini": "workspace:*",
|
||||||
"@strudel/tonal": "workspace:*",
|
"@strudel/tonal": "workspace:*",
|
||||||
"@strudel/transpiler": "workspace:*",
|
"@strudel/transpiler": "workspace:*",
|
||||||
"@strudel/webaudio": "workspace:*"
|
"@strudel/webaudio": "workspace:*",
|
||||||
|
"@rollup/plugin-replace": "^5.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vite": "^5.0.10"
|
"vite": "^5.0.10"
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import { dependencies } from './package.json';
|
import { dependencies } from './package.json';
|
||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
|
import replace from '@rollup/plugin-replace';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@ -8,11 +9,18 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'web.mjs'),
|
entry: resolve(__dirname, 'web.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
name: 'strudel',
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
formats: ['es', 'iife'],
|
||||||
|
fileName: (ext) => ({ es: 'index.mjs', iife: 'index.js' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
// external: [...Object.keys(dependencies)],
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||||
|
preventAssignment: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
target: 'esnext',
|
target: 'esnext',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export * from '@strudel/transpiler';
|
|||||||
export * from '@strudel/mini';
|
export * from '@strudel/mini';
|
||||||
export * from '@strudel/tonal';
|
export * from '@strudel/tonal';
|
||||||
export * from '@strudel/webaudio';
|
export * from '@strudel/webaudio';
|
||||||
import { Pattern, evalScope, controls } from '@strudel/core';
|
import { Pattern, evalScope } from '@strudel/core';
|
||||||
import { initAudioOnFirstClick, registerSynthSounds, webaudioScheduler } from '@strudel/webaudio';
|
import { initAudioOnFirstClick, registerSynthSounds, webaudioScheduler } from '@strudel/webaudio';
|
||||||
// import { registerSoundfonts } from '@strudel/soundfonts';
|
// import { registerSoundfonts } from '@strudel/soundfonts';
|
||||||
import { evaluate as _evaluate } from '@strudel/transpiler';
|
import { evaluate as _evaluate } from '@strudel/transpiler';
|
||||||
@ -15,7 +15,6 @@ import { miniAllStrings } from '@strudel/mini';
|
|||||||
export async function defaultPrebake() {
|
export async function defaultPrebake() {
|
||||||
const loadModules = evalScope(
|
const loadModules = evalScope(
|
||||||
evalScope,
|
evalScope,
|
||||||
controls,
|
|
||||||
import('@strudel/core'),
|
import('@strudel/core'),
|
||||||
import('@strudel/mini'),
|
import('@strudel/mini'),
|
||||||
import('@strudel/tonal'),
|
import('@strudel/tonal'),
|
||||||
|
|||||||
@ -12,9 +12,8 @@ npm i @strudel/webaudio --save
|
|||||||
## Example
|
## Example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { repl, controls } from "@strudel/core";
|
import { repl, note } from "@strudel/core";
|
||||||
import { initAudioOnFirstClick, getAudioContext, webaudioOutput } from "@strudel/webaudio";
|
import { initAudioOnFirstClick, getAudioContext, webaudioOutput } from "@strudel/webaudio";
|
||||||
const { note } = controls;
|
|
||||||
|
|
||||||
initAudioOnFirstClick();
|
initAudioOnFirstClick();
|
||||||
const ctx = getAudioContext();
|
const ctx = getAudioContext();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/webaudio",
|
"name": "@strudel/webaudio",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Web Audio helpers for Strudel",
|
"description": "Web Audio helpers for Strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@ -8,8 +8,7 @@
|
|||||||
"example": "examples"
|
"example": "examples"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"example": "npx parcel examples/repl.html",
|
"example": "npx parcel examples/repl.html",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/xen",
|
"name": "@strudel/xen",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "Xenharmonic API for strudel",
|
"description": "Xenharmonic API for strudel",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
|
"type": "module",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.mjs"
|
||||||
"module": "dist/index.mjs"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|||||||
@ -8,8 +8,8 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, 'index.mjs'),
|
entry: resolve(__dirname, 'index.mjs'),
|
||||||
formats: ['es', 'cjs'],
|
formats: ['es'],
|
||||||
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
|
fileName: (ext) => ({ es: 'index.mjs' })[ext],
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: [...Object.keys(dependencies)],
|
external: [...Object.keys(dependencies)],
|
||||||
|
|||||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@ -430,6 +430,9 @@ importers:
|
|||||||
|
|
||||||
packages/web:
|
packages/web:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@rollup/plugin-replace':
|
||||||
|
specifier: ^5.0.5
|
||||||
|
version: 5.0.5
|
||||||
'@strudel/core':
|
'@strudel/core':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../core
|
version: link:../core
|
||||||
@ -3691,7 +3694,6 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/pluginutils': 5.1.0
|
'@rollup/pluginutils': 5.1.0
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@rollup/pluginutils@3.1.0(rollup@2.79.1):
|
/@rollup/pluginutils@3.1.0(rollup@2.79.1):
|
||||||
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
|
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
|
||||||
@ -3717,7 +3719,6 @@ packages:
|
|||||||
'@types/estree': 1.0.0
|
'@types/estree': 1.0.0
|
||||||
estree-walker: 2.0.2
|
estree-walker: 2.0.2
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@rollup/rollup-android-arm-eabi@4.9.2:
|
/@rollup/rollup-android-arm-eabi@4.9.2:
|
||||||
resolution: {integrity: sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==}
|
resolution: {integrity: sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==}
|
||||||
@ -7118,7 +7119,6 @@ packages:
|
|||||||
|
|
||||||
/estree-walker@2.0.2:
|
/estree-walker@2.0.2:
|
||||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/estree-walker@3.0.3:
|
/estree-walker@3.0.3:
|
||||||
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { evaluate } from '@strudel/transpiler';
|
|||||||
import { evalScope } from '@strudel/core';
|
import { evalScope } from '@strudel/core';
|
||||||
import * as strudel from '@strudel/core';
|
import * as strudel from '@strudel/core';
|
||||||
import * as webaudio from '@strudel/webaudio';
|
import * as webaudio from '@strudel/webaudio';
|
||||||
import controls from '@strudel/core/controls.mjs';
|
|
||||||
// import gist from '@strudel/core/gist.js';
|
// import gist from '@strudel/core/gist.js';
|
||||||
import { mini, m } from '@strudel/mini/mini.mjs';
|
import { mini, m } from '@strudel/mini/mini.mjs';
|
||||||
// import * as voicingHelpers from '@strudel/tonal/voicings.mjs';
|
// import * as voicingHelpers from '@strudel/tonal/voicings.mjs';
|
||||||
@ -21,7 +20,6 @@ import '@strudel/xen/xen.mjs';
|
|||||||
// import '@strudel/osc/osc.mjs';
|
// import '@strudel/osc/osc.mjs';
|
||||||
// import '@strudel/webaudio/webaudio.mjs';
|
// import '@strudel/webaudio/webaudio.mjs';
|
||||||
// import '@strudel/serial/serial.mjs';
|
// import '@strudel/serial/serial.mjs';
|
||||||
// import controls from '@strudel/core/controls.mjs';
|
|
||||||
import '../website/src/repl/piano';
|
import '../website/src/repl/piano';
|
||||||
|
|
||||||
class MockedNode {
|
class MockedNode {
|
||||||
@ -153,10 +151,9 @@ evalScope(
|
|||||||
strudel,
|
strudel,
|
||||||
toneHelpersMocked,
|
toneHelpersMocked,
|
||||||
uiHelpersMocked,
|
uiHelpersMocked,
|
||||||
controls,
|
|
||||||
webaudio,
|
webaudio,
|
||||||
tonalHelpers,
|
tonalHelpers,
|
||||||
/* controls,
|
/*
|
||||||
toneHelpers,
|
toneHelpers,
|
||||||
voicingHelpers,
|
voicingHelpers,
|
||||||
drawHelpers,
|
drawHelpers,
|
||||||
|
|||||||
@ -29,7 +29,7 @@ edit: the desktop app performance on linux is currently not that great.. the web
|
|||||||
The desktop App has the same features as the webapp, with the additional ability to load samples from disk. It is currently not documented yet, but you can do something like
|
The desktop App has the same features as the webapp, with the additional ability to load samples from disk. It is currently not documented yet, but you can do something like
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await samples('~/music/xxx');
|
samples('~/music/xxx');
|
||||||
|
|
||||||
s('my_sound');
|
s('my_sound');
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export const examples = [
|
export const examples = [
|
||||||
`// "coastline" @by eddyflux
|
`// "coastline" @by eddyflux
|
||||||
await samples('github:eddyflux/crate')
|
samples('github:eddyflux/crate')
|
||||||
setcps(.75)
|
setcps(.75)
|
||||||
let chords = chord("<Bbm9 Fm9>/4").dict('ireal')
|
let chords = chord("<Bbm9 Fm9>/4").dict('ireal')
|
||||||
stack(
|
stack(
|
||||||
@ -30,7 +30,7 @@ stack(
|
|||||||
.late("[0 .01]*4").late("[0 .01]*2").size(4)`,
|
.late("[0 .01]*4").late("[0 .01]*2").size(4)`,
|
||||||
`// "broken cut 1" @by froos
|
`// "broken cut 1" @by froos
|
||||||
|
|
||||||
await samples('github:tidalcycles/Dirt-Samples/master')
|
samples('github:tidalcycles/dirt-samples')
|
||||||
samples({
|
samples({
|
||||||
'slap': 'https://cdn.freesound.org/previews/495/495416_10350281-lq.mp3',
|
'slap': 'https://cdn.freesound.org/previews/495/495416_10350281-lq.mp3',
|
||||||
'whirl': 'https://cdn.freesound.org/previews/495/495313_10350281-lq.mp3',
|
'whirl': 'https://cdn.freesound.org/previews/495/495313_10350281-lq.mp3',
|
||||||
|
|||||||
@ -51,7 +51,7 @@ Alternatively, you can get a taste of what Strudel can do by clicking play on th
|
|||||||
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
|
||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
stack(
|
stack(
|
||||||
s("bd,[~ <sd!3 sd(3,4,2)>],hh*8") // drums
|
s("bd,[~ <sd!3 sd(3,4,2)>],hh*8") // drums
|
||||||
.speed(perlin.range(.7,.9)) // random sample speed variation
|
.speed(perlin.range(.7,.9)) // random sample speed variation
|
||||||
|
|||||||
@ -143,7 +143,7 @@ Because GitHub is a popular place for uploading open source samples, it has its
|
|||||||
bd: 'bd/BT0AADA.wav',
|
bd: 'bd/BT0AADA.wav',
|
||||||
sd: 'sd/rytm-01-classic.wav',
|
sd: 'sd/rytm-01-classic.wav',
|
||||||
hh: 'hh27/000_hh27closedhh.wav',
|
hh: 'hh27/000_hh27closedhh.wav',
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
s("bd sd bd sd,hh*16")`}
|
s("bd sd bd sd,hh*16")`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ It is also possible, to declare multiple files for one sound, using the array no
|
|||||||
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
s("bd:0 bd:1,~ <sd:0 sd:1> ~ sd:0,[hh:0 hh:1]*4")`}
|
s("bd:0 bd:1,~ <sd:0 sd:1> ~ sd:0,[hh:0 hh:1]*4")`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ The sample number can also be set using `n`:
|
|||||||
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
s("bd bd,~ sd ~ sd,hh*8").n("<0 1>")`}
|
s("bd bd,~ sd ~ sd,hh*8").n("<0 1>")`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ For pitched sounds, you can use `note`, just like with synths:
|
|||||||
client:idle
|
client:idle
|
||||||
tune={`samples({
|
tune={`samples({
|
||||||
'gtr': 'gtr/0001_cleanC.wav',
|
'gtr': 'gtr/0001_cleanC.wav',
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').gain(.5)`}
|
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').gain(.5)`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ If we want them to behave more like a synth, we can add `clip(1)`:
|
|||||||
client:idle
|
client:idle
|
||||||
tune={`samples({
|
tune={`samples({
|
||||||
'gtr': 'gtr/0001_cleanC.wav',
|
'gtr': 'gtr/0001_cleanC.wav',
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').clip(1)
|
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').clip(1)
|
||||||
.gain(.5)`}
|
.gain(.5)`}
|
||||||
/>
|
/>
|
||||||
@ -256,7 +256,7 @@ If we have 2 samples with different base pitches, we can make them in tune by sp
|
|||||||
tune={`samples({
|
tune={`samples({
|
||||||
'gtr': 'gtr/0001_cleanC.wav',
|
'gtr': 'gtr/0001_cleanC.wav',
|
||||||
'moog': { 'g3': 'moog/005_Mighty%20Moog%20G3.wav' },
|
'moog': { 'g3': 'moog/005_Mighty%20Moog%20G3.wav' },
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s("gtr,moog").clip(1)
|
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s("gtr,moog").clip(1)
|
||||||
.gain(.5)`}
|
.gain(.5)`}
|
||||||
/>
|
/>
|
||||||
@ -272,7 +272,7 @@ We can also declare different samples for different regions of the keyboard:
|
|||||||
'g2': 'moog/004_Mighty%20Moog%20G2.wav',
|
'g2': 'moog/004_Mighty%20Moog%20G2.wav',
|
||||||
'g3': 'moog/005_Mighty%20Moog%20G3.wav',
|
'g3': 'moog/005_Mighty%20Moog%20G3.wav',
|
||||||
'g4': 'moog/006_Mighty%20Moog%20G4.wav',
|
'g4': 'moog/006_Mighty%20Moog%20G4.wav',
|
||||||
}}, 'github:tidalcycles/Dirt-Samples/master/');
|
}}, 'github:tidalcycles/dirt-samples');
|
||||||
note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
|
note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
|
||||||
.s('moog').clip(1)
|
.s('moog').clip(1)
|
||||||
.gain(.5).cpm(60)`}
|
.gain(.5).cpm(60)`}
|
||||||
@ -287,7 +287,7 @@ With it, you can enter any sample name(s) to query from [freesound.org](https://
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:idle
|
client:idle
|
||||||
tune={`await samples('shabda:bass:4,hihat:4,rimshot:2')
|
tune={`samples('shabda:bass:4,hihat:4,rimshot:2')
|
||||||
stack(
|
stack(
|
||||||
n("0 1 2 3 0 1 2 3").s('bass'),
|
n("0 1 2 3 0 1 2 3").s('bass'),
|
||||||
n("0 1*2 2 3*2").s('hihat'),
|
n("0 1*2 2 3*2").s('hihat'),
|
||||||
@ -300,8 +300,8 @@ Note that the language code and the gender parameters are optional and default t
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:idle
|
client:idle
|
||||||
tune={`await samples('shabda/speech:the_drum,forever')
|
tune={`samples('shabda/speech:the_drum,forever')
|
||||||
await samples('shabda/speech/fr-FR/m:magnifique')
|
samples('shabda/speech/fr-FR/m:magnifique')
|
||||||
stack(
|
stack(
|
||||||
s("the_drum*2").chop(16).speed(rand.range(0.85,1.1)),
|
s("the_drum*2").chop(16).speed(rand.range(0.85,1.1)),
|
||||||
s("forever magnifique").slow(4).late(0.125)
|
s("forever magnifique").slow(4).late(0.125)
|
||||||
|
|||||||
@ -60,7 +60,7 @@ A sample can be looped and chopped like this:
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
tune={`samples('github:yaxu/clean-breaks')
|
||||||
s("amen/4").fit().chop(32)`}
|
s("amen/4").fit().chop(32)`}
|
||||||
punchcard
|
punchcard
|
||||||
/>
|
/>
|
||||||
@ -71,7 +71,7 @@ Let's add randmized doubling + reversing:
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
tune={`samples('github:yaxu/clean-breaks')
|
||||||
s("amen/4").fit().chop(16).cut(1)
|
s("amen/4").fit().chop(16).cut(1)
|
||||||
.sometimesBy(.5, ply("2"))
|
.sometimesBy(.5, ply("2"))
|
||||||
.sometimesBy(.25, mul(speed("-1")))`}
|
.sometimesBy(.25, mul(speed("-1")))`}
|
||||||
@ -82,7 +82,7 @@ If we want to specify the order of samples, we can replace `chop` with `slice`:
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
tune={`samples('github:yaxu/clean-breaks')
|
||||||
s("amen/4").fit()
|
s("amen/4").fit()
|
||||||
.slice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
|
.slice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
|
||||||
.cut(1).rarely(ply("2"))`}
|
.cut(1).rarely(ply("2"))`}
|
||||||
@ -93,7 +93,7 @@ If we use `splice` instead of `slice`, the speed adjusts to the duration of the
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:yaxu/clean-breaks/main')
|
tune={`samples('github:yaxu/clean-breaks')
|
||||||
s("amen")
|
s("amen")
|
||||||
.splice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
|
.splice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
|
||||||
.cut(1).rarely(ply("2"))`}
|
.cut(1).rarely(ply("2"))`}
|
||||||
@ -213,7 +213,7 @@ Using `run` with `n`, we can rush through a sample bank:
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('bubo:fox')
|
tune={`samples('bubo:fox')
|
||||||
n(run(8)).s("ftabla")`}
|
n(run(8)).s("ftabla")`}
|
||||||
punchcard
|
punchcard
|
||||||
/>
|
/>
|
||||||
@ -224,7 +224,7 @@ In this case, I hear the beginning at the third sample, which can be accounted f
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('bubo:fox')
|
tune={`samples('bubo:fox')
|
||||||
n(run(8)).s("ftabla").early(2/8)`}
|
n(run(8)).s("ftabla").early(2/8)`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ Let's add some randomness:
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('bubo:fox')
|
tune={`samples('bubo:fox')
|
||||||
n(run(8)).s("ftabla").early(2/8)
|
n(run(8)).s("ftabla").early(2/8)
|
||||||
.sometimes(mul(speed("1.5")))`}
|
.sometimes(mul(speed("1.5")))`}
|
||||||
/>
|
/>
|
||||||
@ -299,7 +299,7 @@ To simplify loading wavetables, any sample that starts with `wt_` will be looped
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:bubobubobubobubo/dough-waveforms/main')
|
tune={`samples('github:bubobubobubobubo/dough-waveforms')
|
||||||
note("c eb g bb").s("wt_dbass").clip(2)`}
|
note("c eb g bb").s("wt_dbass").clip(2)`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -307,7 +307,7 @@ Running through different wavetables can also give interesting variations:
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:bubobubobubobubo/dough-waveforms/main')
|
tune={`samples('github:bubobubobubobubo/dough-waveforms')
|
||||||
note("c2*8").s("wt_dbass").n(run(8))`}
|
note("c2*8").s("wt_dbass").n(run(8))`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -315,7 +315,7 @@ note("c2*8").s("wt_dbass").n(run(8))`}
|
|||||||
|
|
||||||
<MiniRepl
|
<MiniRepl
|
||||||
client:visible
|
client:visible
|
||||||
tune={`await samples('github:bubobubobubobubo/dough-waveforms/main')
|
tune={`samples('github:bubobubobubobubo/dough-waveforms')
|
||||||
note("c2*8").s("wt_dbass").n(run(8))
|
note("c2*8").s("wt_dbass").n(run(8))
|
||||||
.lpf(perlin.range(200,2000).slow(8))
|
.lpf(perlin.range(200,2000).slow(8))
|
||||||
.lpenv(-3).lpa(.1).room(.5)`}
|
.lpenv(-3).lpa(.1).room(.5)`}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { MiniRepl } from '../../docs/MiniRepl';
|
|||||||
Note:
|
Note:
|
||||||
|
|
||||||
- this has been (partly) translated from https://tidalcycles.org/docs/patternlib/howtos/buildrhythms
|
- this has been (partly) translated from https://tidalcycles.org/docs/patternlib/howtos/buildrhythms
|
||||||
- this only sounds good with `samples('github:tidalcycles/Dirt-Samples/master')` in prebake
|
- this only sounds good with `samples('github:tidalcycles/dirt-samples')` in prebake
|
||||||
|
|
||||||
# Build Rhythms
|
# Build Rhythms
|
||||||
|
|
||||||
|
|||||||
@ -139,7 +139,7 @@ The content of a sequence will be squished into what's called a cycle.
|
|||||||
|
|
||||||
cpm = cycles per minute
|
cpm = cycles per minute
|
||||||
|
|
||||||
By default, the tempo is 60 cycles per minute = 1 cycle per second.
|
By default, the tempo is 30 cycles per minute = 1 half cycle per second.
|
||||||
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@ -64,3 +64,8 @@
|
|||||||
#code .cm-focused {
|
#code .cm-focused {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#code .cm-matchingBracket {
|
||||||
|
text-decoration: underline 0.18rem;
|
||||||
|
text-underline-offset: 0.22rem;
|
||||||
|
}
|
||||||
|
|||||||
@ -7,7 +7,13 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
import { code2hash, getDrawContext, logger, silence } from '@strudel/core';
|
import { code2hash, getDrawContext, logger, silence } from '@strudel/core';
|
||||||
import cx from '@src/cx.mjs';
|
import cx from '@src/cx.mjs';
|
||||||
import { transpiler } from '@strudel/transpiler';
|
import { transpiler } from '@strudel/transpiler';
|
||||||
import { getAudioContext, initAudioOnFirstClick, webaudioOutput } from '@strudel/webaudio';
|
import {
|
||||||
|
getAudioContext,
|
||||||
|
initAudioOnFirstClick,
|
||||||
|
webaudioOutput,
|
||||||
|
resetGlobalEffects,
|
||||||
|
resetLoadedSounds,
|
||||||
|
} from '@strudel/webaudio';
|
||||||
import { defaultAudioDeviceName } from '../settings.mjs';
|
import { defaultAudioDeviceName } from '../settings.mjs';
|
||||||
import { getAudioDevices, setAudioDevice } from './util.mjs';
|
import { getAudioDevices, setAudioDevice } from './util.mjs';
|
||||||
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
|
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
|
||||||
@ -157,6 +163,7 @@ export function Repl({ embedded = false }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resetEditor = async () => {
|
const resetEditor = async () => {
|
||||||
|
resetGlobalEffects();
|
||||||
clearCanvas();
|
clearCanvas();
|
||||||
resetLoadedSounds();
|
resetLoadedSounds();
|
||||||
editorRef.current.repl.setCps(0.5);
|
editorRef.current.repl.setCps(0.5);
|
||||||
@ -183,6 +190,7 @@ export function Repl({ embedded = false }) {
|
|||||||
setViewingPatternData(patternData);
|
setViewingPatternData(patternData);
|
||||||
clearCanvas();
|
clearCanvas();
|
||||||
resetLoadedSounds();
|
resetLoadedSounds();
|
||||||
|
resetGlobalEffects();
|
||||||
await prebake(); // declare default samples
|
await prebake(); // declare default samples
|
||||||
editorRef.current.setCode(code);
|
editorRef.current.setCode(code);
|
||||||
editorRef.current.repl.evaluate(code);
|
editorRef.current.repl.evaluate(code);
|
||||||
|
|||||||
@ -77,6 +77,7 @@ export function SettingsTab({ started }) {
|
|||||||
const {
|
const {
|
||||||
theme,
|
theme,
|
||||||
keybindings,
|
keybindings,
|
||||||
|
isBracketMatchingEnabled,
|
||||||
isLineNumbersDisplayed,
|
isLineNumbersDisplayed,
|
||||||
isPatternHighlightingEnabled,
|
isPatternHighlightingEnabled,
|
||||||
isActiveLineHighlighted,
|
isActiveLineHighlighted,
|
||||||
@ -137,6 +138,11 @@ export function SettingsTab({ started }) {
|
|||||||
></ButtonGroup>
|
></ButtonGroup>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Code Settings">
|
<FormItem label="Code Settings">
|
||||||
|
<Checkbox
|
||||||
|
label="Enable bracket matching"
|
||||||
|
onChange={(cbEvent) => settingsMap.setKey('isBracketMatchingEnabled', cbEvent.target.checked)}
|
||||||
|
value={isBracketMatchingEnabled}
|
||||||
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Display line numbers"
|
label="Display line numbers"
|
||||||
onChange={(cbEvent) => settingsMap.setKey('isLineNumbersDisplayed', cbEvent.target.checked)}
|
onChange={(cbEvent) => settingsMap.setKey('isLineNumbersDisplayed', cbEvent.target.checked)}
|
||||||
|
|||||||
@ -115,13 +115,12 @@ export async function prebake() {
|
|||||||
'numbers/8.wav',
|
'numbers/8.wav',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'github:tidalcycles/Dirt-Samples/master/',
|
'github:tidalcycles/dirt-samples',
|
||||||
{
|
{
|
||||||
prebake: true,
|
prebake: true,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
// await samples('github:tidalcycles/Dirt-Samples/master');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxPan = noteToMidi('C8');
|
const maxPan = noteToMidi('C8');
|
||||||
|
|||||||
@ -527,7 +527,7 @@ export const meltingsubmarine = `// "Melting submarine"
|
|||||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
// @by Felix Roos
|
// @by Felix Roos
|
||||||
|
|
||||||
await samples('github:tidalcycles/Dirt-Samples/master/')
|
samples('github:tidalcycles/dirt-samples')
|
||||||
stack(
|
stack(
|
||||||
s("bd:5,[~ <sd:1!3 sd:1(3,4,3)>],hh27(3,4,1)") // drums
|
s("bd:5,[~ <sd:1!3 sd:1(3,4,3)>],hh27(3,4,1)") // drums
|
||||||
.speed(perlin.range(.7,.9)) // random sample speed variation
|
.speed(perlin.range(.7,.9)) // random sample speed variation
|
||||||
@ -574,7 +574,7 @@ samples({
|
|||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||||
perc: ['perc/002_perc2.wav'],
|
perc: ['perc/002_perc2.wav'],
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
|
|
||||||
chord("<C^7 Am7 Dm7 G7>*2").dict('lefthand').anchor("G4").voicing()
|
chord("<C^7 Am7 Dm7 G7>*2").dict('lefthand').anchor("G4").voicing()
|
||||||
.stack(n("0@6 [<1 2> <2 0> 1]@2").scale('C5 major'))
|
.stack(n("0@6 [<1 2> <2 0> 1]@2").scale('C5 major'))
|
||||||
@ -608,7 +608,7 @@ samples({
|
|||||||
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
|
||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
}, 'github:tidalcycles/dirt-samples');
|
||||||
|
|
||||||
note("<8(3,8) <7 7*2> [4 5@3] 8>".sub(1) // sub 1 -> 1-indexed
|
note("<8(3,8) <7 7*2> [4 5@3] 8>".sub(1) // sub 1 -> 1-indexed
|
||||||
.layer(
|
.layer(
|
||||||
@ -797,7 +797,7 @@ export const amensister = `// "Amensister"
|
|||||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
// @by Felix Roos
|
// @by Felix Roos
|
||||||
|
|
||||||
await samples('github:tidalcycles/Dirt-Samples/master')
|
samples('github:tidalcycles/dirt-samples')
|
||||||
|
|
||||||
stack(
|
stack(
|
||||||
// amen
|
// amen
|
||||||
@ -906,7 +906,7 @@ export const arpoon = `// "Arpoon"
|
|||||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
// @by Felix Roos
|
// @by Felix Roos
|
||||||
|
|
||||||
await samples('github:tidalcycles/Dirt-Samples/master')
|
samples('github:tidalcycles/dirt-samples')
|
||||||
|
|
||||||
n("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).clip(2)
|
n("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).clip(2)
|
||||||
.offset("<<1 2> 2 1 1>")
|
.offset("<<1 2> 2 1 1>")
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { controls, evalScope, hash2code, logger } from '@strudel/core';
|
import { evalScope, hash2code, logger } from '@strudel/core';
|
||||||
import { settingPatterns, defaultAudioDeviceName } from '../settings.mjs';
|
import { settingPatterns, defaultAudioDeviceName } from '../settings.mjs';
|
||||||
import { getAudioContext, initializeAudioOutput, setDefaultAudioContext } from '@strudel/webaudio';
|
import { getAudioContext, initializeAudioOutput, setDefaultAudioContext } from '@strudel/webaudio';
|
||||||
|
|
||||||
@ -92,11 +92,7 @@ export function loadModules() {
|
|||||||
modules = modules.concat([import('@strudel/midi'), import('@strudel/osc')]);
|
modules = modules.concat([import('@strudel/midi'), import('@strudel/osc')]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return evalScope(
|
return evalScope(settingPatterns, ...modules);
|
||||||
controls, // sadly, this cannot be exported from core direclty
|
|
||||||
settingPatterns,
|
|
||||||
...modules,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastShared;
|
let lastShared;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export const defaultAudioDeviceName = 'System Standard';
|
|||||||
export const defaultSettings = {
|
export const defaultSettings = {
|
||||||
activeFooter: 'intro',
|
activeFooter: 'intro',
|
||||||
keybindings: 'codemirror',
|
keybindings: 'codemirror',
|
||||||
|
isBracketMatchingEnabled: true,
|
||||||
isLineNumbersDisplayed: true,
|
isLineNumbersDisplayed: true,
|
||||||
isActiveLineHighlighted: true,
|
isActiveLineHighlighted: true,
|
||||||
isAutoCompletionEnabled: false,
|
isAutoCompletionEnabled: false,
|
||||||
@ -40,6 +41,7 @@ export function useSettings() {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isZen: [true, 'true'].includes(state.isZen) ? true : false,
|
isZen: [true, 'true'].includes(state.isZen) ? true : false,
|
||||||
|
isBracketMatchingEnabled: [true, 'true'].includes(state.isBracketMatchingEnabled) ? true : false,
|
||||||
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
|
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
|
||||||
isActiveLineHighlighted: [true, 'true'].includes(state.isActiveLineHighlighted) ? true : false,
|
isActiveLineHighlighted: [true, 'true'].includes(state.isActiveLineHighlighted) ? true : false,
|
||||||
isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
|
isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user