diff --git a/packages/app/studio/src/ui/devices/panel/DevicePanel.tsx b/packages/app/studio/src/ui/devices/panel/DevicePanel.tsx index 54d30b767..60304947f 100644 --- a/packages/app/studio/src/ui/devices/panel/DevicePanel.tsx +++ b/packages/app/studio/src/ui/devices/panel/DevicePanel.tsx @@ -34,11 +34,13 @@ import {Project} from "@opendaw/studio-core" const className = Html.adoptStyleSheet(css, "DevicePanel") +/** Props for {@link DevicePanel}. */ type Construct = { lifecycle: Lifecycle service: StudioService } +/** Context information for the currently edited device chain. */ type Context = { deviceHost: DeviceHost, instrument: ObservableValue> } /** diff --git a/packages/app/studio/src/ui/mixer/AudioOutputDevices.tsx b/packages/app/studio/src/ui/mixer/AudioOutputDevices.tsx index 0e34463ec..f69b9fb2a 100644 --- a/packages/app/studio/src/ui/mixer/AudioOutputDevices.tsx +++ b/packages/app/studio/src/ui/mixer/AudioOutputDevices.tsx @@ -8,6 +8,7 @@ import { AudioDevices } from "@/audio/AudioDevices"; const className = Html.adoptStyleSheet(css, "AudioOutputDevices"); +/** Props for {@link AudioOutputDevices}. */ type Construct = { output: AudioOutputDevice; provider: Procedure; diff --git a/packages/app/studio/src/ui/mixer/AuxSend.tsx b/packages/app/studio/src/ui/mixer/AuxSend.tsx index 5ffdb5fff..328527cf7 100644 --- a/packages/app/studio/src/ui/mixer/AuxSend.tsx +++ b/packages/app/studio/src/ui/mixer/AuxSend.tsx @@ -14,6 +14,7 @@ import {Colors} from "@opendaw/studio-core" const className = Html.adoptStyleSheet(css, "AuxSend") +/** Constructor options for {@link AuxSend}. */ type Construct = { lifecycle: Lifecycle editing: Editing diff --git a/packages/app/studio/src/ui/mixer/AuxSendGroup.tsx b/packages/app/studio/src/ui/mixer/AuxSendGroup.tsx index c335666b3..bbc5fafb8 100644 --- a/packages/app/studio/src/ui/mixer/AuxSendGroup.tsx +++ b/packages/app/studio/src/ui/mixer/AuxSendGroup.tsx @@ -14,12 +14,14 @@ import {Colors, Project} from "@opendaw/studio-core" const className = Html.adoptStyleSheet(css, "AuxSendGroup") +/** Internal bookkeeping for a rendered send entry. */ type AuxSendEntry = { uuid: UUID.Format element: HTMLElement terminator: Terminator } +/** Props for {@link AuxSendGroup}. */ type Construct = { lifecycle: Lifecycle project: Project diff --git a/packages/app/studio/src/ui/mixer/ChannelOutputSelector.tsx b/packages/app/studio/src/ui/mixer/ChannelOutputSelector.tsx index e71e32245..3be10042f 100644 --- a/packages/app/studio/src/ui/mixer/ChannelOutputSelector.tsx +++ b/packages/app/studio/src/ui/mixer/ChannelOutputSelector.tsx @@ -12,6 +12,7 @@ import {Colors, Project} from "@opendaw/studio-core" const className = Html.adoptStyleSheet(css, "OutputSelector") +/** Props for {@link ChannelOutputSelector}. */ type Construct = { lifecycle: Lifecycle project: Project diff --git a/packages/docs/docs-dev/ui/mixer/routing.md b/packages/docs/docs-dev/ui/mixer/routing.md new file mode 100644 index 000000000..978eff118 --- /dev/null +++ b/packages/docs/docs-dev/ui/mixer/routing.md @@ -0,0 +1,15 @@ +# Routing in the Mixer UI + +Explains how channel strips, sends and output selectors connect audio within the Studio. + +## Channel outputs + +`ChannelOutputSelector` lets users reroute a track's signal to any available bus. The component updates label and icon colors to match the chosen destination and offers quick creation of new busses. + +## Auxiliary sends + +`AuxSendGroup` manages multiple `AuxSend` controls for an audio unit. Each send exposes pan and gain knobs and can target existing or newly created effect busses. + +## Hardware devices + +`AudioOutputDevices` lists discovered browser audio outputs and allows the user to choose the playback device for the session. diff --git a/packages/docs/docs-user/features/mixer.md b/packages/docs/docs-user/features/mixer.md index 7f163baf3..80f548262 100644 --- a/packages/docs/docs-user/features/mixer.md +++ b/packages/docs/docs-user/features/mixer.md @@ -55,3 +55,15 @@ graph LR For a practical example see the [Mixing workflow](../workflows/mixing.md). +## Changing track outputs + +Each channel strip provides an **Output** selector at its base. Use it to route a +track to another bus or directly to a hardware output. The menu lists existing +destinations and also lets you create new busses on the fly. + +### Output devices + +The master channel can target any detected audio device. Open the output menu +and choose from the **Audio Output Devices** list to switch playback to a +different interface such as external speakers or headphones. + diff --git a/packages/docs/sidebarsDev.js b/packages/docs/sidebarsDev.js index bff01e94a..e09df28f6 100644 --- a/packages/docs/sidebarsDev.js +++ b/packages/docs/sidebarsDev.js @@ -212,7 +212,11 @@ module.exports = { "ui/metering/rms-vs-peak", ], }, - "ui/mixer", + { + type: "category", + label: "Mixer", + items: ["ui/mixer", "ui/mixer/routing"], + }, { type: "category", label: "Modular", diff --git a/packages/studio/core-processors/src/AuxSendProcessor.ts b/packages/studio/core-processors/src/AuxSendProcessor.ts index 25bfbcd6d..3d58ee25d 100644 --- a/packages/studio/core-processors/src/AuxSendProcessor.ts +++ b/packages/studio/core-processors/src/AuxSendProcessor.ts @@ -46,7 +46,11 @@ export class AuxSendProcessor extends AudioProcessor implements Processor, Audio /** Clears the output buffer. */ reset(): void {this.#audioOutput.clear()} - /** Exposes the backing adapter for external wiring. */ + /** + * Exposes the backing adapter controlling this send. + * + * @returns adapter providing access to the underlying box parameters + */ get adapter(): AuxSendBoxAdapter {return this.#adapter} /** diff --git a/packages/studio/core-processors/src/ChannelStripProcessor.ts b/packages/studio/core-processors/src/ChannelStripProcessor.ts index 38c8a59d5..9ba1a4d62 100644 --- a/packages/studio/core-processors/src/ChannelStripProcessor.ts +++ b/packages/studio/core-processors/src/ChannelStripProcessor.ts @@ -77,6 +77,11 @@ export class ChannelStripProcessor extends AudioProcessor implements Processor, /** Buffer receiving the processed signal. */ get audioOutput(): AudioBuffer {return this.#audioOutput} + /** + * Handles events dispatched to this processor. + * + * Currently channel strips do not react to events, so the method is a no-op. + */ handleEvent(_event: Event): void {} /** diff --git a/packages/studio/core/src/EffectBox.ts b/packages/studio/core/src/EffectBox.ts index f563be21f..79a64f6b4 100644 --- a/packages/studio/core/src/EffectBox.ts +++ b/packages/studio/core/src/EffectBox.ts @@ -15,7 +15,8 @@ import { * Union of all effect device boxes supported by the studio. * * Effects can be inserted or reached via sends using - * {@link @opendaw/studio-enums#AudioSendRouting | AudioSendRouting}. + * {@link @opendaw/studio-enums#AudioSendRouting | AudioSendRouting}. Unknown + * entries ensure forward compatibility with future devices. * * @public */ diff --git a/packages/studio/core/src/EffectFactories.ts b/packages/studio/core/src/EffectFactories.ts index d6ce8c705..3c83517d5 100644 --- a/packages/studio/core/src/EffectFactories.ts +++ b/packages/studio/core/src/EffectFactories.ts @@ -193,10 +193,15 @@ export namespace EffectFactories { } } + /** Mapping of MIDI effect names to their factory definitions. */ export const MidiNamed = {Arpeggio, Pitch, Zeitgeist} + /** Mapping of audio effect names to their factory definitions. */ export const AudioNamed = {StereoTool, Delay, Reverb, Revamp, Modular} + /** List of all built-in MIDI effect factories. */ export const MidiList: ReadonlyArray> = Object.values(MidiNamed) + /** List of all built-in audio effect factories. */ export const AudioList: ReadonlyArray> = Object.values(AudioNamed) + /** Combined lookup of MIDI and audio effect factories. */ export const MergedNamed = {...MidiNamed, ...AudioNamed} export type MidiEffectKeys = keyof typeof MidiNamed export type AudioEffectKeys = keyof typeof AudioNamed diff --git a/packages/studio/core/src/Mixer.ts b/packages/studio/core/src/Mixer.ts index 11e7d9a53..14814a98d 100644 --- a/packages/studio/core/src/Mixer.ts +++ b/packages/studio/core/src/Mixer.ts @@ -31,6 +31,12 @@ export class Mixer implements Terminable { readonly #virtualSolo: Set readonly #deferUpdate: DeferExec + /** + * Creates a new mixer instance that observes the given channel adapters and + * manages their mute and solo states. + * + * @param audioUnits - collection of channel strip adapters to manage + */ constructor(audioUnits: IndexedBoxAdapterCollection) { this.#states = UUID.newSet(({adapter: {uuid}}) => uuid) this.#solo = new Set()