Allow .zip bundle uploads for all File plugin controls.

This commit is contained in:
Robin Davies
2024-08-21 21:04:59 -04:00
parent 060d02a2f8
commit 4a31015cc5
4 changed files with 282 additions and 331 deletions
+2 -3
View File
@@ -1,14 +1,13 @@
# Release Notes
## PiPedal 1.2.41
Version 1.2 is officially released.
## PiPedal 1.2.41 Release
This version includes the following new features:
- Supports Raspberry Pi 5.
- Supports Rasberry Pi OS Bookworm.
- TooB ML allows uploading of models. See below for further details.
- TooB ML allows uploading of model collections contained in .zip files.
- TooBML support for large models (e.g. GuitarML Proteus models)
- Upload .zip file bundles to all File plugin controls.
- Uploads can be organized into sub-directories.
- Various minor improvements to TooB plugin user interfaces.
+5 -3
View File
@@ -370,7 +370,7 @@ export default withStyles(styles, { withTheme: true })(
<Link underline="hover"
color="inherit"
key="1" onClick={() => { this.navigate(""); }}
sx={{ display: 'flex', alignItems: 'center' }}
sx={{ display: 'flex', alignItems: 'center',cursor: "default" }}
>
<HomeIcon sx={{ mr: 0.6 }} fontSize="inherit" />
Home
@@ -383,7 +383,7 @@ export default withStyles(styles, { withTheme: true })(
target = pathConcat(target, directories[i]);
let myTarget = target;
breadcrumbs.push((
<Link underline="hover" key={(i + 1).toString()}
<Link underline="hover" key={(i + 1).toString()} style={{cursor: "default"}}
color="inherit" onClick={() => { this.navigate(myTarget) }}>
{directories[i]}
</Link>
@@ -392,7 +392,9 @@ export default withStyles(styles, { withTheme: true })(
{
let lastdirectory = directories[directories.length - 1];
breadcrumbs.push((
<Typography noWrap key={directories.length.toString()} color="text.secondary"> {lastdirectory}</Typography>
<Typography noWrap key={directories.length.toString()}
style={{cursor: "default"}}
color="text.secondary"> {lastdirectory}</Typography>
));
}
+103 -151
View File
@@ -54,8 +54,7 @@ export class Port implements Deserializable<Port> {
static deserialize_array(input: any): Port[] {
let result: Port[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new Port().deserialize(input[i]);
}
return result;
@@ -93,8 +92,7 @@ export class PortGroup {
}
static deserialize_array(input: any): PortGroup[] {
let result: PortGroup[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result.push(new PortGroup().deserialize(input[i]));
}
return result;
@@ -114,87 +112,88 @@ export class UiFileType {
this.mimeType = input.mimeType;
return this;
}
static deserialize_array(input: any): UiFileType[]
{
static deserialize_array(input: any): UiFileType[] {
let result: UiFileType[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new UiFileType().deserialize(input[i]);
}
return result;
}
private static IsAndroid() : boolean
{
private static IsAndroid(): boolean {
return /Android/i.test(navigator.userAgent);
}
static MergeMimeTypes(fileTypes: UiFileType[]): string
{
static MergeMimeTypes(fileTypes: UiFileType[]): string {
if (fileTypes.length === 0) {
return "";
}
let result = fileTypes[0].mimeType;
for (let i = 1; i < fileTypes.length; ++i)
{
let fileType = fileTypes[i];
if (fileType.mimeType !== result)
{
if (result.startsWith("audio/") && fileType.mimeType.startsWith("audio/"))
{
result = "audio/*";
} else if (result.startsWith("video/") && fileType.mimeType.startsWith("video/"))
{
result = "video/*";
} else if (result.startsWith("text/") && fileType.mimeType.startsWith("text/"))
{
result = "text/*";
} else {
result = "application/octet-stream";
}
}
}
if (this.IsAndroid())
{
if (result.startsWith("audio/")) result = "audio/*";
if (result.startsWith("video/")) result = "video/*";
if (result.startsWith("text/")) result = "text/*";
if (this.IsAndroid()) {
return ""; // allow selection of .zip files, plus whatever. We'll catch it later.
} else {
// chrome desktop thinks "application/octet-stream" is .exe, .com, or .bat.
// Feed it file extensions isntead.
if (result === "application/octet-stream")
let result = "";
for (let i = 0; i < fileTypes.length; ++i) {
let fileType = fileTypes[i];
if (fileType.fileExtension !== "") {
if (result.length !== 0) // prefer file extensions.
{
result = "";
for (let i = 0; i < fileTypes.length; ++i)
{
if (i !== 0)
{
result += ',';
result += ",";
result += fileType.fileExtension;
}
result += fileTypes[i].fileExtension;
} else {
if (fileType.mimeType !== result) {
let t = "";
if (result.startsWith("audio/") && fileType.mimeType.startsWith("audio/")) {
t = "audio/*";
} else if (result.startsWith("video/") && fileType.mimeType.startsWith("video/")) {
t = "video/*";
} else if (result.startsWith("text/") && fileType.mimeType.startsWith("text/")) {
t = "text/*";
}
if (t.length !== 0) {
if (result.length !== 0) {
result += ",";
}
result += t;
}
}
}
}
let hasZip = false;
let types = result.split(",");
for (let thisType of types) {
if (thisType === ".zip") {
hasZip = true;
break;
}
}
// add .zip files
if (!hasZip) {
if (result.length !== 0) {
result += ",.zip";
}
}
return result;
}
}
name: string = "";
fileExtension: string = "";
mimeType: string = "";
}
export class UiPropertyNotification {
deserialize(input: any): 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[]
{
static deserialize_array(input: any): UiPropertyNotification[] {
let result: UiPropertyNotification[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new UiPropertyNotification().deserialize(input[i]);
}
return result;
@@ -207,8 +206,7 @@ export class UiPropertyNotification {
};
export class UiFrequencyPlot {
deserialize(input: any): UiFrequencyPlot
{
deserialize(input: any): UiFrequencyPlot {
this.patchProperty = input.patchProperty;
this.index = input.index;
this.portGroup = input.portGroup;
@@ -220,11 +218,9 @@ export class UiFrequencyPlot {
this.width = input.width;
return this;
}
static deserialize_array(input: any): UiFrequencyPlot[]
{
static deserialize_array(input: any): UiFrequencyPlot[] {
let result: UiFrequencyPlot[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new UiFrequencyPlot().deserialize(input[i]);
}
return result;
@@ -242,8 +238,7 @@ export class UiFrequencyPlot {
};
export class UiFileProperty {
deserialize(input: any): UiFileProperty
{
deserialize(input: any): UiFileProperty {
this.label = input.label;
this.fileTypes = UiFileType.deserialize_array(input.fileTypes);
this.patchProperty = input.patchProperty;
@@ -253,11 +248,9 @@ export class UiFileProperty {
this.resourceDirectory = input.resourceDirectory ?? "";
return this;
}
static deserialize_array(input: any): UiFileProperty[]
{
static deserialize_array(input: any): UiFileProperty[] {
let result: UiFileProperty[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new UiFileProperty().deserialize(input[i]);
}
return result;
@@ -268,8 +261,7 @@ export class UiFileProperty {
let filenamePos = name.lastIndexOf('/') + 1;
filenamePos = Math.max(name.lastIndexOf('\\') + 1);
filenamePos = Math.max(name.lastIndexOf(':') + 1);
if (pos < filenamePos)
{
if (pos < filenamePos) {
return "";
}
@@ -284,14 +276,14 @@ export class UiFileProperty {
return true;
}
let extension = UiFileProperty.getFileExtension(filename);
for (let fileType of this.fileTypes)
{
if (fileType.fileExtension === extension )
{
if (extension === ".zip") {
return true;
}
if (fileType.fileExtension === "*" || fileType.fileExtension === "")
{
for (let fileType of this.fileTypes) {
if (fileType.fileExtension === extension) {
return true;
}
if (fileType.fileExtension === "*" || fileType.fileExtension === "") {
return true;
}
}
@@ -308,8 +300,7 @@ export class UiFileProperty {
};
export class Lv2Plugin implements Deserializable<Lv2Plugin> {
deserialize(input: any): Lv2Plugin
{
deserialize(input: any): Lv2Plugin {
this.uri = input.uri;
this.name = input.name;
this.brand = input.name ? input.name : "";
@@ -323,21 +314,18 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
this.comment = input.comment;
this.ports = Port.deserialize_array(input.ports);
this.port_groups = PortGroup.deserialize_array(input.port_groups);
if (input.fileProperties)
{
if (input.fileProperties) {
this.fileProperties = UiFileProperty.deserialize_array(input.fileProperties)
} else {
this.fileProperties = [];
}
if (input.frequencyPlots)
{
if (input.frequencyPlots) {
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
} else {
this.frequencyPlots = [];
}
if (input.uiPortNotifications)
{
if (input.uiPortNotifications) {
this.uiPortNotifications = UiPropertyNotification.deserialize_array(input.uiPortNotifications);
} else {
this.uiPortNotifications = [];
@@ -371,11 +359,9 @@ export class ScalePoint implements Deserializable<ScalePoint> {
this.label = input.label;
return this;
}
static deserialize_array(input: any): ScalePoint[]
{
static deserialize_array(input: any): ScalePoint[] {
let result: ScalePoint[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new ScalePoint().deserialize(input[i]);
}
return result;
@@ -458,8 +444,7 @@ export enum ControlType {
}
export class UiControl implements Deserializable<UiControl> {
deserialize(input: any): UiControl
{
deserialize(input: any): UiControl {
this.symbol = input.symbol;
this.name = input.name;
this.index = input.index;
@@ -486,21 +471,17 @@ export class UiControl implements Deserializable<UiControl> {
this.connection_optional = input.connection_optional ? true : false;
if (this.is_bypass)
{
if (this.is_bypass) {
this.not_on_gui = true;
}
this.controlType = ControlType.Dial;
if (!this.is_input)
{
if (this.units === Units.midiNote)
{
if (!this.is_input) {
if (this.units === Units.midiNote) {
this.controlType = ControlType.Tuner;
} else if (this.units === Units.db)
{
} else if (this.units === Units.db) {
this.controlType = ControlType.DbVu;
} else if (this.enumeration_property) {
this.controlType = ControlType.OutputSelect;
@@ -508,45 +489,36 @@ export class UiControl implements Deserializable<UiControl> {
this.controlType = ControlType.Vu;
}
}
if (this.isValidEnumeration())
{
if (this.isValidEnumeration()) {
this.controlType = ControlType.Select;
if (this.scale_points.length === 2)
{
if (this.scale_points.length === 2) {
this.controlType = ControlType.ABSwitch;
}
} else {
if (this.toggled_property || (this.integer_property && this.min_value === 0 && this.max_value === 1))
{
if (this.toggled_property || (this.integer_property && this.min_value === 0 && this.max_value === 1)) {
this.controlType = ControlType.OnOffSwitch;
}
}
return this;
}
applyProperties(properties: Partial<UiControl>): UiControl
{
applyProperties(properties: Partial<UiControl>): UiControl {
return { ...this, ...properties };
}
private hasScalePoint(value: number): boolean {
for (let scale_point of this.scale_points)
{
for (let scale_point of this.scale_points) {
if (scale_point.value === value) return true;
}
return false;
}
private isValidEnumeration(): boolean {
if (this.enumeration_property) return true;
if (this.toggled_property && this.min_value === 0 && this.max_value === 1)
{
if (this.hasScalePoint(this.min_value) && this.hasScalePoint(this.max_value))
{
if (this.toggled_property && this.min_value === 0 && this.max_value === 1) {
if (this.hasScalePoint(this.min_value) && this.hasScalePoint(this.max_value)) {
return true;
}
}
if (this.integer_property && this.min_value === 0 && this.max_value === 1)
{
if (this.hasScalePoint(this.min_value) && this.hasScalePoint(this.max_value))
{
if (this.integer_property && this.min_value === 0 && this.max_value === 1) {
if (this.hasScalePoint(this.min_value) && this.hasScalePoint(this.max_value)) {
return true;
}
}
@@ -557,8 +529,7 @@ export class UiControl implements Deserializable<UiControl> {
static deserialize_array(input: any): UiControl[] {
let result: UiControl[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new UiControl().deserialize(input[i]);
}
return result;
@@ -590,15 +561,12 @@ export class UiControl implements Deserializable<UiControl> {
// Return the value of the closest scale_point.
clampSelectValue(value: number): number {
if (this.scale_points.length !== 0)
{
if (this.scale_points.length !== 0) {
let minError = 1.0E100;
let bestValue = value;
for (let i = 0; i < this.scale_points.length; ++i)
{
for (let i = 0; i < this.scale_points.length; ++i) {
let error = Math.abs(this.scale_points[i].value - value);
if (error < minError)
{
if (error < minError) {
minError = error;
bestValue = this.scale_points[i].value;
}
@@ -680,11 +648,9 @@ export class UiControl implements Deserializable<UiControl> {
value = Math.round(value);
}
for (let i = 0; i < this.scale_points.length; ++i)
{
for (let i = 0; i < this.scale_points.length; ++i) {
let scalePoint = this.scale_points[i];
if (scalePoint.value === value)
{
if (scalePoint.value === value) {
return scalePoint.label;
}
}
@@ -738,8 +704,7 @@ export class UiControl implements Deserializable<UiControl> {
}
return text;
}
formatShortValue(value: number): string
{
formatShortValue(value: number): string {
if (this.enumeration_property) {
for (let i = 0; i < this.scale_points.length; ++i) {
let scale_point = this.scale_points[i];
@@ -766,8 +731,7 @@ export class UiControl implements Deserializable<UiControl> {
export class UiPlugin implements Deserializable<UiPlugin> {
deserialize(input: any): UiPlugin
{
deserialize(input: any): UiPlugin {
this.uri = input.uri;
this.name = input.name;
this.brand = input.brand ? input.brand : "";
@@ -783,14 +747,12 @@ export class UiPlugin implements Deserializable<UiPlugin> {
this.description = input.description;
this.controls = UiControl.deserialize_array(input.controls);
this.port_groups = PortGroup.deserialize_array(input.port_groups);
if (input.fileProperties)
{
if (input.fileProperties) {
this.fileProperties = UiFileProperty.deserialize_array(input.fileProperties)
} else {
this.fileProperties = [];
}
if (input.frequencyPlots)
{
if (input.frequencyPlots) {
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
} else {
this.frequencyPlots = [];
@@ -802,8 +764,7 @@ export class UiPlugin implements Deserializable<UiPlugin> {
}
static deserialize_array(input: any): UiPlugin[] {
let result: UiPlugin[] = [];
for (let i = 0; i < input.length; ++i)
{
for (let i = 0; i < input.length; ++i) {
result[i] = new UiPlugin().deserialize(input[i]);
}
return result;
@@ -814,37 +775,29 @@ export class UiPlugin implements Deserializable<UiPlugin> {
}
getControl(key: string): UiControl | undefined {
for (let i = 0; i < this.controls.length; ++i)
{
for (let i = 0; i < this.controls.length; ++i) {
let control = this.controls[i];
if (control.symbol === key)
{
if (control.symbol === key) {
return control;
}
}
return undefined;
}
getPortGroupByUri(uri: string) :PortGroup | null
{
for (let i = 0; i < this.port_groups.length; ++i)
{
getPortGroupByUri(uri: string): PortGroup | null {
for (let i = 0; i < this.port_groups.length; ++i) {
let port_group = this.port_groups[i];
if (port_group.uri === uri)
{
if (port_group.uri === uri) {
return port_group;
}
}
return null;
}
getPortGroupBySymbol(symbol: string): PortGroup | null
{
for (let i = 0; i < this.port_groups.length; ++i)
{
getPortGroupBySymbol(symbol: string): PortGroup | null {
for (let i = 0; i < this.port_groups.length; ++i) {
let port_group = this.port_groups[i];
if (port_group.symbol === symbol)
{
if (port_group.symbol === symbol) {
return port_group;
}
}
@@ -873,8 +826,7 @@ export class UiPlugin implements Deserializable<UiPlugin> {
export function makeSplitUiPlugin(): UiPlugin
{
export function makeSplitUiPlugin(): UiPlugin {
return new UiPlugin().deserialize({
uri: "uri://two-play/pipedal/pedalboard#Split",
-2
View File
@@ -1,5 +1,3 @@
- change icons on gallery in index.html
- provide direct link to docs on both landing pages.
- feature: redo ./makepackage so that it runs without sudo.
- Bug: text Cursor hovering over the breadcrumb bar in file property dialog.
- Bug: Turning off wifi-direct sould re-enable NetworkManager.