This commit is contained in:
Felix Roos 2022-02-27 12:08:23 +01:00
parent ef3ab6161f
commit 9442b5c66b
9 changed files with 107 additions and 90 deletions

4
docs/dist/App.js vendored
View file

@ -14,7 +14,7 @@ try {
} catch (err) { } catch (err) {
console.warn("failed to decode", err); console.warn("failed to decode", err);
} }
const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destination); const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.getDestination());
defaultSynth.set({ defaultSynth.set({
oscillator: {type: "triangle"}, oscillator: {type: "triangle"},
envelope: { envelope: {
@ -32,7 +32,7 @@ function App() {
const {setCode, setPattern, error, code, cycle, dirty, log, togglePlay, activateCode, pattern, pushLog} = useRepl({ const {setCode, setPattern, error, code, cycle, dirty, log, togglePlay, activateCode, pattern, pushLog} = useRepl({
tune: decoded || randomTune, tune: decoded || randomTune,
defaultSynth, defaultSynth,
onEvent: useCallback(markEvent(editor), [editor]) onDraw: useCallback(markEvent(editor), [editor])
}); });
const logBox = useRef(); const logBox = useRef();
useLayoutEffect(() => { useLayoutEffect(() => {

View file

@ -19,7 +19,7 @@ export default function CodeMirror({value, onChange, options, editorDidMount}) {
editorDidMount editorDidMount
}); });
} }
export const markEvent = (editor) => (event) => { export const markEvent = (editor) => (time, event) => {
const locs = event.value.locations; const locs = event.value.locations;
if (!locs || !editor) { if (!locs || !editor) {
return; return;

10
docs/dist/tone.js vendored
View file

@ -1,7 +1,6 @@
import {Pattern as _Pattern} from "../_snowpack/link/strudel.js"; import {Pattern as _Pattern} from "../_snowpack/link/strudel.js";
import { import {
AutoFilter, AutoFilter,
Destination,
Filter, Filter,
Gain, Gain,
isNote, isNote,
@ -15,7 +14,8 @@ import {
FMSynth, FMSynth,
NoiseSynth, NoiseSynth,
PluckSynth, PluckSynth,
Sampler Sampler,
getDestination
} from "../_snowpack/pkg/tone.js"; } from "../_snowpack/pkg/tone.js";
const Pattern = _Pattern; const Pattern = _Pattern;
Pattern.prototype.tone = function(instrument) { Pattern.prototype.tone = function(instrument) {
@ -50,14 +50,14 @@ export const lowpass = (v) => new Filter(v, "lowpass");
export const highpass = (v) => new Filter(v, "highpass"); export const highpass = (v) => new Filter(v, "highpass");
export const adsr = (a, d = 0.1, s = 0.4, r = 0.01) => ({envelope: {attack: a, decay: d, sustain: s, release: r}}); export const adsr = (a, d = 0.1, s = 0.4, r = 0.01) => ({envelope: {attack: a, decay: d, sustain: s, release: r}});
export const osc = (type) => ({oscillator: {type}}); export const osc = (type) => ({oscillator: {type}});
export const out = Destination; export const out = () => getDestination();
const chainable = function(instr) { const chainable = function(instr) {
const _chain = instr.chain.bind(instr); const _chain = instr.chain.bind(instr);
let chained = []; let chained = [];
instr.chain = (...args) => { instr.chain = (...args) => {
chained = chained.concat(args); chained = chained.concat(args);
instr.disconnect(); instr.disconnect();
return _chain(...chained, Destination); return _chain(...chained, getDestination());
}; };
instr.filter = (freq = 1e3, type = "lowpass") => instr.chain(new Filter(freq, type)); instr.filter = (freq = 1e3, type = "lowpass") => instr.chain(new Filter(freq, type));
instr.gain = (gain2 = 0.9) => instr.chain(new Gain(gain2)); instr.gain = (gain2 = 0.9) => instr.chain(new Gain(gain2));
@ -134,7 +134,7 @@ Pattern.prototype.chain = function(...effectGetters) {
const chain = (value.chain || []).concat(effectGetters); const chain = (value.chain || []).concat(effectGetters);
const getChain = () => { const getChain = () => {
const effects = chain.map((getEffect) => getEffect()); const effects = chain.map((getEffect) => getEffect());
return value.getInstrument().chain(...effects, Destination); return value.getInstrument().chain(...effects, getDestination());
}; };
const onTrigger = getTrigger(getChain, value.value); const onTrigger = getTrigger(getChain, value.value);
return {...value, getChain, onTrigger, chain}; return {...value, getChain, onTrigger, chain};

82
docs/dist/tunes.js vendored
View file

@ -258,20 +258,20 @@ export const zeldasRescue = `stack(
new Gain(0.3), new Gain(0.3),
new Chorus(2, 2.5, 0.5).start(), new Chorus(2, 2.5, 0.5).start(),
new Freeverb(), new Freeverb(),
Destination) getDestination())
)`; )`;
export const technoDrums = `stack( export const technoDrums = `stack(
"c1*2".tone(new Tone.MembraneSynth().toDestination()), "c1*2".tone(new Tone.MembraneSynth().toDestination()),
"~ x".tone(new Tone.NoiseSynth().toDestination()), "~ x".tone(new Tone.NoiseSynth().toDestination()),
"[~ c4]*2".tone(new Tone.MetalSynth().set({envelope:{decay:0.06,sustain:0}}).chain(new Gain(0.5),Destination)) "[~ c4]*2".tone(new Tone.MetalSynth().set({envelope:{decay:0.06,sustain:0}}).chain(new Gain(0.5),getDestination()))
)`; )`;
export const loungerave = `() => { export const loungerave = `() => {
const delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out); const delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out); const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out); const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out); const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out); const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out); const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack( const drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"), "c1*2".tone(kick).mask("<x@7 ~>/8"),
@ -292,12 +292,12 @@ export const loungerave = `() => {
//.early("0.25 0"); //.early("0.25 0");
}`; }`;
export const caverave = `() => { export const caverave = `() => {
const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out); const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out); const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out); const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out); const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out); const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out); const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack( const drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"), "c1*2".tone(kick).mask("<x@7 ~>/8"),
@ -324,16 +324,16 @@ export const caverave = `() => {
}`; }`;
export const callcenterhero = `()=>{ export const callcenterhero = `()=>{
const bpm = 90; const bpm = 90;
const lead = polysynth().set({...osc('sine4'),...adsr(.004)}).chain(vol(0.15),out) const lead = polysynth().set({...osc('sine4'),...adsr(.004)}).chain(vol(0.15),out())
const bass = fmsynth({...osc('sawtooth6'),...adsr(0.05,.6,0.8,0.1)}).chain(vol(0.6), out); const bass = fmsynth({...osc('sawtooth6'),...adsr(0.05,.6,0.8,0.1)}).chain(vol(0.6), out());
const s = scale(slowcat('F3 minor', 'Ab3 major', 'Bb3 dorian', 'C4 phrygian dominant').slow(4)); const s = scale(slowcat('F3 minor', 'Ab3 major', 'Bb3 dorian', 'C4 phrygian dominant').slow(4));
return stack( return stack(
"0 2".struct("<x ~> [x ~]").apply(s).scaleTranspose(stack(0,2)).tone(lead), "0 2".struct("<x ~> [x ~]").apply(s).scaleTranspose(stack(0,2)).tone(lead),
"<6 7 9 7>".struct("[~ [x ~]*2]*2").apply(s).scaleTranspose("[0,2] [2,4]".fast(2).every(4,rev)).tone(lead), "<6 7 9 7>".struct("[~ [x ~]*2]*2").apply(s).scaleTranspose("[0,2] [2,4]".fast(2).every(4,rev)).tone(lead),
"-14".struct("[~ x@0.8]*2".early(0.01)).apply(s).tone(bass), "-14".struct("[~ x@0.8]*2".early(0.01)).apply(s).tone(bass),
"c2*2".tone(membrane().chain(vol(0.6), out)), "c2*2".tone(membrane().chain(vol(0.6), out())),
"~ c2".tone(noise().chain(vol(0.2), out)), "~ c2".tone(noise().chain(vol(0.2), out())),
"c4*4".tone(metal(adsr(0,.05,0)).chain(vol(0.03), out)) "c4*4".tone(metal(adsr(0,.05,0)).chain(vol(0.03), out()))
) )
.slow(120 / bpm) .slow(120 / bpm)
} }
@ -342,20 +342,20 @@ export const primalEnemy = `()=>{
const f = fast("<1 <2 [4 8]>>"); const f = fast("<1 <2 [4 8]>>");
return stack( return stack(
"c3,g3,c4".struct("[x ~]*2").apply(f).transpose("<0 <3 [5 [7 [9 [11 13]]]]>>"), "c3,g3,c4".struct("[x ~]*2").apply(f).transpose("<0 <3 [5 [7 [9 [11 13]]]]>>"),
"c2 [c2 ~]*2".tone(synth(osc('sawtooth8')).chain(vol(0.8),out)), "c2 [c2 ~]*2".tone(synth(osc('sawtooth8')).chain(vol(0.8),out())),
"c1*2".tone(membrane().chain(vol(0.8),out)) "c1*2".tone(membrane().chain(vol(0.8),out()))
).slow(1) ).slow(1)
}`; }`;
export const drums = `stack( export const drums = `stack(
"c1*2".tone(membrane().chain(vol(0.8),out)), "c1*2".tone(membrane().chain(vol(0.8),out())),
"~ c3".tone(noise().chain(vol(0.8),out)), "~ c3".tone(noise().chain(vol(0.8),out())),
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.015)).chain(vol(0.8),out)) "c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.015)).chain(vol(0.8),out()))
) )
`; `;
export const xylophoneCalling = `()=>{ export const xylophoneCalling = `()=>{
const t = x=> x.scaleTranspose("<0 2 4 3>/4").transpose(-2) const t = x=> x.scaleTranspose("<0 2 4 3>/4").transpose(-2)
const s = x => x.scale(slowcat('C3 minor pentatonic','G3 minor pentatonic').slow(4)) const s = x => x.scale(slowcat('C3 minor pentatonic','G3 minor pentatonic').slow(4))
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out); const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out());
const chorus = new Chorus(1,2.5,0.5).start(); const chorus = new Chorus(1,2.5,0.5).start();
return stack( return stack(
// melody // melody
@ -365,28 +365,28 @@ export const xylophoneCalling = `()=>{
.apply(t).tone(polysynth().set({ .apply(t).tone(polysynth().set({
...osc('triangle4'), ...osc('triangle4'),
...adsr(0,.08,0) ...adsr(0,.08,0)
}).chain(vol(0.2).connect(delay),chorus,out)).mask("<~@3 x>/16".early(1/8)), }).chain(vol(0.2).connect(delay),chorus,out())).mask("<~@3 x>/16".early(1/8)),
// pad // pad
"[1,3]/4".scale('G3 minor pentatonic').apply(t).tone(polysynth().set({ "[1,3]/4".scale('G3 minor pentatonic').apply(t).tone(polysynth().set({
...osc('square2'), ...osc('square2'),
...adsr(0.1,.4,0.8) ...adsr(0.1,.4,0.8)
}).chain(vol(0.2),chorus,out)).mask("<~ x>/32"), }).chain(vol(0.2),chorus,out())).mask("<~ x>/32"),
// xylophone // xylophone
"c3,g3,c4".struct("<x*2 x>").fast("<1 <2!3 [4 8]>>").apply(s).scaleTranspose("<0 <1 [2 [3 <4 5>]]>>").apply(t).tone(polysynth().set({ "c3,g3,c4".struct("<x*2 x>").fast("<1 <2!3 [4 8]>>").apply(s).scaleTranspose("<0 <1 [2 [3 <4 5>]]>>").apply(t).tone(polysynth().set({
...osc('sawtooth4'), ...osc('sawtooth4'),
...adsr(0,.1,0) ...adsr(0,.1,0)
}).chain(vol(0.4).connect(delay),out)).mask("<x@3 ~>/16".early(1/8)), }).chain(vol(0.4).connect(delay),out())).mask("<x@3 ~>/16".early(1/8)),
// bass // bass
"c2 [c2 ~]*2".scale('C hirajoshi').apply(t).tone(synth({ "c2 [c2 ~]*2".scale('C hirajoshi').apply(t).tone(synth({
...osc('sawtooth6'), ...osc('sawtooth6'),
...adsr(0,.03,.4,.1) ...adsr(0,.03,.4,.1)
}).chain(vol(0.4),out)), }).chain(vol(0.4),out())),
// kick // kick
"<c1!3 [c1 ~]*2>*2".tone(membrane().chain(vol(0.8),out)), "<c1!3 [c1 ~]*2>*2".tone(membrane().chain(vol(0.8),out())),
// snare // snare
"~ <c3!7 [c3 c3*2]>".tone(noise().chain(vol(0.8),out)), "~ <c3!7 [c3 c3*2]>".tone(noise().chain(vol(0.8),out())),
// hihat // hihat
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)).chain(vol(0.5).connect(delay),out)) "c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)).chain(vol(0.5).connect(delay),out()))
).slow(1) ).slow(1)
}`; }`;
export const sowhatelse = `()=> { export const sowhatelse = `()=> {
@ -399,18 +399,18 @@ export const sowhatelse = `()=> {
kick: .9, kick: .9,
hihat: .35, hihat: .35,
}[key]||0); }[key]||0);
const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out); const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out());
const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out); const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out());
const chorus = new Chorus(1,2.5,0.5).start(); const chorus = new Chorus(1,2.5,0.5).start();
// instruments // instruments
const instr = (instrument) => ({ const instr = (instrument) => ({
organ: polysynth().set({...osc('sawtooth4'), ...adsr(.01,.2,0)}).chain(mix('chords').connect(delay),out), organ: polysynth().set({...osc('sawtooth4'), ...adsr(.01,.2,0)}).chain(mix('chords').connect(delay),out()),
lead: polysynth().set({...osc('triangle4'),...adsr(0.01,.05,0)}).chain(mix('lead').connect(delay2), out), lead: polysynth().set({...osc('triangle4'),...adsr(0.01,.05,0)}).chain(mix('lead').connect(delay2), out()),
bass: polysynth().set({...osc('sawtooth8'),...adsr(.02,.05,.3,.2)}).chain(mix('bass'),lowpass(3000), out), bass: polysynth().set({...osc('sawtooth8'),...adsr(.02,.05,.3,.2)}).chain(mix('bass'),lowpass(3000), out()),
pad: polysynth().set({...osc('square2'),...adsr(0.1,.4,0.8)}).chain(vol(0.15),chorus,out), pad: polysynth().set({...osc('square2'),...adsr(0.1,.4,0.8)}).chain(vol(0.15),chorus,out()),
hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out), hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out()),
snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out), snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out()),
kick: membrane().chain(mix('kick'), out) kick: membrane().chain(mix('kick'), out())
}[instrument]); }[instrument]);
// harmony // harmony
const t = transpose("<0 0 1 0>/8"); const t = transpose("<0 0 1 0>/8");

19
docs/dist/useCycle.js vendored
View file

@ -2,29 +2,32 @@ import {useEffect, useState} from "../_snowpack/pkg/react.js";
import * as Tone from "../_snowpack/pkg/tone.js"; import * as Tone from "../_snowpack/pkg/tone.js";
import {TimeSpan} from "../_snowpack/link/strudel.js"; import {TimeSpan} from "../_snowpack/link/strudel.js";
function useCycle(props) { function useCycle(props) {
const {onEvent, onQuery, onSchedule, ready = true} = props; const {onEvent, onQuery, onSchedule, ready = true, onDraw} = props;
const [started, setStarted] = useState(false); const [started, setStarted] = useState(false);
const cycleDuration = 1; const cycleDuration = 1;
const activeCycle = () => Math.floor(Tone.Transport.seconds / cycleDuration); const activeCycle = () => Math.floor(Tone.getTransport().seconds / cycleDuration);
const query = (cycle = activeCycle()) => { const query = (cycle = activeCycle()) => {
const timespan = new TimeSpan(cycle, cycle + 1); const timespan = new TimeSpan(cycle, cycle + 1);
const events = onQuery?.(timespan) || []; const events = onQuery?.(timespan) || [];
onSchedule?.(events, cycle); onSchedule?.(events, cycle);
const cancelFrom = timespan.begin.valueOf(); const cancelFrom = timespan.begin.valueOf();
Tone.Transport.cancel(cancelFrom); Tone.getTransport().cancel(cancelFrom);
const queryNextTime = (cycle + 1) * cycleDuration - 0.5; const queryNextTime = (cycle + 1) * cycleDuration - 0.5;
const t = Math.max(Tone.Transport.seconds, queryNextTime) + 0.1; const t = Math.max(Tone.getTransport().seconds, queryNextTime) + 0.1;
Tone.Transport.schedule(() => { Tone.getTransport().schedule(() => {
query(cycle + 1); query(cycle + 1);
}, t); }, t);
events?.filter((event) => event.part.begin.valueOf() === event.whole.begin.valueOf()).forEach((event) => { events?.filter((event) => event.part.begin.valueOf() === event.whole.begin.valueOf()).forEach((event) => {
Tone.Transport.schedule((time) => { Tone.getTransport().schedule((time) => {
const toneEvent = { const toneEvent = {
time: event.part.begin.valueOf(), time: event.part.begin.valueOf(),
duration: event.whole.end.sub(event.whole.begin).valueOf(), duration: event.whole.end.sub(event.whole.begin).valueOf(),
value: event.value value: event.value
}; };
onEvent(time, toneEvent); onEvent(time, toneEvent);
Tone.Draw.schedule(() => {
onDraw?.(time, toneEvent);
}, time);
}, event.part.begin.valueOf()); }, event.part.begin.valueOf());
}); });
}; };
@ -34,12 +37,12 @@ function useCycle(props) {
const start = async () => { const start = async () => {
setStarted(true); setStarted(true);
await Tone.start(); await Tone.start();
Tone.Transport.start("+0.1"); Tone.getTransport().start("+0.1");
}; };
const stop = () => { const stop = () => {
console.log("stop"); console.log("stop");
setStarted(false); setStarted(false);
Tone.Transport.pause(); Tone.getTransport().pause();
}; };
const toggle = () => started ? stop() : start(); const toggle = () => started ? stop() : start();
return {start, stop, setStarted, onEvent, started, toggle, query, activeCycle}; return {start, stop, setStarted, onEvent, started, toggle, query, activeCycle};

View file

@ -6,7 +6,7 @@ import usePostMessage from "./usePostMessage.js";
let s4 = () => { let s4 = () => {
return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1); return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
}; };
function useRepl({tune, defaultSynth, autolink = true, onEvent}) { function useRepl({tune, defaultSynth, autolink = true, onEvent, onDraw}) {
const id = useMemo(() => s4(), []); const id = useMemo(() => s4(), []);
const [code, setCode] = useState(tune); const [code, setCode] = useState(tune);
const [activeCode, setActiveCode] = useState(); const [activeCode, setActiveCode] = useState();
@ -44,6 +44,7 @@ function useRepl({tune, defaultSynth, autolink = true, onEvent}) {
} }
}; };
const cycle = useCycle({ const cycle = useCycle({
onDraw,
onEvent: useCallback((time, event) => { onEvent: useCallback((time, event) => {
try { try {
onEvent?.(event); onEvent?.(event);
@ -71,6 +72,7 @@ function useRepl({tune, defaultSynth, autolink = true, onEvent}) {
try { try {
return pattern?.query(span) || []; return pattern?.query(span) || [];
} catch (err) { } catch (err) {
console.warn(err);
err.message = "query error: " + err.message; err.message = "query error: " + err.message;
setError(err); setError(err);
return []; return [];

View file

@ -7330,12 +7330,12 @@ It aims to be `, /*#__PURE__*/ _react1.mdx("a", {
"href": "https://strudel.tidalcycles.org/" "href": "https://strudel.tidalcycles.org/"
}, `Strudel REPL`), `.`), /*#__PURE__*/ _react1.mdx("h2", null, `Show me a Demo`), /*#__PURE__*/ _react1.mdx("p", null, `To get a taste of what Strudel can do, check out this track:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }, `Strudel REPL`), `.`), /*#__PURE__*/ _react1.mdx("h2", null, `Show me a Demo`), /*#__PURE__*/ _react1.mdx("p", null, `To get a taste of what Strudel can do, check out this track:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `() => { tune: `() => {
const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out); const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out); const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out); const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out); const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out); const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out); const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack( const drums = stack(
"c1*2".tone(kick).bypass("<0@7 1>/8"), "c1*2".tone(kick).bypass("<0@7 1>/8"),
@ -7577,12 +7577,12 @@ For sharp notes, the letter "s" is used instead of "#", because JavaScript does
}, `Show Source on Github`)), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }, `Show Source on Github`)), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `stack( tune: `stack(
"[c5 c5 bb4 c5] [~ g4 ~ g4] [c5 f5 e5 c5] ~" "[c5 c5 bb4 c5] [~ g4 ~ g4] [c5 f5 e5 c5] ~"
.tone(synth(adsr(0,.1,0,0)).chain(out)), .tone(synth(adsr(0,.1,0,0)).chain(out())),
"[c2 c3]*8" "[c2 c3]*8"
.tone(synth({ .tone(synth({
...osc('sawtooth'), ...osc('sawtooth'),
...adsr(0,.1,0.4,0) ...adsr(0,.1,0.4,0)
}).chain(lowpass(300), out)) }).chain(lowpass(300), out()))
).slow(4)`, ).slow(4)`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("h3", null, `tone(instrument)`), /*#__PURE__*/ _react1.mdx("p", null, `To change the instrument of a pattern, you can pass any `, /*#__PURE__*/ _react1.mdx("a", { }), /*#__PURE__*/ _react1.mdx("h3", null, `tone(instrument)`), /*#__PURE__*/ _react1.mdx("p", null, `To change the instrument of a pattern, you can pass any `, /*#__PURE__*/ _react1.mdx("a", {
@ -7608,15 +7608,15 @@ const sampler = (options) => new Sampler(options);
const synth = (options) => new Synth(options); const synth = (options) => new Synth(options);
`)), /*#__PURE__*/ _react1.mdx("h3", null, `out`), /*#__PURE__*/ _react1.mdx("p", null, `Shortcut for Tone.Destination. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { `)), /*#__PURE__*/ _react1.mdx("h3", null, `out`), /*#__PURE__*/ _react1.mdx("p", null, `Shortcut for Tone.Destination. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4) tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(membrane().chain(out))`, .tone(membrane().chain(out()))`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("p", null, `This alone is not really useful, so read on..`), /*#__PURE__*/ _react1.mdx("h3", null, `vol(volume)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper that returns a Gain Node with the given volume. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }), /*#__PURE__*/ _react1.mdx("p", null, `This alone is not really useful, so read on..`), /*#__PURE__*/ _react1.mdx("h3", null, `vol(volume)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper that returns a Gain Node with the given volume. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4) tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(noise().chain(vol(0.5), out))`, .tone(noise().chain(vol(0.5), out()))`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("h3", null, `osc(type)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper to set the waveform of a synth, monosynth or polysynth:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }), /*#__PURE__*/ _react1.mdx("h3", null, `osc(type)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper to set the waveform of a synth, monosynth or polysynth:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4) tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(synth(osc('sawtooth4')).chain(out))`, .tone(synth(osc('sawtooth4')).chain(out()))`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("p", null, `The base types are `, /*#__PURE__*/ _react1.mdx("inlineCode", { }), /*#__PURE__*/ _react1.mdx("p", null, `The base types are `, /*#__PURE__*/ _react1.mdx("inlineCode", {
parentName: "p" parentName: "p"
@ -7628,15 +7628,15 @@ const synth = (options) => new Synth(options);
parentName: "p" parentName: "p"
}, `triangle`), `. You can also append a number between 1 and 32 to reduce the harmonic partials.`), /*#__PURE__*/ _react1.mdx("h3", null, `lowpass(cutoff)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper that returns a Filter Node of type lowpass with the given cutoff. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }, `triangle`), `. You can also append a number between 1 and 32 to reduce the harmonic partials.`), /*#__PURE__*/ _react1.mdx("h3", null, `lowpass(cutoff)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper that returns a Filter Node of type lowpass with the given cutoff. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4) tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(synth(osc('sawtooth')).chain(lowpass(800), out))`, .tone(synth(osc('sawtooth')).chain(lowpass(800), out()))`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("h3", null, `highpass(cutoff)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper that returns a Filter Node of type highpass with the given cutoff. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }), /*#__PURE__*/ _react1.mdx("h3", null, `highpass(cutoff)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper that returns a Filter Node of type highpass with the given cutoff. Intended to be used with Tone's .chain:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4) tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(synth(osc('sawtooth')).chain(highpass(2000), out))`, .tone(synth(osc('sawtooth')).chain(highpass(2000), out()))`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("h3", null, `adsr(attack, decay?, sustain?, release?)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper to set the envelope of a Tone.js instrument. Intended to be used with Tone's .set:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }), /*#__PURE__*/ _react1.mdx("h3", null, `adsr(attack, decay?, sustain?, release?)`), /*#__PURE__*/ _react1.mdx("p", null, `Helper to set the envelope of a Tone.js instrument. Intended to be used with Tone's .set:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4) tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(synth(adsr(0,.1,0,0)).chain(out))`, .tone(synth(adsr(0,.1,0,0)).chain(out()))`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("h3", null, `Experimental: Patternification`), /*#__PURE__*/ _react1.mdx("p", null, `While the above methods work for static sounds, there is also the option to patternify tone methods. }), /*#__PURE__*/ _react1.mdx("h3", null, `Experimental: Patternification`), /*#__PURE__*/ _react1.mdx("p", null, `While the above methods work for static sounds, there is also the option to patternify tone methods.
This is currently experimental, because the performance is not stable, and audio glitches will appear after some time. This is currently experimental, because the performance is not stable, and audio glitches will appear after some time.
@ -7690,7 +7690,7 @@ It would be great to get this to work without glitches though, because it is fun
}), /*#__PURE__*/ _react1.mdx("p", null, `Together with edit, struct and voicings, this can be used to create a basic backing track:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, { }), /*#__PURE__*/ _react1.mdx("p", null, `Together with edit, struct and voicings, this can be used to create a basic backing track:`), /*#__PURE__*/ _react1.mdx(_miniReplDefault.default, {
tune: `"<C^7 A7b13 Dm7 G7>".edit( tune: `"<C^7 A7b13 Dm7 G7>".edit(
x => x.voicings(['d3','g4']).struct("~ x"), x => x.voicings(['d3','g4']).struct("~ x"),
x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out)) x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out()))
)`, )`,
mdxType: "MiniRepl" mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("p", null, `TODO: use range instead of octave. }), /*#__PURE__*/ _react1.mdx("p", null, `TODO: use range instead of octave.
@ -7946,13 +7946,18 @@ const defaultSynth = new _tone.PolySynth().chain(new _tone.Gain(0.5), _tone.Dest
release: 0.01 release: 0.01
} }
}); });
// "balanced" | "interactive" | "playback";
_tone.setContext(new _tone.Context({
latencyHint: 'playback',
lookAhead: 1
}));
function MiniRepl({ tune , maxHeight =500 }) { function MiniRepl({ tune , maxHeight =500 }) {
const [editor, setEditor] = _react.useState(); const [editor, setEditor] = _react.useState();
const { code , setCode , activateCode , activeCode , setPattern , error , cycle , dirty , log , togglePlay , hash } = _useReplDefault.default({ const { code , setCode , activateCode , activeCode , setPattern , error , cycle , dirty , log , togglePlay , hash } = _useReplDefault.default({
tune, tune,
defaultSynth, defaultSynth,
autolink: false, autolink: false,
onEvent: _react.useCallback(_codeMirror.markEvent(editor), [ onDraw: _react.useCallback(_codeMirror.markEvent(editor), [
editor editor
]) ])
}); });
@ -41655,7 +41660,7 @@ var _usePostMessageDefault = parcelHelpers.interopDefault(_usePostMessage);
let s4 = ()=>{ let s4 = ()=>{
return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1); return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
}; };
function useRepl({ tune , defaultSynth , autolink =true , onEvent }) { function useRepl({ tune , defaultSynth , autolink =true , onEvent , onDraw }) {
const id = _react.useMemo(()=>s4() const id = _react.useMemo(()=>s4()
, []); , []);
const [code, setCode] = _react.useState(tune); const [code, setCode] = _react.useState(tune);
@ -41700,6 +41705,7 @@ function useRepl({ tune , defaultSynth , autolink =true , onEvent }) {
}; };
// cycle hook to control scheduling // cycle hook to control scheduling
const cycle1 = _useCycleDefault.default({ const cycle1 = _useCycleDefault.default({
onDraw,
onEvent: _react.useCallback((time, event)=>{ onEvent: _react.useCallback((time, event)=>{
try { try {
onEvent?.(event); onEvent?.(event);
@ -41725,6 +41731,7 @@ function useRepl({ tune , defaultSynth , autolink =true , onEvent }) {
try { try {
return pattern?.query(span) || []; return pattern?.query(span) || [];
} catch (err) { } catch (err) {
console.warn(err);
err.message = 'query error: ' + err.message; err.message = 'query error: ' + err.message;
setError(err); setError(err);
return []; return [];
@ -56548,7 +56555,8 @@ const osc = (type)=>({
} }
}) })
; ;
const out = _tone.Destination; const out = ()=>_tone.getDestination()
;
/* /*
You are entering experimental zone You are entering experimental zone
@ -56560,7 +56568,7 @@ const chainable = function(instr) {
instr.chain = (...args)=>{ instr.chain = (...args)=>{
chained = chained.concat(args); chained = chained.concat(args);
instr.disconnect(); // disconnect from destination / previous chain instr.disconnect(); // disconnect from destination / previous chain
return _chain(...chained, _tone.Destination); return _chain(...chained, _tone.getDestination());
}; };
// shortcuts: chaining multiple won't work forn now.. like filter(1000).gain(0.5). use chain + native Tone calls instead // shortcuts: chaining multiple won't work forn now.. like filter(1000).gain(0.5). use chain + native Tone calls instead
instr.filter = (freq = 1000, type = 'lowpass')=>instr.chain(new _tone.Filter(freq, type) // .Q.setValueAtTime(q, time); instr.filter = (freq = 1000, type = 'lowpass')=>instr.chain(new _tone.Filter(freq, type) // .Q.setValueAtTime(q, time);
@ -56693,7 +56701,7 @@ Pattern.prototype.chain = function(...effectGetters) {
const getChain = ()=>{ const getChain = ()=>{
const effects = chain.map((getEffect)=>getEffect() const effects = chain.map((getEffect)=>getEffect()
); );
return value.getInstrument().chain(...effects, _tone.Destination); return value.getInstrument().chain(...effects, _tone.getDestination());
}; };
const onTrigger = getTrigger(getChain, value.value); const onTrigger = getTrigger(getChain, value.value);
return { return {
@ -98097,10 +98105,10 @@ var _tone = require("tone");
var _strudelMjs = require("../../strudel.mjs"); var _strudelMjs = require("../../strudel.mjs");
function useCycle(props) { function useCycle(props) {
// onX must use useCallback! // onX must use useCallback!
const { onEvent , onQuery , onSchedule , ready =true } = props; const { onEvent , onQuery , onSchedule , ready =true , onDraw } = props;
const [started, setStarted] = _react.useState(false); const [started, setStarted] = _react.useState(false);
const cycleDuration = 1; const cycleDuration = 1;
const activeCycle = ()=>Math.floor(_tone.Transport.seconds / cycleDuration) const activeCycle = ()=>Math.floor(_tone.getTransport().seconds / cycleDuration)
; ;
// pull events with onQuery + count up to next cycle // pull events with onQuery + count up to next cycle
const query = (cycle = activeCycle())=>{ const query = (cycle = activeCycle())=>{
@ -98111,24 +98119,28 @@ function useCycle(props) {
// console.log('schedule', cycle); // console.log('schedule', cycle);
// query next cycle in the middle of the current // query next cycle in the middle of the current
const cancelFrom = timespan.begin.valueOf(); const cancelFrom = timespan.begin.valueOf();
_tone.Transport.cancel(cancelFrom); _tone.getTransport().cancel(cancelFrom);
// const queryNextTime = (cycle + 1) * cycleDuration - 0.1; // const queryNextTime = (cycle + 1) * cycleDuration - 0.1;
const queryNextTime = (cycle + 1) * cycleDuration - 0.5; const queryNextTime = (cycle + 1) * cycleDuration - 0.5;
// if queryNextTime would be before current time, execute directly (+0.1 for safety that it won't miss) // if queryNextTime would be before current time, execute directly (+0.1 for safety that it won't miss)
const t = Math.max(_tone.Transport.seconds, queryNextTime) + 0.1; const t = Math.max(_tone.getTransport().seconds, queryNextTime) + 0.1;
_tone.Transport.schedule(()=>{ _tone.getTransport().schedule(()=>{
query(cycle + 1); query(cycle + 1);
}, t); }, t);
// schedule events for next cycle // schedule events for next cycle
events?.filter((event)=>event.part.begin.valueOf() === event.whole.begin.valueOf() events?.filter((event)=>event.part.begin.valueOf() === event.whole.begin.valueOf()
).forEach((event)=>{ ).forEach((event)=>{
_tone.Transport.schedule((time)=>{ _tone.getTransport().schedule((time)=>{
const toneEvent = { const toneEvent = {
time: event.part.begin.valueOf(), time: event.part.begin.valueOf(),
duration: event.whole.end.sub(event.whole.begin).valueOf(), duration: event.whole.end.sub(event.whole.begin).valueOf(),
value: event.value value: event.value
}; };
onEvent(time, toneEvent); onEvent(time, toneEvent);
_tone.Draw.schedule(()=>{
// do drawing or DOM manipulation here
onDraw?.(time, toneEvent);
}, time);
}, event.part.begin.valueOf()); }, event.part.begin.valueOf());
}); });
}; };
@ -98143,12 +98155,12 @@ function useCycle(props) {
const start = async ()=>{ const start = async ()=>{
setStarted(true); setStarted(true);
await _tone.start(); await _tone.start();
_tone.Transport.start('+0.1'); _tone.getTransport().start('+0.1');
}; };
const stop = ()=>{ const stop = ()=>{
console.log('stop'); console.log('stop');
setStarted(false); setStarted(false);
_tone.Transport.pause(); _tone.getTransport().pause();
}; };
const toggle = ()=>started ? stop() : start() const toggle = ()=>started ? stop() : start()
; ;
@ -98212,7 +98224,7 @@ function CodeMirror({ value , onChange , options , editorDidMount }) {
})); }));
} }
exports.default = CodeMirror; exports.default = CodeMirror;
const markEvent = (editor)=>(event)=>{ const markEvent = (editor)=>(time, event)=>{
const locs = event.value.locations; const locs = event.value.locations;
if (!locs || !editor) return; if (!locs || !editor) return;
// mark active event // mark active event
@ -109452,4 +109464,4 @@ exports.default = cx;
},{"@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}]},["3uVTb"], "3uVTb", "parcelRequire94c2") },{"@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}]},["3uVTb"], "3uVTb", "parcelRequire94c2")
//# sourceMappingURL=index.8834957f.js.map //# sourceMappingURL=index.4ae5d228.js.map

File diff suppressed because one or more lines are too long

View file

@ -11,6 +11,6 @@
<body> <body>
<div id="root"></div> <div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/tutorial/index.8834957f.js" defer=""></script> <script src="/tutorial/index.4ae5d228.js" defer=""></script>
</body> </body>
</html> </html>