Interim checking, Convolution Reverb

This commit is contained in:
Robin Davies
2023-04-05 03:00:51 -04:00
parent ed1dc75c53
commit b83ba7ca94
115 changed files with 7643 additions and 3055 deletions
+10 -7
View File
@@ -162,15 +162,18 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
}
componentDidMount() {
super.componentDidMount?.();
this.mounted = true;
this.updateNotifications();
this.startFossRequest();
}
componentWillUnmount() {
super.componentWillUnmount?.();
this.mounted = false;
this.updateNotifications();
}
componentDidUpdate() {
componentDidUpdate(prevProps: Readonly<AboutDialogProps>, prevState: Readonly<AboutDialogState>, snapshot: any): void {
super.componentDidUpdate?.(prevProps,prevState,snapshot);
this.updateNotifications();
}
@@ -196,7 +199,7 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
>
<ArrowBackIcon />
</IconButton>
<Typography variant="h6" className={classes.dialogTitle}>
<Typography noWrap variant="h6" className={classes.dialogTitle}>
About
</Typography>
</Toolbar>
@@ -208,28 +211,28 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
}}
>
<div style={{ margin: 24 }}>
<Typography display="block" variant="h6" color="textPrimary">
<Typography noWrap display="block" variant="h6" color="textPrimary">
PiPedal <span style={{ fontSize: "0.7em" }}>
{(this.model.serverVersion ? this.model.serverVersion.serverVersion : "")
+ (this.model.serverVersion?.debug ? " (Debug)" : "")}
</span>
</Typography>
<Typography display="block" variant="body2" style={{ marginBottom: 12 }} >
<Typography noWrap display="block" variant="body2" style={{ marginBottom: 12 }} >
Copyright &#169; 2022 Robin Davies.
</Typography>
{this.model.isAndroidHosted() && (
<Typography display="block" variant="body2" style={{ marginBottom: 0 }} >
<Typography noWrap display="block" variant="body2" style={{ marginBottom: 0 }} >
{this.model.getAndroidHostVersion()}
</Typography>
)}
{this.model.isAndroidHosted() && (
<Typography display="block" variant="body2" style={{ marginBottom: 12 }} >
<Typography noWrap display="block" variant="body2" style={{ marginBottom: 12 }} >
Copyright &#169; 2022 Robin Davies.
</Typography>
)}
<Divider />
<Typography display="block" variant="caption" >
<Typography noWrap display="block" variant="caption" >
ADDRESSES
</Typography>
<div style={{marginBottom: 16}}>
+7 -12
View File
@@ -398,7 +398,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
}
handDisplayOnboarding() {
handleDisplayOnboarding() {
this.setState({
isDrawerOpen: false,
isSettingsDialogOpen: true,
@@ -502,7 +502,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
this.model_.errorMessage.addOnChangedHandler(this.errorChangeHandler_);
this.model_.state.addOnChangedHandler(this.stateChangeHandler_);
this.model_.pedalBoard.addOnChangedHandler(this.presetChangedHandler);
this.model_.pedalboard.addOnChangedHandler(this.presetChangedHandler);
this.model_.alertMessage.addOnChangedHandler(this.alertMessageChangedHandler);
this.model_.banks.addOnChangedHandler(this.banksChangedHandler);
this.model_.showStatusMonitor.addOnChangedHandler(this.showStatusMonitorHandler);
@@ -529,7 +529,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
super.componentWillUnmount();
this.model_.errorMessage.removeOnChangedHandler(this.errorChangeHandler_);
this.model_.state.removeOnChangedHandler(this.stateChangeHandler_);
this.model_.pedalBoard.removeOnChangedHandler(this.presetChangedHandler);
this.model_.pedalboard.removeOnChangedHandler(this.presetChangedHandler);
this.model_.banks.removeOnChangedHandler(this.banksChangedHandler);
this.model_.banks.removeOnChangedHandler(this.showStatusMonitorHandler);
@@ -575,7 +575,6 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
this.setState({ errorMessage: message });
}
onboardingShown: boolean = false;
setDisplayState(newState: State): void {
this.updateOverscroll();
@@ -586,13 +585,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
});
if (newState === State.Ready)
{
if (!this.onboardingShown)
if (this.model_.isOnboarding())
{
this.onboardingShown = true;
if (!this.model_.hasConfiguration())
{
this.handDisplayOnboarding();
}
this.handleDisplayOnboarding();
}
}
}
@@ -867,7 +862,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<div className={classes.loadingBoxItem}>
<CircularProgress color="inherit" className={classes.loadingBoxItem} />
</div>
<Typography variant="body2" className={classes.progressText}>
<Typography noWrap variant="body2" className={classes.progressText}>
{this.state.displayState === State.ApplyingChanges ? "Applying\u00A0changes..." : "Reconnecting..."}
</Typography>
</div>
@@ -905,7 +900,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<div className={classes.loadingBoxItem}>
<CircularProgress color="inherit" className={classes.loadingBoxItem} />
</div>
<Typography variant="body2" className={classes.loadingBoxItem}>
<Typography noWrap variant="body2" className={classes.loadingBoxItem}>
Loading...
</Typography>
</div>
+3 -3
View File
@@ -298,7 +298,7 @@ const BankDialog = withStyles(styles, { withTheme: true })(
<img src="img/ic_bank.svg" className={classes.itemIcon} alt="" />
</div>
<div className={classes.itemLabel}>
<Typography>
<Typography noWrap>
{bankEntry.name}
</Typography>
</div>
@@ -410,7 +410,7 @@ const BankDialog = withStyles(styles, { withTheme: true })(
>
<ArrowBackIcon />
</IconButton>
<Typography variant="h6" className={classes.dialogTitle}>
<Typography noWrap variant="h6" className={classes.dialogTitle}>
Banks
</Typography>
<IconButton color="inherit" onClick={(e) => this.showActionBar(true)} >
@@ -433,7 +433,7 @@ const BankDialog = withStyles(styles, { withTheme: true })(
</IconButton>
)}
<Typography variant="h6" className={classes.dialogTitle}>
<Typography noWrap variant="h6" className={classes.dialogTitle}>
Banks
</Typography>
{(this.state.banks.getEntry(this.state.selectedItem) != null)
+10 -10
View File
@@ -21,7 +21,7 @@ import React from 'react';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import {PedalBoardItem, PedalBoardSplitItem} from './PedalBoard';
import {PedalboardItem, PedalboardSplitItem} from './Pedalboard';
import PluginControlView from './PluginControlView';
import SplitControlView from './SplitControlView';
import Typography from '@mui/material/Typography';
@@ -47,38 +47,38 @@ let pluginFactories: IControlViewFactory[] = [
];
export function GetControlView(pedalBoardItem?: PedalBoardItem| null): React.ReactNode
export function GetControlView(pedalboardItem?: PedalboardItem| null): React.ReactNode
{
let model: PiPedalModel = PiPedalModelFactory.getInstance();
if (!pedalBoardItem) {
if (!pedalboardItem) {
return (<div/>);
}
if (pedalBoardItem.isSplit())
if (pedalboardItem.isSplit())
{
return (
<SplitControlView item={pedalBoardItem as PedalBoardSplitItem} instanceId={pedalBoardItem!.instanceId}
<SplitControlView item={pedalboardItem as PedalboardSplitItem} instanceId={pedalboardItem!.instanceId}
/>
);
} else {
for (let i = 0; i < pluginFactories.length; ++i)
{
let factory = pluginFactories[i];
if (factory.uri === pedalBoardItem.uri)
if (factory.uri === pedalboardItem.uri)
{
return factory.Create(model,pedalBoardItem);
return factory.Create(model,pedalboardItem);
}
}
let uiPlugin = model.getUiPlugin(pedalBoardItem.uri);
let uiPlugin = model.getUiPlugin(pedalboardItem.uri);
if (!uiPlugin)
{
<div style={{paddingLeft: 40, paddingRight: 40}}>
<Typography color="error" variant="h6" >Missing plugin.</Typography>
<Typography>The plugin '{pedalBoardItem.pluginName}' ({pedalBoardItem.uri}) is not currently installed.</Typography>
<Typography>The plugin '{pedalboardItem.pluginName}' ({pedalboardItem.uri}) is not currently installed.</Typography>
</div>
} else {
return (
<PluginControlView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />
<PluginControlView instanceId={pedalboardItem.instanceId} item={pedalboardItem} />
)
}
}
+23 -41
View File
@@ -47,12 +47,9 @@ function peekDialogStack(): string {
return "";
}
let ignoreNextPop = false;
function popDialogStack(ignoreNextPop_: boolean): void {
function popDialogStack(): void {
if (dialogStack.length !== 0)
{
ignoreNextPop = ignoreNextPop_;
dialogStack.splice(dialogStack.length-1,1);
}
}
@@ -76,27 +73,23 @@ class DialogEx extends React.Component<DialogExProps,DialogExState> {
mounted: boolean = false;
hasHooks: boolean = false;
stateWasPopped: boolean = false;
handlePopState(e: any): any {
handlePopState(e: any): any
{
let shouldClose = (peekDialogStack() === this.props.tag);
if (shouldClose)
{
if (ignoreNextPop)
{
ignoreNextPop = false;
} else {
if (!this.stateWasPopped)
{
this.stateWasPopped = true;
if (this.props.onClose)
{
popDialogStack(false);
this.props.onClose(e,"backdropClick");
}
if (!this.stateWasPopped)
{
this.stateWasPopped = true;
popDialogStack();
if (this.props.open) {
this.props.onClose?.(e,"backdropClick");
}
}
window.removeEventListener("popstate",this.handlePopState);
e.stopPropagation();
}
}
@@ -111,49 +104,35 @@ class DialogEx extends React.Component<DialogExProps,DialogExState> {
{
this.stateWasPopped = false;
window.addEventListener("popstate",this.handlePopState);
// eslint-disable-next-line no-restricted-globals
let state = history.state;
if (!state)
{
state = {};
}
state[this.props.tag] = true;
pushDialogStack(this.props.tag);
let state: {tag: string} = {tag: this.props.tag};
// eslint-disable-next-line no-restricted-globals
history.pushState(
state,
"",
"" //"#" + this.props.tag
"#" + this.props.tag
);
} else {
if (!this.stateWasPopped)
{
this.stateWasPopped = true;
popDialogStack(true);
// eslint-disable-next-line no-restricted-globals
history.back();
}
window.removeEventListener("popstate",this.handlePopState);
}
}
}
componentDidMount()
{
if (super.componentDidMount)
{
super.componentDidMount();
}
super.componentDidMount?.();
this.mounted = true;
this.updateHooks();
}
componentWillUnmount()
{
if (super.componentWillUnmount)
{
super.componentWillUnmount();
}
super.componentWillUnmount?.();
this.mounted = false;
this.updateHooks();
}
@@ -162,12 +141,15 @@ class DialogEx extends React.Component<DialogExProps,DialogExState> {
{
this.updateHooks();
}
myOnClose(event:{}, reason: "backdropClick" | "escapeKeyDown")
{
if (this.props.onClose) this.props.onClose(event,reason);
}
render() {
let { tag, ...extra} = this.props;
let { tag,onClose, ...extra} = this.props;
return (
<Dialog {...extra}>
<Dialog {...extra} onClose={(event,reason)=>{ this.myOnClose(event,reason);}}>
{this.props.children}
</Dialog>
);
+84 -40
View File
@@ -22,33 +22,20 @@
* SOFTWARE.
*/
import React, { TouchEvent, PointerEvent, ReactNode, Component, SyntheticEvent } from 'react';
import React, { Component, SyntheticEvent } from 'react';
import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import { PiPedalFileProperty, PiPedalFileType } from './Lv2Plugin';
import { PiPedalFileProperty } from './Lv2Plugin';
import Typography from '@mui/material/Typography';
import Input from '@mui/material/Input';
import Select from '@mui/material/Select';
import Switch from '@mui/material/Switch';
import Utility, { nullCast } from './Utility';
import MenuItem from '@mui/material/MenuItem';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { PiPedalModel, PiPedalModelFactory, ListenHandle, StateChangedHandle } from './PiPedalModel';
import ButtonBase from '@mui/material/ButtonBase'
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
const MIN_ANGLE = -135;
const MAX_ANGLE = 135;
const FONT_SIZE = "0.8em";
const SELECTED_OPACITY = 0.8;
const DEFAULT_OPACITY = 0.6;
const RANGE_SCALE = 120; // 120 pixels to move from 0 to 1.
const FINE_RANGE_SCALE = RANGE_SCALE * 10; // 1200 pixels to move from 0 to 1.
const ULTRA_FINE_RANGE_SCALE = RANGE_SCALE * 50; // 12000 pixels to move from 0 to 1.
export const StandardItemSize = { width: 80, height: 140 }
@@ -88,13 +75,12 @@ const styles = (theme: Theme) => createStyles({
export interface FilePropertyControlProps extends WithStyles<typeof styles> {
instanceId: number;
fileProperty: PiPedalFileProperty;
value: string;
onFileClick: (fileProperty: PiPedalFileProperty,value: string) => void;
onFileClick: (fileProperty: PiPedalFileProperty, value: string) => void;
theme: Theme;
}
type FilePropertyControlState = {
error: boolean;
showDialog: boolean;
value: string;
};
const FilePropertyControl =
@@ -110,13 +96,75 @@ const FilePropertyControl =
this.state = {
error: false,
showDialog: false
value: "",
};
this.model = PiPedalModelFactory.getInstance();
if (this.props.fileProperty.patchProperty !== "") {
this.subscribeToPropertyGet();
}
}
componentWillUnmount() {
private propertyGetHandle?: ListenHandle;
refreshPatchProperty()
{
this.model.getPatchProperty(this.props.instanceId, this.props.fileProperty.patchProperty)
.then(
(json: any) => {
if (json && json.otype_ === "Path") {
let path = json.value as string;
this.setState({ value: path });
}
}
)
.catch(
(error: Error) => {
this.model.showAlert(error.toString());
}
);
}
stateChangedHandle?: StateChangedHandle;
subscribeToPropertyGet() {
// this.propertyGetHandle = this.model.listenForAtomOutput(this.props.instanceId,(instanceId,atomOutput)=>{
// // PARSE THE OBJECT!
// // this.setState({value: atomOutput?.value as string});
// });
if (this.stateChangedHandle)
{
this.model.removeLv2StateChangedListener(this.stateChangedHandle);
}
this.refreshPatchProperty();
this.stateChangedHandle = this.model.addLv2StateChangedListener(
this.props.instanceId,
() => {
this.refreshPatchProperty();
});
}
unsubscribeToPropertyGet() {
if (this.stateChangedHandle)
{
this.model.removeLv2StateChangedListener(this.stateChangedHandle);
}
}
componentDidMount() {
this.subscribeToPropertyGet();
}
componentWillUnmount() {
this.unsubscribeToPropertyGet();
}
componentDidUpdate(prevProps: Readonly<FilePropertyControlProps>, prevState: Readonly<FilePropertyControlState>, snapshot?: any): void {
if (prevProps.fileProperty.patchProperty !== this.props.fileProperty.patchProperty
|| prevProps.instanceId !== this.props.instanceId) {
this.setState({ value: "" });
this.unsubscribeToPropertyGet();
this.subscribeToPropertyGet();
}
}
inputChanged: boolean = false;
onDrag(e: SyntheticEvent) {
@@ -124,40 +172,36 @@ const FilePropertyControl =
}
onFileClick() {
this.props.onFileClick(this.props.fileProperty,this.props.value);
this.props.onFileClick(this.props.fileProperty, this.state.value);
}
private fileNameOnly(path: string): string {
let slashPos = path.lastIndexOf('/');
if (slashPos < 0)
{
if (slashPos < 0) {
slashPos = 0;
} else {
++slashPos;
}
let extPos = path.lastIndexOf('.');
if (extPos < 0 || extPos < slashPos)
{
if (extPos < 0 || extPos < slashPos) {
extPos = path.length;
}
}
return path.substring(slashPos,extPos);
return path.substring(slashPos, extPos);
}
}
render() {
let classes = this.props.classes;
//let classes = this.props.classes;
let fileProperty = this.props.fileProperty;
let value = this.props.value;
if (!value || value.length === 0)
{
let value = this.fileNameOnly(this.state.value);
if (!value || value.length === 0) {
value = "\u00A0";
}
value = this.fileNameOnly(value);
let item_width = 264;
return (
<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 */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" noWrap style={{
@@ -169,13 +213,13 @@ const FilePropertyControl =
<div style={{ flex: "0 0 auto", width: "100%" }}>
<ButtonBase style={{ width: "100%", borderRadius: "4px 4px 0px 0px", overflow: "hidden",marginTop: 8}} onClick={()=> {this.onFileClick()}} >
<div style={{width: "100%", background: "rgba(0,0,0,0.07)", borderRadius: "4px 4px 0px 0px"}}>
<ButtonBase style={{ width: "100%", borderRadius: "4px 4px 0px 0px", overflow: "hidden", marginTop: 8 }} onClick={() => { this.onFileClick() }} >
<div style={{ width: "100%", background: "rgba(0,0,0,0.07)", borderRadius: "4px 4px 0px 0px" }}>
<div style={{ display: "flex", alignItems: "center", flexFlow: "row nowrap" }}>
<Typography noWrap={true} style={{ flex: "1 1 100%", textAlign: "start", verticalAlign: "center", paddingTop: 4,paddingBottom: 4,paddingLeft: 4}}
<Typography noWrap={true} style={{ flex: "1 1 100%", textAlign: "start", verticalAlign: "center", paddingTop: 4, paddingBottom: 4, paddingLeft: 4 }}
variant='caption'
>{value}</Typography>
<MoreHorizIcon style={{ flex: "0 0 auto", width: "16px", height: "16px", verticalAlign: "center",opacity: 0.5, marginRight: 4 }} />
>{value}</Typography>
<MoreHorizIcon style={{ flex: "0 0 auto", width: "16px", height: "16px", verticalAlign: "center", opacity: 0.5, marginRight: 4 }} />
</div>
<div style={{ height: "1px", width: "100%", background: "black" }}>&nbsp;</div>
</div>
+47 -24
View File
@@ -23,35 +23,27 @@ import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import Button from '@mui/material/Button';
import Radio from '@mui/material/Radio';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import FileUploadIcon from '@mui/icons-material/FileUpload';
import AudioFileIcon from '@mui/icons-material/AudioFile';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DeleteIcon from '@mui/icons-material/Delete';
import IconButton from '@mui/material/IconButton';
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import { PiPedalFileProperty, PiPedalFileType } from './Lv2Plugin';
import { PiPedalFileProperty } from './Lv2Plugin';
import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography';
import DialogEx from './DialogEx';
import { ModelTraining } from '@mui/icons-material';
export interface FilePropertyDialogProps {
open: boolean,
fileProperty: PiPedalFileProperty,
selectedFile: string,
onOk: (fileProperty: PiPedalFileProperty, selectedItem: string) => void,
onClose: () => void
onCancel: () => void
};
export interface FilePropertyDialogState {
@@ -82,7 +74,23 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
private mounted: boolean = false;
private model: PiPedalModel;
private lastFileProperty: PiPedalFileProperty = new PiPedalFileProperty();
private requestFiles() {
if (!this.props.open)
{
return;
}
if (this.props.fileProperty.directory === "")
{
return;
}
if (this.lastFileProperty === this.props.fileProperty)
{
return;
}
this.lastFileProperty = this.props.fileProperty;
this.model.requestFileList(this.props.fileProperty)
.then((files) => {
if (this.mounted)
@@ -108,6 +116,11 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
this.mounted = false;
}
componentDidUpdate(prevProps: Readonly<FilePropertyDialogProps>, prevState: Readonly<FilePropertyDialogState>, snapshot?: any): void {
super.componentDidUpdate?.(prevProps,prevState,snapshot);
if (prevProps.fileProperty !== this.props.fileProperty)
{
this.requestFiles()
}
}
private fileNameOnly(path: string): string {
@@ -142,29 +155,39 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
this.setState({ selectedFile: selectedFile, hasSelection: this.isFileInList(this.state.files,selectedFile) })
}
mapKey: number = 0;
render() {
return (
<DialogEx onClose={() => this.props.onClose()} open={this.props.open} tag="FilePropertyDialog" fullWidth maxWidth="xl" style={{ height: "90%" }}
this.mapKey = 0;
return this.props.open &&
(
<DialogEx onClose={() => this.props.onCancel()} open={this.props.open} tag="FilePropertyDialog" fullWidth maxWidth="xl" style={{ height: "90%" }}
PaperProps={{ style: { minHeight: "90%", maxHeight: "90%", overflowY: "visible" } }}
>
<DialogTitle >{this.props.fileProperty.name}</DialogTitle>
<DialogTitle >
<div>
<IconButton edge="start" color="inherit" onClick={()=> {this.props.onCancel();}} aria-label="back"
>
<ArrowBackIcon fontSize="small" style={{opacity: "0.6"}} />
</IconButton>
<Typography display="inline" >{this.props.fileProperty.name}</Typography>
</div>
</DialogTitle>
<div style={{ flex: "0 0 auto", height: "1px", background: "rgba(0,0,0,0.2" }}>&nbsp;</div>
<div style={{ flex: "1 1 auto", height: "300", display: "flex", flexFlow: "row nowrap", overflowX: "auto", overflowY: "visible" }}>
<div style={{ flex: "1 1 100%", display: "flex", flexFlow: "column wrap", justifyContent: "start", alignItems: "flex-start" }}>
<div style={{ flex: "1 1 100%", display: "flex", flexFlow: "column wrap", justifyContent: "start", alignItems: "flex-start",paddingLeft: 16,paddingTop:16 }}>
{
this.state.files.map(
(value: string, index: number) => {
let selected = value === this.state.selectedFile;
let selectBg = selected ? "rgba(0,0,0,0.15)" : "rgba(0,0,0,0.0)";
return (
<ButtonBase
style={{ width: "320px", flex: "0 0 48px", position: "relative" }}
<ButtonBase key={ this.mapKey++ }
style={{ width: "320px", flex: "0 0 48px", position: "relative"}}
onClick={() => this.onSelect(value)}
>
<div style={{ position: "absolute", background: selectBg, width: "100%", height: "100%" }} />
<div style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} />
<div style={{ display: "flex", flexFlow: "row nowrap", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}>
<AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 4 }} />
<AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
<Typography noWrap style={{ flex: "1 1 auto", textAlign: "left" }}>{this.fileNameOnly(value)}</Typography>
</div>
</ButtonBase>
@@ -181,14 +204,14 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
<input hidden accept="audio/x-wav" name="Upload Impuse File" type="file" multiple />
Upload
</Button>
<IconButton style={{visibility: (this.state.hasSelection? "visible": "hidden")}} aria-label="delete selected file" component="label">
<DeleteIcon />
<IconButton style={{visibility: (this.state.hasSelection? "visible": "hidden")}} aria-label="delete selected file" component="label" color="primary" >
<DeleteIcon fontSize='small' />
</IconButton>
<div style={{ flex: "1 1 auto" }}>&nbsp;</div>
<Button onClick={() => this.props.onClose()} aria-label="cancel">
<Button onClick={() => {this.props.onCancel();}} aria-label="cancel">
Cancel
</Button>
<Button style={{ flex: "0 0 auto" }} onClick={() => this.props.onClose()} color="secondary" disabled={!this.state.hasSelection} aria-label="select">
<Button style={{ flex: "0 0 auto" }} onClick={() => {this.props.onOk(this.props.fileProperty,this.state.selectedFile);}} color="secondary" disabled={!this.state.hasSelection} aria-label="select">
Select
</Button>
</div>
+1 -1
View File
@@ -203,7 +203,7 @@ const FullScreenIME =
justifyContent: "center", alignItems: "center"
}}
>
<Typography variant="body2">{this.props.caption}</Typography>
<Typography noWrap variant="body2">{this.props.caption}</Typography>
<Input key={value}
type="number"
defaultValue={control.formatShortValue(value)}
+6 -6
View File
@@ -26,7 +26,7 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import GxTunerControl from './GxTunerControl';
@@ -40,7 +40,7 @@ const styles = (theme: Theme) => createStyles({
interface GxTunerProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
isToobTuner: boolean;
}
@@ -115,8 +115,8 @@ const GxTunerView =
export class GxTunerViewFactory implements IControlViewFactory {
uri: string = GXTUNER_URI;
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<GxTunerView isToobTuner={false} instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<GxTunerView isToobTuner={false} instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
@@ -126,8 +126,8 @@ export class GxTunerViewFactory implements IControlViewFactory {
export class ToobTunerViewFactory implements IControlViewFactory {
uri: string = TOOBTUNER_URI;
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<GxTunerView isToobTuner={true} instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<GxTunerView isToobTuner={true} instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+2 -2
View File
@@ -19,13 +19,13 @@
import React from 'react';
import { PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
interface IControlViewFactory {
uri: string;
Create(model: PiPedalModel,pedalBoardItem: PedalBoardItem): React.ReactNode;
Create(model: PiPedalModel,pedalboardItem: PedalboardItem): React.ReactNode;
}
+3 -1
View File
@@ -22,6 +22,7 @@
export default class JackServerSettings {
deserialize(input: any) : JackServerSettings{
this.valid = input.valid;
this.isOnboarding = input.isOnboarding;
this.isJackAudio = input.isJackAudio;
this.rebootRequired = input.rebootRequired;
this.alsaDevice = input.alsaDevice?? "";
@@ -44,6 +45,7 @@ export default class JackServerSettings {
return new JackServerSettings().deserialize(this);
}
valid: boolean = false;
isOnboarding: boolean = true;
rebootRequired = false;
isJackAudio = false;
alsaDevice: string = "";
@@ -54,7 +56,7 @@ export default class JackServerSettings {
getSummaryText() {
if (this.valid) {
let device = this.alsaDevice;
if (device.startsWith("hw:")) device = device.substr(3);
if (device.startsWith("hw:")) device = device.substring(3);
return device + " - Rate: " + this.sampleRate + " BufferSize: " + this.bufferSize + " Buffers: " + this.numberOfBuffers;
} else {
return "Not configured";
+2 -2
View File
@@ -134,8 +134,8 @@ const JackServerSettingsDialog = withStyles(styles)(
}
if (result.sampleRate === 0) result.sampleRate = 48000;
if (result.bufferSize === 0) result.bufferSize = 64;
if (result.numberOfBuffers === 0) result.numberOfBuffers = 2;
if (result.bufferSize === 0) result.bufferSize = 16;
if (result.numberOfBuffers === 0) result.numberOfBuffers = 3;
result.sampleRate = selectedDevice.closestSampleRate(result.sampleRate);
result.bufferSize = selectedDevice.closestBufferSize(result.bufferSize);
result.valid = true;
+137
View File
@@ -0,0 +1,137 @@
// Copyright (c) 2023 Robin Davies
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Utility class for constructing Json atoms.
class JsonAtom {
static Property(value: string): any
{
return {
"otype_": "Property",
"value": value
};
}
static Bool(value: boolean): any
{
return {
"otype_": "Bool",
"value": value
};
}
static Int(value: number): any
{
return {
"otype_": "Int",
"value": value
};
}
static Long(value: number): any
{
return {
"otype_": "Long",
"value": value
};
}
static Float(value: number): any
{
return value;
}
static Double(value: number): any
{
return {
"otype_": "Double",
"value": value
};
}
static String(value: string): any
{
return value;
}
static Path(value: string): any
{
return {
"otype_": "Path",
"value": value
};
}
static Uri(value: string): any
{
return {
"otype_": "URI",
"value": value
};
}
static Urid(value: string): any
{
return {
"otype_": "URID",
"value": value
};
}
static Object(type: string): any
{
return {
"otype_": type
};
}
static Tuple(values: any[]): any
{
return {
"otype_": "Tuple",
"value": values
};
}
static IntVector(values: []): any
{
return {
"otype_": "Vector",
"vtype_": "Int",
"value": values
};
}
static LongVector(values: []): any
{
return {
"otype_": "Vector",
"vtype_": "Long",
"value": values
};
}
static FloatVector(values: []): any
{
return {
"otype_": "Vector",
"vtype_": "Float",
"value": values
};
}
static DoubleVector(values: []): any
{
return {
"otype_": "Vector",
"vtype_": "Float",
"value": values
};
}
};
export default JsonAtom;
+32 -2
View File
@@ -123,13 +123,37 @@ export class PiPedalFileType {
name: string = "";
fileExtension: string = "";
}
export class UiPropertyNotification {
deserialize(input: any): UiPropertyNotification
{
this.portIndex = input.portIndex;
this.symbol = input.symbol;
this.plugin = input.plugin;
this.protocol = input.protocol;
return this;
}
static deserialize_array(input: any): UiPropertyNotification[]
{
let result: UiPropertyNotification[] = [];
for (let i = 0; i < input.length; ++i)
{
result[i] = new UiPropertyNotification().deserialize(input[i]);
}
return result;
}
portIndex: number = -1;
symbol: string = "";
plugin: string = "";
protocol: string = "";
};
export class PiPedalFileProperty {
deserialize(input: any): PiPedalFileProperty
{
this.name = input.name;
this.fileTypes = PiPedalFileType.deserialize_array(input.fileTypes);
this.patchProperty = input.patchProperty;
this.defaultFile = input.defaultFile;
this.directory = input.directory;
return this;
}
@@ -147,7 +171,6 @@ export class PiPedalFileProperty {
fileTypes: PiPedalFileType[] = [];
patchProperty: string = "";
directory: string = "";
defaultFile: string = "";
};
export class Lv2Plugin implements Deserializable<Lv2Plugin> {
@@ -170,6 +193,12 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
} else {
this.fileProperties = [];
}
if (input.uiPortNotifications)
{
this.uiPortNotifications = UiPropertyNotification.deserialize_array(input.uiPortNotifications);
} else {
this.uiPortNotifications = [];
}
return this;
}
static EmptyFeatures: string[] = [];
@@ -186,6 +215,7 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
ports: Port[] = Port.EmptyPorts;
port_groups: PortGroup[] = [];
fileProperties: PiPedalFileProperty[] = [];
uiPortNotifications: UiPropertyNotification[] = [];
}
+58 -58
View File
@@ -24,15 +24,15 @@ import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import {
PedalBoard, PedalBoardItem, PedalBoardSplitItem, SplitType
} from './PedalBoard';
Pedalboard, PedalboardItem, PedalboardSplitItem, SplitType
} from './Pedalboard';
import Button from '@mui/material/Button';
import InputIcon from '@mui/icons-material/Input';
import LoadPluginDialog from './LoadPluginDialog';
import Switch from '@mui/material/Switch';
import Typography from '@mui/material/Typography';
import PedalBoardView from './PedalBoardView';
import PedalboardView from './PedalboardView';
import { PiPedalStateError } from './PiPedalError';
import IconButton from '@mui/material/IconButton';
import AddIcon from '@mui/icons-material/Add';
@@ -58,11 +58,11 @@ const styles = ({ palette }: Theme) => createStyles({
position: "absolute", display: "flex", flexDirection: "column", flexWrap: "nowrap",
justifyContent: "flex-start", left: "0px", top: "0px", bottom: "0px", right: "0px", overflow: "hidden"
},
pedalBoardScroll: {
pedalboardScroll: {
position: "relative", width: "100%",
flex: "0 0 auto", overflow: "auto", maxHeight: 220
},
pedalBoardScrollSmall: {
pedalboardScrollSmall: {
position: "relative", width: "100%",
flex: "1 1 1px", overflow: "auto"
},
@@ -97,7 +97,7 @@ interface MainProps extends WithStyles<typeof styles> {
interface MainState {
selectedPedal: number;
loadDialogOpen: boolean;
pedalBoard: PedalBoard;
pedalboard: Pedalboard;
addMenuAnchorEl: HTMLElement | null;
splitControlBar: boolean;
horizontalScrollLayout: boolean;
@@ -116,13 +116,13 @@ export const MainPage =
constructor(props: MainProps) {
super(props);
this.model = PiPedalModelFactory.getInstance();
let pedalboard = this.model.pedalBoard.get();
let pedalboard = this.model.pedalboard.get();
let selectedPedal = pedalboard.getFirstSelectableItem();
this.state = {
selectedPedal: selectedPedal,
loadDialogOpen: false,
pedalBoard: pedalboard,
pedalboard: pedalboard,
addMenuAnchorEl: null,
splitControlBar: this.windowSize.width < SPLIT_CONTROLBAR_THRESHHOLD,
horizontalScrollLayout: this.windowSize.height < HORIZONTAL_CONTROL_SCROLL_HEIGHT_BREAK,
@@ -135,31 +135,31 @@ export const MainPage =
this.onLoadClick = this.onLoadClick.bind(this);
this.onLoadOk = this.onLoadOk.bind(this);
this.onLoadCancel = this.onLoadCancel.bind(this);
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.handleEnableCurrentItemChanged = this.handleEnableCurrentItemChanged.bind(this);
}
onInsertPedal(instanceId: number) {
this.setAddMenuAnchorEl(null);
let newId = this.model.addPedalBoardItem(instanceId, false);
let newId = this.model.addPedalboardItem(instanceId, false);
this.setSelection(newId);
}
onAppendPedal(instanceId: number) {
this.setAddMenuAnchorEl(null);
let newId = this.model.addPedalBoardItem(instanceId, true);
let newId = this.model.addPedalboardItem(instanceId, true);
this.setSelection(newId);
}
onInsertSplit(instanceId: number) {
this.setAddMenuAnchorEl(null);
let newId = this.model.addPedalBoardSplitItem(instanceId, false);
let newId = this.model.addPedalboardSplitItem(instanceId, false);
this.setSelection(newId);
}
onAppendSplit(instanceId: number) {
this.setAddMenuAnchorEl(null);
let newId = this.model.addPedalBoardSplitItem(instanceId, true);
let newId = this.model.addPedalboardSplitItem(instanceId, true);
this.setSelection(newId);
}
@@ -182,16 +182,16 @@ export const MainPage =
}
handleEnableCurrentItemChanged(event: any): void {
let newValue = event.target.checked;
let item = this.getSelectedPedalBoardItem();
let item = this.getSelectedPedalboardItem();
if (item != null) {
this.model.setPedalBoardItemEnabled(item.getInstanceId(), newValue);
this.model.setPedalboardItemEnabled(item.getInstanceId(), newValue);
}
}
handleSelectPluginPreset(instanceId: number, presetInstanceId: number) {
this.model.loadPluginPreset(instanceId, presetInstanceId);
}
onPedalBoardChanged(value: PedalBoard) {
onPedalboardChanged(value: Pedalboard) {
let selectedItem = -1;
if (value.hasItem(this.state.selectedPedal))
{
@@ -200,12 +200,12 @@ export const MainPage =
selectedItem = value.getFirstSelectableItem();
}
this.setState({
pedalBoard: value,
pedalboard: value,
selectedPedal: selectedItem
});
}
onDeletePedal(instanceId: number): void {
let result = this.model.deletePedalBoardPedal(instanceId);
let result = this.model.deletePedalboardPedal(instanceId);
if (result != null) {
this.setState({ selectedPedal: result });
}
@@ -213,10 +213,10 @@ export const MainPage =
componentDidMount() {
super.componentDidMount();
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
}
componentWillUnmount() {
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
super.componentWillUnmount();
}
updateResponsive() {
@@ -241,14 +241,14 @@ export const MainPage =
}
onPedalDoubleClick(selectedId: number): void {
this.setSelection(selectedId);
let item = this.getPedalBoardItem(selectedId);
let item = this.getPedalboardItem(selectedId);
if (item != null) {
if (item.isSplit()) {
let split = item as PedalBoardSplitItem;
let split = item as PedalboardSplitItem;
if (split.getSplitType() === SplitType.Ab) {
let cv = split.getToggleAbControlValue();
if (split.instanceId === undefined) throw new PiPedalStateError("Split without valid id.");
this.model.setPedalBoardControlValue(split.instanceId, cv.key, cv.value);
this.model.setPedalboardControl(split.instanceId, cv.key, cv.value);
}
} else {
this.setState({ loadDialogOpen: true });
@@ -261,7 +261,7 @@ export const MainPage =
onLoadOk(selectedUri: string): void {
this.setState({ loadDialogOpen: false });
let itemId = this.state.selectedPedal;
let newSelectedItem = this.model.loadPedalBoardPlugin(itemId, selectedUri);
let newSelectedItem = this.model.loadPedalboardPlugin(itemId, selectedUri);
this.setState({ selectedPedal: newSelectedItem });
}
@@ -269,12 +269,12 @@ export const MainPage =
this.setState({ loadDialogOpen: true });
}
getPedalBoardItem(selectedId?: number): PedalBoardItem | null {
getPedalboardItem(selectedId?: number): PedalboardItem | null {
if (selectedId === undefined) return null;
let pedalBoard = this.model.pedalBoard.get();
if (!pedalBoard) return null;
let it = pedalBoard.itemsGenerator();
let pedalboard = this.model.pedalboard.get();
if (!pedalboard) return null;
let it = pedalboard.itemsGenerator();
if (!selectedId) return null;
while (true) {
let v = it.next();
@@ -290,32 +290,32 @@ export const MainPage =
}
onPedalboardPropertyChanged(instanceId: number, key: string, value: number) {
this.model.setPedalBoardControlValue(instanceId, key, value);
this.model.setPedalboardControl(instanceId, key, value);
}
getSelectedPedalBoardItem(): PedalBoardItem | null {
return this.getPedalBoardItem(this.state.selectedPedal);
getSelectedPedalboardItem(): PedalboardItem | null {
return this.getPedalboardItem(this.state.selectedPedal);
}
getSelectedUri(): string {
let pedalBoardItem = this.getSelectedPedalBoardItem();
if (pedalBoardItem == null) return "";
return pedalBoardItem.uri;
let pedalboardItem = this.getSelectedPedalboardItem();
if (pedalboardItem == null) return "";
return pedalboardItem.uri;
}
titleBar(pedalBoardItem: PedalBoardItem | null): React.ReactNode {
titleBar(pedalboardItem: PedalboardItem | null): React.ReactNode {
let title = "";
let author = "";
let pluginUri = "";
let presetsUri = "";
let missing = false;
if (pedalBoardItem) {
if (pedalBoardItem.isEmpty()) {
if (pedalboardItem) {
if (pedalboardItem.isEmpty()) {
title = "";
} else if (pedalBoardItem.isSplit()) {
} else if (pedalboardItem.isSplit()) {
title = "Split";
} else {
let uiPlugin = this.model.getUiPlugin(pedalBoardItem.uri);
let uiPlugin = this.model.getUiPlugin(pedalboardItem.uri);
if (!uiPlugin) {
missing = true;
title = pedalBoardItem?.pluginName ?? "Missing plugin";
title = pedalboardItem?.pluginName ?? "Missing plugin";
} else {
title = uiPlugin.name;
author = uiPlugin.author_name;
@@ -362,7 +362,7 @@ export const MainPage =
<PluginInfoDialog plugin_uri={pluginUri} />
</div>
<div style={{ flex: "0 0 auto" }}>
<PluginPresetSelector pluginUri={presetsUri} instanceId={pedalBoardItem?.instanceId ?? 0}
<PluginPresetSelector pluginUri={presetsUri} instanceId={pedalboardItem?.instanceId ?? 0}
/>
</div>
</div>
@@ -373,8 +373,8 @@ export const MainPage =
render() {
let classes = this.props.classes;
let pedalBoard = this.model.pedalBoard.get();
let pedalBoardItem = this.getSelectedPedalBoardItem();
let pedalboard = this.model.pedalboard.get();
let pedalboardItem = this.getSelectedPedalboardItem();
let uiPlugin = null;
let bypassVisible = false;
let bypassChecked = false;
@@ -384,20 +384,20 @@ export const MainPage =
let missing = false;
let pluginUri = "#error";
if (pedalBoardItem) {
canDelete = pedalBoard.canDeleteItem(pedalBoardItem.instanceId);
instanceId = pedalBoardItem.instanceId;
if (pedalBoardItem.isEmpty()) {
if (pedalboardItem) {
canDelete = pedalboard.canDeleteItem(pedalboardItem.instanceId);
instanceId = pedalboardItem.instanceId;
if (pedalboardItem.isEmpty()) {
canAdd = true;
} else if (pedalBoardItem.isSplit()) {
} else if (pedalboardItem.isSplit()) {
canAdd = true;
} else {
pluginUri = pedalBoardItem.uri;
pluginUri = pedalboardItem.uri;
uiPlugin = this.model.getUiPlugin(pluginUri);
canAdd = true;
if (uiPlugin) {
bypassVisible = true;
bypassChecked = pedalBoardItem.isEnabled;
bypassChecked = pedalboardItem.isEnabled;
} else {
missing = true;
}
@@ -407,9 +407,9 @@ export const MainPage =
return (
<div className={classes.frame}>
<div id="pedalBoardScroll" className={horizontalScrollLayout ? classes.pedalBoardScrollSmall : classes.pedalBoardScroll}
<div id="pedalboardScroll" className={horizontalScrollLayout ? classes.pedalboardScrollSmall : classes.pedalboardScroll}
style={{ maxHeight: horizontalScrollLayout ? undefined : this.state.screenHeight / 2 }}>
<PedalBoardView key={pluginUri} selectedId={this.state.selectedPedal}
<PedalboardView key={pluginUri} selectedId={this.state.selectedPedal}
onSelectionChanged={this.onSelectionChanged}
onDoubleClick={this.onPedalDoubleClick}
hasTinyToolBar={this.props.hasTinyToolBar}
@@ -427,7 +427,7 @@ export const MainPage =
</div>
</div>
{
(!this.state.splitControlBar) && this.titleBar(pedalBoardItem)
(!this.state.splitControlBar) && this.titleBar(pedalboardItem)
}
<div style={{ flex: "1 1 1px" }}>
@@ -453,7 +453,7 @@ export const MainPage =
</div>
<div style={{ flex: "0 0 auto", display: canDelete ? "block" : "none", paddingRight: 8 }}>
<IconButton
onClick={() => { this.onDeletePedal(pedalBoardItem?.instanceId ?? -1) }}
onClick={() => { this.onDeletePedal(pedalboardItem?.instanceId ?? -1) }}
size="large">
<img src="/img/old_delete_outline_black_24dp.svg" alt="Delete" style={{ width: 24, height: 24, opacity: 0.6 }} />
</IconButton>
@@ -464,7 +464,7 @@ export const MainPage =
color="primary"
size="small"
onClick={this.onLoadClick}
disabled={this.state.selectedPedal === -1 || (this.getSelectedPedalBoardItem()?.isSplit() ?? true)}
disabled={this.state.selectedPedal === -1 || (this.getSelectedPedalboardItem()?.isSplit() ?? true)}
startIcon={<InputIcon />}
style={{ borderRadius: 24, paddingLeft: 18, paddingRight: 18, textTransform: "none"}}
>
@@ -485,7 +485,7 @@ export const MainPage =
this.state.splitControlBar && (
<div className={classes.splitControlBar}>
{
this.titleBar(pedalBoardItem)
this.titleBar(pedalboardItem)
}
</div>
)
@@ -495,12 +495,12 @@ export const MainPage =
missing ? (
<div style={{marginLeft: 100,marginTop: 20}}>
<Typography variant="body1" paragraph={true}>Error: Plugin is not installed.</Typography>
<Typography variant="body2" paragraph={true}>{pluginUri}</Typography>
<Typography noWrap variant="body2" paragraph={true}>{pluginUri}</Typography>
</div>
):
(
GetControlView(pedalBoardItem)
GetControlView(pedalboardItem)
)
}
</div>
+3 -3
View File
@@ -139,8 +139,8 @@ const MidiBindingView =
render() {
let classes = this.props.classes;
let midiBinding = this.props.midiBinding;
let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId);
let uiPlugin = this.model.getUiPlugin(pedalBoardItem.uri);
let pedalboardItem = this.model.pedalboard.get().getItem(this.props.instanceId);
let uiPlugin = this.model.getUiPlugin(pedalboardItem.uri);
if (!uiPlugin) {
return (<div />);
}
@@ -267,7 +267,7 @@ const MidiBindingView =
(canTrigger) &&
(
<div className={classes.controlDiv2} >
<Typography style={{paddingTop: 12, paddingBottom: 12}}>(Trigger)</Typography>
<Typography noWrap style={{paddingTop: 12, paddingBottom: 12}}>(Trigger)</Typography>
</div>
)
+4 -4
View File
@@ -123,8 +123,8 @@ export const MidiBindingDialog =
{
this.cancelListenForControl();
let pedalBoard = this.model.pedalBoard.get();
let item = pedalBoard.getItem(instanceId);
let pedalboard = this.model.pedalboard.get();
let item = pedalboard.getItem(instanceId);
if (!item) return;
let binding = item.getMidiBinding(symbol);
@@ -181,7 +181,7 @@ export const MidiBindingDialog =
let classes = this.props.classes;
let result: React.ReactNode[] = [];
let pedalboard = this.model.pedalBoard.get();
let pedalboard = this.model.pedalboard.get();
let iter = pedalboard.itemsGenerator();
while (true) {
let v = iter.next();
@@ -285,7 +285,7 @@ export const MidiBindingDialog =
size="large">
<ArrowBackIcon />
</IconButton>
<Typography variant="h6" className={classes.dialogTitle}>
<Typography noWrap variant="h6" className={classes.dialogTitle}>
Preset MIDI Bindings
</Typography>
</Toolbar>
@@ -57,30 +57,9 @@ export class ControlValue implements Deserializable<ControlValue> {
value: number;
}
export class PropertyValue implements Deserializable<PropertyValue> {
deserialize(input: any): PropertyValue {
this.propertyUri = input.propertyUri;
this.value = input.value;
return this;
}
static deserializeArray(input: any[]): PropertyValue[] {
let result: PropertyValue[] = [];
for (let i = 0; i < input.length; ++i) {
result[i] = new PropertyValue().deserialize(input[i]);
}
return result;
}
setValue(value: number) {
this.value = value;
}
propertyUri: string = "";
value: any = null;
}
export class PedalBoardItem implements Deserializable<PedalBoardItem> {
deserializePedalBoardItem(input: any): PedalBoardItem {
export class PedalboardItem implements Deserializable<PedalboardItem> {
deserializePedalboardItem(input: any): PedalboardItem {
this.instanceId = input.instanceId ?? -1;
this.uri = input.uri;
this.pluginName = input.pluginName;
@@ -88,24 +67,24 @@ export class PedalBoardItem implements Deserializable<PedalBoardItem> {
this.midiBindings = MidiBinding.deserialize_array(input.midiBindings);
this.controlValues = ControlValue.deserializeArray(input.controlValues);
this.propertyValues = PropertyValue.deserializeArray(input.propertyValues);
this.vstState = input.vstState ?? "";
this.lv2State = input.lv2State;
return this;
}
deserialize(input: any): PedalBoardItem {
return this.deserializePedalBoardItem(input);
deserialize(input: any): PedalboardItem {
return this.deserializePedalboardItem(input);
}
static deserializeArray(input: any): PedalBoardItem[] {
let result: PedalBoardItem[] = [];
static deserializeArray(input: any): PedalboardItem[] {
let result: PedalboardItem[] = [];
for (let i = 0; i < input.length; ++i) {
let inputItem: any = input[i];
let uri: string = inputItem.uri as string;
let outputItem: PedalBoardItem;
let outputItem: PedalboardItem;
if (uri === SPLIT_PEDALBOARD_ITEM_URI) {
outputItem = new PedalBoardSplitItem().deserialize(inputItem);
outputItem = new PedalboardSplitItem().deserialize(inputItem);
} else {
outputItem = new PedalBoardItem().deserialize(inputItem);
outputItem = new PedalboardItem().deserialize(inputItem);
}
result[i] = outputItem;
@@ -158,17 +137,6 @@ export class PedalBoardItem implements Deserializable<PedalBoardItem> {
}
return false;
}
setPropertyValue(propertyUri: string, value: any): boolean {
for (let i = 0; i < this.propertyValues.length; ++i) {
let v = this.propertyValues[i];
if (v.propertyUri === propertyUri) {
if (v.value === value) return false;
v.value = value;
return true;
}
}
return false;
}
setMidiBinding(midiBinding: MidiBinding): boolean {
if (this.midiBindings)
{
@@ -209,16 +177,16 @@ export class PedalBoardItem implements Deserializable<PedalBoardItem> {
}
static EmptyArray: PedalBoardItem[] = [];
static EmptyArray: PedalboardItem[] = [];
instanceId: number = -1;
isEnabled: boolean = false;
uri: string = "";
pluginName?: string;
controlValues: ControlValue[] = ControlValue.EmptyArray;
propertyValues: PropertyValue[] = [];
midiBindings: MidiBinding[] = [];
vstState: string = "";
lv2State: any = {};
};
@@ -230,7 +198,7 @@ export enum SplitType {
export class PedalBoardSplitItem extends PedalBoardItem {
export class PedalboardSplitItem extends PedalboardItem {
static PANL_KEY: string = "panL";
static PANR_KEY: string = "panR";
static VOLL_KEY: string = "volL";
@@ -241,15 +209,15 @@ export class PedalBoardSplitItem extends PedalBoardItem {
static SELECT_KEY: string = "select";
deserialize(input: any): PedalBoardSplitItem {
this.deserializePedalBoardItem(input);
this.topChain = PedalBoardItem.deserializeArray(input.topChain);
this.bottomChain = PedalBoardItem.deserializeArray(input.bottomChain);
deserialize(input: any): PedalboardSplitItem {
this.deserializePedalboardItem(input);
this.topChain = PedalboardItem.deserializeArray(input.topChain);
this.bottomChain = PedalboardItem.deserializeArray(input.bottomChain);
return this;
}
getSplitType(): SplitType {
let rawValue = this.getControlValue(PedalBoardSplitItem.TYPE_KEY);
let rawValue = this.getControlValue(PedalboardSplitItem.TYPE_KEY);
if (rawValue < 1) return SplitType.Ab;
if (rawValue < 2) return SplitType.Mix;
@@ -263,43 +231,43 @@ export class PedalBoardSplitItem extends PedalBoardItem {
}
getMixControl(): ControlValue {
return this.getControl(PedalBoardSplitItem.MIX_KEY);
return this.getControl(PedalboardSplitItem.MIX_KEY);
}
getMix(): number {
return this.getControlValue(PedalBoardSplitItem.MIX_KEY);
return this.getControlValue(PedalboardSplitItem.MIX_KEY);
}
isASelected(): boolean {
return this.getSplitType() !== SplitType.Ab || this.getControlValue(PedalBoardSplitItem.SELECT_KEY) === 0;
return this.getSplitType() !== SplitType.Ab || this.getControlValue(PedalboardSplitItem.SELECT_KEY) === 0;
}
isBSelected(): boolean {
return this.getSplitType() !== SplitType.Ab || this.getControlValue(PedalBoardSplitItem.SELECT_KEY) !== 0;
return this.getSplitType() !== SplitType.Ab || this.getControlValue(PedalboardSplitItem.SELECT_KEY) !== 0;
}
topChain: PedalBoardItem[] = PedalBoardItem.EmptyArray;
bottomChain: PedalBoardItem[] = PedalBoardItem.EmptyArray;
topChain: PedalboardItem[] = PedalboardItem.EmptyArray;
bottomChain: PedalboardItem[] = PedalboardItem.EmptyArray;
}
export class PedalBoard implements Deserializable<PedalBoard> {
export class Pedalboard implements Deserializable<Pedalboard> {
deserialize(input: any): PedalBoard {
deserialize(input: any): Pedalboard {
this.name = input.name;
this.items = PedalBoardItem.deserializeArray(input.items);
this.items = PedalboardItem.deserializeArray(input.items);
this.nextInstanceId = input.nextInstanceId ?? -1;
return this;
}
clone(): PedalBoard {
return new PedalBoard().deserialize(this);
clone(): Pedalboard {
return new Pedalboard().deserialize(this);
}
name: string = "";
items: PedalBoardItem[] = [];
items: PedalboardItem[] = [];
nextInstanceId: number = -1;
*itemsGenerator(): Generator<PedalBoardItem, void, undefined> {
*itemsGenerator(): Generator<PedalboardItem, void, undefined> {
let it = itemGenerator_(this.items);
while (true)
{
@@ -335,7 +303,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
maybeGetItem(instanceId: number): PedalBoardItem | null{
maybeGetItem(instanceId: number): PedalboardItem | null{
let it = this.itemsGenerator();
while (true)
{
@@ -348,7 +316,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
return null;
}
getItem(instanceId: number): PedalBoardItem {
getItem(instanceId: number): PedalboardItem {
let it = this.itemsGenerator();
while (true)
{
@@ -361,7 +329,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
throw new PiPedalArgumentError("Item not found.");
}
deleteItem_(instanceId: number,items: PedalBoardItem[]): number | null
deleteItem_(instanceId: number,items: PedalboardItem[]): number | null
{
for (let i = 0; i < items.length; ++i)
{
@@ -383,7 +351,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
} else {
if (item.isSplit())
{
let splitItem = item as PedalBoardSplitItem;
let splitItem = item as PedalboardSplitItem;
let t = this.deleteItem_(instanceId,splitItem.topChain);
if (t != null) return t;
@@ -395,7 +363,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
return null;
}
canDeleteItem_(instanceId: number,items: PedalBoardItem[]): boolean
canDeleteItem_(instanceId: number,items: PedalboardItem[]): boolean
{
for (let i = 0; i < items.length; ++i)
{
@@ -407,7 +375,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
if (item.isSplit())
{
let splitItem = item as PedalBoardSplitItem;
let splitItem = item as PedalboardSplitItem;
if (this.canDeleteItem_(instanceId,splitItem.topChain))
{
return true;
@@ -436,15 +404,15 @@ export class PedalBoard implements Deserializable<PedalBoard> {
if (!item) return false;
return item.setMidiBinding(midiBinding);
}
addToStart(item: PedalBoardItem)
addToStart(item: PedalboardItem)
{
this.items.splice(0,0,item);
}
addToEnd(item: PedalBoardItem)
addToEnd(item: PedalboardItem)
{
this.items.splice(this.items.length,0,item);
}
static _addRelative(items: PedalBoardItem[],newItem: PedalBoardItem, instanceId: number, addBefore: boolean): boolean
static _addRelative(items: PedalboardItem[],newItem: PedalboardItem, instanceId: number, addBefore: boolean): boolean
{
for (let i = 0; i < items.length; ++i)
{
@@ -461,7 +429,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
if (item.isSplit())
{
let split = item as PedalBoardSplitItem;
let split = item as PedalboardSplitItem;
if (this._addRelative(split.topChain,newItem,instanceId,addBefore))
{
return true;
@@ -476,19 +444,19 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
addBefore(item: PedalBoardItem, instanceId: number)
addBefore(item: PedalboardItem, instanceId: number)
{
if (item.instanceId === instanceId) return;
let result = PedalBoard._addRelative(this.items,item, instanceId, true);
let result = Pedalboard._addRelative(this.items,item, instanceId, true);
if (!result) {
throw new PiPedalArgumentError("instanceId not found.");
}
}
addAfter(item: PedalBoardItem, instanceId: number)
addAfter(item: PedalboardItem, instanceId: number)
{
if (item.instanceId === instanceId) return;
let result = PedalBoard._addRelative(this.items,item, instanceId, false);
let result = Pedalboard._addRelative(this.items,item, instanceId, false);
if (!result) {
throw new PiPedalArgumentError("instanceId not found.");
}
@@ -520,8 +488,8 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
}
}
createEmptySplit(): PedalBoardSplitItem {
let result: PedalBoardSplitItem = new PedalBoardSplitItem();
createEmptySplit(): PedalboardSplitItem {
let result: PedalboardSplitItem = new PedalboardSplitItem();
result.uri = SPLIT_PEDALBOARD_ITEM_URI;
result.instanceId = ++this.nextInstanceId;
result.pluginName = "";
@@ -529,13 +497,13 @@ export class PedalBoard implements Deserializable<PedalBoard> {
result.topChain = [ this.createEmptyItem()];
result.bottomChain = [ this.createEmptyItem()];
result.controlValues = [
new ControlValue(PedalBoardSplitItem.TYPE_KEY, 0),
new ControlValue(PedalBoardSplitItem.SELECT_KEY,0),
new ControlValue(PedalBoardSplitItem.MIX_KEY,0),
new ControlValue(PedalBoardSplitItem.PANL_KEY,0),
new ControlValue(PedalBoardSplitItem.VOLL_KEY,-3),
new ControlValue(PedalBoardSplitItem.PANR_KEY,0),
new ControlValue(PedalBoardSplitItem.VOLR_KEY,-3)
new ControlValue(PedalboardSplitItem.TYPE_KEY, 0),
new ControlValue(PedalboardSplitItem.SELECT_KEY,0),
new ControlValue(PedalboardSplitItem.MIX_KEY,0),
new ControlValue(PedalboardSplitItem.PANL_KEY,0),
new ControlValue(PedalboardSplitItem.VOLL_KEY,-3),
new ControlValue(PedalboardSplitItem.PANR_KEY,0),
new ControlValue(PedalboardSplitItem.VOLR_KEY,-3)
];
@@ -543,8 +511,8 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
createEmptyItem(): PedalBoardItem {
let result: PedalBoardItem = new PedalBoardItem();
createEmptyItem(): PedalboardItem {
let result: PedalboardItem = new PedalboardItem();
result.uri = EMPTY_PEDALBOARD_ITEM_URI;
result.instanceId = ++this.nextInstanceId;
result.pluginName = "";
@@ -552,7 +520,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
return result;
}
setItemEmpty(item: PedalBoardItem)
setItemEmpty(item: PedalboardItem)
{
item.uri = EMPTY_PEDALBOARD_ITEM_URI;
item.instanceId = ++this.nextInstanceId;
@@ -562,7 +530,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
_replaceItem(items: PedalBoardItem[], instanceId: number, newItem: PedalBoardItem): boolean {
_replaceItem(items: PedalboardItem[], instanceId: number, newItem: PedalboardItem): boolean {
for (let i = 0; i < items.length; ++i)
{
let item = items[i];
@@ -573,7 +541,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
if (items[i].isSplit())
{
let splitItem = item as PedalBoardSplitItem;
let splitItem = item as PedalboardSplitItem;
if (this._replaceItem(splitItem.topChain,instanceId,newItem))
return true;
if (this._replaceItem(splitItem.bottomChain,instanceId,newItem))
@@ -585,7 +553,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
return false;
}
replaceItem(instanceId: number, newItem: PedalBoardItem)
replaceItem(instanceId: number, newItem: PedalboardItem)
{
let result = this._replaceItem(this.items,instanceId,newItem);
if (!result)
@@ -593,7 +561,7 @@ export class PedalBoard implements Deserializable<PedalBoard> {
throw new PiPedalArgumentError("instanceId not found.");
}
}
_addItem(items: PedalBoardItem[], newItem: PedalBoardItem, instanceId: number, append: boolean)
_addItem(items: PedalboardItem[], newItem: PedalboardItem, instanceId: number, append: boolean)
{
for (let i = 0; i < items.length; ++i)
{
@@ -611,27 +579,27 @@ export class PedalBoard implements Deserializable<PedalBoard> {
}
if (item.isSplit())
{
let splitItem = item as PedalBoardSplitItem;
let splitItem = item as PedalboardSplitItem;
if (this._addItem(splitItem.topChain,newItem,instanceId,append)) return true;
if (this._addItem(splitItem.bottomChain,newItem,instanceId,append)) return true;
}
}
}
addItem(newItem: PedalBoardItem, instanceId: number, append: boolean): void
addItem(newItem: PedalboardItem, instanceId: number, append: boolean): void
{
this._addItem(this.items,newItem,instanceId,append);
}
}
function* itemGenerator_(items: PedalBoardItem[]): Generator<PedalBoardItem, void, undefined> {
function* itemGenerator_(items: PedalboardItem[]): Generator<PedalboardItem, void, undefined> {
for (let i = 0; i < items.length; ++i) {
let item = items[i];
yield item;
if (item.uri === SPLIT_PEDALBOARD_ITEM_URI) {
let splitItem = item as PedalBoardSplitItem;
let splitItem = item as PedalboardSplitItem;
let it = itemGenerator_(splitItem.topChain);
while (true) {
@@ -36,8 +36,8 @@ import Utility from './Utility'
import {
PedalBoard, PedalBoardItem, PedalBoardSplitItem, SplitType,
} from './PedalBoard';
Pedalboard, PedalboardItem, PedalboardSplitItem, SplitType,
} from './Pedalboard';
const START_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#Start";
const END_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#End";
@@ -69,7 +69,7 @@ function CalculateConnection(numberOfInputs: number, numberOfOutputs: number)
return result;
}
const pedalBoardStyles = (theme: Theme) => createStyles({
const pedalboardStyles = (theme: Theme) => createStyles({
scrollContainer: {
},
@@ -177,7 +177,7 @@ const pedalBoardStyles = (theme: Theme) => createStyles({
export type OnSelectHandler = (selectedPedal: number) => void;
interface PedalBoardProps extends WithStyles<typeof pedalBoardStyles> {
interface PedalboardProps extends WithStyles<typeof pedalboardStyles> {
theme: Theme;
selectedId?: number;
onSelectionChanged?: OnSelectHandler;
@@ -190,14 +190,14 @@ interface LayoutSize {
height: number;
}
type PedalBoardState = {
pedalBoard?: PedalBoard;
type PedalboardState = {
pedalboard?: Pedalboard;
};
const EMPTY_PEDALS: PedalLayout[] = [];
function makeChain(model: PiPedalModel, uiItems?: PedalBoardItem[]): PedalLayout[] {
function makeChain(model: PiPedalModel, uiItems?: PedalboardItem[]): PedalLayout[] {
let result: PedalLayout[] = [];
if (uiItems) {
for (let i = 0; i < uiItems.length; ++i) {
@@ -219,7 +219,7 @@ class PedalLayout {
numberOfInputs: number = 2;
numberOfOutputs: number = 2;
pedalItem?: PedalBoardItem;
pedalItem?: PedalboardItem;
// Split Layout only.
topChildren: PedalLayout[] = EMPTY_PEDALS;
@@ -245,7 +245,7 @@ class PedalLayout {
t.numberOfOutputs = 0;
return t;
}
constructor(model?: PiPedalModel, pedalItem?: PedalBoardItem) {
constructor(model?: PiPedalModel, pedalItem?: PedalboardItem) {
if (model === undefined && pedalItem === undefined) {
return;
}
@@ -255,7 +255,7 @@ class PedalLayout {
this.pedalItem = pedalItem;
this.uri = pedalItem.uri;
if (pedalItem.isSplit()) {
let splitter = pedalItem as PedalBoardSplitItem;
let splitter = pedalItem as PedalboardSplitItem;
this.pluginType = PluginType.UtilityPlugin;
this.topChildren = makeChain(model, splitter.topChain);
@@ -350,9 +350,9 @@ class LayoutParams {
}
const PedalBoardView =
withStyles(pedalBoardStyles, { withTheme: true })(
class extends Component<PedalBoardProps, PedalBoardState>
const PedalboardView =
withStyles(pedalboardStyles, { withTheme: true })(
class extends Component<PedalboardProps, PedalboardState>
{
model: PiPedalModel;
@@ -360,15 +360,15 @@ const PedalBoardView =
scrollRef: React.RefObject<HTMLDivElement>;
constructor(props: PedalBoardProps) {
constructor(props: PedalboardProps) {
super(props);
this.model = PiPedalModelFactory.getInstance();
if (!props.selectedId) props.selectedId = -1;
this.state = {
pedalBoard: this.model.pedalBoard.get(),
pedalboard: this.model.pedalboard.get(),
};
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.frameRef = React.createRef();
this.scrollRef = React.createRef();
this.handleTouchStart = this.handleTouchStart.bind(this);
@@ -402,11 +402,11 @@ const PedalBoardView =
if (item.isSplitter() && item.pedalItem) {
if (item.bounds.contains(clientX, clientY)) {
if (clientX < item.bounds.x + CELL_WIDTH / 2) {
this.model.movePedalBoardItemBefore(instanceId, item.pedalItem.instanceId);
this.model.movePedalboardItemBefore(instanceId, item.pedalItem.instanceId);
this.setSelection(instanceId);
return;
} else if (clientX > item.bounds.right - CELL_WIDTH / 2) {
this.model.movePedalBoardItemAfter(instanceId, item.pedalItem.instanceId);
this.model.movePedalboardItemAfter(instanceId, item.pedalItem.instanceId);
this.setSelection(instanceId);
return;
@@ -420,7 +420,7 @@ const PedalBoardView =
if (clientX < item.topChildren[0].bounds.x) {
let topPedalItem = item.topChildren[0].pedalItem;
if (topPedalItem) {
this.model.movePedalBoardItemBefore(instanceId, topPedalItem.instanceId);
this.model.movePedalboardItemBefore(instanceId, topPedalItem.instanceId);
this.setSelection(instanceId);
return;
}
@@ -428,7 +428,7 @@ const PedalBoardView =
let lastTop = item.topChildren[item.topChildren.length - 1];
if (clientX >= lastTop.bounds.right && clientX < item.bounds.right - CELL_WIDTH / 2) {
if (lastTop.pedalItem) {
this.model.movePedalBoardItemAfter(instanceId, lastTop.pedalItem.instanceId);
this.model.movePedalboardItemAfter(instanceId, lastTop.pedalItem.instanceId);
this.setSelection(instanceId);
return;
}
@@ -441,7 +441,7 @@ const PedalBoardView =
if (clientX < item.bottomChildren[0].bounds.x) {
let bottomPedalItem = item.bottomChildren[0].pedalItem;
if (bottomPedalItem) {
this.model.movePedalBoardItemBefore(instanceId, bottomPedalItem.instanceId);
this.model.movePedalboardItemBefore(instanceId, bottomPedalItem.instanceId);
this.setSelection(instanceId);
return;
}
@@ -450,7 +450,7 @@ const PedalBoardView =
if (clientX >= lastBottom.bounds.right && clientX < item.bounds.right-CELL_WIDTH/2)
{
if (lastBottom.pedalItem) {
this.model.movePedalBoardItemAfter(instanceId, lastBottom.pedalItem.instanceId);
this.model.movePedalboardItemAfter(instanceId, lastBottom.pedalItem.instanceId);
this.setSelection(instanceId);
return;
}
@@ -461,11 +461,11 @@ const PedalBoardView =
} else if (item.bounds.contains(clientX, clientY)) {
if (item.isStart()) {
this.model.movePedalBoardItemToStart(instanceId);
this.model.movePedalboardItemToStart(instanceId);
this.setSelection(instanceId);
return;
} else if (item.isEnd()) {
this.model.movePedalBoardItemToEnd(instanceId);
this.model.movePedalboardItemToEnd(instanceId);
this.setSelection(instanceId);
return;
} else {
@@ -473,11 +473,11 @@ const PedalBoardView =
{
let margin = (CELL_WIDTH - FRAME_SIZE) / 2;
if (clientX < item.bounds.x + margin) {
this.model.movePedalBoardItemBefore(instanceId, item.pedalItem.instanceId);
this.model.movePedalboardItemBefore(instanceId, item.pedalItem.instanceId);
} else if (clientX > item.bounds.right - margin) {
this.model.movePedalBoardItemAfter(instanceId, item.pedalItem.instanceId);
this.model.movePedalboardItemAfter(instanceId, item.pedalItem.instanceId);
} else {
this.model.movePedalBoardItem(instanceId, item.pedalItem.instanceId);
this.model.movePedalboardItem(instanceId, item.pedalItem.instanceId);
}
this.setSelection(instanceId);
return;
@@ -487,23 +487,23 @@ const PedalBoardView =
}
}
// delete the plugin.
let newId = this.model.setPedalBoardItemEmpty(instanceId);
let newId = this.model.setPedalboardItemEmpty(instanceId);
this.setSelection(newId);
}
onPedalBoardChanged(value?: PedalBoard) {
this.setState({ pedalBoard: value });
onPedalboardChanged(value?: Pedalboard) {
this.setState({ pedalboard: value });
}
componentDidMount() {
this.scrollRef.current!.addEventListener("touchstart",this.handleTouchStart, {passive: false});
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
}
componentWillUnmount() {
this.scrollRef.current!.removeEventListener("touchstart",this.handleTouchStart);
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
}
offsetLayout_(layoutItems: PedalLayout[], offset: number): void {
@@ -523,7 +523,7 @@ const PedalBoardView =
if (layoutItem.pedalItem === undefined) {
throw new Error("Invalid splitter");
}
let split = layoutItem.pedalItem as PedalBoardSplitItem;
let split = layoutItem.pedalItem as PedalboardSplitItem;
if (split.getSplitType() === SplitType.Ab) {
if (split.isASelected()) {
return "img/fx_split_a.svg";
@@ -706,7 +706,7 @@ const PedalBoardView =
let yTop = item.topConnectorY;
let yBottom = item.bottomConnectorY;
//let isStereo = item.stereoOutput;
let split = item.pedalItem as PedalBoardSplitItem;
let split = item.pedalItem as PedalboardSplitItem;
let topEnabled = enabled && split.isASelected();
let bottomEnabled = enabled && split.isBSelected();
@@ -889,7 +889,7 @@ const PedalBoardView =
// actually not here anymore. :-/ It has a reactive definition in MainPage.tsx now.
while (el)
{
if (el.id === "pedalBoardScroll")
if (el.id === "pedalboardScroll")
{
return el as HTMLDivElement;
}
@@ -930,7 +930,7 @@ const PedalBoardView =
for (let i = 0; i < length; ++i) {
let item = layoutChain[i];
if (item.isSplitter()) {
let splitter = item.pedalItem as PedalBoardSplitItem;
let splitter = item.pedalItem as PedalboardSplitItem;
this.renderSplitConnectors(output, item, enabled, i === length - 1 && shortSplitOutput,);
this.renderConnectors(output, item.topChildren, enabled && splitter.isASelected(), false);
this.renderConnectors(output, item.bottomChildren, enabled && splitter.isBSelected(), false);
@@ -942,15 +942,14 @@ const PedalBoardView =
}
}
renderConnectorFrame(layoutChain: PedalLayout[], layoutSize: LayoutSize): ReactNode {
let output: ReactNode[] = [];
this.renderConnectors(output, layoutChain, true, false);
let outputs: ReactNode[] = [];
this.renderConnectors(outputs, layoutChain, true, false);
return (
<svg width={layoutSize.width} height={layoutSize.height}
xmlns="http://www.w3.org/2000/svg" viewBox={"0 0 " + layoutSize.width + " " + layoutSize.height}>
<g fill="none">
{
output
outputs
}
</g>
@@ -1065,7 +1064,7 @@ const PedalBoardView =
let topInputs = item.topChildren[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)
{
item.numberOfInputs = CalculateConnection(item.numberOfInputs, Math.max(topInputs,bottomInputs));
@@ -1102,7 +1101,7 @@ const PedalBoardView =
for (let i = 0; i < layoutChain.length; ++i) {
let item = layoutChain[i];
if (item.isSplitter()) {
let splitter = item.pedalItem as PedalBoardSplitItem;
let splitter = item.pedalItem as PedalboardSplitItem;
item.numberOfInputs = numberOfInputs;
let chainInputs = numberOfInputs;
@@ -1156,7 +1155,7 @@ const PedalBoardView =
render() {
const { classes } = this.props;
let layoutChain = makeChain(this.model, this.state.pedalBoard?.items);
let layoutChain = makeChain(this.model, this.state.pedalboard?.items);
let start = PedalLayout.Start();
let end = PedalLayout.End();
if (layoutChain.length !== 0)
@@ -1187,4 +1186,4 @@ const PedalBoardView =
}
);
export default PedalBoardView
export default PedalboardView
+423 -372
View File
File diff suppressed because it is too large Load Diff
+42 -45
View File
@@ -23,10 +23,10 @@ import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { UiPlugin, UiControl, PiPedalFileProperty,PiPedalFileType } from './Lv2Plugin';
import { UiPlugin, UiControl, PiPedalFileProperty} from './Lv2Plugin';
import {
PedalBoard, PedalBoardItem, ControlValue,PropertyValue
} from './PedalBoard';
Pedalboard, PedalboardItem, ControlValue
} from './Pedalboard';
import PluginControl from './PluginControl';
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import VuMeter from './VuMeter';
@@ -36,6 +36,7 @@ import Typography from '@mui/material/Typography';
import FullScreenIME from './FullScreenIME';
import FilePropertyControl from './FilePropertyControl';
import FilePropertyDialog from './FilePropertyDialog';
import JsonAtom from './JsonAtom';
export const StandardItemSize = { width: 80, height: 110 };
@@ -188,7 +189,7 @@ export interface ControlViewCustomization {
export interface PluginControlViewProps extends WithStyles<typeof styles> {
theme: Theme;
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
customization?: ControlViewCustomization;
customizationId?: number;
}
@@ -224,35 +225,32 @@ const PluginControlView =
dialogFileValue: ""
}
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.onControlValueChanged = this.onControlValueChanged.bind(this);
this.onPreviewChange = this.onPreviewChange.bind(this);
}
onPreviewChange(key: string, value: number): void {
this.model.previewPedalBoardValue(this.props.instanceId, key, value);
this.model.previewPedalboardValue(this.props.instanceId, key, value);
}
onControlValueChanged(key: string, value: number): void {
this.model.setPedalBoardControlValue(this.props.instanceId, key, value);
}
onPropertyValueChanged(propertyUri: string, value: any): void {
this.model.setPedalBoardPropertyValue(this.props.instanceId, propertyUri, value);
this.model.setPedalboardControl(this.props.instanceId, key, value);
}
onPedalBoardChanged(value?: PedalBoard) {
//let item = this.model.pedalBoard.get().maybeGetItem(this.props.instanceId);
//this.setState({ pedalBoardItem: item });
onPedalboardChanged(value?: Pedalboard) {
//let item = this.model.pedalboard.get().maybeGetItem(this.props.instanceId);
//this.setState({ pedalboardItem: item });
}
componentDidMount() {
super.componentDidMount();
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
}
componentWillUnmount() {
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
super.componentWillUnmount();
}
@@ -285,22 +283,10 @@ const PluginControlView =
});
}
makeFilePropertyUI(fileProperty: PiPedalFileProperty, propertyValues: PropertyValue[]): ReactNode {
let propertyValue: PropertyValue | undefined = undefined;
for (let i = 0; i < propertyValues.length; ++i) {
if (propertyValues[i].propertyUri === fileProperty.patchProperty) {
propertyValue = propertyValues[i];
break;
}
}
if (!propertyValue) {
propertyValue = new PropertyValue();
propertyValue.value = fileProperty.defaultFile;
propertyValue.propertyUri = fileProperty.patchProperty;
}
makeFilePropertyUI(fileProperty: PiPedalFileProperty): ReactNode {
return ((
<FilePropertyControl instanceId={this.props.instanceId} value={propertyValue.value}
<FilePropertyControl instanceId={this.props.instanceId}
fileProperty={fileProperty}
onFileClick={(fileProperty,selectedFile) => {
this.setState({showFileDialog: true,dialogFileProperty: fileProperty,dialogFileValue: selectedFile});
@@ -333,7 +319,7 @@ const PluginControlView =
}
getStandardControlNodes(plugin: UiPlugin, controlValues: ControlValue[],propertyValues: PropertyValue[]): ControlNodes {
getStandardControlNodes(plugin: UiPlugin, controlValues: ControlValue[]): ControlNodes {
let result: ControlNodes = [];
for (let i = 0; i < plugin.controls.length; ++i) {
@@ -350,7 +336,7 @@ const PluginControlView =
pluginControl = plugin.controls[i];
if (!pluginControl.not_on_gui) {
groupControls.push(
this.makeStandardControl(pluginControl, controlValues)
this.makeStandardControl(pluginControl,controlValues)
)
}
}
@@ -359,7 +345,7 @@ const PluginControlView =
)
} else {
result.push(
this.makeStandardControl(pluginControl, controlValues)
this.makeStandardControl(pluginControl,controlValues)
);
}
}
@@ -367,7 +353,7 @@ const PluginControlView =
for (let i = 0; i < plugin.fileProperties.length; ++i) {
let fileProperty = plugin.fileProperties[i];
result.push(
this.makeFilePropertyUI(fileProperty, propertyValues)
this.makeFilePropertyUI(fileProperty)
);
}
return result;
@@ -383,7 +369,7 @@ const PluginControlView =
}
onImeValueChange(key: string, value: number) {
this.model.setPedalBoardControlValue(this.props.instanceId, key, value);
this.model.setPedalboardControl(this.props.instanceId, key, value);
this.onImeClose();
}
onImeClose() {
@@ -427,7 +413,7 @@ const PluginControlView =
result.push((
<div className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}>
<div className={classes.portGroupTitle}>
<Typography variant="caption">{controlGroup.name}</Typography>
<Typography noWrap variant="caption">{controlGroup.name}</Typography>
</div>
<div className={classes.portGroupControls} >
{
@@ -452,16 +438,15 @@ const PluginControlView =
render(): ReactNode {
let classes = this.props.classes;
let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId);
let pedalboardItem = this.model.pedalboard.get().getItem(this.props.instanceId);
if (!pedalBoardItem)
if (!pedalboardItem)
return (<div className={classes.frame} ></div>);
let controlValues = pedalBoardItem.controlValues;
let propertyValues = pedalBoardItem.propertyValues;
let controlValues = pedalboardItem.controlValues;
let plugin: UiPlugin = nullCast(this.model.getUiPlugin(pedalBoardItem.uri));
let plugin: UiPlugin = nullCast(this.model.getUiPlugin(pedalboardItem.uri));
controlValues = this.filterNotOnGui(controlValues, plugin);
@@ -472,7 +457,7 @@ const PluginControlView =
let vuMeterRClass = this.state.landscapeGrid ? classes.vuMeterRLandscape : classes.vuMeterR;
let controlNodes: ControlNodes;
controlNodes = this.getStandardControlNodes(plugin, controlValues,propertyValues);
controlNodes = this.getStandardControlNodes(plugin, controlValues);
if (this.props.customization) {
// allow wrapper class to insert/remove/rebuild controls.
@@ -484,10 +469,10 @@ const PluginControlView =
return (
<div className={classes.frame}>
<div className={classes.vuMeterL}>
<VuMeter display="input" instanceId={pedalBoardItem.instanceId} />
<VuMeter display="input" instanceId={pedalboardItem.instanceId} />
</div>
<div className={vuMeterRClass}>
<VuMeter display="output" instanceId={pedalBoardItem.instanceId} />
<VuMeter display="output" instanceId={pedalboardItem.instanceId} />
</div>
<div className={gridClass} >
{
@@ -503,9 +488,21 @@ const PluginControlView =
<FilePropertyDialog open={this.state.showFileDialog}
fileProperty={this.state.dialogFileProperty}
selectedFile={this.state.dialogFileValue}
onClose={()=> { this.setState({ showFileDialog: false});}}
onCancel={()=> { this.setState({ showFileDialog: false});}}
onOk={(fileProperty,selectedFile)=> {
this.model.setPedalBoardPropertyValue(this.props.instanceId,fileProperty.patchProperty,selectedFile)
this.model.setPatchProperty(
this.props.instanceId,
fileProperty.patchProperty,
JsonAtom.Path(selectedFile)
)
.then( () => {
})
.catch((error) =>
{
this.model.showAlert("setPatchProperty failed: " +error);
});
this.setState({ showFileDialog: false});}
}
/>
+4 -4
View File
@@ -259,7 +259,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })(
<img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" />
</div>
<div className={classes.itemLabel}>
<Typography>
<Typography> noWrap
{presetEntry.label}
</Typography>
</div>
@@ -312,8 +312,8 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })(
this.setState({ renameOpen: false });
}
getPluginUri() : string {
let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId);
return pedalBoardItem.uri;
let pedalboardItem = this.model.pedalboard.get().getItem(this.props.instanceId);
return pedalboardItem.uri;
}
handleCopy() {
let item = this.props.presets.getItem(this.state.selectedItem);
@@ -359,7 +359,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })(
>
<ArrowBackIcon />
</IconButton>
<Typography variant="h6" className={classes.dialogTitle}>
<Typography noWrap variant="h6" className={classes.dialogTitle}>
{title}
</Typography>
<IconButton color="inherit" onClick={(e) => this.showActionBar(true)} >
+31 -26
View File
@@ -497,6 +497,10 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
}
onOnboardingContinue() {
this.model.setOnboarding(false);
this.props.onClose();
}
render() {
let classes = this.props.classes;
let isConfigValid = this.state.jackConfiguration.isValid;
@@ -544,40 +548,41 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
}}
>
<div >
{this.props.onboarding ?
{this.props.onboarding &&
(
<div>
<Typography display="block" variant="caption" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}>
<Typography display="block" variant="body1" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}>
Select and configure an audio device. You may optionally configure MIDI inputs, and set up a Wi-Fi Direct Hotspot now as well.
</Typography>
<Typography display="block" variant="caption" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}>
<Typography display="block" variant="body1" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}>
Access and modify these settings later by selecting the <i>Settings</i> menu item on the main menu.
</Typography>
</div>
):
(
<div>
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
STATUS
</Typography>
{(!isConfigValid) ?
(
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
<Typography display="block" variant="caption" color="textSecondary">Status: <span style={{ color: "#F00" }}>Not configured.</span></Typography>
<Typography display="block" variant="caption" color="textSecondary">Governor: </Typography>
</div>
) :
(
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
{JackHostStatus.getDisplayView("", this.state.jackStatus)}
{JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
</div>
)
}
<Divider />
</div>
)}
<div>
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
STATUS
</Typography>
{(!isConfigValid) ?
(
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
<Typography display="block" variant="caption" color="textSecondary">Status: <span style={{ color: "#F00" }}>Not configured.</span></Typography>
{(!this.props.onboarding) && (
<Typography display="block" variant="caption" color="textSecondary">Governor: </Typography>
)}
</div>
) :
(
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
{JackHostStatus.getDisplayView("", this.state.jackStatus)}
{ (!this.props.onboarding) && JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
</div>
)
}
</div>
{this.state.jackConfiguration.errorState !== "" &&
(
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
@@ -782,7 +787,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<Divider/>
<div style={{display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16,marginRight: 16,
marginTop: 16,marginBottom: 16}}>
<Button variant="outlined" disabled={this.state.continueDisabled} style={{width: 120}}>Continue</Button>
<Button variant="outlined" onClick={()=> {this.onOnboardingContinue()}} disabled={this.state.continueDisabled} style={{width: 120}}>Continue</Button>
</div>
</div>
)
+22 -22
View File
@@ -25,8 +25,8 @@ import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { UiPlugin } from './Lv2Plugin';
import {
PedalBoard, PedalBoardSplitItem, ControlValue,
} from './PedalBoard';
Pedalboard, PedalboardSplitItem, ControlValue,
} from './Pedalboard';
import PluginControl from './PluginControl';
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import VuMeter from './VuMeter';
@@ -97,7 +97,7 @@ const styles = (theme: Theme) => createStyles({
interface SplitControlViewProps extends WithStyles<typeof styles> {
theme: Theme;
instanceId: number;
item: PedalBoardSplitItem;
item: PedalboardSplitItem;
}
type SplitControlViewState = {
landscapeGrid: boolean;
@@ -117,32 +117,32 @@ const SplitControlView =
landscapeGrid: false
}
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.onValueChanged = this.onValueChanged.bind(this);
this.onPreviewChange = this.onPreviewChange.bind(this);
}
onPreviewChange(key: string, value: number): void {
this.model.previewPedalBoardValue(this.props.instanceId, key, value);
this.model.previewPedalboardValue(this.props.instanceId, key, value);
}
onValueChanged(key: string, value: number): void {
this.model.setPedalBoardControlValue(this.props.instanceId, key, value);
this.model.setPedalboardControl(this.props.instanceId, key, value);
}
onPedalBoardChanged(value?: PedalBoard) {
//let item = this.model.pedalBoard.get().maybeGetItem(this.props.instanceId);
//this.setState({ pedalBoardItem: item });
onPedalboardChanged(value?: Pedalboard) {
//let item = this.model.pedalboard.get().maybeGetItem(this.props.instanceId);
//this.setState({ pedalboardItem: item });
}
componentDidMount() {
super.componentDidMount();
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
}
componentWillUnmount() {
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
super.componentWillUnmount();
}
@@ -162,29 +162,29 @@ const SplitControlView =
render(): ReactNode {
let classes = this.props.classes;
let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId);
let pedalboardItem = this.model.pedalboard.get().getItem(this.props.instanceId);
if (!pedalBoardItem)
if (!pedalboardItem)
return (<div className={classes.frame}></div>);
let gridClass = this.state.landscapeGrid ? classes.landscapeGrid : classes.normalGrid;
let vuMeterRClass = this.state.landscapeGrid ? classes.vuMeterRLandscape : classes.vuMeterR;
let typeValue = pedalBoardItem.getControl(PedalBoardSplitItem.TYPE_KEY);
let mixValue = pedalBoardItem.getControl(PedalBoardSplitItem.MIX_KEY);
let selectValue = pedalBoardItem.getControl(PedalBoardSplitItem.SELECT_KEY);
let panLValue = pedalBoardItem.getControl(PedalBoardSplitItem.PANL_KEY);
let volumeLValue = pedalBoardItem.getControl(PedalBoardSplitItem.VOLL_KEY);
let panRValue = pedalBoardItem.getControl(PedalBoardSplitItem.PANR_KEY);
let volumeRValue = pedalBoardItem.getControl(PedalBoardSplitItem.VOLR_KEY);
let typeValue = pedalboardItem.getControl(PedalboardSplitItem.TYPE_KEY);
let mixValue = pedalboardItem.getControl(PedalboardSplitItem.MIX_KEY);
let selectValue = pedalboardItem.getControl(PedalboardSplitItem.SELECT_KEY);
let panLValue = pedalboardItem.getControl(PedalboardSplitItem.PANL_KEY);
let volumeLValue = pedalboardItem.getControl(PedalboardSplitItem.VOLL_KEY);
let panRValue = pedalboardItem.getControl(PedalboardSplitItem.PANR_KEY);
let volumeRValue = pedalboardItem.getControl(PedalboardSplitItem.VOLR_KEY);
return (
<div className={classes.frame}>
<div className={classes.vuMeterL}>
<VuMeter display="input" instanceId={pedalBoardItem.instanceId} />
<VuMeter display="input" instanceId={pedalboardItem.instanceId} />
</div>
<div className={vuMeterRClass}>
<VuMeter display="output" instanceId={pedalBoardItem.instanceId} />
<VuMeter display="output" instanceId={pedalboardItem.instanceId} />
</div>
<div className={gridClass} >
<div style={{ flex: "0 0 auto" }}>
+8 -8
View File
@@ -18,13 +18,13 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import {UiControl,ScalePoint} from './Lv2Plugin';
import {PedalBoardSplitItem} from './PedalBoard';
import {PedalboardSplitItem} from './Pedalboard';
import Units from './Units'
export const SplitTypeControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.TYPE_KEY,
symbol: PedalboardSplitItem.TYPE_KEY,
name: "Type",
index: 0,
min_value: 0,
@@ -47,7 +47,7 @@ export const SplitTypeControl: UiControl = new UiControl().deserialize({
});
export const SplitAbControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.SELECT_KEY,
symbol: PedalboardSplitItem.SELECT_KEY,
name: "Select",
index: 1,
min_value: 0,
@@ -70,7 +70,7 @@ export const SplitAbControl: UiControl = new UiControl().deserialize({
export const SplitMixControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.MIX_KEY,
symbol: PedalboardSplitItem.MIX_KEY,
name: "Mix",
index: 2,
min_value: -1,
@@ -87,7 +87,7 @@ export const SplitMixControl: UiControl = new UiControl().deserialize({
});
export const SplitPanLeftControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.PANL_KEY,
symbol: PedalboardSplitItem.PANL_KEY,
name: "Pan Top",
index: 3,
min_value: -1,
@@ -104,7 +104,7 @@ export const SplitPanLeftControl: UiControl = new UiControl().deserialize({
});
export const SplitVolLeftControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.VOLL_KEY,
symbol: PedalboardSplitItem.VOLL_KEY,
name: "Vol Top",
index: 4,
min_value: -60,
@@ -128,7 +128,7 @@ export const SplitVolLeftControl: UiControl = new UiControl().deserialize({
export const SplitPanRightControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.PANR_KEY,
symbol: PedalboardSplitItem.PANR_KEY,
name: "Pan Bottom",
index: 5,
min_value: -1,
@@ -145,7 +145,7 @@ export const SplitPanRightControl: UiControl = new UiControl().deserialize({
});
export const SplitVolRightControl: UiControl = new UiControl().deserialize({
symbol: PedalBoardSplitItem.VOLR_KEY,
symbol: PedalboardSplitItem.VOLR_KEY,
name: "Vol Bottom",
index: 6,
min_value: -60,
+2 -2
View File
@@ -20,7 +20,7 @@
import StringBuilder from './StringBuilder';
class SvgPathBuilder {
_sb: StringBuilder = new StringBuilder();
private _sb: StringBuilder = new StringBuilder();
moveTo(x: number, y: number): SvgPathBuilder
{
@@ -37,7 +37,7 @@ class SvgPathBuilder {
this._sb.append('C').append(x1).append(',').append(y1)
.append(' ').append(x2).append(',').append(y2)
.append(' ').append(x).append(',').append(y).append(' ');
return this;
}
closePath(): SvgPathBuilder {
this._sb.append("Z ");
+4 -4
View File
@@ -26,7 +26,7 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
@@ -37,7 +37,7 @@ const styles = (theme: Theme) => createStyles({
interface ToobCabSimProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
}
interface ToobCabSimState {
@@ -83,8 +83,8 @@ const ToobCabSimView =
class ToobCabSimViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-cab-sim";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobCabSimView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<ToobCabSimView instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+69 -76
View File
@@ -30,14 +30,15 @@ import Utility from './Utility';
import SvgPathBuilder from './SvgPathBuilder';
const FREQUENCY_RESPONSE_VECTOR_URI = "http://two-play.com/plugins/toob#frequencyResponseVector";
const PLOT_WIDTH = StandardItemSize.width*2-16;
const PLOT_HEIGHT = StandardItemSize.height-12;
const PLOT_WIDTH = StandardItemSize.width * 2 - 16;
const PLOT_HEIGHT = StandardItemSize.height - 12;
const styles = (theme: Theme) => createStyles({
frame: {
width: PLOT_WIDTH, height: PLOT_HEIGHT, background: "#444",
width: PLOT_WIDTH, height: PLOT_HEIGHT, background: "#444",
borderRadius: 6,
marginTop: 12, marginLeft: 8, marginRight: 8,
boxShadow: "1px 4px 8px #000 inset"
@@ -73,33 +74,31 @@ const ToobFrequencyResponseView =
};
this.pathRef = React.createRef();
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.onStateChanged = this.onStateChanged.bind(this);
}
onStateChanged()
{
if (this.model.state.get() === State.Ready)
{
onStateChanged() {
if (this.model.state.get() === State.Ready) {
this.requestDeferred = false;
this.requestOutstanding = false;
this.updateAllWaveShapes(); // after a reconnect.
}
}
onPedalBoardChanged()
{
onPedalboardChanged() {
this.updateAllWaveShapes();
}
componentDidMount()
{
private mounted: boolean = false;
componentDidMount() {
this.mounted = true;
this.model.state.addOnChangedHandler(this.onStateChanged);
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
this.updateAllWaveShapes();
}
componentWillUnmount()
{
componentWillUnmount() {
this.mounted = false;
this.model.state.removeOnChangedHandler(this.onStateChanged);
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
}
componentDidUpdate() {
@@ -113,24 +112,23 @@ const ToobFrequencyResponseView =
dbTickSpacingOpt: number = 10;
MIN_DB_AF: number = Math.pow(10,-192/20);
MIN_DB_AF: number = Math.pow(10, -192 / 20);
fMin: number = 30;
fMax: number = 20000;
logMin: number = Math.log(this.fMin);
logMax: number = Math.log(this.fMax);
// Size of the SVG element.
xMin: number = 0;
xMax: number = PLOT_WIDTH+4;
xMax: number = PLOT_WIDTH + 4;
yMin: number = 0;
yMax: number = PLOT_HEIGHT;
dbTickSpacing: number = this.dbTickSpacingOpt;
toX(frequency: number): number
{
toX(frequency: number): number {
var logV = Math.log(frequency);
return (this.xMax-this.xMin) * (logV-this.logMin)/(this.logMax-this.logMin) + this.xMin;
return (this.xMax - this.xMin) * (logV - this.logMin) / (this.logMax - this.logMin) + this.xMin;
}
toY(value: number): number {
value = Math.abs(value);
@@ -139,24 +137,23 @@ const ToobFrequencyResponseView =
if (value < this.MIN_DB_AF) {
db = -192.0;
} else {
db = 20*Math.log10(value);
db = 20 * Math.log10(value);
}
var y = (db-this.dbMin)/(this.dbMax-this.dbMin)*(this.yMax-this.yMin) + this.yMin;
var y = (db - this.dbMin) / (this.dbMax - this.dbMin) * (this.yMax - this.yMin) + this.yMin;
return y;
}
onFrequencyResponseUpdated(data: number[]) {
if (!this.mounted) return;
let pathBuilder = new SvgPathBuilder();
if (data.length > 2)
{
pathBuilder.moveTo(this.toX(data[0]),this.toY(data[1]))
for (let i = 2; i < data.length; i += 2)
{
pathBuilder.lineTo(this.toX(data[i]),this.toY(data[i+1]));
if (data.length > 2) {
pathBuilder.moveTo(this.toX(data[0]), this.toY(data[1]))
for (let i = 2; i < data.length; i += 2) {
pathBuilder.lineTo(this.toX(data[i]), this.toY(data[i + 1]));
}
}
this.currentPath = pathBuilder.toString();
this.setState({path: this.currentPath});
this.setState({ path: this.currentPath });
}
@@ -166,21 +163,23 @@ const ToobFrequencyResponseView =
return;
}
this.requestOutstanding = true;
this.model.getLv2Parameter<number[]>(this.props.instanceId, FREQUENCY_RESPONSE_VECTOR_URI)
.then((data) => {
this.onFrequencyResponseUpdated(data);
if (this.requestDeferred) {
Utility.delay(10) // take breath
.then(
() => {
this.requestOutstanding = false;
this.requestDeferred = false;
this.updateAllWaveShapes();
}
this.model.getPatchProperty<any>(this.props.instanceId, FREQUENCY_RESPONSE_VECTOR_URI)
.then((json) => {
if (json && json.otype_ === "Vector" && json.vtype_ === "Float") {
this.onFrequencyResponseUpdated(json.value as number[]);
if (this.requestDeferred) {
Utility.delay(10) // take breath
.then(
() => {
this.requestOutstanding = false;
this.requestDeferred = false;
this.updateAllWaveShapes();
}
);
} else {
this.requestOutstanding = false;
);
} else {
this.requestOutstanding = false;
}
}
}).catch(error => {
// assume the connection was lost. We'll get saved by a reconnect.
@@ -201,42 +200,36 @@ const ToobFrequencyResponseView =
grid(): React.ReactNode[] {
let result: React.ReactNode[] = [];
for (var db = Math.ceil(this.dbMax/this.dbTickSpacing)*this.dbTickSpacing; db < this.dbMin; db += this.dbTickSpacing )
{
var y = (db-this.dbMin)/(this.dbMax-this.dbMin)*(this.yMax-this.yMin);
if (db === 0)
{
result.push(
this.majorGridLine(this.xMin,y,this.xMax,y)
);
for (var db = Math.ceil(this.dbMax / this.dbTickSpacing) * this.dbTickSpacing; db < this.dbMin; db += this.dbTickSpacing) {
var y = (db - this.dbMin) / (this.dbMax - this.dbMin) * (this.yMax - this.yMin);
if (db === 0) {
result.push(
this.majorGridLine(this.xMin, y, this.xMax, y)
);
} else {
result.push(
this.gridLine(this.xMin,y,this.xMax,y)
);
result.push(
this.gridLine(this.xMin, y, this.xMax, y)
);
}
}
let decade0 = Math.pow(10,Math.floor(Math.log10(this.fMin)));
for (var decade = decade0; decade < this.fMax; decade *= 10)
{
for (var i = 1; i <= 10; ++i)
{
var f = decade*i;
if (f > this.fMin && f < this.fMax)
{
let decade0 = Math.pow(10, Math.floor(Math.log10(this.fMin)));
for (var decade = decade0; decade < this.fMax; decade *= 10) {
for (var i = 1; i <= 10; ++i) {
var f = decade * i;
if (f > this.fMin && f < this.fMax) {
var x = this.toX(f);
if (i === 10)
{
result.push(this.majorGridLine(x,this.yMin,x,this.yMax));
if (i === 10) {
result.push(this.majorGridLine(x, this.yMin, x, this.yMax));
} else {
result.push(this.gridLine(x,this.yMin,x,this.yMax));
result.push(this.gridLine(x, this.yMin, x, this.yMax));
}
}
}
}
return result;
return result;
}
dbMin: number = 5;
@@ -244,20 +237,20 @@ const ToobFrequencyResponseView =
render() {
// deliberately reversed to flip up and down.
this.dbMax = this.props.minDb ?? this.dbMinDefault;
this.dbMax = this.props.minDb ?? this.dbMinDefault;
this.dbMin = this.props.maxDb ?? this.dbMaxDefault;
this.fMin = this.props.minFrequency ?? 30;
this.fMax = this.props.maxFrequency ?? 20000;
this.logMin = Math.log(this.fMin);
this.logMax = Math.log(this.fMax);
let classes = this.props.classes;
return (
<div className={classes.frame} >
<svg width={PLOT_WIDTH} height={PLOT_HEIGHT} viewBox={"0 0 " + PLOT_WIDTH + " " + PLOT_HEIGHT} stroke="#0F8" fill="none" strokeWidth="2.5" opacity="0.6">
{ this.grid() }
{this.grid()}
<path d={this.state.path} ref={this.pathRef} />
</svg>
+4 -4
View File
@@ -26,7 +26,7 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
@@ -37,7 +37,7 @@ const styles = (theme: Theme) => createStyles({
interface ToobInputStageProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
}
interface ToobInputStageState {
@@ -84,8 +84,8 @@ const ToobInputStageView =
class ToobInputStageViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-input_stage";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobInputStageView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<ToobInputStageView instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+4 -4
View File
@@ -26,7 +26,7 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel,MonitorPortHandle } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
@@ -37,7 +37,7 @@ const styles = (theme: Theme) => createStyles({
interface ToobMLProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
}
interface ToobMLState {
@@ -135,8 +135,8 @@ const ToobMLView =
class ToobMLViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-ml";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobMLView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<ToobMLView instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+18 -13
View File
@@ -26,18 +26,19 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel, State,ListenHandle } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobWaveShapeView, {BidirectionalVuPeak} from './ToobWaveShapeView';
let POWERSTAGE_UI_URI = "http://two-play.com/plugins/toob-power-stage-2#uiState";
const styles = (theme: Theme) => createStyles({
});
interface ToobPowerstage2Props extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
}
interface ToobPowerstage2State {
@@ -60,18 +61,11 @@ const ToobPowerstage2View =
uiState: [0,0,0,0,0,0,0,0]
}
this.onStateChanged = this.onStateChanged.bind(this);
this.onAtomOutput = this.onAtomOutput.bind(this);
}
listeningForOutput: boolean = false;
atomOutputHandle?: ListenHandle;
onAtomOutput(instanceId: number, atomOutput: any): void {
if (atomOutput.lv2Type === "http://two-play.com/plugins/toob-power-stage-2#uiState" )
{
this.setState({uiState: atomOutput.data as number[]});
}
}
maybeListenForAtomOutput(): void {
let listenForOutput = this.isReady && this.isControlMounted;
@@ -80,11 +74,22 @@ const ToobPowerstage2View =
this.listeningForOutput = listenForOutput;
if (listenForOutput)
{
this.atomOutputHandle = this.model.listenForAtomOutput(this.props.instanceId,this.onAtomOutput);
this.atomOutputHandle = this.model.monitorPatchProperty(
this.props.instanceId,
POWERSTAGE_UI_URI,
(instanceId: number, propertyUri: string, json: any) => {
if (json.otype_ === "Vector")
{
this.setState({uiState: json.value as number[]});
}
});
// discard the output as we will be getting it through monitorPatchProperty as well.
this.model.getPatchProperty(this.props.instanceId,POWERSTAGE_UI_URI);
} else {
if (this.atomOutputHandle)
{
this.model.cancelListenForAtomOutput(this.atomOutputHandle);
this.model.cancelMonitorPatchProperty(this.atomOutputHandle);
this.atomOutputHandle = undefined;
}
@@ -180,8 +185,8 @@ const ToobPowerstage2View =
class ToobPowerstage2ViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-power-stage-2";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobPowerstage2View instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<ToobPowerstage2View instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+4 -4
View File
@@ -26,7 +26,7 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobSpectrumResponseView from './ToobSpectrumResponseView';
@@ -38,7 +38,7 @@ const styles = (theme: Theme) => createStyles({
interface ToobSpectrumAnalyzerProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
}
interface ToobSpectrumAnalyzerState {
@@ -84,8 +84,8 @@ const ToobSpectrumAnalyzerView =
class ToobSpectrumAnalyzerViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-spectrum";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobSpectrumAnalyzerView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<ToobSpectrumAnalyzerView instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+148 -139
View File
@@ -25,22 +25,30 @@ import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles';
import { PiPedalModelFactory, PiPedalModel, State,ListenHandle } from "./PiPedalModel";
import { PiPedalModelFactory, PiPedalModel, State, ListenHandle } from "./PiPedalModel";
import { StandardItemSize } from './PluginControlView';
import Utility from './Utility';
// import { setInterval,clearInterval } from 'timers'; // no longer requires polyfill (webpack >= 5)
const SPECTRUM_RESPONSE_VECTOR_URI = "http://two-play.com/plugins/toob#spectrumResponse";
const PLOT_WIDTH = StandardItemSize.width*3-16;
const PLOT_HEIGHT = StandardItemSize.height-12;
import SvgPathBuilder from './SvgPathBuilder'
const SPECTRUM_RESPONSE_URI = "http://two-play.com/plugins/toob#spectrumResponse";
const SPECTRUM_ENABLE_URI = "http://two-play.com/plugins/toob#spectrumEnable";
const PLOT_WIDTH = StandardItemSize.width * 3 - 16;
const PLOT_HEIGHT = StandardItemSize.height - 12;
const styles = (theme: Theme) => createStyles({
frame: {
width: PLOT_WIDTH, height: PLOT_HEIGHT, background: "#444",
width: PLOT_WIDTH, height: PLOT_HEIGHT, background: "#333",
borderRadius: 6,
marginTop: 12, marginLeft: 8, marginRight: 8,
overflow: "hidden"
},
frameShadow: {
width: PLOT_WIDTH, height: PLOT_HEIGHT,
borderRadius: 6,
boxShadow: "1px 4px 8px #000 inset"
},
});
@@ -51,6 +59,7 @@ interface ToobSpectrumResponseProps extends WithStyles<typeof styles> {
}
interface ToobSpectrumResponseState {
path: string;
holdPath: string;
minF: number;
maxF: number;
}
@@ -72,9 +81,8 @@ const ToobSpectrumResponseView =
let minF = 60;
let maxF = 18000;
let plugin = this.model.pedalBoard.get()?.maybeGetItem(this.props.instanceId);
if (plugin)
{
let plugin = this.model.pedalboard.get()?.maybeGetItem(this.props.instanceId);
if (plugin) {
minF = plugin.getControlValue("minF");
maxF = plugin.getControlValue("maxF");
}
@@ -82,62 +90,59 @@ const ToobSpectrumResponseView =
this.state = {
path: "",
holdPath: "",
minF: minF,
maxF: maxF
};
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.onStateChanged = this.onStateChanged.bind(this);
}
onStateChanged()
{
if (this.model.state.get() === State.Ready)
{
onStateChanged() {
if (this.model.state.get() === State.Ready) {
this.requestDeferred = false;
this.requestOutstanding = false;
let plugin = this.model.pedalBoard.get()?.maybeGetItem(this.props.instanceId);
if (plugin)
{
let plugin = this.model.pedalboard.get()?.maybeGetItem(this.props.instanceId);
if (plugin) {
let minF = plugin.getControlValue("minF");
let maxF = plugin.getControlValue("maxF");
this.setState({minF: minF, maxF: maxF});
this.setState({ minF: minF, maxF: maxF });
}
}
this.isReady = this.model.state.get() === State.Ready;
this.maybeStartClock(); // after a reconnect.
this.maybeStartMonitoring(); // after a reconnect.
}
onPedalBoardChanged()
{
this.maybeStartClock();
let plugin = this.model.pedalBoard.get()?.maybeGetItem(this.props.instanceId);
if (plugin)
{
onPedalboardChanged() {
// rebind our monitoring hooks.
this.maybeStartMonitoring(false);
this.maybeStartMonitoring(true);
let plugin = this.model.pedalboard.get()?.maybeGetItem(this.props.instanceId);
if (plugin) {
let minF = plugin.getControlValue("minF");
let maxF = plugin.getControlValue("maxF");
this.setState({minF: minF, maxF: maxF});
this.setState({ minF: minF, maxF: maxF });
}
}
mounted: boolean = false;
isReady: boolean = false;
componentDidMount()
{
componentDidMount() {
this.model.state.addOnChangedHandler(this.onStateChanged);
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
this.mounted = true;
this.isReady = this.model.state.get() === State.Ready;
this.maybeStartClock();
this.maybeStartMonitoring();
}
componentWillUnmount()
{
componentWillUnmount() {
this.mounted = false;
this.maybeStartClock();
this.maybeStartMonitoring();
this.model.state.removeOnChangedHandler(this.onStateChanged);
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
}
componentDidUpdate() {
@@ -147,77 +152,50 @@ const ToobSpectrumResponseView =
// Size of the SVG element.
xMin: number = 0;
xMax: number = PLOT_WIDTH+4;
xMax: number = PLOT_WIDTH + 4;
yMin: number = 0;
yMax: number = PLOT_HEIGHT;
onSpectrumResponseUpdated(svgPath: string) {
this.setState({path: svgPath});
onSpectrumResponseUpdated(svgPath: string, holdSvgPath: string) {
this.setState({ path: svgPath, holdPath: holdSvgPath });
}
isTicking : boolean = false;
hClock?: NodeJS.Timeout;
hAtomOutput?: ListenHandle;
private isMonitoring: boolean = false;
private hClock?: NodeJS.Timeout;
private hAtomOutput?: ListenHandle;
maybeStartClock() {
let shouldTick = this.isReady && this.mounted;
private maybeStartMonitoring(wantsMonitoring: boolean = true) {
let shouldMonitor = this.isReady && this.mounted && wantsMonitoring;
if (shouldTick !== this.isTicking)
{
this.isTicking = shouldTick;
if (shouldTick)
{
this.hAtomOutput = this.model.listenForAtomOutput(this.props.instanceId,
(instanceId,atomOutput)=> {
this.onSpectrumResponseUpdated(atomOutput.value as string);
if (this.requestDeferred) {
Utility.delay(30) // take breath
.then(
() => {
this.requestOutstanding = false;
this.requestDeferred = false;
this.requestSpectrum();
}
);
} else {
this.requestOutstanding = false;
if (shouldMonitor !== this.isMonitoring) {
this.isMonitoring = shouldMonitor;
if (shouldMonitor) {
this.hAtomOutput = this.model.monitorPatchProperty(
this.props.instanceId,
SPECTRUM_RESPONSE_URI,
(instanceId, propertyUri, json) => {
if (propertyUri === SPECTRUM_RESPONSE_URI && json.otype_ === "Tuple") {
let values = json.value as string[];
this.onSpectrumResponseUpdated(values[0], values[1]);
}
});
this.hClock = setInterval(()=> {
this.requestSpectrum();
},
1000/15);
}
);
this.model.setPatchProperty(this.props.instanceId, SPECTRUM_ENABLE_URI, true)
.catch((error)=> {});
} else {
if (this.hAtomOutput)
{
this.model.cancelListenForAtomOutput(this.hAtomOutput);
this.model.setPatchProperty(this.props.instanceId, SPECTRUM_ENABLE_URI, false)
.catch((error)=> {}); // e.g. plugin not found.
if (this.hAtomOutput) {
this.model.cancelMonitorPatchProperty(this.hAtomOutput);
this.hAtomOutput = undefined;
}
if (this.hClock)
{
clearInterval(this.hClock);
this.hClock = undefined;
}
}
}
}
requestSpectrum() {
if (this.requestOutstanding) { // throttling.
this.requestDeferred = true;
return;
}
this.requestOutstanding = true;
this.model.getLv2Parameter<string>(this.props.instanceId, SPECTRUM_RESPONSE_VECTOR_URI)
.then((data) => {
}).catch(error => {
// assume the connection was lost. We'll get saved by a reconnect.
});
}
numPoints = 200;
@@ -228,22 +206,21 @@ const ToobSpectrumResponseView =
logMaxF = Math.log(this.maxF);
toX(f: number): number {
let width = PLOT_WIDTH-8;
return (Math.log(f)-this.logMinF)*width/(this.logMaxF-this.logMinF);
let width = PLOT_WIDTH - 8;
return (Math.log(f) - this.logMinF) * width / (this.logMaxF - this.logMinF);
}
grid(): React.ReactNode[] {
let result: React.ReactNode[] = [];
let width = PLOT_WIDTH-8;
let height = PLOT_HEIGHT-8;
for (let db = -20; db >= -100; db -= 20)
{
let y = height*db/-100;
result.push(
(
<line x1={0} y1={y} x2={width} y2={y} key={"db" + db} />
)
);
private minorGrid(): string {
let ss = new SvgPathBuilder();
let width = PLOT_WIDTH;
let height = PLOT_HEIGHT;
for (let db = -20; db >= -100; db -= 20) {
let y = height * db / -100;
ss.moveTo(0,y);
ss.lineTo(width,y);
}
let minF = this.state.minF;
@@ -252,54 +229,86 @@ const ToobSpectrumResponseView =
this.maxF = maxF;
this.logMinF = Math.log(this.minF);
this.logMaxF = Math.log(this.maxF);
for (let decade = 10; decade < 100000; decade *= 10)
{
for (let minorTick = 1; minorTick <= 5; ++ minorTick)
{
let f = decade*minorTick;
if (f > minF && f < maxF)
{
for (let decade = 10; decade < 100000; decade *= 10) {
for (let minorTick = 1; minorTick <= 5; ++minorTick) {
let f = decade * minorTick;
if (f > minF && f < maxF) {
let x = this.toX(f);
if (minorTick === 1)
{
result.push(
(
<line x1={x} y1={0} x2={x} y2={height} key={"hgrid"+f} strokeWidth={1}/>
)
);
if (minorTick === 1) {
ss.moveTo(x,0);
ss.lineTo(x,height);
} else {
result.push(
(
<line x1={x} y1={0} x2={x} y2={height} key={"hgrid"+f} />
)
);
ss.moveTo(x,0);
ss.lineTo(x,height);
}
}
}
}
return result;
return ss.toString();
}
private majorGrid(): string {
let ss = new SvgPathBuilder();
let height = PLOT_HEIGHT;
let minF = this.state.minF;
let maxF = this.state.maxF;
this.minF = minF;
this.maxF = maxF;
this.logMinF = Math.log(this.minF);
this.logMaxF = Math.log(this.maxF);
for (let decade = 10; decade < 100000; decade *= 10) {
if (decade > minF && decade < maxF)
{
let x = this.toX(decade);
ss.moveTo(x,0);
ss.lineTo(x,height);
}
}
return ss.toString();
}
render() {
let classes = this.props.classes;
return (
<div className={classes.frame} style={{position: "relative"}} >
<div style={{position: "absolute", left: 4, top: 4}}>
<svg width={PLOT_WIDTH-8} height={PLOT_HEIGHT-8} stroke="#888" strokeWidth="0.5" opacity="1"
>
{this.grid()}
<div className={classes.frame} style={{ position: "relative" }} >
{/* <div style={{ position: "absolute", left: 0, top: 0 }}>
<svg fill="#660" width={PLOT_WIDTH } height={PLOT_HEIGHT} preserveAspectRatio='none'
viewBox={"0 0 " + this.numPoints + " " + 1000} stroke="none" strokeWidth="2.5" opacity="1.0"
>
<path d={this.state.holdPath} />
</svg>
</div> */}
<div style={{ position: "absolute", left: 0, top: 0 }}>
<svg fill="#0C4" width={PLOT_WIDTH } height={PLOT_HEIGHT } preserveAspectRatio='none'
viewBox={"0 0 " + this.numPoints + " " + 1000} stroke="none" strokeWidth="2.5" opacity="1.0"
>
<path d={this.state.path} />
</svg>
</div>
<div style={{position: "absolute", left: 4, top: 4}}>
<svg width={PLOT_WIDTH-8} height={PLOT_HEIGHT-8} preserveAspectRatio='none' viewBox={"0 0 " + this.numPoints + " " + 1000} stroke="none" fill="#0FC" strokeWidth="2.5" opacity="0.6"
>
<path d={this.state.path} />
<div style={{ position: "absolute", left: 0, top: 0 }}>
<svg width={PLOT_WIDTH } height={PLOT_HEIGHT} stroke="#FFF" strokeWidth="0.9" opacity="0.3"
>
<path d={this.minorGrid()} />
</svg>
</div>
<div style={{ position: "absolute", left: 0, top: 0 }}>
<svg width={PLOT_WIDTH} height={PLOT_HEIGHT} stroke="#FFF" strokeWidth="0.9" opacity="0.5"
>
<path d={this.majorGrid()} />
</svg>
</div>
<div className={classes.frameShadow} style={{ position: "absolute", left: 0, top: 0, right: 0, bottom: 0 }}>
</div>
</div>);
}
+4 -4
View File
@@ -26,7 +26,7 @@ import withStyles from '@mui/styles/withStyles';
import IControlViewFactory from './IControlViewFactory';
import { PiPedalModelFactory, PiPedalModel,ControlValueChangedHandle } from "./PiPedalModel";
import { PedalBoardItem } from './PedalBoard';
import { PedalboardItem } from './Pedalboard';
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
@@ -37,7 +37,7 @@ const styles = (theme: Theme) => createStyles({
interface ToobToneStackProps extends WithStyles<typeof styles> {
instanceId: number;
item: PedalBoardItem;
item: PedalboardItem;
}
interface ToobToneStackState {
@@ -117,8 +117,8 @@ const ToobToneStackView =
class ToobToneStackViewFactory implements IControlViewFactory {
uri: string = "http://two-play.com/plugins/toob-tone-stack";
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
return (<ToobToneStackView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
Create(model: PiPedalModel, pedalboardItem: PedalboardItem): React.ReactNode {
return (<ToobToneStackView instanceId={pedalboardItem.instanceId} item={pedalboardItem} />);
}
+24 -18
View File
@@ -128,7 +128,7 @@ const ToobWaveShapeView =
data: []
};
this.onPedalBoardChanged = this.onPedalBoardChanged.bind(this);
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
this.onStateChanged = this.onStateChanged.bind(this);
this.onControlValueChanged = this.onControlValueChanged.bind(this);
this.isReady = this.model.state.get() === State.Ready;
@@ -147,7 +147,7 @@ const ToobWaveShapeView =
}
}
}
onPedalBoardChanged() {
onPedalboardChanged() {
this.updateWaveShape();
}
_valueChangedHandle?: ControlValueChangedHandle;
@@ -158,7 +158,7 @@ const ToobWaveShapeView =
componentDidMount() {
this.mounted = true;
this.model.state.addOnChangedHandler(this.onStateChanged);
this.model.pedalBoard.addOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.addOnChangedHandler(this.onPedalboardChanged);
this._valueChangedHandle = this.model.addControlValueChangeListener(
this.props.instanceId,
this.onControlValueChanged);
@@ -180,7 +180,7 @@ const ToobWaveShapeView =
this._valueChangedHandle = undefined;
}
this.model.state.removeOnChangedHandler(this.onStateChanged);
this.model.pedalBoard.removeOnChangedHandler(this.onPedalBoardChanged);
this.model.pedalboard.removeOnChangedHandler(this.onPedalboardChanged);
}
onControlValueChanged(key: string, value: number) {
@@ -230,21 +230,27 @@ const ToobWaveShapeView =
return;
}
this.requestOutstanding = true;
this.model.getLv2Parameter<number[]>(this.props.instanceId, WAVESHAPE_VECTOR_URI + this.props.controlNumber)
.then((data) => {
this.onWaveShapeUpdated(data);
if (this.requestDeferred) {
Utility.delay(10) // take breath
.then(
() => {
this.requestOutstanding = false;
this.requestDeferred = false;
this.updateWaveShape();
}
this.model.getPatchProperty<any>(this.props.instanceId, WAVESHAPE_VECTOR_URI + this.props.controlNumber)
.then((json) => {
if (!this.mounted) return;
if (json.otype_ === "Vector" && json.vtype_ === "Float")
{
let data = json.value;
this.onWaveShapeUpdated(data);
if (this.requestDeferred) {
Utility.delay(10) // take breath
.then(
() => {
this.requestOutstanding = false;
this.requestDeferred = false;
this.updateWaveShape();
}
);
} else {
this.requestOutstanding = false;
);
} else {
this.requestOutstanding = false;
}
}
}).catch(error => {
// assume the connection was lost. We'll get saved by a reconnect.
+2 -2
View File
@@ -170,8 +170,8 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
let uiControl = this.props.controlInfo.uiControl;
let instanceId = this.props.controlInfo.instanceId;
if (instanceId === -1) return 0;
let pedalBoardItem = this.model.pedalBoard.get()?.getItem(instanceId);
let value: number = pedalBoardItem?.getControlValue(uiControl.symbol) ?? 0;
let pedalboardItem = this.model.pedalboard.get()?.getItem(instanceId);
let value: number = pedalboardItem?.getControlValue(uiControl.symbol) ?? 0;
this.defaultValue = value;
return value;
}
+5 -5
View File
@@ -94,8 +94,8 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
let uiControl = this.props.controlInfo.uiControl;
let instanceId = this.props.controlInfo.instanceId;
if (instanceId === -1) return 0;
let pedalBoardItem = this.model.pedalBoard.get()?.getItem(instanceId);
let value: number = pedalBoardItem?.getControlValue(uiControl.symbol) ?? 0;
let pedalboardItem = this.model.pedalboard.get()?.getItem(instanceId);
let value: number = pedalboardItem?.getControlValue(uiControl.symbol) ?? 0;
return value;
}
}
@@ -105,7 +105,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
let v = Number.parseFloat(val.toString());
this.setState({ value: v });
if (this.props.controlInfo) {
this.model.setPedalBoardControlValue(
this.model.setPedalboardControl(
this.props.controlInfo.instanceId,
this.props.controlInfo.uiControl.symbol,
v);
@@ -116,7 +116,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
let v = checked ? 1: 0;
this.setState({ value: v });
if (this.props.controlInfo) {
this.model.setPedalBoardControlValue(
this.model.setPedalboardControl(
this.props.controlInfo.instanceId,
this.props.controlInfo.uiControl.symbol,
v);
@@ -247,7 +247,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
onSetValue={(v) => {
this.setState({ value: v });
if (this.props.controlInfo) {
this.model.setPedalBoardControlValue(
this.model.setPedalboardControl(
this.props.controlInfo.instanceId,
this.props.controlInfo.uiControl.symbol,
v);