Improvements to file uploads. UI improvements for future looper and audio capture plugins.

This commit is contained in:
Robin E. R. Davies
2025-02-15 12:29:53 -05:00
parent b07f590b49
commit 09f73e26d6
41 changed files with 1714 additions and 626 deletions
+3 -1
View File
@@ -12,7 +12,9 @@ import JackHostStatus from './JackHostStatus';
import { PiPedalError } from './PiPedalError';
import DialogEx from './DialogEx';
import { Theme, createStyles } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import { withStyles, WithStyles } from '@mui/styles';
import Slide, { SlideProps } from '@mui/material/Slide';
+5 -3
View File
@@ -27,7 +27,9 @@ import ButtonBase from "@mui/material/ButtonBase";
import Slide, { SlideProps } from '@mui/material/Slide';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import { Theme, createStyles } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import { WithStyles, withStyles } from "@mui/styles";
import DraggableGrid, { ScrollDirection } from './DraggableGrid';
import Fade from '@mui/material/Fade';
@@ -304,8 +306,8 @@ const BankDialog = withStyles(styles, { withTheme: true })(
>
<SelectHoverBackground selected={bankEntry.instanceId === selectedItem} showHover={true} />
<div className={classes.itemFrame}>
<div className={classes.ListItemIcon}>
<BankIcon className={classes.listIcon}/>
<div className={classes.listIcon}>
<BankIcon />
</div>
<div className={classes.itemLabel}>
<Typography noWrap variant="body2" color="textPrimary">
+10 -3
View File
@@ -19,7 +19,9 @@
import React from 'react';
import { Theme, createStyles } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import CreateNewFolderIcon from '@mui/icons-material/CreateNewFolder';
import RenameDialog from './RenameDialog';
import Divider from '@mui/material/Divider';
@@ -32,7 +34,7 @@ import Button from '@mui/material/Button';
import FileUploadIcon from '@mui/icons-material/FileUpload';
import AudioFileIcon from '@mui/icons-material/AudioFile';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import FolderOutlinedIcon from '@mui/icons-material/FolderOutlined';
import FolderIcon from '@mui/icons-material/Folder';
import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import DialogActions from '@mui/material/DialogActions';
@@ -92,6 +94,7 @@ function isAudioFile(filename: string) {
export interface FilePropertyDialogProps extends WithStyles<typeof styles> {
open: boolean,
fileProperty: UiFileProperty,
instanceId: number,
selectedFile: string,
onOk: (fileProperty: UiFileProperty, selectedItem: string) => void,
onCancel: () => void
@@ -557,7 +560,7 @@ export default withStyles(styles, { withTheme: true })(
}
if (fileEntry.isDirectory) {
return (
<FolderOutlinedIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
<FolderIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
);
}
if (isAudioFile(fileEntry.pathname)) {
@@ -750,6 +753,8 @@ export default withStyles(styles, { withTheme: true })(
}
uploadPage={
"uploadUserFile?directory=" + encodeURIComponent(this.state.uploadDirectory)
+ "&id=" + this.props.instanceId.toString()
+ "&property=" + encodeURIComponent(this.props.fileProperty.patchProperty)
+ "&ext="
+ encodeURIComponent(this.getFileExtensionList(this.props.fileProperty))
}
@@ -794,8 +799,10 @@ export default withStyles(styles, { withTheme: true })(
(
<FilePropertyDirectorySelectDialog
open={this.state.moveDialogOpen}
dialogTitle="Move to"
uiFileProperty={this.props.fileProperty}
defaultPath={this.getDefaultPath()}
selectedFile={this.state.selectedFile}
excludeDirectory={
this.isDirectory(this.state.selectedFile)
? this.state.selectedFile : ""}
@@ -121,9 +121,11 @@ class DirectoryTree {
export interface FilePropertyDirectorySelectDialogProps {
open: boolean,
dialogTitle: string,
uiFileProperty: UiFileProperty;
defaultPath: string,
excludeDirectory: string,
selectedFile: string,
onOk: (path: string) => void,
onClose: () => void
};
@@ -181,7 +183,7 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
requestDirectoryTree() {
if (!this.props.open) return;
this.model.getFilePropertyDirectoryTree(this.props.uiFileProperty)
this.model.getFilePropertyDirectoryTree(this.props.uiFileProperty,this.props.selectedFile)
.then((filePropertyDirectoryTree) => {
let myTree = new DirectoryTree(filePropertyDirectoryTree);
if (this.props.excludeDirectory.length !== 0)
@@ -327,7 +329,7 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
PaperProps={{ style: { minHeight: "80%", maxHeight: "80%", minWidth: "75%", maxWidth: "75%", overflowY: "visible" } }}
>
<DialogTitle>
<Typography variant="body1">Select folder</Typography>
<Typography variant="body1">{this.props.dialogTitle}</Typography>
</DialogTitle>
<Divider />
<DialogContent style={{marginLeft: 0, paddingLeft: 0}} >
+2 -1
View File
@@ -43,7 +43,8 @@ import { FixedSizeGrid } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import StarBorderIcon from '@mui/icons-material/StarBorder';
import StarIcon from '@mui/icons-material/Star';
import { createStyles, Theme } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import { WithStyles, withStyles } from '@mui/styles';
import FilterListIcon from '@mui/icons-material/FilterList';
import FilterListOffIcon from '@mui/icons-material/FilterListOff';
+2 -2
View File
@@ -38,8 +38,8 @@ export const modDirectories: ModDirectory[] = [
{modType: "ir", pipedalPath: "ReverbImpulseFiles", displayName: "Impulse Responses", defaultFileExtensions: ["audio/*"]}, // Impulse Responses
{modType: "midiclip", pipedalPath: "shared/midiClips",displayName: "MIDI Clips", defaultFileExtensions: [".mid", ".midi"]}, // MIDI Clips, to be used in sync with host tempo, must have mid or midi file extension
{modType: "midisong", pipedalPath: "shared/midiSongs", displayName: "MIDI Songs", defaultFileExtensions: [".mid", ".midi"]}, // MIDI Songs, meant to be used as full-performance/song or backtrack
{modType: "sf2", pipedalPath: "shared/sf2",displayName: "Sound Fonts", defaultFileExtensions: ["sf2", "sf3"]}, // SF2 Instruments, must have sf2 or sf3 file extension
{modType: "sfz", pipedalPath: "shared/sfz",displayName: "Sfz Files", defaultFileExtensions: ["sfz"]}, // SFZ Instruments, must have sfz file extension
{modType: "sf2", pipedalPath: "shared/sf2",displayName: "Sound Fonts", defaultFileExtensions: [".sf2", ".sf3"]}, // SF2 Instruments, must have sf2 or sf3 file extension
{modType: "sfz", pipedalPath: "shared/sfz",displayName: "Sfz Files", defaultFileExtensions: [".sfz"]}, // SFZ Instruments, must have sfz file extension
// extensions observed in the field.
{modType: "audio", pipedalPath: "shared/audio", displayName: "Audio", defaultFileExtensions: ["audio/*"]}, // all audio files (Ratatoille)
{modType: "nammodel", pipedalPath: "NeuralAmpModels", displayName: "Neural Amp Models", defaultFileExtensions: [".nam"]}, // Ratatoille, Mike's NAM.
+2 -2
View File
@@ -2610,7 +2610,7 @@ export class PiPedalModel //implements PiPedalModel
});
}
getFilePropertyDirectoryTree(uiFileProperty: UiFileProperty): Promise<FilePropertyDirectoryTree> {
getFilePropertyDirectoryTree(uiFileProperty: UiFileProperty,selectedPath: string): Promise<FilePropertyDirectoryTree> {
return new Promise<FilePropertyDirectoryTree>((resolve, reject) => {
let ws = this.webSocket;
if (!ws) {
@@ -2619,7 +2619,7 @@ export class PiPedalModel //implements PiPedalModel
}
ws.request<FilePropertyDirectoryTree>(
"getFilePropertyDirectoryTree",
uiFileProperty
{fileProperty: uiFileProperty, selectedPath: selectedPath}
).then((result) => {
resolve(new FilePropertyDirectoryTree().deserialize(result));
}).catch((e) => {
+99 -36
View File
@@ -73,7 +73,7 @@ export const pluginControlStyles = (theme: Theme) => createStyles({
},
titleSection: {
flex: "0 0 auto", alignSelf:"stretch", marginBottom: 8, marginLeft: 0, marginRight: 0
flex: "0 0 auto", alignSelf: "stretch", marginBottom: 8, marginLeft: 0, marginRight: 0
},
displayValue: {
position: "absolute",
@@ -87,10 +87,10 @@ export const pluginControlStyles = (theme: Theme) => createStyles({
// zIndex: -1,
},
midSection: {
flex: "1 1 1", display: "flex",flexFlow: "column nowrap",alignContent: "center",justifyContent: "center"
flex: "1 1 1", display: "flex", flexFlow: "column nowrap", alignContent: "center", justifyContent: "center"
},
editSection: {
flex: "0 0 0", display: "flex", flexFlow: "column nowrap", justifyContent: "center",position: "relative", width: 60, height: 28,minHeight: 28
flex: "0 0 0", display: "flex", flexFlow: "column nowrap", justifyContent: "center", position: "relative", width: 60, height: 28, minHeight: 28
}
});
@@ -500,14 +500,12 @@ const PluginControl =
}
handleTriggerMouseDown() {
let uiControl = this.props.uiControl;
if (uiControl)
{
if (uiControl) {
let value = uiControl.max_value;
if (uiControl.max_value === uiControl.default_value)
{
if (uiControl.max_value === uiControl.default_value) {
value = uiControl.min_value;
}
this.model.sendPedalboardControlTrigger(this.props.instanceId,uiControl.symbol,value);
this.model.sendPedalboardControlTrigger(this.props.instanceId, uiControl.symbol, value);
}
}
handleTriggerMouseUp() {
@@ -650,13 +648,39 @@ const PluginControl =
}
let range: number;
if (uiControl.is_logarithmic) {
range = Math.log(value / uiControl.min_value) / Math.log(uiControl.max_value / uiControl.min_value);
let minValue = uiControl.min_value;
if (minValue === 0) // LSP plugins do this.
{
minValue = 0.0001;
}
range = Math.log(value / minValue) / Math.log(uiControl.max_value / minValue);
if (!isFinite(range)) {
if (range < 0)
{
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
if (uiControl.range_steps > 1) {
range = Math.round(range * (uiControl.range_steps - 1)) / (uiControl.range_steps - 1);
}
} else {
range = (value - uiControl.min_value) / (uiControl.max_value - uiControl.min_value);
if (!isFinite(range)) {
if (range < 0)
{
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
}
if (range > 1) range = 1;
if (range < 0) range = 0;
return range;
@@ -676,7 +700,17 @@ const PluginControl =
value = uiControl.min_value;
} else {
if (uiControl.is_logarithmic) {
value = uiControl.min_value * Math.pow(uiControl.max_value / uiControl.min_value, range);
let minValue = uiControl.min_value;
if (minValue === 0) // LSP controls.
{
minValue = 0.0001;
}
value = minValue * Math.pow(uiControl.max_value / minValue, range);
if (!isFinite(value)) {
value = uiControl.max_value;
} else if (isNaN(value)) {
value = uiControl.min_value;
}
} else {
value = range * (uiControl.max_value - uiControl.min_value) + uiControl.min_value;
}
@@ -731,23 +765,23 @@ const PluginControl =
}
let item_width: number | undefined = isSelect ? 160 : 80;
if (isTrigger)
{
if (isTrigger) {
item_width = undefined;
}
return (
<div ref={this.frameRef}
<div ref={this.frameRef}
className={this.props.classes.controlFrame}
style={{ width: item_width }}
>
>
{/* TITLE SECTION */}
<div className={this.props.classes.titleSection}
style={
{ alignSelf:"stretch", marginBottom: 8, marginLeft: isSelect ? 8 : 0, marginRight: 0
style={
{
alignSelf: "stretch", marginBottom: 8, marginLeft: isSelect ? 8 : 0, marginRight: 0
}}>
}}>
<ControlTooltip uiControl={control} >
<Typography variant="caption" display="block" noWrap style={{
width: "100%",
@@ -758,27 +792,56 @@ const PluginControl =
{/* CONTROL SECTION */}
<div className={this.props.classes.midSection}>
{isTrigger ? (
<Button variant="contained" color="primary" size="small"
onMouseDown={
(evt)=> { this.handleTriggerMouseDown(); }
}
onMouseUp={
(evt)=> { this.handleTriggerMouseUp(); }
}
style={{
textTransform: "none",
background: (isDarkMode() ? "#6750A4" : undefined),
marginLeft: 8, marginRight: 8,minWidth:60,
marginTop: 0
}}
{isTrigger ?
(
control.name.length !== 1 ? (
<Button variant="contained" color="primary" size="small"
onMouseDown={
(evt) => { this.handleTriggerMouseDown(); }
}
onMouseUp={
(evt) => { this.handleTriggerMouseUp(); }
}
style={{
textTransform: "none",
background: (isDarkMode() ? "#6750A4" : undefined),
marginLeft: 8, marginRight: 8, minWidth: 60,
marginTop: 0
}}
>
{control.name}
</Button>
) : (
<Button variant="contained" color="primary" size="small"
onMouseDown={
(evt) => { this.handleTriggerMouseDown(); }
}
onMouseUp={
(evt) => { this.handleTriggerMouseUp(); }
}
style={{
textTransform: "none",
background: (isDarkMode() ? "#6750A4" : undefined),
marginLeft: 8, marginRight: 8,
paddingLeft: 0, paddingRight: 0,
width: 36, height: 36,
marginTop: 0,
borderRadius: 8,
minWidth: 0,
fontSize: "1.2em"
}}
>
{control.name}
</Button>
)
)
>
{control.name}
</Button>
)
: ((isSelect || isAbSwitch || isOnOffSwitch) ? (
this.makeSelect(control, value)
) : (
+1
View File
@@ -767,6 +767,7 @@ const PluginControlView =
<FilePropertyDialog open={this.state.showFileDialog}
fileProperty={this.state.dialogFileProperty}
instanceId={this.props.instanceId}
selectedFile={this.state.dialogFileValue}
onCancel={() => {
this.setState({ showFileDialog: false });
+2 -1
View File
@@ -43,7 +43,8 @@ import EditIcon from '@mui/icons-material//Edit';
import RenameDialog from './RenameDialog';
import Slide, {SlideProps} from '@mui/material/Slide';
import { createStyles, Theme } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import { WithStyles, withStyles} from '@mui/styles';
import {ReactComponent as PluginPresetIcon} from "./svg/ic_pluginpreset2.svg";
+2 -1
View File
@@ -43,7 +43,8 @@ import EditIcon from '@mui/icons-material//Edit';
import RenameDialog from './RenameDialog';
import Slide, {SlideProps} from '@mui/material/Slide';
import { createStyles, Theme } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import { WithStyles, withStyles} from '@mui/styles';
import { ReactComponent as DownloadIcon} from './svg/file_download_black_24dp.svg';
import { ReactComponent as UploadIcon} from './svg/file_upload_black_24dp.svg';
+2 -1
View File
@@ -49,7 +49,8 @@ import SystemMidiBindingsDialog from './SystemMidiBindingsDialog';
import SelectThemeDialog from './SelectThemeDialog';
import Slide, { SlideProps } from '@mui/material/Slide';
import { createStyles, Theme } from '@mui/material/styles';
import createStyles from '@mui/styles/createStyles';
import { Theme } from '@mui/material/styles';
import { WithStyles, withStyles } from '@mui/styles';
import { canScaleWindow, getWindowScaleOptions, getWindowScaleText, setWindowScale, getWindowScale } from './WindowScale';
import OptionsDialog from './OptionsDialog';
+31 -11
View File
@@ -284,23 +284,39 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
return this.state.files.length !== 0;
}
getIcon(status: FileUploadStatus) {
let size = 14;
private innerGetIcon(status: FileUploadStatus)
{
let size=16;
let style = { width: size, height: size, opacity: 0.75 };
let top = 0;
switch (status) {
case FileUploadStatus.Error:
return (<div style={{ position: "relative", top: top }}><ErrorIcon color="error" style={style} /></div>);
return (<ErrorIcon color="error" style={style} />);
case FileUploadStatus.Uploaded:
return (<div style={{ position: "relative", top: top }}><CheckCircleOutlineIcon color="success" style={style}/></div >);
return (
<CheckCircleOutlineIcon color="success" style={style}/>);
case FileUploadStatus.Uploading:
return (<CircularProgress size={size } style={{ margin: 2 }} />);
return (<CircularProgress size={size + "px"} />);
default:
return (<SvgIcon style={{ width: size, height: size, }} />);
}
return (<SvgIcon style={{ width: size, height: size, }} />)
}
}
getIcon(status: FileUploadStatus) {
let size = 16;
//let top = 0;
return (
<div style={{ width: size, position: "relative", top: 1 }}>
{
this.innerGetIcon(status)
}
</div>
);
}
makeBrowserAcceptList() {
let result = UiFileType.MergeMimeTypes(this.props.fileProperty.fileTypes);
@@ -368,9 +384,13 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
return (
<tr>
<td style={{ verticalAlign: "middle" }}>
<div ref={myRef} style={{ display: "flex", flexFlow: "row nowrap", alignItems: "center" }}>
<div ref={myRef} style={{
display: "flex",
flexFlow: "row nowrap",
alignItems: "center",
}}>
{this.getIcon(upload.status)}
<Typography variant="caption" noWrap display="block" style={{ marginLeft: 4 }}> {upload.name} </Typography>
<Typography variant="caption" noWrap display="inline-block" style={{ marginLeft: 4 }}> {upload.name} </Typography>
</div>
</td>
<td style={{ verticalAlign: "middle" }}>