diff --git a/packages/desktopbridge/oscbridge.mjs b/packages/desktopbridge/oscbridge.mjs index 645f7b4f..9bead6d1 100644 --- a/packages/desktopbridge/oscbridge.mjs +++ b/packages/desktopbridge/oscbridge.mjs @@ -1,20 +1,12 @@ -import { parseNumeral, Pattern, ClockCollator } from '@strudel/core'; - +import { Pattern, ClockCollator } from '@strudel/core'; +import { parseControlsFromHap } from 'node_modules/@strudel/osc/osc.mjs'; import { Invoke } from './utils.mjs'; const collator = new ClockCollator({}); export async function oscTriggerTauri(t_deprecate, hap, currentTime, cps = 1, targetTime) { - hap.ensureObjectValue(); - const cycle = hap.wholeOrPart().begin.valueOf(); - const delta = hap.duration.valueOf(); - const controls = Object.assign({}, { cps, cycle, delta }, hap.value); - // make sure n and note are numbers - controls.n && (controls.n = parseNumeral(controls.n)); - controls.note && (controls.note = parseNumeral(controls.note)); - + const controls = parseControlsFromHap(hap, cps); const params = []; - const timestamp = collator.calculateTimestamp(currentTime, targetTime); Object.keys(controls).forEach((key) => { diff --git a/packages/osc/osc.mjs b/packages/osc/osc.mjs index 8c063095..62a1812f 100644 --- a/packages/osc/osc.mjs +++ b/packages/osc/osc.mjs @@ -34,11 +34,8 @@ function connect() { return connection; } -const collator = new ClockCollator({}); - -export async function oscTrigger(t_deprecate, hap, currentTime, cps = 1, targetTime) { +export function parseControlsFromHap(hap, cps) { hap.ensureObjectValue(); - const osc = await connect(); const cycle = hap.wholeOrPart().begin.valueOf(); const delta = hap.duration.valueOf(); const controls = Object.assign({}, { cps, cycle, delta }, hap.value); @@ -53,9 +50,19 @@ export async function oscTrigger(t_deprecate, hap, currentTime, cps = 1, targetT } controls.bank && (controls.s = controls.bank + controls.s); controls.roomsize && (controls.size = parseNumeral(controls.roomsize)); - const keyvals = Object.entries(controls).flat(); - const ts = Math.round(collator.calculateTimestamp(currentTime, targetTime) * 1000); + const channels = controls.channels; + channels != undefined && (controls.channels = JSON.stringify(channels)); + return controls; +} +const collator = new ClockCollator({}); + +export async function oscTrigger(t_deprecate, hap, currentTime, cps = 1, targetTime) { + const osc = await connect(); + const controls = parseControlsFromHap(hap, cps); + const keyvals = Object.entries(controls).flat(); + + const ts = Math.round(collator.calculateTimestamp(currentTime, targetTime) * 1000); const message = new OSC.Message('/dirt/play', ...keyvals); const bundle = new OSC.Bundle([message], ts); bundle.timestamp(ts); // workaround for https://github.com/adzialocha/osc-js/issues/60 diff --git a/website/src/pages/learn/input-output.mdx b/website/src/pages/learn/input-output.mdx index 0151e6eb..93cbfdc5 100644 --- a/website/src/pages/learn/input-output.mdx +++ b/website/src/pages/learn/input-output.mdx @@ -45,7 +45,7 @@ But you can also control cc messages separately like this: $: ccv(sine.segment(16).slow(4)).ccn(74).midi()`} /> -# SuperDirt API +# OSC/SuperDirt API In mainline tidal, the actual sound is generated via [SuperDirt](https://github.com/musikinformatik/SuperDirt/), which runs inside SuperCollider. Strudel also supports using [SuperDirt](https://github.com/musikinformatik/SuperDirt/) as a backend, although it requires some developer tooling to run. @@ -73,16 +73,14 @@ Now you're all set! If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT). +Note: if you have the 'Audio Engine Target' in settings set to 'OSC', you do not need to add .osc() to the end of your pattern. + ### Pattern.osc ## SuperDirt Params -The following functions can be used with [SuperDirt](https://github.com/musikinformatik/SuperDirt/): - -`s n note freq channel orbit cutoff resonance hcutoff hresonance bandf bandq djf vowel cut begin end loop fadeTime speed unitA gain amp accelerate crush coarse delay lock leslie lrate lsize pan panspan pansplay room size dry shape squiz waveloss attack decay octave detune tremolodepth` - Please refer to [Tidal Docs](https://tidalcycles.org/) for more info.
diff --git a/website/src/repl/components/panel/AudioEngineTargetSelector.jsx b/website/src/repl/components/panel/AudioEngineTargetSelector.jsx index fc894d02..a6826144 100644 --- a/website/src/repl/components/panel/AudioEngineTargetSelector.jsx +++ b/website/src/repl/components/panel/AudioEngineTargetSelector.jsx @@ -9,7 +9,16 @@ export function AudioEngineTargetSelector({ target, onChange, isDisabled }) { }; const options = new Map([ [audioEngineTargets.webaudio, audioEngineTargets.webaudio], - [audioEngineTargets.superdirt, 'superdirt (osc)'], + [audioEngineTargets.osc, audioEngineTargets.osc], ]); - return ; + return ( +
+ + {target === audioEngineTargets.osc && ( +
+

⚠ Events routed to OSC, audio is silenced! See Docs

+
+ )} +
+ ); } diff --git a/website/src/repl/useReplContext.jsx b/website/src/repl/useReplContext.jsx index 58ac10b9..ba861627 100644 --- a/website/src/repl/useReplContext.jsx +++ b/website/src/repl/useReplContext.jsx @@ -57,7 +57,7 @@ async function getModule(name) { export function useReplContext() { const { isSyncEnabled, audioEngineTarget } = useSettings(); - const shouldUseWebaudio = audioEngineTarget !== audioEngineTargets.superdirt; + const shouldUseWebaudio = audioEngineTarget !== audioEngineTargets.osc; const defaultOutput = shouldUseWebaudio ? webaudioOutput : superdirtOutput; const getTime = shouldUseWebaudio ? getAudioContextCurrentTime : getPerformanceTimeSeconds; diff --git a/website/src/settings.mjs b/website/src/settings.mjs index 7c202e4c..8e527d71 100644 --- a/website/src/settings.mjs +++ b/website/src/settings.mjs @@ -7,7 +7,7 @@ export const defaultAudioDeviceName = 'System Standard'; export const audioEngineTargets = { webaudio: 'webaudio', - superdirt: 'superdirt', + osc: 'osc', }; export const defaultSettings = { @@ -33,7 +33,7 @@ export const defaultSettings = { panelPosition: 'right', userPatterns: '{}', audioDeviceName: defaultAudioDeviceName, - audioEngineTarget: audioEngineTargets.webaudio, //webaudio | superdirt + audioEngineTarget: audioEngineTargets.webaudio, }; let search = null;