Manifest.json, Channel Router Sync. Alsa device enumeration.
This commit is contained in:
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
@@ -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"
|
||||
}
|
||||
@@ -49,4 +49,5 @@ input[type=number] {
|
||||
|
||||
img {
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user