v1.1.20 Release

This commit is contained in:
Robin Davies
2023-04-20 15:27:18 -04:00
parent e2b62da073
commit 37426d9047
117 changed files with 2147 additions and 711 deletions
+2 -1
View File
@@ -72,7 +72,8 @@
"args": [ "args": [
//"[Dev]" -- all dev-machine tests. //"[Dev]" -- all dev-machine tests.
"[json_variants]" // subtest of your choice, or none to run all of the tests. //"[json_variants]" // subtest of your choice, or none to run all of the tests.
"[inverting_mutex_test]"
], ],
"stopAtEntry": false, "stopAtEntry": false,
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.16.0)
project(pipedal project(pipedal
VERSION 1.0.19 VERSION 1.1.20
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
HOMEPAGE_URL "https://rerdavies.github.io/pipedal" HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
) )
set (DISPLAY_VERSION "v1.0.19") set (DISPLAY_VERSION "v1.1.20")
set (CMAKE_INSTALL_PREFIX "/usr/") set (CMAKE_INSTALL_PREFIX "/usr/")
+4 -1
View File
@@ -1,10 +1,13 @@
<img src='docs/GithubBanner.png' width="100%" /><br/> <img src='docs/GithubBanner.png' width="100%" /><br/>
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.0.19</a> Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.1.20</a>
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
<quote>
NEW version 1.1 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
</quote>
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet. Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats. PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/bash
# Copy current pipedal presets to provisioning directories.
rm -rf default_presets/plugin_presets
rm -rf default_presets/presets
mkdir default_presets/plugin_presets
mkdir default_presets/presets
cp -r /var/pipedal/plugin_presets default_presets/plugin_presets/
cp -r /var/pipedal/presets default_presets/presets/
+3 -3
View File
@@ -1,14 +1,14 @@
Architecture: arm64 Architecture: arm64
Depends: libstdc++6 (>= 9), libasound2 (>= 1.0.17), libc6 (>= 2.34), libgcc-s1 (>= 4.0), libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125, liblilv-0-0 (>= 0.22.0~dfsg0), libnl-3-200 (>= 3.2.7), libnl-genl-3-200 (>= 3.2.7), libstdc++6 (>= 11), libsystemd0 Depends: libstdc++6 (>= 9), libasound2 (>= 1.0.17), libc6 (>= 2.34), libgcc-s1 (>= 4.0), libjack-jackd2-0 (>= 1.9.10+20150825) | libjack-0.125, liblilv-0-0 (>= 0.22.0~dfsg0), libnl-3-200 (>= 3.2.7), libnl-genl-3-200 (>= 3.2.7), libstdc++6 (>= 11), libsystemd0, dnsmasq(>= 2.85)
Description: IoT guitar effect for Raspberry Pi Description: IoT guitar effect for Raspberry Pi
IoT guitar effect pedal for Raspberry Pi, with phone-friendly web interface. IoT guitar effect pedal for Raspberry Pi, with phone-friendly web interface.
Homepage: https://github.com/rerdavies/pipedal Homepage: https://github.com/rerdavies/pipedal
Maintainer: Robin E. R. Davies<rerdavies@gmail.com> Maintainer: Robin E. R. Davies<rerdavies@gmail.com>
Source: pipedal Source: pipedal
Package: pipedal Package: pipedal
Pre-Depends: hostapd;authbind Pre-Depends: hostapd;authbind;dnsmasq
Priority: optional Priority: optional
Section: sound Section: sound
Version: 1.0.19 Version: 1.1.20
Installed-Size: 15147 Installed-Size: 15147
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZaMaximX2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"ceil": 0,"rel": 25,"thresh": 0}}],"nextInstanceId": 2}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamGate","presets": [{"instanceId": 1,"label": "Default","controlValues": {"att": 50,"close": -50,"mak": 0,"mode": 0,"rel": 100,"sidechain": 0,"thr": -60}}],"nextInstanceId": 2}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamGateX2","presets": [{"instanceId": 1,"label": "Default","controlValues": {"att": 50,"close": -50,"mak": 0,"mode": 0,"rel": 100,"sidechain": 0,"thr": -60}}],"nextInstanceId": 2}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamGrains","presets": [ ],"nextInstanceId": 1}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamHeadX2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"az": 0,"elev": 0,"width": 1}}],"nextInstanceId": 2}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamPhono","presets": [ ],"nextInstanceId": 1}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamTube","presets": [ ],"nextInstanceId": 1}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamVerb","presets": [ ],"nextInstanceId": 1}
@@ -0,0 +1 @@
{"pluginUri": "http://two-play.com/plugins/toob-delay","presets": [{"instanceId": 1,"label": "Classic","controlValues": {"delay": 340,"feedback": 39.1666679,"level": 27}},{"instanceId": 2,"label": "Slapback","controlValues": {"delay": 94.6446991,"feedback": 39.1666679,"level": 42}}],"nextInstanceId": 3}
@@ -0,0 +1 @@
{"pluginUri": "http://two-play.com/plugins/toob-ml","presets": [{"instanceId": 1,"label": "Fender Clean","controlValues": {"bass": 0.783333361,"gain": 0,"master": 1.5,"mid": 0.5,"model": 8,"treble": 0.550000012,"trim": -3}},{"instanceId": 2,"label": "Mesa Crunch","controlValues": {"bass": 0.650000036,"gain": 0,"master": 1.5,"mid": 0.5,"model": 17,"treble": 0.550000012,"trim": -3}},{"instanceId": 3,"label": "Sparkling Clean","controlValues": {"bass": 0.650000036,"gain": 0,"master": 1.5,"mid": 0.5,"model": 19,"treble": 0.550000012,"trim": -3}}],"nextInstanceId": 4}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZaMultiComp","presets": [{"instanceId": 1,"label": "Presence","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 3,"kn2": 3,"kn3": 3,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 9,"mak2": 6,"mak3": 6,"rat1": 5,"rat2": 5,"rat3": 5,"rel1": 200,"rel2": 200,"rel3": 200,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 1,"toggle2": 1,"toggle3": 1,"xover1": 160,"xover2": 1400}},{"instanceId": 2,"label": "Zero","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 0,"kn2": 0,"kn3": 0,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 0,"mak2": 0,"mak3": 0,"rat1": 4,"rat2": 4,"rat3": 4,"rel1": 80,"rel2": 80,"rel3": 80,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 0,"toggle2": 0,"toggle3": 0,"xover1": 160,"xover2": 1400}}],"nextInstanceId": 3}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZaMultiCompX2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 0,"kn2": 0,"kn3": 0,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 0,"mak2": 0,"mak3": 0,"rat1": 4,"rat2": 4,"rat3": 4,"rel1": 80,"rel2": 80,"rel3": 80,"stereodet": 1,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 0,"toggle2": 0,"toggle3": 0,"xover1": 160,"xover2": 1400}},{"instanceId": 2,"label": "Presence","controlValues": {"att1": 10,"att2": 10,"att3": 10,"globalgain": 0,"kn1": 3,"kn2": 3,"kn3": 3,"listen1": 0,"listen2": 0,"listen3": 0,"mak1": 9,"mak2": 6,"mak3": 6,"rat1": 5,"rat2": 5,"rat3": 5,"rel1": 200,"rel2": 200,"rel3": 200,"stereodet": 1,"thr1": -20,"thr2": -18,"thr3": -16,"toggle1": 1,"toggle2": 1,"toggle3": 1,"xover1": 160,"xover2": 1400}}],"nextInstanceId": 3}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamComp","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"att": 10,"kn": 0,"mak": 0,"rat": 4,"rel": 80,"sidech": 0,"slew": 1,"thr": 0}},{"instanceId": 2,"label": "VocalLeveller","controlValues": {"att": 50,"kn": 8,"mak": 9,"rat": 5,"rel": 400,"sidech": 0,"slew": 1,"thr": -16}},{"instanceId": 3,"label": "PoppySnare","controlValues": {"att": 10,"kn": 1,"mak": 6,"rat": 5,"rel": 10,"sidech": 0,"slew": 20,"thr": -18}}],"nextInstanceId": 4}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamCompX2","presets": [{"instanceId": 1,"label": "PoppySnare","controlValues": {"att": 10,"kn": 1,"mak": 6,"rat": 5,"rel": 10,"sidechain": 0,"slew": 20,"stereodet": 1,"thr": -18}},{"instanceId": 2,"label": "VocalLeveller","controlValues": {"att": 50,"kn": 8,"mak": 9,"rat": 5,"rel": 400,"sidechain": 0,"slew": 1,"stereodet": 1,"thr": -16}},{"instanceId": 3,"label": "Zero","controlValues": {"att": 10,"kn": 0,"mak": 0,"rat": 4,"rel": 80,"sidechain": 0,"slew": 1,"stereodet": 0,"thr": 0}}],"nextInstanceId": 4}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamDelay","presets": [ ],"nextInstanceId": 1}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamDynamicEQ","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"att": 10,"boostcut": 0,"detectfreq": 1000,"kn": 0,"max": 10,"rat": 1.5,"rel": 80,"sidech": 0,"slew": 1,"targetfreq": 1000,"targetwidth": 1,"thr": 0,"togglehigh": 0,"togglelow": 0,"togglepeak": 1}},{"instanceId": 2,"label": "PoppySnare","controlValues": {"att": 10,"boostcut": 0,"detectfreq": 1000,"kn": 1,"max": 10,"rat": 1.5,"rel": 10,"sidech": 0,"slew": 20,"targetfreq": 1000,"targetwidth": 1,"thr": -18,"togglehigh": 0,"togglelow": 0,"togglepeak": 1}}],"nextInstanceId": 3}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamEQ2","presets": [{"instanceId": 1,"label": "Zero","controlValues": {"boost1": 0,"boost2": 0,"boosth": 0,"boostl": 0,"bw1": 1,"bw2": 1,"f1": 500,"f2": 3000,"fh": 8000,"fl": 250,"master": 0,"peaks": 0}},{"instanceId": 2,"label": "CarvedBass","controlValues": {"boost1": 0,"boost2": 0,"boosth": 0,"boostl": 6,"bw1": 1,"bw2": 1,"f1": 500,"f2": 3000,"fh": 8000,"fl": 60,"master": -6,"peaks": 0}},{"instanceId": 3,"label": "CarvedVox","controlValues": {"boost1": 0,"boost2": 0,"boosth": 6,"boostl": 6,"bw1": 1,"bw2": 1,"f1": 500,"f2": 3000,"fh": 330,"fl": 6600,"master": -12,"peaks": 0}},{"instanceId": 4,"label": "CarvedGuitar","controlValues": {"boost1": 5.5999999,"boost2": 0.699999988,"boosth": 0,"boostl": -1.04999995,"bw1": 1.46000004,"bw2": 1.33000004,"f1": 175,"f2": 500,"fh": 8000,"fl": 30,"master": -6,"peaks": 0}}],"nextInstanceId": 5}
@@ -0,0 +1 @@
{"pluginUri": "urn:zamaudio:ZamGEQ31","presets": [{"instanceId": 1,"label": "Default","controlValues": {"band1": 0,"band10": 0,"band11": 0,"band12": 0,"band13": 0,"band14": 0,"band15": 0,"band16": 0,"band17": 0,"band18": 0,"band19": 0,"band2": 0,"band20": 0,"band21": 0,"band22": 0,"band23": 0,"band24": 0,"band25": 0,"band26": 0,"band27": 0,"band28": 0,"band29": 0,"band3": 0,"band4": 0,"band5": 0,"band6": 0,"band7": 0,"band8": 0,"band9": 0,"master": 0}}],"nextInstanceId": 2}
@@ -0,0 +1 @@
{"entries": [{"pluginUri": "urn:zamaudio:ZaMaximX2","fileName": "1.json"},{"pluginUri": "urn:zamaudio:ZaMultiComp","fileName": "2.json"},{"pluginUri": "urn:zamaudio:ZaMultiCompX2","fileName": "3.json"},{"pluginUri": "urn:zamaudio:ZamComp","fileName": "4.json"},{"pluginUri": "urn:zamaudio:ZamCompX2","fileName": "5.json"},{"pluginUri": "urn:zamaudio:ZamDelay","fileName": "6.json"},{"pluginUri": "urn:zamaudio:ZamDynamicEQ","fileName": "7.json"},{"pluginUri": "urn:zamaudio:ZamEQ2","fileName": "8.json"},{"pluginUri": "urn:zamaudio:ZamGEQ31","fileName": "9.json"},{"pluginUri": "urn:zamaudio:ZamGate","fileName": "10.json"},{"pluginUri": "urn:zamaudio:ZamGateX2","fileName": "11.json"},{"pluginUri": "urn:zamaudio:ZamGrains","fileName": "12.json"},{"pluginUri": "urn:zamaudio:ZamHeadX2","fileName": "13.json"},{"pluginUri": "urn:zamaudio:ZamPhono","fileName": "14.json"},{"pluginUri": "urn:zamaudio:ZamTube","fileName": "15.json"},{"pluginUri": "urn:zamaudio:ZamVerb","fileName": "16.json"},{"pluginUri": "http://two-play.com/plugins/toob-delay","fileName": "17.json"},{"pluginUri": "http://two-play.com/plugins/toob-ml","fileName": "18.json"}],"nextInstanceId": 19}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"selectedBank": 1,"nextInstanceId": 1,"entries": [{"instanceId": 1,"name": "Default Bank"}]}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://calf.sourceforge.net/plugins/Filter","presets": [{"instanceId": 1,"label": "Distant Headphones","controlValues": {"freq": 305.817993,"inertia": 74,"mode": 3,"res": 0.707000017},"state": [false,{}]},{"instanceId": 2,"label": "Totally muted","controlValues": {"freq": 10,"inertia": 20,"mode": 2,"res": 0.707000017},"state": [false,{}]},{"instanceId": 3,"label": "Disco","controlValues": {"freq": 193.820999,"inertia": 74,"mode": 0,"res": 1.37955999},"state": [false,{}]}],"nextInstanceId": 4}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://calf.sourceforge.net/plugins/Flanger","presets": [{"instanceId": 1,"label": "Allpass filter","controlValues": {"amount": 1.85318005,"dry": 1,"feedback": -0.446399987,"min_delay": 2.63027,"mod_depth": 0.5,"mod_rate": 2.56892991,"reset": 0,"stereo": 0},"state": [false,{}]},{"instanceId": 2,"label": "Tooth Killer","controlValues": {"amount": 0.318639994,"feedback": 0.99000001,"min_delay": 0.363077998,"mod_depth": 0.181538999,"mod_rate": 0.100419},"state": [false,{}]},{"instanceId": 3,"label": "Waterlike","controlValues": {"amount": 0.926587999,"feedback": -0.169200003,"min_delay": 0.478630006,"mod_depth": 0.722720027,"mod_rate": 1.67184997},"state": [false,{}]},{"instanceId": 4,"label": "Chorus Lite","controlValues": {"amount": 0.632878006,"feedback": 0.0683998987,"min_delay": 10,"mod_depth": 2.08435011,"mod_rate": 0.910154998},"state": [false,{}]},{"instanceId": 5,"label": "Fast Sweep","controlValues": {"amount": 0.926587999,"feedback": 0.761399984,"min_delay": 0.100000001,"mod_depth": 4.35481977,"mod_rate": 5.22819996},"state": [false,{}]},{"instanceId": 6,"label": "Slow Resonant","controlValues": {"amount": 1,"feedback": -0.882000029,"min_delay": 0.125892997,"mod_depth": 0.362217993,"mod_rate": 0.146847993},"state": [false,{}]},{"instanceId": 7,"label": "Warble","controlValues": {"amount": 0.318639994,"feedback": -0.99000001,"min_delay": 0.218776003,"mod_depth": 0.181538999,"mod_rate": 20},"state": [false,{}]}],"nextInstanceId": 8}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://calf.sourceforge.net/plugins/MonoCompressor","presets": [{"instanceId": 1,"label": "Vocal Leveller","controlValues": {"attack": 3.10086989,"bypass": 0,"clip_in": 0,"clip_out": 1,"compression": 0.176127002,"detection": 0,"knee": 8,"level_in": 1,"makeup": 4.85678005,"meter_in": 0.847831011,"meter_out": 0.908609986,"ratio": 4.25008011,"release": 25.0011997,"stereo_link": 0,"threshold": 0.0883883983},"state": [false,{}]},{"instanceId": 2,"label": "Vocal Leveller 2","controlValues": {"attack": 10.5095997,"bypass": 0,"clip_in": 0,"clip_out": 1,"compression": 0.247421995,"detection": 0,"knee": 8,"level_in": 1,"makeup": 4.85678005,"meter_in": 0.533456981,"meter_out": 0.740245998,"ratio": 4.25008011,"release": 106.851997,"stereo_link": 0,"threshold": 0.0883883983},"state": [false,{}]},{"instanceId": 3,"label": "Snare Mic","controlValues": {"attack": 3.5034399,"bypass": 0,"clip_in": 0,"clip_out": 0,"compression": 1,"detection": 0,"knee": 1,"level_in": 1.05701995,"makeup": 2.94853997,"meter_in": 0,"meter_out": 0,"ratio": 3.00696993,"release": 21.8598995,"stereo_link": 0,"threshold": 0.164939001},"state": [false,{}]},{"instanceId": 4,"label": "Snare Mic 2","controlValues": {"attack": 10.5095997,"bypass": 0,"clip_in": 0,"clip_out": 0,"compression": 1,"detection": 0,"knee": 1,"level_in": 1.05701995,"makeup": 2.94853997,"meter_in": 0,"meter_out": 0,"ratio": 3.00696993,"release": 80.6973038,"stereo_link": 0,"threshold": 0.164939001},"state": [false,{}]}],"nextInstanceId": 5}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://calf.sourceforge.net/plugins/Reverb","presets": [{"instanceId": 1,"label": "Ambience","controlValues": {"amount": 0.291182995,"bass_cut": 514.078979,"decay_time": 1.10353994,"diffusion": 0.689999998,"dry": 1,"hf_damp": 2182.58008,"predelay": 6.5,"room_size": 4,"treble_cut": 4064.1499},"state": [false,{}]},{"instanceId": 2,"label": "Large Occupied Hall","controlValues": {"amount": 0.184284002,"decay_time": 1.45396996,"hf_damp": 9795.58008},"state": [false,{}]},{"instanceId": 3,"label": "Room","controlValues": {"amount": 0.469761014,"bass_cut": 257.649994,"decay_time": 0.445944995,"diffusion": 0.540000021,"dry": 1,"hf_damp": 5508.45996,"predelay": 25,"room_size": 4,"treble_cut": 20000},"state": [false,{}]},{"instanceId": 4,"label": "Large Empty Hall","controlValues": {"amount": 0.366021991,"decay_time": 2.00689006,"hf_damp": 20000},"state": [false,{}]},{"instanceId": 5,"label": "DiscoVerb","controlValues": {"amount": 0.269807011,"decay_time": 1,"hf_damp": 3396.48999},"state": [false,{}]},{"instanceId": 6,"label": "Empty walls","controlValues": {"amount": 0.198883995,"bass_cut": 240.453003,"decay_time": 0.505686998,"diffusion": 0.170000002,"dry": 1,"hf_damp": 3971.63989,"predelay": 13,"room_size": 4,"treble_cut": 3303.46997},"state": [false,{}]}],"nextInstanceId": 7}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://calf.sourceforge.net/plugins/Wavetable","presets": [{"instanceId": 1,"label": "Jazz Guitar","controlValues": {"adsr2_a": 1,"adsr2_d": 350,"adsr2_r": 50,"adsr2_s": 0.5,"adsr2_v": 1,"adsr3_a": 1,"adsr3_d": 350,"adsr3_r": 50,"adsr3_s": 0.5,"adsr3_v": 0,"adsr_a": 1,"adsr_d": 1863.34998,"adsr_r": 50,"adsr_s": 0.0299999993,"adsr_v": 0.5,"o1detune": 1,"o1level": 0.133972004,"o1offset": 0.0399999991,"o1trans": 0,"o1wave": 20,"o2detune": -1,"o2level": 0,"o2offset": 0.140000001,"o2trans": 0,"o2wave": 16},"state": [false,{}]},{"instanceId": 2,"label": "Reed","controlValues": {"adsr2_a": 1,"adsr2_d": 350,"adsr2_r": 50,"adsr2_s": 0.5,"adsr2_v": 1,"adsr3_a": 1,"adsr3_d": 350,"adsr3_r": 50,"adsr3_s": 0.5,"adsr3_v": 0,"adsr_a": 78.0643997,"adsr_d": 350,"adsr_r": 50,"adsr_s": 0.5,"adsr_v": 1,"o1detune": 6,"o1level": 0.100000001,"o1offset": -0.280000001,"o1trans": 0,"o1wave": 23,"o2detune": -6,"o2level": 0.0669858009,"o2offset": 0.400000006,"o2trans": 0,"o2wave": 24},"state": [false,{}]},{"instanceId": 3,"label": "AmbiDeXtrous","controlValues": {"adsr2_a": 1,"adsr2_d": 60.9300003,"adsr2_r": 50,"adsr2_s": 0,"adsr2_v": 1,"adsr3_a": 1,"adsr3_d": 350,"adsr3_r": 50,"adsr3_s": 0.5,"adsr3_v": 0,"adsr_a": 1,"adsr_d": 1274.21997,"adsr_r": 50,"adsr_s": 0.389999986,"adsr_v": 1,"o1detune": 6,"o1level": 0.03125,"o1offset": -0.0199999996,"o1trans": 0,"o1wave": 13,"o2detune": -6,"o2level": 0.0412346013,"o2offset": 0.0199999996,"o2trans": 0,"o2wave": 15},"state": [false,{}]},{"instanceId": 4,"label": "Double Reed","controlValues": {"adsr2_a": 1,"adsr2_d": 350,"adsr2_r": 50,"adsr2_s": 0.5,"adsr2_v": 1,"adsr3_a": 1,"adsr3_d": 350,"adsr3_r": 50,"adsr3_s": 0.5,"adsr3_v": 0,"adsr_a": 78.0643997,"adsr_d": 350,"adsr_r": 50,"adsr_s": 0.5,"adsr_v": 1,"o1detune": 6,"o1level": 0.100000001,"o1offset": 0.0199999996,"o1trans": 0,"o1wave": 24,"o2detune": -6,"o2level": 0.0669858009,"o2offset": 0.239999995,"o2trans": -12,"o2wave": 23},"state": [false,{}]},{"instanceId": 5,"label": "Sharp Sync","controlValues": {"adsr2_a": 1,"adsr2_d": 350,"adsr2_r": 50,"adsr2_s": 0.5,"adsr2_v": 0,"adsr3_a": 1,"adsr3_d": 350,"adsr3_r": 50,"adsr3_s": 0.5,"adsr3_v": 0,"adsr_a": 1,"adsr_d": 350,"adsr_r": 50,"adsr_s": 0.5,"adsr_v": 0,"o1detune": 6,"o1level": 0.03125,"o1offset": -0.0599999987,"o1trans": 0,"o1wave": 0,"o2detune": -5,"o2level": 0.0441941991,"o2offset": -0.519999981,"o2trans": 0,"o2wave": 11},"state": [false,{}]},{"instanceId": 6,"label": "Swish","controlValues": {"adsr2_a": 1,"adsr2_d": 350,"adsr2_r": 50,"adsr2_s": 0.5,"adsr2_v": 1,"adsr3_a": 1,"adsr3_d": 350,"adsr3_r": 50,"adsr3_s": 0.5,"adsr3_v": 0,"adsr_a": 47.5774994,"adsr_d": 350,"adsr_r": 50,"adsr_s": 0.5,"adsr_v": 1,"o1detune": 6,"o1level": 0.100000001,"o1offset": -0.319999993,"o1trans": 0,"o1wave": 1,"o2detune": -6,"o2level": 0,"o2offset": 0.400000006,"o2trans": 0,"o2wave": 0},"state": [false,{}]}],"nextInstanceId": 7}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/Detune","presets": [{"instanceId": 1,"label": "Stereo Detune","controlValues": {"detune": 0.200000003,"latency": 0.5,"mix": 0.899999976,"output": 0.5},"state": [false,{}]},{"instanceId": 2,"label": "Symphonic","controlValues": {"detune": 0.200000003,"latency": 0.5,"mix": 0.899999976,"output": 0.5},"state": [false,{}]},{"instanceId": 3,"label": "Out Of Tune","controlValues": {"detune": 0.800000012,"latency": 0.5,"mix": 0.699999988,"output": 0.5},"state": [false,{}]}],"nextInstanceId": 4}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/Leslie","presets": [{"instanceId": 1,"label": "Default","controlValues": {"hi_depth": 0.600000024,"hi_throb": 0.699999988,"hi_width": 0.699999988,"lo_throb": 0.600000024,"lo_width": 0.5,"mode": 0.5,"output": 0.5,"speed": 0.5,"x_over": 0.479999989},"state": [false,{}]},{"instanceId": 2,"label": "Slow","controlValues": {"hi_depth": 0.75,"hi_throb": 0.569999993,"hi_width": 0.699999988,"lo_throb": 0.600000024,"lo_width": 0.5,"mode": 0.5,"output": 0.5,"speed": 0.5,"x_over": 0.479999989},"state": [false,{}]},{"instanceId": 3,"label": "Fast","controlValues": {"hi_depth": 0.600000024,"hi_throb": 0.699999988,"hi_width": 0.699999988,"lo_throb": 0.600000024,"lo_width": 0.5,"mode": 1,"output": 0.5,"speed": 0.5,"x_over": 0.479999989},"state": [false,{}]}],"nextInstanceId": 4}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/Piano","presets": [{"instanceId": 1,"label": "Broken Piano","controlValues": {"env_decay": 0.0500000007,"env_release": 0.957000017,"fine_tuning": 0.449999988,"hardness_offset": 0.5,"muffling_filter": 0.298999995,"polyphony": 0.330000013,"random_detuning": 0.717999995,"stereo_width": 0.5,"stretch_tuning": 0,"vel_sensitivity": 0,"vel_to_hardness": 0.5,"vel_to_muffling": 1},"state": [false,{}]},{"instanceId": 2,"label": "Plain Piano","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness_offset": 0.5,"muffling_filter": 0.750999987,"polyphony": 0,"random_detuning": 0,"stereo_width": 0,"stretch_tuning": 0.5,"vel_sensitivity": 0.451999992,"vel_to_hardness": 0.5,"vel_to_muffling": 0},"state": [false,{}]},{"instanceId": 3,"label": "MDA Piano","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness_offset": 0.5,"muffling_filter": 0.802999973,"polyphony": 0.330000013,"random_detuning": 0.246000007,"stereo_width": 0.5,"stretch_tuning": 0.5,"vel_sensitivity": 0.375999987,"vel_to_hardness": 0.5,"vel_to_muffling": 0.250999987},"state": [false,{}]},{"instanceId": 4,"label": "Compressed Piano","controlValues": {"env_decay": 0.90200001,"env_release": 0.398999989,"fine_tuning": 0.5,"hardness_offset": 0.623000026,"muffling_filter": 1,"polyphony": 0.330000013,"random_detuning": 0,"stereo_width": 0.499000013,"stretch_tuning": 0.5,"vel_sensitivity": 0.298999995,"vel_to_hardness": 0.5,"vel_to_muffling": 0.331},"state": [false,{}]},{"instanceId": 5,"label": "Dark Piano","controlValues": {"env_decay": 0.5,"env_release": 0.601999998,"fine_tuning": 0.5,"hardness_offset": 0,"muffling_filter": 0.30399999,"polyphony": 0.330000013,"random_detuning": 0.317000002,"stereo_width": 0.651000023,"stretch_tuning": 0.5,"vel_sensitivity": 0.335999995,"vel_to_hardness": 0.5,"vel_to_muffling": 0.200000003},"state": [false,{}]},{"instanceId": 6,"label": "Concert Piano","controlValues": {"env_decay": 0.648000002,"env_release": 0.5,"fine_tuning": 0.5,"hardness_offset": 0.5,"muffling_filter": 0.298000008,"polyphony": 0.356000006,"random_detuning": 0.338999987,"stereo_width": 0.850000024,"stretch_tuning": 0.660000026,"vel_sensitivity": 0.550000012,"vel_to_hardness": 0.5,"vel_to_muffling": 0.601999998},"state": [false,{}]},{"instanceId": 7,"label": "School Piano","controlValues": {"env_decay": 0.449999988,"env_release": 0.59799999,"fine_tuning": 0.5,"hardness_offset": 0.625999987,"muffling_filter": 0.602999985,"polyphony": 0.330000013,"random_detuning": 0.421000004,"stereo_width": 0.331,"stretch_tuning": 0.800999999,"vel_sensitivity": 0.173999995,"vel_to_hardness": 0.5,"vel_to_muffling": 0.5},"state": [false,{}]},{"instanceId": 8,"label": "Dance Piano","controlValues": {"env_decay": 0.398999989,"env_release": 0.250999987,"fine_tuning": 0.5,"hardness_offset": 1,"muffling_filter": 0.671999991,"polyphony": 0.330000013,"random_detuning": 0.282999992,"stereo_width": 0.248999998,"stretch_tuning": 0.666999996,"vel_sensitivity": 0.127000004,"vel_to_hardness": 0.5,"vel_to_muffling": 0.123999998},"state": [false,{}]}],"nextInstanceId": 9}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/Splitter","presets": [{"instanceId": 1,"label": "Frequency/Level Splitter","controlValues": {"envelope": 0.5,"freq": 0.5,"freq_sw": 0.25,"level": 0.5,"level_sw": 0.5,"mode": 0,"output": 0.5},"state": [false,{}]},{"instanceId": 2,"label": "Pass Peaks Only","controlValues": {"envelope": 0.5,"freq": 0.5,"freq_sw": 0.5,"level": 0.5,"level_sw": 0,"mode": 0,"output": 0.5},"state": [false,{}]},{"instanceId": 3,"label": "Stereo Crossover","controlValues": {"envelope": 0.5,"freq": 0.5,"freq_sw": 0.25,"level": 0.5,"level_sw": 0.5,"mode": 0.666666985,"output": 0.5},"state": [false,{}]}],"nextInstanceId": 4}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/ThruZero","presets": [{"instanceId": 1,"label": "Phase Canceller","controlValues": {"depth": 0.200000003,"depth_mod": 1,"feedback": 0.300000012,"mix": 0.469999999,"rate": 0.5},"state": [false,{}]},{"instanceId": 2,"label": "Mad Modulator","controlValues": {"depth": 1,"depth_mod": 1,"feedback": 0.75,"mix": 0.5,"rate": 0.75},"state": [false,{}]},{"instanceId": 3,"label": "Chorus Doubler","controlValues": {"depth": 0.600000024,"depth_mod": 0.699999988,"feedback": 0.300000012,"mix": 0.349999994,"rate": 0.600000024},"state": [false,{}]},{"instanceId": 4,"label": "Thru-Zero Flanger","controlValues": {"depth": 0.430000007,"depth_mod": 1,"feedback": 0.300000012,"mix": 0.469999999,"rate": 0.300000012},"state": [false,{}]}],"nextInstanceId": 5}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/Vocoder","presets": [{"instanceId": 1,"label": "Default","controlValues": {"envelope": 0.159999996,"filter_q": 0.550000012,"hi_band": 0.400000006,"hi_thru": 0.400000006,"mid_freq": 0.666700006,"mod_in": 0,"output": 0.5,"quality": 0},"state": [false,{}]},{"instanceId": 2,"label": "Old Vocoder","controlValues": {"envelope": 0.159999996,"filter_q": 0.550000012,"hi_band": 0,"hi_thru": 0,"mid_freq": 0.5,"mod_in": 0,"output": 0.5,"quality": 0},"state": [false,{}]},{"instanceId": 3,"label": "Pad Vocoder","controlValues": {"envelope": 0.779999971,"filter_q": 0.550000012,"hi_band": 0.400000006,"hi_thru": 0.400000006,"mid_freq": 0.300000012,"mod_in": 0,"output": 0.5,"quality": 0},"state": [false,{}]},{"instanceId": 4,"label": "16 Band Vocoder","controlValues": {"envelope": 0.159999996,"filter_q": 0.550000012,"hi_band": 0.400000006,"hi_thru": 0.400000006,"mid_freq": 0.666700006,"mod_in": 0,"output": 0.5,"quality": 1},"state": [false,{}]},{"instanceId": 5,"label": "Choral Vocoder","controlValues": {"envelope": 0.159999996,"filter_q": 0.699999988,"hi_band": 0,"hi_thru": 0.400000006,"mid_freq": 0.5,"mod_in": 0,"output": 0.5,"quality": 0},"state": [false,{}]}],"nextInstanceId": 6}
+1
View File
@@ -0,0 +1 @@
{"pluginUri": "http://drobilla.net/plugins/mda/EPiano","presets": [{"instanceId": 1,"label": "Bright","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness": 1,"lfo_rate": 0.649999976,"modulation": 0.5,"overdrive": 0.5,"polyphonic": 1,"random_tuning": 0.145999998,"stereo_width": 0.5,"treble_boost": 0.800000012,"vel_sense": 0.25},"state": [false,{}]},{"instanceId": 2,"label": "Default","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness": 0.5,"lfo_rate": 0.649999976,"modulation": 0.5,"overdrive": 0,"polyphonic": 1,"random_tuning": 0.145999998,"stereo_width": 0.5,"treble_boost": 0.5,"vel_sense": 0.25},"state": [false,{}]},{"instanceId": 3,"label": "Tremolo","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness": 0.5,"lfo_rate": 0.649999976,"modulation": 0.75,"overdrive": 0,"polyphonic": 1,"random_tuning": 0.246000007,"stereo_width": 0.5,"treble_boost": 0.5,"vel_sense": 0.25},"state": [false,{}]},{"instanceId": 4,"label": "Mellow","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness": 0,"lfo_rate": 0.649999976,"modulation": 0.5,"overdrive": 0,"polyphonic": 1,"random_tuning": 0.246000007,"stereo_width": 0.5,"treble_boost": 0,"vel_sense": 0.25},"state": [false,{}]},{"instanceId": 5,"label": "Autopan","controlValues": {"env_decay": 0.5,"env_release": 0.5,"fine_tuning": 0.5,"hardness": 0.5,"lfo_rate": 0.649999976,"modulation": 0.25,"overdrive": 0,"polyphonic": 1,"random_tuning": 0.246000007,"stereo_width": 0.5,"treble_boost": 0.5,"vel_sense": 0.25},"state": [false,{}]}],"nextInstanceId": 6}
+1 -1
View File
@@ -1 +1 @@
{"entries": [{"pluginUri": "urn:zamaudio:ZaMaximX2","fileName": "1.json"},{"pluginUri": "urn:zamaudio:ZaMultiComp","fileName": "2.json"},{"pluginUri": "urn:zamaudio:ZaMultiCompX2","fileName": "3.json"},{"pluginUri": "urn:zamaudio:ZamComp","fileName": "4.json"},{"pluginUri": "urn:zamaudio:ZamCompX2","fileName": "5.json"},{"pluginUri": "urn:zamaudio:ZamDelay","fileName": "6.json"},{"pluginUri": "urn:zamaudio:ZamDynamicEQ","fileName": "7.json"},{"pluginUri": "urn:zamaudio:ZamEQ2","fileName": "8.json"},{"pluginUri": "urn:zamaudio:ZamGEQ31","fileName": "9.json"},{"pluginUri": "urn:zamaudio:ZamGate","fileName": "10.json"},{"pluginUri": "urn:zamaudio:ZamGateX2","fileName": "11.json"},{"pluginUri": "urn:zamaudio:ZamGrains","fileName": "12.json"},{"pluginUri": "urn:zamaudio:ZamHeadX2","fileName": "13.json"},{"pluginUri": "urn:zamaudio:ZamPhono","fileName": "14.json"},{"pluginUri": "urn:zamaudio:ZamTube","fileName": "15.json"},{"pluginUri": "urn:zamaudio:ZamVerb","fileName": "16.json"},{"pluginUri": "http://two-play.com/plugins/toob-delay","fileName": "17.json"},{"pluginUri": "http://two-play.com/plugins/toob-ml","fileName": "18.json"}],"nextInstanceId": 19} {"entries": [{"pluginUri": "urn:zamaudio:ZaMaximX2","fileName": "1.json"},{"pluginUri": "urn:zamaudio:ZaMultiComp","fileName": "2.json"},{"pluginUri": "urn:zamaudio:ZaMultiCompX2","fileName": "3.json"},{"pluginUri": "urn:zamaudio:ZamComp","fileName": "4.json"},{"pluginUri": "urn:zamaudio:ZamCompX2","fileName": "5.json"},{"pluginUri": "urn:zamaudio:ZamDelay","fileName": "6.json"},{"pluginUri": "urn:zamaudio:ZamDynamicEQ","fileName": "7.json"},{"pluginUri": "urn:zamaudio:ZamEQ2","fileName": "8.json"},{"pluginUri": "urn:zamaudio:ZamGEQ31","fileName": "9.json"},{"pluginUri": "urn:zamaudio:ZamGate","fileName": "10.json"},{"pluginUri": "urn:zamaudio:ZamGateX2","fileName": "11.json"},{"pluginUri": "urn:zamaudio:ZamGrains","fileName": "12.json"},{"pluginUri": "urn:zamaudio:ZamHeadX2","fileName": "13.json"},{"pluginUri": "urn:zamaudio:ZamPhono","fileName": "14.json"},{"pluginUri": "urn:zamaudio:ZamTube","fileName": "15.json"},{"pluginUri": "urn:zamaudio:ZamVerb","fileName": "16.json"},{"pluginUri": "http://two-play.com/plugins/toob-delay","fileName": "17.json"},{"pluginUri": "http://two-play.com/plugins/toob-ml","fileName": "18.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/Filter","fileName": "19.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/Flanger","fileName": "20.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/MonoCompressor","fileName": "21.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/Monosynth","fileName": "22.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/Organ","fileName": "23.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/Reverb","fileName": "24.json"},{"pluginUri": "http://calf.sourceforge.net/plugins/Wavetable","fileName": "25.json"},{"pluginUri": "http://drobilla.net/plugins/mda/DX10","fileName": "26.json"},{"pluginUri": "http://drobilla.net/plugins/mda/Detune","fileName": "27.json"},{"pluginUri": "http://drobilla.net/plugins/mda/JX10","fileName": "28.json"},{"pluginUri": "http://drobilla.net/plugins/mda/Leslie","fileName": "29.json"},{"pluginUri": "http://drobilla.net/plugins/mda/Piano","fileName": "30.json"},{"pluginUri": "http://drobilla.net/plugins/mda/Splitter","fileName": "31.json"},{"pluginUri": "http://drobilla.net/plugins/mda/ThruZero","fileName": "32.json"},{"pluginUri": "http://drobilla.net/plugins/mda/Vocoder","fileName": "33.json"},{"pluginUri": "http://drobilla.net/plugins/mda/EPiano","fileName": "34.json"}],"nextInstanceId": 35}
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -13,14 +13,14 @@ page_icon: img/Install4.jpg
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- [Ubuntu/Raspberry Pi OS (64-bit) v1.0.19](https://github.com/rerdavies/pipedal/releases/download/v1.0.19/pipedal_1.0.19_arm64.deb) - [Ubuntu/Raspberry Pi OS (64-bit) v1.1.20](https://github.com/rerdavies/pipedal/releases/download/v1.1.20/pipedal_1.1.20_arm64.deb)
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install ./pipedal_1.0.19_arm64.deb sudo apt-get install ./pipedal_1.1.20_arm64.deb
``` ```
On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager. On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager.
+19
View File
@@ -0,0 +1,19 @@
# Release Notes
## PiPedal 1.1.20
Features:
- Two new plugins: TooB Convolution Reverb, and TooB Cab IR.
- Output ports for LV2 plugins are now displayed (vu meters and status controls)
- File selection dialog, and uploads for LV2 atom:path Properties for 3rd party LV2 plugins.
Bug fixes:
- Improvements to onboarding procedure.
- Problems with restarting audio after changing audio parameters.
- Occasional loss of audio after reboot caused by ALSA USB initialization race conditions.
+2 -2
View File
@@ -4,14 +4,14 @@
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.0.19/pipedal_1.0.19_arm64.deb) v1.0.19 - [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.1.20/pipedal_1.1.20_arm64.deb) v1.1.20
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install ./pipedal_1.0.19_arm64.deb sudo apt-get install ./pipedal_1.1.20_arm64.deb
``` ```
Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation.
+5 -1
View File
@@ -1,12 +1,16 @@
<img src="GithubBanner.png" width="100%"/> <img src="GithubBanner.png" width="100%"/>
<a href="Installing.html"><i>v1.0.19</i></a> <a href="Installing.html"><i>v1.1.20</i></a>
&nbsp; &nbsp;
To download PiPedal, click [here](download.md). To download PiPedal, click [here](download.md).
<quote>
NEW version 1.1 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
</quote>
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet. Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats. PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
+431
View File
@@ -0,0 +1,431 @@
@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 cabir: <http://two-play.com/plugins/toob-cab-ir#> .
@prefix toobimpulse: <http://two-play.com/plugins/toob-impulse#> .
cabir:impulseFile1Group
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Impulse Response 1" ;
lv2:symbol "impulse1" .
cabir:impulseFile2Group
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Impulse Response 2" ;
lv2:symbol "impulse2" .
cabir:impulseFile3Group
a param:ControlGroup ,
pg:InputGroup ;
lv2:name "Impulse Response 3" ;
lv2:symbol "impulse3" .
cabir:impulseFile
a rdf:property;
rdfs:label "IR";
pg:group cabir:impulseFile1Group ;
rdfs:range atom:Path.
cabir:impulseFile2
a rdf:property;
rdfs:label "IR";
pg:group cabir:impulseFile2Group ;
rdfs:range atom:Path.
cabir:impulseFile3
a rdf:property;
rdfs:label "IR";
pg:group cabir:impulseFile3Group ;
rdfs:range atom:Path.
<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-cab-ir>
a lv2:Plugin ,
lv2:ReverbPlugin ;
doap:name "TooB Cab IR" ,
"TooB Cab IR"@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 14 ;
rdfs:comment """
TooB Cab IR is a convolution-based guitar cabinet impulse response simulator.
TooB Cab IR allows you to select and mix impulse responses for up to three microphone positions. Mixing is done before convolution FFTs are calculated,
so there is no performance cost for using more than one impulse response file.
Cab IR files are usually short, but sometimes include room response impulse files, which can be quite long. The Max T control determines the maximum length
to use for impulse response files. If the length of the impulse file is longer than the specified time, samples occuring after
the specified time are discarded, and the tail of the impulse convolution is fed back into the imput of the convolution. This ensures a smooth reverb tail,
and has little effect on the quality of the resulting reverb. If the impulse file is shorter than the specified time, then all samples in the impulse
file are used, and no feedback occurs.
Toob Convolution Reverb comes with a nominal set of cabinet impulse files to get you started. You are strongly encouraged to seek out reverb impulse files
on the internet.
Special thanks are extended to Kristoffer Ekstrand of Adventure Kid Research & Technology, who generously provided the base set of impulse files distributed with Toob Cab IR.
---
![CC-BY-4.0](/img/cc-by.png)
By: Kristoffer Ekstrand, Adventure Kid Research & Technology.
The following files are licensed under a [Creative Commons Attribution 4.0 International License.][1]
```
80s UK 001.wav
80s UK 002.wav
80s US 001.wav
80s US 002.wav
Modern UK 001.wav
Modern UK 002.wav
Modern US 001.wav
Modern US 002.wav
Modern US 003.wav
Modern US 004.wav
Radio 001.wav
Speaker 001.wav
Speaker 002.wav
Vintage UK 001.wav
Vintage UK 002.wav
Vintage US 001.wav
Vintage US 002.wav
```
Source: <https://www.adventurekid.se/akrt/free-reverb-impulse-responses/>
[1]: https://creativecommons.org/licenses/by/4.0/
""" ;
mod:brand "TooB";
mod:label "Convolution Reverb";
lv2:requiredFeature urid:map, state:makePath, state:mapPath ;
lv2:optionalFeature state::freePath;
lv2:extensionData state:interface;
lv2:optionalFeature lv2:hardRTCapable;
patch:readable
cabir:impulseFile, cabir:impulseFile2, cabir:impulseFile3;
patch:writable
cabir:impulseFile,cabir:impulseFile2,cabir:impulseFile3;
lv2:extensionData state:interface,
work:interface;
lv2:port
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 0 ;
lv2:symbol "reverb_mix" ;
lv2:name "Volume";
pg:group cabir:impulseFile1Group ;
lv2:default -10.0 ;
lv2:minimum -40.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
lv2:scalePoint [
rdfs:label "-INF" ;
rdf:value -40.0
];
rdfs:comment "Volume for impulse file #1." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 1 ;
lv2:symbol "reverb_mix2" ;
lv2:name "Volume";
pg:group cabir:impulseFile2Group ;
lv2:default -10.0 ;
lv2:minimum -40.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
lv2:scalePoint [
rdfs:label "-INF" ;
rdf:value -40.0
];
rdfs:comment "Volume for impulse file #2." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 2 ;
lv2:symbol "reverb_mix3" ;
lv2:name "Volume";
pg:group cabir:impulseFile3Group ;
lv2:default -10.0 ;
lv2:minimum -40.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
lv2:scalePoint [
rdfs:label "-INF" ;
rdf:value -40.0
];
rdfs:comment "Volume for impulse file #3." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 3;
lv2:symbol "time" ;
lv2:name "Max T";
lv2:default 2.0 ;
lv2:minimum 0.1 ;
lv2:maximum 6.0 ;
lv2:portProperty epp:notAutomatic ;
lv2:portProperty epp:expensive ;
units:unit units:s ;
rdfs:comment "Maximum length of impulse data to use." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 4;
lv2:symbol "direct_mix" ;
lv2:name "Direct";
lv2:default -40.0 ;
lv2:minimum -40.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
lv2:scalePoint [
rdfs:label "-INF" ;
rdf:value -40.0
];
rdfs:comment "Direct mix. Set to minimum to disable." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 5 ;
lv2:symbol "predelay" ;
lv2:name "Predelay";
lv2:portProperty epp:notOnGUI;
lv2:default 0 ;
lv2:minimum 0 ;
lv2:maximum 1 ;
lv2:portProperty lv2:enumeration ;
lv2:scalePoint [
rdfs:label "Remove" ;
rdf:value 0.0;
],
[
rdfs:label "Keep" ;
rdf:value 1.0;
];
rdfs:comment "Removes leading silence in impulse when set to false." ;
],
[
a lv2:OutputPort ,
lv2:ControlPort ;
lv2:index 6 ;
lv2:symbol "loading_state" ;
lv2:name "Status";
lv2:portProperty lv2:enumeration ;
lv2:default 0.0 ;
lv2:minimum 0.0 ;
lv2:maximum 5.0 ;
# NotLoaded = 0,
# Idle = 1,
# Error = 2,
# SentRequest = 3,
# GotResponse = 4,
# CleaningUp = 5,
lv2:scalePoint [
rdfs:label "Not loaded" ;
rdf:value 0.0
],[
rdfs:label "Ready" ;
rdf:value 1.0
],[
rdfs:label "Error" ;
rdf:value 2.0
],[
rdfs:label "Loading" ;
rdf:value 3.0
],[
rdfs:label "Loading" ;
rdf:value 4.0
],[
rdfs:label "Loading" ;
rdf:value 5.0
];
rdfs:comment "Plugin status." ;
],
[
a lv2:AudioPort ,
lv2:InputPort ;
lv2:index 7 ;
lv2:symbol "in" ;
lv2:name "In"
],
[
a lv2:AudioPort ,
lv2:OutputPort ;
lv2:index 8 ;
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 9 ;
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 10;
lv2:symbol "notify" ;
lv2:name "Notify" ;
rdfs:comment "Notification" ;
]
.
<http://two-play.com/plugins/toob-cab-ir> pipedal_ui:ui cabir:ui .
cabir:ui
a pipedal_ui:ui ;
pipedal_ui:fileProperties
[
a pipedal_ui:fileProperty;
rdfs:label "Impulse File" ;
lv2:index 0 ;
pg:group cabir:impulseFile1Group ;
pipedal_ui:directory "CabIR";
pipedal_ui:patchProperty cabir:impulseFile ;
pipedal_ui:fileTypes
[
a pipedal_ui:fileType;
rdfs:label "WAV File";
pipedal_ui:fileExtension ".wav";
];
],[
a pipedal_ui:fileProperty;
rdfs:label "Impulse File" ;
lv2:index 0 ;
pg:group cabir:impulseFile2Group ;
pipedal_ui:patchProperty cabir:impulseFile2 ;
pipedal_ui:directory "CabIR";
pipedal_ui:fileTypes
[
a pipedal_ui:fileType;
rdfs:label "WAV File";
pipedal_ui:fileExtension ".wav";
];
],[
a pipedal_ui:fileProperty;
rdfs:label "Impulse File" ;
lv2:index 0 ;
pg:group cabir:impulseFile3Group ;
pipedal_ui:patchProperty cabir:impulseFile3 ;
pipedal_ui:directory "CabIR";
pipedal_ui:fileTypes
[
a pipedal_ui:fileType;
rdfs:label "WAV File";
pipedal_ui:mimeType "audio/wav";
],
[
a pipedal_ui:fileType;
rdfs:label "FLAC File";
pipedal_ui:mimeType "audio/flac";
];
];
ui:portNotification
[
lv2:symbol "loading_state";
ui:plugin <http://two-play.com/plugins/toob-cab-ir>;
ui:protocol ui:floatProtocol;
# pipedal_ui:style pipedal_ui:text ;
# pipedal_ui:redLevel 0;
# pipedal_ui:yellowLevel -12;
# ui:portIndex 3;
]
.
+66 -18
View File
@@ -25,10 +25,10 @@
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix toobConvolutionReverb: <http://two-play.com/plugins/toob-convolution-reverb#> . @prefix toobcr: <http://two-play.com/plugins/toob-convolution-reverb#> .
@prefix toobImpulse: <http://two-play.com/impulseFile#> . @prefix toobimpulse: <http://two-play.com/plugins/toob-impulse#> .
toobImpulse:#impulseFile toobimpulse:impulseFile
a rdf:property; a rdf:property;
rdfs:label "File"; rdfs:label "File";
rdfs:range atom:Path. rdfs:range atom:Path.
@@ -154,16 +154,17 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
mod:brand "TooB"; mod:brand "TooB";
mod:label "Convolution Reverb"; mod:label "Convolution Reverb";
lv2:requiredFeature urid:map ; lv2:requiredFeature urid:map, state:makePath, state:mapPath ;
lv2:optionalFeature state::freePath;
lv2:extensionData state:interface; lv2:extensionData state:interface;
lv2:optionalFeature lv2:hardRTCapable; lv2:optionalFeature lv2:hardRTCapable;
patch:readable patch:readable
toobImpulse:#impulseFile toobimpulse:impulseFile
; ;
patch:writable patch:writable
toobImpulse:#impulseFile toobimpulse:impulseFile
; ;
lv2:extensionData state:interface, lv2:extensionData state:interface,
work:interface; work:interface;
@@ -220,6 +221,27 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
lv2:maximum 20.0 ; lv2:maximum 20.0 ;
units:unit units:db ; units:unit units:db ;
lv2:scalePoint [
rdfs:label "-INF" ;
rdf:value -40.0
];
rdfs:comment "Reverb mix. Set to minimum to disable." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 3 ;
lv2:portProperty epp:notOnGUI;
lv2:symbol "reverb_mix2" ;
lv2:name "IR Mix";
lv2:default -10.0 ;
lv2:minimum -40.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
lv2:scalePoint [ lv2:scalePoint [
rdfs:label "-INF" ; rdfs:label "-INF" ;
rdf:value -40.0 rdf:value -40.0
@@ -230,7 +252,28 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
a lv2:InputPort , a lv2:InputPort ,
lv2:ControlPort ; lv2:ControlPort ;
lv2:index 3 ; lv2:index 4 ;
lv2:portProperty epp:notOnGUI;
lv2:symbol "reverb_mix3" ;
lv2:name "IR Mix";
lv2:default -10.0 ;
lv2:minimum -40.0 ;
lv2:maximum 20.0 ;
units:unit units:db ;
lv2:scalePoint [
rdfs:label "-INF" ;
rdf:value -40.0
];
rdfs:comment "Reverb mix. Set to minimum to disable." ;
],
[
a lv2:InputPort ,
lv2:ControlPort ;
lv2:index 5 ;
lv2:symbol "predelay" ; lv2:symbol "predelay" ;
lv2:name "Predelay"; lv2:name "Predelay";
@@ -255,7 +298,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
a lv2:OutputPort , a lv2:OutputPort ,
lv2:ControlPort ; lv2:ControlPort ;
lv2:index 4 ; lv2:index 6 ;
lv2:symbol "loading_state" ; lv2:symbol "loading_state" ;
lv2:name "Status"; lv2:name "Status";
@@ -295,14 +338,14 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
[ [
a lv2:AudioPort , a lv2:AudioPort ,
lv2:InputPort ; lv2:InputPort ;
lv2:index 5 ; lv2:index 7 ;
lv2:symbol "in" ; lv2:symbol "in" ;
lv2:name "In" lv2:name "In"
], ],
[ [
a lv2:AudioPort , a lv2:AudioPort ,
lv2:OutputPort ; lv2:OutputPort ;
lv2:index 6 ; lv2:index 8 ;
lv2:symbol "out" ; lv2:symbol "out" ;
lv2:name "Out" lv2:name "Out"
], ],
@@ -314,7 +357,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
lv2:designation lv2:control ; lv2:designation lv2:control ;
atom:supports patch:Message ; atom:supports patch:Message ;
lv2:index 7 ; lv2:index 9 ;
lv2:symbol "control" ; lv2:symbol "control" ;
lv2:name "Control" ; lv2:name "Control" ;
rdfs:comment "Control" ; rdfs:comment "Control" ;
@@ -324,7 +367,7 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
atom:bufferType atom:Sequence ; atom:bufferType atom:Sequence ;
atom:supports patch:Message; atom:supports patch:Message;
lv2:designation lv2:control ; lv2:designation lv2:control ;
lv2:index 8; lv2:index 10;
lv2:symbol "notify" ; lv2:symbol "notify" ;
lv2:name "Notify" ; lv2:name "Notify" ;
rdfs:comment "Notification" ; rdfs:comment "Notification" ;
@@ -332,23 +375,28 @@ Source: https://www.openair.hosted.york.ac.uk/?page_id=483
. .
<http://two-play.com/plugins/toob-convolution-reverb> pipedal_ui:ui toobConvolutionReverb:ui . <http://two-play.com/plugins/toob-convolution-reverb> pipedal_ui:ui toobcr:ui .
toobConvolutionReverb:ui toobcr:ui
a pipedal_ui:ui ; a pipedal_ui:ui ;
pipedal_ui:fileProperties pipedal_ui:fileProperties
[ [
a pipedal_ui:fileProperty; a pipedal_ui:fileProperty;
rdfs:label "Impulse File" ; rdfs:label "Impulse File" ;
lv2:index 4 ; lv2:index 4 ;
pipedal_ui:patchProperty toobImpulse:impulseFile ; pipedal_ui:patchProperty toobimpulse:impulseFile ;
pipedal_ui:directory "ReverbImpulseFiles"; pipedal_ui:directory "ReverbImpulseFiles";
pipedal_ui:fileTypes pipedal_ui:fileTypes
[ [
a pipedal_ui:fileType; a pipedal_ui:fileType;
rdfs:label "WAV File"; rdfs:label "WAV File";
pipedal_ui:fileExtension ".wav"; pipedal_ui:mimeType "audio/wav";
]; ],
[
a pipedal_ui:fileType;
rdfs:label "FLAC File";
pipedal_ui:mimeType "audio/flac";
] ;
]; ];
ui:portNotification ui:portNotification
[ [
+1 -1
View File
@@ -1 +1 @@
ToobAmp.so.0.1.7 ToobAmp.so.1.0.8
Binary file not shown.
@@ -0,0 +1,26 @@
The following files have been graciously provided by Kristoffer Ekstrand (akak Adventure Kid),
and are licensed under a CC-BY-4.0 license:
https://creativecommons.org/licenses/by/4.0/
80s UK 001.wav
80s UK 002.wav
80s US 001.wav
80s US 002.wav
Modern UK 001.wav
Modern UK 002.wav
Modern US 001.wav
Modern US 002.wav
Modern US 003.wav
Modern US 004.wav
Radio 001.wav
Speaker 001.wav
Speaker 002.wav
Vintage UK 001.wav
Vintage UK 002.wav
Vintage US 001.wav
Vintage US 002.wav
By: Adventure Kid Research & Technology, Kristoffer Ekstrand.
Source: https://www.adventurekid.se/akrt/free-reverb-impulse-responses/
Binary file not shown.
+221 -216
View File
@@ -11,12 +11,17 @@
lv2:binary <ToobAmp.so> ; lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ConvolutionReverb.ttl> . rdfs:seeAlso <ConvolutionReverb.ttl> .
<http://two-play.com/plugins/toob-cab-ir> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <CabIR.ttl> .
<http://two-play.com/plugins/toob-ml> a lv2:Plugin ; <http://two-play.com/plugins/toob-ml> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ; lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <ToobML.ttl> . rdfs:seeAlso <ToobML.ttl> .
<http://two-play.com/plugins/toob-power-stage-2> a lv2:Plugin ; <http://two-play.com/plugins/toob-power-stage-2> a lv2:Plugin ;
lv2:binary <ToobAmp.so> ; lv2:binary <ToobAmp.so> ;
rdfs:seeAlso <PowerStage2.ttl> . rdfs:seeAlso <PowerStage2.ttl> .
@@ -52,231 +57,231 @@
<http://two-play.com/plugins/toob-power-stage> # <http://two-play.com/plugins/toob-power-stage>
modgui:gui [ # modgui:gui [
modgui:resourcesDirectory <modgui> ; # modgui:resourcesDirectory <modgui> ;
modgui:iconTemplate <modgui/icon-toob-power-stage.html> ; # modgui:iconTemplate <modgui/icon-toob-power-stage.html> ;
modgui:stylesheet <modgui/stylesheet-toob.css> ; # modgui:stylesheet <modgui/stylesheet-toob.css> ;
modgui:screenshot <modgui/screenshot-toob-power-stage.png> ; # modgui:screenshot <modgui/screenshot-toob-power-stage.png> ;
modgui:thumbnail <modgui/thumbnail-toob-power-stage.png> ; # modgui:thumbnail <modgui/thumbnail-toob-power-stage.png> ;
modgui:javascript <modgui/script-toob-power-stage.js> ; # modgui:javascript <modgui/script-toob-power-stage.js> ;
modgui:brand "TooB" ; # modgui:brand "TooB" ;
modgui:label "TooB Power Stage" ; # modgui:label "TooB Power Stage" ;
modgui:monitoredOutputs [ lv2:symbol "notify"] ; # modgui:monitoredOutputs [ lv2:symbol "notify"] ;
modgui:port [ # modgui:port [
lv2:index 0 ; # lv2:index 0 ;
lv2:symbol "trim1" ; # lv2:symbol "trim1" ;
lv2:name "TRIM" ; # lv2:name "TRIM" ;
] , [ # ] , [
lv2:index 1 ; # lv2:index 1 ;
lv2:symbol "gain1" ; # lv2:symbol "gain1" ;
lv2:name "GAIN" ; # lv2:name "GAIN" ;
] , [ # ] , [
lv2:index 2 ; # lv2:index 2 ;
lv2:symbol "locut1" ; # lv2:symbol "locut1" ;
lv2:name "LO CUT" ; # lv2:name "LO CUT" ;
] , [ # ] , [
lv2:index 3 ; # lv2:index 3 ;
lv2:symbol "hicut1" ; # lv2:symbol "hicut1" ;
lv2:name "HI CUT" ; # lv2:name "HI CUT" ;
], [ # ], [
lv2:index 22 ; # lv2:index 22 ;
lv2:symbol "shape1" ; # lv2:symbol "shape1" ;
lv2:name "SHAPE1" ; # lv2:name "SHAPE1" ;
], [ # ], [
lv2:index 4 ; # lv2:index 4 ;
lv2:symbol "gain2_enable" ; # lv2:symbol "gain2_enable" ;
lv2:name "Ena" ; # lv2:name "Ena" ;
] , [ # ] , [
lv2:index 5 ; # lv2:index 5 ;
lv2:symbol "trim2" ; # lv2:symbol "trim2" ;
lv2:name "TRIM" ; # lv2:name "TRIM" ;
] , [ # ] , [
lv2:index 6 ; # lv2:index 6 ;
lv2:symbol "gain2" ; # lv2:symbol "gain2" ;
lv2:name "GAIN" ; # lv2:name "GAIN" ;
] , [ # ] , [
lv2:index 7 ; # lv2:index 7 ;
lv2:symbol "locut2" ; # lv2:symbol "locut2" ;
lv2:name "LO CUT" ; # lv2:name "LO CUT" ;
] , [ # ] , [
lv2:index 8 ; # lv2:index 8 ;
lv2:symbol "hicut2" ; # lv2:symbol "hicut2" ;
lv2:name "HI CUT" ; # lv2:name "HI CUT" ;
], [ # ], [
lv2:index 23 ; # lv2:index 23 ;
lv2:symbol "shape2" ; # lv2:symbol "shape2" ;
lv2:name "SHAPE2" ; # lv2:name "SHAPE2" ;
] , [ # ] , [
lv2:index 9 ; # lv2:index 9 ;
lv2:symbol "gain3_enable" ; # lv2:symbol "gain3_enable" ;
lv2:name "Ena" ; # lv2:name "Ena" ;
] , # ] ,
[ # [
lv2:index 10 ; # lv2:index 10 ;
lv2:symbol "trim3" ; # lv2:symbol "trim3" ;
lv2:name "TRIM" ; # lv2:name "TRIM" ;
] , [ # ] , [
lv2:index 11 ; # lv2:index 11 ;
lv2:symbol "gain3" ; # lv2:symbol "gain3" ;
lv2:name "GAIN" ; # lv2:name "GAIN" ;
] , [ # ] , [
lv2:index 12 ; # lv2:index 12 ;
lv2:symbol "locut3" ; # lv2:symbol "locut3" ;
lv2:name "LO CUT" ; # lv2:name "LO CUT" ;
] , [ # ] , [
lv2:index 13 ; # lv2:index 13 ;
lv2:symbol "hicut3" ; # lv2:symbol "hicut3" ;
lv2:name "HI CUT" ; # lv2:name "HI CUT" ;
] , [ # ] , [
lv2:index 24 ; # lv2:index 24 ;
lv2:symbol "shape3" ; # lv2:symbol "shape3" ;
lv2:name "SHAPE3" ; # lv2:name "SHAPE3" ;
], [ # ], [
lv2:index 14 ; # lv2:index 14 ;
lv2:symbol "sag" ; # lv2:symbol "sag" ;
lv2:name "SAG" ; # lv2:name "SAG" ;
] , [ # ] , [
lv2:index 15 ; # lv2:index 15 ;
lv2:symbol "sagd" ; # lv2:symbol "sagd" ;
lv2:name "SAGD" ; # lv2:name "SAGD" ;
], [ # ], [
lv2:index 16 ; # lv2:index 16 ;
lv2:symbol "master" ; # lv2:symbol "master" ;
lv2:name "MASTER" ; # lv2:name "MASTER" ;
], # ],
[ # [
a lv2:InputPort , # a lv2:InputPort ,
lv2:ControlPort ; # lv2:ControlPort ;
lv2:index 21 ; # lv2:index 21 ;
lv2:symbol "sagf" ; # lv2:symbol "sagf" ;
lv2:name "SagF"; # lv2:name "SagF";
] # ]
; # ;
] . # ] .
<http://two-play.com/plugins/toob-input_stage> # <http://two-play.com/plugins/toob-input_stage>
modgui:gui [ # modgui:gui [
modgui:resourcesDirectory <modgui> ; # modgui:resourcesDirectory <modgui> ;
modgui:javascript <modgui/script-toob-input-stage.js> ; # modgui:javascript <modgui/script-toob-input-stage.js> ;
modgui:iconTemplate <modgui/icon-toob-input-stage.html> ; # modgui:iconTemplate <modgui/icon-toob-input-stage.html> ;
modgui:stylesheet <modgui/stylesheet-toob.css> ; # modgui:stylesheet <modgui/stylesheet-toob.css> ;
modgui:screenshot <modgui/screenshot-toob-input-stage.png> ; # modgui:screenshot <modgui/screenshot-toob-input-stage.png> ;
modgui:thumbnail <modgui/thumbnail-toob-input-stage.png> ; # modgui:thumbnail <modgui/thumbnail-toob-input-stage.png> ;
modgui:brand "TooB" ; # modgui:brand "TooB" ;
modgui:label "TooB Input Stage" ; # modgui:label "TooB Input Stage" ;
modgui:monitoredOutputs [ lv2:symbol "notify"] ; # modgui:monitoredOutputs [ lv2:symbol "notify"] ;
modgui:port [ # modgui:port [
lv2:index 0 ; # lv2:index 0 ;
lv2:symbol "trim" ; # lv2:symbol "trim" ;
lv2:name "Trim" ; # lv2:name "Trim" ;
] , [ # ] , [
lv2:index 1 ; # lv2:index 1 ;
lv2:symbol "locut" ; # lv2:symbol "locut" ;
lv2:name "Lo Cut" ; # lv2:name "Lo Cut" ;
] , [ # ] , [
lv2:index 2 ; # lv2:index 2 ;
lv2:symbol "bright" ; # lv2:symbol "bright" ;
lv2:name "Bright" ; # lv2:name "Bright" ;
] , [ # ] , [
lv2:index 3 ; # lv2:index 3 ;
lv2:symbol "brightf" ; # lv2:symbol "brightf" ;
lv2:name "Bright F" ; # lv2:name "Bright F" ;
] , [ # ] , [
lv2:index 4 ; # lv2:index 4 ;
lv2:symbol "hicut" ; # lv2:symbol "hicut" ;
lv2:name "Hi Cut" ; # lv2:name "Hi Cut" ;
] , [ # ] , [
lv2:index 5 ; # lv2:index 5 ;
lv2:symbol "gate_t" ; # lv2:symbol "gate_t" ;
lv2:name "Gate T" ; # lv2:name "Gate T" ;
] , [ # ] , [
lv2:index 6 ; # lv2:index 6 ;
lv2:symbol "boost" ; # lv2:symbol "boost" ;
lv2:name "Boost" ; # lv2:name "Boost" ;
] # ]
; # ;
] . # ] .
<http://two-play.com/plugins/toob-cab-sim> # <http://two-play.com/plugins/toob-cab-sim>
modgui:gui [ # modgui:gui [
modgui:resourcesDirectory <modgui> ; # modgui:resourcesDirectory <modgui> ;
modgui:javascript <modgui/script-toob-cab-sim.js> ; # modgui:javascript <modgui/script-toob-cab-sim.js> ;
modgui:iconTemplate <modgui/icon-toob-cab-sim.html> ; # modgui:iconTemplate <modgui/icon-toob-cab-sim.html> ;
modgui:stylesheet <modgui/stylesheet-toob.css> ; # modgui:stylesheet <modgui/stylesheet-toob.css> ;
modgui:screenshot <modgui/screenshot-toob-cab-sim.png> ; # modgui:screenshot <modgui/screenshot-toob-cab-sim.png> ;
modgui:thumbnail <modgui/thumbnail-toob-cab-sim.png> ; # modgui:thumbnail <modgui/thumbnail-toob-cab-sim.png> ;
modgui:brand "TooB" ; # modgui:brand "TooB" ;
modgui:label "TooB Cab Simulator" ; # modgui:label "TooB Cab Simulator" ;
modgui:monitoredOutputs [ lv2:symbol "notify"] ; # modgui:monitoredOutputs [ lv2:symbol "notify"] ;
modgui:port [ # modgui:port [
lv2:index 0 ; # lv2:index 0 ;
lv2:symbol "locut" ; # lv2:symbol "locut" ;
lv2:name "Lo Cut" ; # lv2:name "Lo Cut" ;
] , [ # ] , [
lv2:index 1 ; # lv2:index 1 ;
lv2:symbol "bright" ; # lv2:symbol "bright" ;
lv2:name "Bright" ; # lv2:name "Bright" ;
] , [ # ] , [
lv2:index 2 ; # lv2:index 2 ;
lv2:symbol "brightf" ; # lv2:symbol "brightf" ;
lv2:name "F" ; # lv2:name "F" ;
] , [ # ] , [
lv2:index 3 ; # lv2:index 3 ;
lv2:symbol "hicut" ; # lv2:symbol "hicut" ;
lv2:name "Hi Cut" ; # lv2:name "Hi Cut" ;
], [ # ], [
lv2:index 4 ; # lv2:index 4 ;
lv2:symbol "comb" ; # lv2:symbol "comb" ;
lv2:name "Comb" ; # lv2:name "Comb" ;
], [ # ], [
lv2:index 5 ; # lv2:index 5 ;
lv2:symbol "combf" ; # lv2:symbol "combf" ;
lv2:name "F" ; # lv2:name "F" ;
], [ # ], [
lv2:index 6 ; # lv2:index 6 ;
lv2:symbol "trim" ; # lv2:symbol "trim" ;
lv2:name "Trim" ; # lv2:name "Trim" ;
] # ]
; # ;
] . # ] .
<http://two-play.com/plugins/toob-tone-stack> # <http://two-play.com/plugins/toob-tone-stack>
modgui:gui [ # modgui:gui [
modgui:resourcesDirectory <modgui> ; # modgui:resourcesDirectory <modgui> ;
modgui:javascript <modgui/script-toob-tone-stack.js> ; # modgui:javascript <modgui/script-toob-tone-stack.js> ;
modgui:iconTemplate <modgui/icon-toob-tone-stack.html> ; # modgui:iconTemplate <modgui/icon-toob-tone-stack.html> ;
modgui:stylesheet <modgui/stylesheet-toob.css> ; # modgui:stylesheet <modgui/stylesheet-toob.css> ;
modgui:screenshot <modgui/screenshot-toob-tone-stack.png> ; # modgui:screenshot <modgui/screenshot-toob-tone-stack.png> ;
modgui:thumbnail <modgui/thumbnail-toob-tone-stack.png> ; # modgui:thumbnail <modgui/thumbnail-toob-tone-stack.png> ;
modgui:brand "TooB" ; # modgui:brand "TooB" ;
modgui:label "TooB Tone Stack" ; # modgui:label "TooB Tone Stack" ;
modgui:monitoredOutputs [ lv2:symbol "notify"] ; # modgui:monitoredOutputs [ lv2:symbol "notify"] ;
modgui:port [ # modgui:port [
lv2:index 0 ; # lv2:index 0 ;
lv2:symbol "bass" ; # lv2:symbol "bass" ;
lv2:name "Bass" ; # lv2:name "Bass" ;
] , [ # ] , [
lv2:index 1 ; # lv2:index 1 ;
lv2:symbol "mid" ; # lv2:symbol "mid" ;
lv2:name "Mid" ; # lv2:name "Mid" ;
], [ # ], [
lv2:index 2 ; # lv2:index 2 ;
lv2:symbol "treble" ; # lv2:symbol "treble" ;
lv2:name "Treble" ; # lv2:name "Treble" ;
] , [ # ] , [
lv2:index 3 ; # lv2:index 3 ;
lv2:symbol "ampmodel" ; # lv2:symbol "ampmodel" ;
lv2:name "Amp Model" ; # lv2:name "Amp Model" ;
] # ]
; # ;
] . # ] .
+189 -159
View File
@@ -21,176 +21,206 @@ add_custom_command(
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
DEPENDS DEPENDS
src/AlsaMidiDeviceInfo.tsx src/OkCancelDialog.tsx
src/SearchControl.tsx src/PluginControl.tsx
src/SplitControlView.tsx src/reportWebVitals.ts
src/WifiConfigSettings.tsx
src/FullScreenIME.tsx
src/JackHostStatus.tsx src/JackHostStatus.tsx
src/PluginPresetsDialog.tsx
src/ToobSpectrumAnalyzerView.tsx
src/MidiBindingsDialog.tsx
src/MidiBinding.tsx
src/TemporaryDrawer.tsx
src/ToobFrequencyResponseView.tsx
src/index.css src/index.css
src/setupTests.ts src/PluginOutputControl.tsx
src/SearchFilter.tsx src/BankDialog.tsx
src/VuMeter.tsx
src/StringBuilder.tsx
src/FilePropertyDialog.tsx
src/GxTunerControl.tsx
src/App.tsx
src/GxTunerView.tsx
src/Rect.tsx
src/ToobSpectrumResponseView.tsx
src/DialogEx.tsx
src/GovernorSettings.tsx
src/FilePropertyControl.tsx
src/JackServerSettingsDialog.tsx
src/ZoomedUiControl.tsx
src/Pedal.tsx
src/FullScreenIME.tsx
src/PluginPreset.tsx
src/SystemMidiBindingsDialog.tsx
src/AppThemed.tsx
src/MainPage.tsx src/MainPage.tsx
src/PiPedalModel.tsx src/PiPedalModel.tsx
src/AppThemed.css src/PedalboardView.tsx
src/ControlViewFactory.tsx
src/PiPedalSocket.tsx
src/PluginClass.tsx
src/SplitControlView.tsx
src/logo.svg
src/ToobToneStackView.tsx
src/Banks.tsx
src/ToobPowerStage2View.tsx
src/ListSelectDialog.tsx
src/ToobWaveShapeView.tsx
src/PluginInfoDialog.tsx
src/SearchFilter.tsx
src/SearchControl.tsx
src/JackServerSettings.tsx
src/WifiChannel.tsx
src/WifiConfigDialog.tsx
src/App.test.tsx
src/PluginPresetSelector.tsx src/PluginPresetSelector.tsx
src/Pedal.tsx src/ObservableProperty.tsx
src/ToobMLView.tsx src/PresetDialog.tsx
src/SettingsDialog.tsx src/AndroidHost.tsx
src/SelectHoverBackground.tsx
src/WifiDirectConfigDialog.tsx src/WifiDirectConfigDialog.tsx
src/WifiDirectConfigSettings.tsx src/WifiDirectConfigSettings.tsx
src/PiPedalSocket.tsx src/WifiConfigSettings.tsx
src/ToobFrequencyResponseView.tsx
src/ControlViewFactory.tsx
src/Utility.tsx
src/ToobToneStackView.tsx
src/SelectHoverBackground.tsx
src/MidiBindingsDialog.tsx
src/TemporaryDrawer.tsx
src/GxTunerView.tsx
src/ToobInputStageView.tsx
src/DraggableGrid.tsx
src/JackStatusView.tsx
src/PluginControl.tsx
src/XxxSnippet.tsx
src/PluginPreset.tsx
src/Jack.tsx
src/AlsaDeviceInfo.tsx
src/MidiBinding.tsx
src/PiPedalError.tsx
src/IControlViewFactory.tsx
src/Lv2Plugin.tsx
src/Pedalboard.tsx
src/AndroidHost.tsx
src/PedalboardView.tsx
src/PresetDialog.tsx
src/AppThemed.tsx
src/ZoomedDial.tsx
src/RenameDialog.tsx
src/SplitUiControls.tsx
src/GovernorSettings.tsx
src/AboutDialog.tsx
src/ToobSpectrumResponseView.tsx
src/PluginControlView.tsx
src/NoChangePassword.tsx
src/ToobSpectrumAnalyzerView.tsx
src/MidiBindingView.tsx
src/GxTunerControl.tsx
src/Banks.tsx
src/PluginPresetsDialog.tsx
src/BankDialog.tsx
src/UploadPresetDialog.tsx
src/ToobPowerStage2View.tsx
src/index.tsx
src/Units.tsx
src/VuMeter.tsx
src/App.test.tsx
src/DialogEx.tsx
src/StringBuilder.tsx
src/SelectChannelsDialog.tsx
src/Draggable.tsx src/Draggable.tsx
src/ZoomedUiControl.tsx src/JsonAtom.tsx
src/logo.svg src/SplitUiControls.tsx
src/Rect.tsx src/SelectChannelsDialog.tsx
src/PluginClass.tsx src/ToobMLView.tsx
src/reportWebVitals.ts src/IControlViewFactory.tsx
src/PluginIcon.tsx src/AppThemed.css
src/App.tsx src/ZoomedDial.tsx
src/ResizeResponsiveComponent.tsx src/Units.tsx
src/SvgPathBuilder.tsx src/UploadPresetDialog.tsx
src/NumericInput.tsx src/NumericInput.tsx
src/JackServerSettings.tsx src/Pedalboard.tsx
src/ListSelectDialog.tsx
src/react-app-env.d.ts
src/JackServerSettingsDialog.tsx
src/ObservableProperty.tsx
src/SelectMidiChannelsDialog.tsx src/SelectMidiChannelsDialog.tsx
src/WifiChannel.tsx src/AlsaMidiDeviceInfo.tsx
src/LoadPluginDialog.tsx src/ResizeResponsiveComponent.tsx
src/WifiConfigDialog.tsx src/RenameDialog.tsx
src/PluginInfoDialog.tsx src/SystemMidiBindingView.tsx
src/ToobWaveShapeView.tsx src/OldDeleteIcon.tsx
src/ToobCabSimView.tsx src/ToobInputStageView.tsx
src/XxxSnippet.tsx
src/NoChangePassword.tsx
src/react-app-env.d.ts
src/PiPedalError.tsx
src/AlsaDeviceInfo.tsx
src/index.tsx
src/SettingsDialog.tsx
src/PluginControlView.tsx
src/PresetSelector.tsx src/PresetSelector.tsx
src/OkCancelDialog.tsx src/ToobCabSimView.tsx
src/Utility.tsx
public/css/roboto.css src/Lv2Plugin.tsx
public/fonts/Roboto-BlackItalic.woff2 src/Jack.tsx
public/fonts/Roboto-Black.woff2 src/JackStatusView.tsx
public/fonts/Roboto-BoldItalic.woff2 src/AboutDialog.tsx
public/fonts/Roboto-Bold.woff2 src/setupTests.ts
public/fonts/Roboto-Italic.woff2 src/DraggableGrid.tsx
public/fonts/Roboto-LightItalic.woff2 src/SvgPathBuilder.tsx
public/fonts/Roboto-Light.woff2 src/LoadPluginDialog.tsx
public/fonts/Roboto-MediumItalic.woff2 src/MidiBindingView.tsx
public/fonts/Roboto-Medium.woff2 src/PluginIcon.tsx
public/fonts/Roboto-Regular.woff2 src/UploadFileDialog.tsx
public/fonts/Roboto-ThinItalic.woff2
public/fonts/Roboto-Thin.woff2 public/
public/css
public/iso_codes.json public/css/roboto.css
public/logo512.png public/logo192x.png
public/index.html public/robots.txt
public/manifest.json public/img
public/var public/img/ic_drawer_2.png
public/var/current_pedalboard.json public/img/fx_constant.svg
public/var/uiplugins.json public/img/cx_mono.svg
public/var/config.json public/img/cx_stereo.svg
public/var/plugin_classes.json public/img/fx_distortion.svg
public/logo192.png public/img/fx_oscillator.svg
public/serve.json public/img/settings_black_24dp.svg
public/robots.txt public/img/fx_filter.svg
public/sample_lv2_plugins.json public/img/delete_outline_black_24dp.svg
public/logo192x.png public/img/fx_function.svg
public/img/fx_analyzer.svg public/img/fx_generator.svg
public/img/fx_flanger.svg public/img/old_delete_outline_black_24dp.svg
public/img/cx_stereo.svg public/img/ic_bank.svg
public/img/fx_split_a.svg public/img/fx_compressor.svg
public/img/fx_dial.svg public/img/file_download_black_24dp.svg
public/img/drive_file_rename_outline_black_24dp.svg public/img/fx_filter_hp.svg
public/img/fx_filter.svg public/img/fx_plugin.svg
public/img/fx_filter_hp.svg public/img/fx_error.svg
public/img/cx_mono.svg public/img/fx_gate.svg
public/img/fx_limiter.svg public/img/cc-by.png
public/img/fx_converter.svg public/img/ic_midi.svg
public/img/fx_simulator.svg public/img/ic_pluginpreset.svg
public/img/fx_delay.svg public/img/fx_split_a.svg
public/img/fx_reverb.svg public/img/fx_utility.svg
public/img/fx_empty.svg public/img/ic_navigate_before.svg
public/img/fx_eq.svg public/img/ic_drawer_2.svg
public/img/edit_banks.svg public/img/ic_pluginpreset2.svg
public/img/fx_gate.svg public/img/fx_parametric_eq.svg
public/img/settings_black_24dp.svg public/img/fx_terminal.svg
public/img/help_outline_black_24dp.svg public/img/ic_presets.svg
public/img/fx_oscillator.svg public/img/VST_Logo_Steinberg.ico
public/img/fx_split_b.svg public/img/fx_flanger.svg
public/img/fx_phaser.svg public/img/fx_analyzer.svg
public/img/fx_amplifier.svg public/img/fx_delay.svg
public/img/fx_plugin.svg public/img/fx_spectral.svg
public/img/ic_drawer.svg public/img/edit_banks.svg
public/img/ic_drawer_2.png public/img/fx_chorus.svg
public/img/fx_simulator.svg
public/img/fx_terminal.svg public/img/drive_file_rename_outline_black_24dp.svg
public/img/fx_spatial.svg public/img/fx_mixer.svg
public/img/fx_pitch.svg public/img/fx_eq.svg
public/img/ic_logo.svg public/img/fx_modulator.svg
public/img/fx_flanger2.svg public/img/file_upload_black_24dp.svg
public/img/fx_function.svg public/img/fx_pitch.svg
public/img/fx_lr.svg public/img/ic_navigate_next.svg
public/img/fx_generator.svg public/img/fx_phaser.svg
public/img/fx_spectral.svg public/img/ic_drawer.svg
public/img/fx_chorus.svg public/img/fx_amplifier.svg
public/img/fx_utility.svg public/img/save_bank_as.svg
public/img/fx_mixer.svg public/img/fx_lr.svg
public/img/ic_presets.svg public/img/fx_instrument.svg
public/img/fx_instrument.svg public/img/fx_reverb.svg
public/img/fx_modulator.svg public/img/fx_limiter.svg
public/img/fx_compressor.svg public/img/VST_Logo_Steinberg.png
public/img/fx_constant.svg public/img/fx_empty.svg
public/img/fx_distortion.svg public/img/fx_dial.svg
public/img/save_bank_as.svg public/img/ic_logo.svg
public/favicon.ico 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/vst.svg
public/img/vst.png
public/sample_lv2_plugins.json
public/serve.json
public/fonts
public/fonts/Roboto-LightItalic.woff2
public/fonts/Roboto-Light.woff2
public/fonts/Roboto-BlackItalic.woff2
public/fonts/Roboto-ThinItalic.woff2
public/fonts/Roboto-Bold.woff2
public/fonts/Roboto-Italic.woff2
public/fonts/Roboto-Black.woff2
public/fonts/Roboto-BoldItalic.woff2
public/fonts/Roboto-Regular.woff2
public/fonts/Roboto-Medium.woff2
public/fonts/Roboto-Thin.woff2
public/fonts/LICENSE.txt
public/fonts/Roboto-MediumItalic.woff2
public/favicon.ico
public/iso_codes.json
public/logo192.png
public/logo512.png
public/index.html
public/manifest.json
public/var
public/var/config.json
public/var/current_pedalboard.json
public/var/uiplugins.json
public/var/plugin_classes.json
) )
add_custom_target ( add_custom_target (
+5 -3
View File
@@ -837,9 +837,11 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
> >
<DialogContent> <DialogContent>
<DialogContentText id="alert-dialog-description"> <DialogContentText id="alert-dialog-description">
{ <Typography variant="body2">
this.model_.alertMessage.get() {
} this.state.alertDialogMessage
}
</Typography>
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
+27 -16
View File
@@ -27,15 +27,12 @@ import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles'; import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles'; import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import { PiPedalFileProperty } from './Lv2Plugin'; import { UiFileProperty } from './Lv2Plugin';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, ListenHandle, StateChangedHandle } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, ListenHandle, StateChangedHandle } from './PiPedalModel';
import ButtonBase from '@mui/material/ButtonBase' import ButtonBase from '@mui/material/ButtonBase'
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import {PedalboardItem} from './Pedalboard';
export const StandardItemSize = { width: 80, height: 140 } export const StandardItemSize = { width: 80, height: 140 }
@@ -73,13 +70,14 @@ const styles = (theme: Theme) => createStyles({
export interface FilePropertyControlProps extends WithStyles<typeof styles> { export interface FilePropertyControlProps extends WithStyles<typeof styles> {
instanceId: number; fileProperty: UiFileProperty;
fileProperty: PiPedalFileProperty; pedalboardItem: PedalboardItem;
onFileClick: (fileProperty: PiPedalFileProperty, value: string) => void; onFileClick: (fileProperty: UiFileProperty, value: string) => void;
theme: Theme; theme: Theme;
} }
type FilePropertyControlState = { type FilePropertyControlState = {
error: boolean; error: boolean;
hasValue: boolean;
value: string; value: string;
}; };
@@ -96,6 +94,7 @@ const FilePropertyControl =
this.state = { this.state = {
error: false, error: false,
hasValue: false,
value: "", value: "",
}; };
this.model = PiPedalModelFactory.getInstance(); this.model = PiPedalModelFactory.getInstance();
@@ -108,12 +107,12 @@ const FilePropertyControl =
refreshPatchProperty() refreshPatchProperty()
{ {
this.model.getPatchProperty(this.props.instanceId, this.props.fileProperty.patchProperty) this.model.getPatchProperty(this.props.pedalboardItem.instanceId, this.props.fileProperty.patchProperty)
.then( .then(
(json: any) => { (json: any) => {
if (json && json.otype_ === "Path") { if (json && json.otype_ === "Path") {
let path = json.value as string; let path = json.value as string;
this.setState({ value: path }); this.setState({ value: path, hasValue: true });
} }
} }
) )
@@ -138,7 +137,7 @@ const FilePropertyControl =
} }
this.refreshPatchProperty(); this.refreshPatchProperty();
this.stateChangedHandle = this.model.addLv2StateChangedListener( this.stateChangedHandle = this.model.addLv2StateChangedListener(
this.props.instanceId, this.props.pedalboardItem.instanceId,
() => { () => {
this.refreshPatchProperty(); this.refreshPatchProperty();
}); });
@@ -149,19 +148,25 @@ const FilePropertyControl =
this.model.removeLv2StateChangedListener(this.stateChangedHandle); this.model.removeLv2StateChangedListener(this.stateChangedHandle);
} }
} }
private mounted: boolean = false;
componentDidMount() { componentDidMount() {
this.mounted = true;
this.subscribeToPropertyGet(); this.subscribeToPropertyGet();
} }
componentWillUnmount() { componentWillUnmount() {
this.unsubscribeToPropertyGet(); this.unsubscribeToPropertyGet();
this.mounted = false;
} }
componentDidUpdate(prevProps: Readonly<FilePropertyControlProps>, prevState: Readonly<FilePropertyControlState>, snapshot?: any): void { componentDidUpdate(prevProps: Readonly<FilePropertyControlProps>, prevState: Readonly<FilePropertyControlState>, snapshot?: any): void {
if (prevProps.fileProperty.patchProperty !== this.props.fileProperty.patchProperty if (prevProps.fileProperty.patchProperty !== this.props.fileProperty.patchProperty
|| prevProps.instanceId !== this.props.instanceId) { || prevProps.pedalboardItem.instanceId !== this.props.pedalboardItem.instanceId
this.setState({ value: "" }); || prevProps.pedalboardItem.stateUpdateCount !== this.props.pedalboardItem.stateUpdateCount
) {
this.unsubscribeToPropertyGet(); this.unsubscribeToPropertyGet();
this.subscribeToPropertyGet(); this.subscribeToPropertyGet();
} }
} }
@@ -193,9 +198,15 @@ const FilePropertyControl =
//let classes = this.props.classes; //let classes = this.props.classes;
let fileProperty = this.props.fileProperty; let fileProperty = this.props.fileProperty;
let value = this.fileNameOnly(this.state.value); let value = "\u00A0";
if (!value || value.length === 0) { if (this.state.hasValue)
value = "\u00A0"; {
if (this.state.value.length === 0)
{
value = "<none>";
} else {
value = this.fileNameOnly(this.state.value);
}
} }
let item_width = 264; let item_width = 264;
+98 -12
View File
@@ -33,7 +33,7 @@ import IconButton from '@mui/material/IconButton';
import OldDeleteIcon from './OldDeleteIcon'; import OldDeleteIcon from './OldDeleteIcon';
import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import { PiPedalFileProperty } from './Lv2Plugin'; import { UiFileProperty } from './Lv2Plugin';
import ButtonBase from '@mui/material/ButtonBase'; import ButtonBase from '@mui/material/ButtonBase';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import DialogEx from './DialogEx'; import DialogEx from './DialogEx';
@@ -42,9 +42,9 @@ import OkCancelDialog from './OkCancelDialog';
export interface FilePropertyDialogProps { export interface FilePropertyDialogProps {
open: boolean, open: boolean,
fileProperty: PiPedalFileProperty, fileProperty: UiFileProperty,
selectedFile: string, selectedFile: string,
onOk: (fileProperty: PiPedalFileProperty, selectedItem: string) => void, onOk: (fileProperty: UiFileProperty, selectedItem: string) => void,
onCancel: () => void onCancel: () => void
}; };
@@ -53,6 +53,8 @@ export interface FilePropertyDialogState {
selectedFile: string; selectedFile: string;
hasSelection: boolean; hasSelection: boolean;
files: string[]; files: string[];
columns: number;
columnWidth: number;
openUploadFileDialog: boolean; openUploadFileDialog: boolean;
openConfirmDeleteDialog: boolean; openConfirmDeleteDialog: boolean;
}; };
@@ -70,13 +72,33 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
fullScreen: false, fullScreen: false,
selectedFile: props.selectedFile, selectedFile: props.selectedFile,
hasSelection: false, hasSelection: false,
columns: 0,
columnWidth: 1,
files: [], files: [],
openUploadFileDialog: false, openUploadFileDialog: false,
openConfirmDeleteDialog: false openConfirmDeleteDialog: false
}; };
this.requestScroll = true;
this.requestFiles(); this.requestFiles();
} }
private scrollRef: HTMLDivElement | null = null;
onScrollRef(element: HTMLDivElement | null) {
this.scrollRef = element;
this.maybeScrollIntoView();
}
private maybeScrollIntoView()
{
if (this.scrollRef !== null && this.state.files.length !== 0 && this.mounted && this.requestScroll)
{
this.requestScroll = false;
let options: ScrollIntoViewOptions = { block: "nearest"};
options.block = "nearest";
this.scrollRef.scrollIntoView(options);
}
}
private mounted: boolean = false; private mounted: boolean = false;
private model: PiPedalModel; private model: PiPedalModel;
@@ -91,6 +113,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
this.model.requestFileList(this.props.fileProperty) this.model.requestFileList(this.props.fileProperty)
.then((files) => { .then((files) => {
if (this.mounted) { if (this.mounted) {
files.splice(0,0,"");
this.setState({ files: files, hasSelection: this.isFileInList(files, this.state.selectedFile) }); this.setState({ files: files, hasSelection: this.isFileInList(files, this.state.selectedFile) });
} }
}).catch((error) => { }).catch((error) => {
@@ -98,10 +121,39 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
}); });
} }
private lastDivRef : HTMLDivElement | null = null;
onMeasureRef(div: HTMLDivElement | null)
{
this.lastDivRef = div;
if (div) {
let width = div.offsetWidth;
if (width === 0) return;
let columns = Math.floor((width-40)/280);
if(columns === 0)
{
columns = 1;
}
let columnWidth = (width-40)/columns;
if (columns !== this.state.columns || columnWidth !== this.state.columnWidth)
{
this.setState({columns: columns, columnWidth: columnWidth});
}
}
}
onWindowSizeChanged(width: number, height: number): void { onWindowSizeChanged(width: number, height: number): void {
this.setState({ fullScreen: height < 200 })
this.setState({
fullScreen: height < 200
})
if (this.lastDivRef !== null)
{
this.onMeasureRef(this.lastDivRef);
}
} }
private requestScroll: boolean = false;
componentDidMount() { componentDidMount() {
super.componentDidMount(); super.componentDidMount();
@@ -110,6 +162,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
componentWillUnmount() { componentWillUnmount() {
super.componentWillUnmount(); super.componentWillUnmount();
this.mounted = false; this.mounted = false;
this.lastDivRef = null;
} }
componentDidUpdate(prevProps: Readonly<FilePropertyDialogProps>, prevState: Readonly<FilePropertyDialogState>, snapshot?: any): void { componentDidUpdate(prevProps: Readonly<FilePropertyDialogProps>, prevState: Readonly<FilePropertyDialogState>, snapshot?: any): void {
super.componentDidUpdate?.(prevProps, prevState, snapshot); super.componentDidUpdate?.(prevProps, prevState, snapshot);
@@ -118,6 +171,11 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
if (this.props.open) if (this.props.open)
{ {
this.requestFiles() this.requestFiles()
this.requestScroll = true;
if (this.state.selectedFile !== this.props.selectedFile)
{
this.setState({selectedFile: this.props.selectedFile});
}
} }
} else if (prevProps.fileProperty !== this.props.fileProperty) { } else if (prevProps.fileProperty !== this.props.fileProperty) {
this.requestFiles() this.requestFiles()
@@ -144,6 +202,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
private isFileInList(files: string[], file: string) { private isFileInList(files: string[], file: string) {
let hasSelection = false; let hasSelection = false;
if (file === "") return true;
for (var listFile of files) { for (var listFile of files) {
if (listFile === file) { if (listFile === file) {
hasSelection = true; hasSelection = true;
@@ -154,6 +213,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
} }
onSelectValue(selectedFile: string) { onSelectValue(selectedFile: string) {
this.requestScroll = true;
this.setState({ selectedFile: selectedFile, hasSelection: this.isFileInList(this.state.files, selectedFile) }) this.setState({ selectedFile: selectedFile, hasSelection: this.isFileInList(this.state.files, selectedFile) })
} }
onDoubleClickValue(selectedFile: string) { onDoubleClickValue(selectedFile: string) {
@@ -205,9 +265,13 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
} }
} }
private wantsScrollRef: boolean = true;
mapKey: number = 0; mapKey: number = 0;
render() { render() {
this.mapKey = 0; this.mapKey = 0;
let columnWidth = this.state.columnWidth;
return this.props.open && return this.props.open &&
( (
<DialogEx onClose={() => this.props.onCancel()} open={this.props.open} tag="FilePropertyDialog" fullWidth maxWidth="xl" style={{ height: "90%" }} <DialogEx onClose={() => this.props.onCancel()} open={this.props.open} tag="FilePropertyDialog" fullWidth maxWidth="xl" style={{ height: "90%" }}
@@ -223,22 +287,40 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
</div> </div>
</DialogTitle> </DialogTitle>
<div style={{ flex: "0 0 auto", height: "1px", background: "rgba(0,0,0,0.2" }}>&nbsp;</div> <div style={{ flex: "0 0 auto", height: "1px", background: "rgba(0,0,0,0.2" }}>&nbsp;</div>
<div style={{ flex: "1 1 auto", height: "300", display: "flex", flexFlow: "row nowrap", overflowX: "auto", overflowY: "visible" }}> <div style={{ flex: "1 1 auto", height: "300", display: "flex", flexFlow: "row wrap", overflowX: "hidden", overflowY: "auto" }}>
<div style={{ flex: "1 1 100%", display: "flex", flexFlow: "column wrap", justifyContent: "start", alignItems: "flex-start", paddingLeft: 16, paddingTop: 16 }}> <div
ref={(element)=> this.onMeasureRef(element)}
style={{ flex: "1 1 100%", display: "flex", flexFlow: "row wrap",
justifyContent: "flex-start", alignContent: "flex-start", paddingLeft: 16, paddingTop: 16,paddingBottom: 16 }}>
{ {
(this.state.columns !== 0) && // don't render until we have number of columns derived from layout.
this.state.files.map( this.state.files.map(
(value: string, index: number) => { (value: string, index: number) => {
let displayValue = value;
if (displayValue === "")
{
displayValue = "<none>";
} else {
displayValue = this.fileNameOnly(value);
}
let selected = value === this.state.selectedFile; let selected = value === this.state.selectedFile;
let selectBg = selected ? "rgba(0,0,0,0.15)" : "rgba(0,0,0,0.0)"; let selectBg = selected ? "rgba(0,0,0,0.15)" : "rgba(0,0,0,0.0)";
let scrollRef: ((element: HTMLDivElement | null) => void) | undefined = undefined;
if (selected)
{
scrollRef = (element)=> { this.onScrollRef(element)};
}
return ( return (
<ButtonBase key={this.mapKey++} <ButtonBase key={this.mapKey++}
style={{ width: "320px", flex: "0 0 48px", position: "relative" }}
style={{ width: columnWidth, flex: "0 0 auto", height: 48, position: "relative" }}
onClick={() => this.onSelectValue(value)} onDoubleClick={()=> {this.onDoubleClickValue(value);}} onClick={() => this.onSelectValue(value)} onDoubleClick={()=> {this.onDoubleClickValue(value);}}
> >
<div style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} /> <div ref={scrollRef} style={{ position: "absolute", background: selectBg, width: "100%", height: "100%", borderRadius: 4 }} />
<div style={{ display: "flex", flexFlow: "row nowrap", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}> <div style={{ display: "flex", flexFlow: "row nowrap", textOverflow: "ellipsis", justifyContent: "start", alignItems: "center", width: "100%", height: "100%" }}>
<AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} /> <AudioFileIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
<Typography noWrap style={{ flex: "1 1 auto", textAlign: "left" }}>{this.fileNameOnly(value)}</Typography> <Typography noWrap style={{ flex: "1 1 auto", textAlign: "left" }}>{displayValue}</Typography>
</div> </div>
</ButtonBase> </ButtonBase>
); );
@@ -265,7 +347,11 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent<FilePr
<Button onClick={() => { this.props.onCancel(); }} aria-label="cancel"> <Button onClick={() => { this.props.onCancel(); }} aria-label="cancel">
Cancel Cancel
</Button> </Button>
<Button style={{ flex: "0 0 auto" }} onClick={() => { this.props.onOk(this.props.fileProperty, this.state.selectedFile); }} color="secondary" disabled={!this.state.hasSelection} aria-label="select"> <Button style={{ flex: "0 0 auto" }}
onClick={() => { this.props.onOk(this.props.fileProperty, this.state.selectedFile); }}
color="secondary"
disabled={(!this.state.hasSelection) && this.state.selectedFile !== ""} aria-label="select"
>
Select Select
</Button> </Button>
</div> </div>
+73 -18
View File
@@ -107,23 +107,78 @@ export class PortGroup {
program_list_id: number = -1; program_list_id: number = -1;
}; };
export class PiPedalFileType { export class UiFileType {
deserialize(input: any): PiPedalFileType { deserialize(input: any): UiFileType {
this.name = input.name; this.name = input.name;
this.fileExtension = input.fileExtension; this.fileExtension = input.fileExtension;
this.mimeType = input.mimeType;
return this; return this;
} }
static deserialize_array(input: any): PiPedalFileType[] static deserialize_array(input: any): UiFileType[]
{ {
let result: PiPedalFileType[] = []; let result: UiFileType[] = [];
for (let i = 0; i < input.length; ++i) for (let i = 0; i < input.length; ++i)
{ {
result[i] = new PiPedalFileType().deserialize(input[i]); result[i] = new UiFileType().deserialize(input[i]);
}
return result;
}
private static IsAndroid() : boolean
{
return /Android/i.test(navigator.userAgent);
}
static MergeMimeTypes(fileTypes: UiFileType[]): string
{
if (fileTypes.length === 0) {
return "";
}
let result = fileTypes[0].mimeType;
for (let i = 1; i < fileTypes.length; ++i)
{
let fileType = fileTypes[i];
if (fileType.mimeType !== result)
{
if (result.startsWith("audio/") && fileType.mimeType.startsWith("audio/"))
{
result = "audio/*";
} else if (result.startsWith("video/") && fileType.mimeType.startsWith("video/"))
{
result = "video/*";
} else if (result.startsWith("text/") && fileType.mimeType.startsWith("text/"))
{
result = "text/*";
} else {
result = "application/octet-stream";
}
}
}
if (this.IsAndroid())
{
if (result.startsWith("audio/")) result = "audio/*";
if (result.startsWith("video/")) result = "video/*";
if (result.startsWith("text/")) result = "text/*";
} else {
// chrome desktop thinks "application/octet-stream" is .exe, .com, or .bat.
// Feed it file extensions isntead.
if (result = "application/octet-stream")
{
result = "";
for (let i = 0; i < fileTypes.length; ++i)
{
if (i !== 0)
{
result += ',';
}
result += fileTypes[i].fileExtension;
}
}
} }
return result; return result;
} }
name: string = ""; name: string = "";
fileExtension: string = ""; fileExtension: string = "";
mimeType: string = "";
} }
export class UiPropertyNotification { export class UiPropertyNotification {
@@ -150,23 +205,23 @@ export class UiPropertyNotification {
protocol: string = ""; protocol: string = "";
}; };
export class PiPedalFileProperty { export class UiFileProperty {
deserialize(input: any): PiPedalFileProperty deserialize(input: any): UiFileProperty
{ {
this.label = input.label; this.label = input.label;
this.fileTypes = PiPedalFileType.deserialize_array(input.fileTypes); this.fileTypes = UiFileType.deserialize_array(input.fileTypes);
this.patchProperty = input.patchProperty; this.patchProperty = input.patchProperty;
this.directory = input.directory; this.directory = input.directory;
this.index = input.index; this.index = input.index;
this.portGroup = input.portGroup; this.portGroup = input.portGroup;
return this; return this;
} }
static deserialize_array(input: any): PiPedalFileProperty[] static deserialize_array(input: any): UiFileProperty[]
{ {
let result: PiPedalFileProperty[] = []; let result: UiFileProperty[] = [];
for (let i = 0; i < input.length; ++i) for (let i = 0; i < input.length; ++i)
{ {
result[i] = new PiPedalFileProperty().deserialize(input[i]); result[i] = new UiFileProperty().deserialize(input[i]);
} }
return result; return result;
} }
@@ -191,7 +246,7 @@ export class PiPedalFileProperty {
if (this.fileTypes.length === 0) { if (this.fileTypes.length === 0) {
return true; return true;
} }
let extension = PiPedalFileProperty.getFileExtension(filename); let extension = UiFileProperty.getFileExtension(filename);
for (let fileType of this.fileTypes) for (let fileType of this.fileTypes)
{ {
if (fileType.fileExtension === extension ) if (fileType.fileExtension === extension )
@@ -203,7 +258,7 @@ export class PiPedalFileProperty {
} }
label: string = ""; label: string = "";
fileTypes: PiPedalFileType[] = []; fileTypes: UiFileType[] = [];
patchProperty: string = ""; patchProperty: string = "";
directory: string = ""; directory: string = "";
index: number = -1; index: number = -1;
@@ -226,7 +281,7 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
this.port_groups = PortGroup.deserialize_array(input.port_groups); this.port_groups = PortGroup.deserialize_array(input.port_groups);
if (input.fileProperties) if (input.fileProperties)
{ {
this.fileProperties = PiPedalFileProperty.deserialize_array(input.fileProperties) this.fileProperties = UiFileProperty.deserialize_array(input.fileProperties)
} else { } else {
this.fileProperties = []; this.fileProperties = [];
} }
@@ -251,7 +306,7 @@ export class Lv2Plugin implements Deserializable<Lv2Plugin> {
comment: string = ""; comment: string = "";
ports: Port[] = Port.EmptyPorts; ports: Port[] = Port.EmptyPorts;
port_groups: PortGroup[] = []; port_groups: PortGroup[] = [];
fileProperties: PiPedalFileProperty[] = []; fileProperties: UiFileProperty[] = [];
uiPortNotifications: UiPropertyNotification[] = []; uiPortNotifications: UiPropertyNotification[] = [];
} }
@@ -508,7 +563,7 @@ export class UiControl implements Deserializable<UiControl> {
} }
formatDisplayValue(value: number): string { formatDisplayValue(value: number): string {
if (this.integer_property || this.enumeration_property) { if (this.integer_property) {
value = Math.round(value); value = Math.round(value);
} }
@@ -614,7 +669,7 @@ export class UiPlugin implements Deserializable<UiPlugin> {
this.port_groups = PortGroup.deserialize_array(input.port_groups); this.port_groups = PortGroup.deserialize_array(input.port_groups);
if (input.fileProperties) if (input.fileProperties)
{ {
this.fileProperties = PiPedalFileProperty.deserialize_array(input.fileProperties) this.fileProperties = UiFileProperty.deserialize_array(input.fileProperties)
} else { } else {
this.fileProperties = []; this.fileProperties = [];
} }
@@ -682,7 +737,7 @@ export class UiPlugin implements Deserializable<UiPlugin> {
description: string = ""; description: string = "";
controls: UiControl[] = []; controls: UiControl[] = [];
port_groups: PortGroup[] = []; port_groups: PortGroup[] = [];
fileProperties: PiPedalFileProperty[] = []; fileProperties: UiFileProperty[] = [];
is_vst3 : boolean = false; is_vst3 : boolean = false;
} }
+2
View File
@@ -67,6 +67,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
this.controlValues = ControlValue.deserializeArray(input.controlValues); this.controlValues = ControlValue.deserializeArray(input.controlValues);
this.vstState = input.vstState ?? ""; this.vstState = input.vstState ?? "";
this.stateUpdateCount = input.stateUpdateCount;
this.lv2State = input.lv2State; this.lv2State = input.lv2State;
return this; return this;
} }
@@ -195,6 +196,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
controlValues: ControlValue[] = ControlValue.EmptyArray; controlValues: ControlValue[] = ControlValue.EmptyArray;
midiBindings: MidiBinding[] = []; midiBindings: MidiBinding[] = [];
vstState: string = ""; vstState: string = "";
stateUpdateCount: number = 0;
lv2State: [boolean,any] = [false,{}] lv2State: [boolean,any] = [false,{}]
}; };
+11 -3
View File
@@ -17,7 +17,7 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // 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. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { UiPlugin, UiControl, PluginType, PiPedalFileProperty } from './Lv2Plugin'; import { UiPlugin, UiControl, PluginType, UiFileProperty } from './Lv2Plugin';
import { PiPedalArgumentError, PiPedalStateError } from './PiPedalError'; import { PiPedalArgumentError, PiPedalStateError } from './PiPedalError';
@@ -588,6 +588,10 @@ export class PiPedalModel //implements PiPedalModel
} else if (message === "onSystemMidiBindingsChanged") { } else if (message === "onSystemMidiBindingsChanged") {
let bindings = MidiBinding.deserialize_array(body); let bindings = MidiBinding.deserialize_array(body);
this.systemMidiBindings.set(bindings); this.systemMidiBindings.set(bindings);
} else if (message === "onErrorMessage")
{
this.showAlert(body as string);
} else { } else {
throw new PiPedalStateError("Unrecognized message received from server: " + message); throw new PiPedalStateError("Unrecognized message received from server: " + message);
} }
@@ -1054,6 +1058,8 @@ export class PiPedalModel //implements PiPedalModel
handleOnLoadPluginPreset(instanceId: number, controlValues: ControlValue[]) { handleOnLoadPluginPreset(instanceId: number, controlValues: ControlValue[]) {
// note that plugins with state are dealt with server-side.
// if we made it here, we can just load the controls.
let pedalboard = this.pedalboard.get(); let pedalboard = this.pedalboard.get();
if (pedalboard === undefined) throw new PiPedalStateError("Pedalboard not ready."); if (pedalboard === undefined) throw new PiPedalStateError("Pedalboard not ready.");
let newPedalboard = pedalboard.clone(); let newPedalboard = pedalboard.clone();
@@ -1342,13 +1348,15 @@ export class PiPedalModel //implements PiPedalModel
while (true) { while (true) {
let v = it.next(); let v = it.next();
if (v.done) break; if (v.done) break;
let item = v.value; let item = v.value;
if (item.instanceId === itemId) { if (item.instanceId === itemId) {
item.deserialize(new PedalboardItem()); // skeezy way to re-initialize.
item.instanceId = ++newPedalboard.nextInstanceId; item.instanceId = ++newPedalboard.nextInstanceId;
item.uri = selectedUri; item.uri = selectedUri;
item.pluginName = plugin.name; item.pluginName = plugin.name;
item.controlValues = this.getDefaultValues(item.uri); item.controlValues = this.getDefaultValues(item.uri);
item.isEnabled = true; item.isEnabled = true;
// lv2State: not valid. vstState : not valid.
this.pedalboard.set(newPedalboard); this.pedalboard.set(newPedalboard);
this.updateServerPedalboard() this.updateServerPedalboard()
return item.instanceId; return item.instanceId;
@@ -1590,7 +1598,7 @@ export class PiPedalModel //implements PiPedalModel
}); });
} }
requestFileList(piPedalFileProperty: PiPedalFileProperty): Promise<string[]> { requestFileList(piPedalFileProperty: UiFileProperty): Promise<string[]> {
return nullCast(this.webSocket) return nullCast(this.webSocket)
.request<string[]>('requestFileList', piPedalFileProperty); .request<string[]>('requestFileList', piPedalFileProperty);
} }
+5 -5
View File
@@ -23,7 +23,7 @@ import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles'; import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { UiPlugin, UiControl, PiPedalFileProperty, ScalePoint } from './Lv2Plugin'; import { UiPlugin, UiControl, UiFileProperty, ScalePoint } from './Lv2Plugin';
import { import {
Pedalboard, PedalboardItem, ControlValue Pedalboard, PedalboardItem, ControlValue
} from './Pedalboard'; } from './Pedalboard';
@@ -239,7 +239,7 @@ type PluginControlViewState = {
imeCaption: string; imeCaption: string;
imeInitialHeight: number; imeInitialHeight: number;
showFileDialog: boolean, showFileDialog: boolean,
dialogFileProperty: PiPedalFileProperty, dialogFileProperty: UiFileProperty,
dialogFileValue: string dialogFileValue: string
}; };
@@ -260,7 +260,7 @@ const PluginControlView =
imeCaption: "", imeCaption: "",
imeInitialHeight: 0, imeInitialHeight: 0,
showFileDialog: false, showFileDialog: false,
dialogFileProperty: new PiPedalFileProperty(), dialogFileProperty: new UiFileProperty(),
dialogFileValue: "" dialogFileValue: ""
} }
@@ -323,10 +323,10 @@ const PluginControlView =
}); });
} }
makeFilePropertyUI(fileProperty: PiPedalFileProperty): ReactNode { makeFilePropertyUI(fileProperty: UiFileProperty): ReactNode {
return (( return ((
<FilePropertyControl instanceId={this.props.instanceId} <FilePropertyControl pedalboardItem={this.props.item}
fileProperty={fileProperty} fileProperty={fileProperty}
onFileClick={(fileProperty, selectedFile) => { onFileClick={(fileProperty, selectedFile) => {
this.setState({ showFileDialog: true, dialogFileProperty: fileProperty, dialogFileValue: selectedFile }); this.setState({ showFileDialog: true, dialogFileProperty: fileProperty, dialogFileValue: selectedFile });
+1 -1
View File
@@ -259,7 +259,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })(
<img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" /> <img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" />
</div> </div>
<div className={classes.itemLabel}> <div className={classes.itemLabel}>
<Typography> noWrap <Typography noWrap>
{presetEntry.label} {presetEntry.label}
</Typography> </Typography>
</div> </div>
+1 -6
View File
@@ -80,13 +80,10 @@ export const SelectHoverBackground =
} }
handleMouseOver(e: SyntheticEvent): void { handleMouseOver(e: SyntheticEvent): void {
console.log("onMouseOver")
if (this.props.showHover ?? true) { if (this.props.showHover ?? true) {
if (this.hoverElementRef.current) if (this.hoverElementRef.current)
{ {
this.hoverElementRef.current.style.display = "block"; this.hoverElementRef.current.style.display = "block";
} else {
console.log("No hoverElementRef")
} }
} }
@@ -96,9 +93,7 @@ export const SelectHoverBackground =
if (this.hoverElementRef.current) if (this.hoverElementRef.current)
{ {
this.hoverElementRef.current.style.display = "none"; this.hoverElementRef.current.style.display = "none";
} else { }
console.log("No hoverElementRef")
}
} }
} }
+20 -17
View File
@@ -27,7 +27,7 @@ import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent'; import DialogContent from '@mui/material/DialogContent';
import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import { PiPedalFileProperty } from './Lv2Plugin'; import { UiFileProperty,UiFileType } from './Lv2Plugin';
import SvgIcon from '@mui/material/SvgIcon'; import SvgIcon from '@mui/material/SvgIcon';
import ErrorIcon from '@mui/icons-material/Error'; import ErrorIcon from '@mui/icons-material/Error';
import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import ArrowBackIcon from '@mui/icons-material/ArrowBack';
@@ -45,7 +45,7 @@ export interface UploadFileDialogProps {
onClose: () => void, onClose: () => void,
onUploaded: (fileName: string) => void, onUploaded: (fileName: string) => void,
uploadPage: string, uploadPage: string,
fileProperty: PiPedalFileProperty fileProperty: UiFileProperty
}; };
@@ -204,6 +204,10 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
this.updateUploadDisplayList(); this.updateUploadDisplayList();
try { try {
upload.abortController = new AbortController(); upload.abortController = new AbortController();
if (!this.wantsFile(this.uploadList[i].file))
{
throw new Error("Invalid file type.");
}
let filename = await this.model.uploadFile(this.props.uploadPage, this.uploadList[i].file, "application/octet-stream", upload.abortController); let filename = await this.model.uploadFile(this.props.uploadPage, this.uploadList[i].file, "application/octet-stream", upload.abortController);
this.props.onUploaded(filename); this.props.onUploaded(filename);
upload.status = FileUploadStatus.Uploaded; upload.status = FileUploadStatus.Uploaded;
@@ -262,7 +266,12 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
e.currentTarget.style.background = "#D8D8D8"; e.currentTarget.style.background = "#D8D8D8";
} }
handleButtonSelect(e: React.ChangeEvent<HTMLInputElement>) { private static IsAndroid() : boolean
{
return /Android/i.test(navigator.userAgent);
}
handleButtonSelect(e: any) {
if (e.currentTarget.files) { if (e.currentTarget.files) {
this.uploadFiles(e.currentTarget.files); this.uploadFiles(e.currentTarget.files);
} }
@@ -290,20 +299,13 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
} }
} }
makeBrowserAcceptList() { makeBrowserAcceptList() {
let fileTypes = this.props.fileProperty.fileTypes; let result = UiFileType.MergeMimeTypes(this.props.fileProperty.fileTypes);
let result = "";
for (let i = 0; i < fileTypes.length; ++i) {
if (result.length !== 0) {
result += ',';
}
result += fileTypes[i].fileExtension;
}
return result; return result;
} }
render() { render() {
let isAndroid = UploadFileDialog.IsAndroid();
return ( return (
<DialogEx tag="UploadFileDialog" open={this.props.open} fullWidth onClose={() => this.handleClose()} <DialogEx tag="UploadFileDialog" open={this.props.open} fullWidth onClose={() => this.handleClose()}
fullScreen={this.state.fullScreen} fullScreen={this.state.fullScreen}
@@ -321,7 +323,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
<DialogContent style={{ paddingBottom: 0 }}> <DialogContent style={{ paddingBottom: 0 }}>
<div style={{ <div style={{
width: "100%", height: 140, marginBottom: 0, width: "100%", height: 140, marginBottom: 0,
border: "2px dashed #CCC", border: (isAndroid? "2px solid #CCC" :"2px dashed #CCC"),
borderRadius: "10px", borderRadius: "10px",
fontFamily: "Roboto", fontFamily: "Roboto",
padding: 0 padding: 0
@@ -334,7 +336,8 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
}} }}
> >
{!this.hasFileList() && ( {!this.hasFileList() && (
<Typography noWrap color="textSecondary" align="center" display="block" variant="caption" style={{ width: "100%", marginTop: 20, verticalAlign: "middle" }} >Drop files here</Typography> <Typography noWrap color="textSecondary" align="center" display="block" variant="caption" style={{ width: "100%", marginTop: 20, verticalAlign: "middle" }} >
{ isAndroid? "Select files": "Drop files here" }</Typography>
)} )}
{this.hasFileList() && ( {this.hasFileList() && (
<div style={{ width: "100%", height: "100%", overflow: "auto" }}> <div style={{ width: "100%", height: "100%", overflow: "auto" }}>
@@ -381,15 +384,15 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
<DialogActions > <DialogActions >
<Button <Button
component="label" color="primary" style={{ marginLeft: 16, width: 120, flex: "0 0 auto" }} component="label" color="primary" style={{ whiteSpace: "nowrap", textOverflow: "ellipsis", marginLeft: 16, width: 120, flex: "0 0 auto" }}
> >
Select Files Select&nbsp;Files
<input <input
type="file" type="file"
hidden hidden
accept={this.makeBrowserAcceptList()} accept={this.makeBrowserAcceptList()}
multiple multiple
onChange={(e) => this.handleButtonSelect(e)} onInput={(e) => this.handleButtonSelect(e)}
/> />
</Button> </Button>
<div style={{ flex: "1 1 20px" }} /> <div style={{ flex: "1 1 20px" }} />
-81
View File
@@ -1,81 +0,0 @@
src/SearchControl.tsx
src/SplitControlView.tsx
src/WifiConfigSettings.tsx
src/FullScreenIME.tsx
src/JackHostStatus.tsx
src/SearchFilter.tsx
src/MainPage.tsx
src/PiPedalModel.tsx
src/PluginPresetSelector.tsx
src/Pedal.tsx
src/ToobMLView.tsx
src/SettingsDialog.tsx
src/PiPedalSocket.tsx
src/ToobFrequencyResponseView.tsx
src/ControlViewFactory.tsx
src/Utility.tsx
src/ToobToneStackView.tsx
src/SelectHoverBackground.tsx
src/MidiBindingsDialog.tsx
src/TemporaryDrawer.tsx
src/GxTunerView.tsx
src/ToobInputStageView.tsx
src/DraggableGrid.tsx
src/JackStatusView.tsx
src/PluginControl.tsx
src/XxxSnippet.tsx
src/PluginPreset.tsx
src/Jack.tsx
src/AlsaDeviceInfo.tsx
src/MidiBinding.tsx
src/PiPedalError.tsx
src/IControlViewFactory.tsx
src/Lv2Plugin.tsx
src/Pedalboard.tsx
src/PedalboardView.tsx
src/PresetDialog.tsx
src/AppThemed.tsx
src/ZoomedDial.tsx
src/RenameDialog.tsx
src/SplitUiControls.tsx
src/GovernorSettings.tsx
src/AboutDialog.tsx
src/ToobSpectrumResponseView.tsx
src/PluginControlView.tsx
src/NoChangePassword.tsx
src/ToobSpectrumAnalyzerView.tsx
src/MidiBindingView.tsx
src/GxTunerControl.tsx
src/Banks.tsx
src/PluginPresetsDialog.tsx
src/BankDialog.tsx
src/UploadPresetDialog.tsx
src/ToobPowerStage2View.tsx
src/index.tsx
src/Units.tsx
src/VuMeter.tsx
src/App.test.tsx
src/DialogEx.tsx
src/StringBuilder.tsx
src/SelectChannelsDialog.tsx
src/Draggable.tsx
src/ZoomedUiControl.tsx
src/Rect.tsx
src/PluginClass.tsx
src/PluginIcon.tsx
src/App.tsx
src/ResizeResponsiveComponent.tsx
src/SvgPathBuilder.tsx
src/NumericInput.tsx
src/JackServerSettings.tsx
src/ListSelectDialog.tsx
src/JackServerSettingsDialog.tsx
src/ObservableProperty.tsx
src/SelectMidiChannelsDialog.tsx
src/WifiChannel.tsx
src/LoadPluginDialog.tsx
src/WifiConfigDialog.tsx
src/PluginInfoDialog.tsx
src/ToobWaveShapeView.tsx
src/ToobCabSimView.tsx
src/PresetSelector.tsx
Executable
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/bash
# Set presets and plugin presets to default.
rm -rf /var/pipedal/plugin_presets
rm -rf /var/pipedal/presets
mkdir /var/pipedal/plugin_presets
mkdir /var/pipedal/presets
cp -r default_presets/plugin_presets /var/pipedal/plugin_presets/
cp -r default_presets/presets /var/pipedal/presets/
+19 -1
View File
@@ -349,7 +349,6 @@ private:
audioDriver->Close(); audioDriver->Close();
StopReaderThread(); StopReaderThread();
pHost->GetHostWorkerThread()->Close();
// release any pdealboards owned by the process thread. // release any pdealboards owned by the process thread.
@@ -1164,6 +1163,21 @@ public:
RealtimeNextMidiProgramRequest request; RealtimeNextMidiProgramRequest request;
hostReader.read(&request); hostReader.read(&request);
pNotifyCallbacks->OnNotifyNextMidiProgram(request); pNotifyCallbacks->OnNotifyNextMidiProgram(request);
} else if (command == RingBufferCommand::Lv2ErrorMessage)
{
size_t size;
int64_t instanceId;
hostReader.read(&instanceId);
hostReader.read(&size);
if (this->atomBuffer.size() < size+1)
{
this->atomBuffer.resize(size+1);
}
hostReader.read(size, &(atomBuffer[0]));
char *p = (char*)&(atomBuffer[0]);
p[size] = 0;
std::string message(p);
pNotifyCallbacks->OnNotifyLv2RealtimeError(instanceId,message);
} }
else else
{ {
@@ -1243,6 +1257,10 @@ public:
this->inputRingBuffer.reset(); this->inputRingBuffer.reset();
this->outputRingBuffer.reset(); this->outputRingBuffer.reset();
this->hostReader.Reset();
this->hostWriter.Reset();
this->realtimeReader.Reset();
this->realtimeWriter.Reset();
this->channelSelection = channelSelection; this->channelSelection = channelSelection;
+2
View File
@@ -154,6 +154,7 @@ public:
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest&midiProgramRequest) = 0; virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest&midiProgramRequest) = 0;
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest&request) = 0; virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest&request) = 0;
virtual void OnNotifyLv2RealtimeError(int64_t instanceId,const std::string &error) = 0;
}; };
@@ -195,6 +196,7 @@ public:
virtual void SetListenForAtomOutput(bool listen) = 0; virtual void SetListenForAtomOutput(bool listen) = 0;
virtual void UpdatePluginStates(Pedalboard& pedalboard) = 0; virtual void UpdatePluginStates(Pedalboard& pedalboard) = 0;
virtual void UpdatePluginState(PedalboardItem& pedalboardItem) = 0;
virtual void Open(const JackServerSettings&jackServerSettings,const JackChannelSelection & channelSelection) = 0; virtual void Open(const JackServerSettings&jackServerSettings,const JackChannelSelection & channelSelection) = 0;
+4
View File
@@ -141,6 +141,8 @@ else()
endif() endif()
set (PIPEDAL_SOURCES set (PIPEDAL_SOURCES
MimeTypes.cpp MimeTypes.hpp
inverting_mutex.hpp
DbDezipper.hpp DbDezipper.cpp DbDezipper.hpp DbDezipper.cpp
WebServerLog.hpp WebServerLog.hpp
@@ -277,6 +279,8 @@ target_link_libraries(pipedald PRIVATE
################################# #################################
add_executable(pipedaltest testMain.cpp add_executable(pipedaltest testMain.cpp
InvertingMutexTest.cpp
jsonTest.cpp jsonTest.cpp
json_variant.cpp json_variant.cpp
json_variant.hpp json_variant.hpp
+3
View File
@@ -59,5 +59,8 @@ namespace pipedal {
virtual bool IsVst3() const = 0; virtual bool IsVst3() const = 0;
virtual bool GetLv2State(Lv2PluginState*state) = 0; virtual bool GetLv2State(Lv2PluginState*state) = 0;
virtual bool HasErrorMessage() const = 0;
virtual const char*TakeErrorMessage() = 0;
}; };
} //namespace } //namespace
+1
View File
@@ -49,5 +49,6 @@ namespace pipedal {
virtual std::shared_ptr<HostWorkerThread> GetHostWorkerThread() = 0; virtual std::shared_ptr<HostWorkerThread> GetHostWorkerThread() = 0;
virtual IEffect *CreateEffect(PedalboardItem &pedalboard) = 0; virtual IEffect *CreateEffect(PedalboardItem &pedalboard) = 0;
}; };
} }
+71
View File
@@ -0,0 +1,71 @@
// Copyright (c) 2022 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.
#include "pch.h"
#include "catch.hpp"
#include <sstream>
#include <cstdint>
#include <string>
#include "json.hpp"
#include "json_variant.hpp"
#include <concepts>
#include <type_traits>
#include "inverting_mutex.hpp"
#include <iostream>
#include <thread>
#include <functional>
#include "util.hpp"
using namespace pipedal;
using namespace std;
using namespace std::chrono;
TEST_CASE("inverting_mutext test", "[inverting_mutex_test]")
{
inverting_mutex mutex;
{
std::thread thread(
[&mutex]() mutable
{
nice(5);
{
std::lock_guard<inverting_mutex> lock(mutex);
SetThreadName("imTest");
cout << "Thread holds lock" << endl;
std::this_thread::sleep_for(3s);
std::this_thread::sleep_for(1s);
cout << "Thread releases lock" << endl;
}
});
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<inverting_mutex> lock(mutex); // cause the thread to avoid priority-inversion.
cout << "Main resumed." << endl;
}
{
std::lock_guard<inverting_mutex> lock(mutex);
}
thread.join();
}
}
+33 -22
View File
@@ -50,29 +50,38 @@ int LogFeature::vprintf(LV2_URID type,const char*fmt, va_list va)
{ {
std::lock_guard<std::mutex> guard(logMutex); std::lock_guard<std::mutex> guard(logMutex);
const char* prefix = ""; int result = 0;
char buffer[1024]; if (this->logMessageListener)
int result = vsnprintf(buffer, sizeof(buffer), fmt, va); {
const char* prefix = "";
char buffer[1024];
strcpy(buffer,messagePrefix.c_str());
char *p = buffer+messagePrefix.length();
if (type == uris.ridError)
{ result = vsnprintf(p, sizeof(buffer)-messagePrefix.length(), fmt, va);
Lv2Log::error(buffer); buffer[sizeof(buffer)-1] = '\0';
if (type == uris.ridError)
{
logMessageListener->OnLogError(buffer);
}
else if (type == uris.ridWarning)
{
logMessageListener->OnLogWarning(buffer);
}
else if (type == uris.ridNote)
{
logMessageListener->OnLogInfo(buffer);
}
else if (type == uris.ridTrace)
{
logMessageListener->OnLogDebug(buffer);
}
else {
logMessageListener->OnLogInfo(buffer);
}
} }
else if (type == uris.ridWarning)
{
Lv2Log::warning(buffer);
}
else if (type == uris.ridNote)
{
Lv2Log::info(buffer);
}
else if (type == uris.ridTrace)
{
Lv2Log::debug(buffer);
}
else {
Lv2Log::info(buffer);
}
return result; return result;
} }
@@ -85,9 +94,11 @@ LogFeature::LogFeature()
log.printf = printfFn; log.printf = printfFn;
log.vprintf = vprintfFn; log.vprintf = vprintfFn;
} }
void LogFeature::Prepare(MapFeature*map) void LogFeature::Prepare(MapFeature*map, const std::string &messagePrefix, LogMessageListener*listener)
{ {
uris.Map(map); uris.Map(map);
this->messagePrefix = messagePrefix;
this->logMessageListener = listener;
} }
+13 -2
View File
@@ -35,8 +35,17 @@
namespace pipedal { namespace pipedal {
class LogFeature { class LogFeature {
public:
class LogMessageListener {
public:
virtual void OnLogError(const char*message) = 0;
virtual void OnLogWarning(const char*message) = 0;
virtual void OnLogInfo(const char*message) = 0;
virtual void OnLogDebug(const char*message) = 0;
};
private: private:
LogMessageListener *logMessageListener = nullptr;
std::string messagePrefix;
LV2_URID nextAtom = 0; LV2_URID nextAtom = 0;
LV2_Feature feature; LV2_Feature feature;
LV2_Log_Log log; LV2_Log_Log log;
@@ -59,7 +68,8 @@ namespace pipedal {
public: public:
LogFeature(); LogFeature();
void Prepare(MapFeature* map); void Prepare(MapFeature* map, const std::string &messagePrefix, LogMessageListener*listener);
void LogError(const char*fmt,...); void LogError(const char*fmt,...);
void LogWarning(const char*fmt,...); void LogWarning(const char*fmt,...);
@@ -84,5 +94,6 @@ namespace pipedal {
int vprintf(LV2_URID type, const char* fmt, va_list va); int vprintf(LV2_URID type, const char* fmt, va_list va);
}; };
} }
+28 -1
View File
@@ -54,6 +54,7 @@ Lv2Effect::Lv2Effect(
{ {
auto pWorld = pHost_->getWorld(); auto pWorld = pHost_->getWorld();
logFeature.Prepare(&(pHost_->GetMapFeature()),info_->name() + ": ",this);
this->bypassStartingSamples = (uint32_t)(pHost->GetSampleRate() * BYPASS_TIME_S); this->bypassStartingSamples = (uint32_t)(pHost->GetSampleRate() * BYPASS_TIME_S);
this->bypass = pedalboardItem.isEnabled(); this->bypass = pedalboardItem.isEnabled();
@@ -71,6 +72,8 @@ Lv2Effect::Lv2Effect(
LV2_Feature *const *features = pHost_->GetLv2Features(); LV2_Feature *const *features = pHost_->GetLv2Features();
this->features.push_back(logFeature.GetFeature());
for (auto p = features; *p != nullptr; ++p) for (auto p = features; *p != nullptr; ++p)
{ {
this->features.push_back(*p); this->features.push_back(*p);
@@ -92,7 +95,7 @@ Lv2Effect::Lv2Effect(
} }
this->features.push_back(nullptr); this->features.push_back(nullptr);
LV2_Feature **myFeatures = &this->features[0]; const LV2_Feature **myFeatures = &this->features[0];
LilvInstance *pInstance = nullptr; LilvInstance *pInstance = nullptr;
try { try {
@@ -676,4 +679,28 @@ bool Lv2Effect::GetLv2State(Lv2PluginState*state)
} }
void Lv2Effect::OnLogError(const char*message)
{
// only errors get transmitted to the client.
strncpy(this->errorMessage,message,sizeof(errorMessage));
errorMessage[sizeof(errorMessage)-1] = '\0';
this->hasErrorMessage = true;
}
void Lv2Effect::OnLogWarning(const char*message)
{
Lv2Log::warning(message);
}
void Lv2Effect::OnLogInfo(const char*message)
{
Lv2Log::info(message);
}
void Lv2Effect::OnLogDebug(const char*message)
{
Lv2Log::debug(message);
}
+16 -5
View File
@@ -34,6 +34,7 @@
#include "lv2/atom.lv2/forge.h" #include "lv2/atom.lv2/forge.h"
#include "AtomBuffer.hpp" #include "AtomBuffer.hpp"
#include "StateInterface.hpp" #include "StateInterface.hpp"
#include "LogFeature.hpp"
namespace pipedal namespace pipedal
@@ -41,12 +42,19 @@ namespace pipedal
class RealtimeRingBufferWriter; class RealtimeRingBufferWriter;
class Lv2Effect : public IEffect class Lv2Effect : public IEffect, private LogFeature::LogMessageListener
{ {
private: private:
virtual void OnLogError(const char*message);
virtual void OnLogWarning(const char*message);
virtual void OnLogInfo(const char*message);
virtual void OnLogDebug(const char*message);
private:
std::unique_ptr<StateInterface> stateInterface; std::unique_ptr<StateInterface> stateInterface;
void RestoreState(const PedalboardItem&pedalboardItem); void RestoreState(const PedalboardItem&pedalboardItem);
LogFeature logFeature;
std::map<std::string,AtomBuffer> patchPropertyPrototypes; std::map<std::string,AtomBuffer> patchPropertyPrototypes;
IHost *pHost = nullptr; IHost *pHost = nullptr;
@@ -74,7 +82,7 @@ namespace pipedal
std::vector<char *> inputAtomBuffers; std::vector<char *> inputAtomBuffers;
std::vector<char *> outputAtomBuffers; std::vector<char *> outputAtomBuffers;
std::vector<LV2_Feature *> features; std::vector<const LV2_Feature *> features;
LV2_Feature *work_schedule_feature = nullptr; LV2_Feature *work_schedule_feature = nullptr;
virtual std::string GetUri() const { return info->uri(); } virtual std::string GetUri() const { return info->uri(); }
@@ -169,6 +177,7 @@ namespace pipedal
void BypassTo(float value); void BypassTo(float value);
public: public:
virtual bool GetLv2State(Lv2PluginState*state); virtual bool GetLv2State(Lv2PluginState*state);
virtual void RequestPatchProperty(LV2_URID uridUri); virtual void RequestPatchProperty(LV2_URID uridUri);
virtual void SetPatchProperty(LV2_URID uridUri,size_t size, LV2_Atom*value); virtual void SetPatchProperty(LV2_URID uridUri,size_t size, LV2_Atom*value);
@@ -187,7 +196,8 @@ namespace pipedal
} }
bool hasErrorMessage = false;
char errorMessage[1024];
public: public:
Lv2Effect( Lv2Effect(
IHost *pHost, IHost *pHost,
@@ -195,7 +205,8 @@ namespace pipedal
const PedalboardItem &pedalboardItem); const PedalboardItem &pedalboardItem);
~Lv2Effect(); ~Lv2Effect();
bool HasErrorMessage() const { return this->hasErrorMessage; }
const char*TakeErrorMessage() { this->hasErrorMessage = false; return this->errorMessage; }
virtual void ResetAtomBuffers(); virtual void ResetAtomBuffers();
virtual uint64_t GetInstanceId() const { return instanceId; } virtual uint64_t GetInstanceId() const { return instanceId; }
+23 -5
View File
@@ -46,6 +46,8 @@ std::vector<float *> Lv2Pedalboard::AllocateAudioBuffers(int nChannels)
return result; return result;
} }
int Lv2Pedalboard::GetControlIndex(uint64_t instanceId, const std::string &symbol) int Lv2Pedalboard::GetControlIndex(uint64_t instanceId, const std::string &symbol)
{ {
for (int i = 0; i < realtimeEffects.size(); ++i) for (int i = 0; i < realtimeEffects.size(); ++i)
@@ -60,7 +62,9 @@ int Lv2Pedalboard::GetControlIndex(uint64_t instanceId, const std::string &symbo
} }
std::vector<float *> Lv2Pedalboard::PrepareItems( std::vector<float *> Lv2Pedalboard::PrepareItems(
std::vector<PedalboardItem> &items, std::vector<PedalboardItem> &items,
std::vector<float *> inputBuffers) std::vector<float *> inputBuffers,
Lv2PedalboardErrorList&errorList
)
{ {
for (int i = 0; i < items.size(); ++i) for (int i = 0; i < items.size(); ++i)
{ {
@@ -84,8 +88,8 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
this->processActions.push_back(preMixAction); this->processActions.push_back(preMixAction);
std::vector<float *> topResult = PrepareItems(item.topChain(), topInputs); std::vector<float *> topResult = PrepareItems(item.topChain(), topInputs,errorList);
std::vector<float *> bottomResult = PrepareItems(item.bottomChain(), bottomInputs); std::vector<float *> bottomResult = PrepareItems(item.bottomChain(), bottomInputs,errorList);
this->processActions.push_back( this->processActions.push_back(
[pSplit](uint32_t frames) [pSplit](uint32_t frames)
@@ -113,6 +117,12 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
{ {
Lv2Log::warning(SS(e.what())); Lv2Log::warning(SS(e.what()));
} }
if (pLv2Effect->HasErrorMessage())
{
std::string error = pLv2Effect->TakeErrorMessage();
Lv2Log::error(error);
errorList.push_back({item.instanceId(), error});
}
if (pLv2Effect) if (pLv2Effect)
{ {
@@ -206,7 +216,7 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
return inputBuffers; return inputBuffers;
} }
void Lv2Pedalboard::Prepare(IHost *pHost, Pedalboard &pedalboard) void Lv2Pedalboard::Prepare(IHost *pHost, Pedalboard &pedalboard, Lv2PedalboardErrorList &errorList)
{ {
this->pHost = pHost; this->pHost = pHost;
@@ -224,7 +234,7 @@ void Lv2Pedalboard::Prepare(IHost *pHost, Pedalboard &pedalboard)
this->pedalboardInputBuffers.push_back(bufferPool.AllocateBuffer<float>(pHost->GetMaxAudioBufferSize())); this->pedalboardInputBuffers.push_back(bufferPool.AllocateBuffer<float>(pHost->GetMaxAudioBufferSize()));
} }
auto outputs = PrepareItems(pedalboard.items(), this->pedalboardInputBuffers); auto outputs = PrepareItems(pedalboard.items(), this->pedalboardInputBuffers,errorList);
int nOutputs = pHost->GetNumberOfOutputAudioChannels(); int nOutputs = pHost->GetNumberOfOutputAudioChannels();
if (nOutputs == 1) if (nOutputs == 1)
{ {
@@ -396,6 +406,14 @@ bool Lv2Pedalboard::Run(float **inputBuffers, float **outputBuffers, uint32_t sa
{ {
processActions[i](samples); processActions[i](samples);
} }
for (size_t i = 0; i < this->effects.size(); ++i)
{
IEffect* effect = effects[i].get();
if (effect->HasErrorMessage())
{
ringBufferWriter->WriteLv2ErrorMessage(effect->GetInstanceId(),effect->TakeErrorMessage());
}
}
for (size_t i = 0; i < samples; ++i) for (size_t i = 0; i < samples; ++i)
{ {
float volume = outputVolume.Tick(); float volume = outputVolume.Tick();
+13 -2
View File
@@ -35,6 +35,16 @@ class RealtimeVuBuffers;
class RealtimePatchPropertyRequest; class RealtimePatchPropertyRequest;
class RealtimeRingBufferWriter; class RealtimeRingBufferWriter;
struct Lv2PedalboardError {
int64_t intanceId;
std::string message;
};
class Lv2PedalboardErrorList: public std::vector<Lv2PedalboardError> // (forward declaration issues with a using statement)
{
};
class Lv2Pedalboard { class Lv2Pedalboard {
IHost *pHost = nullptr; IHost *pHost = nullptr;
@@ -86,7 +96,8 @@ class Lv2Pedalboard {
std::vector<float*> PrepareItems( std::vector<float*> PrepareItems(
std::vector<PedalboardItem> & items, std::vector<PedalboardItem> & items,
std::vector<float*> inputBuffers std::vector<float*> inputBuffers,
Lv2PedalboardErrorList &errorList
); );
void PrepareMidiMap(const Pedalboard&pedalboard); void PrepareMidiMap(const Pedalboard&pedalboard);
@@ -99,7 +110,7 @@ public:
Lv2Pedalboard() { } Lv2Pedalboard() { }
~Lv2Pedalboard() { } ~Lv2Pedalboard() { }
void Prepare(IHost *pHost,Pedalboard&pedalboard); void Prepare(IHost *pHost,Pedalboard&pedalboard, Lv2PedalboardErrorList &errorList);
std::vector<IEffect* > GetEffects() { return realtimeEffects; } std::vector<IEffect* > GetEffects() { return realtimeEffects; }
+23
View File
@@ -36,10 +36,15 @@ MapPathFeature::MapPathFeature(const std::filesystem::path &storagePath)
lv2_state_make_path.handle = (LV2_State_Make_Path_Handle*)this; lv2_state_make_path.handle = (LV2_State_Make_Path_Handle*)this;
lv2_state_make_path.path = FnAbsolutePath; lv2_state_make_path.path = FnAbsolutePath;
lv2_state_free_path.handle = (LV2_State_Free_Path_Handle*)this;
lv2_state_free_path.free_path = FnFreePath;
mapPathFeature.URI = LV2_STATE__mapPath; mapPathFeature.URI = LV2_STATE__mapPath;
mapPathFeature.data = (void*)&lv2_state_map_path; mapPathFeature.data = (void*)&lv2_state_map_path;
makePathFeature.URI = LV2_STATE__makePath; makePathFeature.URI = LV2_STATE__makePath;
makePathFeature.data = (void*)&lv2_state_make_path; makePathFeature.data = (void*)&lv2_state_make_path;
freePathFeature.URI = LV2_STATE__freePath;
freePathFeature.data = (void*)&lv2_state_free_path;
} }
void MapPathFeature::Prepare(MapFeature* map) void MapPathFeature::Prepare(MapFeature* map)
@@ -47,6 +52,16 @@ void MapPathFeature::Prepare(MapFeature* map)
} }
void MapPathFeature::FreePath(char *path)
{
free(path);
}
void MapPathFeature::FnFreePath(LV2_State_Free_Path_Handle handle, char* path)
{
((MapPathFeature*)handle)->FreePath(path);
}
/*static*/ char *MapPathFeature::FnAbsolutePath( /*static*/ char *MapPathFeature::FnAbsolutePath(
LV2_State_Map_Path_Handle handle, LV2_State_Map_Path_Handle handle,
@@ -57,6 +72,10 @@ void MapPathFeature::Prepare(MapFeature* map)
char *MapPathFeature::AbsolutePath(const char *abstract_path) char *MapPathFeature::AbsolutePath(const char *abstract_path)
{ {
if (strlen(abstract_path) == 0)
{
return strdup("");
}
std::filesystem::path t (abstract_path); std::filesystem::path t (abstract_path);
if (t.is_absolute()) { if (t.is_absolute()) {
return strdup(abstract_path); return strdup(abstract_path);
@@ -75,6 +94,10 @@ char *MapPathFeature::FnAbstractPath(
char *MapPathFeature::AbstractPath(const char *absolute_path) char *MapPathFeature::AbstractPath(const char *absolute_path)
{ {
if (strlen(absolute_path) == 0)
{
return strdup("");
}
if (strncmp(storagePath.c_str(),absolute_path,storagePath.length()) == 0) if (strncmp(storagePath.c_str(),absolute_path,storagePath.length()) == 0)
{ {
const char*result = absolute_path + storagePath.length(); const char*result = absolute_path + storagePath.length();
+9
View File
@@ -32,16 +32,25 @@ namespace pipedal
void SetPluginStoragePath(const std::filesystem::path&path) { storagePath = path;} void SetPluginStoragePath(const std::filesystem::path&path) { storagePath = path;}
const LV2_Feature*GetMapPathFeature() { return &mapPathFeature;} const LV2_Feature*GetMapPathFeature() { return &mapPathFeature;}
const LV2_Feature*GetMakePathFeature() { return &makePathFeature;} const LV2_Feature*GetMakePathFeature() { return &makePathFeature;}
const LV2_Feature*GetFreePathFeature() { return &freePathFeature;}
private: private:
char *AbsolutePath(const char *abstract_path); char *AbsolutePath(const char *abstract_path);
static char *FnAbsolutePath(LV2_State_Map_Path_Handle handle, static char *FnAbsolutePath(LV2_State_Map_Path_Handle handle,
const char *abstract_path); const char *abstract_path);
LV2_State_Map_Path lv2_state_map_path; LV2_State_Map_Path lv2_state_map_path;
LV2_State_Make_Path lv2_state_make_path; LV2_State_Make_Path lv2_state_make_path;
LV2_State_Free_Path lv2_state_free_path;
void FreePath(char *path);
static void FnFreePath(LV2_State_Free_Path_Handle handle, char* path);
LV2_Feature mapPathFeature; LV2_Feature mapPathFeature;
LV2_Feature makePathFeature; LV2_Feature makePathFeature;
LV2_Feature freePathFeature;
char *AbstractPath(const char *abstract_path); char *AbstractPath(const char *abstract_path);
static char * FnAbstractPath( static char * FnAbstractPath(
+160
View File
@@ -0,0 +1,160 @@
// 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.
#include "MimeTypes.hpp"
using namespace pipedal;
void MimeTypes::MaybeInitialize()
{
if (!initialized)
{
initialized = true;
AddMimeType("MP3", "audio/mpeg");
AddMimeType("MPGA", "audio/mpeg");
AddMimeType("M4A", "audio/mp4");
AddMimeType("WAV", "audio/x-wav");
AddMimeType("WAV", "audio/wav");
AddMimeType("AMR", "audio/amr");
AddMimeType("AWB", "audio/amr-wb");
AddMimeType("WMA", "audio/x-ms-wma");
AddMimeType("OGG", "audio/ogg");
AddMimeType("OGG", "application/ogg");
AddMimeType("OGA", "application/ogg");
AddMimeType("AAC", "audio/aac");
AddMimeType("AAC", "audio/aac-adts");
AddMimeType("MKA", "audio/x-matroska");
AddMimeType("MID", "audio/midi");
AddMimeType("MIDI", "audio/midi");
AddMimeType("XMF", "audio/midi");
AddMimeType("RTTTL", "audio/midi");
AddMimeType("SMF", "audio/sp-midi");
AddMimeType("IMY", "audio/imelody");
AddMimeType("RTX", "audio/midi");
AddMimeType("OTA", "audio/midi");
AddMimeType("MXMF", "audio/midi");
AddMimeType("MPEG", "video/mpeg");
AddMimeType("MPG", "video/mpeg");
AddMimeType("MP4", "video/mp4");
AddMimeType("M4V", "video/mp4");
AddMimeType("3GP", "video/3gpp");
AddMimeType("3GPP", "video/3gpp");
AddMimeType("3G2", "video/3gpp2");
AddMimeType("3GPP2", "video/3gpp2");
AddMimeType("MKV", "video/x-matroska");
AddMimeType("WEBM", "video/webm");
AddMimeType("TS", "video/mp2ts");
AddMimeType("AVI", "video/avi");
AddMimeType("WMV", "video/x-ms-wmv");
AddMimeType("ASF", "video/x-ms-asf");
AddMimeType("JPG", "image/jpeg");
AddMimeType("JPEG", "image/jpeg");
AddMimeType("GIF", "image/gif");
AddMimeType("PNG", "image/png");
AddMimeType("BMP", "image/x-ms-bmp");
AddMimeType("WBMP", "image/vnd.wap.wbmp");
AddMimeType("WEBP", "image/webp");
AddMimeType("M3U", "audio/x-mpegurl");
AddMimeType("M3U", "application/x-mpegurl");
AddMimeType("PLS", "audio/x-scpls");
AddMimeType("WPL", "application/vnd.ms-wpl");
AddMimeType("M3U8", "application/vnd.apple.mpegurl");
AddMimeType("M3U8", "audio/mpegurl");
AddMimeType("M3U8", "audio/x-mpegurl");
AddMimeType("FL", "application/x-android-drm-fl");
AddMimeType("TXT", "text/plain");
AddMimeType("HTM", "text/html");
AddMimeType("HTML", "text/html");
AddMimeType("PDF", "application/pdf");
AddMimeType("DOC", "application/msword");
AddMimeType("XLS", "application/vnd.ms-excel");
AddMimeType("PPT", "application/mspowerpoint");
AddMimeType("FLAC", "audio/x-flac");
AddMimeType("FLAC", "audio/flac");
AddMimeType("ZIP", "application/zip");
AddMimeType("MPG", "video/mp2p");
AddMimeType("MPEG", "video/mp2p");
}
}
static MimeTypes staticContruct;
static std::string empty;
const std::string& MimeTypes::MimeTypeFromExtension(const std::string &extension)
{
MaybeInitialize();
auto iter = extensionToMimeType.find(extension);
if (iter == extensionToMimeType.end()) return empty;
return iter->second;
}
const std::string& MimeTypes::ExtensionFromMimeType(const std::string &mimeType)
{
MaybeInitialize();
auto iter = mimeTypeToExtension.find(mimeType);
if (iter == mimeTypeToExtension.end()) return empty;
return iter->second;
}
static std::string toLower(const std::string&value)
{
std::string result;
result.resize(value.length());
for (size_t i = 0; i < value.length(); ++i)
{
char c = value[i];
if (c >= 'A' && c <= 'Z')
{
c += 'a'-'A';
}
result[i] = c;
}
return result;
}
void MimeTypes::AddMimeType(const std::string&extension_, const std::string&mimeType)
{
std::string extension = "." + toLower(extension_);
mimeTypeToExtension[mimeType] = extension;
extensionToMimeType[extension] = mimeType;
if (mimeType.starts_with("audio/"))
{
audioExtensions.insert(extension);
}
if (mimeType.starts_with("video/"))
{
videoExtensions.insert(extension);
}
}
std::map<std::string,std::string> MimeTypes::mimeTypeToExtension;
std::map<std::string,std::string> MimeTypes::extensionToMimeType;
std::set<std::string> MimeTypes::audioExtensions;
std::set<std::string> MimeTypes::videoExtensions;
bool MimeTypes::initialized;

Some files were not shown because too many files have changed in this diff Show More