This commit is contained in:
Robin E.R. Davies
2026-06-17 14:11:24 -04:00
85 changed files with 1702 additions and 437 deletions
+27 -9
View File
@@ -1,19 +1,37 @@
cmake_minimum_required(VERSION 3.16.0)
project(pipedal
VERSION 2.0.105
VERSION 2.0.106
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
)
execute_process( COMMAND dpkg --print-architecture COMMAND tr -d '\n' OUTPUT_VARIABLE DEBIAN_ARCHITECTURE )
set (DISPLAY_VERSION "PiPedal v2.0.106-Release")
set (DISPLAY_VERSION "PiPedal v2.0.105-Release")
set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
set (CMAKE_INSTALL_PREFIX "/usr/")
option(PIPEDAL_DISABLE_COPYRIGHT_BUILD "Skip generation of copyright notices (use on non-Debian distros)" OFF)
option(PIPEDAL_EXCLUDE_TESTS "Exclude test targets from default build" OFF)
set(PIPEDAL_T3K_PUBLISHABLE_KEY "t3k_pub_bHrH8btdwXXTtxz5ryEU8sNLF-2TGRT9")
# Determine Debian-compatible architecture name (portable across distros)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
set(DEBIAN_ARCHITECTURE "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(DEBIAN_ARCHITECTURE "arm64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7l")
set(DEBIAN_ARCHITECTURE "armhf")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686")
set(DEBIAN_ARCHITECTURE "i386")
else()
execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE UNAME_M)
message(FATAL_ERROR "Cannot determine Debian architecture from CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR} (uname -m: ${UNAME_M})")
endif()
message(STATUS "DEBIAN_ARCHITECTURE=${DEBIAN_ARCHITECTURE}")
set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
set (CMAKE_INSTALL_PREFIX "/usr/")
set (LIBZIP_DO_INSTALL OFF CACHE BOOL "Disable libzip install" FORCE)
set (SQLITECPP_INSTALL OFF CACHE BOOL "Disable SQLiteCpp install" FORCE)
@@ -24,8 +42,6 @@ set(CPACK_SOURCE_IGNORE_FILES
"*.a;sqlite3.h;$(CPACK_SOURCE_IGNORE_FILES)"
)
set (PIPEDAL_EXCLUDE_TESTS false)
include(CTest)
enable_testing()
@@ -58,8 +74,10 @@ install (
install (
DIRECTORY ${VITE_BUILD_DIRECTORY} DESTINATION /etc/pipedal/react
)
install (FILES ${PROJECT_SOURCE_DIR}/build/src/notices.txt
DESTINATION /etc/pipedal/react/var/)
if(NOT PIPEDAL_DISABLE_COPYRIGHT_BUILD)
install (FILES ${PROJECT_SOURCE_DIR}/build/src/notices.txt
DESTINATION /etc/pipedal/react/var/)
endif()
install (
DIRECTORY ${PROJECT_SOURCE_DIR}/src/templates
+1 -1
View File
@@ -97,7 +97,7 @@ add_library(PiPedalCommon STATIC
ss.hpp
)
target_include_directories(PiPedalCommon PUBLIC "include" ${LIBNL3_INCLUDE_DIRS})
target_link_libraries(PiPedalCommon PUBLIC ${LIBNL3_LIBRARIES} sdbus-c++-objlib
target_link_libraries(PiPedalCommon PUBLIC ${LIBNL3_LIBRARIES} sdbus-c++-objlib asound
)
+1
View File
@@ -3,6 +3,7 @@
#include <sdbus-c++/IConnection.h>
#include <poll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include "ss.hpp"
#include <chrono>
#include <cassert>
+2 -2
View File
@@ -9,11 +9,11 @@
<img src="https://img.shields.io/github/downloads/rerdavies/pipedal/total?color=%23808080&link=https%3A%2F%2Frerdavies.github.io%2Fpipedal%2Fdownload.html"/>
Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v2.0.105</a>
Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v2.0.106</a>
Website:&nbsp;[https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
Documentation:&nbsp;[https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).
#### Announcing PiPedal 2.0 (2.0.105)&mdash;a major update to PiPedal, including exciting new features. See the Pipedal website [documentation](https://rerdavies.github.io/pipedal/PiPedal.html) for more information.
#### Announcing PiPedal 2.0 (2.0.106)&mdash;a major update to PiPedal, including exciting new features. See the Pipedal website [documentation](https://rerdavies.github.io/pipedal/PiPedal.html) for more information.
&nbsp;
+22 -1
View File
@@ -17,7 +17,8 @@ If your distribution doesn't provide a suitable version of nodejs,
please refer to the `node.js` website for instructions on [how to install the latest version of `node.js`](https://nodejs.org/en/download) directly.
Run the following commands to install dependent libraries required by the PiPedal build.
Ubuntu:
sudo apt update
sudo apt upgrade
@@ -27,6 +28,26 @@ Run the following commands to install dependent libraries required by the PiPeda
libsdbus-c++-dev libzip-dev google-perftools \
libgoogle-perftools-dev \
libpipewire-0.3-dev libbz2-dev libssl-dev librsvg2-dev
Arch Linux (alpha status):
sudo pacman -S --needed lilv boost systemd catch2 alsa-lib \
util-linux avahi networkmanager icu libzip gperftools \
pipewire bzip2 openssl librsvg sdbus-cpp
There is one AUR package:
sudo paru -S authbind
Note: in the Arch Linux build, copyright notices generation won't work, so it needs to be disabled with a cmake argument. Add this to your .vscode/settings.json file:
```json
{
"cmake.configureSettings": {
"PIPEDAL_DISABLE_COPYRIGHT_BUILD": "ON"
},
...
}
```
### Installing Sources
+7 -7
View File
@@ -13,18 +13,18 @@ page_icon: img/Install4.jpg
Download the most recent Debian (.deb) package for your platform:
- [Raspberry Pi OS bookworm (aarch64) v2.0.105](https://github.com/rerdavies/pipedal/releases/download/v2.0.105/pipedal_2.0.105_arm64.deb)
- [Ubuntu 24.04 through 25.04 (aarch64) v2.0.105](https://github.com/rerdavies/pipedal/releases/download/v2.0.105/pipedal_2.0.105_arm64.deb)
- [Ubuntu 24.04 through 25.04 (amd64) v2.0.105](https://github.com/rerdavies/pipedal/releases/download/v2.0.105/pipedal_2.0.105_amd64.deb)
- [Raspberry Pi OS bookworm (aarch64) v2.0.106](https://github.com/rerdavies/pipedal/releases/download/v2.0.106/pipedal_2.0.106_arm64.deb)
- [Ubuntu 24.04 through 25.04 (aarch64) v2.0.106](https://github.com/rerdavies/pipedal/releases/download/v2.0.106/pipedal_2.0.106_arm64.deb)
- [Ubuntu 24.04 through 25.04 (amd64) v2.0.106](https://github.com/rerdavies/pipedal/releases/download/v2.0.106/pipedal_2.0.106_amd64.deb)
Version 2.0.105 has been tested on Raspberry Pi OS bookworm, Ubuntu 24.04 (amd64), Ubuntu 24.10 (aarch64), and Ubuntu 25.04 (aarch64). Download the appropriate package for your platform, and install using the following procedure:
Version 2.0.106 has been tested on Raspberry Pi OS bookworm, Ubuntu 24.04 (amd64), Ubuntu 24.10 (aarch64), and Ubuntu 25.04 (aarch64). Download the appropriate package for your platform, and install using the following procedure:
```
sudo apt update
sudo apt upgrade
cd ~/Downloads
sudo apt-get install ./pipedal_2.0.105_arm64.deb
sudo apt-get install ./pipedal_2.0.106_arm64.deb
```
You MUST use `apt-get`. `apt` will not install downloaded packages; and `dpkg -i` will not install dependencies.
@@ -62,7 +62,7 @@ Use the following command to copy the downloaded package to the server from Linu
Adjust `username`, `server_address` and the actual name of the Debian package you downloaded as needed:
```
scp Downloads/pipedal_2.0.105_arm64.deb username@server_address:/home/username/
scp Downloads/pipedal_2.0.106_arm64.deb username@server_address:/home/username/
```
This will copy the downloaded package on your desktop computer to your home directory on the PiPedal server computer.
@@ -70,7 +70,7 @@ Once you have copied the package to the server, you can SSH into the server and
```
ssh username@server_address
sudo apt-get install ./pipedal_2.0.105_arm64.deb
sudo apt-get install ./pipedal_2.0.106_arm64.deb
```
The PiPedal package installer will print out the port number that the PiPedal web server is listening on. It defaults to port 80, but if you have another web server already running on port 80, it will select the next available port. Ubuntu default installs have Apache Server running on port 80, so the PiPedal web server will default to port 81 on Ubuntu.
+1 -1
View File
@@ -11,7 +11,7 @@
<a href="https://rerdavies.github.io/pipedal/download2"><img src="https://img.shields.io/badge/Download-008060" /></a>
<a href="https://rerdavies.github.io/pipedal/Documentation"><img src="https://img.shields.io/badge/Documentation-0060d0"/></a>
_To download PiPedal v2.0.105-alpha, click [*here*](download.md).
_To download PiPedal v2.0.106-alpha, click [*here*](download.md).
To view PiPedal documentation, click [*here*](Documentation.md)._
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
+18
View File
@@ -1,5 +1,23 @@
# Release Notes
## PiPedal 2.0.106-Release
New Features
- New TooB Multi-Tap Delay plugin.
- Drag and copy/paste Split nodes (and all their children) to new locations in the pedalboard. This allows you to easily rearrange the structure of your pedalboard.
- Range mapping controls in MIDI bindings now use the units of the target control, instead of 0..1 ranges. Provided by Fulgenzio Ruiz Rubio.
- New system MIDI bindings for Next/Previous Snapshot. Provided by Fulgenzio Ruiz Rubio.
Minor Features:
- Alpha release of PiPedal build procedure for ARCH Linux.
- Fix compilation warnings/errors when compiling with GCC 16.
- Better display names for ALSA USB audio devices in the UI.
Bug fixes:
- Incorrect rendering when dragging plugins.
- MIDI hangups when using MIDI footpedals (or other high-rate CC messages). Provided by onirob.
## PiPedal 2.0.105-Release
Bug fix:
+5 -5
View File
@@ -1,13 +1,13 @@
## Download
# Download PiPedal 2.0.105-alpha
# Download PiPedal 2.0.106-alpha
Download the most recent Debian (.deb) package for your platform:
- [Raspberry Pi OS bookworm (aarch64) v2.0.105 Alpha](https://github.com/rerdavies/pipedal/releases/download/v2.0.105/pipedal_2.0.105_arm64.deb)
- [Ubuntu 24.x, 25.04 (aarch64) v2.0.105 Alpha](https://github.com/rerdavies/pipedal/releases/download/v2.0.105/pipedal_2.0.105_arm64.deb)
- [Ubuntu 24.x, 25.04 (amd64/x86_64) v2.0.105 Alpha](https://github.com/rerdavies/pipedal/releases/download/v2.0.105/pipedal_2.0.105_amd64.deb)
- [Raspberry Pi OS bookworm (aarch64) v2.0.106 Alpha](https://github.com/rerdavies/pipedal/releases/download/v2.0.106/pipedal_2.0.106_arm64.deb)
- [Ubuntu 24.x, 25.04 (aarch64) v2.0.106 Alpha](https://github.com/rerdavies/pipedal/releases/download/v2.0.106/pipedal_2.0.106_arm64.deb)
- [Ubuntu 24.x, 25.04 (amd64/x86_64) v2.0.106 Alpha](https://github.com/rerdavies/pipedal/releases/download/v2.0.106/pipedal_2.0.106_amd64.deb)
Install the package by running
@@ -15,7 +15,7 @@ Install the package by running
```
sudo apt update
cd ~/Downloads
sudo apt install ./pipedal_2.0.105_arm64.deb
sudo apt install ./pipedal_2.0.106_arm64.deb
# or ... _amd64.deb as appropriate for your platform
```
The message about missing permissions given by `apt` is
+1 -1
View File
@@ -9,7 +9,7 @@
<a href="https://rerdavies.github.io/pipedal/download"><img src="https://img.shields.io/badge/Download-008060" /></a>
<a href="https://rerdavies.github.io/pipedal/Documentation"><img src="https://img.shields.io/badge/Documentation-0060d0"/></a>
_To download PiPedal v2.0.105 Release, click [*here*](download.md).
_To download PiPedal v2.0.106 Release, click [*here*](download.md).
To view PiPedal documentation, click [*here*](Documentation.md)._
Use your Raspberry Pi, or Ubuntu amd/x86-64 computer as a guitar effects pedal. Configure and control PiPedal remotedly, with your phone or tablet, or via a web browser.
+1 -1
View File
@@ -93,7 +93,7 @@ cabir:impulseFile3
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
TooB Cab IR is a convolution-based guitar cabinet impulse response simulator.
+1 -1
View File
@@ -50,7 +50,7 @@ toob:frequencyResponseVector
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
mod:brand "TooB";
mod:label "Cab Simulator";
@@ -53,7 +53,7 @@ toobimpulse:impulseFile
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Toob Convolution Reverb Stereo uses convolution reverb impulse/response files in order to produce highly
@@ -51,7 +51,7 @@ toobimpulse:impulseFile
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
+1 -1
View File
@@ -66,7 +66,7 @@ inputStage:filterGroup
doap:license <https://two-play.com/TooB/licenses/isc> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
mod:brand "TooB";
mod:label "Input";
+1 -1
View File
@@ -68,7 +68,7 @@ pstage:stage3
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
mod:brand "TooB";
mod:label "Power Stage";
+1 -1
View File
@@ -57,7 +57,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment "TooB spectrum analyzer" ;
mod:brand "TooB";
+1 -1
View File
@@ -57,7 +57,7 @@ tonestack:eqGroup
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
uiext:ui <http://two-play.com/plugins/toob-tone-stack-ui>;
+1 -1
View File
@@ -52,7 +52,7 @@ toob:frequencyResponseVector
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
uiext:ui <http://two-play.com/plugins/toob-three-band-eq-ui>;
@@ -52,7 +52,7 @@ toob:frequencyResponseVector
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
uiext:ui <http://two-play.com/plugins/toob-three-band-eq-stereo-ui>;
Binary file not shown.
+1 -1
View File
@@ -40,7 +40,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Emulation of a Boss CE-2 Chorus.
+1 -1
View File
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
A straightforward no-frills digital delay.
+1 -1
View File
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Emulation of a Boss BF-2 Flanger, based on circuit analysis and simulation of the original.
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Digital emulation of a Boss BF-2 Flanger.
+1 -1
View File
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Toob Freeverb is an Lv2 implementation of the famous Freeverb reverb effect. FreeVerb delivers a well-balanced reverb with very little tonal coloration.
+1 -1
View File
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
A 7 octave graphic equalizer, with frequencies chosen to be useful for EQ-ing guitar signals.
""" ;
+1 -1
View File
@@ -92,7 +92,7 @@ myprefix:output_group
doap:license <https://opensource.org/license/mit/> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 3 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
ui:ui <http://two-play.com/plugins/toob-looper-four-ui>;
+1 -1
View File
@@ -78,7 +78,7 @@ myprefix:output_group
doap:license <https://opensource.org/license/mit/> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 3 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
ui:ui <http://two-play.com/plugins/toob-looper-one-ui>;
+1 -1
View File
@@ -67,7 +67,7 @@ toobml:sagGroup
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
The TooB ML Amplifier plugin provides emulation of a variety of amplifiers and overdrive pedals that are implemented
using neural-network-based machine learning models of real amplifiers.
+1 -1
View File
@@ -40,7 +40,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Remix a stereo input signal.
+457
View File
@@ -0,0 +1,457 @@
@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 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 toobMultiEcho: <http://two-play.com/plugins/toob-multi-echo#> .
toobMultiEcho:tap1
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 1" ;
lv2:symbol "tap1" .
toobMultiEcho:tap2
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 2" ;
lv2:symbol "tap2" .
toobMultiEcho:tap3
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 3" ;
lv2:symbol "tap3" .
toobMultiEcho:tap4
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 4" ;
lv2:symbol "tap4" .
<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> .
<http://two-play.com/plugins/toob-multi-echo>
a lv2:Plugin ,
lv2:DelayPlugin ;
doap:name "TooB Multi-Tap Delay" ,
"Toob Multi-Tap Delay"@en-gb-gb
;
uiext:ui <http://two-play.com/plugins/toob-multi-echo-ui> ;
doap:license <https:##rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 81 ;
rdfs:comment """
A 4-tap Echo/Delay effect.
""" ;
mod:brand "TooB";
mod:label "Multi-Tap Delay";
lv2:optionalFeature lv2:hardRTCapable;
lv2:port
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 0 ;
lv2:symbol "bypass" ;
lv2:name "Bypass" ;
lv2:default 1.0 ;
lv2:minimum 0.0 ;
lv2:maximum 1.0 ;
lv2:designation lv2:enabled;
lv2:portProperty lv2:toggled;
],
#### tap1 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 1;
lv2:symbol "delay1" ;
lv2:name "Delay";
lv2:default 340 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 2 ;
lv2:symbol "level1" ;
lv2:name "Level";
lv2:default 27.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 3 ;
lv2:symbol "feedback1" ;
lv2:name "Feedback";
lv2:default 39.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 4 ;
lv2:symbol "pan1" ;
lv2:name "Pan";
lv2:portProperty epp:notOnGUI;
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
#### tap2 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 5;
lv2:symbol "delay2" ;
lv2:name "Delay";
lv2:default 111 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 6 ;
lv2:symbol "level2" ;
lv2:name "Level";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
], [
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 7 ;
lv2:symbol "feedback2" ;
lv2:name "Feedback";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 8 ;
lv2:symbol "pan2" ;
lv2:name "Pan";
lv2:portProperty epp:notOnGUI;
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
#### tap3 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 9;
lv2:symbol "delay3" ;
lv2:name "Delay";
lv2:default 23 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 10 ;
lv2:symbol "level3" ;
lv2:name "Level";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
], [
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 11 ;
lv2:symbol "feedback3" ;
lv2:name "Feedback";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 12 ;
lv2:symbol "pan3" ;
lv2:name "Pan";
lv2:portProperty epp:notOnGUI;
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
#### tap4 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 13;
lv2:symbol "delay4" ;
lv2:name "Delay";
lv2:default 40 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 14 ;
lv2:symbol "level4" ;
lv2:name "Level";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
], [
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 15 ;
lv2:symbol "feedback4" ;
lv2:name "Feedback";
lv2:default 50.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 16 ;
lv2:symbol "pan4" ;
lv2:name "Pan";
lv2:portProperty epp:notOnGUI;
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
######### Mix ################################
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 17 ;
lv2:symbol "direct" ;
lv2:name "Direct";
lv2:default 100.0 ;
lv2:minimum 0.0 ;
lv2:maximum 200.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 18;
lv2:symbol "master" ;
lv2:name "Master";
lv2:default 0.0 ;
lv2:minimum -40.0;
lv2:maximum 40.0;
units:unit units:db;
rdfs:comment "Master volume";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 19 ;
lv2:symbol "tails" ;
lv2:name "Tails";
lv2:default 1 ;
lv2:minimum 0;
lv2:maximum 1 ;
lv2:portProperty lv2:toggled;
rdfs:comment "Enable echo tails when bypassed" ;
],
############# Audio I/O #######################
[
a lv2:AudioPort ,
lv2:InputPort ;
lv2:index 20 ;
lv2:symbol "inl" ;
lv2:name "In L"
],
[
a lv2:AudioPort ,
lv2:OutputPort ;
lv2:index 21 ;
lv2:symbol "outl" ;
lv2:name "Out L"
]
#,[
# a lv2:AudioPort ,
# lv2:InputPort ;
# lv2:index 22 ;
# lv2:symbol "inr" ;
# lv2:name "In R"
#],
#[
# a lv2:AudioPort ,
# lv2:OutputPort ;
# lv2:index 23 ;
# lv2:symbol "outr" ;
# lv2:name "OutR"
#]
.
<http://two-play.com/plugins/toob-multi-echo-ui>
a uiext:X11UI ;
lv2:binary <ToobAmpUI.so>;
lv2:extensionData uiext::idle ;
lv2:extensionData uiext:resize ;
lv2:extensionData uiext:idleInterface;
lv2:requiredFeature uiext:idleInterface ;
.
@@ -0,0 +1,453 @@
@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 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 toobMultiEcho: <http://two-play.com/plugins/toob-multi-echo-stereo#> .
toobMultiEcho:tap1
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 1" ;
lv2:symbol "tap1" .
toobMultiEcho:tap2
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 2" ;
lv2:symbol "tap2" .
toobMultiEcho:tap3
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 3" ;
lv2:symbol "tap3" .
toobMultiEcho:tap4
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Tap 4" ;
lv2:symbol "tap4" .
<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> .
<http://two-play.com/plugins/toob-multi-echo-stereo>
a lv2:Plugin ,
lv2:DelayPlugin ;
doap:name "TooB Multi-Tap Delay (Stereo)" ,
"Toob Multi-Tap Delay (Stereo)"@en-gb-gb
;
uiext:ui <http://two-play.com/plugins/toob-multi-echo-stereo-ui> ;
doap:license <https:##rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 81 ;
rdfs:comment """
A 4-tap Echo/Delay effect.
""" ;
mod:brand "TooB";
mod:label "Multi-Tap Delay";
lv2:optionalFeature lv2:hardRTCapable;
lv2:port
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 0 ;
lv2:symbol "bypass" ;
lv2:name "Bypass" ;
lv2:default 1.0 ;
lv2:minimum 0.0 ;
lv2:maximum 1.0 ;
lv2:designation lv2:enabled;
lv2:portProperty lv2:toggled;
],
#### tap1 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 1;
lv2:symbol "delay1" ;
lv2:name "Delay";
lv2:default 340 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 2 ;
lv2:symbol "level1" ;
lv2:name "Level";
lv2:default 27.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 3 ;
lv2:symbol "feedback1" ;
lv2:name "Feedback";
lv2:default 39.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap1 ;
lv2:index 4 ;
lv2:symbol "pan1" ;
lv2:name "Pan";
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
#### tap2 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 5;
lv2:symbol "delay2" ;
lv2:name "Delay";
lv2:default 111 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 6 ;
lv2:symbol "level2" ;
lv2:name "Level";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
], [
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 7 ;
lv2:symbol "feedback2" ;
lv2:name "Feedback";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap2 ;
lv2:index 8 ;
lv2:symbol "pan2" ;
lv2:name "Pan";
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
#### tap3 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 9;
lv2:symbol "delay3" ;
lv2:name "Delay";
lv2:default 23 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 10 ;
lv2:symbol "level3" ;
lv2:name "Level";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
], [
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 11 ;
lv2:symbol "feedback3" ;
lv2:name "Feedback";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap3 ;
lv2:index 12 ;
lv2:symbol "pan3" ;
lv2:name "Pan";
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
#### tap4 ##############################################################
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 13;
lv2:symbol "delay4" ;
lv2:name "Delay";
lv2:default 40 ;
lv2:minimum 5;
lv2:maximum 3000;
units:unit units:ms;
lv2:portProperty <http://lv2plug.in/ns/ext/port-props#logarithmic>;
rdfs:comment "Delay in ms";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 14 ;
lv2:symbol "level4" ;
lv2:name "Level";
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
], [
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 15 ;
lv2:symbol "feedback4" ;
lv2:name "Feedback";
lv2:default 50.0 ;
lv2:minimum 0.0 ;
lv2:maximum 100.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of subequent echoes";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
pg:group toobMultiEcho:tap4 ;
lv2:index 16 ;
lv2:symbol "pan4" ;
lv2:name "Pan";
lv2:default 0.0 ;
lv2:minimum -1.0 ;
lv2:maximum 1.0 ;
rdfs:comment "Pan (tap 1)";
],
######### Mix ################################
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 17 ;
lv2:symbol "direct" ;
lv2:name "Direct";
lv2:default 100.0 ;
lv2:minimum 0.0 ;
lv2:maximum 200.0 ;
units:unit units:pc;
rdfs:comment "Attenuation of the first echo";
lv2:scalePoint [
rdfs:label "Off" ;
rdf:value 0.0
]
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 18;
lv2:symbol "master" ;
lv2:name "Master";
lv2:default 0.0 ;
lv2:minimum -40.0;
lv2:maximum 40.0;
units:unit units:db;
rdfs:comment "Master volume";
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 19 ;
lv2:symbol "tails" ;
lv2:name "Tails";
lv2:default 1 ;
lv2:minimum 0;
lv2:maximum 1 ;
lv2:portProperty lv2:toggled;
rdfs:comment "Enable echo tails when bypassed" ;
],
############# Audio I/O #######################
[
a lv2:AudioPort ,
lv2:InputPort ;
lv2:index 20 ;
lv2:symbol "inl" ;
lv2:name "In L"
],
[
a lv2:AudioPort ,
lv2:OutputPort ;
lv2:index 21 ;
lv2:symbol "outl" ;
lv2:name "Out L"
]
,[
a lv2:AudioPort ,
lv2:InputPort ;
lv2:index 22 ;
lv2:symbol "inr" ;
lv2:name "In R"
],
[
a lv2:AudioPort ,
lv2:OutputPort ;
lv2:index 23 ;
lv2:symbol "outr" ;
lv2:name "OutR"
]
.
<http://two-play.com/plugins/toob-multi-echo-stereo-ui>
a uiext:X11UI ;
lv2:binary <ToobAmpUI.so>;
lv2:extensionData uiext::idle ;
lv2:extensionData uiext:resize ;
lv2:extensionData uiext:idleInterface;
lv2:requiredFeature uiext:idleInterface ;
.
@@ -74,7 +74,7 @@ toobNam:calibrationGroup
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
TooB Neural Amp Modeler is a neural network based Amp Simulator. It uses .nam model files that are generated by training nueral networks
on audio recordings of actual guitar amps, effects pedals and other equipment. .nam files contain data from the trained models, which can be loaded into
+1 -1
View File
@@ -54,7 +54,7 @@ noisegate:envelope_group
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
A noise gate is an audio processing tool that controls the volume of an audio signal
by allowing it to pass through only when it exceeds a set threshold.
+1 -1
View File
@@ -87,7 +87,7 @@ parametric_eq:hfGroup
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
uiext:ui <http://two-play.com/plugins/toob-parametric-eq-ui>;
@@ -87,7 +87,7 @@ toob-parametric-eq-stereo:hfGroup
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
uiext:ui <http://two-play.com/plugins/toob-parametric-eq-stereo-ui>;
+1 -1
View File
@@ -40,7 +40,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
A loose emulation of an MXR® Phase 90 Phaser.
+1 -1
View File
@@ -60,7 +60,7 @@ toobPlayer:seek
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Play audio files. Audio files can optionally be loooped by pressing the "Set loop" button.
+1 -1
View File
@@ -51,7 +51,7 @@ recordPrefix:audioFile
doap:license <https://opensource.org/license/mit/> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 3 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
ui:ui <http://two-play.com/plugins/toob-record-mono-ui>;
+1 -1
View File
@@ -88,7 +88,7 @@ myprefix:loop3_group
doap:license <https://opensource.org/license/mit/> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 3 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
ui:ui <http://two-play.com/plugins/toob-record-stereo-ui>;
+1 -1
View File
@@ -43,7 +43,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
TooB Tone is a simple tone control. For more flexible EQ plugins, see TooB 3 Band Eq, or TooB Parameteric EQ.
+1 -1
View File
@@ -43,7 +43,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
TooB Tone is a simple tone control. For more flexible EQ plugins, see TooB 3 Band Eq, or TooB Parameteric EQ.
+1 -1
View File
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
A tremolo effect, equivalent to "vibrato" on vintage Fender tube amps.
+1 -1
View File
@@ -41,7 +41,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
A tremolo effect, equivalent to "vibrato" on vintage Fender tube amps.
+1 -1
View File
@@ -44,7 +44,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
TooB Tuner is a chromatic guitar tuner.
""" ;
+1 -1
View File
@@ -39,7 +39,7 @@
doap:license <https://rerdavies.github.io/pipedal/LicenseToobAmp> ;
doap:maintainer <http://two-play.com/rerdavies#me> ;
lv2:minorVersion 0 ;
lv2:microVersion 80 ;
lv2:microVersion 81 ;
rdfs:comment """
Volume control.
Binary file not shown.
Binary file not shown.
+11
View File
@@ -4,6 +4,7 @@
@prefix tpset: <http://two-play.com/plugins/preset#> .
<http://two-play.com/plugins/toob-tone-stack> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToneStack.ttl> .
@@ -114,6 +115,16 @@
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToobMix.ttl> .
<http://two-play.com/plugins/toob-multi-echo> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToobMultiEcho.ttl> .
<http://two-play.com/plugins/toob-multi-echo-stereo> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToobMultiEchoStereo.ttl> .
<http://two-play.com/plugins/toob-tremolo> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToobTremolo.ttl> .
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 25 KiB

+16 -3
View File
@@ -1,7 +1,20 @@
#!/usr/bin/bash
rm -rf build/lv2_x64
mkdir build/lv2_x64
mkdir -p build/lv2_x64/pkg
mkdir build/lv2_x64/pkg
dpkg-deb -x lv2/x86_64/toobamp_*_amd64.deb build/lv2_x64/pkg
# Extract .deb using ar + tar (portable, no dpkg-deb needed)
cd build/lv2_x64
ar x ../../lv2/x86_64/toobamp_*_amd64.deb
if [ -f data.tar.zst ]; then
tar --zstd -xf data.tar.zst -C pkg
elif [ -f data.tar.xz ]; then
tar -xJf data.tar.xz -C pkg
elif [ -f data.tar.gz ]; then
tar -xzf data.tar.gz -C pkg
else
echo "Error: cannot find data.tar.* in the .deb package"
exit 1
fi
rm -f control.tar.* data.tar.* debian-binary
cd "$OLDPWD"
+6 -1
View File
@@ -1,8 +1,10 @@
cmake_minimum_required(VERSION 3.16.0)
# Prevent installation of SQLite built components. (we use the .a library files directly)
option(SQLITECPP_INSTALL "Enables the install target." OFF)
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
add_subdirectory("SQLiteCpp" EXCLUDE_FROM_ALL)
add_subdirectory("SQLiteCpp")
set(SDBUSCPP_BUILD_CODEGEN off)
@@ -25,5 +27,8 @@ option(BUILD_REGRESS "Build regression tests" OFF)
option(BUILD_OSSFUZZ "Build fuzzers for ossfuzz" OFF)
option(BUILD_EXAMPLES "Build examples" OFF)
option(BUILD_DOC "Build documentation" OFF)
option(LIBZIP_DO_INSTALL "Install libzip and the related files" OFF)
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
add_subdirectory("libzip")
+3
View File
@@ -2,6 +2,7 @@
* MIT License
*
* Copyright (c) Robin E.R. Davies
* Copyright (c) Roberto Figliè
*
* 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
@@ -1681,6 +1682,7 @@ namespace pipedal
AlsaMidiMessage message;
midiEventCount = 0;
midiEventMemoryIndex = 0;
auto alsaSequener = this->alsaSequencer; // take an addref
if (!alsaSequener)
{
@@ -1772,6 +1774,7 @@ namespace pipedal
break;
}
this->midiEventCount = 0;
this->midiEventMemoryIndex = 0;
// snd_pcm_wait(captureHandle, 1);
ssize_t framesToRead = bufferSize;
+1
View File
@@ -28,6 +28,7 @@
#include <mutex>
#include <iostream>
#include <algorithm>
#include <unistd.h>
#include "AlsaDriver.hpp"
#include "ChannelRouterSettings.hpp"
+28
View File
@@ -516,6 +516,8 @@ private:
SystemMidiBinding snapshot5MidiBinding;
SystemMidiBinding snapshot6MidiBinding;
SystemMidiBinding nextSnapshotMidiBinding;
SystemMidiBinding prevSnapshotMidiBinding;
SystemMidiBinding startHotspotMidiBinding;
SystemMidiBinding stopHotspotMidiBinding;
SystemMidiBinding rebootMidiBinding;
@@ -1015,6 +1017,18 @@ private:
midiProgramChangePending = true;
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId), -1);
}
else if (nextSnapshotMidiBinding.IsTriggered(event))
{
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
midiProgramChangePending = true;
this->realtimeWriter.OnNextMidiSnapshot(++(this->midiProgramChangeId), 1);
}
else if (prevSnapshotMidiBinding.IsTriggered(event))
{
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
midiProgramChangePending = true;
this->realtimeWriter.OnNextMidiSnapshot(++(this->midiProgramChangeId), -1);
}
else if (shutdownMidiBinding.IsTriggered(event))
{
@@ -1737,6 +1751,12 @@ public:
hostReader.read(&request);
pNotifyCallbacks->OnNotifyNextMidiBank(request);
}
else if (command == RingBufferCommand::NextMidiSnapshot)
{
RealtimeNextMidiProgramRequest request;
hostReader.read(&request);
pNotifyCallbacks->OnNotifyNextMidiSnapshot(request);
}
else if (command == RingBufferCommand::RealtimeMidiEvent)
{
@@ -2423,6 +2443,14 @@ void AudioHostImpl::SetSystemMidiBindings(const std::vector<MidiBinding> &bindin
{
this->snapshot6MidiBinding.SetBinding(*i);
}
else if (i->symbol() == "nextSnapshot")
{
this->nextSnapshotMidiBinding.SetBinding(*i);
}
else if (i->symbol() == "prevSnapshot")
{
this->prevSnapshotMidiBinding.SetBinding(*i);
}
else
{
Lv2Log::error(SS("Invalid system midi binding: " << i->symbol()));
+1
View File
@@ -177,6 +177,7 @@ namespace pipedal
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest) = 0;
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request) = 0;
virtual void OnNotifyNextMidiBank(const RealtimeNextMidiProgramRequest &request) = 0;
virtual void OnNotifyNextMidiSnapshot(const RealtimeNextMidiProgramRequest &request) = 0;
virtual void OnNotifyLv2RealtimeError(int64_t instanceId, const std::string &error) = 0;
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) = 0;
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) = 0;
+1
View File
@@ -19,6 +19,7 @@
#include "AuxIn.hpp"
#include <unistd.h>
using namespace pipedal;
int main(int argc, char**argv) {
+63 -9
View File
@@ -22,6 +22,38 @@ set(CXX_STANDARD 20)
find_package(PkgConfig REQUIRED)
find_package(Catch2 QUIET)
# Catch2 Arch and Debian13 provide catch2 v3, with multi-headers under catch2
# Catch2 Debian12 provides catch2 v2, with a single header.
# When Catch2 v3 is found via CMake, generate compatibility wrappers so
# old-style #include "catch.hpp" and #include <catch/catch.hpp> still work.
if(Catch2_FOUND)
if(Catch2_VERSION VERSION_GREATER_EQUAL "3.0.0") # Generate catch.hpp wrapper in the build directory.
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/catch.hpp"
"#pragma once\n"
"#include <catch2/catch_all.hpp>\n"
)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/catch")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/catch/catch.hpp"
"#pragma once\n"
"#include <catch2/catch_all.hpp>\n"
)
# Add the build directory to the global include paths so that
# both #include "catch.hpp" (quote) and #include <catch/catch.hpp> (angle)
# can find the compatibility wrappers.
include_directories(${CMAKE_CURRENT_BINARY_DIR})
message(STATUS "Catch2 v3 found. Generated compatibility wrappers in ${CMAKE_CURRENT_BINARY_DIR}")
elseif(Catch2_VERSION VERSION_GREATER_EQUAL "2.0.0") # Generate catch.hpp wrapper in the build directory.
# Just use the system version directly.
message(STATUS "Catch2 v2 found. Using system catch2/catch.hpp directly.")
else()
message(ERROR "Catch2: Unsupported Catch2 version: ${Catch2_VERSION}. Expecting Catch2 v2 or v3.")
endif()
else()
message(ERROR "Catch2 CMake package not found. Expecting system catch.hpp (Catch2 v2 style).")
endif()
pkg_check_modules(PipeWire REQUIRED libpipewire-0.3)
include(FetchContent)
@@ -155,15 +187,27 @@ else()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar -Wno-psabi")
endif()
execute_process( COMMAND dpkg --print-architecture COMMAND tr -d '\n' OUTPUT_VARIABLE DEBIAN_ARCHITECTURE )
message(STATUS DEBIAN_ARCHITECTURE="${DEBIAN_ARCHITECTURE}")
# Determine Debian-compatible architecture name (portable across distros)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
set(DEBIAN_ARCHITECTURE "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
set(DEBIAN_ARCHITECTURE "arm64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7l")
set(DEBIAN_ARCHITECTURE "armhf")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686")
set(DEBIAN_ARCHITECTURE "i386")
else()
execute_process(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE UNAME_M)
message(FATAL_ERROR "Cannot determine Debian architecture from CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR} (uname -m: ${UNAME_M})")
endif()
message(STATUS "DEBIAN_ARCHITECTURE=${DEBIAN_ARCHITECTURE}")
add_compile_definitions(DEBIAN_ARCHITECTURE="${DEBIAN_ARCHITECTURE}")
if (CMAKE_BUILD_TYPE MATCHES Debug)
message(STATUS "Debug build")
# Must not -D_GLIBCXX_DEBUG, since it conflict with SQLiteCpp.lol
# Must not -D_GLIBCXX_DEBUG, since it conflict with SQLiteCpp
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -DDEBUG " )
if (USE_SANITIZE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -static-libasan " )
@@ -460,6 +504,10 @@ add_executable(pipedaltest
target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS} ${ICU_LIBRARIES})
target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES})
if(Catch2_FOUND)
target_link_libraries(pipedaltest PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
endif()
set_target_properties(pipedaltest PROPERTIES EXCLUDE_FROM_ALL ${PIPEDAL_EXCLUDE_TESTS})
if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action servers.
@@ -490,6 +538,10 @@ add_executable(jsonTest
target_link_libraries(jsonTest PRIVATE PiPedalCommon)
target_include_directories(jsonTest PRIVATE ${PIPEDAL_INCLUDES})
if(Catch2_FOUND)
target_link_libraries(jsonTest PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
endif()
set_target_properties(jsonTest PROPERTIES EXCLUDE_FROM_ALL ${PIPEDAL_EXCLUDE_TESTS})
@@ -856,8 +908,8 @@ elseif(EXISTS "/usr/share/doc/libboost1.71-dev")
set (BOOST_COPYRIGHT_DIR "libboost1.71-dev")
elseif(EXISTS "/usr/share/doc/libboost1.67-dev")
set (BOOST_COPYRIGHT_DIR "libboost1.67-dev")
else()
message(FATAL_ERROR "Boost libary version has changed. Please update me.")
# else()
# message(FATAL_ERROR "Boost libary version has changed. Please update me.")
endif()
@@ -871,10 +923,12 @@ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Updating copyright notices."
)
add_custom_target (
CopyrightBuild ALL
DEPENDS ${REACT_NOTICES_FILE}
)
if(NOT PIPEDAL_DISABLE_COPYRIGHT_BUILD)
add_custom_target (
CopyrightBuild ALL
DEPENDS ${REACT_NOTICES_FILE}
)
endif()
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.31)
cmake_policy(SET CMP0177 NEW)
+1
View File
@@ -1154,6 +1154,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
// Add to audio groups.
sysExec(USERMOD_BIN " -a -G " AUDIO_SERVICE_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// add to netdev group
sysExec(GROUPADD_BIN " -f " NETDEV_GROUP_NAME);
sysExec(USERMOD_BIN " -a -G " NETDEV_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
try
+1
View File
@@ -21,6 +21,7 @@
#include "util.hpp"
#include <stdexcept>
#include <iostream>
#include <mutex>
#include "ss.hpp"
#include "MimeTypes.hpp"
+86
View File
@@ -1181,6 +1181,92 @@ void PiPedalModel::NextPreset(Direction direction)
LoadPreset(-1, index.presets()[currentPresetIndex].instanceId());
}
void PiPedalModel::NextSnapshot(Direction direction)
{
std::lock_guard<std::recursive_mutex> guard{mutex};
auto &snapshots = this->pedalboard.snapshots();
if (snapshots.size() == 0)
{
return;
}
int64_t currentSnapshot = this->pedalboard.selectedSnapshot();
int64_t nextSnapshot = -1;
if (direction == Direction::Increase)
{
for (int64_t i = currentSnapshot + 1; i < (int64_t)snapshots.size(); ++i)
{
if (snapshots[i])
{
nextSnapshot = i;
break;
}
}
if (nextSnapshot == -1)
{
for (int64_t i = 0; i <= currentSnapshot && i < (int64_t)snapshots.size(); ++i)
{
if (snapshots[i])
{
nextSnapshot = i;
break;
}
}
}
}
else
{
for (int64_t i = currentSnapshot - 1; i >= 0; --i)
{
if (snapshots[i])
{
nextSnapshot = i;
break;
}
}
if (nextSnapshot == -1)
{
for (int64_t i = (int64_t)snapshots.size() - 1; i > currentSnapshot; --i)
{
if (snapshots[i])
{
nextSnapshot = i;
break;
}
}
}
}
if (nextSnapshot != -1 && nextSnapshot != currentSnapshot)
{
SetSnapshot(nextSnapshot);
}
}
void PiPedalModel::OnNotifyNextMidiSnapshot(const RealtimeNextMidiProgramRequest &request)
{
std::lock_guard<std::recursive_mutex> guard{mutex};
try
{
if (request.direction >= 0)
{
NextSnapshot();
}
else
{
PreviousSnapshot();
}
}
catch (std::exception &e)
{
Lv2Log::error(e.what());
}
if (this->audioHost)
{
this->audioHost->AckMidiProgramRequest(request.requestId);
}
}
void PiPedalModel::OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request)
{
std::lock_guard<std::recursive_mutex> guard{mutex};
+3
View File
@@ -273,6 +273,7 @@ namespace pipedal
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest) override;
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request) override;
virtual void OnNotifyNextMidiBank(const RealtimeNextMidiProgramRequest &request) override;
virtual void OnNotifyNextMidiSnapshot(const RealtimeNextMidiProgramRequest &request) override;
virtual void OnNotifyLv2RealtimeError(int64_t instanceId, const std::string &error) override;
PostHandle networkChangingDelayHandle = 0;
@@ -311,6 +312,8 @@ namespace pipedal
void PreviousBank() { NextBank(Direction::Decrease); }
void NextPreset(Direction direction = Direction::Increase);
void PreviousPreset() { NextPreset(Direction::Decrease); }
void NextSnapshot(Direction direction = Direction::Increase);
void PreviousSnapshot() { NextSnapshot(Direction::Decrease); }
int64_t DownloadModelsFromTone3000(
const std::string &responseuri,
+6
View File
@@ -83,6 +83,7 @@ namespace pipedal
NextMidiProgram,
NextMidiBank,
NextMidiSnapshot,
Lv2StateChanged,
MaybeLv2StateChanged,
@@ -444,6 +445,11 @@ namespace pipedal
RealtimeNextMidiProgramRequest msg{requestId : requestId, direction : direction};
write(RingBufferCommand::NextMidiBank, msg);
}
void OnNextMidiSnapshot(int64_t requestId, int32_t direction)
{
RealtimeNextMidiProgramRequest msg{requestId : requestId, direction : direction};
write(RingBufferCommand::NextMidiSnapshot, msg);
}
void SetControlValue(int effectIndex, int controlIndex, float value)
{
+3
View File
@@ -2213,6 +2213,9 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
result.push_back(MidiBinding::SystemBinding("snapshot5"));
result.push_back(MidiBinding::SystemBinding("snapshot6"));
result.push_back(MidiBinding::SystemBinding("prevSnapshot"));
result.push_back(MidiBinding::SystemBinding("nextSnapshot"));
result.push_back(MidiBinding::SystemBinding("stopHotspot"));
result.push_back(MidiBinding::SystemBinding("startHotspot"));
result.push_back(MidiBinding::SystemBinding("shutdown"));
+1
View File
@@ -55,6 +55,7 @@
#include <atomic>
#include "BootConfig.hpp"
#include <array>
#include <unistd.h>
#include "CommandLineParser.hpp"
#include "PrettyPrinter.hpp"
#include "SysExec.hpp"
+1 -1
View File
@@ -293,7 +293,7 @@ add_custom_command(
src/pipedal/IconColorDropdownButton.tsx
src/pipedal/PluginOutputControl.tsx
src/pipedal/PluginPresetsDialog.tsx
src/pipedal/JackServerSettingsDialog.tsx
src/pipedal/AudioDeviceDialog.tsx
src/pipedal/TextInfo_RewriteT3kUrls.ts
src/pipedal/MidiBindingsDialog.tsx
src/pipedal/DialogStack.tsx
+8
View File
@@ -83,6 +83,14 @@ export default class AlsaDeviceInfo {
}
return result;
}
shortDeviceName() : string {
// The best device names for USB devices are buried in the long name, so we try to extract them if we can.
let pos = this.longName.indexOf(" at usb-");
if (pos > 0) {
return this.longName.substring(0, pos);
}
return this.name;
}
cardId: number = -1;
id: string = "";
@@ -67,7 +67,7 @@ function sortDevices(devices: AlsaDeviceInfo[]): AlsaDeviceInfo[] {
let ca = category(a);
let cb = category(b);
if (ca !== cb) return ca - cb;
return a.name.localeCompare(b.name);
return a.shortDeviceName().localeCompare(b.shortDeviceName());
});
return copy;
}
@@ -91,7 +91,7 @@ enum WarningDialogType {
Apply,
Ok,
};
interface JackServerSettingsDialogState {
interface AudioDeviceDialogState {
latencyText: string;
jackServerSettings: JackServerSettings;
jackHostStatus?: JackHostStatus;
@@ -117,7 +117,7 @@ const styles = (theme: Theme) =>
whiteSpace: "nowrap"
}
});
export interface JackServerSettingsDialogProps extends WithStyles<typeof styles> {
export interface AudioDeviceDialogProps extends WithStyles<typeof styles> {
open: boolean;
jackServerSettings: JackServerSettings;
onClose: () => void;
@@ -287,12 +287,12 @@ function isOkEnabled(jackServerSettings: JackServerSettings, alsaDevices?: AlsaD
}
const JackServerSettingsDialog = withStyles(
class extends ResizeResponsiveComponent<JackServerSettingsDialogProps, JackServerSettingsDialogState> {
const AudioDeviceDialog = withStyles(
class extends ResizeResponsiveComponent<AudioDeviceDialogProps, AudioDeviceDialogState> {
model: PiPedalModel;
constructor(props: JackServerSettingsDialogProps) {
constructor(props: AudioDeviceDialogProps) {
super(props);
this.model = PiPedalModelFactory.getInstance();
@@ -456,7 +456,7 @@ const JackServerSettingsDialog = withStyles(
}
componentDidUpdate(oldProps: JackServerSettingsDialogProps) {
componentDidUpdate(oldProps: AudioDeviceDialogProps) {
this.updateActive();
}
@@ -584,7 +584,7 @@ const JackServerSettingsDialog = withStyles(
if (!this.state.alsaDevices) return deviceId;
for (let i = 0; i < this.state.alsaDevices.length; ++i) {
if (this.state.alsaDevices[i].id === deviceId) {
return this.state.alsaDevices[i].name;
return this.state.alsaDevices[i].shortDeviceName();
}
}
return deviceId;
@@ -673,7 +673,7 @@ const JackServerSettingsDialog = withStyles(
<MenuItem key={d.id} disabled={d.captureBusy}
value={d.id}
style={{ opacity: d.captureBusy ? 0.3 : 1 }}
>{d.name}</MenuItem>
>{d.shortDeviceName()}</MenuItem>
))}
</Select>
</FormControl>
@@ -695,7 +695,7 @@ const JackServerSettingsDialog = withStyles(
<MenuItem key={d.id} value={d.id}
style={{ opacity: d.playbackBusy ? 0.3 : 1.0 }}
disabled={d.playbackBusy}
>{d.name}</MenuItem>
>{d.shortDeviceName()}</MenuItem>
))}
</Select>
</FormControl>
@@ -819,4 +819,4 @@ const JackServerSettingsDialog = withStyles(
},
styles);
export default JackServerSettingsDialog;
export default AudioDeviceDialog;
+2
View File
@@ -251,6 +251,7 @@ const Draggable =
if (this.pointerType !== "touch") {
this.dragTarget.style.transform = "scale(" + SELECT_SCALE + ")";
this.dragTarget.style.zIndex = "3";
this.dragTarget.style.position = "absolute";
}
}
}
@@ -259,6 +260,7 @@ const Draggable =
element.style.transform = "";
element.style.zIndex = this.savedIndex;
element.style.opacity = this.savedOpacity;
element.style.position = "relative";
}
onPointerCancel(e: PointerEvent<HTMLDivElement>) {
+90 -57
View File
@@ -1,4 +1,5 @@
// Copyright (c) Robin E.R. Davies
// Copyright (c) 2022 Robin Davies
// Copyright (c) Fulgencio Ruiz Rubio.
//
// 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
@@ -835,15 +836,44 @@ export class UiControl implements Deserializable<UiControl> {
valueToRange(value: number): number {
if (this.toggled_property) return value === 0 ? 0 : 1;
if (this.integer_property || this.enumeration_property) {
value = Math.round(value);
}
let range = (value - this.min_value) / (this.max_value - this.min_value);
let range: number;
if (this.is_logarithmic) {
let minValue = this.min_value;
if (minValue === 0) // LSP plugins do this.
{
minValue = 0.0001;
}
range = Math.log(value / minValue) / Math.log(this.max_value / minValue);
if (!isFinite(range)) {
if (range < 0) {
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
if (this.range_steps > 1) {
range = Math.round(range * (this.range_steps - 1)) / (this.range_steps - 1);
}
} else {
range = (value - this.min_value) / (this.max_value - this.min_value);
if (!isFinite(range)) {
if (range < 0) {
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
}
if (range > 1) range = 1;
if (range < 0) range = 0;
return range;
}
@@ -852,17 +882,67 @@ export class UiControl implements Deserializable<UiControl> {
if (range > 1) range = 1;
if (this.toggled_property) return range === 0 ? 0 : 1;
if (this.range_steps > 1) {
range = Math.round(range * (this.range_steps - 1)) / (this.range_steps - 1);
}
let value: number;
let value = range * (this.max_value - this.min_value) + this.min_value;
if (this.integer_property || this.enumeration_property) {
value = Math.round(value);
if (this.min_value === this.max_value) {
value = this.min_value;
} else {
if (this.is_logarithmic) {
let minValue = this.min_value;
if (minValue === 0) // LSP controls.
{
minValue = 0.0001;
}
value = minValue * Math.pow(this.max_value / minValue, range);
if (!isFinite(value)) {
value = this.max_value;
} else if (isNaN(value)) {
value = this.min_value;
}
} else {
value = range * (this.max_value - this.min_value) + this.min_value;
}
if (this.integer_property) {
value = Math.round(value);
}
}
return value;
}
clampValue(value: number): number {
return this.rangeToValue(this.valueToRange(value));
}
getDisplayUnits(): string {
if (this.custom_units !== "") {
return this.custom_units.replace("%f", "");
}
switch (this.units) {
case Units.bar: return "bar";
case Units.beat: return "beats";
case Units.bpm: return "bpm";
case Units.cent: return "cents";
case Units.cm: return "cm";
case Units.db: return "dB";
case Units.hz: return "Hz";
case Units.khz: return "kHz";
case Units.km: return "km";
case Units.m: return "m";
case Units.mhz: return "MHz";
case Units.midiNote: return "MIDI note";
case Units.min: return "min";
case Units.ms: return "ms";
case Units.pc: return "%";
case Units.s: return "s";
case Units.semitone12TET: return "st";
default: return "";
}
}
formatDisplayValue(value: number): string {
if (this.integer_property) {
value = Math.round(value);
@@ -893,56 +973,9 @@ export class UiControl implements Deserializable<UiControl> {
return semitone12TETValue(value);
}
let text = this.formatShortValue(value);
switch (this.units) {
case Units.bpm:
text += "bpm";
break;
case Units.cent:
text += "cents";
break;
case Units.cm:
text += "cm";
break;
case Units.db:
text += "dB";
break;
case Units.hz:
text += "Hz";
break;
case Units.khz:
text += "kHz";
break;
case Units.km:
text += "km";
break;
case Units.m:
text += "m";
break;
case Units.mhz:
text += "MHz";
break;
case Units.min:
text += "min";
break;
case Units.ms:
text += "ms";
break;
case Units.pc:
text += "%";
break;
case Units.unknown:
if (this.custom_units !== "") {
text = this.custom_units.replace("%f", text);
}
break;
default:
break;
}
return text;
return this.formatShortValue(value) + this.getDisplayUnits();
}
formatShortValue(value: number): string {
if (this.enumeration_property) {
for (let i = 0; i < this.scale_points.length; ++i) {
+40 -10
View File
@@ -1,4 +1,5 @@
// Copyright (c) Robin E.R. Davies
// Copyright (c) 2022 Robin Davies
// Copyright (c) Fulgencio Ruiz Rubio.
//
// 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
@@ -25,7 +26,7 @@ import { withStyles } from "tss-react/mui";
import { createStyles } from './WithStyles';
import Snackbar from '@mui/material/Snackbar';
import { UiPlugin } from './Lv2Plugin';
import { UiPlugin, UiControl } from './Lv2Plugin';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
@@ -96,6 +97,7 @@ interface MidiBindingViewProps extends WithStyles<typeof styles> {
midiBinding: MidiBinding;
midiControlType: MidiControlType;
canDoTapTempo: boolean;
uiControl?: UiControl;
onChange: (instanceId: number, newBinding: MidiBinding) => void;
}
@@ -188,15 +190,28 @@ const MidiBindingView =
this.props.onChange(this.props.instanceId, newBinding);
}
handleMinChange(value: number): void {
if (!this.props.uiControl) return;
let newBinding = this.props.midiBinding.clone();
newBinding.minValue = value;
newBinding.minValue = this.props.uiControl.valueToRange(value) ;
this.props.onChange(this.props.instanceId, newBinding);
}
handleMaxChange(value: number): void {
if (!this.props.uiControl) return;
let newBinding = this.props.midiBinding.clone();
newBinding.maxValue = value;
newBinding.maxValue = this.props.uiControl.valueToRange(value);
console.log(value, newBinding.maxValue)
this.props.onChange(this.props.instanceId, newBinding);
}
private getDisplayUnit(): string {
let control = this.props.uiControl;
if (!control) return "";
if (control.custom_units !== "") {
return control.custom_units.replace("%f", "");
}
return ` ${control.getDisplayUnits()}`
}
handleCtlMinChange(value: number): void {
let newBinding = this.props.midiBinding.clone();
newBinding.minControlValue = Math.round(value);
@@ -638,21 +653,36 @@ const MidiBindingView =
)
}
{
showLinearRange && (
showLinearRange && (() => {
let uiControl = this.props.uiControl;
let displayMin = uiControl ? uiControl.min_value : 0;
let displayMax = uiControl ? uiControl.max_value : 1;
let unit = this.getDisplayUnit();
let isInteger = uiControl?.integer_property ?? false;
return (
<div style={{ display: "flex", flexFlow: "row wrap", alignItems: "center" }}>
<div className={classes.controlDiv}>
<Typography noWrap display="inline">Min Val:&nbsp;</Typography>
<NumericInput value={midiBinding.minValue} ariaLabel='min'
min={0} max={1} onChange={(value) => { this.handleMinChange(value); }}
<NumericInput value={this.props.uiControl?.rangeToValue(midiBinding.minValue) ?? 0} ariaLabel='min'
min={displayMin} max={displayMax} integer={isInteger}
onChange={(value) => { this.handleMinChange(value); }}
/>
{unit !== "" && (
<Typography noWrap display="inline">&nbsp;{unit.trim()}</Typography>
)}
</div>
<div className={classes.controlDiv}>
<Typography noWrap display="inline">Max Val:&nbsp;</Typography>
<NumericInput value={midiBinding.maxValue} ariaLabel='max'
min={0} max={1} onChange={(value) => { this.handleMaxChange(value); }} />
<NumericInput value={this.props.uiControl?.rangeToValue(midiBinding.maxValue) ?? 0} ariaLabel='max'
min={displayMin} max={displayMax} integer={isInteger}
onChange={(value) => { this.handleMaxChange(value); }} />
{unit !== "" && (
<Typography noWrap display="inline">&nbsp;{unit.trim()}</Typography>
)}
</div>
</div>
)
);
})()
}
{
canRotaryScale && (
+2
View File
@@ -214,6 +214,7 @@ export const MidiBindingDialog =
midiControlType={ getMidiControlType(plugin, "__bypass")
}
canDoTapTempo={false }
uiControl={plugin.getControl("__bypass")}
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
/>
</td>
@@ -258,6 +259,7 @@ export const MidiBindingDialog =
midiControlType={getMidiControlType(plugin, symbol)}
midiBinding={item.getMidiBinding(symbol)}
canDoTapTempo={canDoTapTempo(plugin, symbol)}
uiControl={control}
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
/>
</td>
+8 -103
View File
@@ -862,7 +862,7 @@ class FilmstripControl implements ModGuiControl {
console.error("pipedal: Invalid mod-widget-rotation value: " + rotationAttr);
return;
}
let range = this.valueToRange(this.value);
let range = this.props.pluginControl.valueToRange(this.value);
this.frameElement.style.transform = `rotate(${rotation * range - rotation / 2}deg)`;
return;
@@ -926,13 +926,13 @@ class FilmstripControl implements ModGuiControl {
let pluginControl = this.props.pluginControl;
let value = this.isPointerDown ? this.pointerDownValue : this.value;
value = this.clampValue(value);
value = this.props.pluginControl.clampValue(value);
let isHorizontalStrip =
this.filmstripInfo.frameWidth / this.filmstripInfo.frameHeight
< this.filmstripInfo.width / this.filmstripInfo.height;
if (isHorizontalStrip) {
let range = this.valueToRange(value);
let range = this.props.pluginControl.valueToRange(value);
if (range < 0) {
range = 0;
@@ -1045,101 +1045,6 @@ class FilmstripControl implements ModGuiControl {
this.pointerDownValue = this.value;
}
valueToRange(value: number): number {
let uiControl = this.props.pluginControl;
if (uiControl) {
let range: number;
if (uiControl.is_logarithmic) {
let minValue = uiControl.min_value;
if (minValue === 0) // LSP plugins do this.
{
minValue = 0.0001;
}
range = Math.log(value / minValue) / Math.log(uiControl.max_value / minValue);
if (!isFinite(range)) {
if (range < 0) {
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
} else {
range = (value - uiControl.min_value) / (uiControl.max_value - uiControl.min_value);
if (!isFinite(range)) {
if (range < 0) {
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
}
if (range > 1) range = 1;
if (range < 0) range = 0;
return range;
}
return 0;
}
rangeToValue(range: number): number {
if (range < 0) range = 0;
if (range > 1) range = 1;
let uiControl = this.props.pluginControl;
if (uiControl) {
let value: number;
if (uiControl.min_value === uiControl.max_value) {
value = uiControl.min_value;
} else {
if (uiControl.is_logarithmic) {
let minValue = uiControl.min_value;
if (minValue === 0) // LSP controls.
{
minValue = 0.0001;
}
value = minValue * Math.pow(uiControl.max_value / minValue, range);
if (!isFinite(value)) {
value = uiControl.max_value;
} else if (isNaN(value)) {
value = uiControl.min_value;
}
} else {
value = range * (uiControl.max_value - uiControl.min_value) + uiControl.min_value;
}
}
return value;
}
return 0;
}
clampValue(value: number): number {
let control = this.props.pluginControl;
if (control.enumeration_property) {
value = control.clampSelectValue(value);
} else if (control.toggled_property) {
if (value < (control.min_value + control.max_value) / 2) {
value = control.min_value;
} else {
value = control.max_value;
}
} else if (control.integer_property) {
value = Math.round(value);
} else if (control.range_steps != 0) {
let step = (control.max_value - control.min_value) / control.range_steps;
value = Math.round((value - control.min_value) / step) * step + control.min_value;
}
if (value < control.min_value) {
value = control.min_value;
}
if (value > control.max_value) {
value = control.max_value;
}
return value;
}
handlePointerMove(event: PointerEvent) {
if (!this.frameElement) {
return; // Not mounted yet
@@ -1167,14 +1072,14 @@ class FilmstripControl implements ModGuiControl {
let dRange = -dy / rate;
let range = this.valueToRange(this.pointerDownValue);
let range = this.props.pluginControl.valueToRange(this.pointerDownValue);
range += dRange;
if (range < 0) range = 0;
if (range > 1) range = 1;
let newValue = this.rangeToValue(range);
let newValue = this.props.pluginControl.rangeToValue(range);
this.pointerDownValue = newValue;
this.setControlValue(newValue);
this.props.onValueChanged(this.props.instanceId, this.props.pluginControl.symbol, this.clampValue(newValue));
this.props.onValueChanged(this.props.instanceId, this.props.pluginControl.symbol, this.props.pluginControl.clampValue(newValue));
}
handlePointerUp(event: PointerEvent) {
let index = this.pointerIds.indexOf(event.pointerId);
@@ -1229,11 +1134,11 @@ class FilmstripControl implements ModGuiControl {
}
let dRange = event.deltaY / rate;
let range = this.valueToRange(this.value);
let range = this.props.pluginControl.valueToRange(this.value);
range += dRange;
if (range < 0) range = 0;
if (range > 1) range = 1;
let newValue = this.rangeToValue(range);
let newValue = this.props.pluginControl.rangeToValue(range);
this.setControlValue(newValue);
this.props.onValueChanged(this.props.instanceId, this.props.pluginControl.symbol, newValue);
}
+45 -2
View File
@@ -59,7 +59,13 @@ export class ControlValue implements Deserializable<ControlValue> {
}
export class PedalboardItem implements Deserializable<PedalboardItem> {
clone() {
clone(): PedalboardItem {
if (this.isSplit())
{
let result = new PedalboardSplitItem();
result.deserialize(this);
return result as PedalboardItem;;
}
return new PedalboardItem().deserialize(this);
}
deserializePedalboardItem(input: any): PedalboardItem {
@@ -144,6 +150,23 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
}
isChild(instanceId: number): boolean {
if (this.instanceId === instanceId) return true;
if (this.isSplit())
{
let splitItem = this as unknown as PedalboardSplitItem;
for (let topItem of splitItem.topChain)
{
if (topItem.isChild(instanceId)) return true;
}
for (let bottomItem of splitItem.bottomChain)
{
if (bottomItem.isChild(instanceId)) return true;
}
}
return false;
}
getControlValue(key: string): number {
for (let i = 0; i < this.controlValues.length; ++i) {
let v = this.controlValues[i];
@@ -753,7 +776,20 @@ export class Pedalboard implements Deserializable<Pedalboard> {
}
return false;
}
assignNewInstanceIds(items: PedalboardItem[])
{
for (let i = 0; i < items.length; ++i)
{
items[i].instanceId = ++this.nextInstanceId;
if (items[i].isSplit())
{
let splitItem = items[i] as PedalboardSplitItem;
this.assignNewInstanceIds(splitItem.topChain);
this.assignNewInstanceIds(splitItem.bottomChain);
}
}
}
replaceItem(instanceId: number, newItem: PedalboardItem)
{
newItem.instanceId = ++this.nextInstanceId;
@@ -763,6 +799,13 @@ export class Pedalboard implements Deserializable<Pedalboard> {
{
throw new PiPedalArgumentError("instanceId not found.");
}
if (newItem.isSplit())
{
// Generate new instance ids for all children, to avoid conflicts.
let splitItem = newItem as PedalboardSplitItem;
this.assignNewInstanceIds(splitItem.topChain);
this.assignNewInstanceIds(splitItem.bottomChain);
}
return newItem.instanceId;
}
private _addItem(items: PedalboardItem[], newItem: PedalboardItem, instanceId: number, append: boolean)
+93 -45
View File
@@ -147,24 +147,36 @@ const pedalboardStyles = (theme: Theme) => createStyles({
top: -6,
fill: theme.palette.text.secondary
}),
iconFrame: css({
display: "flex",
alignItems: "center",
justifyContent: "center",
pedalButton: css({
position: "relative",
background: theme.palette.background.default,
marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2,
marginRight: (CELL_WIDTH - FRAME_SIZE) / 2,
marginTop: (CELL_HEIGHT - FRAME_SIZE) / 2,
marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2,
width: FRAME_SIZE,
height: FRAME_SIZE,
padding: 0,
borderRadius: 8
}),
iconFrame: css({
display: "flex",
alignItems: "center",
justifyContent: "center",
position: "relative",
background: theme.palette.background.paper,
width: FRAME_SIZE,
height: FRAME_SIZE,
borderColor: "#777",
borderWidth: 2,
borderStyle: "solid",
padding: 1,
overflow: "hidden",
padding: 0,
borderRadius: 8
}),
selectedIconFrame: css({
@@ -173,12 +185,7 @@ const pedalboardStyles = (theme: Theme) => createStyles({
alignItems: "center",
justifyContent: "center",
position: "relative",
background: theme.palette.background.default,
marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2,
marginRight: (CELL_WIDTH - FRAME_SIZE) / 2,
marginTop: (CELL_HEIGHT - FRAME_SIZE) / 2,
marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2,
background: theme.palette.background.paper,
width: FRAME_SIZE,
height: FRAME_SIZE,
borderColor: theme.palette.primary.main,
@@ -195,10 +202,6 @@ const pedalboardStyles = (theme: Theme) => createStyles({
justifyContent: "center",
background: "transparent",
marginLeft: (CELL_WIDTH - FRAME_SIZE) / 2,
marginRight: (CELL_WIDTH - FRAME_SIZE) / 2,
marginTop: (CELL_HEIGHT - FRAME_SIZE) / 2,
marginBottom: (CELL_HEIGHT - FRAME_SIZE) / 2,
width: FRAME_SIZE,
height: FRAME_SIZE,
border: "0px #666 solid",
@@ -458,6 +461,20 @@ const PedalboardView =
// touchyMove. :-/
}
isSplitterChild(item: PedalboardItem, splitterInstanceId: number) {
if (item.instanceId === splitterInstanceId) {
return true;
}
let pedalboard: Pedalboard | undefined = this.state.pedalboard;
if (!pedalboard) return false;
let splitter = pedalboard.maybeGetItem(splitterInstanceId);
if (splitter === null) {
return false;
}
return splitter.isChild(item.instanceId);
}
onDragEnd(instanceId: number, clientX: number, clientY: number) {
if (!this.props.enableStructureEditing) {
return;
@@ -483,10 +500,18 @@ const PedalboardView =
if (item.isSplitter() && item.pedalItem) {
if (item.bounds.contains(clientX, clientY)) {
if (clientX < item.bounds.x + CELL_WIDTH / 2) {
if (this.isSplitterChild(item.pedalItem, instanceId))
{
return;
}
this.model.movePedalboardItemBefore(instanceId, item.pedalItem.instanceId);
this.setSelection(instanceId);
return;
} else if (clientX > item.bounds.right - CELL_WIDTH / 2) {
if (this.isSplitterChild(item.pedalItem, instanceId))
{
return;
}
this.model.movePedalboardItemAfter(instanceId, item.pedalItem.instanceId);
this.setSelection(instanceId);
return;
@@ -501,6 +526,11 @@ const PedalboardView =
if (clientX < item.topChildren[0].bounds.x) {
let topPedalItem = item.topChildren[0].pedalItem;
if (topPedalItem) {
if (this.isSplitterChild(topPedalItem, instanceId))
{
return;
}
this.model.movePedalboardItemBefore(instanceId, topPedalItem.instanceId);
this.setSelection(instanceId);
return;
@@ -509,6 +539,9 @@ const PedalboardView =
let lastTop = item.topChildren[item.topChildren.length - 1];
if (clientX >= lastTop.bounds.right && clientX < item.bounds.right - CELL_WIDTH / 2) {
if (lastTop.pedalItem) {
if (this.isSplitterChild(lastTop.pedalItem, instanceId)) {
return;
}
this.model.movePedalboardItemAfter(instanceId, lastTop.pedalItem.instanceId);
this.setSelection(instanceId);
return;
@@ -522,6 +555,9 @@ const PedalboardView =
if (clientX < item.bottomChildren[0].bounds.x) {
let bottomPedalItem = item.bottomChildren[0].pedalItem;
if (bottomPedalItem) {
if (this.isSplitterChild(bottomPedalItem, instanceId)) {
return;
}
this.model.movePedalboardItemBefore(instanceId, bottomPedalItem.instanceId);
this.setSelection(instanceId);
return;
@@ -530,6 +566,9 @@ const PedalboardView =
let lastBottom = item.bottomChildren[item.bottomChildren.length - 1];
if (clientX >= lastBottom.bounds.right && clientX < item.bounds.right - CELL_WIDTH / 2) {
if (lastBottom.pedalItem) {
if (this.isSplitterChild(lastBottom.pedalItem, instanceId)) {
return;
}
this.model.movePedalboardItemAfter(instanceId, lastBottom.pedalItem.instanceId);
this.setSelection(instanceId);
return;
@@ -552,10 +591,22 @@ const PedalboardView =
if (item.pedalItem) {
let margin = (CELL_WIDTH - FRAME_SIZE) / 2;
if (clientX < item.bounds.x + margin) {
if (this.isSplitterChild(item.pedalItem,instanceId))
{
return;
}
this.model.movePedalboardItemBefore(instanceId, item.pedalItem.instanceId);
} else if (clientX > item.bounds.right - margin) {
if (this.isSplitterChild(item.pedalItem,instanceId))
{
return;
}
this.model.movePedalboardItemAfter(instanceId, item.pedalItem.instanceId);
} else {
if (this.isSplitterChild(item.pedalItem,instanceId))
{
return;
}
this.model.movePedalboardItem(instanceId, item.pedalItem.instanceId);
}
this.setSelection(instanceId);
@@ -1036,39 +1087,35 @@ const PedalboardView =
}
return (
<div className={frameStyle} onContextMenu={(e) => { e.preventDefault(); }}
>
{/* {!enabled && (
<div className={classes.midiConnectorDecoration} >
<CloseIcon style={{ width: 16, height: 16, opacity: 0.6, fill: this.props.theme.palette.text.secondary }} />
</div>
)} */}
<ButtonBase style={{ width: "100%", height: "100%" }}
<div style={{ width: "100%", height: "100%" }}>
<ButtonBase className={classes.pedalButton}
onClick={(e) => { this.onItemClick(e, instanceId); }}
onDoubleClick={(e: SyntheticEvent) => { this.onItemDoubleClick(e, instanceId); }}
onContextMenu={(e: SyntheticEvent) => { this.onItemLongClick(e, instanceId); }}
>
<SelectHoverBackground selected={instanceId === this.props.selectedId} showHover={true}
clipChildren={true}
<div className={frameStyle} style={{ position: "absolute" }} onContextMenu={(e) => { e.preventDefault(); }}
>
<Draggable draggable={draggable && (this.props.enableStructureEditing)} getScrollContainer={() => this.getScrollContainer()}
onDragEnd={(x, y) => { this.onDragEnd(instanceId, x, y) }}
style={{ opacity: enabled ? 0.99 : 0.3 }}
<SelectHoverBackground selected={instanceId === this.props.selectedId} showHover={true}
clipChildren={false}
>
<div id="childIcon" style={{ position: "relative", display: "flex", justifyContent: "center", alignItems: "center" }} >
<PluginIcon pluginType={iconType}
size={24}
color={getIconColor(iconColor)}
pluginMissing={pluginNotFound}
/>
</div>
</SelectHoverBackground>
</div>
<Draggable draggable={draggable && (this.props.enableStructureEditing)} getScrollContainer={() => this.getScrollContainer()}
onDragEnd={(x, y) => { this.onDragEnd(instanceId, x, y) }}
style={{ opacity: enabled ? 0.99 : 0.3 }}
</Draggable>
</SelectHoverBackground>
>
<div id="childIcon" style={{ position: "relative", display: "flex", justifyContent: "center", alignItems: "center" }} >
<PluginIcon pluginType={iconType}
size={24}
color={getIconColor(iconColor)}
pluginMissing={pluginNotFound}
/>
</div>
</Draggable>
</ButtonBase>
</div>
);
@@ -1146,7 +1193,7 @@ const PedalboardView =
result.push(<div key={this.renderKey++} className={classes.splitItem} style={{ left: item.bounds.x, top: item.bounds.y, width: item.bounds.width }} >
<div className={classes.splitStart} >
{this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), "", false, true, true, false, false)}
{this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), "", true, true, true, false, false)}
</div>
</div>);
@@ -1157,9 +1204,10 @@ const PedalboardView =
position: "absolute", left: item.bounds.x, width: CELL_WIDTH, top: item.bounds.bottom - 12, paddingLeft: 2, paddingRight: 2
}}>
<Typography variant="caption" display="block" noWrap={true}
style={{ width: CELL_WIDTH - 4, textAlign: "center", flex: "0 1 auto",
opacity: item.pedalItem?.isEnabled??true ? 1.0 : 0.4
}}
style={{
width: CELL_WIDTH - 4, textAlign: "center", flex: "0 1 auto",
opacity: item.pedalItem?.isEnabled ?? true ? 1.0 : 0.4
}}
>{item.name}</Typography>
</div>
)
+3 -1
View File
@@ -602,7 +602,9 @@ export class PiPedalModel //implements PiPedalModel
(
[
MidiBinding.systemBinding("prevProgram"),
MidiBinding.systemBinding("nextProgram")
MidiBinding.systemBinding("nextProgram"),
MidiBinding.systemBinding("prevSnapshot"),
MidiBinding.systemBinding("nextSnapshot")
]
);
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
+12 -106
View File
@@ -1,4 +1,5 @@
// Copyright (c) Robin E.R. Davies
// Copyright (c) 2022 Robin Davies
// Copyright (c) Fulgencio Ruiz Rubio.
//
// 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
@@ -203,7 +204,6 @@ const CustomPluginControl =
</div>
);
return (<div />);
}
},
@@ -342,8 +342,9 @@ const PluginControl =
result = this.currentValue; // reset the value!
}
// clamp and quantize.
let range = this.valueToRange(result);
result = this.rangeToValue(range);
let range = this.props.uiControl?.valueToRange(result) ?? 0;
result = this.props.uiControl?.rangeToValue(range) ?? 0;
let displayVal = this.props.uiControl?.formatShortValue(result) ?? "";
if (event.currentTarget) {
event.currentTarget.value = displayVal;
@@ -682,8 +683,8 @@ const PluginControl =
this.setState({ previewValue: undefined });
}
previewInputValue(value: number, commitValue: boolean) {
let range = this.valueToRange(value);
value = this.rangeToValue(range);
let range = this.props.uiControl?.valueToRange(value) ?? 0;
value = this.props.uiControl?.rangeToValue(range) ?? 0;
let imgElement = this.imgRef.current
if (imgElement) {
@@ -712,13 +713,13 @@ const PluginControl =
}
previewRange(dRange: number, commitValue: boolean): void {
let range = this.valueToRange(this.currentValue) + dRange;
let range = (this.props.uiControl?.valueToRange(this.currentValue) ?? 0) + dRange;
if (range > 1) range = 1;
if (range < 0) range = 0;
let value = this.rangeToValue(range);
let value = this.props.uiControl?.rangeToValue(range) ?? 0;
// apply value quantization and clipping.
range = this.valueToRange(value);
range = this.props.uiControl?.valueToRange(value) ?? 0;
if (this.props.uiControl?.isGraphicEq()) {
let imgElement = this.imgRef.current
@@ -835,89 +836,6 @@ const PluginControl =
if (!uiControl) return "";
return uiControl.formatDisplayValue(value);
}
valueToRange(value: number): number {
let uiControl = this.props.uiControl;
if (uiControl) {
if (uiControl.integer_property) {
value = Math.round(value);
}
let range: number;
if (uiControl.is_logarithmic) {
let minValue = uiControl.min_value;
if (minValue === 0) // LSP plugins do this.
{
minValue = 0.0001;
}
range = Math.log(value / minValue) / Math.log(uiControl.max_value / minValue);
if (!isFinite(range)) {
if (range < 0) {
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
if (uiControl.range_steps > 1) {
range = Math.round(range * (uiControl.range_steps - 1)) / (uiControl.range_steps - 1);
}
} else {
range = (value - uiControl.min_value) / (uiControl.max_value - uiControl.min_value);
if (!isFinite(range)) {
if (range < 0) {
range = 0;
} else {
range = 1.0;
}
} else if (isNaN(range)) {
range = 0;
}
}
if (range > 1) range = 1;
if (range < 0) range = 0;
return range;
}
return 0;
}
rangeToValue(range: number): number {
if (range < 0) range = 0;
if (range > 1) range = 1;
let uiControl = this.props.uiControl;
if (uiControl) {
if (uiControl.range_steps > 1) {
range = Math.round(range * (uiControl.range_steps - 1)) / (uiControl.range_steps - 1);
}
let value: number;
if (uiControl.min_value === uiControl.max_value) {
value = uiControl.min_value;
} else {
if (uiControl.is_logarithmic) {
let minValue = uiControl.min_value;
if (minValue === 0) // LSP controls.
{
minValue = 0.0001;
}
value = minValue * Math.pow(uiControl.max_value / minValue, range);
if (!isFinite(value)) {
value = uiControl.max_value;
} else if (isNaN(value)) {
value = uiControl.min_value;
}
} else {
value = range * (uiControl.max_value - uiControl.min_value) + uiControl.min_value;
}
if (uiControl.integer_property) {
value = Math.round(value);
}
}
return value;
}
return 0;
}
rangeToRotationTransform(range: number): string {
@@ -926,22 +844,10 @@ const PluginControl =
}
getEqPosition(): number {
let range = 0;
let uiControl = this.props.uiControl;
if (uiControl) {
let value = this.props.value;
range = this.valueToRange(value);
}
return range;
return this.props.uiControl?.valueToRange(this.props.value) ?? 0;
}
getRotationTransform(): string {
let range = 0;
let uiControl = this.props.uiControl;
if (uiControl) {
let value = this.props.value;
range = this.valueToRange(value);
}
let range = this.props.uiControl?.valueToRange(this.props.value) ?? 0;
return this.rangeToRotationTransform(range);
}
+22 -23
View File
@@ -114,7 +114,7 @@ const PluginPresetSelector =
hasPresets(pedalboardItem: PedalboardItem | null): boolean {
if (pedalboardItem === null) return false;
if (!pedalboardItem.uri) return false;
if (pedalboardItem.isStart() || pedalboardItem.isEnd()
if (pedalboardItem.isStart() || pedalboardItem.isEnd()
|| pedalboardItem.isEmpty() || pedalboardItem.isSplit()) {
return false;
}
@@ -123,8 +123,8 @@ const PluginPresetSelector =
isVisible(pedalboardItem: PedalboardItem | null): boolean {
if (pedalboardItem === null) return false;
if (!pedalboardItem.uri) return false;
if (pedalboardItem.isStart() || pedalboardItem.isEnd()
|| pedalboardItem.isSplit()) {
if (pedalboardItem.isStart() || pedalboardItem.isEnd()
) {
return false;
}
return true;
@@ -197,7 +197,7 @@ const PluginPresetSelector =
loadPresets(): void {
if (this.props.pedalboardItem === null) return;
if (!this.hasPresets(this.props.pedalboardItem)) return;
if (!this.hasPresets(this.props.pedalboardItem)) return;
let captureUri: string = this.props.pedalboardItem.uri;
this.model.getPluginPresets(captureUri)
.then((presets: PluginUiPresets) => {
@@ -235,20 +235,18 @@ const PluginPresetSelector =
currentPedalboard?: PedalboardItem;
componentDidUpdate(
prevProps: Readonly<PluginPresetSelectorProps>,
prevState: Readonly<PluginPresetSelectorState>,
snapshot?: any): void
{
prevProps: Readonly<PluginPresetSelectorProps>,
prevState: Readonly<PluginPresetSelectorState>,
snapshot?: any): void {
if (this.props.pedalboardItem !== prevProps.pedalboardItem) {
this.setState({
this.setState({
isVisible: this.isVisible(this.props.pedalboardItem),
hasPresets: this.hasPresets(this.props.pedalboardItem) });
hasPresets: this.hasPresets(this.props.pedalboardItem)
});
if (this.props.pedalboardItem) {
if (this.props.pedalboardItem.isEmpty())
{
if (this.props.pedalboardItem.isEmpty()) {
this.setState({ presets: new PluginUiPresets() });
} else
{
} else {
this.loadPresets();
}
}
@@ -272,7 +270,8 @@ const PluginPresetSelector =
}
isMenuCopyPluginEnabled(): boolean {
return this.state.hasPresets;
if (this.props.pedalboardItem === null) return false;
return !this.props.pedalboardItem.isEmpty();
}
handleMenuCopyPlugin(): void {
this.handlePresetsMenuClose();
@@ -340,7 +339,7 @@ const PluginPresetSelector =
}
buildMenuItems() {
let result : React.ReactNode[] = [];
let result: React.ReactNode[] = [];
if (this.state.hasPresets) {
result.push((<MenuItem key="menuSaveAs" onClick={(e) => this.handlePluginPresetsMenuSaveAs(e)}>Save plugin preset...</MenuItem>));
result.push((<MenuItem key="menuEdit" onClick={(e) => this.handleMenuEditPluginPresets()}>Manage plugin presets...</MenuItem>));
@@ -355,7 +354,7 @@ const PluginPresetSelector =
<PluginPresetIcon className={this.props.classes?.pluginMenuIcon ?? ""} />
{preset.label}</MenuItem>
));
));
hasPresets = true;
}
if (hasPresets) {
@@ -402,12 +401,12 @@ const PluginPresetSelector =
}
</Menu>
{this.state.hasPresets && this.state.showPresetsDialog && (
<PluginPresetsDialog
instanceId={this.props.instanceId}
presets={this.state.presets}
show={this.state.showPresetsDialog}
isEditDialog={this.state.showEditPresetsDialog}
onDialogClose={() => this.handleDialogClose()} />
<PluginPresetsDialog
instanceId={this.props.instanceId}
presets={this.state.presets}
show={this.state.showPresetsDialog}
isEditDialog={this.state.showEditPresetsDialog}
onDialogClose={() => this.handleDialogClose()} />
)}
<RenameDialog open={this.state.renameDialogOpen}
title="Rename"
+2 -2
View File
@@ -40,7 +40,7 @@ import SelectChannelsDialog from './SelectChannelsDialog';
import SelectMidiChannelsDialog from './SelectMidiChannelsDialog';
import SelectHoverBackground from './SelectHoverBackground';
import JackServerSettings from './JackServerSettings';
import JackServerSettingsDialog from './JackServerSettingsDialog';
import AudioDeviceDialog from './AudioDeviceDialog';
import JackHostStatus from './JackHostStatus';
import WifiConfigSettings from './WifiConfigSettings';
import WifiDirectConfigSettings from './WifiDirectConfigSettings';
@@ -711,7 +711,7 @@ const SettingsDialog = withStyles(
)}
{this.state.showJackServerSettingsDialog && (
<JackServerSettingsDialog
<AudioDeviceDialog
open={this.state.showJackServerSettingsDialog}
jackServerSettings={this.state.jackServerSettings}
onClose={() => this.setState({ showJackServerSettingsDialog: false })}
@@ -159,6 +159,11 @@ export const SystemMidiBindingDialog =
}
else if (item.symbol === "snapshot6") {
displayName = "Snapshot 6";
}
else if (item.symbol === "nextSnapshot") {
displayName = "Next Snapshot";
} else if (item.symbol === "prevSnapshot") {
displayName = "Previous Snapshot";
} else if (item.symbol === "startHotspot") {
displayName = "Enable Hotspot";
} else if (item.symbol === "stopHotspot") {
+1 -1
View File
@@ -20,7 +20,7 @@ export default defineConfig({
target: 'http://localhost:8080',
changeOrigin: false,
},
'^/var/(?!config\\.json$).*': {
'^/var/.*': {
target: 'http://localhost:8080',
changeOrigin: false,
},