Dark Mode, Toob Neural Amp Modeler
@@ -1,10 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
project(pipedal
|
||||
VERSION 1.1.27
|
||||
VERSION 1.1.28
|
||||
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
||||
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
||||
)
|
||||
set (DISPLAY_VERSION "v1.1.27")
|
||||
set (DISPLAY_VERSION "v1.1.28")
|
||||
|
||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
<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).
|
||||
|
||||
|
||||
> 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.
|
||||
PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
|
||||
|
||||
@@ -9,6 +9,6 @@ Package: pipedal
|
||||
Pre-Depends: hostapd;authbind;dnsmasq
|
||||
Priority: optional
|
||||
Section: sound
|
||||
Version: 1.1.27
|
||||
Version: 1.1.28
|
||||
Installed-Size: 15147
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ page_icon: img/Install4.jpg
|
||||
|
||||
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
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# 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
|
||||
|
||||
- Add missing lv2-dev dependency.
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
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
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
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.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
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.
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
rdfs:comment "TooB amplifier cabinet simulator." ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "Cab Simulator";
|
||||
mod:label "TooB CabSim";
|
||||
lv2:requiredFeature urid:map ;
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
patch:readable
|
||||
|
||||
@@ -152,7 +152,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "Convolution Reverb";
|
||||
mod:label "TooB CReverb";
|
||||
lv2:requiredFeature urid:map;
|
||||
lv2:optionalFeature state::freePath, state:makePath, state:mapPath, work:schedule ;
|
||||
lv2:extensionData state:interface;
|
||||
|
||||
@@ -152,7 +152,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "Convolution Reverb (Stereo)";
|
||||
mod:label "TooB CReverb Stereo";
|
||||
lv2:requiredFeature urid:map;
|
||||
lv2:optionalFeature state::freePath, state:makePath, state:mapPath, work:schedule ;
|
||||
lv2:extensionData state:interface;
|
||||
|
||||
@@ -62,7 +62,7 @@ inputStage:filterGroup
|
||||
lv2:microVersion 16 ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "Input Stage";
|
||||
mod:label "TooB Input";
|
||||
lv2:requiredFeature urid:map ;
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
ToobAmp.so.1.0.16
|
||||
ToobAmp.so.1.0.17
|
||||
@@ -46,7 +46,7 @@ Emulation of a Boss CE-2 Chorus.
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "CE-2 Chorus";
|
||||
mod:label "TooB CE-2";
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
|
||||
lv2:port
|
||||
|
||||
@@ -46,7 +46,7 @@ A straighforward no-frills digital delay.
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "Delay";
|
||||
mod:label "TooB Delay";
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
|
||||
lv2:port
|
||||
|
||||
@@ -49,7 +49,7 @@ Emulation of a Boss BF-2 Flanger*.
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "BF-2 Flanger";
|
||||
mod:label "TooB BF-2";
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
|
||||
lv2:port
|
||||
|
||||
@@ -52,7 +52,7 @@ should use the monophonic version of this effect.
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "BF-2 Stereo Flanger";
|
||||
mod:label "TooB BF-2 Stereo";
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
|
||||
lv2:port
|
||||
|
||||
@@ -48,7 +48,7 @@ The core implementation is taken from the The Synthesis Toolkit in C++ (STK), ht
|
||||
""" ;
|
||||
|
||||
mod:brand "TooB";
|
||||
mod:label "Freeverb";
|
||||
mod:label "TooB Freeverb";
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
|
||||
lv2:port
|
||||
|
||||
@@ -40,7 +40,7 @@ toobml:filterGroup
|
||||
|
||||
<http://two-play.com/plugins/toob-ml>
|
||||
a lv2:Plugin ,
|
||||
lv2:SimulatorPlugin ;
|
||||
lv2:AmplifierPlugin ;
|
||||
doap:name "TooB ML Amplifier" ,
|
||||
"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:label "ML Amplifier";
|
||||
mod:label "TooB ML";
|
||||
lv2:requiredFeature urid:map, work:schedule ;
|
||||
lv2:optionalFeature lv2:hardRTCapable;
|
||||
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;
|
||||
]
|
||||
|
||||
.
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
lv2:binary <ToobAmp.so> ;
|
||||
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 ;
|
||||
lv2:binary <ToobAmp.so> ;
|
||||
rdfs:seeAlso <ConvolutionReverbStereo.ttl> .
|
||||
|
||||
@@ -21,6 +21,7 @@ add_custom_command(
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
|
||||
|
||||
DEPENDS
|
||||
src/SelectThemeDialog.tsx
|
||||
src/OkCancelDialog.tsx
|
||||
src/PluginControl.tsx
|
||||
src/reportWebVitals.ts
|
||||
@@ -133,9 +134,9 @@ add_custom_command(
|
||||
public/img/fx_distortion.svg
|
||||
public/img/Pi-Logo-3.png
|
||||
public/img/fx_oscillator.svg
|
||||
public/img/save_bank_as_white.svg
|
||||
public/img/edit_banks_white.svg
|
||||
public/img/settings_black_24dp.svg
|
||||
src/svg/ic_save_bank_as.svg
|
||||
src/svg/ic_edit_banks.svg
|
||||
src/svg/ic_settings.svg
|
||||
public/img/fx_filter.svg
|
||||
public/img/delete_outline_black_24dp.svg
|
||||
public/img/fx_function.svg
|
||||
@@ -150,7 +151,7 @@ add_custom_command(
|
||||
public/img/cc-by.png
|
||||
public/img/fx_split_a.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_drawer_2.svg
|
||||
public/img/fx_parametric_eq.svg
|
||||
@@ -161,10 +162,8 @@ add_custom_command(
|
||||
public/img/fx_analyzer.svg
|
||||
public/img/fx_delay.svg
|
||||
public/img/fx_spectral.svg
|
||||
public/img/edit_banks.svg
|
||||
public/img/fx_chorus.svg
|
||||
public/img/fx_simulator.svg
|
||||
public/img/drive_file_rename_outline_black_24dp.svg
|
||||
public/img/fx_mixer.svg
|
||||
public/img/fx_eq.svg
|
||||
public/img/fx_modulator.svg
|
||||
@@ -173,7 +172,6 @@ add_custom_command(
|
||||
public/img/fx_phaser.svg
|
||||
public/img/ic_drawer.svg
|
||||
public/img/fx_amplifier.svg
|
||||
public/img/save_bank_as.svg
|
||||
public/img/fx_lr.svg
|
||||
public/img/fx_instrument.svg
|
||||
public/img/Pi-Logo-3.svg
|
||||
@@ -183,14 +181,11 @@ add_custom_command(
|
||||
public/img/fx_empty.svg
|
||||
public/img/fx_dial.svg
|
||||
public/img/ic_logo.svg
|
||||
public/img/help_outline_black_24dp.svg
|
||||
public/img/fx_flanger2.svg
|
||||
public/img/old_delete_outline_white_24dp.svg
|
||||
public/img/fx_split_b.svg
|
||||
public/img/fx_spatial.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.png
|
||||
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 |
@@ -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 |
@@ -1,26 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="PiPedal Guitar Pedals"
|
||||
/>
|
||||
<!--
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" 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="/css/roboto.css" />
|
||||
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
<link rel="stylesheet" href="/css/roboto.css" />
|
||||
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
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/
|
||||
-->
|
||||
<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.
|
||||
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.
|
||||
@@ -29,14 +27,30 @@
|
||||
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`.
|
||||
-->
|
||||
<title>PiPedal</title>
|
||||
<style>
|
||||
BODY { background: #D0D0D0; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
BODY { background: #333; }
|
||||
}
|
||||
<title>PiPedal</title>
|
||||
<style>
|
||||
BODY {
|
||||
background: #D0D0D0;
|
||||
}
|
||||
</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>
|
||||
<body >
|
||||
<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`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -25,10 +25,12 @@ import isDarkMode from './DarkMode';
|
||||
|
||||
declare module '@mui/material/styles' {
|
||||
interface Theme {
|
||||
mainBackground: string;
|
||||
mainBackground: React.CSSProperties['color'];
|
||||
toolbarColor: React.CSSProperties['color'];
|
||||
}
|
||||
interface ThemeOptions {
|
||||
mainBackground?: string;
|
||||
mainBackground?: React.CSSProperties['color'];
|
||||
toolbarColor?: React.CSSProperties['color'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,13 +52,14 @@ const theme = createTheme(
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
main: "#6750A4" // #5B5690 #60529A #5C5694
|
||||
main: '#A770E4'// #6750A4" // #5B5690 #60529A #5C5694
|
||||
},
|
||||
secondary: {
|
||||
main: "#FF6060"
|
||||
},
|
||||
},
|
||||
mainBackground: "#222"
|
||||
mainBackground: "#222",
|
||||
toolbarColor: '#FFFFFF'
|
||||
}
|
||||
:
|
||||
{
|
||||
@@ -69,7 +72,9 @@ const theme = createTheme(
|
||||
}
|
||||
|
||||
},
|
||||
mainBackground: "#FFFFFF"
|
||||
mainBackground: "#FFFFFF",
|
||||
toolbarColor: '#FFFFFF'
|
||||
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
@@ -16,8 +16,3 @@ div {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
@@ -62,14 +62,27 @@ import JackStatusView from './JackStatusView';
|
||||
import { Theme } from '@mui/material/styles';
|
||||
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({
|
||||
menuIcon: {
|
||||
fill: "green"
|
||||
"&": { // :root
|
||||
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: {
|
||||
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) {
|
||||
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?";
|
||||
return "Are you sure you want to leave this page?";
|
||||
}
|
||||
@@ -652,6 +665,7 @@ render() {
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
colorScheme: isDarkMode() ? "dark": "light", // affects scrollbar color
|
||||
minHeight: 345, minWidth: 390,
|
||||
position: "absolute", width: "100%", height: "100%", background: "#F88", userSelect: "none",
|
||||
display: "flex", flexDirection: "column", flexWrap: "nowrap",
|
||||
@@ -666,14 +680,15 @@ render() {
|
||||
<CssBaseline />
|
||||
{(!this.state.tinyToolBar) ?
|
||||
(
|
||||
<AppBar className="appBar" position="absolute" >
|
||||
<Toolbar variant="dense" >
|
||||
<AppBar position="absolute" >
|
||||
<Toolbar variant="dense" className={classes.toolBar} >
|
||||
<IconButton
|
||||
edge="start"
|
||||
aria-label="menu"
|
||||
color="inherit"
|
||||
onClick={() => { this.showDrawer() }}
|
||||
size="large">
|
||||
<MenuButton />
|
||||
<MenuButton style={{opacity: 0.75}} />
|
||||
</IconButton>
|
||||
<div style={{ flex: "0 1 400px", minWidth: 100 }}>
|
||||
<PresetSelector />
|
||||
@@ -683,11 +698,12 @@ render() {
|
||||
<IconButton
|
||||
aria-label="menu"
|
||||
onClick={() => { this.toggleFullScreen(); }}
|
||||
color="inherit"
|
||||
size="large">
|
||||
{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 }}
|
||||
aria-label="menu"
|
||||
onClick={() => { this.showDrawer() }}
|
||||
color="inherit"
|
||||
size="large">
|
||||
<MenuButton />
|
||||
</IconButton>
|
||||
@@ -708,6 +725,7 @@ render() {
|
||||
<IconButton
|
||||
style={{ position: "absolute", right: 8, top: 8, zIndex: 2 }}
|
||||
aria-label="menu"
|
||||
color="inherit"
|
||||
onClick={() => { this.toggleFullScreen(); }}
|
||||
size="large">
|
||||
{this.state.isFullScreen ? (
|
||||
@@ -756,26 +774,20 @@ render() {
|
||||
<Divider />
|
||||
<List>
|
||||
<ListItem button key='RenameBank' onClick={() => { this.handleDrawerRenameBank() }}>
|
||||
<ListItemIcon>
|
||||
<img className='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 >
|
||||
<RenameOutlineIcon color='inherit' className={classes.menuIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Rename Bank' />
|
||||
</ListItem>
|
||||
<ListItem button key='SaveBank' onClick={() => { this.handleDrawerSaveBankAs() }} >
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/save_bank_as_white.svg" :"img/save_bank_as.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<SaveBankAsIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Save As New Bank' />
|
||||
</ListItem>
|
||||
<ListItem button key='CreateBank' onClick={() => { this.handleDrawerManageBanks(); }}>
|
||||
<ListItem button key='EditBanks' onClick={() => { this.handleDrawerManageBanks(); }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/edit_banks_white.svg" :"img/edit_banks.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<EditBanksIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Manage Banks...' />
|
||||
</ListItem>
|
||||
@@ -784,23 +796,19 @@ render() {
|
||||
<List>
|
||||
<ListItem button key='Settings' onClick={() => { this.handleDrawerSettingsClick() }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src={isDarkMode()? "img/settings_white_24dp.svg" :"img/settings_black_24dp.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<SettingsIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Settings' />
|
||||
</ListItem>
|
||||
<ListItem button key='About' onClick={() => { this.handleDrawerAboutClick() }}>
|
||||
<ListItemIcon>
|
||||
<img className='menuIcon'
|
||||
src= {isDarkMode() ? "img/help_outline_white_24dp.svg": "img/help_outline_black_24dp.svg"}
|
||||
alt="" style={{ opacity: 0.6 }} />
|
||||
<HelpOutlineIcon color="inherit" className={classes.menuIcon}/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='About' />
|
||||
</ListItem>
|
||||
<ListItem button key='Donations' onClick={() => { this.handleDrawerDonationClick() }}>
|
||||
<ListItemIcon>
|
||||
<VolunteerActivismIcon style={{ opacity: 0.6 }}/>
|
||||
<ListItemIcon >
|
||||
<VolunteerActivismIcon className={classes.menuIcon} color="inherit" />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary='Donations' />
|
||||
</ListItem>
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
|
||||
export default function isDarkMode(): boolean {
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
let value = localStorage.getItem("darkMode");
|
||||
return value === "true";
|
||||
}
|
||||
|
||||
export function setDarkMode(value: boolean): void {
|
||||
localStorage.setItem("darkMode",value? "true": "false");
|
||||
}
|
||||
|
||||
@@ -602,7 +602,7 @@ export const LoadPluginDialog =
|
||||
<SelectHoverBackground selected={value.uri === this.state.selected_uri} showHover={true} />
|
||||
<div className={classes.content}>
|
||||
<div className={classes.iconBorder} >
|
||||
<PluginIcon pluginType={value.plugin_type} size={24} />
|
||||
<PluginIcon pluginType={value.plugin_type} size={24} opacity={0.6} />
|
||||
</div>
|
||||
<div className={classes.content2}>
|
||||
<div className={classes.label} style={{ display: "flex", flexFlow: "row nowrap", alignItems: "center" }} >
|
||||
|
||||
@@ -204,6 +204,42 @@ export class UiPropertyNotification {
|
||||
plugin: 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 {
|
||||
deserialize(input: any): UiFileProperty
|
||||
@@ -253,6 +289,10 @@ export class UiFileProperty {
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (fileType.fileExtension === "*" || fileType.fileExtension === "")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -270,6 +310,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
{
|
||||
this.uri = input.uri;
|
||||
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.supported_features = input.supported_features;
|
||||
this.required_features = input.required_features;
|
||||
@@ -285,6 +327,13 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
} else {
|
||||
this.fileProperties = [];
|
||||
}
|
||||
if (input.frequencyPlots)
|
||||
{
|
||||
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
|
||||
} else {
|
||||
this.frequencyPlots = [];
|
||||
}
|
||||
|
||||
if (input.uiPortNotifications)
|
||||
{
|
||||
this.uiPortNotifications = UiPropertyNotification.deserialize_array(input.uiPortNotifications);
|
||||
@@ -297,6 +346,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
|
||||
uri: string = "";
|
||||
name: string = "";
|
||||
brand: string = "";
|
||||
label: string = "";
|
||||
plugin_class: string = "";
|
||||
supported_features: string[] = Lv2Plugin.EmptyFeatures;
|
||||
required_features: string[] = Lv2Plugin.EmptyFeatures;
|
||||
@@ -306,7 +357,8 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
|
||||
comment: string = "";
|
||||
ports: Port[] = Port.EmptyPorts;
|
||||
port_groups: PortGroup[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
frequencyPlots: UiFrequencyPlot[] = [];
|
||||
uiPortNotifications: UiPropertyNotification[] = [];
|
||||
}
|
||||
|
||||
@@ -668,6 +720,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
{
|
||||
this.uri = input.uri;
|
||||
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_display_type = input.plugin_display_type;
|
||||
this.author_name = input.author_name;
|
||||
@@ -685,6 +739,12 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
} else {
|
||||
this.fileProperties = [];
|
||||
}
|
||||
if (input.frequencyPlots)
|
||||
{
|
||||
this.frequencyPlots = UiFrequencyPlot.deserialize_array(input.frequencyPlots)
|
||||
} else {
|
||||
this.frequencyPlots = [];
|
||||
}
|
||||
|
||||
this.is_vst3 = input.is_vst3;
|
||||
return this;
|
||||
@@ -738,6 +798,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
|
||||
uri: string = "";
|
||||
name: string = "";
|
||||
brand: string = "";
|
||||
label: string = "";
|
||||
plugin_type: PluginType = PluginType.InvalidPlugin;
|
||||
plugin_display_type: string = "";
|
||||
author_name: string = "";
|
||||
@@ -749,7 +811,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
||||
description: string = "";
|
||||
controls: UiControl[] = [];
|
||||
port_groups: PortGroup[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
fileProperties: UiFileProperty[] = [];
|
||||
frequencyPlots: UiFrequencyPlot[] = [];
|
||||
is_vst3 : boolean = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ import MidiBindingsDialog from './MidiBindingsDialog';
|
||||
import PluginPresetSelector from './PluginPresetSelector';
|
||||
import {ReactComponent as OldDeleteIcon} from "./svg/old_delete_outline_24dp.svg";
|
||||
import {ReactComponent as MidiIcon} from "./svg/ic_midi.svg";
|
||||
|
||||
import isDarkMode from './DarkMode';
|
||||
|
||||
|
||||
const SPLIT_CONTROLBAR_THRESHHOLD = 650;
|
||||
@@ -463,7 +463,7 @@ export const MainPage =
|
||||
</div>
|
||||
<div style={{ flex: "0 0 auto", display: (canInsert || canAppend) ? "block" : "none", paddingRight: 8 }}>
|
||||
<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>
|
||||
<Menu
|
||||
id="add-menu"
|
||||
@@ -495,7 +495,8 @@ export const MainPage =
|
||||
onClick={this.onLoadClick}
|
||||
disabled={this.state.selectedPedal === -1 || (!canLoad) || (this.getSelectedPedalboardItem()?.isSplit() ?? true)}
|
||||
startIcon={<InputIcon />}
|
||||
style={{ textTransform: "none" }}
|
||||
style={{ textTransform: "none",
|
||||
background: (isDarkMode() ? "#6750A4": undefined) }}
|
||||
>
|
||||
Load
|
||||
</Button>
|
||||
|
||||
@@ -298,7 +298,7 @@ class PedalLayout {
|
||||
if (uiPlugin != null) {
|
||||
this.pluginType = 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.numberOfOutputs = Math.max(uiPlugin.audio_outputs,2);
|
||||
} else {
|
||||
@@ -679,7 +679,7 @@ const PedalboardView =
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!Utility.isTouchDevice()) {
|
||||
if (!Utility.needsZoomedControls()) {
|
||||
if (this.props.onDoubleClick && instanceId) {
|
||||
this.props.onDoubleClick(instanceId);
|
||||
}
|
||||
@@ -1014,7 +1014,7 @@ const PedalboardView =
|
||||
}}>
|
||||
<Typography variant="caption" display="block" noWrap={true}
|
||||
style={{ width: CELL_WIDTH - 4, textAlign: "center", flex: "0 1 auto" }}
|
||||
>{item.pedalItem?.pluginName}</Typography>
|
||||
>{item.name}</Typography>
|
||||
</div>
|
||||
)
|
||||
result.push(<div key={this.renderKey++} className={classes.pedalItem} style={{ left: item.bounds.x, top: item.bounds.y }} >
|
||||
|
||||
@@ -38,7 +38,12 @@ import GovernorSettings from './GovernorSettings';
|
||||
import WifiChannel from './WifiChannel';
|
||||
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
||||
import { AndroidHostInterface, FakeAndroidHost } from './AndroidHost';
|
||||
import isDarkMode, {setDarkMode} from './DarkMode';
|
||||
|
||||
export enum ColorTheme {
|
||||
Light,
|
||||
Dark
|
||||
};
|
||||
|
||||
export enum State {
|
||||
Loading,
|
||||
@@ -470,8 +475,11 @@ export class PiPedalModel //implements PiPedalModel
|
||||
let value = body as number;
|
||||
this._setInputVolume(value,false);
|
||||
} 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") {
|
||||
let controlChangedBody = body as Vst3ControlChangedBody;
|
||||
this._setVst3PedalboardControlValue(
|
||||
@@ -665,6 +673,10 @@ export class PiPedalModel //implements PiPedalModel
|
||||
this.getWebSocket().request<number>("hello")
|
||||
.then(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");
|
||||
})
|
||||
.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) {
|
||||
if (item.instanceId === instanceId) {
|
||||
item.onStateChanged(instanceId);
|
||||
@@ -2531,6 +2545,27 @@ export class PiPedalModel //implements PiPedalModel
|
||||
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;
|
||||
|
||||
@@ -137,7 +137,7 @@ const PluginControl =
|
||||
this.onInputKeyPress = this.onInputKeyPress.bind(this);
|
||||
}
|
||||
isTouchDevice(): boolean {
|
||||
return Utility.isTouchDevice();
|
||||
return Utility.needsZoomedControls();
|
||||
}
|
||||
|
||||
showZoomedControl()
|
||||
@@ -547,7 +547,7 @@ const PluginControl =
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Select variant="standard"
|
||||
<Select variant="standard"
|
||||
ref={this.selectRef}
|
||||
value={control.clampSelectValue(value)}
|
||||
onChange={this.onSelectChanged}
|
||||
@@ -556,7 +556,7 @@ const PluginControl =
|
||||
id: 'id' + control.symbol,
|
||||
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) => (
|
||||
<MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem>
|
||||
|
||||
@@ -23,7 +23,7 @@ import { WithStyles } from '@mui/styles';
|
||||
import createStyles from '@mui/styles/createStyles';
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||
import { UiPlugin, UiControl, UiFileProperty, ScalePoint } from './Lv2Plugin';
|
||||
import { UiPlugin, UiControl, UiFileProperty,UiFrequencyPlot, ScalePoint } from './Lv2Plugin';
|
||||
import {
|
||||
Pedalboard, PedalboardItem, ControlValue
|
||||
} from './Pedalboard';
|
||||
@@ -39,6 +39,7 @@ import FilePropertyDialog from './FilePropertyDialog';
|
||||
import JsonAtom from './JsonAtom';
|
||||
import PluginOutputControl from './PluginOutputControl';
|
||||
import Units from './Units';
|
||||
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
|
||||
|
||||
|
||||
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 {
|
||||
let symbol = uiControl.symbol;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ const styles = (theme: Theme) =>
|
||||
top: theme.spacing(1),
|
||||
color: theme.palette.grey[500],
|
||||
},
|
||||
icon: {
|
||||
fill: theme.palette.text.primary,
|
||||
opacity: 0.6
|
||||
}
|
||||
});
|
||||
};
|
||||
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" }}
|
||||
onClick={handleClickOpen}
|
||||
size="large">
|
||||
<InfoOutlinedIcon style={{opacity: 0.6}} />
|
||||
<InfoOutlinedIcon className={classes.icon} color='inherit' />
|
||||
</IconButton>
|
||||
{open && (
|
||||
<Dialog onClose={handleClose} open={open} fullWidth >
|
||||
|
||||
@@ -25,6 +25,7 @@ import withStyles from '@mui/styles/withStyles';
|
||||
import { UiControl } from './Lv2Plugin';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { PiPedalModel, PiPedalModelFactory, MonitorPortHandle,State } from './PiPedalModel';
|
||||
import isDarkMode from './DarkMode';
|
||||
|
||||
|
||||
|
||||
@@ -77,11 +78,13 @@ const PluginOutputControl =
|
||||
|
||||
private model: PiPedalModel;
|
||||
private vuRef: React.RefObject<HTMLDivElement>;
|
||||
private lampRef: React.RefObject<HTMLDivElement>;
|
||||
|
||||
|
||||
constructor(props: PluginOutputControlProps) {
|
||||
super(props);
|
||||
this.vuRef = React.createRef<HTMLDivElement>();
|
||||
this.lampRef = React.createRef<HTMLDivElement>();
|
||||
this.state = {
|
||||
hasValue: false,
|
||||
value: 0
|
||||
@@ -130,6 +133,12 @@ const PluginOutputControl =
|
||||
private animationHandle: number | undefined = undefined;
|
||||
|
||||
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) {
|
||||
let control = this.props.uiControl;
|
||||
let range = (value-control.min_value)/(control.max_value-control.min_value);
|
||||
@@ -241,6 +250,38 @@ const PluginOutputControl =
|
||||
</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 }}>
|
||||
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", width: item_width, margin: 8, height: 98 }}>
|
||||
|
||||
@@ -58,7 +58,7 @@ interface PresetSelectorState {
|
||||
}
|
||||
|
||||
|
||||
const selectColor = isDarkMode()? "#888": "black";
|
||||
const selectColor = isDarkMode()? "#888": "#FFFFFF";
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
select: { // fu fu fu.Overrides for white selector on dark background.
|
||||
@@ -301,17 +301,17 @@ const PresetSelector =
|
||||
}}>
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<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(); }}
|
||||
size="large">
|
||||
<SaveIconOutline style={{ opacity: 0.75 }} />
|
||||
<SaveIconOutline style={{ opacity: 0.75 }} color="inherit" />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: "1 1 auto", minWidth: 60, maxWidth: 300, position: "relative", paddingRight: 12 }} >
|
||||
<Select variant="standard"
|
||||
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)}
|
||||
onClose={(e) => this.handleSelectClose(e)}
|
||||
displayEmpty
|
||||
@@ -336,12 +336,13 @@ const PresetSelector =
|
||||
}
|
||||
</Select>
|
||||
</div>
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<div style={{ flex: "0 0 auto"}}>
|
||||
<IconButton
|
||||
style={{ flex: "0 0 auto" }}
|
||||
style={{ flex: "0 0 auto", color: "#FFFFFF" }}
|
||||
onClick={(e) => this.handlePresetMenuClick(e)}
|
||||
size="large">
|
||||
<MoreVertIcon style={{ opacity: 0.75 }} />
|
||||
size="large"
|
||||
>
|
||||
<MoreVertIcon style={{ opacity: 0.75 }} color="inherit" />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="edit-presets-menu"
|
||||
|
||||
@@ -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;
|
||||
@@ -23,7 +23,7 @@ import OkCancelDialog from './OkCancelDialog';
|
||||
import ListSelectDialog from './ListSelectDialog';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
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 AppBar from '@mui/material/AppBar';
|
||||
import Button from '@mui/material/Button';
|
||||
@@ -45,6 +45,7 @@ import DialogEx from './DialogEx'
|
||||
import GovernorSettings from './GovernorSettings';
|
||||
import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo';
|
||||
import SystemMidiBindingsDialog from './SystemMidiBindingsDialog';
|
||||
import SelectThemeDialog from './SelectThemeDialog';
|
||||
|
||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||
import { createStyles, Theme } from '@mui/material/styles';
|
||||
@@ -79,6 +80,7 @@ interface SettingsDialogState {
|
||||
showInputSelectDialog: boolean;
|
||||
showOutputSelectDialog: boolean;
|
||||
showMidiSelectDialog: boolean;
|
||||
showThemeSelectDialog: boolean;
|
||||
showJackServerSettingsDialog: boolean;
|
||||
shuttingDown: boolean;
|
||||
restarting: boolean;
|
||||
@@ -184,6 +186,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
showInputSelectDialog: false,
|
||||
showOutputSelectDialog: false,
|
||||
showMidiSelectDialog: false,
|
||||
showThemeSelectDialog: false,
|
||||
showJackServerSettingsDialog: false,
|
||||
shuttingDown: false,
|
||||
restarting: false,
|
||||
@@ -384,6 +387,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
showMidiSelectDialog: true
|
||||
})
|
||||
}
|
||||
handleThemeSelection() {
|
||||
this.setState({
|
||||
showThemeSelectDialog: true
|
||||
});
|
||||
}
|
||||
handleMidiMessageSettings() {
|
||||
this.setState({
|
||||
showSystemMidiBindingsDialog: true
|
||||
@@ -553,22 +561,22 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
}}
|
||||
>
|
||||
<div >
|
||||
{this.props.onboarding &&
|
||||
(
|
||||
<div>
|
||||
<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.
|
||||
</Typography>
|
||||
<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.
|
||||
</Typography>
|
||||
<Divider />
|
||||
</div>
|
||||
)}
|
||||
{this.props.onboarding &&
|
||||
(
|
||||
<div>
|
||||
<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.
|
||||
</Typography>
|
||||
<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.
|
||||
</Typography>
|
||||
<Divider />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||
STATUS
|
||||
STATUS
|
||||
</Typography>
|
||||
{(!isConfigValid) ?
|
||||
(
|
||||
@@ -582,7 +590,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
(
|
||||
<div className={classes.cpuStatusColor} style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||
{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>
|
||||
)
|
||||
}
|
||||
@@ -657,7 +665,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>System MIDI Bindings</Typography>
|
||||
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
|
||||
@@ -713,7 +721,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
</div>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
{ (!this.props.onboarding) ? (
|
||||
{(!this.props.onboarding) ? (
|
||||
<div >
|
||||
<Divider />
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
|
||||
@@ -735,7 +743,23 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
<ButtonBase
|
||||
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} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<div style={{
|
||||
@@ -746,6 +770,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
Show status monitor on main screen.</Typography>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<Switch
|
||||
checked={this.state.showStatusMonitor}
|
||||
@@ -787,16 +812,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
</div >
|
||||
</ButtonBase>
|
||||
</div>
|
||||
): (
|
||||
) : (
|
||||
<div>
|
||||
<Divider/>
|
||||
<div style={{display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16,marginRight: 16,
|
||||
marginTop: 16,marginBottom: 16}}>
|
||||
<Button variant="outlined" onClick={()=> {this.onOnboardingContinue()}} disabled={this.state.continueDisabled} style={{width: 120}}>Continue</Button>
|
||||
<Divider />
|
||||
<div style={{
|
||||
display: "grid", placeContent: "end", maxWidth: 550, marginLeft: 16, marginRight: 16,
|
||||
marginTop: 16, marginBottom: 16
|
||||
}}>
|
||||
<Button variant="outlined" onClick={() => { this.onOnboardingContinue() }} disabled={this.state.continueDisabled} style={{ width: 120 }}>Continue</Button>
|
||||
</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}
|
||||
onClose={() => this.setState({ showWifiConfigDialog: false })}
|
||||
onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)}
|
||||
@@ -869,8 +910,8 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
/>
|
||||
<SystemMidiBindingsDialog
|
||||
open={this.state.showSystemMidiBindingsDialog}
|
||||
onClose={()=> { this.setState({showSystemMidiBindingsDialog: false});}}
|
||||
/>
|
||||
onClose={() => { this.setState({ showSystemMidiBindingsDialog: false }); }}
|
||||
/>
|
||||
</DialogEx >
|
||||
|
||||
);
|
||||
|
||||
@@ -25,11 +25,11 @@ import createStyles from '@mui/styles/createStyles';
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
|
||||
import { PiPedalModelFactory, PiPedalModel, State } from "./PiPedalModel";
|
||||
import { StandardItemSize } from './PluginControlView';
|
||||
import Utility from './Utility';
|
||||
import SvgPathBuilder from './SvgPathBuilder';
|
||||
|
||||
|
||||
const StandardItemSize = { width: 80, height: 110 };
|
||||
|
||||
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> {
|
||||
instanceId: number;
|
||||
maxDb?: number;
|
||||
minDb?: number;
|
||||
minFrequency?: number;
|
||||
maxFrequency?: number;
|
||||
propertyName?: string;
|
||||
width?: number;
|
||||
|
||||
}
|
||||
interface ToobFrequencyResponseState {
|
||||
minDb: number;
|
||||
maxDb: number;
|
||||
minF: number;
|
||||
maxF: number;
|
||||
path: string;
|
||||
}
|
||||
|
||||
@@ -70,7 +72,11 @@ const ToobFrequencyResponseView =
|
||||
super(props);
|
||||
this.model = PiPedalModelFactory.getInstance();
|
||||
this.state = {
|
||||
path: ""
|
||||
path: "",
|
||||
minDb: -30,
|
||||
maxDb: 5,
|
||||
minF: 30,
|
||||
maxF: 20000
|
||||
};
|
||||
|
||||
this.pathRef = React.createRef();
|
||||
@@ -146,24 +152,61 @@ const ToobFrequencyResponseView =
|
||||
onFrequencyResponseUpdated(data: number[]) {
|
||||
if (!this.mounted) return;
|
||||
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) {
|
||||
pathBuilder.moveTo(this.toX(data[0]), this.toY(data[1]))
|
||||
for (let i = 2; i < data.length; i += 2) {
|
||||
pathBuilder.lineTo(this.toX(data[i]), this.toY(data[i + 1]));
|
||||
pathBuilder.moveTo(toX_(data[4]), toY_(data[5]))
|
||||
for (let i = 6; i < data.length; i += 2) {
|
||||
pathBuilder.lineTo(toX_(data[i]), toY_(data[i + 1]));
|
||||
}
|
||||
}
|
||||
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() {
|
||||
if (this.requestOutstanding) { // throttling.
|
||||
this.requestDeferred = true;
|
||||
return;
|
||||
}
|
||||
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) => {
|
||||
if (json && json.otype_ === "Vector" && json.vtype_ === "Float") {
|
||||
this.onFrequencyResponseUpdated(json.value as number[]);
|
||||
@@ -237,11 +280,11 @@ const ToobFrequencyResponseView =
|
||||
|
||||
render() {
|
||||
// deliberately reversed to flip up and down.
|
||||
this.dbMax = this.props.minDb ?? this.dbMinDefault;
|
||||
this.dbMin = this.props.maxDb ?? this.dbMaxDefault;
|
||||
this.dbMax = this.state.minDb;
|
||||
this.dbMin = this.state.maxDb;
|
||||
|
||||
this.fMin = this.props.minFrequency ?? 30;
|
||||
this.fMax = this.props.maxFrequency ?? 20000;
|
||||
this.fMin = this.state.minF;
|
||||
this.fMax = this.state.maxF;
|
||||
this.logMin = Math.log(this.fMin);
|
||||
this.logMax = Math.log(this.fMax);
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ const ToobMLView =
|
||||
{
|
||||
let group = controls[4] as ControlGroup;
|
||||
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;
|
||||
|
||||
@@ -92,7 +92,7 @@ const ToobToneStackView =
|
||||
{
|
||||
controls.splice(0,0,
|
||||
( <ToobFrequencyResponseView instanceId={this.props.instanceId}
|
||||
minDb={-20} maxDb={20} />)
|
||||
/>)
|
||||
);
|
||||
} else {
|
||||
controls.splice(0,0,
|
||||
|
||||
@@ -206,7 +206,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
|
||||
upload.abortController = new AbortController();
|
||||
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);
|
||||
this.props.onUploaded(filename);
|
||||
|
||||
@@ -41,11 +41,11 @@ const Utility = class {
|
||||
static isLandscape(): boolean {
|
||||
return window.innerWidth > window.innerHeight;
|
||||
}
|
||||
static isTouchDevice(): boolean {
|
||||
static needsZoomedControls(): boolean {
|
||||
if (!this.isLandscape()) return false;
|
||||
|
||||
if (window.innerHeight > 500) return false;
|
||||
|
||||
if (window.innerHeight > 300) return true;
|
||||
return (('ontouchstart' in window) &&
|
||||
((navigator.maxTouchPoints??0) > 0) );
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { WithStyles } from '@mui/styles';
|
||||
import withStyles from '@mui/styles/withStyles';
|
||||
import createStyles from '@mui/styles/createStyles';
|
||||
import { PiPedalModel, PiPedalModelFactory, ZoomedControlInfo } from './PiPedalModel';
|
||||
import {ReactComponent as DialIcon} from './svg/fx_dial.svg';
|
||||
|
||||
const SELECTED_OPACITY = 0.8;
|
||||
const DEFAULT_OPACITY = 0.6;
|
||||
@@ -34,6 +35,12 @@ const DEAD_ZONE_SIZE = 5;
|
||||
|
||||
|
||||
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> {
|
||||
|
||||
model: PiPedalModel = PiPedalModelFactory.getInstance();
|
||||
imgRef: React.RefObject<HTMLImageElement> = React.createRef();
|
||||
imgRef: React.RefObject<SVGSVGElement> = React.createRef();
|
||||
|
||||
constructor(props: ZoomedDialProps) {
|
||||
super(props);
|
||||
@@ -75,7 +82,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
}
|
||||
|
||||
onPointerUp(e: PointerEvent<HTMLImageElement>) {
|
||||
onPointerUp(e: PointerEvent<SVGSVGElement>) {
|
||||
|
||||
if (this.isCapturedPointer(e)) {
|
||||
--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;
|
||||
|
||||
@@ -118,7 +125,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
|
||||
|
||||
onPointerLostCapture(e: PointerEvent<HTMLImageElement>) {
|
||||
onPointerLostCapture(e: PointerEvent<SVGSVGElement>) {
|
||||
if (this.isCapturedPointer(e)) {
|
||||
--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
|
||||
}
|
||||
onTouchMove(e: TouchEvent<HTMLImageElement>) {
|
||||
onTouchMove(e: TouchEvent<SVGSVGElement>) {
|
||||
// e.preventDefault();
|
||||
e.stopPropagation(); // cancels scroll!!!
|
||||
|
||||
@@ -150,7 +157,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
currentAngle: number = 0;
|
||||
lastPointerAngle: number = 0;
|
||||
|
||||
isValidPointer(e: PointerEvent<HTMLImageElement>): boolean {
|
||||
isValidPointer(e: PointerEvent<SVGSVGElement>): boolean {
|
||||
if (e.pointerType === "mouse") {
|
||||
return e.button === 0;
|
||||
} else if (e.pointerType === "pen") {
|
||||
@@ -202,7 +209,7 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
return 0;
|
||||
}
|
||||
|
||||
pointerToAngle(e: PointerEvent<HTMLImageElement>): number {
|
||||
pointerToAngle(e: PointerEvent<SVGSVGElement>): number {
|
||||
|
||||
if (this.imgRef.current) {
|
||||
let img = this.imgRef.current;
|
||||
@@ -220,10 +227,10 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
return NaN;
|
||||
}
|
||||
captureElement?: HTMLElement;
|
||||
captureElement?: SVGSVGElement;
|
||||
pointersDown: number = 0;
|
||||
|
||||
onPointerDown(e: PointerEvent<HTMLImageElement>): void {
|
||||
onPointerDown(e: PointerEvent<SVGSVGElement>): void {
|
||||
if (!this.mouseDown && this.isValidPointer(e)) {
|
||||
e.preventDefault();
|
||||
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
|
||||
&& e.pointerId === this.pointerId
|
||||
&& 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)) {
|
||||
e.preventDefault();
|
||||
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);
|
||||
if (!isNaN(angle)) {
|
||||
if (!isNaN(this.lastPointerAngle)) {
|
||||
@@ -352,14 +359,13 @@ const ZoomedDial = withStyles(styles, { withTheme: true })(
|
||||
|
||||
|
||||
render() {
|
||||
let classes = this.props.classes;
|
||||
return (
|
||||
<img ref={this.imgRef} src="img/fx_dial.svg" alt=""
|
||||
<DialIcon ref={this.imgRef} className={classes.dialIcon}
|
||||
style={{
|
||||
overscrollBehavior: "none", touchAction: "none",
|
||||
width: this.props.size, height: this.props.size, opacity: DEFAULT_OPACITY,
|
||||
transform: this.getDefaultRotationTransform()
|
||||
transform: this.getDefaultRotationTransform(),
|
||||
width: this.props.size, height: this.props.size,
|
||||
}}
|
||||
draggable="true"
|
||||
onTouchStart={this.onTouchStart} onTouchMove={this.onTouchMove}
|
||||
onPointerDown={this.onPointerDown} onPointerUp={this.onPointerUp}
|
||||
onPointerMoveCapture={this.onPointerMove} onDrag={this.onDrag}
|
||||
|
||||
@@ -215,8 +215,8 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
||||
onClose={() => { this.props.onDialogClose() }}
|
||||
onAbort={() => { this.props.onDialogClose() }}
|
||||
>
|
||||
<div style={{
|
||||
width: 380, height: 300, background: "FFFF",
|
||||
<div style={{
|
||||
width: 380, height: 300,
|
||||
display: "flex", flexFlow: "row", alignItems: "center", alignContent: " center", justifyContent: "center"
|
||||
}}>
|
||||
<IconButton sx={{ height: "100%", width: 48, borderRadius: "0% 50% 50% 0%" }} onClick={
|
||||
@@ -227,7 +227,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
||||
<NavigateBeforeIcon />
|
||||
</IconButton>
|
||||
<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"
|
||||
|
||||
}}
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -991,7 +991,7 @@ int main(int argc, char **argv)
|
||||
parser.AddOption("--help", &help);
|
||||
parser.AddOption("--prefix", &prefixOption);
|
||||
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("--enable-p2p", &enable_p2p);
|
||||
parser.AddOption("--disable-p2p", &disable_p2p);
|
||||
|
||||
@@ -378,6 +378,8 @@ void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
||||
|
||||
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
|
||||
Lv2PluginState newState = item->lv2State();
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t[i] = this->subscribers[i];
|
||||
@@ -386,7 +388,7 @@ void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->OnLv2StateChanged(instanceId);
|
||||
t[i]->OnLv2StateChanged(instanceId,newState);
|
||||
}
|
||||
}
|
||||
delete[] t;
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace pipedal
|
||||
virtual void OnInputVolumeChanged(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 OnPedalboardChanged(int64_t clientId, const Pedalboard &pedalboard) = 0;
|
||||
virtual void OnPresetsChanged(int64_t clientId, const PresetIndex &presets) = 0;
|
||||
|
||||
@@ -57,6 +57,21 @@ JSON_MAP_REFERENCE(GetPatchPropertyBody, instanceId)
|
||||
JSON_MAP_REFERENCE(GetPatchPropertyBody, propertyUri)
|
||||
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 {
|
||||
public:
|
||||
uint64_t instanceId_;
|
||||
@@ -1493,9 +1508,10 @@ protected:
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -26,14 +26,16 @@
|
||||
#include "PluginHost.hpp"
|
||||
#include "ss.hpp"
|
||||
#include "MimeTypes.hpp"
|
||||
#include "AutoLilvNode.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::filesystem::path &resourcePath)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
lilv_nodes_free(fileNodes);
|
||||
}
|
||||
|
||||
UiFileType::UiFileType(PluginHost *pHost, const LilvNode *node)
|
||||
@@ -330,7 +345,15 @@ UiFileProperty::UiFileProperty(const std::string &name, const std::string &patch
|
||||
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);
|
||||
}
|
||||
@@ -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_REFERENCE(UiPortNotification, portIndex)
|
||||
JSON_MAP_REFERENCE(UiPortNotification, symbol)
|
||||
@@ -377,4 +460,17 @@ JSON_MAP_REFERENCE(UiFileProperty, directory)
|
||||
JSON_MAP_REFERENCE(UiFileProperty, patchProperty)
|
||||
JSON_MAP_REFERENCE(UiFileProperty, fileTypes)
|
||||
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()
|
||||
@@ -50,12 +50,20 @@
|
||||
#define PIPEDAL_UI__outputPorts PIPEDAL_UI_PREFIX "outputPorts"
|
||||
#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 {
|
||||
|
||||
class PluginHost;
|
||||
|
||||
|
||||
class UiFileType {
|
||||
private:
|
||||
std::string label_;
|
||||
@@ -126,18 +134,55 @@ namespace pipedal {
|
||||
public:
|
||||
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 {
|
||||
public:
|
||||
using ptr = std::shared_ptr<PiPedalUI>;
|
||||
PiPedalUI(PluginHost*pHost, const LilvNode*uiNode, const std::filesystem::path&resourcePath);
|
||||
|
||||
PiPedalUI(std::vector<UiFileProperty::ptr> &&fileProperites);
|
||||
PiPedalUI(
|
||||
std::vector<UiFileProperty::ptr> &&fileProperties,
|
||||
std::vector<UiFrequencyPlot::ptr> &&frequencyPlots);
|
||||
PiPedalUI(
|
||||
std::vector<UiFileProperty::ptr> &&fileProperties);
|
||||
|
||||
const std::vector<UiFileProperty::ptr>& fileProperties() const
|
||||
{
|
||||
return fileProperties_;
|
||||
}
|
||||
const std::vector<UiFrequencyPlot::ptr>& frequencyPlots() const
|
||||
{
|
||||
return frequencyPlots_;
|
||||
}
|
||||
|
||||
const std::vector<UiPortNotification::ptr> &portNotifications() const { return portNotifications_; }
|
||||
|
||||
@@ -155,6 +200,7 @@ namespace pipedal {
|
||||
|
||||
private:
|
||||
std::vector<UiFileProperty::ptr> fileProperties_;
|
||||
std::vector<UiFrequencyPlot::ptr> frequencyPlots_;
|
||||
std::vector<UiPortNotification::ptr> portNotifications_;
|
||||
};
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ PiPedalVersion::PiPedalVersion(PiPedalModel&model)
|
||||
std::string p2pAddr = GetInterfaceIpv4Address("p2p-wlan0-0");
|
||||
if (p2pAddr.length() != 0)
|
||||
{
|
||||
this->webAddresses_.push_back(MakeWebAddress(p2pAddr,port));
|
||||
this->webAddresses_.push_back(MakeWebAddress(p2pAddr,port) + " (WiFi Direct)");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,14 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
|
||||
pipedalUI__outputPorts = lilv_new_uri(pWorld, PIPEDAL_UI__outputPorts);
|
||||
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__plugin = lilv_new_uri(pWorld, LV2_UI__plugin);
|
||||
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__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:portIndex 3;
|
||||
@@ -639,11 +650,25 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP
|
||||
|
||||
this->has_factory_presets_ = HasFactoryPresets(lv2Host, pPlugin);
|
||||
|
||||
AutoLilvNode plugUri = lilv_plugin_get_uri(pPlugin);
|
||||
this->uri_ = nodeAsString(lilv_plugin_get_uri(pPlugin));
|
||||
|
||||
AutoLilvNode name = (lilv_plugin_get_name(pPlugin));
|
||||
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));
|
||||
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)
|
||||
: uri_(plugin->uri()),
|
||||
name_(plugin->name()),
|
||||
brand_(plugin->brand()),
|
||||
label_(plugin->label()),
|
||||
author_name_(plugin->author_name()),
|
||||
author_homepage_(plugin->author_homepage()),
|
||||
plugin_type_(uri_to_plugin_type(plugin->plugin_class())),
|
||||
@@ -1082,6 +1109,7 @@ Lv2PluginUiInfo::Lv2PluginUiInfo(PluginHost *pHost, const Lv2PluginInfo *plugin)
|
||||
if (piPedalUI)
|
||||
{
|
||||
this->fileProperties_ = piPedalUI->fileProperties();
|
||||
this->frequencyPlots_ = piPedalUI->frequencyPlots();
|
||||
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("uri", &Lv2PluginInfo::uri_),
|
||||
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("supported_features", &Lv2PluginInfo::supported_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("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::reference("plugin_display_type", &Lv2PluginUiInfo::plugin_display_type_),
|
||||
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("is_vst3", &Lv2PluginUiInfo::is_vst3_),
|
||||
json_map::reference("fileProperties", &Lv2PluginUiInfo::fileProperties_),
|
||||
json_map::reference("frequencyPlots", &Lv2PluginUiInfo::frequencyPlots_),
|
||||
json_map::reference("uiPortNotifications", &Lv2PluginUiInfo::uiPortNotifications_),
|
||||
}};
|
||||
|
||||
@@ -346,6 +346,8 @@ namespace pipedal
|
||||
std::string uri_;
|
||||
std::string name_;
|
||||
std::string plugin_class_;
|
||||
std::string brand_;
|
||||
std::string label_;
|
||||
std::vector<std::string> supported_features_;
|
||||
std::vector<std::string> required_features_;
|
||||
std::vector<std::string> optional_features_;
|
||||
@@ -367,6 +369,8 @@ namespace pipedal
|
||||
LV2_PROPERTY_GETSET(bundle_path)
|
||||
LV2_PROPERTY_GETSET(uri)
|
||||
LV2_PROPERTY_GETSET(name)
|
||||
LV2_PROPERTY_GETSET(brand)
|
||||
LV2_PROPERTY_GETSET(label)
|
||||
LV2_PROPERTY_GETSET(plugin_class)
|
||||
LV2_PROPERTY_GETSET(supported_features)
|
||||
LV2_PROPERTY_GETSET(required_features)
|
||||
@@ -574,6 +578,8 @@ namespace pipedal
|
||||
private:
|
||||
std::string uri_;
|
||||
std::string name_;
|
||||
std::string brand_;
|
||||
std::string label_;
|
||||
std::string author_name_;
|
||||
std::string author_homepage_;
|
||||
PluginType plugin_type_;
|
||||
@@ -588,11 +594,14 @@ namespace pipedal
|
||||
std::vector<Lv2PluginUiPort> controls_;
|
||||
std::vector<Lv2PluginUiPortGroup> port_groups_;
|
||||
std::vector<UiFileProperty::ptr> fileProperties_;
|
||||
std::vector<UiFrequencyPlot::ptr> frequencyPlots_;
|
||||
std::vector<UiPortNotification::ptr> uiPortNotifications_;
|
||||
|
||||
public:
|
||||
LV2_PROPERTY_GETSET(uri)
|
||||
LV2_PROPERTY_GETSET(name)
|
||||
LV2_PROPERTY_GETSET(brand)
|
||||
LV2_PROPERTY_GETSET(label)
|
||||
LV2_PROPERTY_GETSET(author_name)
|
||||
LV2_PROPERTY_GETSET(author_homepage)
|
||||
LV2_PROPERTY_GETSET_SCALAR(plugin_type)
|
||||
@@ -606,6 +615,7 @@ namespace pipedal
|
||||
LV2_PROPERTY_GETSET(port_groups)
|
||||
LV2_PROPERTY_GETSET_SCALAR(is_vst3)
|
||||
LV2_PROPERTY_GETSET(fileProperties)
|
||||
LV2_PROPERTY_GETSET(frequencyPlots)
|
||||
LV2_PROPERTY_GETSET(uiPortNotifications)
|
||||
|
||||
static json_map::storage_type<Lv2PluginUiInfo> jmap;
|
||||
@@ -676,6 +686,15 @@ namespace pipedal
|
||||
AutoLilvNode pipedalUI__fileExtension;
|
||||
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__text;
|
||||
|
||||
@@ -696,9 +715,14 @@ namespace pipedal
|
||||
AutoLilvNode lv2__symbol;
|
||||
AutoLilvNode lv2__port;
|
||||
|
||||
AutoLilvNode ui__FrequencyPlot;
|
||||
|
||||
AutoLilvNode patch__writable;
|
||||
AutoLilvNode patch__readable;
|
||||
|
||||
AutoLilvNode mod__brand;
|
||||
AutoLilvNode mod__label;
|
||||
|
||||
AutoLilvNode dc__format;
|
||||
};
|
||||
LilvUris lilvUris;
|
||||
|
||||