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) {
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({
oscillator: {type: "triangle"},
envelope: {
@ -32,7 +32,7 @@ function App() {
const {setCode, setPattern, error, code, cycle, dirty, log, togglePlay, activateCode, pattern, pushLog} = useRepl({
tune: decoded || randomTune,
defaultSynth,
onEvent: useCallback(markEvent(editor), [editor])
onDraw: useCallback(markEvent(editor), [editor])
});
const logBox = useRef();
useLayoutEffect(() => {

View File

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

10
docs/dist/tone.js vendored
View File

@ -1,7 +1,6 @@
import {Pattern as _Pattern} from "../_snowpack/link/strudel.js";
import {
AutoFilter,
Destination,
Filter,
Gain,
isNote,
@ -15,7 +14,8 @@ import {
FMSynth,
NoiseSynth,
PluckSynth,
Sampler
Sampler,
getDestination
} from "../_snowpack/pkg/tone.js";
const Pattern = _Pattern;
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 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 out = Destination;
export const out = () => getDestination();
const chainable = function(instr) {
const _chain = instr.chain.bind(instr);
let chained = [];
instr.chain = (...args) => {
chained = chained.concat(args);
instr.disconnect();
return _chain(...chained, Destination);
return _chain(...chained, getDestination());
};
instr.filter = (freq = 1e3, type = "lowpass") => instr.chain(new Filter(freq, type));
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 getChain = () => {
const effects = chain.map((getEffect) => getEffect());
return value.getInstrument().chain(...effects, Destination);
return value.getInstrument().chain(...effects, getDestination());
};
const onTrigger = getTrigger(getChain, value.value);
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 Chorus(2, 2.5, 0.5).start(),
new Freeverb(),
Destination)
getDestination())
)`;
export const technoDrums = `stack(
"c1*2".tone(new Tone.MembraneSynth().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 = `() => {
const delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out);
const kick = new MembraneSynth().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 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 delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out());
const kick = new MembraneSynth().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 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 drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"),
@ -292,12 +292,12 @@ export const loungerave = `() => {
//.early("0.25 0");
}`;
export const caverave = `() => {
const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out);
const kick = new MembraneSynth().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 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 delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
const kick = new MembraneSynth().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 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 drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"),
@ -324,16 +324,16 @@ export const caverave = `() => {
}`;
export const callcenterhero = `()=>{
const bpm = 90;
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 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 s = scale(slowcat('F3 minor', 'Ab3 major', 'Bb3 dorian', 'C4 phrygian dominant').slow(4));
return stack(
"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),
"-14".struct("[~ x@0.8]*2".early(0.01)).apply(s).tone(bass),
"c2*2".tone(membrane().chain(vol(0.6), out)),
"~ c2".tone(noise().chain(vol(0.2), out)),
"c4*4".tone(metal(adsr(0,.05,0)).chain(vol(0.03), out))
"c2*2".tone(membrane().chain(vol(0.6), out())),
"~ c2".tone(noise().chain(vol(0.2), out())),
"c4*4".tone(metal(adsr(0,.05,0)).chain(vol(0.03), out()))
)
.slow(120 / bpm)
}
@ -342,20 +342,20 @@ export const primalEnemy = `()=>{
const f = fast("<1 <2 [4 8]>>");
return stack(
"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)),
"c1*2".tone(membrane().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()))
).slow(1)
}`;
export const drums = `stack(
"c1*2".tone(membrane().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))
"c1*2".tone(membrane().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()))
)
`;
export const xylophoneCalling = `()=>{
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 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();
return stack(
// melody
@ -365,28 +365,28 @@ export const xylophoneCalling = `()=>{
.apply(t).tone(polysynth().set({
...osc('triangle4'),
...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
"[1,3]/4".scale('G3 minor pentatonic').apply(t).tone(polysynth().set({
...osc('square2'),
...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
"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'),
...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
"c2 [c2 ~]*2".scale('C hirajoshi').apply(t).tone(synth({
...osc('sawtooth6'),
...adsr(0,.03,.4,.1)
}).chain(vol(0.4),out)),
}).chain(vol(0.4),out())),
// 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
"~ <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
"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)
}`;
export const sowhatelse = `()=> {
@ -399,18 +399,18 @@ export const sowhatelse = `()=> {
kick: .9,
hihat: .35,
}[key]||0);
const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out);
const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out);
const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out());
const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out());
const chorus = new Chorus(1,2.5,0.5).start();
// instruments
const instr = (instrument) => ({
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),
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),
hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out),
snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out),
kick: membrane().chain(mix('kick'), 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()),
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()),
hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out()),
snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out()),
kick: membrane().chain(mix('kick'), out())
}[instrument]);
// harmony
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 {TimeSpan} from "../_snowpack/link/strudel.js";
function useCycle(props) {
const {onEvent, onQuery, onSchedule, ready = true} = props;
const {onEvent, onQuery, onSchedule, ready = true, onDraw} = props;
const [started, setStarted] = useState(false);
const cycleDuration = 1;
const activeCycle = () => Math.floor(Tone.Transport.seconds / cycleDuration);
const activeCycle = () => Math.floor(Tone.getTransport().seconds / cycleDuration);
const query = (cycle = activeCycle()) => {
const timespan = new TimeSpan(cycle, cycle + 1);
const events = onQuery?.(timespan) || [];
onSchedule?.(events, cycle);
const cancelFrom = timespan.begin.valueOf();
Tone.Transport.cancel(cancelFrom);
Tone.getTransport().cancel(cancelFrom);
const queryNextTime = (cycle + 1) * cycleDuration - 0.5;
const t = Math.max(Tone.Transport.seconds, queryNextTime) + 0.1;
Tone.Transport.schedule(() => {
const t = Math.max(Tone.getTransport().seconds, queryNextTime) + 0.1;
Tone.getTransport().schedule(() => {
query(cycle + 1);
}, t);
events?.filter((event) => event.part.begin.valueOf() === event.whole.begin.valueOf()).forEach((event) => {
Tone.Transport.schedule((time) => {
Tone.getTransport().schedule((time) => {
const toneEvent = {
time: event.part.begin.valueOf(),
duration: event.whole.end.sub(event.whole.begin).valueOf(),
value: event.value
};
onEvent(time, toneEvent);
Tone.Draw.schedule(() => {
onDraw?.(time, toneEvent);
}, time);
}, event.part.begin.valueOf());
});
};
@ -34,12 +37,12 @@ function useCycle(props) {
const start = async () => {
setStarted(true);
await Tone.start();
Tone.Transport.start("+0.1");
Tone.getTransport().start("+0.1");
};
const stop = () => {
console.log("stop");
setStarted(false);
Tone.Transport.pause();
Tone.getTransport().pause();
};
const toggle = () => started ? stop() : start();
return {start, stop, setStarted, onEvent, started, toggle, query, activeCycle};

View File

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

View File

@ -7330,12 +7330,12 @@ It aims to be `, /*#__PURE__*/ _react1.mdx("a", {
"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, {
tune: `() => {
const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out);
const kick = new MembraneSynth().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 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 delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
const kick = new MembraneSynth().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 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 drums = stack(
"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, {
tune: `stack(
"[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"
.tone(synth({
...osc('sawtooth'),
...adsr(0,.1,0.4,0)
}).chain(lowpass(300), out))
}).chain(lowpass(300), out()))
).slow(4)`,
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", {
@ -7608,15 +7608,15 @@ const sampler = (options) => new Sampler(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, {
tune: `"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(membrane().chain(out))`,
.tone(membrane().chain(out()))`,
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, {
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"
}), /*#__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)
.tone(synth(osc('sawtooth4')).chain(out))`,
.tone(synth(osc('sawtooth4')).chain(out()))`,
mdxType: "MiniRepl"
}), /*#__PURE__*/ _react1.mdx("p", null, `The base types are `, /*#__PURE__*/ _react1.mdx("inlineCode", {
parentName: "p"
@ -7628,15 +7628,15 @@ const synth = (options) => new Synth(options);
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, {
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"
}), /*#__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)
.tone(synth(osc('sawtooth')).chain(highpass(2000), out))`,
.tone(synth(osc('sawtooth')).chain(highpass(2000), out()))`,
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, {
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"
}), /*#__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.
@ -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, {
tune: `"<C^7 A7b13 Dm7 G7>".edit(
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"
}), /*#__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
}
});
// "balanced" | "interactive" | "playback";
_tone.setContext(new _tone.Context({
latencyHint: 'playback',
lookAhead: 1
}));
function MiniRepl({ tune , maxHeight =500 }) {
const [editor, setEditor] = _react.useState();
const { code , setCode , activateCode , activeCode , setPattern , error , cycle , dirty , log , togglePlay , hash } = _useReplDefault.default({
tune,
defaultSynth,
autolink: false,
onEvent: _react.useCallback(_codeMirror.markEvent(editor), [
onDraw: _react.useCallback(_codeMirror.markEvent(editor), [
editor
])
});
@ -41655,7 +41660,7 @@ var _usePostMessageDefault = parcelHelpers.interopDefault(_usePostMessage);
let s4 = ()=>{
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 [code, setCode] = _react.useState(tune);
@ -41700,6 +41705,7 @@ function useRepl({ tune , defaultSynth , autolink =true , onEvent }) {
};
// cycle hook to control scheduling
const cycle1 = _useCycleDefault.default({
onDraw,
onEvent: _react.useCallback((time, event)=>{
try {
onEvent?.(event);
@ -41725,6 +41731,7 @@ function useRepl({ tune , defaultSynth , autolink =true , onEvent }) {
try {
return pattern?.query(span) || [];
} catch (err) {
console.warn(err);
err.message = 'query error: ' + err.message;
setError(err);
return [];
@ -56548,7 +56555,8 @@ const osc = (type)=>({
}
})
;
const out = _tone.Destination;
const out = ()=>_tone.getDestination()
;
/*
You are entering experimental zone
@ -56560,7 +56568,7 @@ const chainable = function(instr) {
instr.chain = (...args)=>{
chained = chained.concat(args);
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
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 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);
return {
@ -98097,10 +98105,10 @@ var _tone = require("tone");
var _strudelMjs = require("../../strudel.mjs");
function useCycle(props) {
// 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 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
const query = (cycle = activeCycle())=>{
@ -98111,24 +98119,28 @@ function useCycle(props) {
// console.log('schedule', cycle);
// query next cycle in the middle of the current
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.5;
// 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;
_tone.Transport.schedule(()=>{
const t = Math.max(_tone.getTransport().seconds, queryNextTime) + 0.1;
_tone.getTransport().schedule(()=>{
query(cycle + 1);
}, t);
// schedule events for next cycle
events?.filter((event)=>event.part.begin.valueOf() === event.whole.begin.valueOf()
).forEach((event)=>{
_tone.Transport.schedule((time)=>{
_tone.getTransport().schedule((time)=>{
const toneEvent = {
time: event.part.begin.valueOf(),
duration: event.whole.end.sub(event.whole.begin).valueOf(),
value: event.value
};
onEvent(time, toneEvent);
_tone.Draw.schedule(()=>{
// do drawing or DOM manipulation here
onDraw?.(time, toneEvent);
}, time);
}, event.part.begin.valueOf());
});
};
@ -98143,12 +98155,12 @@ function useCycle(props) {
const start = async ()=>{
setStarted(true);
await _tone.start();
_tone.Transport.start('+0.1');
_tone.getTransport().start('+0.1');
};
const stop = ()=>{
console.log('stop');
setStarted(false);
_tone.Transport.pause();
_tone.getTransport().pause();
};
const toggle = ()=>started ? stop() : start()
;
@ -98212,7 +98224,7 @@ function CodeMirror({ value , onChange , options , editorDidMount }) {
}));
}
exports.default = CodeMirror;
const markEvent = (editor)=>(event)=>{
const markEvent = (editor)=>(time, event)=>{
const locs = event.value.locations;
if (!locs || !editor) return;
// mark active event
@ -109452,4 +109464,4 @@ exports.default = cx;
},{"@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>
<div id="root"></div>
<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>
</html>