Manifest.json, Channel Router Sync. Alsa device enumeration.

This commit is contained in:
Robin E.R. Davies
2026-02-13 16:06:10 -05:00
parent cf7f499994
commit 564ed914cc
33 changed files with 2001 additions and 1191 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 27 KiB

+37 -22
View File
@@ -1,24 +1,39 @@
{
"short_name": "PiPedal",
"name": "PiPedal",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
"manifest_version": 3,
"short_name": "PiPedal",
"name": "PiPedal",
"author": "Robin E.R. Davies",
"description": "A web-based client for the PiPedal guitar effects processor.",
"developer": {
"name": "Robin E.R. Davies",
"url": "https://rerdavies.github.io"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"theme_color": "#000000",
"background_color": "#ffffff"
}
"homepage_url": "https://rerdavies.github.io/pipedal",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"theme_color": "#000000",
"display": "standalone",
"display_override": [
"fullscreen",
"standalone",
"minimal-ui",
"browser"
],
"background_color": "#000000"
}
+2 -1
View File
@@ -49,4 +49,5 @@ input[type=number] {
img {
user-select: none;
}
}
+51 -10
View File
@@ -3,24 +3,34 @@ 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 {
if (channels.length < 2) return false;
return channels[1] >= 0 || channels[0] >= 0;
return channels[1] !== -1 || channels[0] !== -1;
}
function chName(ch: number): string {
if (ch === -1) {
return "None";
}
return "Ch " + (ch + 1);
return "Ch" + (ch + 1);
}
function channelPairName(channels: number[], maxChannels: number): string {
function channelPairName(channels: number[], maxChannels: number, input: boolean): string {
if (channels.length !== 2) {
return "Invalid";
}
if (channels[0] === -1 && channels[1] === -1) {
return "None";
}
if (maxChannels === 1) {
return input ? "Input": "Output";
}
if (maxChannels === 2) {
if (channels[0] === 0 && channels[1] === 1) {
@@ -36,13 +46,28 @@ function channelPairName(channels: number[], maxChannels: number): string {
return "Right,Left";
}
}
return chName(channels[0]) + "," + chName(channels[1]);
if (channels[0] === channels[1]) {
return chName(channels[0]);
}
return '[' + chName(channels[0]) + " " + chName(channels[1]) + "]";
}
function arrayEquals(a: number[], b: number[]): boolean {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
export default class ChannelRouterSettings {
configured: boolean = false;
modified: boolean = false;
channelRouterPresetId: number = -1;
mainInputChannels: number[] = [1, 1];
@@ -61,6 +86,7 @@ export default class ChannelRouterSettings {
deserialize(obj: any): ChannelRouterSettings {
this.configured = obj.configured;
this.modified = obj.modified;
this.channelRouterPresetId = obj.channelRouterPresetId ? obj.channelRouterPresetId : -1;
this.mainInputChannels = obj.mainInputChannels.slice();
this.mainOutputChannels = obj.mainOutputChannels.slice();
@@ -73,6 +99,9 @@ export default class ChannelRouterSettings {
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) {
@@ -111,16 +140,21 @@ export default class ChannelRouterSettings {
}
let nInputs = jackConfiguration.inputAudioPorts.length;
let nOutputs = jackConfiguration.outputAudioPorts.length;
let description = channelPairName(this.mainInputChannels, nInputs) + " -> " +
channelPairName(this.mainOutputChannels, nOutputs);
let description = channelPairName(this.mainInputChannels, nInputs,true) + " -> " +
channelPairName(this.mainOutputChannels, nOutputs,false);
if (isActiveChannel(this.auxInputChannels) && isActiveChannel(this.auxOutputChannels))
{
description += " " + "+ re-amp: " + channelPairName(this.auxInputChannels, nInputs) + " -> " +
channelPairName(this.auxOutputChannels, nOutputs);
if (arrayEquals(this.mainInputChannels, this.auxInputChannels))
{
description += ", re-amp -> " + channelPairName(this.auxOutputChannels,nOutputs, false);
} else {
description += " " + ", aux: " + channelPairName(this.auxInputChannels, nInputs,true) + " -> " +
channelPairName(this.auxOutputChannels, nOutputs,false);
}
}
if (isActiveChannel(this.sendInputChannels) && isActiveChannel(this.sendOutputChannels)) {
description += " " + "+ send: " +channelPairName(this.sendOutputChannels, nOutputs)
+ " -> " + channelPairName(this.sendInputChannels, nInputs);
description += " " + ", send: " +channelPairName(this.sendOutputChannels, nOutputs, false)
+ " -> " + channelPairName(this.sendInputChannels, nInputs,true);
}
return description;
}
@@ -128,6 +162,7 @@ export default class ChannelRouterSettings {
return jackConfiguration.isValid;
}
isValid(jackConfiguration: JackConfiguration): boolean {
if (!this.configured) {
return false;
@@ -176,5 +211,11 @@ export default class ChannelRouterSettings {
}
return true;
}
isAuxActive() : boolean {
return isActiveChannel(this.auxInputChannels) && isActiveChannel(this.auxOutputChannels);
}
isSendActive() : boolean{
return isActiveChannel(this.sendInputChannels) && isActiveChannel(this.sendOutputChannels);
}
}
+348 -164
View File
@@ -31,20 +31,22 @@ 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 DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import Typography from '@mui/material/Typography';
import ChannelRouterSettings from './ChannelRouterSettings';
import { Pedalboard, ControlValue } from './Pedalboard';
import ChannelRouterSettings, { MAIN_OUT_LEFT_CHANNEL, MAIN_OUT_RIGHT_CHANNEL } from './ChannelRouterSettings';
import { Pedalboard } from './Pedalboard';
import DialogEx from './DialogEx';
import { PiPedalModelFactory } from './PiPedalModel';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { JackConfiguration } from './Jack';
let debugInputChannels: number | null = 2;
let debugOutputChannels: number | null = 4;
let debugInputChannels: number | null = 1;
let debugOutputChannels: number | null = 1;
export interface ChannelRouterSettingsDialogProps {
@@ -65,129 +67,168 @@ interface ChannelRouterSettingsPreset {
}
let channelRouterPresets: ChannelRouterSettingsPreset[] = [
{
id: -2, name: "Left -> Left", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -2,
mainInputChannels: [0, 0],
mainOutputChannels: [0, 0],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: [],
})
},
{
id: -3, name: "Left -> Stereo", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -3,
mainInputChannels: [0, 0],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, -1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: [],
})
},
{
id: -4, name: "Right -> Stereo", settings: 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: [],
})
},
{
id: -5, name: "Right -> Left + re-amp", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -5,
mainInputChannels: [1, 1],
mainOutputChannels: [0, 0],
mainInserts: new Pedalboard(),
auxInputChannels: [1, 1],
auxOutputChannels: [1, 1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, - 1],
sendOutputChannels: [-1, -1],
controlValues: [],
})
},
{
id: -6, name: "Left -> Left + send", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -6,
mainInputChannels: [0, 0],
mainOutputChannels: [0, 0],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, - 1],
auxInserts: new Pedalboard(),
sendInputChannels: [1, 1],
sendOutputChannels: [1, 1],
controlValues: [],
})
},
{
id: -7, name: "Right -> Right + send", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -7,
mainInputChannels: [1, 1],
mainOutputChannels: [1, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, - 1],
auxInserts: new Pedalboard(),
sendInputChannels: [0, 0],
sendOutputChannels: [0, 0],
controlValues: [],
})
},
{
id: -8, name: "Left -> Stereo + re-amp", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -8,
mainInputChannels: [0, 0],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [0, 0],
auxOutputChannels: [2, 2],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: [],
let DEFAULT_MONO_TO_MONO_ROUTING_PRESET = -2; // corresponds to Input->Output.
let DEFAULT_LEFT_TO_STEREO_ROUTING_PRESET = -3; // corresponds to Input->Stereo out.
let DEFAULT_RIGHT_TO_STEREO_ROUTING_PRESET = -4; // corresponds to Right->Stereo out.
})
},
{
id: -9, name: "Left -> Stereo + stereo send", settings: new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -9,
mainInputChannels: [0, 0],
mainOutputChannels: [0, 1],
mainInserts: new Pedalboard(),
auxInputChannels: [-1, -1],
auxOutputChannels: [-1, - 1],
auxInserts: new Pedalboard(),
sendInputChannels: [2, 3],
sendOutputChannels: [2, 3],
controlValues: [],
})
},
let factoryRouterPresets: ChannelRouterSettings[] = [
// Input->Output
new ChannelRouterSettings().deserialize({
configured: true,
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.
new ChannelRouterSettings().deserialize({
configured: true,
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->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: [],
})
,
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: [],
})
,
new ChannelRouterSettings().deserialize({
configured: true,
channelRouterPresetId: -7,
mainInputChannels: [1,-1],
mainOutputChannels: [0, -1],
mainInserts: new Pedalboard(),
auxInputChannels: [0, -1],
auxOutputChannels: [1,-1],
auxInserts: new Pedalboard(),
sendInputChannels: [-1, -1],
sendOutputChannels: [-1, -1],
controlValues: []
})
,
new ChannelRouterSettings().deserialize({
configured: true,
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: []
})
,
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],
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: []
})
,
];
let cellPortraitInOutDiv: React.CSSProperties = {
@@ -248,41 +289,132 @@ let cellPortraitInOut: React.CSSProperties = {
verticalAlign: "middle"
};
function MakeChannelMenu(channelCount: number): React.ReactElement[] {
function normalizeChannelSelection(channelSelection: number[]) {
if (channelSelection.length === 2) {
if (channelSelection[0] === -1) {
channelSelection[0] = channelSelection[1];
channelSelection[1] = -1;
} else {
if (channelSelection[0] === channelSelection[1]) {
channelSelection[1] = -1;
}
}
}
}
function makeRoutingPresets(audioConfig: JackConfiguration): ChannelRouterSettingsPreset[] {
let result: ChannelRouterSettingsPreset[] = [];
for (let preset of factoryRouterPresets) {
if (preset.isValid(audioConfig)) {
normalizeChannelSelection(preset.mainInputChannels);
normalizeChannelSelection(preset.mainOutputChannels);
normalizeChannelSelection(preset.auxInputChannels);
normalizeChannelSelection(preset.auxOutputChannels);
normalizeChannelSelection(preset.sendInputChannels);
normalizeChannelSelection(preset.sendOutputChannels);
let newPreset = {
id: preset.channelRouterPresetId,
name: preset.getDescription(audioConfig),
settings: preset
};
result.push(newPreset);
}
}
return result;
}
function MakeChannelMenu(channelCount: number, routeType: RouteType, input: boolean, disallowedSelections: number[]): React.ReactElement[] {
let items: React.ReactElement[] = [(<MenuItem key={-1} value={-1}>None</MenuItem>)]
if (channelCount === 0) {
return items;
}
if (channelCount === 2) {
items.push((<MenuItem key={0} value={0}>Left</MenuItem>));
items.push((<MenuItem key={1} value={1}>Right</MenuItem>));
if (channelCount === 1) {
if (input) {
items.push((<MenuItem key={0} value={0} disabled={disallowedSelections.includes(0)}>Input</MenuItem>));
} else {
items.push((<MenuItem key={0} value={0} disabled={disallowedSelections.includes(0)}>Output</MenuItem>));
}
} else if (channelCount === 2) {
items.push((<MenuItem key={0} value={0} disabled={disallowedSelections.includes(0)}>Left</MenuItem>));
items.push((<MenuItem key={1} value={1} disabled={disallowedSelections.includes(1)}>Right</MenuItem>));
return items;
} else {
for (let i = 0; i < channelCount; ++i) {
items.push((<MenuItem key={i} value={i} disabled={disallowedSelections.includes(i)}>Ch {i + 1}</MenuItem>));
}
}
for (let i = 0; i < channelCount; ++i) {
items.push((<MenuItem key={i} value={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;
}
function makeDebugConfig(baseConfig: JackConfiguration): JackConfiguration {
let config = new JackConfiguration().deserialize(baseConfig); // clone.
for (let i = config.inputAudioPorts.length; i < (debugInputChannels ?? 0); ++i) {
config.inputAudioPorts.push("ch" + (i + 1));
}
if (config.inputAudioPorts.length > (debugInputChannels ?? 0)) {
config.inputAudioPorts = config.inputAudioPorts.slice(0, debugInputChannels ?? 0);
}
for (let i = config.outputAudioPorts.length; i < (debugOutputChannels ?? 0); ++i) {
config.outputAudioPorts.push("ch" + (i + 1));
}
if (config.outputAudioPorts.length > (debugOutputChannels ?? 0)) {
config.outputAudioPorts = config.outputAudioPorts.slice(0, debugOutputChannels ?? 0);
}
return config;
}
function getChannelRouterSettingsPresetById(presetId: number): ChannelRouterSettings {
for (let preset of factoryRouterPresets) {
if (preset.channelRouterPresetId === presetId) {
return preset.clone();
}
}
throw new Error("Error setting defaults. Preset not found: " + presetId);
}
function GetDefaultChannelRouterSettings(model: PiPedalModel) : ChannelRouterSettings {
let currentSettings = model.channelRouterSettings.get();
if (currentSettings.configured) {
return currentSettings;
}
// we're onboarding the user, so set an appropriate default channel routing preset based on the number of ports on the audio interface.
let jackSettings = model.jackConfiguration.get();
let numInputs = jackSettings.inputAudioPorts.length;
let numOutputs = jackSettings.outputAudioPorts.length;
if (numInputs < 2 || numOutputs < 2) {
currentSettings = getChannelRouterSettingsPresetById(DEFAULT_MONO_TO_MONO_ROUTING_PRESET);
} else if (numInputs === 2 && numOutputs === 2) {
currentSettings = getChannelRouterSettingsPresetById(DEFAULT_RIGHT_TO_STEREO_ROUTING_PRESET);
} else {
currentSettings = getChannelRouterSettingsPresetById(DEFAULT_LEFT_TO_STEREO_ROUTING_PRESET);
}
model.setChannelRouterSettings(currentSettings);
return model.channelRouterSettings.get();
}
function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
//const classes = useStyles();
const { open, onClose } = props;
let model = PiPedalModelFactory.getInstance();
let config = model.jackConfiguration.get();
if (debugInputChannels != null || debugOutputChannels != null) {
config = makeDebugConfig(config);
}
let channelRouterPresets = makeRoutingPresets(config);
const [settings, setSettings] = useState<ChannelRouterSettings>(model.channelRouterSettings.get());
const [controlValues, setControlValues] = useState<ControlValue[]>(model.channelRouterControlValues.get());
const [settings, setSettings] = useState<ChannelRouterSettings>(GetDefaultChannelRouterSettings(model));
const [showHelp, setShowHelp] = useState<boolean>(false);
if (settings) {
}
if (controlValues) {
}
React.useEffect(() => {
if (open) {
@@ -290,13 +422,8 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
setSettings(model.channelRouterSettings.get());
};
model.channelRouterSettings.addOnChangedHandler(handleSettingsChanged);
let handleControlsChanged = () => {
setControlValues(model.channelRouterControlValues.get());
};
model.channelRouterControlValues.addOnChangedHandler(handleControlsChanged);
return () => {
model.channelRouterSettings.removeOnChangedHandler(handleSettingsChanged);
model.channelRouterControlValues.removeOnChangedHandler(handleControlsChanged);
}
} else {
return () => { };
@@ -321,61 +448,94 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
let value: number;
let disallowedSelections: number[] = [];
let channelSelection: number[] = [];
switch (routeType) {
case RouteType.Main:
value = input ? settings.mainInputChannels[channelIndex] : settings.mainOutputChannels[channelIndex];
channelSelection = input ? settings.mainInputChannels : settings.mainOutputChannels;
break;
case RouteType.Aux:
value = input ? settings.auxInputChannels[channelIndex] : settings.auxOutputChannels[channelIndex];
channelSelection = input ? settings.auxInputChannels : settings.auxOutputChannels;
break;
case RouteType.Send:
value = input ? settings.sendInputChannels[channelIndex] : settings.sendOutputChannels[channelIndex];
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]);
}
}
let error = false;
if (routeType === RouteType.Main && channelSelection[0] === -1 && channelSelection[1] === -1) {
error = true;
}
return (
<Select variant="standard" style={{ width: 90 }} value={value}
<Select variant="standard" style={{ width: icon ? 130 : 110 }} value={value}
startAdornment={
icon ? (
input ? (<MicIcon style={{ opacity: 0.6, width: 16, height: 16, marginRight: 4 }} />) :
(<SpeakerIcon style={{ opacity: 0.6, width: 16, height: 16, marginRight: 4 }} />)
) : undefined
}
error={error}
onChange={(event) => {
let newValue = event.target.value as number;
let newSettings = new ChannelRouterSettings().deserialize(settings);
let newSettings = new ChannelRouterSettings().deserialize(settings);
switch (routeType) {
case RouteType.Main:
if (input) {
newSettings.mainInputChannels[channelIndex] = newValue;
normalizeChannelSelection(newSettings.mainInputChannels);
} else {
newSettings.mainOutputChannels[channelIndex] = newValue;
normalizeChannelSelection(newSettings.mainOutputChannels);
}
break;
case RouteType.Aux:
if (input) {
newSettings.auxInputChannels[channelIndex] = newValue;
normalizeChannelSelection(newSettings.auxInputChannels);
} else {
newSettings.auxOutputChannels[channelIndex] = newValue;
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;
}
newSettings.channelRouterPresetId = -1; // custom.
if (newSettings.channelRouterPresetId >= 0) {
newSettings.modified = true; // custom.
} else {
newSettings.modified = true;
newSettings.channelRouterPresetId = -1; // custom.
}
newSettings.configured = true;
model.setChannelRouterSettings(newSettings);
}}
>
{MakeChannelMenu(channelCount)}
{MakeChannelMenu(channelCount, routeType, input, disallowedSelections)}
</Select>
)
}
@@ -437,18 +597,32 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
return items;
}
let handleSave = () => {
};
let PresetSelect = (width: number | string | undefined) => {
return (
<div style={{ display: "flex", flexDirection: "row", marginTop: 2, alignItems: "center" }}>
<Select variant="standard" style={{ width: width }} value={settings.channelRouterPresetId}
onChange={(event) => {
ApplyPresetId(event.target.value);
}}
>
{GeneratePresetMenuItems()}
</Select>
<IconButtonEx tooltip="Presets" aria-label="more-presets">
<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) => {
ApplyPresetId(event.target.value);
}}
>
{GeneratePresetMenuItems()}
</Select>
</div>
<IconButtonEx tooltip="Presets" aria-label="more-presets" style={{ marginRight: 24 }}>
<MoreVertIcon style={{ opacity: 0.6 }} onClick={() => { }} />
</IconButtonEx>
</div>
@@ -457,6 +631,7 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
let LandscapeView = () => {
let auxInsertDisabled = !settings.isAuxActive();
return (
<div style={{
display: "flex", flexFlow: "row", alignItems: "center", justifyContent: "center",
@@ -518,7 +693,11 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
</td>
<td rowSpan={2} style={cellLeft}>{Vu()}</td>
<td rowSpan={2} style={cellLeft}>
<Button variant="outlined" style={{ textTransform: "none", borderRadius: 24 }}>
<Button variant="outlined" style={{
textTransform: "none", borderRadius: 24,
}}
disabled={auxInsertDisabled}>
Inserts
</Button>
</td>
@@ -574,6 +753,7 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
);
};
let PortraitView = () => {
let auxInsertDisabled = !settings.isAuxActive();
return (
<div style={{
display: "flex", flexFlow: "row", alignItems: "center", justifyContent: "center",
@@ -685,7 +865,11 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) {
<td style={cellPortraitControlStrip}>{Vu()}</td>
<td style={cellPortraitControlStrip}>
<div style={{ marginLeft: 8, marginRight: 8 }}>
<Button variant="outlined" style={{ textTransform: "none", borderRadius: 24 }}>
<Button variant="outlined" style={{
textTransform: "none", borderRadius: 24,
}}
disabled={auxInsertDisabled}>
Inserts
</Button>
</div>
@@ -105,15 +105,15 @@ export default class ChannelRouterSettingsHelpDialog extends ResizeResponsiveCom
<DialogContent style={{ minHeight: 96 }}>
<div style={{ fontSize: "0.9em", lineHeight: "18pt" }}>
<p> The Mixer Routing Dialog determines how audio signals are processed and routed between input and output audio channels.
<p> The Audio Channel Routing Dialog determines how audio signals are processed and routed between input and output audio channels.
</p>
<p>Guitar effects processing occurs on the <i>Main</i> route only. Plugins in the main PiPedal window are
<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. The Aux route is intended to be
<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>
<ul>
@@ -128,7 +128,13 @@ export default class ChannelRouterSettingsHelpDialog extends ResizeResponsiveCom
mixing it with the processed guitar signal, or passing it out on a dedicated output channel.
</li>
</ul>
<p>although you may find other creative uses for the Aux channel as well.</p>
<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
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
@@ -142,7 +148,8 @@ export default class ChannelRouterSettingsHelpDialog extends ResizeResponsiveCom
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.
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.
</p>
</div>
+9 -12
View File
@@ -27,6 +27,8 @@ export default class JackServerSettings {
this.rebootRequired = input.rebootRequired;
this.alsaInputDevice = input.alsaInputDevice ?? "";
this.alsaOutputDevice = input.alsaOutputDevice ?? "";
this.alsaInputDeviceName = input.alsaInputDeviceName ?? this.alsaInputDevice;
this.alsaOutputDeviceName = input.alsaOutputDeviceName ?? this.alsaOutputDevice;
this.sampleRate = input.sampleRate;
this.bufferSize = input.bufferSize;
this.numberOfBuffers = input.numberOfBuffers;
@@ -50,6 +52,8 @@ export default class JackServerSettings {
isJackAudio = false;
alsaInputDevice: string = "";
alsaOutputDevice: string = "";
alsaInputDeviceName: string = "";
alsaOutputDeviceName: string = "";
sampleRate = 48000;
bufferSize = 64;
numberOfBuffers = 3;
@@ -74,19 +78,12 @@ export default class JackServerSettings {
return "Not selected";
}
let inDev = this.alsaInputDevice.startsWith("hw:")
? this.alsaInputDevice.substring(3)
: this.alsaInputDevice;
let outDev = this.alsaOutputDevice.startsWith("hw:")
? this.alsaOutputDevice.substring(3)
: this.alsaOutputDevice;
let device: string;
if (inDev === outDev) {
device = inDev;
} else {
device = inDev + "-> " + outDev;
if (this.alsaInputDevice === this.alsaOutputDevice) {
device = this.alsaInputDeviceName;;
}
else {
device = this.alsaInputDeviceName + " -> " + this.alsaOutputDeviceName;
}
return `${device} ${this.sampleRate} ${this.bufferSize}x${this.numberOfBuffers}`;
}
@@ -580,10 +580,20 @@ const JackServerSettingsDialog = withStyles(
this.setState({ suppressDeviceWarning: checked });
localStorage.setItem("suppressSeparateDeviceWarning", checked ? "1" : "0");
}
getDeviceName(deviceId: string): string {
if (!this.state.alsaDevices) return deviceId;
for (let i = 0; i < this.state.alsaDevices.length; ++i) {
if (this.state.alsaDevices[i].id === deviceId) {
return this.state.alsaDevices[i].name;
}
}
return deviceId;
}
handleInputDeviceChanged(e: any) {
const d = e.target.value as string;
let s = this.state.jackServerSettings.clone();
s.alsaInputDevice = d;
s.alsaInputDeviceName = this.getDeviceName(d);
s.valid = false;
let settings = this.applyAlsaDevices(s, this.state.alsaDevices);
this.setState({
@@ -597,6 +607,7 @@ const JackServerSettingsDialog = withStyles(
const d = e.target.value as string;
let s = this.state.jackServerSettings.clone();
s.alsaOutputDevice = d;
s.alsaOutputDeviceName = this.getDeviceName(d);
s.valid = false;
let settings = this.applyAlsaDevices(s, this.state.alsaDevices);
this.setState({