Dark Mode, Toob Neural Amp Modeler

This commit is contained in:
Robin Davies
2023-07-03 07:02:59 -04:00
parent 28215eb1d5
commit 15ae8ec049
65 changed files with 1169 additions and 223 deletions
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.16.0)
project(pipedal project(pipedal
VERSION 1.1.27 VERSION 1.1.28
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
HOMEPAGE_URL "https://rerdavies.github.io/pipedal" HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
) )
set (DISPLAY_VERSION "v1.1.27") set (DISPLAY_VERSION "v1.1.28")
set (CMAKE_INSTALL_PREFIX "/usr/") set (CMAKE_INSTALL_PREFIX "/usr/")
+2 -2
View File
@@ -1,12 +1,12 @@
<img src='docs/GithubBanner.png' width="100%" /><br/> <img src='docs/GithubBanner.png' width="100%" /><br/>
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.1.27</a> Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.1.28</a>
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
> NEW version 1.1.27 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. > NEW version 1.1.28 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. 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 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats. PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
+1 -1
View File
@@ -9,6 +9,6 @@ Package: pipedal
Pre-Depends: hostapd;authbind;dnsmasq Pre-Depends: hostapd;authbind;dnsmasq
Priority: optional Priority: optional
Section: sound Section: sound
Version: 1.1.27 Version: 1.1.28
Installed-Size: 15147 Installed-Size: 15147
+2 -2
View File
@@ -13,14 +13,14 @@ page_icon: img/Install4.jpg
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- [Ubuntu/Raspberry Pi OS (64-bit) v1.1.27](https://github.com/rerdavies/pipedal/releases/download/v1.1.27/pipedal_1.1.27_arm64.deb) - [Ubuntu/Raspberry Pi OS (64-bit) v1.1.28](https://github.com/rerdavies/pipedal/releases/download/v1.1.28/pipedal_1.1.28_arm64.deb)
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install ./pipedal_1.1.27_arm64.deb sudo apt-get install ./pipedal_1.1.28_arm64.deb
``` ```
On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager. On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager.
+13
View File
@@ -1,5 +1,18 @@
# Release Notes # Release Notes
## PiPedal 1.1.28
New in this release.
- TooB Neural Amp Modeler - an LV2 port of Steven Atkinson's astounding Neural Amp Modeler. Donwload model files from [ToneHunt.org](https://tonehunt.org). CPU is very high -- it runs on a Raspberry Pi 4 with just enough CPU left over for a couple of extra effects; but the results are worth it. TooB ML provides Neural Net modelled guitar amps with more modest CPU use (but considerably less flexibility).
- Dark mode. Go to the settings dialog to turn on Dark Mode.
Bug fixes:
- Plugin information is updated in the web app after reconnecting, in order to pick up new plugins that may have been detected while the web server was being restarted.
## PiPedal 1.1.27 ## PiPedal 1.1.27
- Add missing lv2-dev dependency. - Add missing lv2-dev dependency.
+2 -2
View File
@@ -4,14 +4,14 @@
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.1.27/pipedal_1.1.27_arm64.deb) v1.1.27 - [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.1.28/pipedal_1.1.28_arm64.deb) v1.1.28
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install ./pipedal_1.1.27_arm64.deb sudo apt-get install ./pipedal_1.1.28_arm64.deb
``` ```
Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation.
+2 -2
View File
@@ -1,13 +1,13 @@
<img src="GithubBanner.png" width="100%"/> <img src="GithubBanner.png" width="100%"/>
<a href="Installing.html"><i>v1.1.27</i></a> <a href="Installing.html"><i>v1.1.28</i></a>
&nbsp; &nbsp;
To download PiPedal, click [here](download.md). To download PiPedal, click [here](download.md).
> NEW version 1.1.27 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. > NEW version 1.1.28 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. Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
+1 -1
View File
@@ -53,7 +53,7 @@
rdfs:comment "TooB amplifier cabinet simulator." ; rdfs:comment "TooB amplifier cabinet simulator." ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "Cab Simulator"; mod:label "TooB CabSim";
lv2:requiredFeature urid:map ; lv2:requiredFeature urid:map ;
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
patch:readable patch:readable
@@ -152,7 +152,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "Convolution Reverb"; mod:label "TooB CReverb";
lv2:requiredFeature urid:map; lv2:requiredFeature urid:map;
lv2:optionalFeature state::freePath, state:makePath, state:mapPath, work:schedule ; lv2:optionalFeature state::freePath, state:makePath, state:mapPath, work:schedule ;
lv2:extensionData state:interface; lv2:extensionData state:interface;
@@ -152,7 +152,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "Convolution Reverb (Stereo)"; mod:label "TooB CReverb Stereo";
lv2:requiredFeature urid:map; lv2:requiredFeature urid:map;
lv2:optionalFeature state::freePath, state:makePath, state:mapPath, work:schedule ; lv2:optionalFeature state::freePath, state:makePath, state:mapPath, work:schedule ;
lv2:extensionData state:interface; lv2:extensionData state:interface;
+1 -1
View File
@@ -62,7 +62,7 @@ inputStage:filterGroup
lv2:microVersion 16 ; lv2:microVersion 16 ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "Input Stage"; mod:label "TooB Input";
lv2:requiredFeature urid:map ; lv2:requiredFeature urid:map ;
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
+1 -1
View File
@@ -1 +1 @@
ToobAmp.so.1.0.16 ToobAmp.so.1.0.17
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -46,7 +46,7 @@ Emulation of a Boss CE-2 Chorus.
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "CE-2 Chorus"; mod:label "TooB CE-2";
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
lv2:port lv2:port
+1 -1
View File
@@ -46,7 +46,7 @@ A straighforward no-frills digital delay.
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "Delay"; mod:label "TooB Delay";
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
lv2:port lv2:port
+1 -1
View File
@@ -49,7 +49,7 @@ Emulation of a Boss BF-2 Flanger*.
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "BF-2 Flanger"; mod:label "TooB BF-2";
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
lv2:port lv2:port
@@ -52,7 +52,7 @@ should use the monophonic version of this effect.
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "BF-2 Stereo Flanger"; mod:label "TooB BF-2 Stereo";
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
lv2:port lv2:port
+1 -1
View File
@@ -48,7 +48,7 @@ The core implementation is taken from the The Synthesis Toolkit in C++ (STK), ht
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "Freeverb"; mod:label "TooB Freeverb";
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
lv2:port lv2:port
+2 -2
View File
@@ -40,7 +40,7 @@ toobml:filterGroup
<http://two-play.com/plugins/toob-ml> <http://two-play.com/plugins/toob-ml>
a lv2:Plugin , a lv2:Plugin ,
lv2:SimulatorPlugin ; lv2:AmplifierPlugin ;
doap:name "TooB ML Amplifier" , doap:name "TooB ML Amplifier" ,
"TooB ML Amplifier"@en-gb-gb "TooB ML Amplifier"@en-gb-gb
; ;
@@ -63,7 +63,7 @@ and uses model files from from the GuitarML Neural Pi project (https://github.co
""" ; """ ;
mod:brand "TooB"; mod:brand "TooB";
mod:label "ML Amplifier"; mod:label "TooB ML";
lv2:requiredFeature urid:map, work:schedule ; lv2:requiredFeature urid:map, work:schedule ;
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
lv2:extensionData state:interface, work:interface; lv2:extensionData state:interface, work:interface;
@@ -0,0 +1,310 @@
@prefix doap: <http://usefulinc.com/ns/doap#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix epp: <http://lv2plug.in/ns/ext/port-props#> .
@prefix uiext: <http://lv2plug.in/ns/extensions/ui#> .
@prefix idpy: <http://harrisonconsoles.com/lv2/inlinedisplay#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix mod: <http://moddevices.com/ns/mod#> .
@prefix param: <http://lv2plug.in/ns/ext/parameters#> .
@prefix work: <http://lv2plug.in/ns/ext/worker#> .
@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .
@prefix pipedal_ui: <http://github.com/rerdavies/pipedal/ui#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix state: <http://lv2plug.in/ns/ext/state#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix toobNam: <http://two-play.com/plugins/toob-nam#> .
<http://two-play.com/rerdavies#me>
a foaf:Person ;
foaf:name "Robin Davies" ;
foaf:mbox <mailto:rerdavies@gmail.com> ;
foaf:homepage <https://github.com/sponsors/rerdavies> .
toobNam:modelFile
a lv2:Parameter;
rdfs:label "Model";
rdfs:range atom:Path.
toobNam:eqGroup
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tone" ;
lv2:symbol "eqGroup" .
<http://two-play.com/plugins/toob-nam>
a lv2:Plugin ,
lv2:AmplifierPlugin ;
doap:name "TooB Neural Amp Modeler" ,
"TooB Neural Amp Modeler"@en-gb-gb
;
doap:license <https://two-play.com/TooB/licenses/isc> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 16 ;
rdfs:comment """
A port of Steven Atkinson's Neural Amp Modeler to LV2.
TooB Neural Amp Modeler uses uplodable .nam model files. Download .nam files from http://tonehunt.org, and then upload them to TooB Neural Amp Modeler.
https://tonehunt.org provides a huge selection of downloadable amp model files.
TooB Neural Amp Modeler supports a much wider range of amp models than ToobML, but usually uses much more CPU.
You will need at least a Pi 4 to use Toob Neural Amp Modeler. If you are having trouble with CPU usage, tonehunt.org
does contain some smaller amp models. Search for the "feather" tag to find models that use less CPU.
If you are interested in building your own amp models, please visit https://www.neuralampmodeler.com/
TooB Neural Amp Modeler uses code from the NeuralAmp Modeler Core project. The TooB Team wishes to express gratitude to Steven Atkinson for
making this extraordinary technology available as open-source code.
Code from the the NeuralAmpModelerCore project (https://github.com/sdatkinson/NeuralAmpModelerCore) is provided under the following license.
MIT License
Copyright (c) 2023 Steven Atkinson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
""" ;
mod:brand "TooB";
mod:label "TooB NAM";
lv2:optionalFeature lv2:hardRTCapable;
patch:readable
toobNam:modelFile;
patch:writable
toobNam:modelFile;
lv2:extensionData state:interface,
work:interface;
lv2:port
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 0;
lv2:symbol "inputGain" ;
lv2:name "Input Gain";
lv2:default 0.0 ;
lv2:minimum -20.0;
lv2:maximum 20.0;
units:unit units:db;
rdfs:comment "Input gain";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 1;
lv2:symbol "outputGain" ;
lv2:name "Output Gain";
lv2:default 0.0 ;
lv2:minimum -40.0;
lv2:maximum 40.0;
units:unit units:db;
rdfs:comment "Output gain";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 2;
lv2:symbol "gate" ;
lv2:name "Noise Gate";
lv2:default -80.0 ;
lv2:minimum -100.0;
lv2:maximum 0.0;
rdfs:comment "Noise gate threshold. Set to minimum to disable.";
units:unit units:db;
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value -100.0
];
],
[
a lv2:OutputPort ,
lv2:ControlPort ;
lv2:index 3;
lv2:symbol "gateOut" ;
lv2:name "\u00A0";
lv2:default 0.0;
lv2:minimum 0.0;
lv2:maximum 1.0;
rdfs:comment "Gate Status";
lv2:portProperty lv2:toggled;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 4;
lv2:symbol "bass" ;
lv2:name "Bass";
lv2:default 5.0;
lv2:minimum 0.0;
lv2:maximum 10.0;
rdfs:comment "Bass";
pg:group toobNam:eqGroup ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 5;
lv2:symbol "mid" ;
lv2:name "Mid";
lv2:default 5.0;
lv2:minimum 0.0;
lv2:maximum 10.0;
rdfs:comment "Mid";
pg:group toobNam:eqGroup ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 6;
lv2:symbol "treble" ;
lv2:name "Treble";
lv2:default 5.0;
lv2:minimum 0.0;
lv2:maximum 10.0;
rdfs:comment "Bass";
pg:group toobNam:eqGroup ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 7 ;
lv2:symbol "toneStack" ;
lv2:name "Type";
lv2:default 0.0 ;
lv2:minimum 2.0 ;
lv2:maximum 3.0;
lv2:portProperty lv2:enumeration ;
lv2:scalePoint [
rdfs:label "Bassman" ;
rdf:value 0.0
] , [
rdfs:label "JCM8000" ;
rdf:value 1.0
], [
rdfs:label "Baxandall" ;
rdf:value 2.0
],[
rdfs:label "Bypass" ;
rdf:value 3.0
];
pg:group toobNam:eqGroup ;
],
[
a lv2:AudioPort ,
lv2:InputPort ;
lv2:index 8 ;
lv2:symbol "in" ;
lv2:name "In"
],
[
a lv2:AudioPort ,
lv2:OutputPort ;
lv2:index 9 ;
lv2:symbol "out" ;
lv2:name "Out"
],
[
a atom:AtomPort ,
lv2:InputPort;
atom:bufferType atom:Sequence ;
atom:supports patch:Message;
lv2:designation lv2:control ;
atom:supports patch:Message ;
lv2:index 10 ;
lv2:symbol "control" ;
lv2:name "Control" ;
rdfs:comment "Control" ;
] , [
a atom:AtomPort ,
lv2:OutputPort ;
atom:bufferType atom:Sequence ;
atom:supports patch:Message;
lv2:designation lv2:control ;
lv2:index 11;
lv2:symbol "notify" ;
lv2:name "Notify" ;
rdfs:comment "Notification" ;
]
.
<http://two-play.com/plugins/toob-nam> pipedal_ui:ui toobNam:ui .
toobNam:ui
a pipedal_ui:ui ;
pipedal_ui:fileProperties
[
a pipedal_ui:fileProperty;
rdfs:label "Model (*.nam)" ;
pipedal_ui:directory "NeuralAmpModels";
lv2:index 8 ;
pipedal_ui:patchProperty toobNam:modelFile ;
pipedal_ui:fileTypes
[
a pipedal_ui:fileType;
rdfs:label ".nam file";
pipedal_ui:fileExtension ".nam";
pipedal_ui:mimeType "application/octet-stream";
];
];
pipedal_ui:frequencyPlot
[
pipedal_ui:patchProperty toobNam:FrequencyResponse;
lv2:index 7 ;
pg:group toobNam:eqGroup ;
pipedal_ui:width: 60;
]
.
+4
View File
@@ -12,6 +12,10 @@
lv2:binary <ToobAmp.so> ; lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ConvolutionReverb.ttl> . rdfs:seeAlso <ConvolutionReverb.ttl> .
<http://two-play.com/plugins/toob-nam> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToobNeuralAmpModeler.ttl> .
<http://two-play.com/plugins/toob-convolution-reverb-stereo> a lv2:Plugin ; <http://two-play.com/plugins/toob-convolution-reverb-stereo> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ; lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ConvolutionReverbStereo.ttl> . rdfs:seeAlso <ConvolutionReverbStereo.ttl> .
+5 -10
View File
@@ -21,6 +21,7 @@ add_custom_command(
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
DEPENDS DEPENDS
src/SelectThemeDialog.tsx
src/OkCancelDialog.tsx src/OkCancelDialog.tsx
src/PluginControl.tsx src/PluginControl.tsx
src/reportWebVitals.ts src/reportWebVitals.ts
@@ -133,9 +134,9 @@ add_custom_command(
public/img/fx_distortion.svg public/img/fx_distortion.svg
public/img/Pi-Logo-3.png public/img/Pi-Logo-3.png
public/img/fx_oscillator.svg public/img/fx_oscillator.svg
public/img/save_bank_as_white.svg src/svg/ic_save_bank_as.svg
public/img/edit_banks_white.svg src/svg/ic_edit_banks.svg
public/img/settings_black_24dp.svg src/svg/ic_settings.svg
public/img/fx_filter.svg public/img/fx_filter.svg
public/img/delete_outline_black_24dp.svg public/img/delete_outline_black_24dp.svg
public/img/fx_function.svg public/img/fx_function.svg
@@ -150,7 +151,7 @@ add_custom_command(
public/img/cc-by.png public/img/cc-by.png
public/img/fx_split_a.svg public/img/fx_split_a.svg
public/img/fx_utility.svg public/img/fx_utility.svg
public/img/help_outline_white_24dp.svg src/svg/ic_help_outline.svg
public/img/ic_navigate_before.svg public/img/ic_navigate_before.svg
public/img/ic_drawer_2.svg public/img/ic_drawer_2.svg
public/img/fx_parametric_eq.svg public/img/fx_parametric_eq.svg
@@ -161,10 +162,8 @@ add_custom_command(
public/img/fx_analyzer.svg public/img/fx_analyzer.svg
public/img/fx_delay.svg public/img/fx_delay.svg
public/img/fx_spectral.svg public/img/fx_spectral.svg
public/img/edit_banks.svg
public/img/fx_chorus.svg public/img/fx_chorus.svg
public/img/fx_simulator.svg public/img/fx_simulator.svg
public/img/drive_file_rename_outline_black_24dp.svg
public/img/fx_mixer.svg public/img/fx_mixer.svg
public/img/fx_eq.svg public/img/fx_eq.svg
public/img/fx_modulator.svg public/img/fx_modulator.svg
@@ -173,7 +172,6 @@ add_custom_command(
public/img/fx_phaser.svg public/img/fx_phaser.svg
public/img/ic_drawer.svg public/img/ic_drawer.svg
public/img/fx_amplifier.svg public/img/fx_amplifier.svg
public/img/save_bank_as.svg
public/img/fx_lr.svg public/img/fx_lr.svg
public/img/fx_instrument.svg public/img/fx_instrument.svg
public/img/Pi-Logo-3.svg public/img/Pi-Logo-3.svg
@@ -183,14 +181,11 @@ add_custom_command(
public/img/fx_empty.svg public/img/fx_empty.svg
public/img/fx_dial.svg public/img/fx_dial.svg
public/img/ic_logo.svg public/img/ic_logo.svg
public/img/help_outline_black_24dp.svg
public/img/fx_flanger2.svg public/img/fx_flanger2.svg
public/img/old_delete_outline_white_24dp.svg public/img/old_delete_outline_white_24dp.svg
public/img/fx_split_b.svg public/img/fx_split_b.svg
public/img/fx_spatial.svg public/img/fx_spatial.svg
public/img/fx_converter.svg public/img/fx_converter.svg
public/img/settings_white_24dp.svg
public/img/drive_file_rename_outline_white_24dp.svg
public/img/vst.svg public/img/vst.svg
public/img/vst.png public/img/vst.png
public/sample_lv2_plugins.json public/sample_lv2_plugins.json
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><g><rect fill="none" height="24" width="24"/></g><g><g><polygon points="15,16 11,20 21,20 21,16"/><path d="M12.06,7.19L3,16.25V20h3.75l9.06-9.06L12.06,7.19z M5.92,18H5v-0.92l7.06-7.06l0.92,0.92L5.92,18z"/><path d="M18.71,8.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C16.17,4.09,15.92,4,15.66,4c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L18.71,8.04z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 503 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><g><rect fill="none" height="24" width="24"/></g><g><g><polygon points="15,16 11,20 21,20 21,16"/><path d="M12.06,7.19L3,16.25V20h3.75l9.06-9.06L12.06,7.19z M5.92,18H5v-0.92l7.06-7.06l0.92,0.92L5.92,18z"/><path d="M18.71,8.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C16.17,4.09,15.92,4,15.66,4c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L18.71,8.04z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 503 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#FFFFFF"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/></svg>

Before

Width:  |  Height:  |  Size: 402 B

-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve" fill="#FFFFFF">
<path d="M16,1H4C2.9,1,2,1.9,2,3v14h2V3h12V1z"/>
<path d="M20.993,10.993L20.99,7c0-1.1-0.891-2-1.99-2h-4h-3H8C6.9,5,6.01,5.9,6.01,7l-0.003,3.993L6,11v10c0,1.1,0.891,2,1.99,2H8
h11h0.01c1.1,0,1.99-0.9,1.99-2V11L20.993,10.993z M19,12v9H8v-9V7h5h1h5V12z"/>
<rect x="10" y="9" width="2" height="2"/>
<rect x="14" y="9" width="3" height="2"/>
<rect x="10" y="13" width="2" height="2"/>
<rect x="14" y="13" width="3" height="2"/>
<rect x="10" y="17" width="2" height="2"/>
<rect x="14" y="17" width="3" height="2"/>
</svg>

Before

Width:  |  Height:  |  Size: 1012 B

+38 -24
View File
@@ -1,26 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="utf-8" /> <head>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="theme-color" content="#000000" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta <meta name="theme-color" content="#000000" />
name="description" <meta name="description" content="PiPedal Guitar Pedals" />
content="PiPedal Guitar Pedals" <!--
/>
<!--
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
--> -->
<link rel="stylesheet" href="/css/roboto.css" /> <link rel="stylesheet" href="/css/roboto.css" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML. Only files inside the `public` folder can be referenced from the HTML.
@@ -29,14 +27,30 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>PiPedal</title> <title>PiPedal</title>
<style> <style>
BODY { background: #D0D0D0; } BODY {
@media (prefers-color-scheme: dark) { background: #D0D0D0;
BODY { background: #333; } }
} </style>
</style> <style id="bgStyle">
BODY {
background: #333;
}
</style>
<script>
const darkMode = localStorage.getItem("darkMode"); if (darkMode) { }
if (darkMode)
{
let bgStyle = document.getElementById("bgStyle");
if (bgStyle)
{
// disable the style block.
bgStyle.setAttribute('media',"max-width: 1px");
}
}
</script>
</head> </head>
<body > <body >
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
@@ -52,4 +66,4 @@
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
</body> </body>
</html> </html>
+10 -5
View File
@@ -25,10 +25,12 @@ import isDarkMode from './DarkMode';
declare module '@mui/material/styles' { declare module '@mui/material/styles' {
interface Theme { interface Theme {
mainBackground: string; mainBackground: React.CSSProperties['color'];
toolbarColor: React.CSSProperties['color'];
} }
interface ThemeOptions { interface ThemeOptions {
mainBackground?: string; mainBackground?: React.CSSProperties['color'];
toolbarColor?: React.CSSProperties['color'];
} }
} }
@@ -50,13 +52,14 @@ const theme = createTheme(
palette: { palette: {
mode: 'dark', mode: 'dark',
primary: { primary: {
main: "#6750A4" // #5B5690 #60529A #5C5694 main: '#A770E4'// #6750A4" // #5B5690 #60529A #5C5694
}, },
secondary: { secondary: {
main: "#FF6060" main: "#FF6060"
}, },
}, },
mainBackground: "#222" mainBackground: "#222",
toolbarColor: '#FFFFFF'
} }
: :
{ {
@@ -69,7 +72,9 @@ const theme = createTheme(
} }
}, },
mainBackground: "#FFFFFF" mainBackground: "#FFFFFF",
toolbarColor: '#FFFFFF'
} }
); );
-5
View File
@@ -16,8 +16,3 @@ div {
min-width: 0; min-width: 0;
} }
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
}
}
+37 -29
View File
@@ -62,14 +62,27 @@ import JackStatusView from './JackStatusView';
import { Theme } from '@mui/material/styles'; import { Theme } from '@mui/material/styles';
import isDarkMode from './DarkMode'; import isDarkMode from './DarkMode';
import {ReactComponent as RenameOutlineIcon} from './svg/drive_file_rename_outline_black_24dp.svg';
import {ReactComponent as SaveBankAsIcon} from './svg/ic_save_bank_as.svg';
import {ReactComponent as EditBanksIcon} from './svg/ic_edit_banks.svg';
import {ReactComponent as SettingsIcon} from './svg/ic_settings.svg';
import {ReactComponent as HelpOutlineIcon} from './svg/ic_help_outline.svg';
const appStyles = (theme: Theme) => createStyles({ const appStyles = (theme: Theme) => createStyles({
menuIcon: { "&": { // :root
fill: "green" colorScheme: (isDarkMode()? "dark": "light")
}, },
appBar: { menuListItem: {
color: "#FE8!important" as any, //theme.palette.text.primary,
fill: "#FE8!important" as any, //theme.palette.text.primary,
},
menuIcon: {
fill: (theme.palette.text.primary + "!important") as any, //theme.palette.text.primary,
opacity: 0.6
},
toolBar: {
color: "white"
}, },
listSubheader: { listSubheader: {
backgroundImage: "linear-gradient(255,255,255,0.15),rgba(255,255,255,0.15)" backgroundImage: "linear-gradient(255,255,255,0.15),rgba(255,255,255,0.15)"
@@ -499,7 +512,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
private unmountListener(e: Event) { private unmountListener(e: Event) {
e.preventDefault(); e.preventDefault();
if (this.model_.state.get() === State.Ready && !this.model_.isAndroidHosted()) { if ((!this.model_.reloadRequested) && this.model_.state.get() === State.Ready && !this.model_.isAndroidHosted()) {
(e as any).returnValue = "Are you sure you want to leave this page?"; (e as any).returnValue = "Are you sure you want to leave this page?";
return "Are you sure you want to leave this page?"; return "Are you sure you want to leave this page?";
} }
@@ -652,6 +665,7 @@ render() {
return ( return (
<div style={{ <div style={{
colorScheme: isDarkMode() ? "dark": "light", // affects scrollbar color
minHeight: 345, minWidth: 390, minHeight: 345, minWidth: 390,
position: "absolute", width: "100%", height: "100%", background: "#F88", userSelect: "none", position: "absolute", width: "100%", height: "100%", background: "#F88", userSelect: "none",
display: "flex", flexDirection: "column", flexWrap: "nowrap", display: "flex", flexDirection: "column", flexWrap: "nowrap",
@@ -666,14 +680,15 @@ render() {
<CssBaseline /> <CssBaseline />
{(!this.state.tinyToolBar) ? {(!this.state.tinyToolBar) ?
( (
<AppBar className="appBar" position="absolute" > <AppBar position="absolute" >
<Toolbar variant="dense" > <Toolbar variant="dense" className={classes.toolBar} >
<IconButton <IconButton
edge="start" edge="start"
aria-label="menu" aria-label="menu"
color="inherit"
onClick={() => { this.showDrawer() }} onClick={() => { this.showDrawer() }}
size="large"> size="large">
<MenuButton /> <MenuButton style={{opacity: 0.75}} />
</IconButton> </IconButton>
<div style={{ flex: "0 1 400px", minWidth: 100 }}> <div style={{ flex: "0 1 400px", minWidth: 100 }}>
<PresetSelector /> <PresetSelector />
@@ -683,11 +698,12 @@ render() {
<IconButton <IconButton
aria-label="menu" aria-label="menu"
onClick={() => { this.toggleFullScreen(); }} onClick={() => { this.toggleFullScreen(); }}
color="inherit"
size="large"> size="large">
{this.state.isFullScreen ? ( {this.state.isFullScreen ? (
<FullscreenExitIcon /> <FullscreenExitIcon style={{opacity: 0.75}} />
) : ( ) : (
<FullscreenIcon /> <FullscreenIcon style={{opacity: 0.75}} />
)} )}
@@ -701,6 +717,7 @@ render() {
style={{ position: "absolute", left: 12, top: 8, zIndex: 2 }} style={{ position: "absolute", left: 12, top: 8, zIndex: 2 }}
aria-label="menu" aria-label="menu"
onClick={() => { this.showDrawer() }} onClick={() => { this.showDrawer() }}
color="inherit"
size="large"> size="large">
<MenuButton /> <MenuButton />
</IconButton> </IconButton>
@@ -708,6 +725,7 @@ render() {
<IconButton <IconButton
style={{ position: "absolute", right: 8, top: 8, zIndex: 2 }} style={{ position: "absolute", right: 8, top: 8, zIndex: 2 }}
aria-label="menu" aria-label="menu"
color="inherit"
onClick={() => { this.toggleFullScreen(); }} onClick={() => { this.toggleFullScreen(); }}
size="large"> size="large">
{this.state.isFullScreen ? ( {this.state.isFullScreen ? (
@@ -756,26 +774,20 @@ render() {
<Divider /> <Divider />
<List> <List>
<ListItem button key='RenameBank' onClick={() => { this.handleDrawerRenameBank() }}> <ListItem button key='RenameBank' onClick={() => { this.handleDrawerRenameBank() }}>
<ListItemIcon> <ListItemIcon >
<img className='menuIcon' <RenameOutlineIcon color='inherit' className={classes.menuIcon} />
src={isDarkMode()? "img/drive_file_rename_outline_white_24dp.svg" :"img/drive_file_rename_outline_black_24dp.svg"}
alt="" style={{ opacity: 0.6 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Rename Bank' /> <ListItemText primary='Rename Bank' />
</ListItem> </ListItem>
<ListItem button key='SaveBank' onClick={() => { this.handleDrawerSaveBankAs() }} > <ListItem button key='SaveBank' onClick={() => { this.handleDrawerSaveBankAs() }} >
<ListItemIcon> <ListItemIcon>
<img className='menuIcon' <SaveBankAsIcon color="inherit" className={classes.menuIcon}/>
src={isDarkMode()? "img/save_bank_as_white.svg" :"img/save_bank_as.svg"}
alt="" style={{ opacity: 0.6 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Save As New Bank' /> <ListItemText primary='Save As New Bank' />
</ListItem> </ListItem>
<ListItem button key='CreateBank' onClick={() => { this.handleDrawerManageBanks(); }}> <ListItem button key='EditBanks' onClick={() => { this.handleDrawerManageBanks(); }}>
<ListItemIcon> <ListItemIcon>
<img className='menuIcon' <EditBanksIcon color="inherit" className={classes.menuIcon}/>
src={isDarkMode()? "img/edit_banks_white.svg" :"img/edit_banks.svg"}
alt="" style={{ opacity: 0.6 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Manage Banks...' /> <ListItemText primary='Manage Banks...' />
</ListItem> </ListItem>
@@ -784,23 +796,19 @@ render() {
<List> <List>
<ListItem button key='Settings' onClick={() => { this.handleDrawerSettingsClick() }}> <ListItem button key='Settings' onClick={() => { this.handleDrawerSettingsClick() }}>
<ListItemIcon> <ListItemIcon>
<img className='menuIcon' <SettingsIcon color="inherit" className={classes.menuIcon}/>
src={isDarkMode()? "img/settings_white_24dp.svg" :"img/settings_black_24dp.svg"}
alt="" style={{ opacity: 0.6 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Settings' /> <ListItemText primary='Settings' />
</ListItem> </ListItem>
<ListItem button key='About' onClick={() => { this.handleDrawerAboutClick() }}> <ListItem button key='About' onClick={() => { this.handleDrawerAboutClick() }}>
<ListItemIcon> <ListItemIcon>
<img className='menuIcon' <HelpOutlineIcon color="inherit" className={classes.menuIcon}/>
src= {isDarkMode() ? "img/help_outline_white_24dp.svg": "img/help_outline_black_24dp.svg"}
alt="" style={{ opacity: 0.6 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='About' /> <ListItemText primary='About' />
</ListItem> </ListItem>
<ListItem button key='Donations' onClick={() => { this.handleDrawerDonationClick() }}> <ListItem button key='Donations' onClick={() => { this.handleDrawerDonationClick() }}>
<ListItemIcon> <ListItemIcon >
<VolunteerActivismIcon style={{ opacity: 0.6 }}/> <VolunteerActivismIcon className={classes.menuIcon} color="inherit" />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Donations' /> <ListItemText primary='Donations' />
</ListItem> </ListItem>
+6 -4
View File
@@ -19,8 +19,10 @@
export default function isDarkMode(): boolean { export default function isDarkMode(): boolean {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { let value = localStorage.getItem("darkMode");
return true; return value === "true";
} }
return false;
export function setDarkMode(value: boolean): void {
localStorage.setItem("darkMode",value? "true": "false");
} }
+1 -1
View File
@@ -602,7 +602,7 @@ export const LoadPluginDialog =
<SelectHoverBackground selected={value.uri === this.state.selected_uri} showHover={true} /> <SelectHoverBackground selected={value.uri === this.state.selected_uri} showHover={true} />
<div className={classes.content}> <div className={classes.content}>
<div className={classes.iconBorder} > <div className={classes.iconBorder} >
<PluginIcon pluginType={value.plugin_type} size={24} /> <PluginIcon pluginType={value.plugin_type} size={24} opacity={0.6} />
</div> </div>
<div className={classes.content2}> <div className={classes.content2}>
<div className={classes.label} style={{ display: "flex", flexFlow: "row nowrap", alignItems: "center" }} > <div className={classes.label} style={{ display: "flex", flexFlow: "row nowrap", alignItems: "center" }} >
+65 -2
View File
@@ -204,6 +204,42 @@ export class UiPropertyNotification {
plugin: string = ""; plugin: string = "";
protocol: string = ""; protocol: string = "";
};
export class UiFrequencyPlot {
deserialize(input: any): UiFrequencyPlot
{
this.patchProperty = input.patchProperty;
this.index = input.index;
this.portGroup = input.portGroup;
this.xLeft = input.xLeft;
this.xRight = input.xRight;
this.xLog = input.xLog;
this.yTop = input.yTop;
this.yBottom = input.yBottom;
this.width = input.width;
return this;
}
static deserialize_array(input: any): UiFrequencyPlot[]
{
let result: UiFrequencyPlot[] = [];
for (let i = 0; i < input.length; ++i)
{
result[i] = new UiFrequencyPlot().deserialize(input[i]);
}
return result;
}
patchProperty: string = "";
index: number = -1;
portGroup: string = "";
xLeft: number = -1;
xRight: number = -1;
xLog: boolean = true;
yTop: number = -1;
yBottom: number = -1;
width: number = -1;
}; };
export class UiFileProperty { export class UiFileProperty {
deserialize(input: any): UiFileProperty deserialize(input: any): UiFileProperty
@@ -253,6 +289,10 @@ export class UiFileProperty {
{ {
return true; return true;
} }
if (fileType.fileExtension === "*" || fileType.fileExtension === "")
{
return true;
}
} }
return false; return false;
} }
@@ -270,6 +310,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
{ {
this.uri = input.uri; this.uri = input.uri;
this.name = input.name; this.name = input.name;
this.brand = input.name? input.name: "";
this.label = input.label? input.label: this.name;
this.plugin_class = input.plugin_class; this.plugin_class = input.plugin_class;
this.supported_features = input.supported_features; this.supported_features = input.supported_features;
this.required_features = input.required_features; this.required_features = input.required_features;
@@ -285,6 +327,13 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
} else { } else {
this.fileProperties = []; this.fileProperties = [];
} }
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); this.uiPortNotifications = UiPropertyNotification.deserialize_array(input.uiPortNotifications);
@@ -297,6 +346,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
uri: string = ""; uri: string = "";
name: string = ""; name: string = "";
brand: string = "";
label: string = "";
plugin_class: string = ""; plugin_class: string = "";
supported_features: string[] = Lv2Plugin.EmptyFeatures; supported_features: string[] = Lv2Plugin.EmptyFeatures;
required_features: string[] = Lv2Plugin.EmptyFeatures; required_features: string[] = Lv2Plugin.EmptyFeatures;
@@ -306,7 +357,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
comment: string = ""; comment: string = "";
ports: Port[] = Port.EmptyPorts; ports: Port[] = Port.EmptyPorts;
port_groups: PortGroup[] = []; port_groups: PortGroup[] = [];
fileProperties: UiFileProperty[] = []; fileProperties: UiFileProperty[] = [];
frequencyPlots: UiFrequencyPlot[] = [];
uiPortNotifications: UiPropertyNotification[] = []; uiPortNotifications: UiPropertyNotification[] = [];
} }
@@ -668,6 +720,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
{ {
this.uri = input.uri; this.uri = input.uri;
this.name = input.name; this.name = input.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_type = input.plugin_type as PluginType;
this.plugin_display_type = input.plugin_display_type; this.plugin_display_type = input.plugin_display_type;
this.author_name = input.author_name; this.author_name = input.author_name;
@@ -685,6 +739,12 @@ export class UiPlugin implements Deserializable<UiPlugin> {
} else { } else {
this.fileProperties = []; this.fileProperties = [];
} }
if (input.frequencyPlots)
{
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
} else {
this.frequencyPlots = [];
}
this.is_vst3 = input.is_vst3; this.is_vst3 = input.is_vst3;
return this; return this;
@@ -738,6 +798,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
uri: string = ""; uri: string = "";
name: string = ""; name: string = "";
brand: string = "";
label: string = "";
plugin_type: PluginType = PluginType.InvalidPlugin; plugin_type: PluginType = PluginType.InvalidPlugin;
plugin_display_type: string = ""; plugin_display_type: string = "";
author_name: string = ""; author_name: string = "";
@@ -749,7 +811,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
description: string = ""; description: string = "";
controls: UiControl[] = []; controls: UiControl[] = [];
port_groups: PortGroup[] = []; port_groups: PortGroup[] = [];
fileProperties: UiFileProperty[] = []; fileProperties: UiFileProperty[] = [];
frequencyPlots: UiFrequencyPlot[] = [];
is_vst3 : boolean = false; is_vst3 : boolean = false;
} }
+4 -3
View File
@@ -47,7 +47,7 @@ import MidiBindingsDialog from './MidiBindingsDialog';
import PluginPresetSelector from './PluginPresetSelector'; import PluginPresetSelector from './PluginPresetSelector';
import {ReactComponent as OldDeleteIcon} from "./svg/old_delete_outline_24dp.svg"; import {ReactComponent as OldDeleteIcon} from "./svg/old_delete_outline_24dp.svg";
import {ReactComponent as MidiIcon} from "./svg/ic_midi.svg"; import {ReactComponent as MidiIcon} from "./svg/ic_midi.svg";
import isDarkMode from './DarkMode';
const SPLIT_CONTROLBAR_THRESHHOLD = 650; const SPLIT_CONTROLBAR_THRESHHOLD = 650;
@@ -463,7 +463,7 @@ export const MainPage =
</div> </div>
<div style={{ flex: "0 0 auto", display: (canInsert || canAppend) ? "block" : "none", paddingRight: 8 }}> <div style={{ flex: "0 0 auto", display: (canInsert || canAppend) ? "block" : "none", paddingRight: 8 }}>
<IconButton onClick={(e) => { this.onAddClick(e) }} size="large"> <IconButton onClick={(e) => { this.onAddClick(e) }} size="large">
<AddIcon style={{opacity: 0.6}} /> <AddIcon style={{height: 24, width: 24,fill: this.props.theme.palette.text.primary, opacity: 0.6}} />
</IconButton> </IconButton>
<Menu <Menu
id="add-menu" id="add-menu"
@@ -495,7 +495,8 @@ export const MainPage =
onClick={this.onLoadClick} onClick={this.onLoadClick}
disabled={this.state.selectedPedal === -1 || (!canLoad) || (this.getSelectedPedalboardItem()?.isSplit() ?? true)} disabled={this.state.selectedPedal === -1 || (!canLoad) || (this.getSelectedPedalboardItem()?.isSplit() ?? true)}
startIcon={<InputIcon />} startIcon={<InputIcon />}
style={{ textTransform: "none" }} style={{ textTransform: "none",
background: (isDarkMode() ? "#6750A4": undefined) }}
> >
Load Load
</Button> </Button>
+3 -3
View File
@@ -298,7 +298,7 @@ class PedalLayout {
if (uiPlugin != null) { if (uiPlugin != null) {
this.pluginType = uiPlugin.plugin_type; this.pluginType = uiPlugin.plugin_type;
this.iconUrl = SelectIconUri(uiPlugin.plugin_type); this.iconUrl = SelectIconUri(uiPlugin.plugin_type);
this.name = uiPlugin.name; this.name = uiPlugin.label;
this.numberOfInputs = Math.max(uiPlugin.audio_inputs,2); this.numberOfInputs = Math.max(uiPlugin.audio_inputs,2);
this.numberOfOutputs = Math.max(uiPlugin.audio_outputs,2); this.numberOfOutputs = Math.max(uiPlugin.audio_outputs,2);
} else { } else {
@@ -679,7 +679,7 @@ const PedalboardView =
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
if (!Utility.isTouchDevice()) { if (!Utility.needsZoomedControls()) {
if (this.props.onDoubleClick && instanceId) { if (this.props.onDoubleClick && instanceId) {
this.props.onDoubleClick(instanceId); this.props.onDoubleClick(instanceId);
} }
@@ -1014,7 +1014,7 @@ const PedalboardView =
}}> }}>
<Typography variant="caption" display="block" noWrap={true} <Typography variant="caption" display="block" noWrap={true}
style={{ width: CELL_WIDTH - 4, textAlign: "center", flex: "0 1 auto" }} style={{ width: CELL_WIDTH - 4, textAlign: "center", flex: "0 1 auto" }}
>{item.pedalItem?.pluginName}</Typography> >{item.name}</Typography>
</div> </div>
) )
result.push(<div key={this.renderKey++} className={classes.pedalItem} style={{ left: item.bounds.x, top: item.bounds.y }} > result.push(<div key={this.renderKey++} className={classes.pedalItem} style={{ left: item.bounds.x, top: item.bounds.y }} >
+38 -3
View File
@@ -38,7 +38,12 @@ import GovernorSettings from './GovernorSettings';
import WifiChannel from './WifiChannel'; import WifiChannel from './WifiChannel';
import AlsaDeviceInfo from './AlsaDeviceInfo'; import AlsaDeviceInfo from './AlsaDeviceInfo';
import { AndroidHostInterface, FakeAndroidHost } from './AndroidHost'; import { AndroidHostInterface, FakeAndroidHost } from './AndroidHost';
import isDarkMode, {setDarkMode} from './DarkMode';
export enum ColorTheme {
Light,
Dark
};
export enum State { export enum State {
Loading, Loading,
@@ -470,8 +475,11 @@ export class PiPedalModel //implements PiPedalModel
let value = body as number; let value = body as number;
this._setInputVolume(value,false); this._setInputVolume(value,false);
} else if (message === "onLv2StateChanged") { } else if (message === "onLv2StateChanged") {
let instanceId = body as number;
this.onLv2StateChanged(instanceId); let instanceId = body.instanceId as number;
let state = body.state as [boolean,any];
this.onLv2StateChanged(instanceId,state);
} else if (message === "onVst3ControlChanged") { } else if (message === "onVst3ControlChanged") {
let controlChangedBody = body as Vst3ControlChangedBody; let controlChangedBody = body as Vst3ControlChangedBody;
this._setVst3PedalboardControlValue( this._setVst3PedalboardControlValue(
@@ -665,6 +673,10 @@ export class PiPedalModel //implements PiPedalModel
this.getWebSocket().request<number>("hello") this.getWebSocket().request<number>("hello")
.then(clientId => { .then(clientId => {
this.clientId = clientId; this.clientId = clientId;
return this.getWebSocket().request<any>("plugins");
})
.then(data => {
this.ui_plugins.set(UiPlugin.deserialize_array(data));
return this.getWebSocket().request<Pedalboard>("currentPedalboard"); return this.getWebSocket().request<Pedalboard>("currentPedalboard");
}) })
.then(data => { .then(data => {
@@ -1116,7 +1128,9 @@ export class PiPedalModel //implements PiPedalModel
} }
} }
private onLv2StateChanged(instanceId: number): void { private onLv2StateChanged(instanceId: number, state: [boolean,any]): void {
let item = this.pedalboard.get().getItem(instanceId);
item.lv2State = state;
for (let item of this.stateChangedListeners) { for (let item of this.stateChangedListeners) {
if (item.instanceId === instanceId) { if (item.instanceId === instanceId) {
item.onStateChanged(instanceId); item.onStateChanged(instanceId);
@@ -2531,6 +2545,27 @@ export class PiPedalModel //implements PiPedalModel
return nullCast(this.webSocket).request<number>("newPreset"); return nullCast(this.webSocket).request<number>("newPreset");
} }
getTheme(): ColorTheme {
return isDarkMode() ? ColorTheme.Dark: ColorTheme.Light;
}
setTheme(value: ColorTheme) {
if (this.getTheme() !== value)
{
setDarkMode(value === ColorTheme.Dark);
this.reloadPage();
}
}
reloadRequested: boolean = false;
reloadPage() {
this.reloadRequested = true;
// eslint-disable-next-line no-restricted-globals
location.reload();
}
}; };
let instance: PiPedalModel | undefined = undefined; let instance: PiPedalModel | undefined = undefined;
+3 -3
View File
@@ -137,7 +137,7 @@ const PluginControl =
this.onInputKeyPress = this.onInputKeyPress.bind(this); this.onInputKeyPress = this.onInputKeyPress.bind(this);
} }
isTouchDevice(): boolean { isTouchDevice(): boolean {
return Utility.isTouchDevice(); return Utility.needsZoomedControls();
} }
showZoomedControl() showZoomedControl()
@@ -547,7 +547,7 @@ const PluginControl =
); );
} else { } else {
return ( return (
<Select variant="standard" <Select variant="standard"
ref={this.selectRef} ref={this.selectRef}
value={control.clampSelectValue(value)} value={control.clampSelectValue(value)}
onChange={this.onSelectChanged} onChange={this.onSelectChanged}
@@ -556,7 +556,7 @@ const PluginControl =
id: 'id' + control.symbol, id: 'id' + control.symbol,
style: { fontSize: FONT_SIZE } style: { fontSize: FONT_SIZE }
}} }}
style={{ marginLeft: 4, marginRight: 4, width: 140 }} style={{ marginLeft: 4, marginRight: 4, width: 140,fontSize: 14 }}
> >
{control.scale_points.map((scale_point: ScalePoint) => ( {control.scale_points.map((scale_point: ScalePoint) => (
<MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem> <MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem>
+52 -1
View File
@@ -23,7 +23,7 @@ import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles'; import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { UiPlugin, UiControl, UiFileProperty, ScalePoint } from './Lv2Plugin'; import { UiPlugin, UiControl, UiFileProperty,UiFrequencyPlot, ScalePoint } from './Lv2Plugin';
import { import {
Pedalboard, PedalboardItem, ControlValue Pedalboard, PedalboardItem, ControlValue
} from './Pedalboard'; } from './Pedalboard';
@@ -39,6 +39,7 @@ import FilePropertyDialog from './FilePropertyDialog';
import JsonAtom from './JsonAtom'; import JsonAtom from './JsonAtom';
import PluginOutputControl from './PluginOutputControl'; import PluginOutputControl from './PluginOutputControl';
import Units from './Units'; import Units from './Units';
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
export const StandardItemSize = { width: 80, height: 110 }; export const StandardItemSize = { width: 80, height: 110 };
@@ -335,6 +336,14 @@ const PluginControlView =
/> />
)); ));
} }
makeFrequencyPlotUI(frequencyPlot: UiFrequencyPlot): ReactNode {
return ((
<ToobFrequencyResponseView instanceId={this.props.instanceId}
propertyName={frequencyPlot.patchProperty}
width={frequencyPlot.width}
/>
));
}
makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode { makeStandardControl(uiControl: UiControl, controlValues: ControlValue[]): ReactNode {
let symbol = uiControl.symbol; let symbol = uiControl.symbol;
if (!uiControl.is_input) { if (!uiControl.is_input) {
@@ -445,6 +454,48 @@ const PluginControlView =
); );
} }
} }
for (let i = 0; i < plugin.frequencyPlots.length; ++i) {
let frequencyPlot = plugin.frequencyPlots[i];
let frequencyPlotUi = this.makeFrequencyPlotUI(frequencyPlot);
if (frequencyPlot.portGroup !== "" && plugin.getPortGroupByUri(frequencyPlot.portGroup)) {
let portGroup = nullCast(plugin.getPortGroupByUri(frequencyPlot.portGroup));
let controlGroup = portGroupMap[portGroup.symbol];
if (controlGroup) {
let insertPosition = controlGroup.indexes.length;
if (frequencyPlot.index !== -1) {
for (let i = 0; i < controlGroup.controls.length; ++i) {
if (controlGroup.indexes[i] >= frequencyPlot.index) {
insertPosition = i;
break;
}
}
}
let index = frequencyPlot.index !== -1 ? frequencyPlot.index : 100;
controlGroup.controls.splice(insertPosition, 0, frequencyPlotUi);
controlGroup.indexes.splice(insertPosition, 0, index);
} else {
let index = frequencyPlot.index !== -1 ? frequencyPlot.index : 100;
let controlGroup = new ControlGroup(
portGroup.name,
[index],
[frequencyPlotUi]);
result.push(
controlGroup
);
portGroupMap[portGroup.symbol] = controlGroup;
}
} else if (frequencyPlot.index !== -1) {
result.splice(frequencyPlot.index, 0, frequencyPlotUi);
} else {
result.push(
frequencyPlotUi
);
}
}
return result; return result;
} }
+5 -1
View File
@@ -54,6 +54,10 @@ const styles = (theme: Theme) =>
top: theme.spacing(1), top: theme.spacing(1),
color: theme.palette.grey[500], color: theme.palette.grey[500],
}, },
icon: {
fill: theme.palette.text.primary,
opacity: 0.6
}
}); });
}; };
export interface PluginInfoDialogTitleProps extends WithStyles<typeof styles> { export interface PluginInfoDialogTitleProps extends WithStyles<typeof styles> {
@@ -228,7 +232,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
style={{ display: (props.plugin_uri !== "") ? "inline-flex" : "none" }} style={{ display: (props.plugin_uri !== "") ? "inline-flex" : "none" }}
onClick={handleClickOpen} onClick={handleClickOpen}
size="large"> size="large">
<InfoOutlinedIcon style={{opacity: 0.6}} /> <InfoOutlinedIcon className={classes.icon} color='inherit' />
</IconButton> </IconButton>
{open && ( {open && (
<Dialog onClose={handleClose} open={open} fullWidth > <Dialog onClose={handleClose} open={open} fullWidth >
+41
View File
@@ -25,6 +25,7 @@ import withStyles from '@mui/styles/withStyles';
import { UiControl } from './Lv2Plugin'; import { UiControl } from './Lv2Plugin';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, MonitorPortHandle,State } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, MonitorPortHandle,State } from './PiPedalModel';
import isDarkMode from './DarkMode';
@@ -77,11 +78,13 @@ const PluginOutputControl =
private model: PiPedalModel; private model: PiPedalModel;
private vuRef: React.RefObject<HTMLDivElement>; private vuRef: React.RefObject<HTMLDivElement>;
private lampRef: React.RefObject<HTMLDivElement>;
constructor(props: PluginOutputControlProps) { constructor(props: PluginOutputControlProps) {
super(props); super(props);
this.vuRef = React.createRef<HTMLDivElement>(); this.vuRef = React.createRef<HTMLDivElement>();
this.lampRef = React.createRef<HTMLDivElement>();
this.state = { this.state = {
hasValue: false, hasValue: false,
value: 0 value: 0
@@ -130,6 +133,12 @@ const PluginOutputControl =
private animationHandle: number | undefined = undefined; private animationHandle: number | undefined = undefined;
private updateValue(value: number) { private updateValue(value: number) {
if (this.lampRef.current)
{
let control = this.props.uiControl;
let range = (value-control.min_value)/(control.max_value-control.min_value);
this.lampRef.current.style.opacity = range +"";
}
if (this.vuRef.current) { if (this.vuRef.current) {
let control = this.props.uiControl; let control = this.props.uiControl;
let range = (value-control.min_value)/(control.max_value-control.min_value); let range = (value-control.min_value)/(control.max_value-control.min_value);
@@ -241,6 +250,38 @@ const PluginOutputControl =
</div > </div >
); );
} else if (control.toggled_property && control.scale_points.length === 0) {
item_width = undefined;
let attachedLamp = control.name === "" || control.name === "\u00A0" ;
return (
<div style={{ display: "flex", flexDirection: "column", width: item_width,
marginTop: 8, marginBottom: 8, marginRight: 8,marginLeft: (attachedLamp? 0: 8), height: 98
}}>
{/* TITLE SECTION */}
<div style={{ flex: "0 0 auto", width: "100%", marginBottom: 8, marginLeft: 0, marginRight: 0 }}>
<Typography variant="caption" display="block" style={{
width: "100%",
textAlign: "center"
}}> {control.name === "" ? "\u00A0": control.name}</Typography>
</div>
{/* CONTROL SECTION */}
<div style={{ flex: "1 1 auto", display: "flex", justifyContent: "left", alignItems: "start", flexFlow: "row nowrap" }}>
<div style={{ width: 12, height: 12, background: isDarkMode()? "#111" : "#444", borderRadius: 5, position: "relative" }}>
<div ref={this.lampRef} style={{ width: 8, height: 8,
background: (isDarkMode()? "radial-gradient(circle at center, #F00 0, #F00 20%, #333 100%)"
: "radial-gradient(circle at center, #F44 0, #F44 40%, #644 100%)"),
opacity: 0, borderRadius: 3,margin: 2,position: "absolute" }} />
</div>
</div>
{/* LABEL/EDIT SECTION*, strictly a placeholder for visual alignment purposes.*/}
<div style={{ flex: "0 0 auto", position: "relative", width: 30, height: 27 }}>
&nbsp;
</div>
</div >
);
} else { } else {
return ( return (
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}> <div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
+9 -8
View File
@@ -58,7 +58,7 @@ interface PresetSelectorState {
} }
const selectColor = isDarkMode()? "#888": "black"; const selectColor = isDarkMode()? "#888": "#FFFFFF";
const styles = (theme: Theme) => createStyles({ const styles = (theme: Theme) => createStyles({
select: { // fu fu fu.Overrides for white selector on dark background. select: { // fu fu fu.Overrides for white selector on dark background.
@@ -301,17 +301,17 @@ const PresetSelector =
}}> }}>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
<IconButton <IconButton
style={{ flex: "0 0 auto", opacity: this.state.presets.presetChanged ? 1.0 : 0.0 }} style={{ flex: "0 0 auto", opacity: this.state.presets.presetChanged ? 1.0 : 0.0, color: "#FFFFFF" }}
onClick={(e) => { this.handleSave(); }} onClick={(e) => { this.handleSave(); }}
size="large"> size="large">
<SaveIconOutline style={{ opacity: 0.75 }} /> <SaveIconOutline style={{ opacity: 0.75 }} color="inherit" />
</IconButton> </IconButton>
</div> </div>
<div style={{ flex: "1 1 auto", minWidth: 60, maxWidth: 300, position: "relative", paddingRight: 12 }} > <div style={{ flex: "1 1 auto", minWidth: 60, maxWidth: 300, position: "relative", paddingRight: 12 }} >
<Select variant="standard" <Select variant="standard"
className={classes.select} className={classes.select}
style={{ width: "100%", position: "relative", top: 0 }} disabled={!this.state.enabled} style={{ width: "100%", position: "relative", top: 0, color: "#FFFFFF" }} disabled={!this.state.enabled}
onChange={(e, extra) => this.handleChange(e, extra)} onChange={(e, extra) => this.handleChange(e, extra)}
onClose={(e) => this.handleSelectClose(e)} onClose={(e) => this.handleSelectClose(e)}
displayEmpty displayEmpty
@@ -336,12 +336,13 @@ const PresetSelector =
} }
</Select> </Select>
</div> </div>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto"}}>
<IconButton <IconButton
style={{ flex: "0 0 auto" }} style={{ flex: "0 0 auto", color: "#FFFFFF" }}
onClick={(e) => this.handlePresetMenuClick(e)} onClick={(e) => this.handlePresetMenuClick(e)}
size="large"> size="large"
<MoreVertIcon style={{ opacity: 0.75 }} /> >
<MoreVertIcon style={{ opacity: 0.75 }} color="inherit" />
</IconButton> </IconButton>
<Menu <Menu
id="edit-presets-menu" id="edit-presets-menu"
+85
View File
@@ -0,0 +1,85 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// Copyright (c) 2023 Robin Davies
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { useState } from 'react';
import Button from '@mui/material/Button';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import Dialog from '@mui/material/Dialog';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormControl from '@mui/material/FormControl';
import RadioGroup from '@mui/material/RadioGroup';
import Radio from '@mui/material/Radio';
import {ColorTheme} from './PiPedalModel';
export interface SelectThemesDialogProps {
open: boolean;
defaultTheme: ColorTheme;
onClose: () => void;
onOk: (value: ColorTheme) => void;
}
function SelectThemesDialog(props: SelectThemesDialogProps) {
//const classes = useStyles();
const { onClose, defaultTheme, open,onOk } = props;
const [ selectedTheme, setSelectedTheme ] = useState(defaultTheme);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
let value = ((event.target as HTMLInputElement).value) === '0' ? ColorTheme.Light: ColorTheme.Dark;
setSelectedTheme(value);
};
const handleClose = (): void => {
onClose();
};
const handleOk = (): void => {
onOk(selectedTheme)
};
return (
<Dialog onClose={handleClose} open={open}>
<DialogTitle id="simple-dialog-title">Theme</DialogTitle>
<DialogContent>
<FormControl>
<RadioGroup
defaultValue={defaultTheme}
onChange={handleChange}
>
<FormControlLabel value={ColorTheme.Light} control={<Radio size='small' />} label="Light" />
<FormControlLabel value={ColorTheme.Dark} control={<Radio size='small' />} label="Dark" />
</RadioGroup>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleOk} color="secondary" >
OK
</Button>
</DialogActions>
</Dialog>
);
}
export default SelectThemesDialog;
+67 -26
View File
@@ -23,7 +23,7 @@ import OkCancelDialog from './OkCancelDialog';
import ListSelectDialog from './ListSelectDialog'; import ListSelectDialog from './ListSelectDialog';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, State, ColorTheme } from './PiPedalModel';
import ButtonBase from "@mui/material/ButtonBase"; import ButtonBase from "@mui/material/ButtonBase";
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
@@ -45,6 +45,7 @@ import DialogEx from './DialogEx'
import GovernorSettings from './GovernorSettings'; import GovernorSettings from './GovernorSettings';
import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo'; import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo';
import SystemMidiBindingsDialog from './SystemMidiBindingsDialog'; import SystemMidiBindingsDialog from './SystemMidiBindingsDialog';
import SelectThemeDialog from './SelectThemeDialog';
import Slide, { SlideProps } from '@mui/material/Slide'; import Slide, { SlideProps } from '@mui/material/Slide';
import { createStyles, Theme } from '@mui/material/styles'; import { createStyles, Theme } from '@mui/material/styles';
@@ -79,6 +80,7 @@ interface SettingsDialogState {
showInputSelectDialog: boolean; showInputSelectDialog: boolean;
showOutputSelectDialog: boolean; showOutputSelectDialog: boolean;
showMidiSelectDialog: boolean; showMidiSelectDialog: boolean;
showThemeSelectDialog: boolean;
showJackServerSettingsDialog: boolean; showJackServerSettingsDialog: boolean;
shuttingDown: boolean; shuttingDown: boolean;
restarting: boolean; restarting: boolean;
@@ -184,6 +186,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
showInputSelectDialog: false, showInputSelectDialog: false,
showOutputSelectDialog: false, showOutputSelectDialog: false,
showMidiSelectDialog: false, showMidiSelectDialog: false,
showThemeSelectDialog: false,
showJackServerSettingsDialog: false, showJackServerSettingsDialog: false,
shuttingDown: false, shuttingDown: false,
restarting: false, restarting: false,
@@ -384,6 +387,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
showMidiSelectDialog: true showMidiSelectDialog: true
}) })
} }
handleThemeSelection() {
this.setState({
showThemeSelectDialog: true
});
}
handleMidiMessageSettings() { handleMidiMessageSettings() {
this.setState({ this.setState({
showSystemMidiBindingsDialog: true showSystemMidiBindingsDialog: true
@@ -553,22 +561,22 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
}} }}
> >
<div > <div >
{this.props.onboarding && {this.props.onboarding &&
( (
<div> <div>
<Typography display="block" variant="body1" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}> <Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
Select and configure an audio device. You may optionally configure MIDI inputs, and set up a Wi-Fi Direct Hotspot now as well. Select and configure an audio device. You may optionally configure MIDI inputs, and set up a Wi-Fi Direct Hotspot now as well.
</Typography> </Typography>
<Typography display="block" variant="body1" color="textSecondary" style={{paddingLeft: 24,paddingBottom: 8 }}> <Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
Access and modify these settings later by selecting the <i>Settings</i> menu item on the main menu. Access and modify these settings later by selecting the <i>Settings</i> menu item on the main menu.
</Typography> </Typography>
<Divider /> <Divider />
</div> </div>
)} )}
<div> <div>
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary"> <Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
STATUS STATUS
</Typography> </Typography>
{(!isConfigValid) ? {(!isConfigValid) ?
( (
@@ -582,7 +590,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
( (
<div className={classes.cpuStatusColor} style={{ paddingLeft: 48, position: "relative", top: -12 }}> <div className={classes.cpuStatusColor} style={{ paddingLeft: 48, position: "relative", top: -12 }}>
{JackHostStatus.getDisplayView("", this.state.jackStatus)} {JackHostStatus.getDisplayView("", this.state.jackStatus)}
{ (!this.props.onboarding) && JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)} {(!this.props.onboarding) && JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
</div> </div>
) )
} }
@@ -657,7 +665,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<SelectHoverBackground selected={false} showHover={true} /> <SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>System MIDI Bindings</Typography> <Typography className={classes.primaryItem} display="block" variant="body2" noWrap>System MIDI Bindings</Typography>
</div> </div>
</ButtonBase> </ButtonBase>
@@ -713,7 +721,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
</div> </div>
</ButtonBase> </ButtonBase>
</div> </div>
{ (!this.props.onboarding) ? ( {(!this.props.onboarding) ? (
<div > <div >
<Divider /> <Divider />
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography> <Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
@@ -735,7 +743,23 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<ButtonBase <ButtonBase
className={classes.setting} className={classes.setting}
onClick={() => { this.setState({ showStatusMonitorDialog: true }); }} > onClick={() => { this.handleThemeSelection(); }} >
<SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}>
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
Color Theme</Typography>
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>
{ this.model.getTheme() === ColorTheme.Dark ? "Dark" :"Light"}
</Typography>
</div>
</ButtonBase>
<ButtonBase
className={classes.setting}
onClick={() => {
this.model.setShowStatusMonitor(!this.state.showStatusMonitor)
}} >
<SelectHoverBackground selected={false} showHover={true} /> <SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<div style={{ <div style={{
@@ -746,6 +770,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap> <Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
Show status monitor on main screen.</Typography> Show status monitor on main screen.</Typography>
</div> </div>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
<Switch <Switch
checked={this.state.showStatusMonitor} checked={this.state.showStatusMonitor}
@@ -787,16 +812,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
</div > </div >
</ButtonBase> </ButtonBase>
</div> </div>
): ( ) : (
<div> <div>
<Divider/> <Divider />
<div style={{display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16,marginRight: 16, <div style={{
marginTop: 16,marginBottom: 16}}> display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16, marginRight: 16,
<Button variant="outlined" onClick={()=> {this.onOnboardingContinue()}} disabled={this.state.continueDisabled} style={{width: 120}}>Continue</Button> marginTop: 16, marginBottom: 16
}}>
<Button variant="outlined" onClick={() => { this.onOnboardingContinue() }} disabled={this.state.continueDisabled} style={{ width: 120 }}>Continue</Button>
</div> </div>
</div> </div>
) )
} }
@@ -849,6 +876,20 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
) )
} }
{
(this.state.showThemeSelectDialog) &&
(
<SelectThemeDialog open={this.state.showThemeSelectDialog}
onClose={()=> { this.setState({showThemeSelectDialog: false});} }
onOk={(selectedTheme: ColorTheme) => {
this.model.setTheme(selectedTheme);
this.setState({showThemeSelectDialog: false});
}}
defaultTheme={this.model.getTheme()}
/>
)
}
<WifiConfigDialog wifiConfigSettings={this.state.wifiConfigSettings} open={this.state.showWifiConfigDialog} <WifiConfigDialog wifiConfigSettings={this.state.wifiConfigSettings} open={this.state.showWifiConfigDialog}
onClose={() => this.setState({ showWifiConfigDialog: false })} onClose={() => this.setState({ showWifiConfigDialog: false })}
onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)} onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)}
@@ -869,8 +910,8 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
/> />
<SystemMidiBindingsDialog <SystemMidiBindingsDialog
open={this.state.showSystemMidiBindingsDialog} open={this.state.showSystemMidiBindingsDialog}
onClose={()=> { this.setState({showSystemMidiBindingsDialog: false});}} onClose={() => { this.setState({ showSystemMidiBindingsDialog: false }); }}
/> />
</DialogEx > </DialogEx >
); );
+58 -15
View File
@@ -25,11 +25,11 @@ import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import { PiPedalModelFactory, PiPedalModel, State } from "./PiPedalModel"; import { PiPedalModelFactory, PiPedalModel, State } from "./PiPedalModel";
import { StandardItemSize } from './PluginControlView';
import Utility from './Utility'; import Utility from './Utility';
import SvgPathBuilder from './SvgPathBuilder'; import SvgPathBuilder from './SvgPathBuilder';
const StandardItemSize = { width: 80, height: 110 };
const FREQUENCY_RESPONSE_VECTOR_URI = "http://two-play.com/plugins/toob#frequencyResponseVector"; const FREQUENCY_RESPONSE_VECTOR_URI = "http://two-play.com/plugins/toob#frequencyResponseVector";
@@ -47,13 +47,15 @@ const styles = (theme: Theme) => createStyles({
interface ToobFrequencyResponseProps extends WithStyles<typeof styles> { interface ToobFrequencyResponseProps extends WithStyles<typeof styles> {
instanceId: number; instanceId: number;
maxDb?: number; propertyName?: string;
minDb?: number; width?: number;
minFrequency?: number;
maxFrequency?: number;
} }
interface ToobFrequencyResponseState { interface ToobFrequencyResponseState {
minDb: number;
maxDb: number;
minF: number;
maxF: number;
path: string; path: string;
} }
@@ -70,7 +72,11 @@ const ToobFrequencyResponseView =
super(props); super(props);
this.model = PiPedalModelFactory.getInstance(); this.model = PiPedalModelFactory.getInstance();
this.state = { this.state = {
path: "" path: "",
minDb: -30,
maxDb: 5,
minF: 30,
maxF: 20000
}; };
this.pathRef = React.createRef(); this.pathRef = React.createRef();
@@ -146,24 +152,61 @@ const ToobFrequencyResponseView =
onFrequencyResponseUpdated(data: number[]) { onFrequencyResponseUpdated(data: number[]) {
if (!this.mounted) return; if (!this.mounted) return;
let pathBuilder = new SvgPathBuilder(); let pathBuilder = new SvgPathBuilder();
let minF = data[0];
let maxF = data[1];
let dbMin = data[2];
let dbMax = data[3];
let logMin = Math.log(minF);
let logMax = Math.log(maxF);
let toX_ = (frequency: number): number => {
var logV = Math.log(frequency);
return (this.xMax - this.xMin) * (logV - logMin) / (logMax - logMin) + this.xMin;
};
let toY_ = (value: number): number => {
var db;
if (value < this.MIN_DB_AF) {
db = -192.0;
} else {
db = 20 * Math.log10(value);
}
var y = (db - dbMin) / (dbMax - dbMin) * (this.yMax - this.yMin) + this.yMin;
return y;
};
if (data.length > 2) { if (data.length > 2) {
pathBuilder.moveTo(this.toX(data[0]), this.toY(data[1])) pathBuilder.moveTo(toX_(data[4]), toY_(data[5]))
for (let i = 2; i < data.length; i += 2) { for (let i = 6; i < data.length; i += 2) {
pathBuilder.lineTo(this.toX(data[i]), this.toY(data[i + 1])); pathBuilder.lineTo(toX_(data[i]), toY_(data[i + 1]));
} }
} }
this.currentPath = pathBuilder.toString(); this.currentPath = pathBuilder.toString();
this.setState({ path: this.currentPath }); this.setState({
minF: data[0],
maxF: data[1],
maxDb: data[2],
minDb: data[3],
path: this.currentPath
});
} }
private getPropertyUri()
{
return this.props.propertyName? this.props.propertyName: FREQUENCY_RESPONSE_VECTOR_URI;
}
updateAllWaveShapes() { updateAllWaveShapes() {
if (this.requestOutstanding) { // throttling. if (this.requestOutstanding) { // throttling.
this.requestDeferred = true; this.requestDeferred = true;
return; return;
} }
this.requestOutstanding = true; this.requestOutstanding = true;
this.model.getPatchProperty<any>(this.props.instanceId, FREQUENCY_RESPONSE_VECTOR_URI) this.model.getPatchProperty<any>(this.props.instanceId, this.getPropertyUri())
.then((json) => { .then((json) => {
if (json && json.otype_ === "Vector" && json.vtype_ === "Float") { if (json && json.otype_ === "Vector" && json.vtype_ === "Float") {
this.onFrequencyResponseUpdated(json.value as number[]); this.onFrequencyResponseUpdated(json.value as number[]);
@@ -237,11 +280,11 @@ const ToobFrequencyResponseView =
render() { render() {
// deliberately reversed to flip up and down. // deliberately reversed to flip up and down.
this.dbMax = this.props.minDb ?? this.dbMinDefault; this.dbMax = this.state.minDb;
this.dbMin = this.props.maxDb ?? this.dbMaxDefault; this.dbMin = this.state.maxDb;
this.fMin = this.props.minFrequency ?? 30; this.fMin = this.state.minF;
this.fMax = this.props.maxFrequency ?? 20000; this.fMax = this.state.maxF;
this.logMin = Math.log(this.fMin); this.logMin = Math.log(this.fMin);
this.logMax = Math.log(this.fMax); this.logMax = Math.log(this.fMax);
+1 -1
View File
@@ -109,7 +109,7 @@ const ToobMLView =
{ {
let group = controls[4] as ControlGroup; let group = controls[4] as ControlGroup;
group.controls.splice(0,0, group.controls.splice(0,0,
( <ToobFrequencyResponseView instanceId={this.props.instanceId} minDb={-20} maxDb={20} />) ( <ToobFrequencyResponseView instanceId={this.props.instanceId} />)
); );
let gainControl: React.ReactElement = controls[2] as React.ReactElement; let gainControl: React.ReactElement = controls[2] as React.ReactElement;
+1 -1
View File
@@ -92,7 +92,7 @@ const ToobToneStackView =
{ {
controls.splice(0,0, controls.splice(0,0,
( <ToobFrequencyResponseView instanceId={this.props.instanceId} ( <ToobFrequencyResponseView instanceId={this.props.instanceId}
minDb={-20} maxDb={20} />) />)
); );
} else { } else {
controls.splice(0,0, controls.splice(0,0,
+1 -1
View File
@@ -206,7 +206,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
upload.abortController = new AbortController(); upload.abortController = new AbortController();
if (!this.wantsFile(this.uploadList[i].file)) if (!this.wantsFile(this.uploadList[i].file))
{ {
throw new Error("Invalid file type."); throw new Error("Invalid file extension.");
} }
let filename = await this.model.uploadFile(this.props.uploadPage, this.uploadList[i].file, "application/octet-stream", upload.abortController); let filename = await this.model.uploadFile(this.props.uploadPage, this.uploadList[i].file, "application/octet-stream", upload.abortController);
this.props.onUploaded(filename); this.props.onUploaded(filename);
+2 -2
View File
@@ -41,11 +41,11 @@ const Utility = class {
static isLandscape(): boolean { static isLandscape(): boolean {
return window.innerWidth > window.innerHeight; return window.innerWidth > window.innerHeight;
} }
static isTouchDevice(): boolean { static needsZoomedControls(): boolean {
if (!this.isLandscape()) return false; if (!this.isLandscape()) return false;
if (window.innerHeight > 500) return false; if (window.innerHeight > 500) return false;
if (window.innerHeight > 300) return true;
return (('ontouchstart' in window) && return (('ontouchstart' in window) &&
((navigator.maxTouchPoints??0) > 0) ); ((navigator.maxTouchPoints??0) > 0) );
} }
+24 -18
View File
@@ -22,6 +22,7 @@ import { WithStyles } from '@mui/styles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import createStyles from '@mui/styles/createStyles'; import createStyles from '@mui/styles/createStyles';
import { PiPedalModel, PiPedalModelFactory, ZoomedControlInfo } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, ZoomedControlInfo } from './PiPedalModel';
import {ReactComponent as DialIcon} from './svg/fx_dial.svg';
const SELECTED_OPACITY = 0.8; const SELECTED_OPACITY = 0.8;
const DEFAULT_OPACITY = 0.6; const DEFAULT_OPACITY = 0.6;
@@ -34,6 +35,12 @@ const DEAD_ZONE_SIZE = 5;
const styles = (theme: Theme) => createStyles({ const styles = (theme: Theme) => createStyles({
dialIcon: {
overscrollBehavior: "none", touchAction: "none",
fill: theme.palette.text.primary,
opacity: DEFAULT_OPACITY,
}
}); });
@@ -56,7 +63,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
class extends React.Component<ZoomedDialProps, ZoomedDialState> { class extends React.Component<ZoomedDialProps, ZoomedDialState> {
model: PiPedalModel = PiPedalModelFactory.getInstance(); model: PiPedalModel = PiPedalModelFactory.getInstance();
imgRef: React.RefObject<HTMLImageElement> = React.createRef(); imgRef: React.RefObject<SVGSVGElement> = React.createRef();
constructor(props: ZoomedDialProps) { constructor(props: ZoomedDialProps) {
super(props); super(props);
@@ -75,7 +82,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
onPointerUp(e: PointerEvent<HTMLImageElement>) { onPointerUp(e: PointerEvent<SVGSVGElement>) {
if (this.isCapturedPointer(e)) { if (this.isCapturedPointer(e)) {
--this.pointersDown; --this.pointersDown;
@@ -94,7 +101,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
releaseCapture(e: PointerEvent<HTMLImageElement>) releaseCapture(e: PointerEvent<SVGSVGElement>)
{ {
let img = this.imgRef.current; let img = this.imgRef.current;
@@ -118,7 +125,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
onPointerLostCapture(e: PointerEvent<HTMLImageElement>) { onPointerLostCapture(e: PointerEvent<SVGSVGElement>) {
if (this.isCapturedPointer(e)) { if (this.isCapturedPointer(e)) {
--this.pointersDown; --this.pointersDown;
@@ -128,10 +135,10 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
onTouchStart(e: TouchEvent<HTMLImageElement>) { onTouchStart(e: TouchEvent<SVGSVGElement>) {
//must be defined to get onTouchMove //must be defined to get onTouchMove
} }
onTouchMove(e: TouchEvent<HTMLImageElement>) { onTouchMove(e: TouchEvent<SVGSVGElement>) {
// e.preventDefault(); // e.preventDefault();
e.stopPropagation(); // cancels scroll!!! e.stopPropagation(); // cancels scroll!!!
@@ -150,7 +157,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
currentAngle: number = 0; currentAngle: number = 0;
lastPointerAngle: number = 0; lastPointerAngle: number = 0;
isValidPointer(e: PointerEvent<HTMLImageElement>): boolean { isValidPointer(e: PointerEvent<SVGSVGElement>): boolean {
if (e.pointerType === "mouse") { if (e.pointerType === "mouse") {
return e.button === 0; return e.button === 0;
} else if (e.pointerType === "pen") { } else if (e.pointerType === "pen") {
@@ -202,7 +209,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
return 0; return 0;
} }
pointerToAngle(e: PointerEvent<HTMLImageElement>): number { pointerToAngle(e: PointerEvent<SVGSVGElement>): number {
if (this.imgRef.current) { if (this.imgRef.current) {
let img = this.imgRef.current; let img = this.imgRef.current;
@@ -220,10 +227,10 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
return NaN; return NaN;
} }
captureElement?: HTMLElement; captureElement?: SVGSVGElement;
pointersDown: number = 0; pointersDown: number = 0;
onPointerDown(e: PointerEvent<HTMLImageElement>): void { onPointerDown(e: PointerEvent<SVGSVGElement>): void {
if (!this.mouseDown && this.isValidPointer(e)) { if (!this.mouseDown && this.isValidPointer(e)) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@@ -262,7 +269,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
} }
isCapturedPointer(e: PointerEvent<HTMLImageElement>): boolean { isCapturedPointer(e: PointerEvent<SVGSVGElement>): boolean {
return this.mouseDown return this.mouseDown
&& e.pointerId === this.pointerId && e.pointerId === this.pointerId
&& e.pointerType === this.pointerType; && e.pointerType === this.pointerType;
@@ -271,7 +278,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
onPointerMove(e: PointerEvent<HTMLImageElement>): void { onPointerMove(e: PointerEvent<SVGSVGElement>): void {
if (this.isCapturedPointer(e)) { if (this.isCapturedPointer(e)) {
e.preventDefault(); e.preventDefault();
this.updateAngle(e) this.updateAngle(e)
@@ -286,7 +293,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
} }
updateAngle(e: PointerEvent<HTMLImageElement>): void { updateAngle(e: PointerEvent<SVGSVGElement>): void {
let angle: number = this.pointerToAngle(e); let angle: number = this.pointerToAngle(e);
if (!isNaN(angle)) { if (!isNaN(angle)) {
if (!isNaN(this.lastPointerAngle)) { if (!isNaN(this.lastPointerAngle)) {
@@ -352,14 +359,13 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
render() { render() {
let classes = this.props.classes;
return ( return (
<img ref={this.imgRef} src="img/fx_dial.svg" alt="" <DialIcon ref={this.imgRef} className={classes.dialIcon}
style={{ style={{
overscrollBehavior: "none", touchAction: "none", transform: this.getDefaultRotationTransform(),
width: this.props.size, height: this.props.size, opacity: DEFAULT_OPACITY, width: this.props.size, height: this.props.size,
transform: this.getDefaultRotationTransform()
}} }}
draggable="true"
onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove} onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove}
onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp} onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp}
onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag} onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag}
+3 -3
View File
@@ -215,8 +215,8 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
onClose={() => { this.props.onDialogClose() }} onClose={() => { this.props.onDialogClose() }}
onAbort={() => { this.props.onDialogClose() }} onAbort={() => { this.props.onDialogClose() }}
> >
<div style={{ <div style={{
width: 380, height: 300, background: "FFFF", width: 380, height: 300,
display: "flex", flexFlow: "row", alignItems: "center", alignContent: " center", justifyContent: "center" display: "flex", flexFlow: "row", alignItems: "center", alignContent: " center", justifyContent: "center"
}}> }}>
<IconButton sx={{ height: "100%", width: 48, borderRadius: "0% 50% 50% 0%" }} onClick={ <IconButton sx={{ height: "100%", width: 48, borderRadius: "0% 50% 50% 0%" }} onClick={
@@ -227,7 +227,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
<NavigateBeforeIcon /> <NavigateBeforeIcon />
</IconButton> </IconButton>
<div style={{ <div style={{
width: 200, flexGrow: 1, height: 300, background: "#FFF", width: 200, flexGrow: 1, height: 300,
display: "flex", flexFlow: "column", alignItems: "center", alignContent: "center", justifyContent: "center" display: "flex", flexFlow: "column", alignItems: "center", alignContent: "center", justifyContent: "center"
}} }}
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px">
<g>
<g>
<polygon points="15,16 11,20 21,20 21,16"/>
<path d="M12.06,7.19L3,16.25V20h3.75l9.06-9.06L12.06,7.19z M5.92,18H5v-0.92l7.06-7.06l0.92,0.92L5.92,18z"/>
<path d="M18.71,8.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34C16.17,4.09,15.92,4,15.66,4c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83 l3.75,3.75L18.71,8.04z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 507 B

+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
<rect x="6" y="9" width="2" height="2"/>
<rect x="6" y="13" width="2" height="2"/>
<rect x="6" y="17" width="2" height="2"/>
<rect x="10" y="17" width="3" height="2"/>
<g>
<g>
<path d="M17.059,5.19l-7.061,7.06V16h3.75l7.061-7.061L17.059,5.19z M12.918,14h-0.92v-0.92l5.061-5.061l0.92,0.92L12.918,14z"/>
<path d="M23.708,6.04c0.39-0.39,0.39-1.02,0-1.41l-2.34-2.34c-0.2-0.2-0.45-0.29-0.71-0.29c-0.25,0-0.51,0.1-0.7,0.29l-1.83,1.83
l3.75,3.75L23.708,6.04z"/>
</g>
</g>
<path d="M15,16.641V21H4v-9V7h5h1h3.672l1.904-1.904C15.393,5.04,15.202,5,15,5h-4H8H4C2.9,5,2.01,5.9,2.01,7l-0.003,3.993L2,11v10
c0,1.1,0.891,2,1.99,2H4h11h0.01c1.1,0,1.99-0.9,1.99-2v-6.359L15,16.641z"/>
<polygon points="11.672,9 10,9 10,10.672 "/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 402 B

After

Width:  |  Height:  |  Size: 402 B

Before

Width:  |  Height:  |  Size: 997 B

After

Width:  |  Height:  |  Size: 997 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19.43 12.98c.04-.32.07-.64.07-.98 0-.34-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.09-.16-.26-.25-.44-.25-.06 0-.12.01-.17.03l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.06-.02-.12-.03-.18-.03-.17 0-.34.09-.43.25l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98 0 .33.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.09.16.26.25.44.25.06 0 .12-.01.17-.03l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.06.02.12.03.18.03.17 0 .34-.09.43-.25l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.98-1.71c.04.31.05.52.05.73 0 .21-.02.43-.05.73l-.14 1.13.89.7 1.08.84-.7 1.21-1.27-.51-1.04-.42-.9.68c-.43.32-.84.56-1.25.73l-1.06.43-.16 1.13-.2 1.35h-1.4l-.19-1.35-.16-1.13-1.06-.43c-.43-.18-.83-.41-1.23-.71l-.91-.7-1.06.43-1.27.51-.7-1.21 1.08-.84.89-.7-.14-1.13c-.03-.31-.05-.54-.05-.74s.02-.43.05-.73l.14-1.13-.89-.7-1.08-.84.7-1.21 1.27.51 1.04.42.9-.68c.43-.32.84-.56 1.25-.73l1.06-.43.16-1.13.2-1.35h1.39l.19 1.35.16 1.13 1.06.43c.43.18.83.41 1.23.71l.91.7 1.06-.43 1.27-.51.7 1.21-1.07.85-.89.7.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1 -1
View File
@@ -991,7 +991,7 @@ int main(int argc, char **argv)
parser.AddOption("--help", &help); parser.AddOption("--help", &help);
parser.AddOption("--prefix", &prefixOption); parser.AddOption("--prefix", &prefixOption);
parser.AddOption("--port", &portOption); parser.AddOption("--port", &portOption);
parser.AddOption("--enable-ap", &enable_ap); parser.AddOption("--enable-legacy-ap", &enable_ap);
parser.AddOption("--disable-ap", &disable_ap); parser.AddOption("--disable-ap", &disable_ap);
parser.AddOption("--enable-p2p", &enable_p2p); parser.AddOption("--enable-p2p", &enable_p2p);
parser.AddOption("--disable-p2p", &disable_p2p); parser.AddOption("--disable-p2p", &disable_p2p);
+3 -1
View File
@@ -378,6 +378,8 @@ void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()]; IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
Lv2PluginState newState = item->lv2State();
for (size_t i = 0; i < subscribers.size(); ++i) for (size_t i = 0; i < subscribers.size(); ++i)
{ {
t[i] = this->subscribers[i]; t[i] = this->subscribers[i];
@@ -386,7 +388,7 @@ void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
{ {
for (size_t i = 0; i < n; ++i) for (size_t i = 0; i < n; ++i)
{ {
t[i]->OnLv2StateChanged(instanceId); t[i]->OnLv2StateChanged(instanceId,newState);
} }
} }
delete[] t; delete[] t;
+1 -1
View File
@@ -55,7 +55,7 @@ namespace pipedal
virtual void OnInputVolumeChanged(float value) = 0; virtual void OnInputVolumeChanged(float value) = 0;
virtual void OnOutputVolumeChanged(float value) = 0; virtual void OnOutputVolumeChanged(float value) = 0;
virtual void OnLv2StateChanged(int64_t pedalItemId) = 0; virtual void OnLv2StateChanged(int64_t pedalItemId,const Lv2PluginState&newState ) = 0;
virtual void OnVst3ControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value, const std::string &state) = 0; virtual void OnVst3ControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value, const std::string &state) = 0;
virtual void OnPedalboardChanged(int64_t clientId, const Pedalboard &pedalboard) = 0; virtual void OnPedalboardChanged(int64_t clientId, const Pedalboard &pedalboard) = 0;
virtual void OnPresetsChanged(int64_t clientId, const PresetIndex &presets) = 0; virtual void OnPresetsChanged(int64_t clientId, const PresetIndex &presets) = 0;
+18 -2
View File
@@ -57,6 +57,21 @@ JSON_MAP_REFERENCE(GetPatchPropertyBody, instanceId)
JSON_MAP_REFERENCE(GetPatchPropertyBody, propertyUri) JSON_MAP_REFERENCE(GetPatchPropertyBody, propertyUri)
JSON_MAP_END() JSON_MAP_END()
class Lv2StateChangedBody {
public:
uint64_t instanceId_;
Lv2PluginState state_;
DECLARE_JSON_MAP(Lv2StateChangedBody);
};
JSON_MAP_BEGIN(Lv2StateChangedBody)
JSON_MAP_REFERENCE(Lv2StateChangedBody, instanceId)
JSON_MAP_REFERENCE(Lv2StateChangedBody, state)
JSON_MAP_END()
class SetPatchPropertyBody { class SetPatchPropertyBody {
public: public:
uint64_t instanceId_; uint64_t instanceId_;
@@ -1493,9 +1508,10 @@ protected:
} }
private: private:
virtual void OnLv2StateChanged(int64_t instanceId) virtual void OnLv2StateChanged(int64_t instanceId, const Lv2PluginState &state)
{ {
Send("onLv2StateChanged",instanceId); Lv2StateChangedBody message { (uint64_t)instanceId, state};
Send("onLv2StateChanged",message);
} }
virtual void OnErrorMessage(const std::string&message) virtual void OnErrorMessage(const std::string&message)
+101 -5
View File
@@ -26,14 +26,16 @@
#include "PluginHost.hpp" #include "PluginHost.hpp"
#include "ss.hpp" #include "ss.hpp"
#include "MimeTypes.hpp" #include "MimeTypes.hpp"
#include "AutoLilvNode.hpp"
using namespace pipedal; using namespace pipedal;
PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::filesystem::path &resourcePath) PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::filesystem::path &resourcePath)
{ {
auto pWorld = pHost->getWorld(); auto pWorld = pHost->getWorld();
LilvNodes *fileNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.pipedalUI__fileProperties, nullptr); AutoLilvNodes fileNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.pipedalUI__fileProperties, nullptr);
LILV_FOREACH(nodes, i, fileNodes) LILV_FOREACH(nodes, i, fileNodes)
{ {
const LilvNode *fileNode = lilv_nodes_get(fileNodes, i); const LilvNode *fileNode = lilv_nodes_get(fileNodes, i);
@@ -47,8 +49,23 @@ PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::files
pHost->LogWarning(SS("Failed to read pipedalui::fileProperties. " << e.what())); pHost->LogWarning(SS("Failed to read pipedalui::fileProperties. " << e.what()));
} }
} }
AutoLilvNodes frequencyPlotNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.pipedalUI__frequencyPlot, nullptr);
LILV_FOREACH(nodes, i, frequencyPlotNodes)
{
const LilvNode *frequencyPlotNode = lilv_nodes_get(frequencyPlotNodes, i);
try
{
UiFrequencyPlot::ptr frequencyPlotUI =
std::make_shared<UiFrequencyPlot>(pHost, frequencyPlotNode, resourcePath);
this->frequencyPlots_.push_back(std::move(frequencyPlotUI));
}
catch (const std::exception &e)
{
pHost->LogWarning(SS("Failed to read pipedalui::frequencyPlots. " << e.what()));
}
}
LilvNodes *portNotifications = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.ui__portNotification, nullptr); AutoLilvNodes portNotifications = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.ui__portNotification, nullptr);
LILV_FOREACH(nodes, i, portNotifications) LILV_FOREACH(nodes, i, portNotifications)
{ {
const LilvNode *portNotificationNode = lilv_nodes_get(portNotifications, i); const LilvNode *portNotificationNode = lilv_nodes_get(portNotifications, i);
@@ -62,8 +79,6 @@ PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::files
pHost->LogWarning(SS("Failed to read ui:portNotifications. " << e.what())); pHost->LogWarning(SS("Failed to read ui:portNotifications. " << e.what()));
} }
} }
lilv_nodes_free(fileNodes);
} }
UiFileType::UiFileType(PluginHost *pHost, const LilvNode *node) UiFileType::UiFileType(PluginHost *pHost, const LilvNode *node)
@@ -330,7 +345,15 @@ UiFileProperty::UiFileProperty(const std::string &name, const std::string &patch
directory_(directory) directory_(directory)
{ {
} }
PiPedalUI::PiPedalUI(std::vector<UiFileProperty::ptr> &&fileProperties) PiPedalUI::PiPedalUI(
std::vector<UiFileProperty::ptr> &&fileProperties,
std::vector<UiFrequencyPlot::ptr>&& frequencyPlots)
{
this->fileProperties_ = std::move(fileProperties);
this->frequencyPlots_ = std::move(frequencyPlots);
}
PiPedalUI::PiPedalUI(
std::vector<UiFileProperty::ptr> &&fileProperties)
{ {
this->fileProperties_ = std::move(fileProperties); this->fileProperties_ = std::move(fileProperties);
} }
@@ -357,6 +380,66 @@ UiFileType::UiFileType(const std::string&label, const std::string &fileType)
} }
} }
static float GetFloat(LilvWorld *pWorld,const LilvNode*node,const LilvNode*property,float defaultValue)
{
AutoLilvNode value = lilv_world_get(
pWorld,
node,
property,
nullptr);
return value.AsFloat(defaultValue);
}
UiFrequencyPlot::UiFrequencyPlot(PluginHost*pHost, const LilvNode*node,
const std::filesystem::path&resourcePath)
{
auto pWorld = pHost->getWorld();
AutoLilvNode patchProperty = lilv_world_get(
pWorld,
node,
pHost->lilvUris.pipedalUI__patchProperty,
nullptr);
if (patchProperty)
{
this->patchProperty_ = patchProperty.AsUri();
}
else
{
throw std::logic_error("PiPedal FileProperty is missing pipedalui:patchProperty value.");
}
AutoLilvNode index = lilv_world_get(
pWorld,
node,
pHost->lilvUris.lv2core__index,
nullptr);
if (index)
{
this->index_ = index.AsInt(-1);
}
else
{
this->index_ = -1;
}
AutoLilvNode portGroup = lilv_world_get(pWorld,node,pHost->lilvUris.portgroups__group,nullptr);
if (portGroup)
{
this->portGroup_ = portGroup.AsUri();
}
this->xLeft_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__xLeft,100);
this->xRight_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__xRight,22000);
this->yTop_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__yTop,5);
this->yBottom_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__yBottom,-35);
this->xLog_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__xLog,-35);
this->width_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__width,60);
}
JSON_MAP_BEGIN(UiPortNotification) JSON_MAP_BEGIN(UiPortNotification)
JSON_MAP_REFERENCE(UiPortNotification, portIndex) JSON_MAP_REFERENCE(UiPortNotification, portIndex)
JSON_MAP_REFERENCE(UiPortNotification, symbol) JSON_MAP_REFERENCE(UiPortNotification, symbol)
@@ -377,4 +460,17 @@ JSON_MAP_REFERENCE(UiFileProperty, directory)
JSON_MAP_REFERENCE(UiFileProperty, patchProperty) JSON_MAP_REFERENCE(UiFileProperty, patchProperty)
JSON_MAP_REFERENCE(UiFileProperty, fileTypes) JSON_MAP_REFERENCE(UiFileProperty, fileTypes)
JSON_MAP_REFERENCE(UiFileProperty, portGroup) JSON_MAP_REFERENCE(UiFileProperty, portGroup)
JSON_MAP_END()
JSON_MAP_BEGIN(UiFrequencyPlot)
JSON_MAP_REFERENCE(UiFrequencyPlot, patchProperty)
JSON_MAP_REFERENCE(UiFrequencyPlot, index)
JSON_MAP_REFERENCE(UiFrequencyPlot, portGroup)
JSON_MAP_REFERENCE(UiFrequencyPlot, xLeft)
JSON_MAP_REFERENCE(UiFrequencyPlot, xRight)
JSON_MAP_REFERENCE(UiFrequencyPlot, xLog)
JSON_MAP_REFERENCE(UiFrequencyPlot, yTop)
JSON_MAP_REFERENCE(UiFrequencyPlot, yBottom)
JSON_MAP_REFERENCE(UiFrequencyPlot, width)
JSON_MAP_END() JSON_MAP_END()
+48 -2
View File
@@ -50,12 +50,20 @@
#define PIPEDAL_UI__outputPorts PIPEDAL_UI_PREFIX "outputPorts" #define PIPEDAL_UI__outputPorts PIPEDAL_UI_PREFIX "outputPorts"
#define PIPEDAL_UI__text PIPEDAL_UI_PREFIX "text" #define PIPEDAL_UI__text PIPEDAL_UI_PREFIX "text"
#define PIPEDAL_UI__frequencyPlot PIPEDAL_UI_PREFIX "frequencyPlot"
#define PIPEDAL_UI__xLeft PIPEDAL_UI_PREFIX "xLeft"
#define PIPEDAL_UI__xRight PIPEDAL_UI_PREFIX "xRight"
#define PIPEDAL_UI__xLog PIPEDAL_UI_PREFIX "xLog"
#define PIPEDAL_UI__yTop PIPEDAL_UI_PREFIX "yTop"
#define PIPEDAL_UI__yBottom PIPEDAL_UI_PREFIX "yBottom"
#define PIPEDAL_UI__width PIPEDAL_UI_PREFIX "width"
namespace pipedal { namespace pipedal {
class PluginHost; class PluginHost;
class UiFileType { class UiFileType {
private: private:
std::string label_; std::string label_;
@@ -126,18 +134,55 @@ namespace pipedal {
public: public:
DECLARE_JSON_MAP(UiFileProperty); DECLARE_JSON_MAP(UiFileProperty);
}; };
class UiFrequencyPlot {
private:
std::string patchProperty_;
std::int64_t index_ = -1;
std::string portGroup_;
float xLeft_ = 100;
float xRight_ = 22000;
float yTop_ = 5;
float yBottom_ = -30;
bool xLog_ = true;
float width_ = 60;
public:
using ptr = std::shared_ptr<UiFrequencyPlot>;
UiFrequencyPlot() { }
UiFrequencyPlot(PluginHost*pHost, const LilvNode*node,
const std::filesystem::path&resourcePath);
const std::string &patchProperty() const { return patchProperty_; }
int64_t index() const { return index_; }
const std::string&portGroup() const { return portGroup_; }
float xLeft() const { return xLeft_; }
float xRight() const { return xRight_; }
float xLog() const { return xLog_; }
float yTop() const { return yTop_; }
float yBottom() const { return yBottom_; }
float width() const { return width_; }
public:
DECLARE_JSON_MAP(UiFrequencyPlot);
};
class PiPedalUI { class PiPedalUI {
public: public:
using ptr = std::shared_ptr<PiPedalUI>; using ptr = std::shared_ptr<PiPedalUI>;
PiPedalUI(PluginHost*pHost, const LilvNode*uiNode, const std::filesystem::path&resourcePath); PiPedalUI(PluginHost*pHost, const LilvNode*uiNode, const std::filesystem::path&resourcePath);
PiPedalUI(
PiPedalUI(std::vector<UiFileProperty::ptr> &&fileProperites); std::vector<UiFileProperty::ptr> &&fileProperties,
std::vector<UiFrequencyPlot::ptr> &&frequencyPlots);
PiPedalUI(
std::vector<UiFileProperty::ptr> &&fileProperties);
const std::vector<UiFileProperty::ptr>& fileProperties() const const std::vector<UiFileProperty::ptr>& fileProperties() const
{ {
return fileProperties_; return fileProperties_;
} }
const std::vector<UiFrequencyPlot::ptr>& frequencyPlots() const
{
return frequencyPlots_;
}
const std::vector<UiPortNotification::ptr> &portNotifications() const { return portNotifications_; } const std::vector<UiPortNotification::ptr> &portNotifications() const { return portNotifications_; }
@@ -155,6 +200,7 @@ namespace pipedal {
private: private:
std::vector<UiFileProperty::ptr> fileProperties_; std::vector<UiFileProperty::ptr> fileProperties_;
std::vector<UiFrequencyPlot::ptr> frequencyPlots_;
std::vector<UiPortNotification::ptr> portNotifications_; std::vector<UiPortNotification::ptr> portNotifications_;
}; };
+1 -1
View File
@@ -107,7 +107,7 @@ PiPedalVersion::PiPedalVersion(PiPedalModel&model)
std::string p2pAddr = GetInterfaceIpv4Address("p2p-wlan0-0"); std::string p2pAddr = GetInterfaceIpv4Address("p2p-wlan0-0");
if (p2pAddr.length() != 0) if (p2pAddr.length() != 0)
{ {
this->webAddresses_.push_back(MakeWebAddress(p2pAddr,port)); this->webAddresses_.push_back(MakeWebAddress(p2pAddr,port) + " (WiFi Direct)");
} }
+33
View File
@@ -145,6 +145,14 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
pipedalUI__outputPorts = lilv_new_uri(pWorld, PIPEDAL_UI__outputPorts); pipedalUI__outputPorts = lilv_new_uri(pWorld, PIPEDAL_UI__outputPorts);
pipedalUI__text = lilv_new_uri(pWorld, PIPEDAL_UI__text); pipedalUI__text = lilv_new_uri(pWorld, PIPEDAL_UI__text);
pipedalUI__frequencyPlot = lilv_new_uri(pWorld, PIPEDAL_UI__frequencyPlot);
pipedalUI__xLeft = lilv_new_uri(pWorld, PIPEDAL_UI__xLeft);
pipedalUI__xRight = lilv_new_uri(pWorld, PIPEDAL_UI__xRight);
pipedalUI__yTop = lilv_new_uri(pWorld, PIPEDAL_UI__yTop);
pipedalUI__yBottom = lilv_new_uri(pWorld, PIPEDAL_UI__yBottom);
pipedalUI__xLog = lilv_new_uri(pWorld, PIPEDAL_UI__xLog);
pipedalUI__width = lilv_new_uri(pWorld, PIPEDAL_UI__width);
ui__portNotification = lilv_new_uri(pWorld, LV2_UI__portNotification); ui__portNotification = lilv_new_uri(pWorld, LV2_UI__portNotification);
ui__plugin = lilv_new_uri(pWorld, LV2_UI__plugin); ui__plugin = lilv_new_uri(pWorld, LV2_UI__plugin);
ui__protocol = lilv_new_uri(pWorld, LV2_UI__protocol); ui__protocol = lilv_new_uri(pWorld, LV2_UI__protocol);
@@ -154,6 +162,9 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
lv2__symbol = lilv_new_uri(pWorld, LV2_CORE__symbol); lv2__symbol = lilv_new_uri(pWorld, LV2_CORE__symbol);
lv2__port = lilv_new_uri(pWorld, LV2_CORE__port); lv2__port = lilv_new_uri(pWorld, LV2_CORE__port);
#define MOD_PREFIX "http://moddevices.com/ns/mod#"
mod__label = lilv_new_uri(pWorld,MOD_PREFIX "label");
mod__brand = lilv_new_uri(pWorld,MOD_PREFIX "brand");
// ui:portNotification // ui:portNotification
// [ // [
// ui:portIndex 3; // ui:portIndex 3;
@@ -639,11 +650,25 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP
this->has_factory_presets_ = HasFactoryPresets(lv2Host, pPlugin); this->has_factory_presets_ = HasFactoryPresets(lv2Host, pPlugin);
AutoLilvNode plugUri = lilv_plugin_get_uri(pPlugin);
this->uri_ = nodeAsString(lilv_plugin_get_uri(pPlugin)); this->uri_ = nodeAsString(lilv_plugin_get_uri(pPlugin));
AutoLilvNode name = (lilv_plugin_get_name(pPlugin)); AutoLilvNode name = (lilv_plugin_get_name(pPlugin));
this->name_ = nodeAsString(name); this->name_ = nodeAsString(name);
AutoLilvNode brand = lilv_world_get(pWorld,plugUri,lv2Host->lilvUris.mod__brand, nullptr);
this->brand_ = nodeAsString(brand);
AutoLilvNode label = lilv_world_get(pWorld,plugUri,lv2Host->lilvUris.mod__label, nullptr);
this->label_ = nodeAsString(label);
if (label_.length() == 0)
{
this->label_ = name;
} else {
std::cout << this->label_ << std::endl;
}
AutoLilvNode author_name = (lilv_plugin_get_author_name(pPlugin)); AutoLilvNode author_name = (lilv_plugin_get_author_name(pPlugin));
this->author_name_ = nodeAsString(author_name); this->author_name_ = nodeAsString(author_name);
@@ -1015,6 +1040,8 @@ bool PluginHost::is_a(const std::string &class_, const std::string &target_class
Lv2PluginUiInfo::Lv2PluginUiInfo(PluginHost *pHost, const Lv2PluginInfo *plugin) Lv2PluginUiInfo::Lv2PluginUiInfo(PluginHost *pHost, const Lv2PluginInfo *plugin)
: uri_(plugin->uri()), : uri_(plugin->uri()),
name_(plugin->name()), name_(plugin->name()),
brand_(plugin->brand()),
label_(plugin->label()),
author_name_(plugin->author_name()), author_name_(plugin->author_name()),
author_homepage_(plugin->author_homepage()), author_homepage_(plugin->author_homepage()),
plugin_type_(uri_to_plugin_type(plugin->plugin_class())), plugin_type_(uri_to_plugin_type(plugin->plugin_class())),
@@ -1082,6 +1109,7 @@ Lv2PluginUiInfo::Lv2PluginUiInfo(PluginHost *pHost, const Lv2PluginInfo *plugin)
if (piPedalUI) if (piPedalUI)
{ {
this->fileProperties_ = piPedalUI->fileProperties(); this->fileProperties_ = piPedalUI->fileProperties();
this->frequencyPlots_ = piPedalUI->frequencyPlots();
this->uiPortNotifications_ = piPedalUI->portNotifications(); this->uiPortNotifications_ = piPedalUI->portNotifications();
} }
} }
@@ -1401,6 +1429,8 @@ json_map::storage_type<Lv2PluginInfo> Lv2PluginInfo::jmap{{
json_map::reference("bundle_path", &Lv2PluginInfo::bundle_path_), json_map::reference("bundle_path", &Lv2PluginInfo::bundle_path_),
json_map::reference("uri", &Lv2PluginInfo::uri_), json_map::reference("uri", &Lv2PluginInfo::uri_),
json_map::reference("name", &Lv2PluginInfo::name_), json_map::reference("name", &Lv2PluginInfo::name_),
json_map::reference("brand", &Lv2PluginInfo::brand_),
json_map::reference("label", &Lv2PluginInfo::label_),
json_map::reference("plugin_class", &Lv2PluginInfo::plugin_class_), json_map::reference("plugin_class", &Lv2PluginInfo::plugin_class_),
json_map::reference("supported_features", &Lv2PluginInfo::supported_features_), json_map::reference("supported_features", &Lv2PluginInfo::supported_features_),
json_map::reference("required_features", &Lv2PluginInfo::required_features_), json_map::reference("required_features", &Lv2PluginInfo::required_features_),
@@ -1466,6 +1496,8 @@ json_map::storage_type<Lv2PluginUiInfo>
{ {
json_map::reference("uri", &Lv2PluginUiInfo::uri_), json_map::reference("uri", &Lv2PluginUiInfo::uri_),
json_map::reference("name", &Lv2PluginUiInfo::name_), json_map::reference("name", &Lv2PluginUiInfo::name_),
json_map::reference("brand", &Lv2PluginUiInfo::brand_),
json_map::reference("label", &Lv2PluginUiInfo::label_),
json_map::enum_reference("plugin_type", &Lv2PluginUiInfo::plugin_type_, get_plugin_type_enum_converter()), json_map::enum_reference("plugin_type", &Lv2PluginUiInfo::plugin_type_, get_plugin_type_enum_converter()),
json_map::reference("plugin_display_type", &Lv2PluginUiInfo::plugin_display_type_), json_map::reference("plugin_display_type", &Lv2PluginUiInfo::plugin_display_type_),
json_map::reference("author_name", &Lv2PluginUiInfo::author_name_), json_map::reference("author_name", &Lv2PluginUiInfo::author_name_),
@@ -1479,5 +1511,6 @@ json_map::storage_type<Lv2PluginUiInfo>
json_map::reference("port_groups", &Lv2PluginUiInfo::port_groups_), json_map::reference("port_groups", &Lv2PluginUiInfo::port_groups_),
json_map::reference("is_vst3", &Lv2PluginUiInfo::is_vst3_), json_map::reference("is_vst3", &Lv2PluginUiInfo::is_vst3_),
json_map::reference("fileProperties", &Lv2PluginUiInfo::fileProperties_), json_map::reference("fileProperties", &Lv2PluginUiInfo::fileProperties_),
json_map::reference("frequencyPlots", &Lv2PluginUiInfo::frequencyPlots_),
json_map::reference("uiPortNotifications", &Lv2PluginUiInfo::uiPortNotifications_), json_map::reference("uiPortNotifications", &Lv2PluginUiInfo::uiPortNotifications_),
}}; }};
+24
View File
@@ -346,6 +346,8 @@ namespace pipedal
std::string uri_; std::string uri_;
std::string name_; std::string name_;
std::string plugin_class_; std::string plugin_class_;
std::string brand_;
std::string label_;
std::vector<std::string> supported_features_; std::vector<std::string> supported_features_;
std::vector<std::string> required_features_; std::vector<std::string> required_features_;
std::vector<std::string> optional_features_; std::vector<std::string> optional_features_;
@@ -367,6 +369,8 @@ namespace pipedal
LV2_PROPERTY_GETSET(bundle_path) LV2_PROPERTY_GETSET(bundle_path)
LV2_PROPERTY_GETSET(uri) LV2_PROPERTY_GETSET(uri)
LV2_PROPERTY_GETSET(name) LV2_PROPERTY_GETSET(name)
LV2_PROPERTY_GETSET(brand)
LV2_PROPERTY_GETSET(label)
LV2_PROPERTY_GETSET(plugin_class) LV2_PROPERTY_GETSET(plugin_class)
LV2_PROPERTY_GETSET(supported_features) LV2_PROPERTY_GETSET(supported_features)
LV2_PROPERTY_GETSET(required_features) LV2_PROPERTY_GETSET(required_features)
@@ -574,6 +578,8 @@ namespace pipedal
private: private:
std::string uri_; std::string uri_;
std::string name_; std::string name_;
std::string brand_;
std::string label_;
std::string author_name_; std::string author_name_;
std::string author_homepage_; std::string author_homepage_;
PluginType plugin_type_; PluginType plugin_type_;
@@ -588,11 +594,14 @@ namespace pipedal
std::vector<Lv2PluginUiPort> controls_; std::vector<Lv2PluginUiPort> controls_;
std::vector<Lv2PluginUiPortGroup> port_groups_; std::vector<Lv2PluginUiPortGroup> port_groups_;
std::vector<UiFileProperty::ptr> fileProperties_; std::vector<UiFileProperty::ptr> fileProperties_;
std::vector<UiFrequencyPlot::ptr> frequencyPlots_;
std::vector<UiPortNotification::ptr> uiPortNotifications_; std::vector<UiPortNotification::ptr> uiPortNotifications_;
public: public:
LV2_PROPERTY_GETSET(uri) LV2_PROPERTY_GETSET(uri)
LV2_PROPERTY_GETSET(name) LV2_PROPERTY_GETSET(name)
LV2_PROPERTY_GETSET(brand)
LV2_PROPERTY_GETSET(label)
LV2_PROPERTY_GETSET(author_name) LV2_PROPERTY_GETSET(author_name)
LV2_PROPERTY_GETSET(author_homepage) LV2_PROPERTY_GETSET(author_homepage)
LV2_PROPERTY_GETSET_SCALAR(plugin_type) LV2_PROPERTY_GETSET_SCALAR(plugin_type)
@@ -606,6 +615,7 @@ namespace pipedal
LV2_PROPERTY_GETSET(port_groups) LV2_PROPERTY_GETSET(port_groups)
LV2_PROPERTY_GETSET_SCALAR(is_vst3) LV2_PROPERTY_GETSET_SCALAR(is_vst3)
LV2_PROPERTY_GETSET(fileProperties) LV2_PROPERTY_GETSET(fileProperties)
LV2_PROPERTY_GETSET(frequencyPlots)
LV2_PROPERTY_GETSET(uiPortNotifications) LV2_PROPERTY_GETSET(uiPortNotifications)
static json_map::storage_type<Lv2PluginUiInfo> jmap; static json_map::storage_type<Lv2PluginUiInfo> jmap;
@@ -676,6 +686,15 @@ namespace pipedal
AutoLilvNode pipedalUI__fileExtension; AutoLilvNode pipedalUI__fileExtension;
AutoLilvNode pipedalUI__mimeType; AutoLilvNode pipedalUI__mimeType;
AutoLilvNode pipedalUI__frequencyPlot;
AutoLilvNode pipedalUI__xLeft;
AutoLilvNode pipedalUI__xRight;
AutoLilvNode pipedalUI__xLog;
AutoLilvNode pipedalUI__yTop;
AutoLilvNode pipedalUI__yBottom;
AutoLilvNode pipedalUI__width;
AutoLilvNode pipedalUI__outputPorts; AutoLilvNode pipedalUI__outputPorts;
AutoLilvNode pipedalUI__text; AutoLilvNode pipedalUI__text;
@@ -696,9 +715,14 @@ namespace pipedal
AutoLilvNode lv2__symbol; AutoLilvNode lv2__symbol;
AutoLilvNode lv2__port; AutoLilvNode lv2__port;
AutoLilvNode ui__FrequencyPlot;
AutoLilvNode patch__writable; AutoLilvNode patch__writable;
AutoLilvNode patch__readable; AutoLilvNode patch__readable;
AutoLilvNode mod__brand;
AutoLilvNode mod__label;
AutoLilvNode dc__format; AutoLilvNode dc__format;
}; };
LilvUris lilvUris; LilvUris lilvUris;