0.1.8-beta-4

This commit is contained in:
Robin Davies
2022-04-26 02:07:05 -04:00
parent 3db29505bb
commit c31bea9ecd
33 changed files with 886 additions and 572 deletions
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.16.0)
project(pipedal project(pipedal
VERSION 0.1.7 VERSION 0.1.8
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 "v0.1.7-beta.3") set (DISPLAY_VERSION "v0.1.8-beta-4")
set (CMAKE_INSTALL_PREFIX "/usr/") set (CMAKE_INSTALL_PREFIX "/usr/")
+1 -1
View File
@@ -1,5 +1,5 @@
<img src='docs/Pi-Logo-3.png' /> <a href='docs/download.md'>v0.1.7-beta-3</a> <img src='docs/Pi-Logo-3.png' /> <a href='docs/download.md'>v0.1.8-beta-4</a>
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.
+23 -14
View File
@@ -4,6 +4,29 @@
"parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase", "parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase",
"plugin_type": "Plugin", "plugin_type": "Plugin",
"children": [ "children": [
{
"uri": "http://two_play.com/ns/pluginClass#ampsNode",
"display_name": "Amp",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "PiPedalAmpsNode",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin",
"display_name": "Amplifier",
"parent_uri": "http://two_play.com/ns/pluginClass#amp",
"plugin_type": "AmplifierPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin",
"display_name": "Simulator",
"parent_uri": "http://two_play.com/ns/pluginClass#amp",
"plugin_type": "SimulatorPlugin",
"children": [ ]
}
]
},
{ {
"uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", "uri": "http://lv2plug.in/ns/lv2core#DelayPlugin",
"display_name": "Delay", "display_name": "Delay",
@@ -40,13 +63,6 @@
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DynamicsPlugin", "plugin_type": "DynamicsPlugin",
"children": [ "children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin",
"display_name": "Amplifier",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "AmplifierPlugin",
"children": [ ]
},
{ {
"uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin", "uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin",
"display_name": "Compressor", "display_name": "Compressor",
@@ -207,13 +223,6 @@
} }
] ]
}, },
{
"uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin",
"display_name": "Simulator",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "SimulatorPlugin",
"children": [ ]
},
{ {
"uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin", "uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin",
"display_name": "Spatial", "display_name": "Spatial",
+23 -14
View File
@@ -4,6 +4,29 @@
"parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase", "parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase",
"plugin_type": "Plugin", "plugin_type": "Plugin",
"children": [ "children": [
{
"uri": "http://two_play.com/ns/pluginClass#ampsNode",
"display_name": "Amp",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "PiPedalAmpsNode",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin",
"display_name": "Amplifier",
"parent_uri": "http://two_play.com/ns/pluginClass#amp",
"plugin_type": "AmplifierPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin",
"display_name": "Simulator",
"parent_uri": "http://two_play.com/ns/pluginClass#amp",
"plugin_type": "SimulatorPlugin",
"children": [ ]
}
]
},
{ {
"uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", "uri": "http://lv2plug.in/ns/lv2core#DelayPlugin",
"display_name": "Delay", "display_name": "Delay",
@@ -40,13 +63,6 @@
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DynamicsPlugin", "plugin_type": "DynamicsPlugin",
"children": [ "children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin",
"display_name": "Amplifier",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "AmplifierPlugin",
"children": [ ]
},
{ {
"uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin", "uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin",
"display_name": "Compressor", "display_name": "Compressor",
@@ -207,13 +223,6 @@
} }
] ]
}, },
{
"uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin",
"display_name": "Simulator",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "SimulatorPlugin",
"children": [ ]
},
{ {
"uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin", "uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin",
"display_name": "Spatial", "display_name": "Spatial",
+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/v0.1.7-beta-3/pipedal_0.1.7_arm64.deb) v0.1.7-beta-3 - [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v0.1.8-beta-4/pipedal_0.1.8_arm64.deb) v0.1.8-beta-4
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_0.1.7_arm64.deb sudo apt-get install ./pipedal_0.1.8_arm64.deb
``` ```
-------- --------
+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/v0.1.7-beta-3/pipedal_0.1.7_arm64.deb) v0.1.7-beta-3 - [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v0.1.8-beta-4/pipedal_0.1.8_arm64.deb) v0.1.8-beta-4
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_0.1.7_arm64.deb sudo apt-get install ./pipedal_0.1.8_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.
+1 -1
View File
@@ -1,6 +1,6 @@
<i>v0.1.7-beta-3</i> <i>v0.1.8-beta-4</i>
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.
+92 -82
View File
@@ -21,88 +21,98 @@ add_custom_command(
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
DEPENDS DEPENDS
src/SearchControl.tsx src/SearchControl.tsx
src/SplitControlView.tsx src/SplitControlView.tsx
src/WifiConfigSettings.tsx src/WifiConfigSettings.tsx
src/FullScreenIME.tsx src/FullScreenIME.tsx
src/JackHostStatus.tsx src/JackHostStatus.tsx
src/SearchFilter.tsx src/index.css
src/MainPage.tsx src/setupTests.ts
src/PiPedalModel.tsx src/SearchFilter.tsx
src/PluginPresetSelector.tsx src/MainPage.tsx
src/Pedal.tsx src/PiPedalModel.tsx
src/ToobMLView.tsx src/AppThemed.css
src/SettingsDialog.tsx src/PluginPresetSelector.tsx
src/PiPedalSocket.tsx src/Pedal.tsx
src/ToobFrequencyResponseView.tsx src/ToobMLView.tsx
src/ControlViewFactory.tsx src/SettingsDialog.tsx
src/Utility.tsx src/WifiDirectConfigDialog.tsx
src/ToobToneStackView.tsx src/WifiDirectConfigSettings.tsx
src/SelectHoverBackground.tsx src/PiPedalSocket.tsx
src/MidiBindingsDialog.tsx src/ToobFrequencyResponseView.tsx
src/TemporaryDrawer.tsx src/ControlViewFactory.tsx
src/GxTunerView.tsx src/Utility.tsx
src/ToobInputStageView.tsx src/ToobToneStackView.tsx
src/DraggableGrid.tsx src/SelectHoverBackground.tsx
src/JackStatusView.tsx src/MidiBindingsDialog.tsx
src/PluginControl.tsx src/TemporaryDrawer.tsx
src/XxxSnippet.tsx src/GxTunerView.tsx
src/PluginPreset.tsx src/ToobInputStageView.tsx
src/Jack.tsx src/DraggableGrid.tsx
src/AlsaDeviceInfo.tsx src/JackStatusView.tsx
src/MidiBinding.tsx src/PluginControl.tsx
src/PiPedalError.tsx src/XxxSnippet.tsx
src/IControlViewFactory.tsx src/PluginPreset.tsx
src/Lv2Plugin.tsx src/Jack.tsx
src/PedalBoard.tsx src/AlsaDeviceInfo.tsx
src/PedalBoardView.tsx src/MidiBinding.tsx
src/PresetDialog.tsx src/PiPedalError.tsx
src/AppThemed.tsx src/IControlViewFactory.tsx
src/ZoomedDial.tsx src/Lv2Plugin.tsx
src/RenameDialog.tsx src/PedalBoard.tsx
src/SplitUiControls.tsx src/AndroidHost.tsx
src/GovernorSettings.tsx src/PedalBoardView.tsx
src/AboutDialog.tsx src/PresetDialog.tsx
src/ToobSpectrumResponseView.tsx src/AppThemed.tsx
src/PluginControlView.tsx src/ZoomedDial.tsx
src/NoChangePassword.tsx src/RenameDialog.tsx
src/ToobSpectrumAnalyzerView.tsx src/SplitUiControls.tsx
src/MidiBindingView.tsx src/GovernorSettings.tsx
src/GxTunerControl.tsx src/AboutDialog.tsx
src/Banks.tsx src/ToobSpectrumResponseView.tsx
src/PluginPresetsDialog.tsx src/PluginControlView.tsx
src/BankDialog.tsx src/NoChangePassword.tsx
src/UploadDialog.tsx src/ToobSpectrumAnalyzerView.tsx
src/ToobPowerStage2View.tsx src/MidiBindingView.tsx
src/index.tsx src/GxTunerControl.tsx
src/Units.tsx src/Banks.tsx
src/VuMeter.tsx src/PluginPresetsDialog.tsx
src/App.test.tsx src/BankDialog.tsx
src/DialogEx.tsx src/UploadDialog.tsx
src/StringBuilder.tsx src/ToobPowerStage2View.tsx
src/SelectChannelsDialog.tsx src/index.tsx
src/Draggable.tsx src/Units.tsx
src/ZoomedUiControl.tsx src/VuMeter.tsx
src/Rect.tsx src/App.test.tsx
src/PluginClass.tsx src/DialogEx.tsx
src/PluginIcon.tsx src/StringBuilder.tsx
src/App.tsx src/SelectChannelsDialog.tsx
src/ResizeResponsiveComponent.tsx src/Draggable.tsx
src/SvgPathBuilder.tsx src/ZoomedUiControl.tsx
src/NumericInput.tsx src/logo.svg
src/JackServerSettings.tsx src/Rect.tsx
src/ListSelectDialog.tsx src/PluginClass.tsx
src/JackServerSettingsDialog.tsx src/reportWebVitals.ts
src/ObservableProperty.tsx src/PluginIcon.tsx
src/SelectMidiChannelsDialog.tsx src/App.tsx
src/WifiChannel.tsx src/ResizeResponsiveComponent.tsx
src/LoadPluginDialog.tsx src/SvgPathBuilder.tsx
src/WifiConfigDialog.tsx src/NumericInput.tsx
src/PluginInfoDialog.tsx src/JackServerSettings.tsx
src/ToobWaveShapeView.tsx src/ListSelectDialog.tsx
src/ToobCabSimView.tsx src/react-app-env.d.ts
src/PresetSelector.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
src/OkCancelDialog.tsx
public/css/roboto.css public/css/roboto.css
public/fonts/Roboto-BlackItalic.woff2 public/fonts/Roboto-BlackItalic.woff2
public/fonts/Roboto-Black.woff2 public/fonts/Roboto-Black.woff2
+273 -264
View File
@@ -4,273 +4,282 @@
"parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase", "parent_uri": "http://lv2plug.in/ns/lv2core#PluginBase",
"plugin_type": "Plugin", "plugin_type": "Plugin",
"children": [ "children": [
{ {
"uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", "uri": "http://two_play.com/ns/pluginClass#amp",
"display_name": "Delay", "display_name": "Amps",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DelayPlugin", "plugin_type": "PiPedalAmpsNode",
"children": [ "children": [
{ {
"uri": "http://lv2plug.in/ns/lv2core#ReverbPlugin", "uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin",
"display_name": "Reverb", "display_name": "Amplifier",
"parent_uri": "http://lv2plug.in/ns/lv2core#DelayPlugin", "parent_uri": "http://two_play.com/ns/pluginClass#amp",
"plugin_type": "ReverbPlugin", "plugin_type": "AmplifierPlugin",
"children": [] "children": [ ]
} },
] {
},
{
"uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin",
"display_name": "Distortion",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DistortionPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#WaveshaperPlugin",
"display_name": "Waveshaper",
"parent_uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin",
"plugin_type": "WaveshaperPlugin",
"children": []
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"display_name": "Dynamics",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DynamicsPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AmplifierPlugin",
"display_name": "Amplifier",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "AmplifierPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin",
"display_name": "Compressor",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "CompressorPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#EnvelopePlugin",
"display_name": "Envelope",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "EnvelopePlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#ExpanderPlugin",
"display_name": "Expander",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "ExpanderPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#GatePlugin",
"display_name": "Gate",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "GatePlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#LimiterPlugin",
"display_name": "Limiter",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "LimiterPlugin",
"children": []
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"display_name": "Filter",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "FilterPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AllpassPlugin",
"display_name": "Allpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "AllpassPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#BandpassPlugin",
"display_name": "Bandpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "BandpassPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#CombPlugin",
"display_name": "Comb",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "CombPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#EQPlugin",
"display_name": "Equaliser",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "EQPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#MultiEQPlugin",
"display_name": "Multiband",
"parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin",
"plugin_type": "MultiEQPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#ParaEQPlugin",
"display_name": "Parametric",
"parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin",
"plugin_type": "ParaEQPlugin",
"children": []
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#HighpassPlugin",
"display_name": "Highpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "HighpassPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#LowpassPlugin",
"display_name": "Lowpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "LowpassPlugin",
"children": []
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
"display_name": "Generator",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "GeneratorPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#ConstantPlugin",
"display_name": "Constant",
"parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
"plugin_type": "ConstantPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#InstrumentPlugin",
"display_name": "Instrument",
"parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
"plugin_type": "InstrumentPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#OscillatorPlugin",
"display_name": "Oscillator",
"parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
"plugin_type": "OscillatorPlugin",
"children": []
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"display_name": "Modulator",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "ModulatorPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#ChorusPlugin",
"display_name": "Chorus",
"parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"plugin_type": "ChorusPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#FlangerPlugin",
"display_name": "Flanger",
"parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"plugin_type": "FlangerPlugin",
"children": []
},
{
"uri": "http://lv2plug.in/ns/lv2core#PhaserPlugin",
"display_name": "Phaser",
"parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"plugin_type": "PhaserPlugin",
"children": []
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin", "uri": "http://lv2plug.in/ns/lv2core#SimulatorPlugin",
"display_name": "Simulator", "display_name": "Simulator",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", "parent_uri": "http://two_play.com/ns/pluginClass#amp",
"plugin_type": "SimulatorPlugin", "plugin_type": "SimulatorPlugin",
"children": [] "children": [ ]
}, }
{
"uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin", ]
"display_name": "Spatial", },
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", {
"plugin_type": "SpatialPlugin", "uri": "http://lv2plug.in/ns/lv2core#DelayPlugin",
"children": [] "display_name": "Delay",
}, "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
{ "plugin_type": "DelayPlugin",
"uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", "children": [
"display_name": "Spectral", {
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", "uri": "http://lv2plug.in/ns/lv2core#ReverbPlugin",
"plugin_type": "SpectralPlugin", "display_name": "Reverb",
"parent_uri": "http://lv2plug.in/ns/lv2core#DelayPlugin",
"plugin_type": "ReverbPlugin",
"children": [ ]
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin",
"display_name": "Distortion",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DistortionPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#WaveshaperPlugin",
"display_name": "Waveshaper",
"parent_uri": "http://lv2plug.in/ns/lv2core#DistortionPlugin",
"plugin_type": "WaveshaperPlugin",
"children": [ ]
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"display_name": "Dynamics",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "DynamicsPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#CompressorPlugin",
"display_name": "Compressor",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "CompressorPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#EnvelopePlugin",
"display_name": "Envelope",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "EnvelopePlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#ExpanderPlugin",
"display_name": "Expander",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "ExpanderPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#GatePlugin",
"display_name": "Gate",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "GatePlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#LimiterPlugin",
"display_name": "Limiter",
"parent_uri": "http://lv2plug.in/ns/lv2core#DynamicsPlugin",
"plugin_type": "LimiterPlugin",
"children": [ ]
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"display_name": "Filter",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "FilterPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AllpassPlugin",
"display_name": "Allpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "AllpassPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#BandpassPlugin",
"display_name": "Bandpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "BandpassPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#CombPlugin",
"display_name": "Comb",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "CombPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#EQPlugin",
"display_name": "Equaliser",
"parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "EQPlugin",
"children": [ "children": [
{ {
"uri": "http://lv2plug.in/ns/lv2core#PitchPlugin", "uri": "http://lv2plug.in/ns/lv2core#MultiEQPlugin",
"display_name": "Pitch Shifter", "display_name": "Multiband",
"parent_uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin", "parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin",
"plugin_type": "PitchPlugin", "plugin_type": "MultiEQPlugin",
"children": [] "children": [ ]
} },
{
"uri": "http://lv2plug.in/ns/lv2core#ParaEQPlugin",
"display_name": "Parametric",
"parent_uri": "http://lv2plug.in/ns/lv2core#EQPlugin",
"plugin_type": "ParaEQPlugin",
"children": [ ]
}
] ]
}, },
{ {
"uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", "uri": "http://lv2plug.in/ns/lv2core#HighpassPlugin",
"display_name": "Utility", "display_name": "Highpass",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin", "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"plugin_type": "UtilityPlugin", "plugin_type": "HighpassPlugin",
"children": [ "children": [ ]
{ },
"uri": "http://lv2plug.in/ns/lv2core#AnalyserPlugin", {
"display_name": "Analyser", "uri": "http://lv2plug.in/ns/lv2core#LowpassPlugin",
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", "display_name": "Lowpass",
"plugin_type": "AnalyserPlugin", "parent_uri": "http://lv2plug.in/ns/lv2core#FilterPlugin",
"children": [] "plugin_type": "LowpassPlugin",
}, "children": [ ]
{ }
"uri": "http://lv2plug.in/ns/lv2core#ConverterPlugin", ]
"display_name": "Converter", },
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", {
"plugin_type": "ConverterPlugin", "uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
"children": [] "display_name": "Generator",
}, "parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
{ "plugin_type": "GeneratorPlugin",
"uri": "http://lv2plug.in/ns/lv2core#FunctionPlugin", "children": [
"display_name": "Function", {
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", "uri": "http://lv2plug.in/ns/lv2core#ConstantPlugin",
"plugin_type": "FunctionPlugin", "display_name": "Constant",
"children": [] "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
}, "plugin_type": "ConstantPlugin",
{ "children": [ ]
"uri": "http://lv2plug.in/ns/lv2core#MixerPlugin", },
"display_name": "Mixer", {
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin", "uri": "http://lv2plug.in/ns/lv2core#InstrumentPlugin",
"plugin_type": "MixerPlugin", "display_name": "Instrument",
"children": [] "parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
} "plugin_type": "InstrumentPlugin",
] "children": [ ]
} },
{
"uri": "http://lv2plug.in/ns/lv2core#OscillatorPlugin",
"display_name": "Oscillator",
"parent_uri": "http://lv2plug.in/ns/lv2core#GeneratorPlugin",
"plugin_type": "OscillatorPlugin",
"children": [ ]
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"display_name": "Modulator",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "ModulatorPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#ChorusPlugin",
"display_name": "Chorus",
"parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"plugin_type": "ChorusPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#FlangerPlugin",
"display_name": "Flanger",
"parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"plugin_type": "FlangerPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#PhaserPlugin",
"display_name": "Phaser",
"parent_uri": "http://lv2plug.in/ns/lv2core#ModulatorPlugin",
"plugin_type": "PhaserPlugin",
"children": [ ]
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#SpatialPlugin",
"display_name": "Spatial",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "SpatialPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin",
"display_name": "Spectral",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "SpectralPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#PitchPlugin",
"display_name": "Pitch Shifter",
"parent_uri": "http://lv2plug.in/ns/lv2core#SpectralPlugin",
"plugin_type": "PitchPlugin",
"children": [ ]
}
]
},
{
"uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin",
"display_name": "Utility",
"parent_uri": "http://lv2plug.in/ns/lv2core#Plugin",
"plugin_type": "UtilityPlugin",
"children": [
{
"uri": "http://lv2plug.in/ns/lv2core#AnalyserPlugin",
"display_name": "Analyser",
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin",
"plugin_type": "AnalyserPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#ConverterPlugin",
"display_name": "Converter",
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin",
"plugin_type": "ConverterPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#FunctionPlugin",
"display_name": "Function",
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin",
"plugin_type": "FunctionPlugin",
"children": [ ]
},
{
"uri": "http://lv2plug.in/ns/lv2core#MixerPlugin",
"display_name": "Mixer",
"parent_uri": "http://lv2plug.in/ns/lv2core#UtilityPlugin",
"plugin_type": "MixerPlugin",
"children": [ ]
}
]
}
] ]
} }
+7 -12
View File
@@ -6,7 +6,7 @@ import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import ArrowBackIcon from '@mui/icons-material//ArrowBack'; import ArrowBackIcon from '@mui/icons-material//ArrowBack';
import Divider from '@mui/material/Divider';
import JackHostStatus from './JackHostStatus'; import JackHostStatus from './JackHostStatus';
import {PiPedalError} from './PiPedalError'; import {PiPedalError} from './PiPedalError';
import DialogEx from './DialogEx'; import DialogEx from './DialogEx';
@@ -219,22 +219,17 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
</span> </span>
</Typography> </Typography>
<Typography display="block" variant="body2" style={{marginBottom: 12}} > <Typography display="block" variant="body2" style={{marginBottom: 12}} >
Copyright &#169; 2021 Robin Davies. All rights reserved. Copyright &#169; 2022 Robin Davies.
</Typography> </Typography>
<Divider/> <Typography display="block" variant="body2" style={{marginBottom: 12}} >
<Typography display="block" variant="caption" > {this.model.getAndroidHostVersion() }
JACK AUDIO STATUS
</Typography> </Typography>
<div style={{paddingTop: 8, paddingBottom: 24}}>
{
JackHostStatus.getDisplayView("",this.state.jackStatus)
}
</div>
<Divider/>
<Typography display="block" variant="caption" > <Typography display="block" variant="caption" >
LEGAL NOTICES LEGAL NOTICES
</Typography> </Typography>
<div dangerouslySetInnerHTML={{__html: this.state.openSourceNotices}}> <div dangerouslySetInnerHTML={{__html: this.state.openSourceNotices}} style={{fontSize: "0.8em" }}>
</div> </div>
</div> </div>
+2 -2
View File
@@ -26,7 +26,7 @@ export interface AndroidHostInterface {
isAndroidHosted(): boolean; isAndroidHosted(): boolean;
getHostVersion() : string; getHostVersion() : string;
chooseNewDevice() : void; chooseNewDevice() : void;
onLostConnection(): void; setDisconnected(isDisconnected: boolean): void;
}; };
@@ -41,7 +41,7 @@ export class FakeAndroidHost implements AndroidHostInterface
chooseNewDevice(): void { chooseNewDevice(): void {
} }
onLostConnection(): void { setDisconnected(isDisconnected: boolean): void {
} }
+1 -1
View File
@@ -36,7 +36,7 @@ declare module '@mui/styles/defaultTheme' {
const theme = createTheme({ const theme = createTheme({
palette: { palette: {
primary: { primary: {
main: "#6750A4" main: "#6750A4" // #5B5690 #60529A #5C5694
}, },
secondary: { secondary: {
main: "#FF6060" main: "#FF6060"
+5 -3
View File
@@ -114,7 +114,7 @@ const appStyles = (theme: Theme) => createStyles({
marginTop: 0, marginTop: 0,
fontWeight: 500, fontWeight: 500,
fontSize: "13pt", fontSize: "13pt",
maxWidth: 250, maxWidth: 350,
opacity: 1, opacity: 1,
zIndex: 2010, zIndex: 2010,
paddingTop: 12, paddingTop: 12,
@@ -785,7 +785,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</DialogActions> </DialogActions>
</Dialog> </Dialog>
<JackStatusView /> <JackStatusView />
<div className={classes.errorContent} style={{ display: this.state.displayState === State.Reconnecting ? "block" : "none" }} <div className={classes.errorContent} style={{
display: (this.state.displayState === State.Reconnecting || this.state.displayState === State.ApplyingChanges)
? "block" : "none" }}
> >
<div className={classes.errorContentMask} /> <div className={classes.errorContentMask} />
@@ -794,7 +796,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<CircularProgress color="inherit" className={classes.loadingBoxItem} /> <CircularProgress color="inherit" className={classes.loadingBoxItem} />
</div> </div>
<Typography variant="body2" className={classes.progressText}> <Typography variant="body2" className={classes.progressText}>
Reconnecting... { this.state.displayState === State.ApplyingChanges ? "Applying\u00A0changes..." : "Reconnecting..."}
</Typography> </Typography>
</div> </div>
</div> </div>
+29 -20
View File
@@ -21,6 +21,7 @@ import React, { ReactNode, SyntheticEvent, CSSProperties } from 'react';
import { PiPedalModel, PiPedalModelFactory, FavoritesList } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, FavoritesList } from './PiPedalModel';
import { UiPlugin, PluginType } from './Lv2Plugin'; import { UiPlugin, PluginType } from './Lv2Plugin';
import TextField from '@mui/material/TextField';
import ButtonBase from '@mui/material/ButtonBase'; import ButtonBase from '@mui/material/ButtonBase';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
@@ -34,9 +35,7 @@ import DialogTitle from '@mui/material/DialogTitle';
import SelectHoverBackground from './SelectHoverBackground'; import SelectHoverBackground from './SelectHoverBackground';
import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Select from '@mui/material/Select';
import PluginClass from './PluginClass' import PluginClass from './PluginClass'
import ClearIcon from '@mui/icons-material/Clear';
import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import ResizeResponsiveComponent from './ResizeResponsiveComponent';
import SearchControl from './SearchControl'; import SearchControl from './SearchControl';
import SearchFilter from './SearchFilter'; import SearchFilter from './SearchFilter';
@@ -46,6 +45,9 @@ import StarBorderIcon from '@mui/icons-material/StarBorder';
import Slide, { SlideProps } from '@mui/material/Slide'; import Slide, { SlideProps } from '@mui/material/Slide';
import { createStyles, Theme } from '@mui/material/styles'; import { createStyles, Theme } from '@mui/material/styles';
import { WithStyles, withStyles } from '@mui/styles'; import { WithStyles, withStyles } from '@mui/styles';
import FilterListIcon from '@mui/icons-material/FilterList';
import FilterListOffIcon from '@mui/icons-material/FilterListOff';
export type CloseEventHandler = () => void; export type CloseEventHandler = () => void;
@@ -504,15 +506,15 @@ export const LoadPluginDialog =
</div> </div>
<div className={classes.content2}> <div className={classes.content2}>
<div className={classes.label} > <div className={classes.label} >
<Typography color="textPrimary" noWrap sx={{display: "inline"}} > <Typography color="textPrimary" noWrap sx={{ display: "inline" }} >
{value.name} {value.name}
{ {
isFavorite && ( isFavorite && (
<StarBorderIcon sx={{ color: "#C80", fontSize:16 }} /> <StarBorderIcon sx={{ color: "#C80", fontSize: 16 }} />
) )
} }
</Typography> </Typography>
</div> </div>
<Typography color="textSecondary" noWrap> <Typography color="textSecondary" noWrap>
{value.plugin_display_type} {this.stereo_indicator(value)} {value.plugin_display_type} {this.stereo_indicator(value)}
@@ -598,19 +600,26 @@ export const LoadPluginDialog =
}} }}
/> />
</div> </div>
<Select variant="standard" <div style={{ flex: "0 0 auto" }} >
defaultValue={this.state.filterType}
key={this.state.filterType}
onChange={(e) => { this.onFilterChange(e); }}
style={{ flex: "0 0 160px" }}
>
{this.createFilterOptions()}
</Select>
<div style={{ flex: "0 0 auto", marginRight: 24, visibility: this.state.filterType === PluginType.Plugin ? "hidden" : "visible" }} >
<IconButton onClick={() => { this.onClearFilter(); }}> <IconButton onClick={() => { this.onClearFilter(); }}>
<ClearIcon fontSize='small' style={{ opacity: 0.6 }} /> {this.state.filterType === PluginType.Plugin ? (
<FilterListIcon fontSize='small' style={{ opacity: 0.75 }} />
) : (
<FilterListOffIcon fontSize='small' style={{ opacity: 0.75 }} />
)}
</IconButton> </IconButton>
</div> </div>
<div style={{ flex: "0 0 160px",marginRight: 24 }} >
<TextField select variant="standard"
defaultValue={this.state.filterType}
key={this.state.filterType}
onChange={(e) => { this.onFilterChange(e); }}
sx={{ minWidth: 160}}
>
{this.createFilterOptions()}
</TextField>
</div>
</div> </div>
</DialogTitle> </DialogTitle>
<DialogContent dividers style={{ <DialogContent dividers style={{
+3
View File
@@ -189,6 +189,9 @@ export enum PluginType {
UtilityPlugin = "UtilityPlugin", UtilityPlugin = "UtilityPlugin",
WaveshaperPlugin = "WaveshaperPlugin", WaveshaperPlugin = "WaveshaperPlugin",
// psuedo plugin type for the Amps node of the filter dialog.
PiPedalAmpsNode = "PiPedalAmpsNode"
} }
export enum ControlType { export enum ControlType {
+67 -6
View File
@@ -45,7 +45,8 @@ export enum State {
Ready, Ready,
Error, Error,
Background, Background,
Reconnecting Reconnecting,
ApplyingChanges
}; };
export type ControlValueChangedHandler = (key: string, value: number) => void; export type ControlValueChangedHandler = (key: string, value: number) => void;
@@ -503,11 +504,18 @@ class PiPedalModelImpl implements PiPedalModel {
this.onSocketReconnecting = this.onSocketReconnecting.bind(this); this.onSocketReconnecting = this.onSocketReconnecting.bind(this);
this.onSocketReconnected = this.onSocketReconnected.bind(this); this.onSocketReconnected = this.onSocketReconnected.bind(this);
this.onVisibilityChanged = this.onVisibilityChanged.bind(this); this.onVisibilityChanged = this.onVisibilityChanged.bind(this);
this.onSocketConnectionLost = this.onSocketConnectionLost.bind(this);
} }
onSocketReconnecting(retry: number, maxRetries: number): void { onSocketReconnecting(retry: number, maxRetries: number): void {
if (this.visibilityState.get() === VisibilityState.Hidden) return; if (this.visibilityState.get() === VisibilityState.Hidden) return;
//if (retry !== 0) { //if (retry !== 0) {
this.setState(State.Reconnecting); if (this.restartExpected)
{
this.setState(State.ApplyingChanges);
} else {
this.setState(State.Reconnecting);
}
//} //}
} }
@@ -697,7 +705,20 @@ class PiPedalModelImpl implements PiPedalModel {
return this.webSocket; return this.webSocket;
} }
onSocketConnectionLost() {
if (this.isAndroidHosted())
{
this.androidHost?.setDisconnected(true);
}
}
onSocketReconnected() { onSocketReconnected() {
if (this.isAndroidHosted())
{
this.androidHost?.setDisconnected(false);
}
this.restartExpected = false;
if (this.visibilityState.get() === VisibilityState.Hidden) return; if (this.visibilityState.get() === VisibilityState.Hidden) return;
// reload state, but not configuration. // reload state, but not configuration.
@@ -778,6 +799,7 @@ class PiPedalModelImpl implements PiPedalModel {
maxUploadSize: number = 512 * 1024; maxUploadSize: number = 512 * 1024;
debug: boolean = false; debug: boolean = false;
requestConfig(): Promise<boolean> { requestConfig(): Promise<boolean> {
const myRequest = new Request(this.varRequest('config.json')); const myRequest = new Request(this.varRequest('config.json'));
return fetch(myRequest) return fetch(myRequest)
@@ -808,10 +830,14 @@ class PiPedalModelImpl implements PiPedalModel {
this.webSocket = new PiPedalSocket( this.webSocket = new PiPedalSocket(
this.socketServerUrl, this.socketServerUrl,
this.onSocketMessage, {
this.onSocketError, onMessageReceived : this.onSocketMessage,
this.onSocketReconnecting, onError: this.onSocketError,
this.onSocketReconnected); onConnectionLost: this.onSocketConnectionLost,
onReconnect: this.onSocketReconnected,
onReconnecting: this.onSocketReconnecting
}
);
return this.webSocket.connect(); return this.webSocket.connect();
}) })
.then(() => { .then(() => {
@@ -948,7 +974,15 @@ class PiPedalModelImpl implements PiPedalModel {
} }
backgroundStateTimeout?: NodeJS.Timeout = undefined;
exitBackgroundState() { exitBackgroundState() {
if (this.backgroundStateTimeout)
{
clearTimeout(this.backgroundStateTimeout);
this.backgroundStateTimeout = undefined;
return;
}
if (this.state.get() === State.Background) { if (this.state.get() === State.Background) {
console.log("Exiting background state."); console.log("Exiting background state.");
this.visibilityState.set(VisibilityState.Visible); this.visibilityState.set(VisibilityState.Visible);
@@ -957,6 +991,24 @@ class PiPedalModelImpl implements PiPedalModel {
} }
enterBackgroundState() { enterBackgroundState() {
// on Android, delay entering background state by 3 seconds,
// so that screen-flips don't trigger disconnects.
if (this.isAndroidHosted())
{
if (this.backgroundStateTimeout)
{
clearTimeout(this.backgroundStateTimeout);
}
this.backgroundStateTimeout = setTimeout(() => {
this.backgroundStateTimeout = undefined;
this.enterBackgroundState_();
}, 3000);
} else {
this.enterBackgroundState_();
}
}
enterBackgroundState_() {
if (this.state.get() !== State.Background) { if (this.state.get() !== State.Background) {
console.log("Entering background state."); console.log("Entering background state.");
this.visibilityState.set(VisibilityState.Hidden); this.visibilityState.set(VisibilityState.Hidden);
@@ -1438,7 +1490,16 @@ class PiPedalModelImpl implements PiPedalModel {
showAlert(message: string): void { showAlert(message: string): void {
this.alertMessage.set(message); this.alertMessage.set(message);
} }
restartExpected: boolean = false;
expectRestart() {
this.restartExpected = true;
}
setJackSettings(jackSettings: JackChannelSelection): void { setJackSettings(jackSettings: JackChannelSelection): void {
this.expectRestart();
this.webSocket?.send("setJackSettings", jackSettings); this.webSocket?.send("setJackSettings", jackSettings);
} }
+24 -23
View File
@@ -36,13 +36,18 @@ export type PiPedalMessageHeader = {
type ReplyHandler = (header: PiPedalMessageHeader, body: any | null) => void; type ReplyHandler = (header: PiPedalMessageHeader, body: any | null) => void;
export interface PiPedalSocketListener {
onMessageReceived : (header: PiPedalMessageHeader, body: any | null) => void;
onError: (message: string, exception?: Error) => void;
onConnectionLost: () => void;
onReconnect: () => void;
onReconnecting: (retry: number, maxRetries: number) => void;
};
class PiPedalSocket { class PiPedalSocket {
onMessageReceived: MessageHandler;
onError: ErrorHandler; listener: PiPedalSocketListener;
onReconnecting: ReconnectingHandler;
onReconnect: ReconnectHandler;
socket?: WebSocket; socket?: WebSocket;
nextResponseCode: number = 0; nextResponseCode: number = 0;
@@ -54,15 +59,10 @@ class PiPedalSocket {
constructor( constructor(
url: string, url: string,
onMessageReceived: MessageHandler, listener: PiPedalSocketListener
onError: ErrorHandler, ) {
onReconnecting: ReconnectingHandler,
onReconnect: ReconnectHandler) {
this.url = url; this.url = url;
this.onMessageReceived = onMessageReceived; this.listener = listener;
this.onError = onError;
this.onReconnecting = onReconnecting;
this.onReconnect = onReconnect;
} }
handleOpen(event: Event): any { handleOpen(event: Event): any {
@@ -160,11 +160,11 @@ class PiPedalSocket {
if (header.message === "error") { if (header.message === "error") {
throw new PiPedalStateError("Server error: " + body); throw new PiPedalStateError("Server error: " + body);
} }
this.onMessageReceived(header, body); this.listener.onMessageReceived(header, body);
} }
} catch (error) { } catch (error) {
if (this.onError) { if (this.listener) {
this.onError("Invalid server response. " + error, error as Error); this.listener.onError("Invalid server response. " + error, error as Error);
} else { } else {
throw new PiPedalStateError("Invalid server response."); throw new PiPedalStateError("Invalid server response.");
} }
@@ -172,8 +172,8 @@ class PiPedalSocket {
} }
handleError(_event: Event): any { handleError(_event: Event): any {
if (this.onError) { if (this.listener) {
this.onError("Server connection lost."); this.listener.onError("Server connection lost.");
} else { } else {
throw new PiPedalStateError("Server connection lost."); throw new PiPedalStateError("Server connection lost.");
} }
@@ -184,8 +184,8 @@ class PiPedalSocket {
handleClose(_event: any): any { handleClose(_event: any): any {
if (this.retrying) { if (this.retrying) {
// treat this as a fatal error. // treat this as a fatal error.
if (this.onError) { if (this.listener) {
this.onError("Server connection lost."); this.listener.onError("Server connection lost.");
} else { } else {
throw new PiPedalStateError("Server connection closed."); throw new PiPedalStateError("Server connection closed.");
} }
@@ -194,6 +194,7 @@ class PiPedalSocket {
} }
if (this.canReconnect) if (this.canReconnect)
{ {
this.listener.onConnectionLost();
this._reconnect(); this._reconnect();
} }
} }
@@ -229,19 +230,19 @@ class PiPedalSocket {
this.close(); this.close();
} }
this.onReconnecting(this.retryCount,MAX_RETRIES); this.listener.onReconnecting(this.retryCount,MAX_RETRIES);
++this.retryCount; ++this.retryCount;
this.connectInternal_() this.connectInternal_()
.then((socket) => { .then((socket) => {
this.socket = socket; this.socket = socket;
this.retrying = false; this.retrying = false;
this.onReconnect(); this.listener.onReconnect();
}) })
.catch(error => { .catch(error => {
if (this.totalRetryDelay === MAX_RETRY_TIME) if (this.totalRetryDelay === MAX_RETRY_TIME)
{ {
this.onError("Server connection lost."); this.listener.onError("Server connection lost.");
return; return;
} else { } else {
this.totalRetryDelay += this.retryDelay; this.totalRetryDelay += this.retryDelay;
+10 -8
View File
@@ -70,7 +70,6 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) {
const { onClose, selectedChannels, availableChannels, open } = props; const { onClose, selectedChannels, availableChannels, open } = props;
const [currentSelection, setCurrentSelection] = useState(selectedChannels); const [currentSelection, setCurrentSelection] = useState(selectedChannels);
let showCheckboxes = availableChannels.length > 2; let showCheckboxes = availableChannels.length > 2;
if (showCheckboxes) { if (showCheckboxes) {
@@ -120,24 +119,27 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) {
} else { } else {
const handleClose = () => { const handleCancel = () => {
onClose(selectedChannels); onClose(null);
}
const handleOk = (channels: string[]) => {
onClose(channels);
}; };
const handleListItemClick = (value: string) => { const handleListItemClick = (value: string) => {
switch (value) { switch (value) {
case "Stereo": case "Stereo":
onClose(availableChannels); handleOk(availableChannels);
break; break;
case "Left": case "Left":
onClose([availableChannels[0]]); handleOk([availableChannels[0]]);
break; break;
case "Right": case "Right":
onClose([availableChannels[1]]); handleOk([availableChannels[1]]);
break; break;
case "None": case "None":
default: default:
onClose([availableChannels[1]]); handleOk([]);
} }
}; };
let selectionKey = "None"; let selectionKey = "None";
@@ -152,7 +154,7 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) {
} }
return ( return (
<Dialog onClose={handleClose} aria-labelledby="select-channels-title" open={open}> <Dialog onClose={handleCancel} aria-labelledby="select-channels-title" open={open}>
<List style={{ marginLeft: 0, marginRight: 0}}> <List style={{ marginLeft: 0, marginRight: 0}}>
<ListItem button onClick={() => handleListItemClick("Stereo")} key={"Stereo"} selected={selectionKey === "Stereo"} > <ListItem button onClick={() => handleListItemClick("Stereo")} key={"Stereo"} selected={selectionKey === "Stereo"} >
+197 -77
View File
@@ -23,12 +23,14 @@
*/ */
import React from 'react'; import React from 'react';
import IconButton from '@mui/material/IconButton';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import DialogEx from './DialogEx'; import DialogEx from './DialogEx';
import DialogActions from '@mui/material/DialogActions'; import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent'; import DialogContent from '@mui/material/DialogContent';
import DialogTitle from '@mui/material/DialogTitle';
import Switch from '@mui/material/Switch'; import Switch from '@mui/material/Switch';
import FormControlLabel from '@mui/material/FormControlLabel'; import FormControlLabel from '@mui/material/FormControlLabel';
import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import ResizeResponsiveComponent from './ResizeResponsiveComponent';
@@ -37,9 +39,6 @@ import { Theme } from '@mui/material/styles';
import { WithStyles } from '@mui/styles'; import { WithStyles } from '@mui/styles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import createStyles from '@mui/styles/createStyles'; import createStyles from '@mui/styles/createStyles';
import Select from '@mui/material/Select';
import FormControl from '@mui/material/FormControl';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import WifiChannel from './WifiChannel'; import WifiChannel from './WifiChannel';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
@@ -72,6 +71,9 @@ export interface WifiDirectConfigState {
pinErrorMessage: string; pinErrorMessage: string;
countryCode: string; countryCode: string;
channel: string; channel: string;
controlWidth: number;
landscapeLayout: boolean;
controlSize: ("medium" | "small" | undefined);
wifiChannels: WifiChannel[]; wifiChannels: WifiChannel[];
} }
@@ -88,7 +90,7 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
super(props); super(props);
this.model = PiPedalModelFactory.getInstance(); this.model = PiPedalModelFactory.getInstance();
this.state = { this.state = {
fullScreen: false, fullScreen: this.useFullScreen(),
enabled: this.props.wifiDirectConfigSettings.enable, enabled: this.props.wifiDirectConfigSettings.enable,
name: this.props.wifiDirectConfigSettings.hotspotName, name: this.props.wifiDirectConfigSettings.hotspotName,
pin: this.props.wifiDirectConfigSettings.pin, pin: this.props.wifiDirectConfigSettings.pin,
@@ -98,6 +100,10 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
pinErrorMessage: NBSP, pinErrorMessage: NBSP,
countryCode: this.props.wifiDirectConfigSettings.countryCode, countryCode: this.props.wifiDirectConfigSettings.countryCode,
channel: this.props.wifiDirectConfigSettings.channel, channel: this.props.wifiDirectConfigSettings.channel,
controlWidth: 260,
controlSize: this.windowSize.height < 600 ? "small" : "medium",
landscapeLayout: this.useLandscapeLayout(),
wifiChannels: [] wifiChannels: []
}; };
this.model.getWifiChannels(this.props.wifiDirectConfigSettings.countryCode) this.model.getWifiChannels(this.props.wifiDirectConfigSettings.countryCode)
@@ -108,6 +114,10 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
this.refName = React.createRef<HTMLInputElement>(); this.refName = React.createRef<HTMLInputElement>();
this.refPassword = React.createRef<HTMLInputElement>(); this.refPassword = React.createRef<HTMLInputElement>();
} }
useLandscapeLayout(): boolean {
return (this.windowSize.height < 690 && this.windowSize.width > this.windowSize.height && this.windowSize.width > 690);
}
mounted: boolean = false; mounted: boolean = false;
handleEnableChanged(e: any) { handleEnableChanged(e: any) {
@@ -116,7 +126,15 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
onWindowSizeChanged(width: number, height: number): void { onWindowSizeChanged(width: number, height: number): void {
this.setState({ fullScreen: height < 200 }) this.setState({
fullScreen: this.useFullScreen(),
controlSize: height < 600 ? "small" : "medium",
landscapeLayout: this.useLandscapeLayout()
})
}
useFullScreen(): boolean {
return this.windowSize.height < 390;
} }
@@ -288,84 +306,94 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
}; };
return ( return (
<DialogEx tag="WifiDirectConfigDialog" open={open} fullWidth onClose={handleClose} style={{ userSelect: "none" }} <DialogEx tag="WifiDirectConfigDialog" open={open} onClose={handleClose} style={{ userSelect: "none", }}
fullScreen={this.state.fullScreen} fullScreen={this.state.fullScreen} fullWidth={this.useLandscapeLayout()}
> >
{this.state.fullScreen && ( {this.state.landscapeLayout && (
<DialogTitle>Wi-fi Hotspot</DialogTitle> <DialogContent >
)} <div style={{ display: "flex", gap: 16, alignItems: "left" }}>
<DialogContent> <IconButton
edge="start"
<FormControlLabel color="inherit"
control={( onClick={()=> {this.props.onClose(); }}
<Switch aria-label="back"
checked={this.state.enabled} size="large">
onChange={(e: any) => this.handleEnableChanged(e)} <ArrowBackIcon htmlColor="#888"/>
color="secondary" </IconButton>
<FormControlLabel
control={(
<Switch
checked={this.state.enabled}
onChange={(e: any) => this.handleEnableChanged(e)}
color="secondary"
/>
)}
label="Wi-Fi Direct Hotspot"
/> />
)} </div>
label="Enable Wi-Fi Direct Hotspot" <div style={{ marginTop: 16, display: 'flex', alignItems: 'center', gap: 16 }}>
/> <TextField
<div style={{ marginTop: 16 }}> required
<TextField
required sx={{ maxWidth: this.state.controlWidth }}
autoComplete="off" autoComplete="off"
id="name" id="name"
spellCheck="false" spellCheck="false"
label="SSID" label="SSID"
type="text" type="text"
fullWidth size={this.state.controlSize}
error={this.state.nameError} fullWidth
helperText={this.state.nameErrorMessage} error={this.state.nameError}
value={this.state.name} helperText={this.state.nameErrorMessage}
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })} value={this.state.name}
inputRef={this.refName} onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
disabled={!this.state.enabled} inputRef={this.refName}
variant="filled" disabled={!this.state.enabled}
/> variant="filled"
</div> />
<div style={{ marginBottom: 0, verticalAlign: "baseline" }}>
<TextField <TextField
inputRef={this.refPassword} inputRef={this.refPassword}
autoComplete="off" sx={{ maxWidth: this.state.controlWidth }}
onChange={(e): void => { this.setState({ pin: e.target.value, pinError: false, pinErrorMessage: NBSP }); }}
label="Pin" size={this.state.controlSize}
error={this.state.pinError} autoComplete="off"
helperText={this.state.pinErrorMessage} onChange={(e): void => { this.setState({ pin: e.target.value, pinError: false, pinErrorMessage: NBSP }); }}
defaultValue={this.state.pin} label="Pin"
disabled={!this.state.enabled} inputProps={{ inputMode: 'numeric' }}
variant="filled" fullWidth
/> error={this.state.pinError}
<FormControl> helperText={this.state.pinErrorMessage}
<div style={{ marginLeft: 16, marginTop: 18 }}> defaultValue={this.state.pin}
<Button size="medium" disabled={!this.state.enabled} disabled={!this.state.enabled}
variant="filled"
/>
</div>
<div style={{ width: this.state.controlWidth * 2 }}>
<div style={{ marginTop: 0, marginBottom: 16, width: this.state.controlWidth, marginLeft: "auto", marginRight: 0, textAlign: "right" }}>
<Button size="small" disabled={!this.state.enabled}
onClick={() => this.onGenerateRandomPin()} onClick={() => this.onGenerateRandomPin()}
>Generate random pin</Button> >Generate random pin</Button>
</div> </div>
</FormControl> </div>
</div> <div style={{ marginTop: 0, display: 'flex', alignItems: 'stretch', gap: 16 }}>
<div style={{ marginBottom: 24 }}> <TextField select label="Country" size={this.state.controlSize} value={this.state.countryCode} variant="filled"
<FormControl variant="filled" sx={{ minWidth: 330 }}> sx={{ width: this.state.controlWidth }}
<InputLabel htmlFor="countryCodeSelect">Country</InputLabel> disabled={!this.state.enabled}
<Select id="countryCodeSelect" label="Country" value={this.state.countryCode} disabled={!this.state.enabled} onChange={(event) => { this.handleCountryChanged(event); }}
onChange={(event) => this.handleCountryChanged(event)} > >
{Object.entries(this.model.countryCodes).map(([key, value]) => { {Object.entries(this.model.countryCodes).map(([key, value]) => {
return ( return (
<MenuItem value={key}>{value}</MenuItem> <MenuItem value={key}>{value}</MenuItem>
); );
})} })}
</Select> </TextField>
</FormControl>
<TextField select id="channelSelect" size={this.state.controlSize} label="Channel"
value={this.state.channel} variant="filled" sx={{ width: this.state.controlWidth }}
</div> disabled={!this.state.enabled}
<div style={{ marginBottom: 24 }}> onChange={(event) => { this.handleChannelChange(event); }}
<FormControl variant="filled" sx={{ minWidth: 330 }} > >
<InputLabel htmlFor="channelSelect">Channel</InputLabel>
<Select id="channelSelect" label="Channel" value={this.state.channel} disabled={!this.state.enabled} onChange={(e) => {
this.handleChannelChange(e);
}}>
{this.state.wifiChannels.map((channel) => { {this.state.wifiChannels.map((channel) => {
let t = channel.channelId; let t = channel.channelId;
if (t.startsWith("a")) t = t.substring(1); if (t.startsWith("a")) t = t.substring(1);
@@ -378,12 +406,104 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })(
<MenuItem value={t}>{name}</MenuItem> <MenuItem value={t}>{name}</MenuItem>
) )
})} })}
</Select> </TextField>
</FormControl>
</div> </div>
</DialogContent>
)}
{(!this.state.landscapeLayout) && (
<DialogContent sx={{minHeight: 96}} >
<FormControlLabel
control={(
<Switch
checked={this.state.enabled}
onChange={(e: any) => this.handleEnableChanged(e)}
color="secondary"
/>
)}
label="Wi-Fi Direct Hotspot"
/>
<div style={{ marginTop: 16 }}>
<TextField
required
sx={{ maxWidth: this.state.controlWidth }}
autoComplete="off"
id="name"
spellCheck="false"
label="SSID"
type="text"
size={this.state.controlSize}
fullWidth
error={this.state.nameError}
helperText={this.state.nameErrorMessage}
value={this.state.name}
onChange={(e) => this.setState({ name: e.target.value, nameError: false, nameErrorMessage: NBSP })}
inputRef={this.refName}
disabled={!this.state.enabled}
variant="filled"
/>
</div><div>
<TextField
inputRef={this.refPassword}
sx={{ maxWidth: this.state.controlWidth }}
style={{ maxWidth: this.state.controlWidth }}
size={this.state.controlSize}
autoComplete="off"
onChange={(e): void => { this.setState({ pin: e.target.value, pinError: false, pinErrorMessage: NBSP }); }}
label="Pin"
inputProps={{ inputMode: 'numeric' }}
fullWidth
error={this.state.pinError}
helperText={this.state.pinErrorMessage}
defaultValue={this.state.pin}
disabled={!this.state.enabled}
variant="filled"
/>
</div>
<div style={{ marginTop: 0, marginBottom: 16, width: this.state.controlWidth, marginLeft: "auto", marginRight: 0, textAlign: "right" }}>
<Button size="small" disabled={!this.state.enabled}
onClick={() => this.onGenerateRandomPin()}
>Generate random pin</Button>
</div>
<div style={{ marginBottom: 16 }}>
<TextField select label="Country" size={this.state.controlSize} value={this.state.countryCode} variant="filled" sx={{ width: this.state.controlWidth }}
disabled={!this.state.enabled}
onChange={(event) => { this.handleCountryChanged(event); }}
>
{Object.entries(this.model.countryCodes).map(([key, value]) => {
return (
<MenuItem value={key}>{value}</MenuItem>
);
})}
</TextField>
</div>
<div style={{ marginBottom: 24 }}>
<TextField select id="channelSelect" size={this.state.controlSize} label="Channel" value={this.state.channel} variant="filled" sx={{ width: this.state.controlWidth }}
disabled={!this.state.enabled}
onChange={(event) => { this.handleChannelChange(event); }}
>
{this.state.wifiChannels.map((channel) => {
let t = channel.channelId;
if (t.startsWith("a")) t = t.substring(1);
if (t.startsWith("g")) t = t.substring(1);
let name = channel.channelName;
if (name.startsWith("1 ") || name.startsWith("6 ") || name.startsWith("11 ")) {
name += " *Recommended";
}
return (
<MenuItem value={t}>{name}</MenuItem>
)
})}
</TextField>
</div>
</DialogContent>
)}
</DialogContent>
<DialogActions> <DialogActions>
<Button onClick={handleClose} color="primary" style={{ width: 120 }}> <Button onClick={handleClose} color="primary" style={{ width: 120 }}>
Cancel Cancel
+1 -1
View File
@@ -55,7 +55,7 @@ export default class WifiDirectConfigSettings {
} else if (!this.enable) { } else if (!this.enable) {
result = "Disabled."; result = "Disabled.";
} else { } else {
result = this.hotspotName; result = "Enabled. (" + this.hotspotName + ")";
} }
if (this.rebootRequired) if (this.rebootRequired)
{ {
+49 -14
View File
@@ -42,13 +42,15 @@ void AvahiService::Announce(
int portNumber, int portNumber,
const std::string &name, const std::string &name,
const std::string &instanceId, const std::string &instanceId,
const std::string &mdnsName) const std::string &mdnsName,
bool addTestGroup)
{ {
Unannounce(); Unannounce();
this->portNumber = portNumber; this->portNumber = portNumber;
this->instanceId = instanceId; this->instanceId = instanceId;
this->mdnsName = mdnsName; this->mdnsName = mdnsName;
this->addTestGroup = addTestGroup;
this->name = avahi_strdup(name.c_str()); this->name = avahi_strdup(name.c_str());
@@ -63,6 +65,9 @@ void AvahiService::Unannounce()
avahi_free(name); avahi_free(name);
this->name = nullptr; this->name = nullptr;
} }
this->group = nullptr;
this->client = nullptr;
this->threadedPoll = nullptr;
} }
void AvahiService::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userData) void AvahiService::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userData)
@@ -87,7 +92,7 @@ void AvahiService::EntryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState s
n = avahi_alternative_service_name(name); n = avahi_alternative_service_name(name);
avahi_free(name); avahi_free(name);
name = n; name = n;
Lv2Log::debug(SS("Service name collision, renaming service to '" << name << "'\n")); Lv2Log::error(SS("Service name collision, renaming service to '" << name << "'\n"));
/* And recreate the services */ /* And recreate the services */
create_group(avahi_entry_group_get_client(g)); create_group(avahi_entry_group_get_client(g));
break; break;
@@ -102,31 +107,32 @@ void AvahiService::EntryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState s
} }
} }
static int toRawDns(char *rawResult, size_t size, const std::string &name)
static int toRawDns(char*rawResult,size_t size, const std::string &name)
{ {
// from standard name format to <nn>xyz<nn>foo<nn>com<00> format // from standard name format to <nn>xyz<nn>foo<nn>com<00> format
size_t len = name.length(); size_t len = name.length();
rawResult[0] = 0; rawResult[0] = 0;
if (len+1 >= size-1) return 0; if (len + 1 >= size - 1)
return 0;
rawResult[len+1] = 0; rawResult[len + 1] = 0;
int count = 0; int count = 0;
for (int i = len-1; i >= 0; --i) for (int i = len - 1; i >= 0; --i)
{ {
if (name[i] == '.') if (name[i] == '.')
{ {
rawResult[i+1] = (char)count; rawResult[i + 1] = (char)count;
count = 0; count = 0;
} else { }
rawResult[i+1] = name[i]; else
{
rawResult[i + 1] = name[i];
++count; ++count;
} }
} }
rawResult[0] = count; rawResult[0] = count;
return len+1; return len + 1;
} }
void AvahiService::create_group(AvahiClient *c) void AvahiService::create_group(AvahiClient *c)
{ {
@@ -149,14 +155,14 @@ void AvahiService::create_group(AvahiClient *c)
{ {
Lv2Log::debug(SS("Adding service '" << name)); Lv2Log::debug(SS("Adding service '" << name));
std::string instanceTxtRecord = SS("pipedal_id=" << this->instanceId); std::string instanceTxtRecord = SS("id=" << this->instanceId);
#define PIPEDAL_SERVICE_TYPE "_pipedal._tcp" #define PIPEDAL_SERVICE_TYPE "_pipedal._tcp"
if ((ret = avahi_entry_group_add_service( if ((ret = avahi_entry_group_add_service(
group, group,
AVAHI_IF_UNSPEC, AVAHI_IF_UNSPEC,
AVAHI_PROTO_INET, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.) AVAHI_PROTO_UNSPEC, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.)
(AvahiPublishFlags)0, (AvahiPublishFlags)0,
name, name,
PIPEDAL_SERVICE_TYPE, PIPEDAL_SERVICE_TYPE,
@@ -174,12 +180,41 @@ void AvahiService::create_group(AvahiClient *c)
goto fail; goto fail;
} }
if (this->addTestGroup)
{
Lv2Log::info("Added tests DNS/SD service.");
std::string instanceTxtRecord = SS("id=" << "0a6045b0-1753-4104-b3e4-b9713b9cc360");
if ((ret = avahi_entry_group_add_service(
group,
AVAHI_IF_UNSPEC,
AVAHI_PROTO_INET, // IPv4 for now, until we figure out why dnsqmasq borks IPv6 routing.)
(AvahiPublishFlags)0,
"Ed's PiPedal",
PIPEDAL_SERVICE_TYPE,
NULL,
NULL,
portNumber,
// txt records.
instanceTxtRecord.c_str(),
NULL)) < 0)
{
if (ret == AVAHI_ERR_COLLISION)
goto collision;
Lv2Log::error(SS("Failed to add _pipedal._tcp service: " << avahi_strerror(ret)));
goto fail;
}
}
/* Tell the server to register the service */ /* Tell the server to register the service */
if ((ret = avahi_entry_group_commit(group)) < 0) if ((ret = avahi_entry_group_commit(group)) < 0)
{ {
Lv2Log::error(SS("Failed to commit entry group: " << avahi_strerror(ret))); Lv2Log::error(SS("Failed to commit entry group: " << avahi_strerror(ret)));
goto fail; goto fail;
} }
Lv2Log::info(SS("DNS/SD service announced."));
} }
return; return;
collision: collision:
+3 -1
View File
@@ -39,7 +39,8 @@ namespace pipedal {
class AvahiService { class AvahiService {
public: public:
~AvahiService() { Unannounce(); } ~AvahiService() { Unannounce(); }
void Announce(int portNumber, const std::string &name, const std::string &instanceId, const std::string&mdnsName); void Announce(
int portNumber, const std::string &name, const std::string &instanceId, const std::string&mdnsName,bool addTestGroup = false);
void Unannounce(); void Unannounce();
@@ -62,6 +63,7 @@ namespace pipedal {
int portNumber = -1; int portNumber = -1;
std::string instanceId; std::string instanceId;
std::string mdnsName; std::string mdnsName;
bool addTestGroup = false;
AvahiClient *client = NULL; AvahiClient *client = NULL;
AvahiEntryGroup *group = NULL; AvahiEntryGroup *group = NULL;
+1
View File
@@ -948,6 +948,7 @@ int main(int argc, char **argv)
settings.valid_ = true; settings.valid_ = true;
settings.enable_ = false; settings.enable_ = false;
SetWifiDirectConfig(settings); SetWifiDirectConfig(settings);
RestartService(true);
} }
else if (enable_ap) else if (enable_ap)
{ {
+20
View File
@@ -18,6 +18,7 @@
// 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.
#include "pch.h" #include "pch.h"
#include "DeviceIdFile.hpp"
#include <sched.h> #include <sched.h>
#include "PiPedalModel.hpp" #include "PiPedalModel.hpp"
#include "JackHost.hpp" #include "JackHost.hpp"
@@ -151,8 +152,10 @@ void PiPedalModel::LoadLv2PluginInfo(const PiPedalConfiguration&configuration)
void PiPedalModel::Load(const PiPedalConfiguration &configuration) void PiPedalModel::Load(const PiPedalConfiguration &configuration)
{ {
this->webRoot = configuration.GetWebRoot(); this->webRoot = configuration.GetWebRoot();
this->webPort = (uint16_t)configuration.GetSocketServerPort();
this->jackServerSettings.ReadJackConfiguration(); this->jackServerSettings.ReadJackConfiguration();
adminClient.MonitorGovernor(storage.GetGovernorSettings()); adminClient.MonitorGovernor(storage.GetGovernorSettings());
// lv2Host.Load(configuration.GetLv2Path().c_str()); // lv2Host.Load(configuration.GetLv2Path().c_str());
@@ -678,6 +681,16 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
delete[] t; delete[] t;
} }
} }
void PiPedalModel::UpdateDnsSd()
{
avahiService.Unannounce();
DeviceIdFile deviceIdFile;
deviceIdFile.Load();
avahiService.Announce(webPort,deviceIdFile.deviceName,deviceIdFile.uuid,"pipedal");
}
void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings) void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings)
{ {
std::lock_guard<std::recursive_mutex> guard(mutex); std::lock_guard<std::recursive_mutex> guard(mutex);
@@ -701,7 +714,14 @@ void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &w
t[i]->OnWifiDirectConfigSettingsChanged(tWifiDirectConfigSettings); t[i]->OnWifiDirectConfigSettingsChanged(tWifiDirectConfigSettings);
} }
delete[] t; delete[] t;
// update NSD-SD announement.
UpdateDnsSd();
} }
} }
WifiConfigSettings PiPedalModel::GetWifiConfigSettings() WifiConfigSettings PiPedalModel::GetWifiConfigSettings()
+8
View File
@@ -35,6 +35,7 @@
#include "WifiConfigSettings.hpp" #include "WifiConfigSettings.hpp"
#include "WifiDirectConfigSettings.hpp" #include "WifiDirectConfigSettings.hpp"
#include "AdminClient.hpp" #include "AdminClient.hpp"
#include "AvahiService.hpp"
@@ -71,6 +72,10 @@ public:
class PiPedalModel: private IJackHostCallbacks { class PiPedalModel: private IJackHostCallbacks {
private: private:
AvahiService avahiService;
uint16_t webPort;
PiPedalAlsaDevices alsaDevices; PiPedalAlsaDevices alsaDevices;
std::recursive_mutex mutex; std::recursive_mutex mutex;
@@ -149,8 +154,11 @@ public:
PiPedalModel(); PiPedalModel();
virtual ~PiPedalModel(); virtual ~PiPedalModel();
void Close(); void Close();
void UpdateDnsSd();
AdminClient&GetAdminClient() { return adminClient; } AdminClient&GetAdminClient() { return adminClient; }
+7
View File
@@ -83,6 +83,11 @@ static std::pair<std::string,PluginType> urisToNames[] {
URI_TO_TYPE_MAP_ENTRY(UtilityPlugin), URI_TO_TYPE_MAP_ENTRY(UtilityPlugin),
URI_TO_TYPE_MAP_ENTRY(WaveshaperPlugin), URI_TO_TYPE_MAP_ENTRY(WaveshaperPlugin),
URI_TO_TYPE_MAP_ENTRY(MIDIPlugin), URI_TO_TYPE_MAP_ENTRY(MIDIPlugin),
// Artificial node in filters plugin that serves as parent of AmplifierPlugin and SimulatorPlugin
{std::string("http://two_play.com/ns/pluginClass#ampsNode"),PluginType::PiPedalAmpsNode }
}; };
PluginType pipedal::uri_to_plugin_type(const std::string&uri) PluginType pipedal::uri_to_plugin_type(const std::string&uri)
@@ -155,6 +160,8 @@ static std::pair<std::string,PluginType> strings_to_type_map[] {
STRING_TO_TYPE_MAP_ENTRY(UtilityPlugin), STRING_TO_TYPE_MAP_ENTRY(UtilityPlugin),
STRING_TO_TYPE_MAP_ENTRY(WaveshaperPlugin), STRING_TO_TYPE_MAP_ENTRY(WaveshaperPlugin),
STRING_TO_TYPE_MAP_ENTRY(MIDIPlugin), STRING_TO_TYPE_MAP_ENTRY(MIDIPlugin),
STRING_TO_TYPE_MAP_ENTRY(MIDIPlugin),
STRING_TO_TYPE_MAP_ENTRY(PiPedalAmpsNode),
}; };
PluginType pipedal::string_to_plugin_type(const std::string&uri) PluginType pipedal::string_to_plugin_type(const std::string&uri)
+2
View File
@@ -71,6 +71,8 @@ enum class PluginType {
UtilityPlugin, UtilityPlugin,
WaveshaperPlugin, WaveshaperPlugin,
MIDIPlugin, MIDIPlugin,
PiPedalAmpsNode, // Pseudo-plugin type used for Amps folder in filter view.
}; };
const std::string &plugin_type_to_uri(PluginType type); const std::string &plugin_type_to_uri(PluginType type);
+12 -11
View File
@@ -499,23 +499,24 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
sysExec("rfkill unblock wlan"); sysExec("rfkill unblock wlan");
sysExec(SYSTEMCTL_BIN " daemon-reload"); sysExec(SYSTEMCTL_BIN " daemon-reload");
sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd");
sysExec(SYSTEMCTL_BIN " restart dnsmasq"); sysExec(SYSTEMCTL_BIN " stop dnsmasq");
sysExec(SYSTEMCTL_BIN " enable dnsmasq"); sysExec(SYSTEMCTL_BIN " stop wpa_supplicant");
sysExec(SYSTEMCTL_BIN " restart dhcpcd"); sysExec(SYSTEMCTL_BIN " restart dhcpcd");
sysExec(SYSTEMCTL_BIN " enable dhcpcd"); sysExec(SYSTEMCTL_BIN " unmask wpa_supplicant");
sysExec(SYSTEMCTL_BIN " start wpa_supplicant");
sysExec(SYSTEMCTL_BIN " enable wpa_supplicant");
sysExec(SYSTEMCTL_BIN " unmask pipedal_p2pd"); sysExec(SYSTEMCTL_BIN " start dnsmasq");
if (sysExec(SYSTEMCTL_BIN " restart pipedal_p2pd") != 0) sysExec(SYSTEMCTL_BIN " enable dnsmasq");
sysExec(SYSTEMCTL_BIN " start pipedal_p2pd");
if (sysExec(SYSTEMCTL_BIN " start pipedal_p2pd") != 0)
{ {
throw PiPedalException("Unable to start the Wi-Fi Direct access point."); throw PiPedalException("Unable to start the Wi-Fi Direct access point.");
} }
sysExec(SYSTEMCTL_BIN " enable pipedal_p2pd"); sysExec(SYSTEMCTL_BIN " enable pipedal_p2pd");
sysExec(SYSTEMCTL_BIN " restart pipedald");
} }
} }
+8
View File
@@ -143,6 +143,14 @@ void WifiDirectConfigSettings::Save() const
} }
void WifiDirectConfigSettings::Load() void WifiDirectConfigSettings::Load()
{ {
this->enable_ = false;
std::string strEnable;
if (ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","enabled",&strEnable))
{
this->enable_ = (strEnable == "true" || strEnable == "1");
}
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_device_name",&this->hotspotName_)) if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_device_name",&this->hotspotName_))
{ {
this->hotspotName_ = "PiPedal"; this->hotspotName_ = "PiPedal";
+4 -9
View File
@@ -504,6 +504,7 @@ int main(int argc, char *argv[])
bool help = false; bool help = false;
bool error = false; bool error = false;
bool systemd = false; bool systemd = false;
bool testExtraDevice = false;
std::string portOption; std::string portOption;
CommandLineParser parser; CommandLineParser parser;
@@ -511,6 +512,7 @@ int main(int argc, char *argv[])
parser.AddOption("--help", &help); parser.AddOption("--help", &help);
parser.AddOption("-systemd", &systemd); parser.AddOption("-systemd", &systemd);
parser.AddOption("-port", &portOption); parser.AddOption("-port", &portOption);
parser.AddOption("-test-extra-device", &testExtraDevice); // advertise two different devices (for testing multi-device connect)
try try
{ {
@@ -700,17 +702,10 @@ int main(int argc, char *argv[])
server->AddRequestHandler(downloadIntercept); server->AddRequestHandler(downloadIntercept);
{ {
// Publish DNS Service.
DeviceIdFile deviceIdFile;
deviceIdFile.Load();
AvahiService service;
service.Announce(
configuration.GetSocketServerPort(),deviceIdFile.deviceName,deviceIdFile.uuid,"pipedal");
server->RunInBackground(SIGUSR1); server->RunInBackground(SIGUSR1);
model.UpdateDnsSd(); // now that the server is running, publish a DNS-SD announcement.
sem_wait(&signalSemaphore); sem_wait(&signalSemaphore);
if (systemd) if (systemd)
+4 -1
View File
@@ -1,13 +1,16 @@
[Unit] [Unit]
Description=PiPedal P2P Session Manager Description=PiPedal P2P Session Manager
After=network.target After=network.target
After=wpa_supplicant.service
After=dhcpcd.service
[Service] [Service]
ExecStart=${COMMAND} --systemd --log-level debug ExecStart=${COMMAND} --systemd --log-level debug
Type=notify Type=notify
WorkingDirectory=/var/pipedal WorkingDirectory=/var/pipedal
TimeoutStopSec=5 TimeoutStopSec=5
Restart=always
RestartSec=5
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
+2
View File
@@ -17,6 +17,8 @@ Group=pipedal_d
Restart=always Restart=always
TimeoutStartSec=60 TimeoutStartSec=60
RestartSec=25 RestartSec=25
TimeoutStopSec=15
WorkingDirectory=/var/pipedal WorkingDirectory=/var/pipedal
Environment=JACK_PROMISCUOUS_SERVER=audio Environment=JACK_PROMISCUOUS_SERVER=audio
Environment=JACK_NO_AUDIO_RESERVATION=1 Environment=JACK_NO_AUDIO_RESERVATION=1