Channel routing without inserts.

This commit is contained in:
Robin E.R. Davies
2026-04-04 14:51:41 -04:00
parent 1f60e02ce0
commit b21c9d636a
25 changed files with 418 additions and 1284 deletions
@@ -1,13 +1,9 @@
import { Pedalboard, ControlValue } from "./Pedalboard.tsx";
import JackConfiguration from "./Jack.tsx";
export const NONE_CHANNEL: number = -1;
// valid for Aux channel input only.
export const MAIN_OUT_LEFT_CHANNEL: number = -2;
// valid for Aux channel input only.
export const MAIN_OUT_RIGHT_CHANNEL: number = -3;
function isActiveChannel(channels: number[]): boolean {
@@ -19,12 +15,6 @@ function chName(ch: number, maxChannels: number): string {
if (ch === -1) {
return "None";
}
if (ch === MAIN_OUT_LEFT_CHANNEL) {
return "Main Out L";
}
if (ch === MAIN_OUT_RIGHT_CHANNEL) {
return "Main Out R";
}
if (maxChannels <= 2) {
if (ch === 0) {
return "Left";
@@ -83,16 +73,10 @@ export default class ChannelRouterSettings {
mainInputChannels: number[] = [1, 1];
mainOutputChannels: number[] = [0, 1];
mainInserts: Pedalboard = new Pedalboard();
auxInputChannels: number[] = [0, 0];
auxOutputChannels: number[] = [-1, -1];
auxInserts: Pedalboard = new Pedalboard();
sendInputChannels: number[] = [-1, -1];
sendOutputChannels: number[] = [-1, -1];
controlValues: ControlValue[] = [];
// Inserts...
deserialize(obj: any): ChannelRouterSettings {
@@ -101,42 +85,13 @@ export default class ChannelRouterSettings {
this.channelRouterPresetId = obj.channelRouterPresetId ? obj.channelRouterPresetId : -1;
this.mainInputChannels = obj.mainInputChannels.slice();
this.mainOutputChannels = obj.mainOutputChannels.slice();
this.mainInserts = new Pedalboard().deserialize(obj.mainInserts);
this.auxInputChannels = obj.auxInputChannels.slice();
this.auxOutputChannels = obj.auxOutputChannels.slice();
this.auxInserts = new Pedalboard().deserialize(obj.auxInserts);
this.sendInputChannels = obj.sendInputChannels.slice();
this.sendOutputChannels = obj.sendOutputChannels.slice();
this.controlValues = ControlValue.deserializeArray(obj.controlValues);
return this;
}
clone() : ChannelRouterSettings {
return new ChannelRouterSettings().deserialize(this);
}
getControlValue(symbol: string): number | null {
for (let control of this.controlValues) {
if (control.key === symbol) {
return control.value;
}
}
return null;
}
setControlValue(symbol: string, value: number): boolean {
for (let control of this.controlValues) {
if (control.key === symbol) {
if (control.value === value) {
return false;
}
control.value = value;
this.controlValues = this.controlValues.slice(); // trigger observers.
return true;
}
}
let newValue = new ControlValue(symbol, value);
this.controlValues.push(newValue);
this.controlValues = this.controlValues.slice(); // trigger observers.
return true;
}
getDescription(jackConfiguration: JackConfiguration): string {
if (!this.configured) {
@@ -163,10 +118,6 @@ export default class ChannelRouterSettings {
channelPairName(this.auxOutputChannels, nOutputs,false);
}
}
if (isActiveChannel(this.sendInputChannels) && isActiveChannel(this.sendOutputChannels)) {
description += " " + ", send: " +channelPairName(this.sendOutputChannels, nOutputs, false)
+ " -> " + channelPairName(this.sendInputChannels, nInputs,true);
}
return description;
}
canEdit(jackConfiguration: JackConfiguration): boolean {
@@ -215,18 +166,10 @@ export default class ChannelRouterSettings {
return false;
}
}
for (let ch of this.sendInputChannels) {
if (ch >= maxInputChannels) {
return false;
}
}
return true;
}
isAuxActive() : boolean {
return isActiveChannel(this.auxInputChannels) && isActiveChannel(this.auxOutputChannels);
}
isSendActive() : boolean{
return isActiveChannel(this.sendInputChannels) && isActiveChannel(this.sendOutputChannels);
}
}
+95 -352
View File
@@ -22,22 +22,18 @@ import { useState } from 'react';
import VuMeter from './VuMeter';
import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
import Divider from '@mui/material/Divider';
import MoreVertIcon from '@mui/icons-material/MoreVert';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import IconButtonEx from './IconButtonEx';
import Button from '@mui/material/Button';
import useWindowSize from "./UseWindowSize";
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import ChannelRouterSettingsHelpDialog from './ChannelRouterSettingsHelpDialog';
import SpeakerIcon from '@mui/icons-material/Speaker';
import MicIcon from '@mui/icons-material/Mic';
import SaveIconOutline from '@mui/icons-material/Save';
import ChannelRouterSettings from './ChannelRouterSettings';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import Typography from '@mui/material/Typography';
import ChannelRouterSettings, { MAIN_OUT_LEFT_CHANNEL, MAIN_OUT_RIGHT_CHANNEL } from './ChannelRouterSettings';
import { Pedalboard } from './Pedalboard';
import DialogEx from './DialogEx';
@@ -58,7 +54,6 @@ export interface ChannelRouterSettingsDialogProps {
enum RouteType {
Main,
Aux,
Send
}
interface ChannelRouterSettingsPreset {
@@ -79,13 +74,8 @@ let factoryRouterPresets: ChannelRouterSettings[] = [
channelRouterPresetId: -2,
mainInputChannels: [0, -1],
mainOutputChannels: [0, -1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: []
})
,
// Input->Stereo out.
@@ -94,70 +84,48 @@ let factoryRouterPresets: ChannelRouterSettings[] = [
channelRouterPresetId: -3,
mainInputChannels: [0, -1],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: []
})
,
// Right->Right
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -4,
mainInputChannels: [1,-1],
mainOutputChannels: [1, -1],
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
})
,
// Right->Stereo out.
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -4,
mainInputChannels: [1,-1],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: [],
})
,
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -5,
mainInputChannels: [1,-1],
mainOutputChannels: [0, -1],
mainInserts: new Pedalboard(),
auxInputChannels: [1,-1],
auxOutputChannels: [1,-1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: [],
mainOutputChannels: [0, 1],
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
})
,
// Right->right, aux: Left->Left .
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -6,
mainInputChannels: [1,-1],
mainOutputChannels: [1,-1],
mainInserts: new Pedalboard(),
auxInputChannels: [0, -1],
auxOutputChannels: [0, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: [],
mainOutputChannels: [1, -1],
auxInputChannels: [0,-1],
auxOutputChannels: [0,-1],
})
,
// Right-Left, re-amp->Right.
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -7,
mainInputChannels: [1,-1],
mainOutputChannels: [0, -1],
mainInserts: new Pedalboard(),
auxInputChannels: [0, -1],
auxInputChannels: [1,-1],
auxOutputChannels: [1,-1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: []
})
,
new ChannelRouterSettings().deserialize({
@@ -165,80 +133,35 @@ let factoryRouterPresets: ChannelRouterSettings[] = [
channelRouterPresetId: -8,
mainInputChannels: [0, -1],
mainOutputChannels: [0, -1],
mainInserts: new Pedalboard(),
auxInputChannels: [1,-1],
auxOutputChannels: [1,-1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: []
})
,
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -9,
mainInputChannels: [0, -1],
mainOutputChannels: [0, -1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [1,-1],
sendOutputChannels: [1,-1],
controlValues: []
mainInputChannels: [1, -1],
mainOutputChannels: [0, 1],
auxInputChannels: [2, 3],
auxOutputChannels: [0, 1],
})
,
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -10,
mainInputChannels: [1,-1],
mainOutputChannels: [1,-1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [0, -1],
sendOutputChannels: [0, -1],
controlValues: []
})
,
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -11,
mainInputChannels: [0, -1],
mainInputChannels: [1, -1],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [0, -1],
auxOutputChannels: [2, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: []
})
,
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -12,
mainInputChannels: [0, -1],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [2, 3],
sendOutputChannels: [2, 3],
controlValues: []
auxInputChannels: [2, 3],
auxOutputChannels: [2, 3],
})
,
];
let cellPortraitInOutDiv: React.CSSProperties = {
width: 80, display: "flex", columnGap: 4, flexDirection: "row", alignItems: "center", justifyContent: "right",
display: "flex", columnGap: 4, flexDirection: "row", alignItems: "center", justifyContent: "right",
};
let cellPortraitSectionHead: React.CSSProperties = {
border: "0px",
paddingTop: 4,
paddingBottom: 4,
paddingLeft: 0,
paddingRight: 12,
width: 50,
@@ -248,9 +171,8 @@ let cellPortraitSectionHead: React.CSSProperties = {
};
let cellPortraitControlStrip: React.CSSProperties = {
border: "0px",
paddingTop: 12,
paddingBottom: 12,
paddingTop: 0,
paddingBottom: 0,
paddingLeft: 0,
paddingRight: 0,
margin: "0px",
@@ -268,6 +190,17 @@ let cellLeft: React.CSSProperties = {
whiteSpace: "nowrap",
verticalAlign: "middle"
};
let cellPortraitLeft: React.CSSProperties = {
border: "0px",
paddingTop: 0,
paddingBottom: 0,
paddingLeft: 4,
paddingRight: 12,
margin: "0px",
textAlign: "left",
whiteSpace: "nowrap",
verticalAlign: "middle"
};
let cellLandscapeTitle: React.CSSProperties = {
border: "0px",
paddingTop: 4,
@@ -279,13 +212,11 @@ let cellLandscapeTitle: React.CSSProperties = {
verticalAlign: "middle"
};
let cellPortraitInOut: React.CSSProperties = {
border: "0px",
paddingTop: 4,
paddingBottom: 4,
paddingLeft: 12,
paddingTop: 0,
paddingBottom: 0,
paddingLeft: 24,
paddingRight: 12,
margin: "0px",
width: 80,
textAlign: "right",
verticalAlign: "middle"
};
@@ -312,8 +243,6 @@ function makeRoutingPresets(audioConfig: JackConfiguration): ChannelRouterSettin
normalizeChannelSelection(preset.mainOutputChannels);
normalizeChannelSelection(preset.auxInputChannels);
normalizeChannelSelection(preset.auxOutputChannels);
normalizeChannelSelection(preset.sendInputChannels);
normalizeChannelSelection(preset.sendOutputChannels);
let newPreset = {
id: preset.channelRouterPresetId,
name: preset.getDescription(audioConfig),
@@ -347,11 +276,6 @@ function MakeChannelMenu(channelCount: number, routeType: RouteType, input: bool
items.push((<MenuItem key={i} value={i} disabled={disallowedSelections.includes(i)}>Ch {i + 1}</MenuItem>));
}
}
if (routeType === RouteType.Aux && input) {
items.push((<MenuItem key={MAIN_OUT_LEFT_CHANNEL} value={MAIN_OUT_LEFT_CHANNEL} >Main Out L</MenuItem>));
items.push((<MenuItem key={MAIN_OUT_RIGHT_CHANNEL} value={MAIN_OUT_RIGHT_CHANNEL} >Main Out R</MenuItem>));
}
return items;
}
@@ -435,7 +359,7 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
onClose();
};
let [windowSize] = useWindowSize();
let landscape = windowSize.width > windowSize.height;
let landscape = windowSize.height < 600;
let fullScreen = windowSize.width < 450 || windowSize.height < 600;
let ChannelSelect = (routeType: RouteType, channelIndex: number, input: boolean, icon: boolean = true) => {
@@ -459,22 +383,12 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
case RouteType.Aux:
channelSelection = input ? settings.auxInputChannels : settings.auxOutputChannels;
break;
case RouteType.Send:
channelSelection = input ? settings.sendInputChannels : settings.sendOutputChannels;
break;
}
value = channelSelection[channelIndex];
if (value >= channelCount) {
value = -1;
}
if (routeType === RouteType.Send) {
if (input) {
disallowedSelections = settings.mainInputChannels.concat(settings.auxInputChannels);
} else {
disallowedSelections = settings.mainOutputChannels.concat(settings.auxOutputChannels);
}
}
if (channelIndex === 1) {
if (channelSelection[0] !== -1) {
disallowedSelections.push(channelSelection[0]);
@@ -515,16 +429,6 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
normalizeChannelSelection(newSettings.auxOutputChannels);
}
break;
case RouteType.Send:
if (input) {
newSettings.sendInputChannels[channelIndex] = newValue;
normalizeChannelSelection(newSettings.sendInputChannels);
} else {
newSettings.sendOutputChannels[channelIndex] = newValue;
normalizeChannelSelection(newSettings.sendOutputChannels);
}
break;
}
if (newSettings.channelRouterPresetId >= 0) {
newSettings.modified = true; // custom.
@@ -544,23 +448,18 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
let instanceId: number;
switch (routeType) {
case RouteType.Main:
instanceId = input ? Pedalboard.START_CONTROL : Pedalboard.MAIN_INSERT_END_CONTROL_ID;
instanceId = input ? Pedalboard.START_CONTROL_ID : Pedalboard.END_CONTROL_ID;
break;
case RouteType.Aux:
instanceId = input ? Pedalboard.AUX_INSERT_START_CONTROL_ID : Pedalboard.AUX_INSERT_END_CONTROL_ID;
instanceId = input ? Pedalboard.AUX_START_CONTROL_ID : Pedalboard.AUX_END_CONTROL_ID;
break;
case RouteType.Send:
instanceId = input ? Pedalboard.SEND_RETURN_CONTROL : Pedalboard.SEND_OUTPUT_CONTROL;
}
return (
<div style={{}} >
<VuMeter instanceId={instanceId}
display={input? "input": "output"}
height={48} />
</div>
);
height={64} displayText={true} />
);
}
let ApplyPresetId = (presetId: number | string | null | undefined) => {
@@ -570,9 +469,6 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
for (let preset of channelRouterPresets) {
if (preset.id === presetId) {
let newPreset = Object.assign(new ChannelRouterSettings(), preset.settings);
// mark the presets as inserts.
newPreset.mainInserts.nextInstanceId = Pedalboard.MAIN_INSERT_INSTANCE_BASE;
newPreset.auxInserts.nextInstanceId = Pedalboard.AUX_INSERT_INSTANCE_BASE;
model.setChannelRouterSettings(newPreset);
return;
}
@@ -586,9 +482,7 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
(preset.settings.mainInputChannels.every((ch) => ch < inputChannels || ch === -1)) &&
(preset.settings.mainOutputChannels.every((ch) => ch < outputChannels || ch === -1)) &&
(preset.settings.auxInputChannels.every((ch) => ch < inputChannels || ch === -1)) &&
(preset.settings.auxOutputChannels.every((ch) => ch < outputChannels || ch === -1)) &&
(preset.settings.sendInputChannels.every((ch) => ch < inputChannels || ch === -1)) &&
(preset.settings.sendOutputChannels.every((ch) => ch < outputChannels || ch === -1))
(preset.settings.auxOutputChannels.every((ch) => ch < outputChannels || ch === -1))
);
}
@@ -612,22 +506,10 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
return items;
}
let handleSave = () => {
};
let PresetSelect = (width: number | string | undefined) => {
return (
<div style={{ display: "flex", flexDirection: "row", alignItems: "center", width: width }}>
<div style={{ flex: "0 0 auto" }}>
<IconButtonEx tooltip="Save current preset"
style={{ flex: "0 0 auto", color: "#FFFFFF" }}
onClick={(e) => { handleSave(); }}
size="large">
<SaveIconOutline style={{ opacity: 0.75 }} color="inherit" />
</IconButtonEx>
</div>
<div style={{ flex: "1 1", display: "relative" }}>
<Select variant="standard" style={{ width: "100%" }} value={settings.channelRouterPresetId}
onChange={(event) => {
@@ -637,16 +519,12 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
{GeneratePresetMenuItems()}
</Select>
</div>
<IconButtonEx tooltip="Presets" aria-label="more-presets" style={{ marginRight: 8 }}>
<MoreVertIcon style={{ opacity: 0.6 }} onClick={() => { }} />
</IconButtonEx>
</div>
)
}
let LandscapeView = () => {
let auxInsertDisabled = !settings.isAuxActive();
return (
<div style={{
display: "flex", flexFlow: "row", alignItems: "center", justifyContent: "center",
@@ -673,17 +551,11 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
<td style={cellLeft}>
{ChannelSelect(RouteType.Main, 0, true)}
</td>
<td rowSpan={2} style={cellLeft}>{Vu(RouteType.Main, true)}</td>
<td rowSpan={2} style={cellLeft}>
<Button variant="outlined" style={{ textTransform: "none", borderRadius: 24 }}>
Inserts
</Button>
</td>
<td rowSpan={2} style={cellLeft}>{Vu(RouteType.Main, false)}</td>
<td rowSpan={3} style={cellLeft}>{Vu(RouteType.Main, true)}</td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Main, 0, false)}
</td>
<td rowSpan={3} style={cellLeft}>{Vu(RouteType.Main, false)}</td>
</tr>
<tr>
<td></td>
@@ -706,20 +578,12 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
<td style={cellLeft}>
{(ChannelSelect(RouteType.Aux, 0, true))}
</td>
<td rowSpan={2} style={cellLeft}>{Vu(RouteType.Aux, true)}</td>
<td rowSpan={2} style={cellLeft}>
<Button variant="outlined" style={{
textTransform: "none", borderRadius: 24,
}}
disabled={auxInsertDisabled}>
Inserts
</Button>
</td>
<td rowSpan={3} style={cellLeft}>{Vu(RouteType.Aux, true)}</td>
<td rowSpan={2} style={cellLeft}>{Vu(RouteType.Aux, false)}</td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Aux, 0, false))}
</td>
<td rowSpan={3} style={cellLeft}>{Vu(RouteType.Aux, false)}</td>
</tr>
<tr>
<td></td>
@@ -730,36 +594,8 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
{(ChannelSelect(RouteType.Aux, 1, false))}
</td>
</tr>
<tr><td colSpan={9} style={{ height: 2 }}></td></tr>
{/* Spacer ---------------- */}
<tr><td colSpan={9} style={{ height: 16 }}></td></tr>
{/* Send ---------------- */}
<tr>
<td rowSpan={1} style={cellLandscapeTitle}>
<Typography variant="body2" color="textSecondary">Send</Typography>
</td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Send, 0, false))}
</td>
<td rowSpan={2} style={cellLeft}>{Vu(RouteType.Send,false)}</td>
<td rowSpan={2} style={cellLeft}>
{/* No button */}
</td>
<td rowSpan={2} style={cellLeft}>{Vu(RouteType.Send,true)}</td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Send, 0, true))}
</td>
</tr>
<tr>
<td></td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Send, 1, false))}
</td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Send, 1, true))}
</td>
</tr>
</tbody>
</table>
@@ -767,97 +603,83 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
);
};
let PortraitView = () => {
let auxInsertDisabled = !settings.isAuxActive();
return (
<div style={{
display: "flex", flexFlow: "row", alignItems: "center", justifyContent: "center",
width: "100%", flexGrow: 0, fontSize: "14px"
}} >
<table style={{ borderCollapse: "collapse" }}>
<table style={{ borderCollapse: "collapse", borderSpacing: 0 }}>
<colgroup>
<col style={{ width: "auto" }} />
<col style={{ width: "auto" }} />
<col style={{ width: "auto" }} />
<col style={{ width: "auto" }} />
<col style={{ width: "auto" }} />
</colgroup>
<tbody>
{/* Main */}
<tr>
<td colSpan={1} style={cellPortraitSectionHead}>
<td colSpan={3} style={cellPortraitSectionHead}>
<Typography variant="body2" color="textSecondary" >Main</Typography>
</td>
<td colSpan={4}>
</td>
</tr>
<tr>
<td style={cellPortraitInOut}>
<td style={cellPortraitInOut} rowSpan={1}>
<div style={cellPortraitInOutDiv}>
<Typography variant="body2" color="textSecondary" >In</Typography>
<MicIcon style={{ verticalAlign: "middle", width: 16, height: 16, opacity: 0.6 }} />
</div>
</td>
<td style={cellLeft}>
<td style={cellPortraitLeft}>
{ChannelSelect(RouteType.Main, 0, true, false)}
</td>
<td style={cellPortraitControlStrip} rowSpan={3}>
{Vu(RouteType.Main,true)}
</td>
<td></td>
</tr>
<tr>
<td></td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Main, 1, true, false)}
</td>
<td></td>
</tr>
<tr>
<td></td>
<td colSpan={4}>
<table>
<tbody>
<tr>
<td style={cellPortraitControlStrip}>{Vu(RouteType.Main,true)}</td>
<td style={cellPortraitControlStrip}>
<div style={{ marginLeft: 8, marginRight: 8 }}>
<Button variant="outlined" style={{ textTransform: "none", borderRadius: 24 }}>
Inserts
</Button>
</div>
</td>
<td style={cellPortraitControlStrip}>{Vu(RouteType.Main,false)}</td>
</tr>
</tbody>
</table>
{(ChannelSelect(RouteType.Main, 1, true, false))}
</td>
</tr>
{/* Spacer */}
<tr>
<td style={cellPortraitInOut}>
<td colSpan={3} style={{ height: 16 }}></td>
</tr>
<tr>
<td style={cellPortraitInOut} rowSpan={1}>
<div style={cellPortraitInOutDiv}>
<Typography variant="body2" color="textSecondary" >Out</Typography>
<SpeakerIcon style={{ verticalAlign: "middle", width: 16, height: 16, opacity: 0.6 }} />
</div>
</td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Main, 0, false, false)}
</td>
<td style={cellPortraitControlStrip} rowSpan={3}>
{Vu(RouteType.Main,false)}</td>
<td></td>
</tr>
<tr>
<td style={cellLeft}>
</td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Main, 1, false, false)}
</td>
<td></td>
</tr>
{/* Spacer ---------------- */}
<tr><td colSpan={5} style={{ height: 16 }}></td></tr>
<tr><td colSpan={3} style={{ height: 16 }}></td></tr>
{/* Aux */}
<tr>
<td colSpan={1} style={cellPortraitSectionHead}>
<td colSpan={3} style={cellPortraitSectionHead}>
<Typography variant="body2" color="textSecondary" >Aux</Typography>
</td>
<td colSpan={4}></td>
</tr>
<tr>
<td style={cellPortraitInOut}>
<div style={cellPortraitInOutDiv}>
<div style={cellPortraitInOutDiv} >
<Typography variant="body2" color="textSecondary" >In</Typography>
<MicIcon style={{ verticalAlign: "middle", width: 16, height: 16, opacity: 0.6 }} />
</div>
@@ -865,39 +687,20 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
<td style={cellLeft}>
{(ChannelSelect(RouteType.Aux, 0, true, false))}
</td>
<td style={cellPortraitControlStrip} rowSpan={3}>{Vu(RouteType.Aux, true)}</td>
</tr>
<tr>
<td></td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Aux, 1, true, false))}
</td>
<td></td>
</tr>
{/* Spacer */}
<tr>
<td colSpan={3} style={{ height: 16 }}></td>
</tr>
<tr>
<td></td>
<td colSpan={4}>
<table>
<tbody>
<tr>
<td style={cellPortraitControlStrip}>{Vu(RouteType.Aux, true)}</td>
<td style={cellPortraitControlStrip}>
<div style={{ marginLeft: 8, marginRight: 8 }}>
<Button variant="outlined" style={{
textTransform: "none", borderRadius: 24,
}}
disabled={auxInsertDisabled}>
Inserts
</Button>
</div>
</td>
<td style={cellPortraitControlStrip}>{Vu(RouteType.Aux, false)}</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style={cellPortraitInOut}>
<td style={cellPortraitInOut} rowSpan={1}>
<div style={cellPortraitInOutDiv}>
<Typography variant="body2" color="textSecondary" >Out</Typography>
<SpeakerIcon style={{ verticalAlign: "middle", width: 16, height: 16, opacity: 0.6 }} />
@@ -906,73 +709,13 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
<td style={cellLeft}>
{ChannelSelect(RouteType.Aux, 0, false, false)}
</td>
<td style={cellPortraitControlStrip} rowSpan={3}>{Vu(RouteType.Aux, false)}</td>
</tr>
<tr>
<td></td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Aux, 1, false, false)}
</td>
<td></td>
</tr>
{/* Spacer ---------------- */}
<tr><td colSpan={5} style={{ height: 16 }}></td></tr>
{/* Send */}
<tr>
<td colSpan={1} style={cellPortraitSectionHead}>
<Typography variant="body2" color="textSecondary" >Send</Typography>
</td>
<td colSpan={4}></td>
</tr>
<tr>
<td style={cellPortraitInOut}>
<div style={cellPortraitInOutDiv}>
<Typography variant="body2" color="textSecondary" >Send</Typography>
<SpeakerIcon style={{ verticalAlign: "middle", width: 16, height: 16, opacity: 0.6 }} />
</div>
</td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Send, 0, false, false))}
</td>
<td style={cellLeft}>
{(ChannelSelect(RouteType.Send, 1, false, false))}
</td>
<td></td>
</tr>
<tr>
<td></td>
<td colSpan={4}>
<table>
<tbody>
<tr>
<td style={cellPortraitControlStrip}>{Vu(RouteType.Send, false)}</td>
<td style={cellPortraitControlStrip}>
<div style={{ marginLeft: 8, marginRight: 8, visibility: "hidden" }}>
<Button variant="outlined" style={{ textTransform: "none", borderRadius: 24 }}>
Inserts
</Button>
</div>
</td>
<td style={cellPortraitControlStrip}>{Vu(RouteType.Send, true)}</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style={cellPortraitInOut}>
<div style={cellPortraitInOutDiv}>
<Typography variant="body2" color="textSecondary" >Return</Typography>
<MicIcon style={{ verticalAlign: "middle", width: 16, height: 16, opacity: 0.6 }} />
</div>
</td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Send, 0, true, false)}
</td>
<td style={cellLeft}>
{ChannelSelect(RouteType.Send, 1, true, false)}
</td>
<td></td>
</tr>
</tbody>
@@ -107,49 +107,23 @@ export default class ChannelRouterSettingsHelpDialog extends ResizeResponsiveCom
<div style={{ fontSize: "0.9em", lineHeight: "18pt" }}>
<p> The Audio Channel Routing Dialog determines how audio signals are processed and routed between input and output audio channels.
</p>
<p>By default, guitar effects processing occurs on the <i>Main</i> route only. Plugins in the main PiPedal window are
applied before any insert plugins that have been added to the <i>Main</i> route. Main insert plugins are
applied globally, regardless of the selected preset or effects in the main PiPedal window. You might
want to add an EQ or reverb plugin here, to allow your presets to be globally adjusted to suit the room
in which you are currently performing.
</p>
<p>Plugins in the main PiPedal window are not applied to the <i>Aux</i> route by default. The Aux route is intended to be
used for
</p>
<p>Guitar effects processing occurs on the <i>Main</i> route only.</p>
<p>The Aux route can be used for a variety of purposes, such as:</p>
<ul>
<li>Passing through a dry (unprocessed) guitar signal that can be recorded by a DAW and
re-amped later during mixing.
</li>
<li>Passing through a vocal mic signal from one of the input channels, perhaps with compression, EQ or
other processing performed by plugins in Aux inserts.
<li>Passing through a vocal mic signal from one of the input channels.
</li>
<li>
Passing through a backing track or other external audio signal from one of the input channels, and then either
Passing through a backing track or other external audio signal from one or two input channels, and then either
mixing it with the processed guitar signal, or passing it out on a dedicated output channel.
</li>
</ul>
<p>However, if "Main Out L" or "Main Out R" is selected as an Aux input channel, then the Aux route will receive the
output of the processed Main route. Main route insrts are not applied
to the Aux route input signal, so you can have an independent set of inserts applied to the Main and Aux output signals.
An example of how one might use this feature: sending the output of the Main route to
a soundboard or PA system without reverb or EQ applied; and then applying reverb and EQ only to the Aux route whose
outputs will be used as inputs to a stage monitor or headphones for the performer.
</p>
<p>If the Main and Aux routes share output channels, then the results of the Main and Output signals are
<p>If the Main and Aux routes share output channels, then the results of the Main and Aux signals are
summed together on those output channels. For stereo mixing, assign the same left and right output
channels to both the Main and Aux routes. If you have a 2x4 or 4x4 audio interface with two guitar input channels
you can also pass through stereo dry signals by configuring Main and Aux input and output channels appropriately.
</p>
<p>The Send route, in conjunction with the TooB Send plugin allows you to send and return audio signals to an external physical device
from within a PiPedal preset. This allows you to integrate external hardware effects into your PiPedal presets.
Connect a cable from the audio interface output <i>Send</i> channel(s) selected here to the input of your
hardware effect, and a cable from the output of your hardware effect to the audio interface's <i>Return</i> channel
assigned here. Then insert the TooB Send plugin into your PiPedal preset. The input of the
TooB Send plugin will be sent to the external hardware effect, and the output the external hardware
effect will be returned to PiPedal at the output of the TooB Send plugin. PiPedal currently supports
only one Send plugin instance per preset; and the Send and Return channels may not be shared with the Main
or Aux routes. Note that you may only use one instance of the TooB Send plugin per preset. The TooB Send plugin
may not be used as a Main or Aux insert effect.
you can also pass through stereo dry signals by configuring Main and Aux input and output channels appropriately.
</p>
</div>
+2 -2
View File
@@ -379,10 +379,10 @@ export const MainPage =
let pedalboard = this.model.pedalboard.get();
if (!pedalboard) return null;
if (selectedId === Pedalboard.START_CONTROL) // synthetic input volume item.
if (selectedId === Pedalboard.START_CONTROL_ID) // synthetic input volume item.
{
return pedalboard.makeStartItem();
} else if (selectedId === Pedalboard.END_CONTROL) // synthetic output volume.
} else if (selectedId === Pedalboard.END_CONTROL_ID) // synthetic output volume.
{
return pedalboard.makeEndItem();
}
+8 -41
View File
@@ -107,8 +107,8 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
}
isSyntheticItem(): boolean {
return this.instanceId === Pedalboard.START_CONTROL
|| this.instanceId === Pedalboard.END_CONTROL;
return this.instanceId === Pedalboard.START_CONTROL_ID
|| this.instanceId === Pedalboard.END_CONTROL_ID;
}
getInstanceId() : number {
if (this.instanceId === undefined)
@@ -357,10 +357,6 @@ export class PedalboardSplitItem extends PedalboardItem {
}
let TWO_POWER_52 = 4503599627370496; // Maximum Javascript integer value.
let TWO_POWER_48 = 281474976710656; // Number of possible instance IDs for Main Pedalboards.
let MAX_INSTANCE_ID = TWO_POWER_48;
export enum InstanceType {
@@ -372,21 +368,11 @@ export enum InstanceType {
export class Pedalboard implements Deserializable<Pedalboard> {
static readonly CHANNEL_ROUTER_CONTROLS_INSTANCE_ID = -4; // Reserved Instance ID for Router Main Inserts.
static readonly CHANNEL_ROUTER_MAIN_INSERT_ID = -5; // Reserved Instance ID for Router Main Inserts.
static readonly CHANNEL_ROUTER_AUX_INSERT_ID = -6; // Reserved Instance ID for Router Aux inserts.
static readonly MAIN_INSERT_INSTANCE_BASE = TWO_POWER_52-2*MAX_INSTANCE_ID;
static readonly AUX_INSERT_INSTANCE_BASE = TWO_POWER_52-1*MAX_INSTANCE_ID;
static readonly START_CONTROL = -2; // synthetic PedalboardItem for input volume.
static readonly END_CONTROL = -3; // synthetic PedalboardItem for output volume.
static readonly SEND_OUTPUT_CONTROL = -4; // synthetic PedalboardItem for send output volume.
static readonly SEND_RETURN_CONTROL = -5; // synthetic PedalboardItem for send return volume.
static readonly MAIN_INSERT_START_CONTROL_ID = Pedalboard.MAIN_INSERT_INSTANCE_BASE + -2 + MAX_INSTANCE_ID;
static readonly MAIN_INSERT_END_CONTROL_ID = Pedalboard.MAIN_INSERT_INSTANCE_BASE + -3 + MAX_INSTANCE_ID;
static readonly AUX_INSERT_START_CONTROL_ID = Pedalboard.AUX_INSERT_INSTANCE_BASE + -2 + MAX_INSTANCE_ID
static readonly AUX_INSERT_END_CONTROL_ID = Pedalboard.AUX_INSERT_INSTANCE_BASE + -3 + MAX_INSTANCE_ID;
static readonly START_CONTROL_ID = -2; // synthetic PedalboardItem for input volume.
static readonly END_CONTROL_ID = -3; // synthetic PedalboardItem for output volume.
static readonly AUX_START_CONTROL_ID = -4;
static readonly AUX_END_CONTROL_ID = -5;
static readonly START_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#Start";
@@ -405,25 +391,6 @@ export class Pedalboard implements Deserializable<Pedalboard> {
return this;
}
static getInstanceTypeFromInstanceId(instanceId: number): InstanceType {
if (instanceId >= Pedalboard.MAIN_INSERT_INSTANCE_BASE) {
return InstanceType.MainInsert;
}
if (instanceId >= Pedalboard.AUX_INSERT_INSTANCE_BASE) {
return InstanceType.AuxInsert;
}
return InstanceType.MainPedalboard;
}
getInstanceType(): InstanceType {
if (this.nextInstanceId >= Pedalboard.MAIN_INSERT_INSTANCE_BASE) {
return InstanceType.MainInsert;
}
if (this.nextInstanceId >= Pedalboard.AUX_INSERT_INSTANCE_BASE) {
return InstanceType.AuxInsert;
}
return InstanceType.MainPedalboard;
}
clone(): Pedalboard {
return new Pedalboard().deserialize(this);
}
@@ -514,7 +481,7 @@ export class Pedalboard implements Deserializable<Pedalboard> {
makeStartItem(): PedalboardItem {
let result = new PedalboardItem();
result.pluginName = "Input";
result.instanceId = Pedalboard.START_CONTROL;
result.instanceId = Pedalboard.START_CONTROL_ID;
result.uri = Pedalboard.START_PEDALBOARD_ITEM_URI;
result.isEnabled = true;
result.controlValues = [new ControlValue("volume_db",this.input_volume_db)];
@@ -524,7 +491,7 @@ export class Pedalboard implements Deserializable<Pedalboard> {
makeEndItem(): PedalboardItem {
let result = new PedalboardItem();
result.pluginName = "Output";
result.instanceId = Pedalboard.END_CONTROL;
result.instanceId = Pedalboard.END_CONTROL_ID;
result.uri = Pedalboard.END_PEDALBOARD_ITEM_URI;
result.isEnabled = true;
result.controlValues = [new ControlValue("volume_db",this.output_volume_db)];
+2 -2
View File
@@ -46,8 +46,8 @@ import {
// import { midiChannelBindingControlFeatureEnabled } from './MidiChannelBinding';
// import CloseIcon from '@mui/icons-material/Close';
const START_CONTROL = Pedalboard.START_CONTROL;
const END_CONTROL = Pedalboard.END_CONTROL;
const START_CONTROL = Pedalboard.START_CONTROL_ID;
const END_CONTROL = Pedalboard.END_CONTROL_ID;
const START_PEDALBOARD_ITEM_URI = Pedalboard.START_PEDALBOARD_ITEM_URI;
+28 -47
View File
@@ -534,7 +534,6 @@ export class PiPedalModel //implements PiPedalModel
jackServerSettings: ObservableProperty<JackServerSettings>
= new ObservableProperty<JackServerSettings>(new JackServerSettings());
channelRouterControlValues: ObservableProperty<ControlValue[]> = new ObservableProperty<ControlValue[]>([]);
channelRouterSettings: ObservableProperty<ChannelRouterSettings> = new ObservableProperty<ChannelRouterSettings>(new ChannelRouterSettings());
wifiConfigSettings: ObservableProperty<WifiConfigSettings> = new ObservableProperty<WifiConfigSettings>(new WifiConfigSettings());
@@ -1752,7 +1751,7 @@ export class PiPedalModel //implements PiPedalModel
for (let i = 0; i < this._controlValueChangeItems.length; ++i) {
let item = this._controlValueChangeItems[i];
if (Pedalboard.START_CONTROL === item.instanceId) {
if (Pedalboard.START_CONTROL_ID === item.instanceId) {
item.onValueChanged("volume_db", volume_db);
}
}
@@ -1779,7 +1778,7 @@ export class PiPedalModel //implements PiPedalModel
}
for (let i = 0; i < this._controlValueChangeItems.length; ++i) {
let item = this._controlValueChangeItems[i];
if (Pedalboard.END_CONTROL === item.instanceId) {
if (Pedalboard.END_CONTROL_ID === item.instanceId) {
item.onValueChanged("volume_db", volume_db);
}
}
@@ -1788,49 +1787,32 @@ export class PiPedalModel //implements PiPedalModel
private lastControlMessageWasSentbyMe = false;
private _setChannelRouterControlValue(key: string, value: number, notifyServer: boolean) : void {
let channelRouterSettings = this.channelRouterSettings.get();
let changed = channelRouterSettings.setControlValue(key, value);
if (changed)
{
this.channelRouterControlValues.set(this.channelRouterSettings.get().controlValues);
if (notifyServer) {
this.lastControlMessageWasSentbyMe = true;
this._setServerControl("setControl", Pedalboard.CHANNEL_ROUTER_CONTROLS_INSTANCE_ID, key, value);
}
}
}
private _setPedalboardControlValue(instanceId: number, key: string, value: number, notifyServer: boolean): void {
let pedalboard = this.pedalboard.get();
if (pedalboard === undefined) throw new PiPedalStateError("Pedalboard not ready.");
if (instanceId == Pedalboard.CHANNEL_ROUTER_CONTROLS_INSTANCE_ID) {
this._setChannelRouterControlValue(key,value,notifyServer);
return;
} else {
let changed: boolean;
let newPedalboard = pedalboard.clone();
let changed: boolean;
let newPedalboard = pedalboard.clone();
if (instanceId === Pedalboard.START_CONTROL && key === "volume_db") {
this._setInputVolume(value, notifyServer);
return;
} else if (instanceId === Pedalboard.END_CONTROL) {
this._setOutputVolume(value, notifyServer);
return;
if (instanceId === Pedalboard.START_CONTROL_ID && key === "volume_db") {
this._setInputVolume(value, notifyServer);
return;
} else if (instanceId === Pedalboard.END_CONTROL_ID) {
this._setOutputVolume(value, notifyServer);
return;
}
let item = newPedalboard.getItem(instanceId);
changed = item.setControlValue(key, value);
if (changed) {
if (notifyServer) {
this.lastControlMessageWasSentbyMe = true;
this._setServerControl("setControl", instanceId, key, value);
}
let item = newPedalboard.getItem(instanceId);
changed = item.setControlValue(key, value);
if (changed) {
if (notifyServer) {
this.lastControlMessageWasSentbyMe = true;
this._setServerControl("setControl", instanceId, key, value);
}
this.setModelPedalboard(newPedalboard);
for (let i = 0; i < this._controlValueChangeItems.length; ++i) {
let item = this._controlValueChangeItems[i];
if (instanceId === item.instanceId) {
item.onValueChanged(key, value);
}
this.setModelPedalboard(newPedalboard);
for (let i = 0; i < this._controlValueChangeItems.length; ++i) {
let item = this._controlValueChangeItems[i];
if (instanceId === item.instanceId) {
item.onValueChanged(key, value);
}
}
}
@@ -2012,10 +1994,10 @@ export class PiPedalModel //implements PiPedalModel
// mouse is down. Don't update EVERYBODY, but we must change
// the control on the running audio plugin.
// TODO: respect "expensive" port attribute.
if (instanceId === Pedalboard.START_CONTROL && key === "volume_db") {
if (instanceId === Pedalboard.START_CONTROL_ID && key === "volume_db") {
this.previewInputVolume(value);
return;
} else if (instanceId === Pedalboard.END_CONTROL) {
} else if (instanceId === Pedalboard.END_CONTROL_ID) {
this.previewOutputVolume(value);
return;
}
@@ -2155,10 +2137,10 @@ export class PiPedalModel //implements PiPedalModel
}
addPedalboardItem(instanceId: number, append: boolean): number {
let pedalboard = this.pedalboard.get();
if (instanceId === Pedalboard.START_CONTROL && append) {
if (instanceId === Pedalboard.START_CONTROL_ID && append) {
instanceId = pedalboard.items[0].instanceId;
append = false;
} else if (instanceId === Pedalboard.END_CONTROL && !append) {
} else if (instanceId === Pedalboard.END_CONTROL_ID && !append) {
instanceId = pedalboard.items[pedalboard.items.length - 1].instanceId;
append = true;
}
@@ -2180,10 +2162,10 @@ export class PiPedalModel //implements PiPedalModel
addPedalboardSplitItem(instanceId: number, append: boolean): number {
let pedalboard = this.pedalboard.get();
if (instanceId === Pedalboard.START_CONTROL && append) {
if (instanceId === Pedalboard.START_CONTROL_ID && append) {
instanceId = pedalboard.items[0].instanceId;
append = false;
} else if (instanceId === Pedalboard.END_CONTROL && !append) {
} else if (instanceId === Pedalboard.END_CONTROL_ID && !append) {
instanceId = pedalboard.items[pedalboard.items.length - 1].instanceId;
append = true;
}
@@ -3817,7 +3799,6 @@ export class PiPedalModel //implements PiPedalModel
setChannelRouterSettings(settings: ChannelRouterSettings) {
this.channelRouterSettings.set(settings);
this.channelRouterControlValues.set(settings.controlValues);
if (this.webSocket) {
this.webSocket.send("setChannelRouterSettings", settings);
}
+2 -2
View File
@@ -1041,9 +1041,9 @@ const PluginControlView =
let pedalboard = this.model.pedalboard.get();
let pedalboardItem: PedalboardItem;
if (this.props.instanceId === Pedalboard.START_CONTROL) {
if (this.props.instanceId === Pedalboard.START_CONTROL_ID) {
pedalboardItem = pedalboard.makeStartItem();
} else if (this.props.instanceId === Pedalboard.END_CONTROL) {
} else if (this.props.instanceId === Pedalboard.END_CONTROL_ID) {
pedalboardItem = pedalboard.makeEndItem();
} else {
pedalboardItem = pedalboard.getItem(this.props.instanceId);
+9 -5
View File
@@ -468,12 +468,16 @@ export const VuMeter =
let height = this.props.height;
let scale = height / DISPLAY_HEIGHT;
return (
<div style={{ height: height, transform: `scale(1.0, ${scale})`, transformOrigin: "top left" }}>
<div className={this.state.isStereo? classes.stereoTextFrame: classes.monoTextFrame}>
{
this.renderVus()
}
<div style={{ display: "flex" , flexFlow: "column nowrap", alignItems: "center" }}>
<div style={{ height: height, transform: `scale(1.0, ${scale})`, transformOrigin: "top left" }}>
<div className={this.state.isStereo? classes.stereoTextFrame: classes.monoTextFrame}>
{
this.renderVus()
}
</div>
</div>
<div ref={this.textRef} className={classes.vuTextFrame}
/>
</div>
);
}