Clean up ToobAmp log messages and rdf:comment's.
This commit is contained in:
Binary file not shown.
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 }}>
|
||||||
|
<Tooltip title={fileProperty.label} placement="top-start" arrow
|
||||||
|
enterDelay={1000} enterNextDelay={1000}
|
||||||
|
>
|
||||||
<Typography variant="caption" display="block" noWrap style={{
|
<Typography variant="caption" display="block" noWrap style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "start"
|
textAlign: "start"
|
||||||
}}> {fileProperty.label}</Typography>
|
}}> {fileProperty.label}</Typography>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -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}
|
||||||
|
|||||||
+155
-95
@@ -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,11 +136,18 @@ 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,
|
||||||
@@ -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: {
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,7 +603,7 @@ const PedalboardView =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let dyTop = (lp.cy + CELL_HEIGHT / 2)- (topBounds.y + topBounds.height) ;
|
let dyTop = (lp.cy + CELL_HEIGHT / 2) - (topBounds.y + topBounds.height);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -598,7 +621,7 @@ const PedalboardView =
|
|||||||
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);
|
||||||
@@ -634,10 +657,9 @@ 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();
|
||||||
@@ -647,8 +669,8 @@ const PedalboardView =
|
|||||||
|
|
||||||
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,8 +747,19 @@ 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} />
|
||||||
@@ -722,6 +771,11 @@ const PedalboardView =
|
|||||||
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 {
|
||||||
@@ -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)) {
|
||||||
@@ -895,8 +949,7 @@ const PedalboardView =
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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} />
|
||||||
@@ -908,14 +961,11 @@ const PedalboardView =
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
||||||
@@ -929,11 +979,19 @@ const PedalboardView =
|
|||||||
draggable: boolean,
|
draggable: boolean,
|
||||||
enabled: boolean,
|
enabled: boolean,
|
||||||
hasBorder: boolean = true,
|
hasBorder: boolean = true,
|
||||||
pluginNotFound: boolean)
|
pluginNotFound: boolean,
|
||||||
|
hasMidiConnector: boolean
|
||||||
|
)
|
||||||
: ReactNode {
|
: 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); }}
|
||||||
@@ -944,7 +1002,7 @@ const PedalboardView =
|
|||||||
<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,7 +1033,7 @@ 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">
|
||||||
@@ -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,29 +1217,33 @@ 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.numberOfInputs = numberOfInputs;
|
||||||
|
item.numberOfOutputs = Math.max(item.numberOfOutputs, numberOfInputs);
|
||||||
|
} else {
|
||||||
|
item.numberOfInputs = CalculateConnection(numberOfInputs, this.getNumberOfInputs(item));
|
||||||
item.numberOfOutputs = this.getNumberOfOutputs(item);
|
item.numberOfOutputs = this.getNumberOfOutputs(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
numberOfInputs = item.numberOfOutputs;
|
numberOfInputs = item.numberOfOutputs;
|
||||||
}
|
}
|
||||||
return numberOfInputs;
|
return numberOfInputs;
|
||||||
@@ -1196,11 +1257,10 @@ 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);
|
||||||
|
|||||||
@@ -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 }}>
|
||||||
|
<ControlTooltip uiControl={control} >
|
||||||
<Typography variant="caption" display="block" noWrap style={{
|
<Typography variant="caption" display="block" noWrap style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: isSelect ? "left" : "center"
|
textAlign: isSelect ? "left" : "center"
|
||||||
}}> {isTrigger ? "\u00A0" : control.name}</Typography>
|
}}> {isTrigger ? "\u00A0" : control.name}</Typography>
|
||||||
|
</ControlTooltip>
|
||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
<Tooltip title={controlGroup.name}
|
||||||
|
placement="top-start" arrow enterDelay={1500} enterNextDelay={1500}
|
||||||
|
>
|
||||||
<Typography noWrap variant="caption" >{controlGroup.name}</Typography>
|
<Typography noWrap variant="caption" >{controlGroup.name}</Typography>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.portGroupControls} >
|
<div className={classes.portGroupControls} >
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,6 +150,7 @@ 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) {
|
||||||
@@ -258,7 +258,7 @@ 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:
|
Author:
|
||||||
{(plugin.author_homepage !== "")
|
{(plugin.author_homepage !== "")
|
||||||
@@ -286,6 +286,8 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
|||||||
{
|
{
|
||||||
makeControls(plugin.controls)
|
makeControls(plugin.controls)
|
||||||
}
|
}
|
||||||
|
{plugin.description.length > 0 && (
|
||||||
|
<div>
|
||||||
<Typography gutterBottom variant="body2" style={{ paddingTop: "1em" }}>
|
<Typography gutterBottom variant="body2" style={{ paddingTop: "1em" }}>
|
||||||
Description:
|
Description:
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -303,7 +305,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
|||||||
|
|
||||||
},
|
},
|
||||||
code: (props: any) => {
|
code: (props: any) => {
|
||||||
return (<code style={{fontSize: 14}} {...props} />);
|
return (<code style={{ fontSize: 14 }} {...props} />);
|
||||||
},
|
},
|
||||||
a: (props: any) => {
|
a: (props: any) => {
|
||||||
return (
|
return (
|
||||||
@@ -317,6 +319,8 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
|||||||
{plugin.description}
|
{plugin.description}
|
||||||
</Remark>
|
</Remark>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</PluginInfoDialogContent>
|
</PluginInfoDialogContent>
|
||||||
<PluginInfoDialogActions>
|
<PluginInfoDialogActions>
|
||||||
<Button variant="dialogPrimary" autoFocus onClick={handleClose} style={{ width: "130px" }}>
|
<Button variant="dialogPrimary" autoFocus onClick={handleClose} style={{ width: "130px" }}>
|
||||||
|
|||||||
@@ -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,15 +125,14 @@ 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;
|
||||||
@@ -144,23 +141,20 @@ const PluginOutputControl =
|
|||||||
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,16 +165,13 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -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 }}>
|
||||||
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography variant="caption" display="block" style={{
|
<Typography variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
}}> {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 }}>
|
||||||
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography variant="caption" display="block" style={{
|
<Typography variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
}}> {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 }}>
|
||||||
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography variant="caption" display="block" style={{
|
<Typography variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
}}> {control.name === "" ? "\u00A0": (control.name)}</Typography>
|
}}> {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,
|
||||||
|
background: (isDarkMode() ? "radial-gradient(circle at center, #F00 0, #F00 20%, #333 100%)"
|
||||||
: "radial-gradient(circle at center, #F44 0, #F44 40%, #644 100%)"),
|
: "radial-gradient(circle at center, #F44 0, #F44 40%, #644 100%)"),
|
||||||
opacity: 0, borderRadius: 3,margin: 2,position: "absolute" }} />
|
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 }}>
|
||||||
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography variant="caption" display="block" style={{
|
<Typography variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "left"
|
textAlign: "left"
|
||||||
}}> {control.name}</Typography>
|
}}> {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 }}>
|
||||||
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography variant="caption" display="block" style={{
|
<Typography variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "left"
|
textAlign: "left"
|
||||||
}}> {control.name}</Typography>
|
}}> {control.name}</Typography>
|
||||||
|
</ControlTooltip>
|
||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -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,12 +1671,17 @@ namespace pipedal
|
|||||||
pBuffer[j] = 0;
|
pBuffer[j] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
while (!terminateAudio())
|
while (!terminateAudio())
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
// zero out input buffers.
|
// zero out input buffers.
|
||||||
this->driverHost->OnProcess(this->bufferSize);
|
this->driverHost->OnProcess(this->bufferSize);
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this->driverHost->OnAudioTerminated();
|
this->driverHost->OnAudioTerminated();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+116
-21
@@ -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;
|
||||||
|
|
||||||
|
if (inputAudioPortIndices.size() == inputAudioBuffers.size())
|
||||||
|
{
|
||||||
int pluginIndex = this->inputAudioPortIndices[index];
|
int pluginIndex = this->inputAudioPortIndices[index];
|
||||||
lilv_instance_connect_port(this->pInstance, pluginIndex, buffer);
|
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;
|
||||||
|
|
||||||
|
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];
|
int pluginIndex = this->outputAudioPortIndices[index];
|
||||||
lilv_instance_connect_port(pInstance, pluginIndex, buffer);
|
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 (this->inputAudioPortIndices.size() != 0) // i.e. not using a mix buffer.
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < this->outputAudioPortIndices.size(); ++i)
|
||||||
{
|
{
|
||||||
if (GetAudioOutputBuffer(i) == nullptr)
|
if (GetAudioOutputBuffer(i) == nullptr)
|
||||||
{
|
{
|
||||||
int pluginIndex = this->outputAudioPortIndices[i];
|
|
||||||
|
|
||||||
float *buffer = bufferPool.AllocateBuffer<float>(pHost->GetMaxAudioBufferSize());
|
float *buffer = bufferPool.AllocateBuffer<float>(pHost->GetMaxAudioBufferSize());
|
||||||
lilv_instance_connect_port(pInstance, pluginIndex, buffer);
|
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
@@ -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]; }
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
+10
-1
@@ -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,7 +2795,10 @@ void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
|
|||||||
|
|
||||||
RestartAudio();
|
RestartAudio();
|
||||||
});
|
});
|
||||||
} else {
|
++audioRestartRetries;
|
||||||
|
} else if (audioRestartRetries == 3) // one attempt to start the dummy driver.
|
||||||
|
{
|
||||||
|
{
|
||||||
this->audioRetryPostHandle = this->Post(
|
this->audioRetryPostHandle = this->Post(
|
||||||
// No lock to avoid deadlocks!
|
// No lock to avoid deadlocks!
|
||||||
[this]() {
|
[this]() {
|
||||||
@@ -2802,5 +2806,10 @@ void PiPedalModel::OnAlsaDriverTerminatedAbnormally() {
|
|||||||
RestartAudio(true); // switch to the dummy driver.
|
RestartAudio(true); // switch to the dummy driver.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
++audioRestartRetries;
|
||||||
|
} else {
|
||||||
|
Lv2Log::error(SS("Unable to reastart audio."));
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
namespace pipedal {
|
namespace pipedal {
|
||||||
class PiPedalModel;
|
class PiPedalModel;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user