From 542b7428e243d31d5248d2691b992288fde2bf8c Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 21 Aug 2024 13:39:46 -0400 Subject: [PATCH 1/6] Restart Wi-Fi after disabling Wi-Fi Direct --- src/SetWifiConfig.cpp | 4 ++++ 1 file changed, 4 insertions(+) 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. + } } From 4513e3ab3ee125ce08c04267865abf511f8ebceb Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 21 Aug 2024 18:07:30 -0400 Subject: [PATCH 2/6] v1.0.40 versioning. --- CMakeLists.txt | 4 ++-- README.md | 4 ++-- docs/Installing.md | 6 ++--- docs/ReleaseNotes.md | 56 +++++++++++++++++++++++++++++++++++++++++++- docs/download.md | 6 ++--- docs/index.md | 4 ++-- 6 files changed, 67 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 10021d3..3ecf7f1 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..f12ffe4 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..b79e1a8 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..9ec3376 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,9 +1,63 @@ # Release Notes +## PiPedal 1.2.41 +Version 1.2 is officially released. + +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) +- 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 modal has a gain control input. +- 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 +- Minor documentation 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..d922684 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..55878d4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1.2.40 +v1,2,41   @@ -9,7 +9,7 @@ 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. From 060d02a2f888306e38be89f24bc9635f7bcb8d95 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 21 Aug 2024 18:32:49 -0400 Subject: [PATCH 3/6] v1.2.41 version strings. --- CMakeLists.txt | 4 ++-- README.md | 4 ++-- docs/Installing.md | 6 +++--- docs/ReleaseNotes.md | 4 ++-- docs/download.md | 6 +++--- docs/index.md | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ecf7f1..8796e44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16.0) project(pipedal - VERSION 1,2,41 + VERSION 1.2.41 DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) -set (DISPLAY_VERSION "v1,2,41") +set (DISPLAY_VERSION "v1.2.41") set (CMAKE_INSTALL_PREFIX "/usr/") diff --git a/README.md b/README.md index f12ffe4..d7583be 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ -Download: v1,2,41 +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,41 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 b79e1a8..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,41](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,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. +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,41_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 9ec3376..d5ac4d4 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -33,7 +33,7 @@ Big fixes: - 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 modal has a gain control input. +- 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 @@ -44,7 +44,7 @@ Big fixes: - 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 -- Minor documentation corrections. With help from @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). diff --git a/docs/download.md b/docs/download.md index d922684..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,41 +- Raspberry Pi OS Bookworm (64-bit) v1.2.41 - Ubuntu 21.04 or Raspberry Pi OS bullseyeyeye (64-bit) v1.1.31 -v1,2,41 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,41_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 55878d4..75a4825 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1,2,41 +v1.2.41   @@ -9,7 +9,7 @@ To download PiPedal, click [here](download.md). To view PiPedal documentation, click [here](Documentation.md). -> NEW version 1,2,41 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. From 4a31015cc51a0383b660c11064e34e6a9a78cde3 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 21 Aug 2024 21:04:59 -0400 Subject: [PATCH 4/6] Allow .zip bundle uploads for all File plugin controls. --- docs/ReleaseNotes.md | 5 +- react/src/FilePropertyDialog.tsx | 8 +- react/src/Lv2Plugin.tsx | 598 ++++++++++++++----------------- todo.txt | 2 - 4 files changed, 282 insertions(+), 331 deletions(-) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index d5ac4d4..9faabce 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -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. 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/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. From d0322ef79dd7cda054ac4e8879cd63aef5bc3301 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 21 Aug 2024 21:10:58 -0400 Subject: [PATCH 5/6] Release --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7583be..736934a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](htt   -#### 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. +#### 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/index.md b/docs/index.md index 75a4825..7706bb2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,7 @@ To download PiPedal, click [here](download.md). To view PiPedal documentation, click [here](Documentation.md). -> NEW version 1.2.41 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. From 0bf3a54cc6c3a792a0610f95091d62f12974c34f Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 21 Aug 2024 21:13:35 -0400 Subject: [PATCH 6/6] Release announcement in bold instead of italic. --- docs/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 7706bb2..7a77c70 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,8 +9,9 @@ To download PiPedal, click [here](download.md). To view PiPedal documentation, click [here](Documentation.md). -> NEW version 1.2.41 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.