diff --git a/CMakeLists.txt b/CMakeLists.txt index 10021d3..8796e44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16.0) project(pipedal - VERSION 1.2.40 + VERSION 1.2.41 DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) -set (DISPLAY_VERSION "v1.2.40Beta6") +set (DISPLAY_VERSION "v1.2.41") set (CMAKE_INSTALL_PREFIX "/usr/") diff --git a/README.md b/README.md index 80862c7..736934a 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ -Download: v1.2.40 Beta6 +Download: v1.2.41 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).   -#### NEW version 1.2.40 Beta6 release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +#### NEW version 1.2.41 Release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.   diff --git a/docs/Installing.md b/docs/Installing.md index 491cc49..7b3f0fd 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -13,17 +13,17 @@ page_icon: img/Install4.jpg Download the most recent Debian (.deb) package for your platform: -- [Raspberry Pi OS bookworm (64-bit) v1.2.40 Beta6](https://github.com/rerdavies/pipedal/releases/download/) +- [Raspberry Pi OS bookworm (64-bit) v1.2.41](https://github.com/rerdavies/pipedal/releases/download/) - [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) -Version 1.2.40 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. +Version 1.2.41 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install pipedal_1.2.40_arm64.deb + sudo apt-get install pipedal_1.2.41_arm64.deb ``` Adjust accordingly if you have downloaded v1.1.31. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index d18864a..9faabce 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,9 +1,62 @@ # Release Notes +## 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. +- 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. + +You can now upload new models into TooB ML. TooB ML models are compatible with models for the GuitarML Proteus plugin. Currently, the GuitarML Proteus model download pages are the best source for new models to use with TooB ML. To install +new models in TooB ML, follow these instructions: + +- Download Proteus models from https://guitarml.com/tonelibrary/tonelib-pro.html to your local computer or Android + device. TooB ML supports both Proteus .json models, and also allows you to install model collections contained in .zip files. +- Load the TooB ML plugin. +- click on the Model control. +- click on the Upload button in the lower left corner of the Model selection dialog. +- Upload the .json model file or .zip model collection that you downloaded from The GuitarML Tone Library. +- PiPedal now monitors LV2 plugin directories for changes, and automatically updates available plugins in the + PiPedal UI, without requiring a restart. + +Big fixes: +- Wi-Fi is restarted properly without requiring a reboot when the PiPedal Wi-Fi Direct connection is disabled. +- Dialog button colors follow Android UI conventions. +- The web server supports uploading of large files (limited by default to 512MB). +- Failure to open audio devices upon reboot for devices that initialize slowly. +- Misbehavior with preset names after renaming a preset. +- Dialog button colors follow Android UI conventions. +- Toggle and on/off controls now display in purple instead of red/pink. +- automatic provisioning of resource files in .LV2 plugins. +- Gain control for ToobML is enabled or disabled depending on whether the model has a gain control input (Thanks to @Foolhen) +- The control view for split controls now displays properly. +- Stereo connectors in dark mode now render properly. +- Permissions are correctly set on existing files and folders in /var/pipedal at install time. `pipedalconfig1 has a new + `--fix-permissions` option, which corrects permissions on files in /var/pipedal. +- Bypass MIDI bindings now work properly. Thanks to @FoolHen. +- GxTuner now correctly displays note pitches. Thanks to @FoolHen. +- Fixed glitch in on-boarding process when changing Wi-Fi direct settings. +- Fixed incorrect display of banks in dark mode Thanks to @FoolHen. +- pidedald service shuts down cleanly. With help from @FoolHen. +- Fixed missing dependency in build procedure documentation. Thanks to @FoolHen +- Documentation edits and corrections. With help from @FoolHen. +- automatic provisioning of resource files in .LV2 plugins (devolopment feature) +- uninstall.sh now removes all files installed by ./install.sh (used only during development). + + + + + ## Pipedal 1.2.40 Beta6 - PiPedal now monitors lv2 directories in order to automatically add newly-installed LV2 plugins. - Toggle and on/off switch colors changed from red/pink to purple. +- MIDI bindings can be created for split controls. -## Pipedal 1.2.38 Beta6 +## Pipedal 1.2.38 Beta5 Fixes: - PiPedal won't run on non-en-US locales. diff --git a/docs/download.md b/docs/download.md index 955d134..d82a39a 100644 --- a/docs/download.md +++ b/docs/download.md @@ -4,17 +4,17 @@ Download the most recent Debian (.deb) package for your platform: -- Raspberry Pi OS Bookworm (64-bit) v1.2.40 Beta6 +- Raspberry Pi OS Bookworm (64-bit) v1.2.41 - Ubuntu 21.04 or Raspberry Pi OS bullseyeyeye (64-bit) v1.1.31 -v1.2.40 Beta6 is does not currently support Ubuntu 21.04, or older versions of Raspberry Pi OS. +v1.2.41 is does not currently support Ubuntu 21.04, or older versions of Raspberry Pi OS. Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install ./pipedal_1.2.40_arm64.deb + sudo apt-get install ./pipedal_1.2.41_arm64.deb ``` Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. diff --git a/docs/index.md b/docs/index.md index 09d9d19..7a77c70 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1.2.40 +v1.2.41   @@ -9,8 +9,9 @@ To download PiPedal, click [here](download.md). To view PiPedal documentation, click [here](Documentation.md). -> NEW version 1.2.40 Beta6 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +#### NEW version 1.2.41 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +  Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet. PiPedal running on a Raspberry Pi 4 or Pi 5 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats. diff --git a/react/src/FilePropertyDialog.tsx b/react/src/FilePropertyDialog.tsx index 7c17ddb..9105244 100644 --- a/react/src/FilePropertyDialog.tsx +++ b/react/src/FilePropertyDialog.tsx @@ -370,7 +370,7 @@ export default withStyles(styles, { withTheme: true })( { this.navigate(""); }} - sx={{ display: 'flex', alignItems: 'center' }} + sx={{ display: 'flex', alignItems: 'center',cursor: "default" }} > Home @@ -383,7 +383,7 @@ export default withStyles(styles, { withTheme: true })( target = pathConcat(target, directories[i]); let myTarget = target; breadcrumbs.push(( - { this.navigate(myTarget) }}> {directories[i]} @@ -392,7 +392,9 @@ export default withStyles(styles, { withTheme: true })( { let lastdirectory = directories[directories.length - 1]; breadcrumbs.push(( - {lastdirectory} + {lastdirectory} )); } diff --git a/react/src/Lv2Plugin.tsx b/react/src/Lv2Plugin.tsx index 2204183..d0b0b2b 100644 --- a/react/src/Lv2Plugin.tsx +++ b/react/src/Lv2Plugin.tsx @@ -26,7 +26,7 @@ interface Deserializable { } -export class Port implements Deserializable { +export class Port implements Deserializable { deserialize(input: any): Port { this.port_index = input.port_index; this.symbol = input.symbol; @@ -54,28 +54,27 @@ export class Port implements Deserializable { 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; } - port_index: number = -1; - symbol: string = ""; - name: string = ""; - min_value: number = 0; - max_value: number = 1; - default_value: number = 0.5; - scale_points: ScalePoint[] = []; - is_input: boolean = false; - is_output: boolean = false + port_index: number = -1; + symbol: string = ""; + name: string = ""; + min_value: number = 0; + max_value: number = 1; + default_value: number = 0.5; + scale_points: ScalePoint[] = []; + is_input: boolean = false; + is_output: boolean = false is_control_port: boolean = false; - is_audio_port: boolean = false; - is_atom_port: boolean = false; - is_valid: boolean = false; - supports_midi: boolean = false; + is_audio_port: boolean = false; + is_atom_port: boolean = false; + is_valid: boolean = false; + supports_midi: boolean = false; supports_time_position: boolean = false; - port_group: string = ""; + port_group: string = ""; comment: string = ""; is_bypass: boolean = false; is_program_controller: boolean = false; @@ -91,10 +90,9 @@ export class PortGroup { return this; } - static deserialize_array(input: any) : 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,67 +112,71 @@ 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 - { - if (fileTypes.length === 0) { + 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") - { - result = ""; - for (let i = 0; i < fileTypes.length; ++i) - { - if (i !== 0) + 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 += ','; + result += ","; + result += fileType.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; + } } - result += fileTypes[i].fileExtension; } } + 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; } - return result; } name: string = ""; fileExtension: string = ""; @@ -182,19 +184,16 @@ export class UiFileType { } 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,78 +238,73 @@ export class UiFrequencyPlot { }; export class UiFileProperty { - deserialize(input: any): UiFileProperty - { - this.label = input.label; - this.fileTypes = UiFileType.deserialize_array(input.fileTypes); - this.patchProperty = input.patchProperty; - this.directory = input.directory; - this.index = input.index; - this.portGroup = input.portGroup; - this.resourceDirectory = input.resourceDirectory??""; - return this; - } - static deserialize_array(input: any): UiFileProperty[] - { - let result: UiFileProperty[] = []; - for (let i = 0; i < input.length; ++i) - { - result[i] = new UiFileProperty().deserialize(input[i]); - } - return result; + deserialize(input: any): UiFileProperty { + this.label = input.label; + this.fileTypes = UiFileType.deserialize_array(input.fileTypes); + this.patchProperty = input.patchProperty; + this.directory = input.directory; + this.index = input.index; + this.portGroup = input.portGroup; + this.resourceDirectory = input.resourceDirectory ?? ""; + return this; + } + static deserialize_array(input: any): UiFileProperty[] { + let result: UiFileProperty[] = []; + for (let i = 0; i < input.length; ++i) { + result[i] = new UiFileProperty().deserialize(input[i]); } + return result; + } - private static getFileExtension(name: string): string { - let pos = name.lastIndexOf('.'); - let filenamePos = name.lastIndexOf('/') +1; - filenamePos = Math.max(name.lastIndexOf('\\')+1); - filenamePos = Math.max(name.lastIndexOf(':')+1); - if (pos < filenamePos) - { - return ""; - } - - if (pos !== -1) { - return name.substring(pos); - } + private static getFileExtension(name: string): string { + let pos = name.lastIndexOf('.'); + let filenamePos = name.lastIndexOf('/') + 1; + filenamePos = Math.max(name.lastIndexOf('\\') + 1); + filenamePos = Math.max(name.lastIndexOf(':') + 1); + if (pos < filenamePos) { return ""; } - - wantsFile(filename: string) : boolean { - if (this.fileTypes.length === 0) { + + if (pos !== -1) { + return name.substring(pos); + } + return ""; + } + + wantsFile(filename: string): boolean { + if (this.fileTypes.length === 0) { + return true; + } + let extension = UiFileProperty.getFileExtension(filename); + if (extension === ".zip") { + return true; + } + for (let fileType of this.fileTypes) { + if (fileType.fileExtension === extension) { return true; } - let extension = UiFileProperty.getFileExtension(filename); - for (let fileType of this.fileTypes) - { - if (fileType.fileExtension === extension ) - { - return true; - } - if (fileType.fileExtension === "*" || fileType.fileExtension === "") - { - return true; - } + if (fileType.fileExtension === "*" || fileType.fileExtension === "") { + return true; } - return false; } + return false; + } - label: string = ""; - fileTypes: UiFileType[] = []; - patchProperty: string = ""; - directory: string = ""; - index: number = -1; - portGroup: string = ""; - resourceDirectory: string = ""; + label: string = ""; + fileTypes: UiFileType[] = []; + patchProperty: string = ""; + directory: string = ""; + index: number = -1; + portGroup: string = ""; + resourceDirectory: string = ""; }; -export class Lv2Plugin implements Deserializable { - deserialize(input: any): Lv2Plugin - { +export class Lv2Plugin implements Deserializable { + deserialize(input: any): Lv2Plugin { this.uri = input.uri; this.name = input.name; - this.brand = input.name? input.name: ""; - this.label = input.label? input.label: this.name; + this.brand = input.name ? input.name : ""; + this.label = input.label ? input.label : this.name; this.plugin_class = input.plugin_class; this.supported_features = input.supported_features; this.required_features = input.required_features; @@ -321,23 +312,20 @@ export class Lv2Plugin implements Deserializable { this.author_name = input.author_name; this.author_homepage = input.author_homepage; this.comment = input.comment; - this.ports= Port.deserialize_array(input.ports); + 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 = []; @@ -346,36 +334,34 @@ export class Lv2Plugin implements Deserializable { } static EmptyFeatures: string[] = []; - uri: string = ""; - name: string = ""; - brand: string = ""; - label: string = ""; - plugin_class: string = ""; + uri: string = ""; + name: string = ""; + brand: string = ""; + label: string = ""; + plugin_class: string = ""; supported_features: string[] = Lv2Plugin.EmptyFeatures; - required_features: string[] = Lv2Plugin.EmptyFeatures; - optional_features: string[] = Lv2Plugin.EmptyFeatures; - author_name: string = ""; - author_homepage: string = ""; - comment: string = ""; - ports: Port[] = Port.EmptyPorts; - port_groups: PortGroup[] = []; - fileProperties: UiFileProperty[] = []; - frequencyPlots: UiFrequencyPlot[] = []; + required_features: string[] = Lv2Plugin.EmptyFeatures; + optional_features: string[] = Lv2Plugin.EmptyFeatures; + author_name: string = ""; + author_homepage: string = ""; + comment: string = ""; + ports: Port[] = Port.EmptyPorts; + port_groups: PortGroup[] = []; + fileProperties: UiFileProperty[] = []; + frequencyPlots: UiFrequencyPlot[] = []; uiPortNotifications: UiPropertyNotification[] = []; } -export class ScalePoint implements Deserializable { +export class ScalePoint implements Deserializable { deserialize(input: any): ScalePoint { this.value = input.value; 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; @@ -386,9 +372,9 @@ export class ScalePoint implements Deserializable { export enum PluginType { // Reserved types used in pedalboards. - None="", - InvalidPlugin= "InvalidPlugin", - + None = "", + InvalidPlugin = "InvalidPlugin", + Plugin = "Plugin", AllpassPlugin = "AllpassPlugin", AmplifierPlugin = "AmplifierPlugin", @@ -428,7 +414,7 @@ export enum PluginType { UtilityPlugin = "UtilityPlugin", WaveshaperPlugin = "WaveshaperPlugin", - // psuedo plugin type for the Amps node of the filter dialog. + // psuedo plugin type for the Amps node of the filter dialog. PiPedalAmpsNode = "PiPedalAmpsNode", // pseudo plugin types for splitter. @@ -457,9 +443,8 @@ export enum ControlType { OutputSelect } -export class UiControl implements Deserializable { - deserialize(input: any): UiControl - { +export class UiControl implements Deserializable { + deserialize(input: any): UiControl { this.symbol = input.symbol; this.name = input.name; this.index = input.index; @@ -480,27 +465,23 @@ export class UiControl implements Deserializable { this.units = input.units as Units; this.comment = input.comment ?? ""; - this.is_bypass = input.is_bypass ? true: false; - this.is_program_controller = input.is_program_controller? true: false; + this.is_bypass = input.is_bypass ? true : false; + this.is_program_controller = input.is_program_controller ? true : false; this.custom_units = input.custom_units ?? ""; - this.connection_optional = input.connection_optional ? true: false; + 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 { 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 - { - return {...this,...properties}; + applyProperties(properties: Partial): 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 { + 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,23 +529,22 @@ export class UiControl implements Deserializable { 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; } symbol: string = ""; - name: string = ""; + name: string = ""; index: number = -1; is_input: boolean = true; min_value: number = 0; max_value: number = 1; - default_value:number = 0.5; + default_value: number = 0.5; is_logarithmic: boolean = false; display_priority: number = -1; range_steps: number = 0; - integer_property:boolean = false; + integer_property: boolean = false; enumeration_property: boolean = false; trigger: boolean = false; not_on_gui: boolean = false; @@ -589,16 +560,13 @@ export class UiControl implements Deserializable { // Return the value of the closest scale_point. - clampSelectValue(value: number): number{ - if (this.scale_points.length !== 0) - { + clampSelectValue(value: number): number { + if (this.scale_points.length !== 0) { let minError = 1.0E100; let bestValue = value; - for (let i = 0; i < this.scale_points.length; ++i) - { - let error = Math.abs(this.scale_points[i].value-value); - if (error < minError) - { + for (let i = 0; i < this.scale_points.length; ++i) { + let error = Math.abs(this.scale_points[i].value - value); + if (error < minError) { minError = error; bestValue = this.scale_points[i].value; } @@ -609,20 +577,20 @@ export class UiControl implements Deserializable { } } - isHidden() : boolean { + isHidden(): boolean { return this.not_on_gui || (this.connection_optional && !this.is_input); } - isOnOffSwitch() : boolean { + isOnOffSwitch(): boolean { return this.controlType === ControlType.OnOffSwitch; } isAbToggle(): boolean { return this.controlType === ControlType.ABSwitch; } - isSelect() : boolean { + isSelect(): boolean { return this.controlType === ControlType.Select; } - isOutputSelect() : boolean { + isOutputSelect(): boolean { return !this.is_input && this.controlType === ControlType.OutputSelect; } @@ -630,23 +598,23 @@ export class UiControl implements Deserializable { isLamp(): boolean { return this.toggled_property && this.scale_points.length === 0 && !this.is_input; } - isDial() : boolean { + isDial(): boolean { return this.controlType === ControlType.Dial; } - isTuner() : boolean { + isTuner(): boolean { return this.controlType === ControlType.Tuner; } - isVu() : boolean { + isVu(): boolean { return this.controlType === ControlType.Vu; } - isDbVu() : boolean { + isDbVu(): boolean { return this.controlType === ControlType.DbVu; } valueToRange(value: number): number { - if (this.toggled_property) return value === 0 ? 0: 1; + if (this.toggled_property) return value === 0 ? 0 : 1; if (this.integer_property || this.enumeration_property) { value = Math.round(value); @@ -659,11 +627,11 @@ export class UiControl implements Deserializable { return range; } - rangeToValue(range: number) : number { + rangeToValue(range: number): number { if (range < 0) range = 0; if (range > 1) range = 1; - if (this.toggled_property) return range === 0? 0: 1; + if (this.toggled_property) return range === 0 ? 0 : 1; let value = range * (this.max_value - this.min_value) + this.min_value; if (this.integer_property || this.enumeration_property) { @@ -680,11 +648,9 @@ export class UiControl implements Deserializable { 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 { } 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]; @@ -761,17 +726,16 @@ export class UiControl implements Deserializable { } } - + } export class UiPlugin implements Deserializable { - deserialize(input: any): UiPlugin - { + deserialize(input: any): UiPlugin { this.uri = input.uri; this.name = input.name; - this.brand = input.brand ? input.brand: ""; - this.label = input.label? input.label: this.name; + this.brand = input.brand ? input.brand : ""; + this.label = input.label ? input.label : this.name; this.plugin_type = input.plugin_type as PluginType; this.plugin_display_type = input.plugin_display_type; this.author_name = input.author_name; @@ -783,14 +747,12 @@ export class UiPlugin implements Deserializable { 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 { } 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,191 +775,182 @@ export class UiPlugin implements Deserializable { } 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; } } return null; } - uri: string = ""; - name: string = ""; - brand: string = ""; - label: string = ""; - plugin_type: PluginType = PluginType.InvalidPlugin; + uri: string = ""; + name: string = ""; + brand: string = ""; + label: string = ""; + plugin_type: PluginType = PluginType.InvalidPlugin; plugin_display_type: string = ""; - author_name: string = ""; - author_homepage: string = ""; - audio_inputs: number = 0; - audio_outputs: number = 0; - has_midi_input: number = 0; - has_midi_output: number = 0; - description: string = ""; - controls: UiControl[] = []; - port_groups: PortGroup[] = []; - fileProperties: UiFileProperty[] = []; - frequencyPlots: UiFrequencyPlot[] = []; - is_vst3 : boolean = false; + author_name: string = ""; + author_homepage: string = ""; + audio_inputs: number = 0; + audio_outputs: number = 0; + has_midi_input: number = 0; + has_midi_output: number = 0; + description: string = ""; + controls: UiControl[] = []; + port_groups: PortGroup[] = []; + fileProperties: UiFileProperty[] = []; + frequencyPlots: UiFrequencyPlot[] = []; + is_vst3: boolean = false; } -export function makeSplitUiPlugin(): UiPlugin -{ +export function makeSplitUiPlugin(): UiPlugin { return new UiPlugin().deserialize({ - uri: "uri://two-play/pipedal/pedalboard#Split", - name: "Split", - brand: "", - label: "", - plugin_type: PluginType.SplitA, + uri: "uri://two-play/pipedal/pedalboard#Split", + name: "Split", + brand: "", + label: "", + plugin_type: PluginType.SplitA, plugin_display_type: "Split", - author_name: "", - author_homepage: "", - audio_inputs: 1, - audio_outputs: 1, - has_midi_input: 0, - has_midi_output: 0, + author_name: "", + author_homepage: "", + audio_inputs: 1, + audio_outputs: 1, + has_midi_input: 0, + has_midi_output: 0, description: "", - controls: [ + controls: [ new UiControl().applyProperties({ symbol: "splitType", - name: "Type", + name: "Type", index: 0, is_input: true, min_value: 0.0, - max_value: 2.0, + max_value: 2.0, enumeration_property: true, scale_points: [ - new ScalePoint().deserialize({value: 0, label: "A/B"}), - new ScalePoint().deserialize({value: 1, label: "mix"}), - new ScalePoint().deserialize({value: 1, label: "L/R"}), + new ScalePoint().deserialize({ value: 0, label: "A/B" }), + new ScalePoint().deserialize({ value: 1, label: "mix" }), + new ScalePoint().deserialize({ value: 1, label: "L/R" }), ], is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - - }) , + + }), new UiControl().applyProperties({ symbol: "select", - name: "Select", + name: "Select", index: 1, is_input: true, min_value: 0.0, - max_value: 1.0, + max_value: 1.0, enumeration_property: true, scale_points: [ - new ScalePoint().deserialize({value: 0, label: "A"}), - new ScalePoint().deserialize({value: 1, label: "B"}), + new ScalePoint().deserialize({ value: 0, label: "A" }), + new ScalePoint().deserialize({ value: 1, label: "B" }), ], is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - - }) , + + }), new UiControl().applyProperties({ symbol: "mix", - name: "Mix", + name: "Mix", index: 2, is_input: true, min_value: -1.0, - max_value: 1.0, + max_value: 1.0, is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - - }) , + + }), new UiControl().applyProperties({ symbol: "panL", - name: "Pan Top", + name: "Pan Top", index: 3, is_input: true, min_value: -1.0, - max_value: 1.0, + max_value: 1.0, is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - - }) , + + }), new UiControl().applyProperties({ symbol: "volL", - name: "Vol Top", + name: "Vol Top", index: 4, is_input: true, min_value: -60.0, - max_value: 12.0, + max_value: 12.0, is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - - }) , + + }), new UiControl().applyProperties({ symbol: "panR", - name: "Pan Bottom", + name: "Pan Bottom", index: 5, is_input: true, min_value: -1.0, - max_value: 1.0, + max_value: 1.0, is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - - }) , + + }), new UiControl().applyProperties({ symbol: "volR", - name: "Vol Bottom", + name: "Vol Bottom", index: 6, is_input: true, min_value: -60.0, - max_value: 12.0, + max_value: 12.0, is_bypass: false, is_program_controller: false, custom_units: "", connection_optional: false, - }) + }) ], - port_groups: [], + port_groups: [], fileProperties: [], frequencyPlots: [], - is_vst3 : false, - + is_vst3: false, + } ); } diff --git a/src/SetWifiConfig.cpp b/src/SetWifiConfig.cpp index 035f049..565f825 100644 --- a/src/SetWifiConfig.cpp +++ b/src/SetWifiConfig.cpp @@ -315,6 +315,8 @@ void pipedal::SetWifiConfig(const WifiConfigSettings &settings) { apdConfig.Load(path); } + if (!UsingNetworkManager()) + {} apdConfig.Set("interface", "wlan0"); apdConfig.Set("driver", "nl80211"); apdConfig.Set("country_code", settings.countryCode_); @@ -553,6 +555,8 @@ void UninstallP2p() wifiDirectConfigSettings.Load(); wifiDirectConfigSettings.enable_ = false; wifiDirectConfigSettings.Save(); + sysExec(SYSTEMCTL_BIN " restart NetworkManager"); // bring up wlan0 wifi. + } } diff --git a/todo.txt b/todo.txt index fcf7c67..b68f42a 100644 --- a/todo.txt +++ b/todo.txt @@ -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.