Clean up ToobAmp log messages and rdf:comment's.

This commit is contained in:
Robin E. R. Davies
2024-11-30 22:59:44 -05:00
parent 4a4bd12d38
commit b26bce7850
22 changed files with 620 additions and 384 deletions
Binary file not shown.
+41
View File
@@ -0,0 +1,41 @@
import React, { ReactElement } from 'react';
import Tooltip from "@mui/material/Tooltip"
import { UiControl } from './Lv2Plugin';
import Typography from "@mui/material/Typography";
import Divider from '@mui/material/Divider';
interface ControlTooltipProps {
children: ReactElement,
uiControl: UiControl
}
export default function ControlTooltip(props: ControlTooltipProps) {
let { children, uiControl } = props;
if (uiControl.comment && (uiControl.comment !== uiControl.name)) {
return (
<Tooltip title={(
<React.Fragment>
<Typography variant="caption">{uiControl.name}</Typography>
<Divider />
<Typography variant="caption">{uiControl.comment}</Typography>
</React.Fragment>
)}
placement="top-start" arrow enterDelay={1500} enterNextDelay={1500}
>
{children}
</Tooltip>
);
} else {
return (
<Tooltip title={uiControl.name}
placement="top-start" arrow enterDelay={1500} enterNextDelay={1500}
>
{children}
</Tooltip>
);
}
}
+9 -4
View File
@@ -34,6 +34,7 @@ import ButtonBase from '@mui/material/ButtonBase'
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import {PedalboardItem} from './Pedalboard'; import {PedalboardItem} from './Pedalboard';
import {isDarkMode} from './DarkMode'; import {isDarkMode} from './DarkMode';
import Tooltip from "@mui/material/Tooltip"
export const StandardItemSize = { width: 80, height: 140 } export const StandardItemSize = { width: 80, height: 140 }
@@ -208,10 +209,14 @@ const FilePropertyControl =
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", width: item_width, margin: 8, paddingLeft: 8 }}> <div style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", width: item_width, margin: 8, paddingLeft: 8 }}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" noWrap style={{ <Tooltip title={fileProperty.label} placement="top-start" arrow
width: "100%", enterDelay={1000} enterNextDelay={1000}
textAlign: "start" >
}}> {fileProperty.label}</Typography> <Typography variant="caption" display="block" noWrap style={{
width: "100%",
textAlign: "start"
}}> {fileProperty.label}</Typography>
</Tooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
+10 -7
View File
@@ -288,7 +288,10 @@ export const MainPage =
this.setSelection(selectedId); this.setSelection(selectedId);
let item = this.getPedalboardItem(selectedId); let item = this.getPedalboardItem(selectedId);
if (item != null) { if (item != null) {
if (item.isSplit()) { if (item.isStart() || item.isEnd())
{
// do nothing.
} else if (item.isSplit()) {
let split = item as PedalboardSplitItem; let split = item as PedalboardSplitItem;
if (split.getSplitType() === SplitType.Ab) { if (split.getSplitType() === SplitType.Ab) {
let cv = split.getToggleAbControlValue(); let cv = split.getToggleAbControlValue();
@@ -363,7 +366,7 @@ export const MainPage =
titleBar(pedalboardItem: PedalboardItem | null): React.ReactNode { titleBar(pedalboardItem: PedalboardItem | null): React.ReactNode {
let title = ""; let title = "";
let author = ""; let author = "";
let pluginUri = ""; let infoPluginUri = "";
let presetsUri = ""; let presetsUri = "";
let missing = false; let missing = false;
if (pedalboardItem) { if (pedalboardItem) {
@@ -375,7 +378,7 @@ export const MainPage =
title = pedalboardItem.pluginName ?? "#error"; title = pedalboardItem.pluginName ?? "#error";
author = ""; author = "";
presetsUri = ""; presetsUri = "";
pluginUri = ""; infoPluginUri = "";
} }
else { else {
let uiPlugin = this.model.getUiPlugin(pedalboardItem.uri); let uiPlugin = this.model.getUiPlugin(pedalboardItem.uri);
@@ -386,9 +389,9 @@ export const MainPage =
title = uiPlugin.name; title = uiPlugin.name;
author = uiPlugin.author_name; author = uiPlugin.author_name;
presetsUri = uiPlugin.uri; presetsUri = uiPlugin.uri;
if (uiPlugin.description.length > 20) { // if (uiPlugin.description.length > 20) {
pluginUri = uiPlugin.uri; // }
} infoPluginUri = uiPlugin.uri;
} }
} }
} }
@@ -422,7 +425,7 @@ export const MainPage =
)} )}
</div> </div>
<div style={{ flex: "0 0 auto", verticalAlign: "center" }}> <div style={{ flex: "0 0 auto", verticalAlign: "center" }}>
<PluginInfoDialog plugin_uri={pluginUri} /> <PluginInfoDialog plugin_uri={infoPluginUri} />
</div> </div>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
<PluginPresetSelector pluginUri={presetsUri} instanceId={pedalboardItem?.instanceId ?? 0} <PluginPresetSelector pluginUri={presetsUri} instanceId={pedalboardItem?.instanceId ?? 0}
+204 -144
View File
@@ -26,18 +26,21 @@ import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { PluginType } from './Lv2Plugin'; import { PluginType } from './Lv2Plugin';
import ButtonBase from '@mui/material/ButtonBase'; import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import PluginIcon, {SelectIconUri} from './PluginIcon'; import PluginIcon, { SelectIconUri } from './PluginIcon';
import { SelectHoverBackground } from './SelectHoverBackground'; import { SelectHoverBackground } from './SelectHoverBackground';
import SvgPathBuilder from './SvgPathBuilder'; import SvgPathBuilder from './SvgPathBuilder';
import Draggable from './Draggable' import Draggable from './Draggable'
import Rect from './Rect'; import Rect from './Rect';
import {PiPedalStateError} from './PiPedalError'; import { PiPedalStateError } from './PiPedalError';
import Utility from './Utility'; import Utility from './Utility';
import {isDarkMode} from './DarkMode'; import { isDarkMode } from './DarkMode';
import { import {
Pedalboard, PedalboardItem, PedalboardSplitItem, SplitType Pedalboard, PedalboardItem, PedalboardSplitItem, SplitType
} from './Pedalboard'; } from './Pedalboard';
import { ReactComponent as MidiIcon } from "./svg/ic_midi.svg";
const START_CONTROL = Pedalboard.START_CONTROL; const START_CONTROL = Pedalboard.START_CONTROL;
const END_CONTROL = Pedalboard.END_CONTROL; const END_CONTROL = Pedalboard.END_CONTROL;
@@ -45,8 +48,8 @@ const END_CONTROL = Pedalboard.END_CONTROL;
const START_PEDALBOARD_ITEM_URI = Pedalboard.START_PEDALBOARD_ITEM_URI; const START_PEDALBOARD_ITEM_URI = Pedalboard.START_PEDALBOARD_ITEM_URI;
const END_PEDALBOARD_ITEM_URI = Pedalboard.END_PEDALBOARD_ITEM_URI; const END_PEDALBOARD_ITEM_URI = Pedalboard.END_PEDALBOARD_ITEM_URI;
const ENABLED_CONNECTOR_COLOR = isDarkMode() ? "#CCC": "#666"; const ENABLED_CONNECTOR_COLOR = isDarkMode() ? "#CCC" : "#666";
const DISABLED_CONNECTOR_COLOR = isDarkMode() ? "#666": "#CCC"; const DISABLED_CONNECTOR_COLOR = isDarkMode() ? "#666" : "#CCC";
@@ -57,8 +60,12 @@ const FRAME_SIZE: number = 36;
const STROKE_WIDTH = 3; const STROKE_WIDTH = 3;
const STEREO_STROKE_WIDTH = 6; const STEREO_STROKE_WIDTH = 6;
const SVG_STROKE_WIDTH = "3";
const SVG_STEREO_STROKE_WIDTH = "6"; const I_SVG_STROKE_WIDTH = 3;
const I_SVG_STEREO_STROKE_WIDTH = 6;
const SVG_STROKE_WIDTH = I_SVG_STROKE_WIDTH.toString();
const SVG_STEREO_STROKE_WIDTH = I_SVG_STEREO_STROKE_WIDTH.toString();
@@ -66,9 +73,13 @@ const EMPTY_ICON_URL = "img/fx_empty.svg";
const ERROR_ICON_URL = "img/fx_error.svg"; const ERROR_ICON_URL = "img/fx_error.svg";
const TERMINAL_ICON_URL = "img/fx_terminal.svg"; const TERMINAL_ICON_URL = "img/fx_terminal.svg";
function CalculateConnection(numberOfInputs: number, numberOfOutputs: number) function CalculateConnection(numberOfInputs: number, numberOfOutputs: number) {
{ if (numberOfInputs === 0) {
return numberOfOutputs;
}
if (numberOfOutputs === 0) {
return numberOfInputs;
}
let result = Math.min(numberOfInputs, numberOfOutputs); let result = Math.min(numberOfInputs, numberOfOutputs);
if (result > 2) result = 2; if (result > 2) result = 2;
return result; return result;
@@ -125,12 +136,19 @@ const pedalboardStyles = (theme: Theme) => createStyles({
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
}, },
midiConnectorDecoration: {
position: "absolute",
left: -20,
top: -6,
fill: theme.palette.text.secondary
},
iconFrame: { iconFrame: {
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
position: "relative",
background: theme.palette.background.default, background: theme.palette.background.default,
marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2, marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2,
marginRight: (CELL_WIDTH - FRAME_SIZE) / 2, marginRight: (CELL_WIDTH - FRAME_SIZE) / 2,
@@ -138,7 +156,7 @@ const pedalboardStyles = (theme: Theme) => createStyles({
marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2, marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2,
width: FRAME_SIZE, width: FRAME_SIZE,
height: FRAME_SIZE, height: FRAME_SIZE,
border: isDarkMode()? "1pt #AAA solid": "1pt #666 solid", border: isDarkMode() ? "1pt #AAA solid" : "1pt #666 solid",
borderRadius: 6 borderRadius: 6
}, },
borderlessIconFrame: { borderlessIconFrame: {
@@ -146,7 +164,7 @@ const pedalboardStyles = (theme: Theme) => createStyles({
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
background: "transparent", background: "transparent",
marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2, marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2,
marginRight: (CELL_WIDTH - FRAME_SIZE) / 2, marginRight: (CELL_WIDTH - FRAME_SIZE) / 2,
@@ -227,6 +245,8 @@ class PedalLayout {
numberOfInputs: number = 2; numberOfInputs: number = 2;
numberOfOutputs: number = 2; numberOfOutputs: number = 2;
originalInputs: number = 2;
originalOutputs: number = 2;
pedalItem?: PedalboardItem; pedalItem?: PedalboardItem;
@@ -286,11 +306,17 @@ class PedalLayout {
this.iconUrl = TERMINAL_ICON_URL; this.iconUrl = TERMINAL_ICON_URL;
this.numberOfInputs = 0; this.numberOfInputs = 0;
this.numberOfOutputs = PiPedalModelFactory.getInstance().jackSettings.get().inputAudioPorts.length; this.numberOfOutputs = PiPedalModelFactory.getInstance().jackSettings.get().inputAudioPorts.length;
if (this.numberOfOutputs === 0) {
this.numberOfOutputs = 1;
}
} else if (pedalItem.uri === END_PEDALBOARD_ITEM_URI) { } else if (pedalItem.uri === END_PEDALBOARD_ITEM_URI) {
this.pluginType = PluginType.UtilityPlugin; this.pluginType = PluginType.UtilityPlugin;
this.iconUrl = TERMINAL_ICON_URL; this.iconUrl = TERMINAL_ICON_URL;
this.numberOfInputs = PiPedalModelFactory.getInstance().jackSettings.get().outputAudioPorts.length; this.numberOfInputs = PiPedalModelFactory.getInstance().jackSettings.get().outputAudioPorts.length;
if (this.numberOfInputs === 0) {
this.numberOfInputs = 1;
}
this.numberOfOutputs = 0; this.numberOfOutputs = 0;
} }
else { else {
@@ -299,17 +325,19 @@ class PedalLayout {
this.pluginType = uiPlugin.plugin_type; this.pluginType = uiPlugin.plugin_type;
this.iconUrl = SelectIconUri(uiPlugin.plugin_type); this.iconUrl = SelectIconUri(uiPlugin.plugin_type);
this.name = uiPlugin.label; this.name = uiPlugin.label;
this.numberOfInputs = Math.max(uiPlugin.audio_inputs,2); this.numberOfInputs = Math.min(uiPlugin.audio_inputs, 2);
this.numberOfOutputs = Math.max(uiPlugin.audio_outputs,2); this.numberOfOutputs = Math.min(uiPlugin.audio_outputs, 2);
} else { } else {
// default to empty plugin. // default to empty plugin.
this.pluginType = PluginType.ErrorPlugin; this.pluginType = PluginType.ErrorPlugin;
this.name = pedalItem.pluginName??"#error"; this.name = pedalItem.pluginName ?? "#error";
this.iconUrl = ERROR_ICON_URL; this.iconUrl = ERROR_ICON_URL;
this.numberOfInputs = 2; this.numberOfInputs = 2;
this.numberOfOutputs = 2; this.numberOfOutputs = 2;
} }
} }
this.originalInputs = this.numberOfInputs;
this.originalOutputs = this.numberOfOutputs;
} }
isEmpty(): boolean { isEmpty(): boolean {
return (!this.pedalItem) || this.pedalItem.isEmpty(); return (!this.pedalItem) || this.pedalItem.isEmpty();
@@ -362,8 +390,7 @@ class LayoutParams {
const PedalboardView = const PedalboardView =
withStyles(pedalboardStyles, { withTheme: true })( withStyles(pedalboardStyles, { withTheme: true })(
class extends Component<PedalboardProps, PedalboardState> class extends Component<PedalboardProps, PedalboardState> {
{
model: PiPedalModel; model: PiPedalModel;
frameRef: React.RefObject<HTMLDivElement>; frameRef: React.RefObject<HTMLDivElement>;
@@ -386,15 +413,13 @@ const PedalboardView =
this.handleTouchStart = this.handleTouchStart.bind(this); this.handleTouchStart = this.handleTouchStart.bind(this);
} }
handleTouchStart(e: any) handleTouchStart(e: any) {
{
// just has to exist to allow Draggable to receive // just has to exist to allow Draggable to receive
// touchyMove. :-/ // touchyMove. :-/
} }
onDragEnd(instanceId: number, clientX: number, clientY: number) { onDragEnd(instanceId: number, clientX: number, clientY: number) {
if (!this.props.enableStructureEditing) if (!this.props.enableStructureEditing) {
{
return; return;
} }
if (!this.currentLayout) return; if (!this.currentLayout) return;
@@ -462,9 +487,8 @@ const PedalboardView =
return; return;
} }
} }
let lastBottom = item.bottomChildren[item.bottomChildren.length-1]; let lastBottom = item.bottomChildren[item.bottomChildren.length - 1];
if (clientX >= lastBottom.bounds.right && clientX < item.bounds.right-CELL_WIDTH/2) if (clientX >= lastBottom.bounds.right && clientX < item.bounds.right - CELL_WIDTH / 2) {
{
if (lastBottom.pedalItem) { if (lastBottom.pedalItem) {
this.model.movePedalboardItemAfter(instanceId, lastBottom.pedalItem.instanceId); this.model.movePedalboardItemAfter(instanceId, lastBottom.pedalItem.instanceId);
this.setSelection(instanceId); this.setSelection(instanceId);
@@ -485,8 +509,7 @@ const PedalboardView =
this.setSelection(instanceId); this.setSelection(instanceId);
return; return;
} else { } else {
if (item.pedalItem) if (item.pedalItem) {
{
let margin = (CELL_WIDTH - FRAME_SIZE) / 2; let margin = (CELL_WIDTH - FRAME_SIZE) / 2;
if (clientX < item.bounds.x + margin) { if (clientX < item.bounds.x + margin) {
this.model.movePedalboardItemBefore(instanceId, item.pedalItem.instanceId); this.model.movePedalboardItemBefore(instanceId, item.pedalItem.instanceId);
@@ -513,12 +536,12 @@ const PedalboardView =
} }
componentDidMount() { componentDidMount() {
this.scrollRef.current!.addEventListener("touchstart",this.handleTouchStart, {passive: false}); this.scrollRef.current!.addEventListener("touchstart", this.handleTouchStart, { passive: false });
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged); this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
} }
componentWillUnmount() { componentWillUnmount() {
this.scrollRef.current!.removeEventListener("touchstart",this.handleTouchStart); this.scrollRef.current!.removeEventListener("touchstart", this.handleTouchStart);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged); this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
} }
@@ -578,11 +601,11 @@ const PedalboardView =
topBounds.height = CELL_HEIGHT; topBounds.height = CELL_HEIGHT;
} }
let dyTop = (lp.cy + CELL_HEIGHT / 2)- (topBounds.y + topBounds.height) ;
let dyTop = (lp.cy + CELL_HEIGHT / 2) - (topBounds.y + topBounds.height);
this.offsetLayout_(layoutItem.topChildren, dyTop); this.offsetLayout_(layoutItem.topChildren, dyTop);
topBounds.offset(0, dyTop); topBounds.offset(0, dyTop);
@@ -597,8 +620,8 @@ const PedalboardView =
bottomBounds.x = lp.cx; bottomBounds.width = 0; bottomBounds.x = lp.cx; bottomBounds.width = 0;
bottomBounds.y = lp.cy; bottomBounds.height = CELL_HEIGHT; bottomBounds.y = lp.cy; bottomBounds.height = CELL_HEIGHT;
} }
let dyBottom = (lp.cy+CELL_HEIGHT/2)-bottomBounds.y ; let dyBottom = (lp.cy + CELL_HEIGHT / 2) - bottomBounds.y;
this.offsetLayout_(layoutItem.bottomChildren, dyBottom) this.offsetLayout_(layoutItem.bottomChildren, dyBottom)
bottomBounds.offset(0, dyBottom); bottomBounds.offset(0, dyBottom);
bounds.accumulate(bottomBounds); bounds.accumulate(bottomBounds);
@@ -633,11 +656,10 @@ const PedalboardView =
} }
doLayout(layoutItems: PedalLayout[]): LayoutSize { doLayout(layoutItems: PedalLayout[]): LayoutSize {
const TWO_ROW_HEIGHT = 142 - 14; const TWO_ROW_HEIGHT = 142 - 14;
if (layoutItems.length === 0) if (layoutItems.length === 0) {
{
// if the current pedalboard is empty, reserve display space anyway. // if the current pedalboard is empty, reserve display space anyway.
return {width: 1, height: TWO_ROW_HEIGHT}; return { width: 1, height: TWO_ROW_HEIGHT };
} }
let lp = new LayoutParams(); let lp = new LayoutParams();
@@ -646,9 +668,9 @@ const PedalboardView =
// shift everything down so there are no negative y coordinates. // shift everything down so there are no negative y coordinates.
if (bounds.height < TWO_ROW_HEIGHT) { if (bounds.height < TWO_ROW_HEIGHT) {
let extra = Math.floor((TWO_ROW_HEIGHT - Math.ceil(bounds.height))/2); let extra = Math.floor((TWO_ROW_HEIGHT - Math.ceil(bounds.height)) / 2);
this.offsetLayout_(layoutItems, Math.floor(-bounds.y + extra/2 )); this.offsetLayout_(layoutItems, Math.floor(-bounds.y + extra / 2));
bounds.height += extra; bounds.height += extra;
} else { } else {
@@ -682,15 +704,13 @@ const PedalboardView =
} }
onItemLongClick(event: SyntheticEvent, instanceId?: number): void { onItemLongClick(event: SyntheticEvent, instanceId?: number): void {
if (!instanceId) if (!instanceId) {
{
return; return;
} }
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
if (!this.props.enableStructureEditing) if (!this.props.enableStructureEditing) {
{
this.setSelection(instanceId); this.setSelection(instanceId);
return; return;
} }
@@ -702,6 +722,24 @@ const PedalboardView =
} }
strokeConnector(output: ReactNode[],channels: number,enabled: Boolean,svgPath: string)
{
let color = enabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR;
if (channels === 2) {
output.push((
<path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
));
output.push((
<path key={this.renderKey++} d={svgPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
));
} else if (channels === 1) {
output.push((
<path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STROKE_WIDTH} />
));
}
}
renderConnector(output: ReactNode[], item: PedalLayout, enabled: boolean): void { renderConnector(output: ReactNode[], item: PedalLayout, enabled: boolean): void {
// let classes = this.props.classes; // let classes = this.props.classes;
let x_ = item.bounds.x + CELL_WIDTH / 2; let x_ = item.bounds.x + CELL_WIDTH / 2;
@@ -709,19 +747,35 @@ const PedalboardView =
let numberOfOutputs = item.numberOfOutputs; let numberOfOutputs = item.numberOfOutputs;
let color = enabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR; let color = enabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR;
let stereoCenterColor = this.bgColor; let stereoCenterColor = this.bgColor;
if (item.originalInputs === 0) {
// break the input paths.
let rx = item.bounds.x + CELL_WIDTH / 2 - FRAME_SIZE / 2 - 4;
let ry = y_ - 4;
output.push((
<rect key={this.renderKey++} x={rx} y={ry} width={4} height={8} fill={this.props.theme.palette.background.paper} />
));
}
let svgPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_ + CELL_WIDTH, y_).toString(); let svgPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_ + CELL_WIDTH, y_).toString();
if (numberOfOutputs === 2) { if (numberOfOutputs === 2) {
output.push(( output.push((
<path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STEREO_STROKE_WIDTH} /> <path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
)); ));
output.push(( output.push((
<path key={this.renderKey++} d={svgPath} stroke={stereoCenterColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={svgPath} stroke={stereoCenterColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} else if (numberOfOutputs === 1) { } else if (numberOfOutputs === 1) {
output.push(( output.push((
<path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} else {
output.push((
<path key={this.renderKey++} d={svgPath} stroke={DISABLED_CONNECTOR_COLOR} strokeWidth={SVG_STROKE_WIDTH} />
));
} }
} }
renderSplitConnectors(output: ReactNode[], item: PedalLayout, enabled: boolean, shortSplitOutput: boolean,): void { renderSplitConnectors(output: ReactNode[], item: PedalLayout, enabled: boolean, shortSplitOutput: boolean,): void {
@@ -743,18 +797,18 @@ const PedalboardView =
let bottomStartPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_, yBottom).lineTo(x_ + CELL_WIDTH, yBottom).toString(); let bottomStartPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_, yBottom).lineTo(x_ + CELL_WIDTH, yBottom).toString();
if (item.numberOfInputs === 2 && item.topChildren[0].numberOfInputs === 2) { if (item.numberOfInputs === 2 && item.topChildren[0].numberOfInputs === 2) {
output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />)); output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />));
output.push((<path key={this.renderKey++} d={topStartPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />)); output.push((<path key={this.renderKey++} d={topStartPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />));
} else if (item.numberOfInputs !== 0 && item.topChildren[0].numberOfInputs !== 0) { } else if (item.numberOfInputs !== 0 && item.topChildren[0].numberOfInputs !== 0) {
output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STROKE_WIDTH} />)); output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STROKE_WIDTH} />));
} }
if (item.numberOfInputs === 2 && item.bottomChildren[0].numberOfInputs === 2) { if (item.numberOfInputs === 2 && item.bottomChildren[0].numberOfInputs === 2) {
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />)); output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />));
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />)); output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />));
} else if (item.numberOfInputs !== 0 && item.bottomChildren[0].numberOfInputs !== 0) { } else if (item.numberOfInputs !== 0 && item.bottomChildren[0].numberOfInputs !== 0) {
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STROKE_WIDTH} />)); output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STROKE_WIDTH} />));
} }
let lastTop = item.topChildren[item.topChildren.length - 1]; let lastTop = item.topChildren[item.topChildren.length - 1];
@@ -798,7 +852,7 @@ const PedalboardView =
secondPath = new SvgPathBuilder().moveTo(xTop, yTop).lineTo(xTee, yTop).lineTo(xTee, y_).toString(); secondPath = new SvgPathBuilder().moveTo(xTop, yTop).lineTo(xTee, yTop).lineTo(xTee, y_).toString();
hasThirdPath = true; hasThirdPath = true;
thirdPath= new SvgPathBuilder().moveTo(xTee0,y_).lineTo(xEnd,y_).toString(); thirdPath = new SvgPathBuilder().moveTo(xTee0, y_).lineTo(xEnd, y_).toString();
firstPathEnabled = bottomEnabled; firstPathEnabled = bottomEnabled;
secondPathEnabled = topEnabled; secondPathEnabled = topEnabled;
} else if (bottomPathFirst || (topEnabled && lastTop.numberOfOutputs === 2)) { } else if (bottomPathFirst || (topEnabled && lastTop.numberOfOutputs === 2)) {
@@ -838,26 +892,26 @@ const PedalboardView =
// display stereo strokes with cutoff line. // display stereo strokes with cutoff line.
if (firstPathStereo) { if (firstPathStereo) {
output.push(( output.push((
<path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} /> <path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
)); ));
output.push(( output.push((
<path key={this.renderKey++} d={firstPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={firstPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} else if (!firstPathAbsent) { } else if (!firstPathAbsent) {
output.push(( output.push((
<path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
if (secondPathStereo) { if (secondPathStereo) {
output.push(( output.push((
<path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} /> <path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
)); ));
output.push(( output.push((
<path key={this.renderKey++} d={secondPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={secondPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} else if (!secondPathAbsent) { } else if (!secondPathAbsent) {
output.push(( output.push((
<path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
@@ -865,57 +919,53 @@ const PedalboardView =
// stereo strokes merge. // stereo strokes merge.
if (firstPathStereo) { if (firstPathStereo) {
output.push(( output.push((
<path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} /> <path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
)); ));
} else if (!firstPathAbsent) { } else if (!firstPathAbsent) {
output.push(( output.push((
<path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
if (secondPathStereo) { if (secondPathStereo) {
output.push(( output.push((
<path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} /> <path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
)); ));
} else if (!secondPathAbsent) { } else if (!secondPathAbsent) {
output.push(( output.push((
<path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
// draw stereo inner lines. // draw stereo inner lines.
if (firstPathStereo) { if (firstPathStereo) {
output.push(( output.push((
<path key={this.renderKey++} d={firstPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={firstPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
if (secondPathStereo) { if (secondPathStereo) {
output.push(( output.push((
<path key={this.renderKey++} d={secondPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={secondPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
} }
if (thirdPath != null) if (thirdPath != null) {
{
// stereo output of L/R splitter // stereo output of L/R splitter
output.push(( output.push((
<path key={this.renderKey++} d={thirdPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} /> <path key={this.renderKey++} d={thirdPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
)); ));
output.push(( output.push((
<path key={this.renderKey++} d={thirdPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} /> <path key={this.renderKey++} d={thirdPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
)); ));
} }
} }
getScrollContainer() getScrollContainer() {
{ let el: HTMLElement | undefined | null = this.scrollRef.current;
let el: HTMLElement | undefined | null= this.scrollRef.current;
// actually not here anymore. :-/ It has a reactive definition in MainPage.tsx now. // actually not here anymore. :-/ It has a reactive definition in MainPage.tsx now.
while (el) while (el) {
{ if (el.id === "pedalboardScroll") {
if (el.id === "pedalboardScroll")
{
return el as HTMLDivElement; return el as HTMLDivElement;
} }
el = el.parentElement; el = el.parentElement;
@@ -924,16 +974,24 @@ const PedalboardView =
} }
pedalButton( pedalButton(
instanceId: number, instanceId: number,
iconType: PluginType, iconType: PluginType,
draggable: boolean, draggable: boolean,
enabled: boolean, enabled: boolean,
hasBorder: boolean = true, hasBorder: boolean = true,
pluginNotFound: boolean) pluginNotFound: boolean,
: ReactNode { hasMidiConnector: boolean
)
: ReactNode {
let classes = this.props.classes; let classes = this.props.classes;
return ( return (
<div className={hasBorder? classes.iconFrame : classes.borderlessIconFrame} onContextMenu={(e) => { e.preventDefault(); }}> <div className={hasBorder ? classes.iconFrame : classes.borderlessIconFrame} onContextMenu={(e) => { e.preventDefault(); }}>
{hasMidiConnector && (
<div className={classes.midiConnectorDecoration} >
<MidiIcon style={{ width: 16, height: 16, fill: this.props.theme.palette.text.secondary }} />
</div>
)}
<ButtonBase style={{ width: "100%", height: "100%" }} <ButtonBase style={{ width: "100%", height: "100%" }}
onClick={(e) => { this.onItemClick(e, instanceId); }} onClick={(e) => { this.onItemClick(e, instanceId); }}
@@ -941,10 +999,10 @@ const PedalboardView =
onContextMenu={(e: SyntheticEvent) => { this.onItemLongClick(e, instanceId); }} onContextMenu={(e: SyntheticEvent) => { this.onItemLongClick(e, instanceId); }}
> >
<SelectHoverBackground selected={instanceId === this.props.selectedId} showHover={true} borderRadius={6} > <SelectHoverBackground selected={instanceId === this.props.selectedId} showHover={true} borderRadius={6} >
<Draggable draggable={draggable && (this.props.enableStructureEditing)} getScrollContainer={() => this.getScrollContainer()} <Draggable draggable={draggable && (this.props.enableStructureEditing)} getScrollContainer={() => this.getScrollContainer()}
onDragEnd={(x, y) => { this.onDragEnd(instanceId, x, y) }} onDragEnd={(x, y) => { this.onDragEnd(instanceId, x, y) }}
> >
<PluginIcon pluginType={iconType} size={24} pluginMissing={pluginNotFound} opacity={enabled? 0.99:0.6} /> <PluginIcon pluginType={iconType} size={24} pluginMissing={pluginNotFound} opacity={enabled ? 0.99 : 0.6} />
</Draggable> </Draggable>
</SelectHoverBackground> </SelectHoverBackground>
</ButtonBase> </ButtonBase>
@@ -975,16 +1033,16 @@ const PedalboardView =
let outputs: ReactNode[] = []; let outputs: ReactNode[] = [];
this.renderConnectors(outputs, layoutChain, true, false); this.renderConnectors(outputs, layoutChain, true, false);
return ( return (
<div key="connectors" style={{width: layoutSize.width, height: layoutSize.height, overflow: "hidden"}}> <div key="connectors" style={{ width: layoutSize.width, height: layoutSize.height, overflow: "hidden" }}>
<svg width={layoutSize.width} height={layoutSize.height} <svg width={layoutSize.width} height={layoutSize.height}
xmlns="http://www.w3.org/2000/svg" viewBox={"0 0 " + layoutSize.width + " " + layoutSize.height}> xmlns="http://www.w3.org/2000/svg" viewBox={"0 0 " + layoutSize.width + " " + layoutSize.height}>
<g fill="none"> <g fill="none">
{ {
outputs outputs
} }
</g> </g>
</svg> </svg>
</div> </div>
); );
@@ -1008,7 +1066,7 @@ const PedalboardView =
result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} > result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} >
<div className={classes.splitStart} > <div className={classes.splitStart} >
{this.pedalButton(START_CONTROL, item.pluginType,false,true,false,false)} {this.pedalButton(START_CONTROL, item.pluginType, false, true, false, false, false)}
</div> </div>
</div>); </div>);
break; break;
@@ -1016,7 +1074,7 @@ const PedalboardView =
result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} > result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} >
<div className={classes.splitStart} > <div className={classes.splitStart} >
{this.pedalButton(END_CONTROL, item.pluginType, false,true,false,false)} {this.pedalButton(END_CONTROL, item.pluginType, false, true, false, false, false)}
</div> </div>
</div>); </div>);
break; break;
@@ -1025,7 +1083,7 @@ const PedalboardView =
result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} > result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} >
<div className={classes.splitStart} > <div className={classes.splitStart} >
{this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), false,true,true,false)} {this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), false, true, true, false, false)}
</div> </div>
</div>); </div>);
@@ -1040,10 +1098,18 @@ const PedalboardView =
>{item.name}</Typography> >{item.name}</Typography>
</div> </div>
) )
let uiPlugin = this.model.getUiPlugin(item.pedalItem?.uri??""); let uiPlugin = this.model.getUiPlugin(item.pedalItem?.uri ?? "");
let pluginMissing = uiPlugin == null; let pluginMissing = uiPlugin == null;
result.push(<div key={this.renderKey++} className={classes.pedalItem} style={{ left: item.bounds.x, top: item.bounds.y }} > result.push(<div key={this.renderKey++} className={classes.pedalItem} style={{ left: item.bounds.x, top: item.bounds.y }} >
{this.pedalButton(item.pedalItem?.instanceId ?? -1, item.pluginType, !item.isEmpty(), item.pedalItem?.isEnabled ?? false,true,pluginMissing)} {this.pedalButton(
item.pedalItem?.instanceId ?? -1,
item.pluginType,
!item.isEmpty(),
item.pedalItem?.isEnabled ?? false,
true,
pluginMissing,
uiPlugin ? ((uiPlugin.has_midi_input !== 0) || (uiPlugin.has_midi_output !== 0)) : false)}
</div>); </div>);
@@ -1090,51 +1156,43 @@ const PedalboardView =
this.markStereoBackward(layoutChain, numberOfOutputs); this.markStereoBackward(layoutChain, numberOfOutputs);
} }
markStereoBackward(layoutChain: PedalLayout[], numberOfOutputs: number) : number markStereoBackward(layoutChain: PedalLayout[], numberOfOutputs: number): number {
{ for (let i = layoutChain.length - 1; i >= 0; --i) {
for (let i = layoutChain.length-1; i >= 0; --i)
{
let item = layoutChain[i]; let item = layoutChain[i];
if (item.isSplitter()) if (item.isSplitter()) {
{
item.numberOfOutputs = CalculateConnection(item.numberOfOutputs, numberOfOutputs) item.numberOfOutputs = CalculateConnection(item.numberOfOutputs, numberOfOutputs)
this.markStereoBackward(item.topChildren,numberOfOutputs); this.markStereoBackward(item.topChildren, numberOfOutputs);
this.markStereoBackward(item.bottomChildren,numberOfOutputs); this.markStereoBackward(item.bottomChildren, numberOfOutputs);
let topInputs = item.topChildren[0].numberOfInputs; let topInputs = item.topChildren[0].numberOfInputs;
let bottomInputs = item.bottomChildren[0].numberOfInputs; let bottomInputs = item.bottomChildren[0].numberOfInputs;
let splitItem = item.pedalItem as PedalboardSplitItem; let splitItem = item.pedalItem as PedalboardSplitItem;
if (splitItem.getSplitType() !== SplitType.Lr) if (splitItem.getSplitType() !== SplitType.Lr) {
{ item.numberOfInputs = CalculateConnection(item.numberOfInputs, Math.max(topInputs, bottomInputs));
item.numberOfInputs = CalculateConnection(item.numberOfInputs, Math.max(topInputs,bottomInputs));
} }
} else if (item.isEnd()) } else if (item.isEnd()) {
{
} else if (item.isStart()) } else if (item.isStart()) {
{ item.numberOfOutputs = CalculateConnection(item.numberOfOutputs, numberOfOutputs);
item.numberOfOutputs = CalculateConnection(item.numberOfOutputs,numberOfOutputs);
return item.numberOfOutputs; return item.numberOfOutputs;
} else if (item.isEmpty()) { } else if (item.isEmpty()) {
if (numberOfOutputs === 0) if (numberOfOutputs === 0) {
{
item.numberOfOutputs = 0; item.numberOfOutputs = 0;
item.numberOfInputs = CalculateConnection(item.numberOfInputs,2); item.numberOfInputs = CalculateConnection(item.numberOfInputs, 2);
} else { } else {
item.numberOfOutputs = CalculateConnection(item.numberOfOutputs,numberOfOutputs); item.numberOfOutputs = CalculateConnection(item.numberOfOutputs, numberOfOutputs);
item.numberOfInputs = CalculateConnection(item.numberOfInputs,numberOfOutputs); item.numberOfInputs = CalculateConnection(item.numberOfInputs, numberOfOutputs);
} }
} else { } else {
item.numberOfOutputs = CalculateConnection(item.numberOfOutputs,numberOfOutputs); item.numberOfOutputs = CalculateConnection(item.numberOfOutputs, numberOfOutputs);
} }
numberOfOutputs = item.numberOfInputs; numberOfOutputs = item.numberOfInputs;
} }
return numberOfOutputs; return numberOfOutputs;
} }
markStereoForward(layoutChain: PedalLayout[],numberOfInputs: number): number markStereoForward(layoutChain: PedalLayout[], numberOfInputs: number): number {
{
if (layoutChain.length === 0) { if (layoutChain.length === 0) {
return numberOfInputs; return numberOfInputs;
} }
@@ -1145,9 +1203,8 @@ const PedalboardView =
item.numberOfInputs = numberOfInputs; item.numberOfInputs = numberOfInputs;
let chainInputs = numberOfInputs; let chainInputs = numberOfInputs;
if (splitter.getSplitType() === SplitType.Lr) if (splitter.getSplitType() === SplitType.Lr) {
{ chainInputs = CalculateConnection(numberOfInputs, 1);
chainInputs = CalculateConnection(numberOfInputs,1);
} }
let topOutputs = this.markStereoForward(item.topChildren, chainInputs); let topOutputs = this.markStereoForward(item.topChildren, chainInputs);
let bottomOutputs = this.markStereoForward(item.bottomChildren, chainInputs); let bottomOutputs = this.markStereoForward(item.bottomChildren, chainInputs);
@@ -1160,28 +1217,32 @@ const PedalboardView =
item.numberOfOutputs = bottomOutputs; item.numberOfOutputs = bottomOutputs;
} }
} else { } else {
item.numberOfOutputs = (topOutputs >= 1 || bottomOutputs >= 1) ? 2: 1; item.numberOfOutputs = (topOutputs >= 1 || bottomOutputs >= 1) ? 2 : 1;
} }
} else if (item.isStart()) } else if (item.isStart()) {
{ item.numberOfOutputs = Math.min(PiPedalModelFactory.getInstance().jackSettings.get().inputAudioPorts.length, 2);
item.numberOfOutputs = Math.min(PiPedalModelFactory.getInstance().jackSettings.get().inputAudioPorts.length,2);
} else if (item.isEnd()) { } else if (item.isEnd()) {
item.numberOfInputs = item.numberOfInputs =
CalculateConnection( CalculateConnection(
Math.min(PiPedalModelFactory.getInstance().jackSettings.get().outputAudioPorts.length,2), Math.min(PiPedalModelFactory.getInstance().jackSettings.get().outputAudioPorts.length, 2),
numberOfInputs); numberOfInputs);
return item.numberOfInputs; return item.numberOfInputs;
} else if (item.isEmpty()) { } else if (item.isEmpty()) {
item.numberOfInputs = numberOfInputs; item.numberOfInputs = numberOfInputs;
if (numberOfInputs === 0) if (numberOfInputs === 0) {
{
item.numberOfOutputs = 2; item.numberOfOutputs = 2;
} else { } else {
item.numberOfOutputs = item.numberOfInputs; item.numberOfOutputs = item.numberOfInputs;
} }
} else { } else {
item.numberOfInputs = CalculateConnection(numberOfInputs,this.getNumberOfInputs(item)); if (item.numberOfInputs === 0) // zero-input plugins merge their output with the input.
item.numberOfOutputs = this.getNumberOfOutputs(item); {
item.numberOfInputs = numberOfInputs;
item.numberOfOutputs = Math.max(item.numberOfOutputs, numberOfInputs);
} else {
item.numberOfInputs = CalculateConnection(numberOfInputs, this.getNumberOfInputs(item));
item.numberOfOutputs = this.getNumberOfOutputs(item);
}
} }
numberOfInputs = item.numberOfOutputs; numberOfInputs = item.numberOfOutputs;
} }
@@ -1196,21 +1257,20 @@ const PedalboardView =
let layoutChain = makeChain(this.model, this.state.pedalboard?.items); let layoutChain = makeChain(this.model, this.state.pedalboard?.items);
let start = PedalLayout.Start(); let start = PedalLayout.Start();
let end = PedalLayout.End(); let end = PedalLayout.End();
if (layoutChain.length !== 0) if (layoutChain.length !== 0) {
{
layoutChain.splice(0, 0, start); layoutChain.splice(0, 0, start);
layoutChain.splice(layoutChain.length, 0, end); layoutChain.splice(layoutChain.length, 0, end);
this.markStereoOutputs(layoutChain, 2,2); this.markStereoOutputs(layoutChain, 2, 2);
} }
let layoutSize = this.doLayout(layoutChain); let layoutSize = this.doLayout(layoutChain);
this.currentLayout = layoutChain; // save for mouse processing &c. this.currentLayout = layoutChain; // save for mouse processing &c.
return ( return (
<div className={classes.scrollContainer} ref={this.scrollRef} <div className={classes.scrollContainer} ref={this.scrollRef}
> >
<div className={classes.container} ref={this.frameRef} <div className={classes.container} ref={this.frameRef}
style={{ style={{
width: layoutSize.width, height: layoutSize.height, width: layoutSize.width, height: layoutSize.height,
+7 -4
View File
@@ -33,6 +33,7 @@ import MenuItem from '@mui/material/MenuItem';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { ReactComponent as DialIcon } from './svg/fx_dial.svg'; import { ReactComponent as DialIcon } from './svg/fx_dial.svg';
import { isDarkMode } from './DarkMode'; import { isDarkMode } from './DarkMode';
import ControlTooltip from './ControlTooltip';
const MIN_ANGLE = -135; const MIN_ANGLE = -135;
const MAX_ANGLE = 135; const MAX_ANGLE = 135;
@@ -725,10 +726,12 @@ const PluginControl =
<div ref={this.frameRef} style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", width: item_width, margin: 8 }}> <div ref={this.frameRef} style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-start", width: item_width, margin: 8 }}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", alignSelf:"stretch", marginBottom: 8, marginLeft: isSelect ? 16 : 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", alignSelf:"stretch", marginBottom: 8, marginLeft: isSelect ? 16 : 0, marginRight: 0 }}>
<Typography variant="caption" display="block" noWrap style={{ <ControlTooltip uiControl={control} >
width: "100%", <Typography variant="caption" display="block" noWrap style={{
textAlign: isSelect ? "left" : "center" width: "100%",
}}> {isTrigger ? "\u00A0" : control.name}</Typography> textAlign: isSelect ? "left" : "center"
}}> {isTrigger ? "\u00A0" : control.name}</Typography>
</ControlTooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
+6 -1
View File
@@ -40,6 +40,7 @@ import JsonAtom from './JsonAtom';
import PluginOutputControl from './PluginOutputControl'; import PluginOutputControl from './PluginOutputControl';
import Units from './Units'; import Units from './Units';
import ToobFrequencyResponseView from './ToobFrequencyResponseView'; import ToobFrequencyResponseView from './ToobFrequencyResponseView';
import Tooltip from '@mui/material/Tooltip';
export const StandardItemSize = { width: 80, height: 110 }; export const StandardItemSize = { width: 80, height: 110 };
@@ -553,7 +554,11 @@ const PluginControlView =
result.push(( result.push((
<div key={"ctl" + (this.controlKeyIndex++)} className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}> <div key={"ctl" + (this.controlKeyIndex++)} className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}>
<div className={classes.portGroupTitle}> <div className={classes.portGroupTitle}>
<Typography noWrap variant="caption" >{controlGroup.name}</Typography> <Tooltip title={controlGroup.name}
placement="top-start" arrow enterDelay={1500} enterNextDelay={1500}
>
<Typography noWrap variant="caption" >{controlGroup.name}</Typography>
</Tooltip>
</div> </div>
<div className={classes.portGroupControls} > <div className={classes.portGroupControls} >
{ {
+57 -53
View File
@@ -37,11 +37,10 @@ import { UiPlugin, UiControl } from './Lv2Plugin';
import PluginIcon from './PluginIcon'; import PluginIcon from './PluginIcon';
import { Remark } from 'react-remark'; import { Remark } from 'react-remark';
/* eslint-disable */ /* eslint-disable */
let myTheme: Theme| undefined = undefined; let myTheme: Theme | undefined = undefined;
const styles = (theme: Theme) => const styles = (theme: Theme) => {
{
myTheme = theme; myTheme = theme;
return createStyles({ return createStyles({
root: { root: {
@@ -151,25 +150,26 @@ function makeControls(controls: UiControl[]) {
break; break;
} }
} }
hasComments = true;
if (hasComments) { if (hasComments) {
let trs: React.ReactElement[] = []; let trs: React.ReactElement[] = [];
for (let i = 0; i < controls.length; ++i) { for (let i = 0; i < controls.length; ++i) {
let control = controls[i]; let control = controls[i];
if (!(control.not_on_gui) && control.is_input) if (!(control.not_on_gui) && control.is_input)
trs.push(( trs.push((
<tr> <tr>
<td style={{ verticalAlign: "top" }}> <td style={{ verticalAlign: "top" }}>
<Typography variant="body2" style={{ whiteSpace: "nowrap" }}> <Typography variant="body2" style={{ whiteSpace: "nowrap" }}>
{control.name} {control.name}
</Typography> </Typography>
</td> </td>
<td style={{ paddingLeft: "16px", verticalAlign: "top" }}> <td style={{ paddingLeft: "16px", verticalAlign: "top" }}>
<Typography variant="body2"> <Typography variant="body2">
{control.comment} {control.comment}
</Typography> </Typography>
</td> </td>
</tr > </tr >
)); ));
} }
return ( return (
@@ -235,7 +235,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
<InfoOutlinedIcon className={classes.icon} color='inherit' /> <InfoOutlinedIcon className={classes.icon} color='inherit' />
</IconButton> </IconButton>
{open && ( {open && (
<DialogEx tag="info" onClose={handleClose} open={open} fullWidth maxWidth="md" <DialogEx tag="info" onClose={handleClose} open={open} fullWidth maxWidth="md"
onEnterKey={handleClose} onEnterKey={handleClose}
> >
<MuiDialogTitle > <MuiDialogTitle >
@@ -258,18 +258,18 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
</MuiDialogTitle> </MuiDialogTitle>
<PluginInfoDialogContent dividers style={{ width: "100%", maxHeight: "80%", overflowX: "hidden" }}> <PluginInfoDialogContent dividers style={{ width: "100%", maxHeight: "80%", overflowX: "hidden" }}>
<div style={{ width: "100%", display: "flex", flexFlow: "row", justifyItems: "stretch", flexWrap: "nowrap" }} > <div style={{ width: "100%", display: "flex", flexFlow: "row", justifyItems: "stretch", flexWrap: "nowrap" }} >
<div style={{ flex: "1 1 auto", whiteSpace: "nowrap",minWidth: "auto" }}> <div style={{ flex: "1 1 auto", whiteSpace: "nowrap", minWidth: "auto" }}>
<Typography gutterBottom variant="body2" > <Typography gutterBottom variant="body2" >
Author:&nbsp; Author:&nbsp;
{(plugin.author_homepage !== "") {(plugin.author_homepage !== "")
? (<a href={plugin.author_homepage} target="_blank" rel="noopener noreferrer"> ? (<a href={plugin.author_homepage} target="_blank" rel="noopener noreferrer">
{plugin.author_name} {plugin.author_name}
</a> </a>
) )
: ( : (
<span>{plugin.author_name}</span> <span>{plugin.author_name}</span>
) )
} }
</Typography> </Typography>
</div> </div>
@@ -286,40 +286,44 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
{ {
makeControls(plugin.controls) makeControls(plugin.controls)
} }
<Typography gutterBottom variant="body2" style={{ paddingTop: "1em" }}> {plugin.description.length > 0 && (
Description: <div>
</Typography> <Typography gutterBottom variant="body2" style={{ paddingTop: "1em" }}>
<div style={{ marginLeft: 24, marginTop: 16 }}> Description:
<Remark </Typography>
rehypeReactOptions={{ <div style={{ marginLeft: 24, marginTop: 16 }}>
components: { <Remark
p: (props: any) => { rehypeReactOptions={{
// return ( components: {
// <p className="MuiTypography-root MuiTypography-body2" {...props} /> p: (props: any) => {
// ); // return (
return ( // <p className="MuiTypography-root MuiTypography-body2" {...props} />
<Typography variant="body2" paragraph={true} {...props} /> // );
); return (
<Typography variant="body2" paragraph={true} {...props} />
}, );
code: (props: any) => {
return (<code style={{fontSize: 14}} {...props} />);
},
a: (props: any) => {
return (
<a target="_blank" {...props} />
);
} },
}, code: (props: any) => {
}} return (<code style={{ fontSize: 14 }} {...props} />);
> },
{plugin.description} a: (props: any) => {
</Remark> return (
</div> <a target="_blank" {...props} />
);
}
},
}}
>
{plugin.description}
</Remark>
</div>
</div>
)}
</PluginInfoDialogContent> </PluginInfoDialogContent>
<PluginInfoDialogActions> <PluginInfoDialogActions>
<Button variant="dialogPrimary" autoFocus onClick={handleClose} style={{ width: "130px" }}> <Button variant="dialogPrimary" autoFocus onClick={handleClose} style={{ width: "130px" }}>
OK OK
</Button> </Button>
</PluginInfoDialogActions> </PluginInfoDialogActions>
+98 -103
View File
@@ -24,10 +24,11 @@ import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import { UiControl } from './Lv2Plugin'; import { UiControl } from './Lv2Plugin';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, MonitorPortHandle,State } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, MonitorPortHandle, State } from './PiPedalModel';
import {isDarkMode} from './DarkMode'; import { isDarkMode } from './DarkMode';
import GxTunerControl from './GxTunerControl'; import GxTunerControl from './GxTunerControl';
import Units from './Units'; import Units from './Units';
import ControlTooltip from './ControlTooltip';
@@ -74,8 +75,7 @@ type PluginOutputControlState = {
const PluginOutputControl = const PluginOutputControl =
withStyles(styles, { withTheme: true })( withStyles(styles, { withTheme: true })(
class extends Component<PluginOutputControlProps, PluginOutputControlState> class extends Component<PluginOutputControlProps, PluginOutputControlState> {
{
private model: PiPedalModel; private model: PiPedalModel;
private vuRef: React.RefObject<HTMLDivElement>; private vuRef: React.RefObject<HTMLDivElement>;
@@ -98,10 +98,8 @@ const PluginOutputControl =
this.onConnectionStateChanged = this.onConnectionStateChanged.bind(this); this.onConnectionStateChanged = this.onConnectionStateChanged.bind(this);
} }
private onConnectionStateChanged(state: State) private onConnectionStateChanged(state: State) {
{ if (state === State.Ready) {
if (state === State.Ready)
{
this.unsubscribe(); this.unsubscribe();
this.subscribe(); this.subscribe();
} }
@@ -127,40 +125,36 @@ const PluginOutputControl =
} }
componentDidUpdate(prevProps: Readonly<PluginOutputControlProps>, prevState: Readonly<PluginOutputControlState>, snapshot?: any): void { componentDidUpdate(prevProps: Readonly<PluginOutputControlProps>, prevState: Readonly<PluginOutputControlState>, snapshot?: any): void {
if (prevProps.instanceId !== this.props.instanceId) if (prevProps.instanceId !== this.props.instanceId) {
{
this.unsubscribe(); this.unsubscribe();
this.subscribe(); this.subscribe();
} }
} }
private VU_HEIGHT = 60-4; private VU_HEIGHT = 60 - 4;
private DB_VU_HEIGHT = 60-4; private DB_VU_HEIGHT = 60 - 4;
private animationHandle: number | undefined = undefined; private animationHandle: number | undefined = undefined;
private dbVuTelltale = -96.0; private dbVuTelltale = -96.0;
private dbVuValue = -96.0; private dbVuValue = -96.0;
private dbVuHoldTime = 0.0; private dbVuHoldTime = 0.0;
private requestDbVuAnimation() { private requestDbVuAnimation() {
if (!this.animationHandle) if (!this.animationHandle) {
{
this.animationHandle = requestAnimationFrame( this.animationHandle = requestAnimationFrame(
()=> { () => {
let value = this.dbVuValue; let value = this.dbVuValue;
let range = this.vuMap(value); let range = this.vuMap(value);
let top = range-this.VU_HEIGHT; let top = range - this.VU_HEIGHT;
if (top > 0) top = 0; if (top > 0) top = 0;
if (value > this.dbVuTelltale) if (value > this.dbVuTelltale) {
{
this.dbVuTelltale = value; this.dbVuTelltale = value;
this.dbVuHoldTime = Date.now()+2000; this.dbVuHoldTime = Date.now() + 2000;
} }
if (this.dbVuRef.current) if (this.dbVuRef.current) {
{ this.dbVuRef.current.style.marginTop = top + "px";
this.dbVuRef.current.style.marginTop = top+"px";
} }
this.animationHandle = undefined; this.animationHandle = undefined;
this.updateDbVuTelltale(); this.updateDbVuTelltale();
@@ -171,19 +165,16 @@ const PluginOutputControl =
updateDbVuTelltale() { updateDbVuTelltale() {
let telltaleDone = true; let telltaleDone = true;
if (this.dbVuHoldTime !== 0) if (this.dbVuHoldTime !== 0) {
{
telltaleDone = false; telltaleDone = false;
let t = Date.now(); let t = Date.now();
if (t >= this.dbVuHoldTime) if (t >= this.dbVuHoldTime) {
{ let dt = t - this.dbVuHoldTime;
let dt = t-this.dbVuHoldTime; let telltaleValue = this.dbVuTelltale - 30 * dt / 1000;
let telltaleValue = this.dbVuTelltale-30*dt/1000; if (telltaleValue < -200) {
if (telltaleValue < -200)
{
telltaleValue = -200; telltaleValue = -200;
telltaleDone = true; telltaleDone = true;
} }
this.dbVuTelltale = telltaleValue; this.dbVuTelltale = telltaleValue;
this.dbVuHoldTime = t; this.dbVuHoldTime = t;
@@ -191,49 +182,41 @@ const PluginOutputControl =
let y = this.dbVuMap(this.dbVuTelltale); let y = this.dbVuMap(this.dbVuTelltale);
if (y < 0) y = 0; if (y < 0) y = 0;
if (this.dbVuTelltaleRef.current) if (this.dbVuTelltaleRef.current) {
{
let telltaleStyle = this.dbVuTelltaleRef.current.style; let telltaleStyle = this.dbVuTelltaleRef.current.style;
telltaleStyle.marginTop = y + "px"; telltaleStyle.marginTop = y + "px";
let telltaleColor = "#0C0"; let telltaleColor = "#0C0";
if (this.dbVuTelltale >= 0) if (this.dbVuTelltale >= 0) {
{
telltaleColor = "#F00"; telltaleColor = "#F00";
} else if (this.dbVuTelltale >= -10) } else if (this.dbVuTelltale >= -10) {
{
telltaleColor = "#FF0"; telltaleColor = "#FF0";
} }
telltaleStyle.background = telltaleColor; telltaleStyle.background = telltaleColor;
} }
} }
if (!telltaleDone) if (!telltaleDone) {
{
this.requestDbVuAnimation(); this.requestDbVuAnimation();
} }
} }
private updateValue(value: number) { private updateValue(value: number) {
if (this.lampRef.current) if (this.lampRef.current) {
{
let control = this.props.uiControl; let control = this.props.uiControl;
let range = (value-control.min_value)/(control.max_value-control.min_value); let range = (value - control.min_value) / (control.max_value - control.min_value);
this.lampRef.current.style.opacity = range +""; this.lampRef.current.style.opacity = range + "";
} else if (this.dbVuRef.current) } else if (this.dbVuRef.current) {
{
this.dbVuValue = value; this.dbVuValue = value;
this.requestDbVuAnimation(); this.requestDbVuAnimation();
} }
else if (this.vuRef.current) { else if (this.vuRef.current) {
let control = this.props.uiControl; let control = this.props.uiControl;
let range = (value-control.min_value)/(control.max_value-control.min_value); let range = (value - control.min_value) / (control.max_value - control.min_value);
let top = this.VU_HEIGHT-range*this.VU_HEIGHT; let top = this.VU_HEIGHT - range * this.VU_HEIGHT;
if (!this.animationHandle) if (!this.animationHandle) {
{
this.animationHandle = requestAnimationFrame( this.animationHandle = requestAnimationFrame(
()=> { () => {
if (this.vuRef.current) if (this.vuRef.current) {
{ this.vuRef.current.style.marginTop = top + "px";
this.vuRef.current.style.marginTop = top+"px";
} }
this.animationHandle = undefined; this.animationHandle = undefined;
} }
@@ -284,13 +267,13 @@ const PluginOutputControl =
dbVuMap(value: number): number { dbVuMap(value: number): number {
let control = this.props.uiControl; let control = this.props.uiControl;
let y = (control.max_value-value)*this.DB_VU_HEIGHT/(control.max_value-control.min_value); let y = (control.max_value - value) * this.DB_VU_HEIGHT / (control.max_value - control.min_value);
return y; return y;
} }
vuMap(value: number): number { vuMap(value: number): number {
let control = this.props.uiControl; let control = this.props.uiControl;
let y = (control.max_value-value)*this.VU_HEIGHT/(control.max_value-control.min_value); let y = (control.max_value - value) * this.VU_HEIGHT / (control.max_value - control.min_value);
return y; return y;
} }
@@ -317,20 +300,18 @@ const PluginOutputControl =
item_width = 80; item_width = 80;
} }
} }
if (control.isTuner()) if (control.isTuner()) {
{
item_width = undefined; item_width = undefined;
return ( return (
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}> <div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
<GxTunerControl instanceId={this.props.instanceId} symbolName={control.symbol} <GxTunerControl instanceId={this.props.instanceId} symbolName={control.symbol}
valueIsMidi={ control.units === Units.midiNote} valueIsMidi={control.units === Units.midiNote}
/> />
</div > </div >
); );
} else if (control.isDbVu()) } else if (control.isDbVu()) {
{
item_width = undefined; item_width = undefined;
let redLevel = this.dbVuMap(0); let redLevel = this.dbVuMap(0);
let yellowLevel = this.dbVuMap(-10); let yellowLevel = this.dbVuMap(-10);
@@ -338,22 +319,24 @@ const PluginOutputControl =
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}> <div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" style={{ <ControlTooltip uiControl={control}>
width: "100%", <Typography variant="caption" display="block" style={{
textAlign: "center" width: "100%",
}}> {control.name === "" ? "\u00A0" : control.name}</Typography> textAlign: "center"
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
</ControlTooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
<div style={{ flex: "1 1 auto", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}> <div style={{ flex: "1 1 auto", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
<div style={{ width: 8, height: this.DB_VU_HEIGHT+4, background: "#000", }}> <div style={{ width: 8, height: this.DB_VU_HEIGHT + 4, background: "#000", }}>
<div style={{ height: this.DB_VU_HEIGHT, width: 4, overflow: "hidden", position: "absolute", margin: 2 }}> <div style={{ height: this.DB_VU_HEIGHT, width: 4, overflow: "hidden", position: "absolute", margin: 2 }}>
<div style={{width: 4, height: redLevel,position: "absolute", marginTop: 0, background: "#F00"}} /> <div style={{ width: 4, height: redLevel, position: "absolute", marginTop: 0, background: "#F00" }} />
<div style={{width: 4, height: (yellowLevel-redLevel),position: "absolute", marginTop: redLevel, background: "#CC0"}} /> <div style={{ width: 4, height: (yellowLevel - redLevel), position: "absolute", marginTop: redLevel, background: "#CC0" }} />
<div style={{width: 4, height: (this.DB_VU_HEIGHT-yellowLevel),position: "absolute", marginTop: yellowLevel, background: "#0A0"}} /> <div style={{ width: 4, height: (this.DB_VU_HEIGHT - yellowLevel), position: "absolute", marginTop: yellowLevel, background: "#0A0" }} />
<div ref={this.dbVuRef} style={{ width: 4,position: "absolute", marginTop: 0,height: this.VU_HEIGHT, background: "#000" }} /> <div ref={this.dbVuRef} style={{ width: 4, position: "absolute", marginTop: 0, height: this.VU_HEIGHT, background: "#000" }} />
<div ref={this.dbVuTelltaleRef} style={{ width: 4,position: "absolute", marginTop: 100,height: 3, background: "#C00" }} /> <div ref={this.dbVuTelltaleRef} style={{ width: 4, position: "absolute", marginTop: 100, height: 3, background: "#C00" }} />
</div> </div>
</div> </div>
@@ -369,15 +352,17 @@ const PluginOutputControl =
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}> <div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" style={{ <ControlTooltip uiControl={control}>
width: "100%", <Typography variant="caption" display="block" style={{
textAlign: "center" width: "100%",
}}> {control.name === "" ? "\u00A0" : control.name}</Typography> textAlign: "center"
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
</ControlTooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
<div style={{ flex: "1 1 auto", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}> <div style={{ flex: "1 1 auto", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
<div style={{ width: 8, height: this.VU_HEIGHT+4, background: "#000", }}> <div style={{ width: 8, height: this.VU_HEIGHT + 4, background: "#000", }}>
<div style={{ height: this.VU_HEIGHT, overflow: "hidden", position: "absolute", margin: 2 }}> <div style={{ height: this.VU_HEIGHT, overflow: "hidden", position: "absolute", margin: 2 }}>
<div ref={this.vuRef} style={{ width: 4, height: this.VU_HEIGHT, background: "#0C0", }} /> <div ref={this.vuRef} style={{ width: 4, height: this.VU_HEIGHT, background: "#0C0", }} />
</div> </div>
@@ -394,26 +379,31 @@ const PluginOutputControl =
); );
} else if (control.isLamp()) { } else if (control.isLamp()) {
item_width = undefined; item_width = undefined;
let attachedLamp = control.name === "" || control.name === "\u00A0" ; let attachedLamp = control.name === "" || control.name === "\u00A0";
return ( return (
<div style={{ display: "flex", flexDirection: "column", width: item_width, <div style={{
marginTop: 8, marginBottom: 8, marginRight: 8,marginLeft: (attachedLamp? 0: 8), height: 98 display: "flex", flexDirection: "column", width: item_width,
}}> marginTop: 8, marginBottom: 8, marginRight: 8, marginLeft: (attachedLamp ? 0 : 8), height: 98
}}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" style={{ <ControlTooltip uiControl={control}>
width: "100%", <Typography variant="caption" display="block" style={{
textAlign: "center" width: "100%",
}}> {control.name === "" ? "\u00A0": (control.name)}</Typography> textAlign: "center"
}}> {control.name === "" ? "\u00A0" : (control.name)}</Typography>
</ControlTooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
<div style={{ flex: "1 1 auto", display: "flex", justifyContent: "left", alignItems: "start", flexFlow: "row nowrap" }}> <div style={{ flex: "1 1 auto", display: "flex", justifyContent: "left", alignItems: "start", flexFlow: "row nowrap" }}>
<div style={{ width: 12, height: 12, background: isDarkMode()? "#111" : "#444", borderRadius: 5, position: "relative" }}> <div style={{ width: 12, height: 12, background: isDarkMode() ? "#111" : "#444", borderRadius: 5, position: "relative" }}>
<div ref={this.lampRef} style={{ width: 8, height: 8, <div ref={this.lampRef} style={{
background: (isDarkMode()? "radial-gradient(circle at center, #F00 0, #F00 20%, #333 100%)" width: 8, height: 8,
: "radial-gradient(circle at center, #F44 0, #F44 40%, #644 100%)"), background: (isDarkMode() ? "radial-gradient(circle at center, #F00 0, #F00 20%, #333 100%)"
opacity: 0, borderRadius: 3,margin: 2,position: "absolute" }} /> : "radial-gradient(circle at center, #F44 0, #F44 40%, #644 100%)"),
opacity: 0, borderRadius: 3, margin: 2, position: "absolute"
}} />
</div> </div>
</div> </div>
@@ -429,11 +419,14 @@ const PluginOutputControl =
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}> <div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" style={{ <ControlTooltip uiControl={control}>
width: "100%", <Typography variant="caption" display="block" style={{
textAlign: "left" width: "100%",
}}> {control.name}</Typography> textAlign: "left"
}}> {control.name}</Typography>
</ControlTooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
<div style={{ flex: "1 1 auto", display: "flex", justifyContent: "start", alignItems: "center", flexFlow: "row nowrap" }}> <div style={{ flex: "1 1 auto", display: "flex", justifyContent: "start", alignItems: "center", flexFlow: "row nowrap" }}>
@@ -449,15 +442,17 @@ const PluginOutputControl =
</div > </div >
); );
}else { } else {
return ( return (
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}> <div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
{/* TITLE SECTION */} {/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}> <div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" style={{ <ControlTooltip uiControl={control}>
width: "100%", <Typography variant="caption" display="block" style={{
textAlign: "left" width: "100%",
}}> {control.name}</Typography> textAlign: "left"
}}> {control.name}</Typography>
</ControlTooltip>
</div> </div>
{/* CONTROL SECTION */} {/* CONTROL SECTION */}
+10 -5
View File
@@ -1257,7 +1257,7 @@ namespace pipedal
{ {
message = message =
SS("Device " << alsa_device_name << " in use. The following applications are using your soundcard: " << apps SS("Device " << alsa_device_name << " in use. The following applications are using your soundcard: " << apps
<< ". Stop them as neccesary before trying to restart pipedald."); << ". Stop them as neccesary before trying to pipedald.");
} }
else else
{ {
@@ -1671,11 +1671,16 @@ namespace pipedal
pBuffer[j] = 0; pBuffer[j] = 0;
} }
} }
while (!terminateAudio()) try {
while (!terminateAudio())
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// zero out input buffers.
this->driverHost->OnProcess(this->bufferSize);
}
} catch (const std::exception &e)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
// zero out input buffers.
this->driverHost->OnProcess(this->bufferSize);
} }
} }
this->driverHost->OnAudioTerminated(); this->driverHost->OnAudioTerminated();
+1 -1
View File
@@ -1217,7 +1217,7 @@ private:
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
Lv2Log::error("Fatal error while processing jack audio. (%s)", e.what()); Lv2Log::error("Fatal error while processing realtime audio. (%s)", e.what());
throw; throw;
} }
} }
+1
View File
@@ -18,6 +18,7 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "FilePropertyDirectoryTree.hpp" #include "FilePropertyDirectoryTree.hpp"
#include <filesystem>
using namespace pipedal; using namespace pipedal;
namespace fs = std::filesystem; namespace fs = std::filesystem;
+1
View File
@@ -58,6 +58,7 @@ namespace pipedal {
virtual bool GetRequestStateChangedNotification() const = 0; virtual bool GetRequestStateChangedNotification() const = 0;
virtual void SetRequestStateChangedNotification(bool value) = 0; virtual void SetRequestStateChangedNotification(bool value) = 0;
virtual void PrepareNoInputEffect(int numberOfInputs, size_t maxBufferSize) = 0;
virtual void SetAudioInputBuffer(int index, float *buffer) = 0; virtual void SetAudioInputBuffer(int index, float *buffer) = 0;
virtual void SetAudioOutputBuffer(int index, float*buffer) = 0; virtual void SetAudioOutputBuffer(int index, float*buffer) = 0;
+123 -28
View File
@@ -47,7 +47,6 @@ namespace fs = std::filesystem;
const float BYPASS_TIME_S = 0.1f; const float BYPASS_TIME_S = 0.1f;
static fs::path makeAbsolutePath(const std::filesystem::path &path, const std::filesystem::path &parentPath) static fs::path makeAbsolutePath(const std::filesystem::path &path, const std::filesystem::path &parentPath)
{ {
if (path.is_absolute()) if (path.is_absolute())
@@ -57,7 +56,6 @@ static fs::path makeAbsolutePath(const std::filesystem::path &path, const std::f
return parentPath / path; return parentPath / path;
} }
Lv2Effect::Lv2Effect( Lv2Effect::Lv2Effect(
IHost *pHost_, IHost *pHost_,
const std::shared_ptr<Lv2PluginInfo> &info_, const std::shared_ptr<Lv2PluginInfo> &info_,
@@ -83,9 +81,9 @@ Lv2Effect::Lv2Effect(
this->pathPropertyWriters.push_back(PatchPropertyWriter(instanceId, filePropertyUrid)); this->pathPropertyWriters.push_back(PatchPropertyWriter(instanceId, filePropertyUrid));
} }
} }
for (auto &pathProperty: pedalboardItem.pathProperties_) for (auto &pathProperty : pedalboardItem.pathProperties_)
{ {
SetPathPatchProperty(pathProperty.first,pathProperty.second); SetPathPatchProperty(pathProperty.first, pathProperty.second);
} }
// initialize the atom forge used on the realtime thread. // initialize the atom forge used on the realtime thread.
@@ -112,7 +110,6 @@ Lv2Effect::Lv2Effect(
bundleUriString, bundleUriString,
storagePath); storagePath);
mapPathFeature.Prepare(&(pHost_->GetMapFeature())); mapPathFeature.Prepare(&(pHost_->GetMapFeature()));
mapPathFeature.SetPluginStoragePath(pHost_->GetPluginStoragePath()); mapPathFeature.SetPluginStoragePath(pHost_->GetPluginStoragePath());
if (info->piPedalUI()) if (info->piPedalUI())
@@ -122,10 +119,8 @@ Lv2Effect::Lv2Effect(
{ {
if (!fileProperty->resourceDirectory().empty()) if (!fileProperty->resourceDirectory().empty())
{ {
mapPathFeature.AddResourceFileMapping({ mapPathFeature.AddResourceFileMapping({makeAbsolutePath(fileProperty->resourceDirectory(), bundleUriString),
makeAbsolutePath(fileProperty->resourceDirectory(),bundleUriString), makeAbsolutePath(fileProperty->directory(), pHost_->GetPluginStoragePath())});
makeAbsolutePath(fileProperty->directory(),pHost_->GetPluginStoragePath())
});
} }
} }
} }
@@ -145,7 +140,6 @@ Lv2Effect::Lv2Effect(
this->features.push_back(mapPathFeature.GetMakePathFeature()); this->features.push_back(mapPathFeature.GetMakePathFeature());
this->features.push_back(mapPathFeature.GetFreePathFeature()); this->features.push_back(mapPathFeature.GetFreePathFeature());
this->features.push_back(this->fileBrowserFilesFeature.GetFeature()); this->features.push_back(this->fileBrowserFilesFeature.GetFeature());
this->work_schedule_feature = nullptr; this->work_schedule_feature = nullptr;
@@ -370,15 +364,52 @@ void Lv2Effect::PreparePortIndices()
outputAtomBuffers.resize(outputAtomPortIndices.size()); outputAtomBuffers.resize(outputAtomPortIndices.size());
} }
void Lv2Effect::PrepareNoInputEffect(int numberOfInputs, size_t maxBufferSize)
{
if (outputAudioPortIndices.size() == 0)
{
// pass the input through unmodified.
inputAudioBuffers.resize(std::max((size_t)numberOfInputs, inputAudioPortIndices.size()));
outputAudioBuffers.resize(numberOfOutputs);
}
else if (inputAudioPortIndices.size() == 0)
{
inputAudioBuffers.resize(numberOfInputs);
outputAudioBuffers.resize(std::max((size_t)numberOfInputs, outputAudioPortIndices.size()));
// allocate a working buffer which we will mix with passed-through data.
outputMixBuffers.resize(outputAudioPortIndices.size());
for (size_t i = 0; i < outputMixBuffers.size(); ++i)
{
outputMixBuffers[i].resize(maxBufferSize);
}
// connect the plugin to the mix buffer instead of output buffer.
for (size_t i = 0; i < outputAudioPortIndices.size(); ++i)
{
int pluginIndex = this->outputAudioPortIndices[i];
lilv_instance_connect_port(this->pInstance, pluginIndex, outputMixBuffers[i].data());
}
}
}
void Lv2Effect::SetAudioInputBuffer(int index, float *buffer) void Lv2Effect::SetAudioInputBuffer(int index, float *buffer)
{ {
if (index >= inputAudioPortIndices.size())
{
throw PiPedalArgumentException("Buffer index out of range.");
}
this->inputAudioBuffers[index] = buffer; this->inputAudioBuffers[index] = buffer;
int pluginIndex = this->inputAudioPortIndices[index];
lilv_instance_connect_port(this->pInstance, pluginIndex, buffer); if (inputAudioPortIndices.size() == inputAudioBuffers.size())
{
int pluginIndex = this->inputAudioPortIndices[index];
lilv_instance_connect_port(this->pInstance, pluginIndex, buffer);
}
else
{
// cases: 1->0, 1->1, 2->0, 2->1
if (index < inputAudioPortIndices.size())
{
int pluginIndex = this->inputAudioPortIndices[index];
lilv_instance_connect_port(this->pInstance, pluginIndex, buffer);
}
}
} }
void Lv2Effect::SetAudioInputBuffer(float *left) void Lv2Effect::SetAudioInputBuffer(float *left)
@@ -388,7 +419,7 @@ void Lv2Effect::SetAudioInputBuffer(float *left)
SetAudioInputBuffer(0, left); SetAudioInputBuffer(0, left);
SetAudioInputBuffer(1, left); SetAudioInputBuffer(1, left);
} }
else else if (GetNumberOfInputAudioPorts() != 0) /// yyx MIXING!
{ {
SetAudioInputBuffer(0, left); SetAudioInputBuffer(0, left);
} }
@@ -400,7 +431,7 @@ void Lv2Effect::SetAudioInputBuffers(float *left, float *right)
{ {
SetAudioInputBuffer(0, left); SetAudioInputBuffer(0, left);
} }
else else if (GetNumberOfInputAudioPorts() > 1)
{ {
SetAudioInputBuffer(0, left); SetAudioInputBuffer(0, left);
SetAudioInputBuffer(1, right); SetAudioInputBuffer(1, right);
@@ -410,8 +441,15 @@ void Lv2Effect::SetAudioInputBuffers(float *left, float *right)
void Lv2Effect::SetAudioOutputBuffer(int index, float *buffer) void Lv2Effect::SetAudioOutputBuffer(int index, float *buffer)
{ {
this->outputAudioBuffers[index] = buffer; this->outputAudioBuffers[index] = buffer;
int pluginIndex = this->outputAudioPortIndices[index];
lilv_instance_connect_port(pInstance, pluginIndex, buffer); if (this->inputAudioPortIndices.size() != 0) // i.e. we're not mixing a zero-input control
{
if ((size_t)index < this->inputAudioPortIndices.size())
{
int pluginIndex = this->outputAudioPortIndices[index];
lilv_instance_connect_port(pInstance, pluginIndex, buffer);
}
}
} }
int Lv2Effect::GetControlIndex(const std::string &key) const int Lv2Effect::GetControlIndex(const std::string &key) const
@@ -452,7 +490,7 @@ void Lv2Effect::Activate()
void Lv2Effect::AssignUnconnectedPorts() void Lv2Effect::AssignUnconnectedPorts()
{ {
for (int i = 0; i < this->GetNumberOfInputAudioPorts(); ++i) for (size_t i = 0; i < this->inputAudioPortIndices.size(); ++i)
{ {
if (GetAudioInputBuffer(i) == nullptr) if (GetAudioInputBuffer(i) == nullptr)
{ {
@@ -462,14 +500,16 @@ void Lv2Effect::AssignUnconnectedPorts()
lilv_instance_connect_port(pInstance, pluginIndex, buffer); lilv_instance_connect_port(pInstance, pluginIndex, buffer);
} }
} }
for (int i = 0; i < this->GetNumberOfOutputAudioPorts(); ++i)
{
if (GetAudioOutputBuffer(i) == nullptr)
{
int pluginIndex = this->outputAudioPortIndices[i];
float *buffer = bufferPool.AllocateBuffer<float>(pHost->GetMaxAudioBufferSize()); if (this->inputAudioPortIndices.size() != 0) // i.e. not using a mix buffer.
lilv_instance_connect_port(pInstance, pluginIndex, buffer); {
for (size_t i = 0; i < this->outputAudioPortIndices.size(); ++i)
{
if (GetAudioOutputBuffer(i) == nullptr)
{
float *buffer = bufferPool.AllocateBuffer<float>(pHost->GetMaxAudioBufferSize());
int pluginIndex = this->outputAudioPortIndices[i];
}
} }
} }
for (int i = 0; i < this->GetNumberOfInputAtomPorts(); ++i) for (int i = 0; i < this->GetNumberOfInputAtomPorts(); ++i)
@@ -529,6 +569,61 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff
// relay worker response // relay worker response
worker->EmitResponses(); worker->EmitResponses();
} }
// for zero-input plugins, mix the plugin output with the input signal.
if (this->inputAudioPortIndices.size() == 0)
{
// mix a zero input controls into the output buffer using a triangular mix curve.
float pluginLevel = std::max(1.0f, this->zeroInputMix * 2);
float inputLevel = std::max(1.0f, (1 - this->zeroInputMix) * 2);
// case
// 1 plugin output into 1 output.
// 2 plugin outputs into 2 outputs.
if (this->outputAudioBuffers.size() == this->outputMixBuffers.size())
{
for (size_t i = 0; i < this->outputMixBuffers.size(); ++i)
{
float *__restrict input;
if (i >= this->inputAudioBuffers.size()) {
if (this->inputAudioBuffers.size() == 0)
{
break;
}
input = this->inputAudioBuffers[0];
} else {
input = this->inputAudioBuffers[i];
}
float *__restrict pluginOutput = this->outputMixBuffers[i].data();
float *__restrict finalOutput = this->outputAudioBuffers[i];
for (uint32_t i = 0; i < samples; ++i)
{
finalOutput[i] = input[i] * inputLevel + pluginOutput[i] * pluginLevel;
}
}
}
else if (this->outputAudioPortIndices.size() == 1 && this->outputAudioBuffers.size() == 2)
{
// 1 plugin output into 2 outputs.
float *__restrict pluginOutput = this->outputMixBuffers[0].data();
for (size_t i = 0; i < this->outputMixBuffers.size(); ++i)
{
float *__restrict input = this->inputAudioBuffers[i];
float *__restrict finalOutput = this->outputAudioBuffers[i];
for (uint32_t i = 0; i < samples; ++i)
{
finalOutput[i] = input[i] * inputLevel + pluginOutput[i] * pluginLevel;
}
}
}
else
{
// e.g. 2 plugin outputs into 1 output (should never happen)
std::runtime_error("Internal error 0xEA48");
}
}
// do soft bypass. // do soft bypass.
if (this->bypassSamplesRemaining == 0) if (this->bypassSamplesRemaining == 0)
+9 -1
View File
@@ -193,9 +193,12 @@ namespace pipedal
bool requestStateChangedNotification = false; bool requestStateChangedNotification = false;
float zeroInputMix = 0.5f;
int actualAudioInputs = 0;
int actualAudioOutputs = 0;
std::vector<std::vector<float>> outputMixBuffers;
void BypassTo(float value); void BypassTo(float value);
public: public:
// non RT-thread use only. // non RT-thread use only.
@@ -242,6 +245,9 @@ namespace pipedal
bool HasErrorMessage() const { return this->hasErrorMessage; } bool HasErrorMessage() const { return this->hasErrorMessage; }
const char*TakeErrorMessage() { this->hasErrorMessage = false; return this->errorMessage; } const char*TakeErrorMessage() { this->hasErrorMessage = false; return this->errorMessage; }
virtual void PrepareNoInputEffect(int numberOfInputs,size_t maxBufferSize) override;
virtual void ResetAtomBuffers(); virtual void ResetAtomBuffers();
virtual uint64_t GetInstanceId() const { return instanceId; } virtual uint64_t GetInstanceId() const { return instanceId; }
virtual int GetNumberOfInputAudioPorts() const { return inputAudioPortIndices.size(); } virtual int GetNumberOfInputAudioPorts() const { return inputAudioPortIndices.size(); }
@@ -251,6 +257,8 @@ namespace pipedal
virtual int GetNumberOfMidiInputPorts() const { return inputMidiPortIndices.size(); } virtual int GetNumberOfMidiInputPorts() const { return inputMidiPortIndices.size(); }
virtual int GetNumberOfMidiOutputPorts() const { return outputMidiPortIndices.size(); } virtual int GetNumberOfMidiOutputPorts() const { return outputMidiPortIndices.size(); }
virtual void SetAudioInputBuffer(int index, float *buffer); virtual void SetAudioInputBuffer(int index, float *buffer);
virtual float *GetAudioInputBuffer(int index) const { return this->inputAudioBuffers[index]; } virtual float *GetAudioInputBuffer(int index) const { return this->inputAudioBuffers[index]; }
+3 -1
View File
@@ -121,6 +121,7 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
if (pLv2Effect) if (pLv2Effect)
{ {
if (pLv2Effect->HasErrorMessage()) if (pLv2Effect->HasErrorMessage())
{ {
std::string error = pLv2Effect->TakeErrorMessage(); std::string error = pLv2Effect->TakeErrorMessage();
@@ -131,6 +132,7 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
pEffect = pLv2Effect; pEffect = pLv2Effect;
uint64_t instanceId = pEffect->GetInstanceId(); uint64_t instanceId = pEffect->GetInstanceId();
pLv2Effect->PrepareNoInputEffect(inputBuffers.size(),pHost->GetMaxAudioBufferSize());
if (inputBuffers.size() == 1) if (inputBuffers.size() == 1)
{ {
@@ -207,7 +209,7 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
effectOutput.push_back(CreateNewAudioBuffer()); effectOutput.push_back(CreateNewAudioBuffer());
} }
#endif #endif
for (size_t i = 0; i < effectOutput.size(); ++i) for (size_t i = 0; i < effectOutput.size(); ++i)
{ {
pEffect->SetAudioOutputBuffer(i, effectOutput[i]); pEffect->SetAudioOutputBuffer(i, effectOutput[i]);
} }
+15 -6
View File
@@ -2782,6 +2782,7 @@ void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
Lv2Log::info("Restarting audio."); Lv2Log::info("Restarting audio.");
this->RestartAudio(); this->RestartAudio();
}); });
++audioRestartRetries;
} else if (audioRestartRetries < 3) } else if (audioRestartRetries < 3)
{ {
this->audioRetryPostHandle = this->PostDelayed( this->audioRetryPostHandle = this->PostDelayed(
@@ -2794,13 +2795,21 @@ void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
RestartAudio(); RestartAudio();
}); });
++audioRestartRetries;
} else if (audioRestartRetries == 3) // one attempt to start the dummy driver.
{
{
this->audioRetryPostHandle = this->Post(
// No lock to avoid deadlocks!
[this]() {
Lv2Log::info(SS("Switching to dummy driver."));
RestartAudio(true); // switch to the dummy driver.
});
}
++audioRestartRetries;
} else { } else {
this->audioRetryPostHandle = this->Post( Lv2Log::error(SS("Unable to reastart audio."));
// No lock to avoid deadlocks!
[this]() {
Lv2Log::info(SS("Switching to dummy driver."));
RestartAudio(true); // switch to the dummy driver.
});
} }
}); });
} }
+19 -1
View File
@@ -482,7 +482,19 @@ void PluginHost::Load(const char *lv2Path)
Lv2PluginUiInfo info(this, plugin.get()); Lv2PluginUiInfo info(this, plugin.get());
if (plugin->is_valid()) if (plugin->is_valid())
{ {
#if SUPPORT_MIDI #if 1
if (info.audio_inputs() > 2 || info.audio_outputs() > 2) {
Lv2Log::debug(
"Plugin %s (%s) skipped. %d inputs, %d outputs.", plugin->name().c_str(), plugin->uri().c_str(),
(int)info.audio_inputs(),(int)info.audio_outputs());
}
else if (info.audio_inputs() == 0 && info.audio_outputs() == 0 )
{
Lv2Log::debug("Plugin %s (%s) skipped. No audio i/o.", plugin->name().c_str(), plugin->uri().c_str());
}
#elif SUPPORT_MIDI
if (info.audio_inputs() == 0 && !info.has_midi_input()) if (info.audio_inputs() == 0 && !info.has_midi_input())
{ {
Lv2Log::debug("Plugin %s (%s) skipped. No inputs.", plugin->name().c_str(), plugin->uri().c_str()); Lv2Log::debug("Plugin %s (%s) skipped. No inputs.", plugin->name().c_str(), plugin->uri().c_str());
@@ -503,6 +515,12 @@ void PluginHost::Load(const char *lv2Path)
#endif #endif
else else
{ {
if (info.audio_inputs() == 0) {
Lv2Log::debug("************* ZERO INPUTS: %s (%s) skipped. No audio outputs.", plugin->name().c_str(), plugin->uri().c_str());
}
if (info.audio_outputs() == 0) {
Lv2Log::debug("************* ZERO OUTPUTS: %s (%s) skipped. No audio outputs.", plugin->name().c_str(), plugin->uri().c_str());
}
ui_plugins_.push_back(std::move(info)); ui_plugins_.push_back(std::move(info));
} }
} }
+1
View File
@@ -20,6 +20,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <filesystem>
namespace pipedal { namespace pipedal {
class PiPedalModel; class PiPedalModel;
+3
View File
@@ -370,6 +370,9 @@ namespace pipedal
virtual void RequestAllPathPatchProperties() {} virtual void RequestAllPathPatchProperties() {}
virtual void PrepareNoInputEffect(int numberOfInputs,size_t maxBufferSize) override {
// do nothing.
}
virtual int GetNumberOfOutputAudioPorts() const virtual int GetNumberOfOutputAudioPorts() const
{ {
return numberOfOutputPorts; return numberOfOutputPorts;
+1
View File
@@ -27,6 +27,7 @@
#include "json.hpp" #include "json.hpp"
#include <chrono> #include <chrono>
#include "UpdaterStatus.hpp" #include "UpdaterStatus.hpp"
#include <filesystem>
namespace pipedal namespace pipedal
+1 -25
View File
@@ -24,7 +24,7 @@
template <typename T> class TypeDisplay; template <typename T> class TypeDisplay;
#ifndef SUPPORT_MIDI // currently, only whether midi plugins can be loaded. No routing or handling implemented (yet). #ifndef SUPPORT_MIDI // currently, only whether midi plugins can be loaded. No routing or handling implemented (yet).
#define SUPPORT_MIDI 0 #define SUPPORT_MIDI 1
#endif #endif
@@ -32,33 +32,9 @@ template <typename T> class TypeDisplay;
#include <string> #include <string>
#include <vector> #include <vector>
#include <mutex>
#include <stdexcept> #include <stdexcept>
#include <cstdlib>
#include <map> #include <map>
#include <fstream> #include <fstream>
#include <chrono>
#include <filesystem>
#include <memory> #include <memory>
#ifdef JUNK
#endif
/*
#include <lv2/lv2core/lv2.h>
#include "lv2/atom/atom.h"
#include "lv2/atom/util.h"
#include "lv2/log/log.h"
#include "lv2/log/logger.h"
#include "lv2/midi/midi.h"
#include "lv2/urid/urid.h"
#include "lv2/log/logger.h"
#include "lv2/uri-map/uri-map.h"
#include "lv2/atom/forge.h"
#include "lv2/worker/worker.h"
#include "lv2/patch/patch.h"
#include "lv2/parameters/parameters.h"
#include "lv2/units/units.h"
*/
#include "ss.hpp" #include "ss.hpp"