mirror of
https://codeberg.org/uzu/strudel
synced 2026-08-14 17:27:14 -04:00
Merge remote-tracking branch 'origin/main' into general-purpose-scheduler
This commit is contained in:
+2
-2
@@ -4,7 +4,6 @@ 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/>.
|
||||
*/
|
||||
|
||||
import controls from '@strudel.cycles/core/controls.mjs';
|
||||
import { evalScope, evaluate } from '@strudel.cycles/eval';
|
||||
import { CodeMirror, cx, flash, useHighlighting, useRepl, useWebMidi } from '@strudel.cycles/react';
|
||||
import { cleanupDraw, cleanupUi, Tone } from '@strudel.cycles/tone';
|
||||
@@ -15,6 +14,7 @@ import * as tunes from './tunes.mjs';
|
||||
import { prebake } from './prebake.mjs';
|
||||
import * as WebDirt from 'WebDirt';
|
||||
import { resetLoadedSamples, getAudioContext } from '@strudel.cycles/webaudio';
|
||||
import { controls } from '@strudel.cycles/core';
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
@@ -26,7 +26,7 @@ const supabase = createClient(
|
||||
|
||||
evalScope(
|
||||
Tone,
|
||||
controls,
|
||||
controls, // sadly, this cannot be exported from core direclty
|
||||
{ WebDirt },
|
||||
import('@strudel.cycles/core'),
|
||||
import('@strudel.cycles/tone'),
|
||||
|
||||
+8
-41
@@ -2,49 +2,16 @@ import { Pattern, toMidi } from '@strudel.cycles/core';
|
||||
import { samples } from '@strudel.cycles/webaudio';
|
||||
|
||||
export async function prebake({ isMock = false, baseDir = '.' } = {}) {
|
||||
samples(
|
||||
{
|
||||
piano: {
|
||||
A0: 'A0v8.mp3',
|
||||
C1: 'C1v8.mp3',
|
||||
Ds1: 'Ds1v8.mp3',
|
||||
Fs1: 'Fs1v8.mp3',
|
||||
A1: 'A1v8.mp3',
|
||||
C2: 'C2v8.mp3',
|
||||
Ds2: 'Ds2v8.mp3',
|
||||
Fs2: 'Fs2v8.mp3',
|
||||
A2: 'A2v8.mp3',
|
||||
C3: 'C3v8.mp3',
|
||||
Ds3: 'Ds3v8.mp3',
|
||||
Fs3: 'Fs3v8.mp3',
|
||||
A3: 'A3v8.mp3',
|
||||
C4: 'C4v8.mp3',
|
||||
Ds4: 'Ds4v8.mp3',
|
||||
Fs4: 'Fs4v8.mp3',
|
||||
A4: 'A4v8.mp3',
|
||||
C5: 'C5v8.mp3',
|
||||
Ds4: 'Ds4v8.mp3',
|
||||
Fs5: 'Fs5v8.mp3',
|
||||
A5: 'A5v8.mp3',
|
||||
C6: 'C6v8.mp3',
|
||||
Ds6: 'Ds6v8.mp3',
|
||||
Fs6: 'Fs6v8.mp3',
|
||||
A6: 'A6v8.mp3',
|
||||
C7: 'C7v8.mp3',
|
||||
Ds7: 'Ds7v8.mp3',
|
||||
Fs7: 'Fs7v8.mp3',
|
||||
A7: 'A7v8.mp3',
|
||||
C8: 'C8v8.mp3',
|
||||
},
|
||||
},
|
||||
if (!isMock) {
|
||||
// https://archive.org/details/SalamanderGrandPianoV3
|
||||
// License: CC-by http://creativecommons.org/licenses/by/3.0/ Author: Alexander Holm
|
||||
`${baseDir}/piano/`,
|
||||
);
|
||||
if (!isMock) {
|
||||
await fetch('EmuSP12.json')
|
||||
.then((res) => res.json())
|
||||
.then((json) => samples(json, `${baseDir}/EmuSP12/`));
|
||||
samples('piano.json', `${baseDir}/piano/`);
|
||||
// https://github.com/sgossner/VCSL/
|
||||
// https://api.github.com/repositories/126427031/contents/
|
||||
// LICENSE: CC0 general-purpose
|
||||
samples('vcsl.json', 'github:sgossner/VCSL/master/');
|
||||
samples('tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/');
|
||||
samples('EmuSP12.json', `${baseDir}/EmuSP12/`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+34
-1
@@ -65,6 +65,7 @@ const toneHelpersMocked = {
|
||||
Chorus: MockedNode,
|
||||
Freeverb: MockedNode,
|
||||
Gain: MockedNode,
|
||||
Reverb: MockedNode,
|
||||
vol: mockNode,
|
||||
out: id,
|
||||
osc: id,
|
||||
@@ -83,7 +84,9 @@ const toneHelpersMocked = {
|
||||
highpass: mockNode,
|
||||
};
|
||||
|
||||
// tone mock
|
||||
strudel.Pattern.prototype.osc = function () {
|
||||
return this;
|
||||
};
|
||||
strudel.Pattern.prototype.tone = function () {
|
||||
return this;
|
||||
};
|
||||
@@ -114,17 +117,40 @@ strudel.Pattern.prototype.adsr = function () {
|
||||
strudel.Pattern.prototype.out = function () {
|
||||
return this;
|
||||
};
|
||||
strudel.Pattern.prototype.soundfont = function () {
|
||||
return this;
|
||||
};
|
||||
// tune mock
|
||||
strudel.Pattern.prototype.tune = function () {
|
||||
return this;
|
||||
};
|
||||
|
||||
strudel.Pattern.prototype.midi = function () {
|
||||
return this;
|
||||
};
|
||||
|
||||
const uiHelpersMocked = {
|
||||
backgroundImage: id,
|
||||
};
|
||||
|
||||
prebake({ isMock: true });
|
||||
|
||||
const canvasCtx = {
|
||||
clearRect: () => {},
|
||||
fillText: () => {},
|
||||
fillRect: () => {},
|
||||
canvas: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
};
|
||||
const audioCtx = {
|
||||
currentTime: 1,
|
||||
};
|
||||
const getDrawContext = () => canvasCtx;
|
||||
const getAudioContext = () => audioCtx;
|
||||
const loadSoundfont = () => {};
|
||||
|
||||
// TODO: refactor to evalScope
|
||||
evalScope(
|
||||
// Tone,
|
||||
@@ -144,6 +170,10 @@ evalScope(
|
||||
// gist,
|
||||
// euclid,
|
||||
mini,
|
||||
getDrawContext,
|
||||
getAudioContext,
|
||||
loadSoundfont,
|
||||
Clock: {}, // whatever
|
||||
// Tone,
|
||||
},
|
||||
);
|
||||
@@ -195,3 +225,6 @@ export const testCycles = {
|
||||
hyperpop: 10,
|
||||
festivalOfFingers3: 16,
|
||||
};
|
||||
|
||||
// fixed: https://strudel.tidalcycles.org/?DBp75NUfSxIn (missing .note())
|
||||
// bug: https://strudel.tidalcycles.org/?xHaKTd1kTpCn + https://strudel.tidalcycles.org/?o5LLePbx8kiQ
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
import { createClient } from '@supabase/supabase-js';
|
||||
|
||||
const supabase = createClient(
|
||||
'https://pidxdsxphlhzjnzmifth.supabase.co',
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM',
|
||||
);
|
||||
|
||||
const { data } = await supabase.from('code');
|
||||
|
||||
console.log(JSON.stringify(data));
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,17 @@
|
||||
import { queryCode } from '../runtime.mjs';
|
||||
import { describe, it } from 'vitest';
|
||||
import data from './dbdump.json';
|
||||
|
||||
describe('renders shared tunes', async () => {
|
||||
data.forEach(({ id, code, hash }) => {
|
||||
const url = `https://strudel.tidalcycles.org/?${hash}`;
|
||||
it(`shared tune ${id} ${url}`, async ({ expect }) => {
|
||||
if (code.includes('import(')) {
|
||||
console.log('skip', url);
|
||||
return;
|
||||
}
|
||||
const haps = await queryCode(code, 1);
|
||||
expect(haps).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
+133
-9
@@ -4,7 +4,7 @@ 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/>.
|
||||
*/
|
||||
|
||||
export const tetrisMini = `\`[[e5 [b4 c5] d5 [c5 b4]]
|
||||
export const tetrisMini = `note(\`[[e5 [b4 c5] d5 [c5 b4]]
|
||||
[a4 [a4 c5] e5 [d5 c5]]
|
||||
[b4 [~ c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
@@ -19,7 +19,7 @@ export const tetrisMini = `\`[[e5 [b4 c5] d5 [c5 b4]]
|
||||
[[d2 d3]*4]
|
||||
[[c2 c3]*4]
|
||||
[[b1 b2]*2 [e2 e3]*2]
|
||||
[[a1 a2]*4]\`.slow(16)
|
||||
[[a1 a2]*4]\`).slow(16)
|
||||
`;
|
||||
|
||||
export const swimming = `stack(
|
||||
@@ -80,7 +80,7 @@ export const swimming = `stack(
|
||||
"[F2 A2 Bb2 B2]",
|
||||
"[G2 C2 F2 F2]"
|
||||
)
|
||||
).slow(51);
|
||||
).note().slow(51);
|
||||
`;
|
||||
|
||||
export const giantSteps = `stack(
|
||||
@@ -105,7 +105,7 @@ export const giantSteps = `stack(
|
||||
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
|
||||
"[B2 F#2] [F2 Bb2] [Eb2 Bb3] [C#2 F#2]"
|
||||
)
|
||||
).slow(20)`;
|
||||
).slow(20).note()`;
|
||||
|
||||
export const giantStepsReggae = `stack(
|
||||
// melody
|
||||
@@ -132,7 +132,7 @@ export const giantStepsReggae = `stack(
|
||||
"[B2 F#2] [F2 Bb2] [Eb2 Bb2] [C#2 F#2]"
|
||||
)
|
||||
.struct("x ~".fast(4*8))
|
||||
).slow(25)`;
|
||||
).slow(25).note()`;
|
||||
|
||||
export const zeldasRescue = `stack(
|
||||
// melody
|
||||
@@ -511,7 +511,7 @@ stack(
|
||||
f3!2 e3!2 ab3!2 ~!2
|
||||
>\`
|
||||
.legato(.5)
|
||||
).fast(2) // .note().piano()`;
|
||||
).fast(2).note()`;
|
||||
|
||||
/*
|
||||
// TODO: does not work on linux (at least for me..)
|
||||
@@ -554,7 +554,6 @@ stack(
|
||||
"<D2 A2 G2 F2>".euclidLegato(6,8,1).note().s('bass').clip(1).gain(.8)
|
||||
)
|
||||
.slow(6)
|
||||
|
||||
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
|
||||
`;
|
||||
|
||||
@@ -701,7 +700,6 @@ stack(
|
||||
.echoWith(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes
|
||||
//.hush()
|
||||
)
|
||||
|
||||
.slow(3/2)`;
|
||||
|
||||
export const swimmingWithSoundfonts = `stack(
|
||||
@@ -814,7 +812,6 @@ x=>x.add(7).color('steelblue')
|
||||
//.hcutoff(400)
|
||||
.clip(1)
|
||||
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
|
||||
|
||||
.pianoroll({vertical:1})`;
|
||||
|
||||
export const bossaRandom = `const chords = "<Am7 Am7 Dm7 E7>"
|
||||
@@ -857,3 +854,130 @@ export const orbit = `stack(
|
||||
.delayfeedback(.7)
|
||||
.orbit(2)
|
||||
).sometimes(x=>x.speed("-1"))`;
|
||||
|
||||
export const belldub = `samples({ bell: {b4:'https://cdn.freesound.org/previews/339/339809_5121236-lq.mp3'}})
|
||||
// "Hand Bells, B, Single.wav" by InspectorJ (www.jshaw.co.uk) of Freesound.org
|
||||
stack(
|
||||
// bass
|
||||
note("[0 ~] [2 [0 2]] [4 4*2] [[4 ~] [2 ~] 0@2]".scale('g1 dorian').superimpose(x=>x.add(.02)))
|
||||
.s('sawtooth').cutoff(200).resonance(20).gain(.15).shape(.6).release(.05),
|
||||
// perc
|
||||
s("[~ hh]*4").room("0 0.5".fast(2)).end(perlin.range(0.02,1)),
|
||||
s("mt lt ht").struct("x(3,8)").fast(2).gain(.5).room(.5).sometimes(x=>x.speed(".5")),
|
||||
s("misc:2").speed(1).delay(.5).delaytime(1/3).gain(.4),
|
||||
// chords
|
||||
note("[~ Gm7] ~ [~ Dm7] ~".voicings().superimpose(x=>x.add(.1)))
|
||||
.s('sawtooth').gain(.5)
|
||||
.cutoff(perlin.range(400,3000).slow(8))
|
||||
.decay(perlin.range(0.05,.2)).sustain(0)
|
||||
.delay(.9).room(1),
|
||||
// blips
|
||||
note(
|
||||
"0 5 4 2".iter(4)
|
||||
.off(1/3, add(7))
|
||||
.scale('g4 dorian')
|
||||
).s('square').cutoff(2000).decay(.03).sustain(0)
|
||||
.degradeBy(.2)
|
||||
.orbit(2).delay(.2).delaytime(".33 | .6 | .166 | .25")
|
||||
.room(1).gain(.5).mask("<0 1>/8"),
|
||||
// bell
|
||||
note(rand.range(0,12).struct("x(5,8)").scale('g2 minor pentatonic')).s('bell').begin(.05)
|
||||
.delay(.2).degradeBy(.4).gain(.4)
|
||||
.mask("<1 0>/8")
|
||||
).slow(5)`;
|
||||
|
||||
export const dinofunk = `samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3',
|
||||
dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}})
|
||||
|
||||
stack(
|
||||
s('bass').loopAt(8,1).clip(1),
|
||||
s("bd*2, ~ sd,hh*4"),
|
||||
note("Abm7".voicings(['c3','a4']).struct("x(3,8,1)".slow(2))),
|
||||
"0 1 2 3".scale('ab4 minor pentatonic')
|
||||
.superimpose(x=>x.add(.1))
|
||||
.sometimes(x=>x.add(12))
|
||||
.note().s('sawtooth')
|
||||
.cutoff(sine.range(400,2000).slow(16)).gain(.8)
|
||||
.decay(perlin.range(.05,.2)).sustain(0)
|
||||
.delay(sine.range(0,.5).slow(32))
|
||||
.degradeBy(.4).room(1),
|
||||
note("<b4 eb4>").s('dino').delay(.8).slow(8).room(.5)
|
||||
)`;
|
||||
|
||||
export const sampleDemo = `stack(
|
||||
// percussion
|
||||
s("[woodblock:1 woodblock:2*2] snare_rim:0,gong/8,brakedrum:1(3,8),~@3 cowbell:3")
|
||||
.sometimes(x=>x.speed(2)),
|
||||
// melody
|
||||
note("<0 4 1 3 2>".off(".25 | .125",add(2)).scale('D3 hirajoshi'))
|
||||
.s("clavisynth").gain(.2).delay(.25).jux(rev)
|
||||
.degradeBy(sine.range(0,.5).slow(32)),
|
||||
// bass
|
||||
note("<0@3 <2(3,8) 3(3,8)>>".scale('D1 hirajoshi'))
|
||||
.s('psaltery_pluck').gain(.6).clip(1)
|
||||
.release(.1).room(.5)
|
||||
)`;
|
||||
|
||||
export const holyflute = `"c3 eb3(3,8) c4/2 g3*2"
|
||||
.superimpose(
|
||||
x=>x.slow(2).add(12),
|
||||
x=>x.slow(4).sub(5)
|
||||
).add("<0 1>/16")
|
||||
.note().s('ocarina_vib').clip(1)
|
||||
.release(.1).room(1).gain(.2)
|
||||
.color("salmon | orange | darkseagreen")
|
||||
.pianoroll({fold:0,autorange:0,vertical:0,cycles:12,smear:0,minMidi:40})
|
||||
`;
|
||||
|
||||
export const flatrave = `stack(
|
||||
s("bd*2,~ [cp,sd]").bank('RolandTR909'),
|
||||
|
||||
s("hh:1*4").sometimes(fast("2"))
|
||||
.rarely(x=>x.speed(".5").delay(.5))
|
||||
.end(perlin.range(0.02,.05).slow(8))
|
||||
.bank('RolandTR909').room(.5)
|
||||
.gain("0.4,0.4(5,8)"),
|
||||
|
||||
note("<0 2 5 3>".scale('G1 minor')).struct("x(5,8)")
|
||||
.s('sawtooth').decay(.1).sustain(0),
|
||||
|
||||
note("<G4 A4 Bb4 A4>,Bb3,D3").struct("~ x*2").s('square').clip(1)
|
||||
.cutoff(sine.range(500,4000).slow(16)).resonance(10)
|
||||
.decay(sine.slow(15).range(.05,.2)).sustain(0)
|
||||
.room(.5).gain(.3).delay(.2).mask("<0 1@3>/8"),
|
||||
|
||||
"0 5 3 2".sometimes(slow(2)).off(1/8,add(5)).scale('G4 minor').note()
|
||||
.decay(.05).sustain(0).delay(.2).degradeBy(.5).mask("<0 1>/16")
|
||||
)`;
|
||||
|
||||
export const amensister = `samples('github:tidalcycles/Dirt-Samples/master')
|
||||
|
||||
stack(
|
||||
// amen
|
||||
n("0 1 2 3 4 5 6 7")
|
||||
.sometimes(x=>x.ply(2))
|
||||
.rarely(x=>x.speed("2 | -2"))
|
||||
.sometimesBy(.4, x=>x.delay(".5"))
|
||||
.s("amencutup")
|
||||
.slow(2)
|
||||
.room(.5)
|
||||
,
|
||||
// bass
|
||||
sine.add(saw.slow(4)).range(0,7).segment(8)
|
||||
.superimpose(x=>x.add(.1))
|
||||
.scale('G0 minor').note()
|
||||
.s("sawtooth").decay(.1).sustain(0)
|
||||
.gain(.4).cutoff(perlin.range(300,3000).slow(8)).resonance(10)
|
||||
.degradeBy("0 0.1 .5 .1")
|
||||
.rarely(add(note("12")))
|
||||
,
|
||||
// chord
|
||||
note("Bb3,D4".superimpose(x=>x.add(.2)))
|
||||
.s('sawtooth').cutoff(1000).struct("<~@3 [~ x]>")
|
||||
.decay(.05).sustain(.0).delay(.8).delaytime(.125).room(.8)
|
||||
,
|
||||
// alien
|
||||
s("breath").room(1).shape(.6).chop(16).rev().mask("<x ~@7>")
|
||||
,
|
||||
n("0 1").s("east").delay(.5).degradeBy(.8).speed(rand.range(.5,1.5))
|
||||
).reset("<x@7 x(5,8)>")`;
|
||||
|
||||
Reference in New Issue
Block a user