This commit is contained in:
Jade (Rose) Rowland 2025-05-07 11:12:05 -04:00
parent 56d3436fda
commit 59bdfd2cb8
4 changed files with 42 additions and 14 deletions

View File

@ -23,9 +23,9 @@ export function setMaxPolyphony(polyphony) {
maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY; maxPolyphony = parseInt(polyphony) ?? DEFAULT_MAX_POLYPHONY;
} }
let multiChannelOrbits = false let multiChannelOrbits = false;
export function setMultiChannelOrbits(bool) { export function setMultiChannelOrbits(bool) {
multiChannelOrbits = (bool == true); multiChannelOrbits = bool == true;
} }
export const soundMap = map(); export const soundMap = map();
@ -201,8 +201,15 @@ function loadWorklets() {
// this function should be called on first user interaction (to avoid console warning) // this function should be called on first user interaction (to avoid console warning)
export async function initAudio(options = {}) { export async function initAudio(options = {}) {
const { disableWorklets = false, maxPolyphony, audioDeviceName = DEFAULT_AUDIO_DEVICE_NAME, multiChannelOrbits = false } = options; const {
disableWorklets = false,
maxPolyphony,
audioDeviceName = DEFAULT_AUDIO_DEVICE_NAME,
multiChannelOrbits = false,
} = options;
setMaxPolyphony(maxPolyphony); setMaxPolyphony(maxPolyphony);
setMultiChannelOrbits(multiChannelOrbits);
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
return; return;
} }
@ -496,7 +503,7 @@ export const superdough = async (value, t, hapDuration) => {
bpsustain, bpsustain,
bprelease, bprelease,
bandq = getDefaultValue('bandq'), bandq = getDefaultValue('bandq'),
//phaser //phaser
phaserrate: phaser, phaserrate: phaser,
phaserdepth = getDefaultValue('phaserdepth'), phaserdepth = getDefaultValue('phaserdepth'),
@ -532,8 +539,14 @@ export const superdough = async (value, t, hapDuration) => {
compressorRelease, compressorRelease,
} = value; } = value;
const orbitChannels = multiChannelOrbits ? [(orbit * 2) - 1, orbit * 2] : getDefaultValue('channels') //music programs/audio gear usually increments inputs/outputs from 1, we need to subtract 1 from the input because the webaudio API channels start at 0
const channels = value.channels ?? orbitChannels; const orbitChannels = (
multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels')
).map((ch) => ch - 1);
const channels =
value.channels != null
? (Array.isArray(value.channels) ? value.channels : [value.channels]).map((ch) => ch - 1)
: orbitChannels;
gain = applyGainCurve(nanFallback(gain, 1)); gain = applyGainCurve(nanFallback(gain, 1));
postgain = applyGainCurve(postgain); postgain = applyGainCurve(postgain);
@ -556,9 +569,6 @@ export const superdough = async (value, t, hapDuration) => {
activeSoundSources.delete(chainID); activeSoundSources.delete(chainID);
} }
//music programs/audio gear usually increments inputs/outputs from 1, so imitate that behavior
channels = (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
let audioNodes = []; let audioNodes = [];
if (bank && s) { if (bank && s) {

View File

@ -6,7 +6,7 @@ import { ButtonGroup } from './Forms.jsx';
import { AudioDeviceSelector } from './AudioDeviceSelector.jsx'; import { AudioDeviceSelector } from './AudioDeviceSelector.jsx';
import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx'; import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx';
import { confirmDialog } from '../../util.mjs'; import { confirmDialog } from '../../util.mjs';
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony } from '@strudel/webaudio'; import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio';
function Checkbox({ label, value, onChange, disabled = false }) { function Checkbox({ label, value, onChange, disabled = false }) {
return ( return (
@ -108,6 +108,7 @@ export function SettingsTab({ started }) {
audioEngineTarget, audioEngineTarget,
togglePanelTrigger, togglePanelTrigger,
maxPolyphony, maxPolyphony,
multiChannelOrbits,
} = useSettings(); } = useSettings();
const shouldAlwaysSync = isUdels(); const shouldAlwaysSync = isUdels();
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null; const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
@ -162,6 +163,17 @@ export function SettingsTab({ started }) {
value={maxPolyphony ?? ''} value={maxPolyphony ?? ''}
/> />
</FormItem> </FormItem>
<FormItem>
<Checkbox
label="Multi Channel Orbits"
onChange={(cbEvent) => {
const val = cbEvent.target.checked;
settingsMap.setKey('multiChannelOrbits', val);
setMultiChannelOrbits(val);
}}
value={multiChannelOrbits}
/>
</FormItem>
<FormItem label="Theme"> <FormItem label="Theme">
<SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} /> <SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} />
</FormItem> </FormItem>

View File

@ -18,7 +18,7 @@ import { setVersionDefaultsFrom } from './util.mjs';
import { StrudelMirror, defaultSettings } from '@strudel/codemirror'; import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
import { clearHydra } from '@strudel/hydra'; import { clearHydra } from '@strudel/hydra';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { settingsMap, useSettings } from '../settings.mjs'; import { parseBoolean, settingsMap, useSettings } from '../settings.mjs';
import { import {
setActivePattern, setActivePattern,
setLatestCode, setLatestCode,
@ -36,11 +36,15 @@ import './Repl.css';
import { setInterval, clearInterval } from 'worker-timers'; import { setInterval, clearInterval } from 'worker-timers';
import { getMetadata } from '../metadata_parser'; import { getMetadata } from '../metadata_parser';
const { latestCode, maxPolyphony, audioDeviceName } = settingsMap.get(); const { latestCode, maxPolyphony, audioDeviceName, multiChannelOrbits } = settingsMap.get();
let modulesLoading, presets, drawContext, clearCanvas, audioReady; let modulesLoading, presets, drawContext, clearCanvas, audioReady;
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
audioReady = initAudioOnFirstClick({ maxPolyphony, audioDeviceName }); audioReady = initAudioOnFirstClick({
maxPolyphony,
audioDeviceName,
multiChannelOrbits: parseBoolean(multiChannelOrbits),
});
modulesLoading = loadModules(); modulesLoading = loadModules();
presets = prebake(); presets = prebake();
drawContext = getDrawContext(); drawContext = getDrawContext();

View File

@ -38,6 +38,7 @@ export const defaultSettings = {
isButtonRowHidden: false, isButtonRowHidden: false,
isCSSAnimationDisabled: false, isCSSAnimationDisabled: false,
maxPolyphony: 128, maxPolyphony: 128,
multiChannelOrbits: false,
}; };
let search = null; let search = null;
@ -50,7 +51,7 @@ const settings_key = `strudel-settings${instance > 0 ? instance : ''}`;
export const settingsMap = persistentMap(settings_key, defaultSettings); export const settingsMap = persistentMap(settings_key, defaultSettings);
const parseBoolean = (booleanlike) => ([true, 'true'].includes(booleanlike) ? true : false); export const parseBoolean = (booleanlike) => ([true, 'true'].includes(booleanlike) ? true : false);
export function useSettings() { export function useSettings() {
const state = useStore(settingsMap); const state = useStore(settingsMap);
@ -81,6 +82,7 @@ export function useSettings() {
isPanelPinned: parseBoolean(state.isPanelPinned), isPanelPinned: parseBoolean(state.isPanelPinned),
isPanelOpen: parseBoolean(state.isPanelOpen), isPanelOpen: parseBoolean(state.isPanelOpen),
userPatterns: userPatterns, userPatterns: userPatterns,
multiChannelOrbits: parseBoolean(state.multiChannelOrbits),
}; };
} }