diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index cbaf8a8a2..d9bb94075 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -3263,7 +3263,7 @@ export const slice = register( * s("bd!8").onTriggerTime((hap) => {console.info(hap)}) */ Pattern.prototype.onTriggerTime = function (func) { - return this.onTrigger((t_deprecate, hap, currentTime, cps = 1, targetTime) => { + return this.onTrigger((hap, currentTime, _cps, targetTime) => { const diff = targetTime - currentTime; window.setTimeout(() => { func(hap); diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index dcc5fcba4..117b1d046 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -252,7 +252,7 @@ export const getTrigger = } if (hap.context.onTrigger) { // call signature of output / onTrigger is different... - await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps, t); + await hap.context.onTrigger(hap, getTime(), cps, t); } } catch (err) { logger(`[cyclist] error: ${err.message}`, 'error'); diff --git a/packages/core/speak.mjs b/packages/core/speak.mjs index 7e548a73b..e0f60184e 100644 --- a/packages/core/speak.mjs +++ b/packages/core/speak.mjs @@ -32,7 +32,7 @@ function triggerSpeech(words, lang, voice) { } export const speak = register('speak', function (lang, voice, pat) { - return pat.onTrigger((_, hap) => { + return pat.onTrigger((hap) => { triggerSpeech(hap.value, lang, voice); }); }); diff --git a/packages/csound/index.mjs b/packages/csound/index.mjs index 1eeaf6fa5..e44765227 100644 --- a/packages/csound/index.mjs +++ b/packages/csound/index.mjs @@ -23,7 +23,7 @@ export const csound = register('csound', (instrument, pat) => { instrument = instrument || 'triangle'; init(); // not async to support csound inside other patterns + to be able to call pattern methods after it // TODO: find a alternative way to wait for csound to load (to wait with first time playback) - return pat.onTrigger((time_deprecate, hap, currentTime, _cps, targetTime) => { + return pat.onTrigger((hap, currentTime, _cps, targetTime) => { if (!_csound) { logger('[csound] not loaded yet', 'warning'); return; @@ -142,7 +142,7 @@ export const csoundm = register('csoundm', (instrument, pat) => { p1 = `"${instrument}"`; } init(); // not async to support csound inside other patterns + to be able to call pattern methods after it - return pat.onTrigger((tidal_time, hap) => { + return pat.onTrigger((hap, currentTime, _cps, targetTime) => { if (!_csound) { logger('[csound] not loaded yet', 'warning'); return; @@ -151,7 +151,7 @@ export const csoundm = register('csoundm', (instrument, pat) => { throw new Error('csound only support objects as hap values'); } // Time in seconds counting from now. - const p2 = tidal_time - getAudioContext().currentTime; + const p2 = targetTime - currentTime; const p3 = hap.duration.valueOf() + 0; const frequency = getFrequency(hap); let { gain = 1, velocity = 0.9 } = hap.value; diff --git a/packages/desktopbridge/midibridge.mjs b/packages/desktopbridge/midibridge.mjs index 471c826ea..2436d8ad7 100644 --- a/packages/desktopbridge/midibridge.mjs +++ b/packages/desktopbridge/midibridge.mjs @@ -6,7 +6,7 @@ const OFF_MESSAGE = 0x80; const CC_MESSAGE = 0xb0; Pattern.prototype.midi = function (output) { - return this.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => { + return this.onTrigger((hap, currentTime, cps, targetTime) => { let { note, nrpnn, nrpv, ccn, ccv, velocity = 0.9, gain = 1 } = hap.value; //magic number to get audio engine to line up, can probably be calculated somehow const latencyMs = 34; diff --git a/packages/desktopbridge/oscbridge.mjs b/packages/desktopbridge/oscbridge.mjs index 9bead6d19..2568c78e5 100644 --- a/packages/desktopbridge/oscbridge.mjs +++ b/packages/desktopbridge/oscbridge.mjs @@ -4,7 +4,7 @@ import { Invoke } from './utils.mjs'; const collator = new ClockCollator({}); -export async function oscTriggerTauri(t_deprecate, hap, currentTime, cps = 1, targetTime) { +export async function oscTriggerTauri(hap, currentTime, cps = 1, targetTime) { const controls = parseControlsFromHap(hap, cps); const params = []; const timestamp = collator.calculateTimestamp(currentTime, targetTime); diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs index af2dd3a62..d0e092938 100644 --- a/packages/midi/midi.mjs +++ b/packages/midi/midi.mjs @@ -333,7 +333,7 @@ Pattern.prototype.midi = function (midiport, options = {}) { logger(`Midi device disconnected! Available: ${getMidiDeviceNamesString(outputs)}`), }); - return this.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => { + return this.onTrigger((hap, currentTime, cps, targetTime) => { if (!WebMidi.enabled) { logger('Midi not enabled'); return; diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index ac70b9e73..8262e5569 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -60,7 +60,7 @@ export function parseControlsFromHap(hap, cps) { const collator = new ClockCollator({}); -export async function oscTrigger(t_deprecate, hap, currentTime, cps = 1, targetTime) { +export async function oscTrigger(hap, currentTime, cps = 1, targetTime) { const osc = await connect(); const controls = parseControlsFromHap(hap, cps); const keyvals = Object.entries(controls).flat(); diff --git a/packages/soundfonts/sfumato.mjs b/packages/soundfonts/sfumato.mjs index 6d60f80dd..4d5e7ef45 100644 --- a/packages/soundfonts/sfumato.mjs +++ b/packages/soundfonts/sfumato.mjs @@ -3,7 +3,7 @@ import { getAudioContext, registerSound } from '@strudel/webaudio'; import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato'; Pattern.prototype.soundfont = function (sf, n = 0) { - return this.onTrigger((time_deprecate, h, ct, cps, targetTime) => { + return this.onTrigger((h, ct, cps, targetTime) => { const ctx = getAudioContext(); const note = getPlayableNoteValue(h); const preset = sf.presets[n % sf.presets.length]; diff --git a/packages/superdough/dspworklet.mjs b/packages/superdough/dspworklet.mjs index ed5c1e7e0..5b02ad298 100644 --- a/packages/superdough/dspworklet.mjs +++ b/packages/superdough/dspworklet.mjs @@ -74,6 +74,6 @@ export const dough = async (code) => { worklet.node.connect(ac.destination); }; -export function doughTrigger(time_deprecate, hap, currentTime, cps, targetTime) { +export function doughTrigger(hap, currentTime, cps, targetTime) { window.postMessage({ time: targetTime, dough: hap.value, currentTime, duration: hap.duration, cps }); } diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs index 14f46711b..003f58bbe 100644 --- a/packages/superdough/superdough.mjs +++ b/packages/superdough/superdough.mjs @@ -451,8 +451,8 @@ function mapChannelNumbers(channels) { } export const superdough = async (value, t, hapDuration, cps = 0.5) => { + // new: t is always expected to be the absolute target onset time const ac = getAudioContext(); - t = typeof t === 'string' && t.startsWith('=') ? Number(t.slice(1)) : ac.currentTime + t; let { stretch } = value; if (stretch != null) { //account for phase vocoder latency diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index 91e28defd..01ad9fb8b 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -15,14 +15,10 @@ const hap2value = (hap) => { return hap.value; }; -export const webaudioOutputTrigger = (t, hap, ct, cps) => superdough(hap2value(hap), t - ct, hap.duration / cps, cps); // uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004 +// TODO: refactor output callbacks to eliminate deadline export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => { - return superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration, cps); -}; - -Pattern.prototype.webaudio = function () { - return this.onTrigger(webaudioOutputTrigger); + return superdough(hap2value(hap), t, hapDuration, cps); }; export function webaudioRepl(options = {}) { diff --git a/test/testtunes.mjs b/test/testtunes.mjs index fc887610e..3690d315b 100644 --- a/test/testtunes.mjs +++ b/test/testtunes.mjs @@ -359,28 +359,6 @@ stack( "[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25) ).note().piano().slow(2)`; -/* -export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ -// by Felix Roos -stack( - freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))), - freq("440(5,8)".clip(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8)) -).s("/2") - .onTrigger((t,hap,ct)=>{ - const ac = Tone.getContext().rawContext; - t = ac.currentTime + t - ct; - const { freq, s, gain = 1 } = hap.value; - const master = ac.createGain(); - master.gain.value = 0.1 * gain; - master.connect(ac.destination); - const o = ac.createOscillator(); - o.type = s || 'triangle'; - o.frequency.value = Number(freq); - o.connect(master); - o.start(t); - o.stop(t + hap.duration); -}).stack(s("bd(3,8),hh*4,~ sd").webdirt())`; */ - export const swimmingWithSoundfonts = `// Koji Kondo - Swimming (Super Mario World) stack( n(