Merge branch 'main'
This commit is contained in:
@@ -4,7 +4,6 @@ project(pipedal
|
|||||||
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.9.11-rc-2")
|
set (DISPLAY_VERSION "v0.9.11-rc-2")
|
||||||
|
|
||||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||||
|
|||||||
Vendored
+2
-2
@@ -3,12 +3,12 @@ Depends: libstdc++6 (>= 9), libasound2 (>= 1.0.16), libc6 (>= 2.34), libgcc-s1 (
|
|||||||
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 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
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Section: sound
|
Section: sound
|
||||||
Version: 0.1.4
|
Version: 0.9.11
|
||||||
Installed-Size: 15147
|
Installed-Size: 15147
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
/usr/local/pipedalconfig --install
|
/usr/bin/pipedalconfig --install
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
/usr/local/pipedalconfig --uninstall
|
/usr/bin/pipedalconfig --uninstall
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Run the following commands to install build tools required by the PiPedal build.
|
|||||||
|
|
||||||
# install CMake
|
# install CMake
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install cmake ninja-build
|
sudo apt install -y cmake ninja-build
|
||||||
|
|
||||||
The PiPedal build process also requires version 12 or later of `node.js`. Type `node --version` to see if you have a version
|
The PiPedal build process also requires version 12 or later of `node.js`. Type `node --version` to see if you have a version
|
||||||
of `node.js` installed already. Otherwise run the following commands as root to install the v14.x lts version of `node.js`:
|
of `node.js` installed already. Otherwise run the following commands as root to install the v14.x lts version of `node.js`:
|
||||||
@@ -22,10 +22,10 @@ with
|
|||||||
Run the following commands to install dependent libraries required by the PiPedal build.
|
Run the following commands to install dependent libraries required by the PiPedal build.
|
||||||
|
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install liblilv-dev libboost-dev jackd2 libjack-jackd2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev catch
|
sudo apt install -y liblilv-dev libboost-dev jackd2 libjack-jackd2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev catch
|
||||||
sudo apt install libasound2-dev jackd2 uuid-dev
|
sudo apt install -y libasound2-dev jackd2 uuid-dev
|
||||||
sudo apt install libwebsocketpp-dev authbind
|
sudo apt install -y libwebsocketpp-dev authbind
|
||||||
sudo apt install libavahi-client-dev
|
sudo apt install -y libavahi-client-dev
|
||||||
|
|
||||||
### Installing Sources
|
### Installing Sources
|
||||||
|
|
||||||
@@ -36,6 +36,12 @@ Clone the rerdavies/pipdal package from github. Use the source control tools fro
|
|||||||
cd ~/src # or whereever you keep your source repositories.
|
cd ~/src # or whereever you keep your source repositories.
|
||||||
git clone https://github.com/rerdavies/pipedal.git
|
git clone https://github.com/rerdavies/pipedal.git
|
||||||
|
|
||||||
|
In the project root, run the following commands to initialze and update pipedal submodules
|
||||||
|
|
||||||
|
cd ~/src/pipedal
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
Run the following command to install and configure React dependencies.
|
Run the following command to install and configure React dependencies.
|
||||||
|
|
||||||
cd ~/src/pipedal
|
cd ~/src/pipedal
|
||||||
|
|||||||
+2
-2
@@ -231,9 +231,9 @@ GEM
|
|||||||
jekyll-seo-tag (~> 2.1)
|
jekyll-seo-tag (~> 2.1)
|
||||||
minitest (5.15.0)
|
minitest (5.15.0)
|
||||||
multipart-post (2.1.1)
|
multipart-post (2.1.1)
|
||||||
nokogiri (1.13.4-aarch64-linux)
|
nokogiri (1.13.6-aarch64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.13.4-x86_64-linux)
|
nokogiri (1.13.6-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
octokit (4.22.0)
|
octokit (4.22.0)
|
||||||
faraday (>= 0.9)
|
faraday (>= 0.9)
|
||||||
|
|||||||
+3
-1
@@ -11,8 +11,10 @@ Install the package by running
|
|||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
cd ~/Downloads
|
cd ~/Downloads
|
||||||
sudo apt-get install ./pipedal_0.9.11_arm64.deb
|
sudo dpkg --install pipedal_0.9.11_arm64.deb
|
||||||
```
|
```
|
||||||
|
On Raspberry Pi OS, if you have a graphical desktop installed, you can also install package by double-clicking on the downloaded package in the File Manager.
|
||||||
|
|
||||||
|
|
||||||
After installing, follow the instructions in [Configuring PiPedal after Installation](Configuring.md).
|
After installing, follow the instructions in [Configuring PiPedal after Installation](Configuring.md).
|
||||||
--------
|
--------
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M14 18.2 7.8 12 14 5.8 15.6 7.4 11 12 15.6 16.6Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 129 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M9.4 18.2 7.8 16.6 12.4 12 7.8 7.4 9.4 5.8 15.6 12Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 132 B |
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"socket_server_port": 8080,
|
"socket_server_port": 80,
|
||||||
"socket_server_address": "*",
|
"socket_server_address": "*",
|
||||||
"debug": true,
|
"debug": true,
|
||||||
"max_upload_size": 1048576,
|
"max_upload_size": 1048576,
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ export interface PluginPresetsChangedHandle {
|
|||||||
|
|
||||||
export interface ZoomedControlInfo {
|
export interface ZoomedControlInfo {
|
||||||
source: HTMLElement;
|
source: HTMLElement;
|
||||||
|
name: string;
|
||||||
instanceId: number;
|
instanceId: number;
|
||||||
uiControl: UiControl;
|
uiControl: UiControl;
|
||||||
}
|
}
|
||||||
@@ -432,6 +433,9 @@ export interface PiPedalModel {
|
|||||||
getAlsaDevices(): Promise<AlsaDeviceInfo[]>;
|
getAlsaDevices(): Promise<AlsaDeviceInfo[]>;
|
||||||
|
|
||||||
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void;
|
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void;
|
||||||
|
|
||||||
|
onPreviousZoomedControl() : void;
|
||||||
|
onNextZoomedControl() : void;
|
||||||
clearZoomedControl(): void;
|
clearZoomedControl(): void;
|
||||||
|
|
||||||
setFavorite(pluginUrl: string, isFavorite: boolean): void;
|
setFavorite(pluginUrl: string, isFavorite: boolean): void;
|
||||||
@@ -2094,8 +2098,92 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void {
|
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void {
|
||||||
this.zoomedUiControl.set({ source: sourceElement, instanceId: instanceId, uiControl: uiControl });
|
let name = uiControl.name;
|
||||||
|
if (uiControl.port_group !== "")
|
||||||
|
{
|
||||||
|
let pedalboard = this.pedalBoard.get();
|
||||||
|
if (pedalboard)
|
||||||
|
{
|
||||||
|
let plugin = pedalboard.getItem(instanceId);
|
||||||
|
let uiPlugin = this.getUiPlugin(plugin.uri);
|
||||||
|
if (uiPlugin)
|
||||||
|
{
|
||||||
|
for (let i = 0; i < uiPlugin.port_groups.length; ++i)
|
||||||
|
{
|
||||||
|
if (uiPlugin.port_groups[i].symbol === uiControl.port_group)
|
||||||
|
{
|
||||||
|
name = uiPlugin.port_groups[i].name + " / " + name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.zoomedUiControl.set({ source: sourceElement, name: name, instanceId: instanceId, uiControl: uiControl });
|
||||||
}
|
}
|
||||||
|
onPreviousZoomedControl() : void
|
||||||
|
{
|
||||||
|
let currentUiControl = this.zoomedUiControl.get();
|
||||||
|
if (!currentUiControl) return;
|
||||||
|
|
||||||
|
let currentSymbol = currentUiControl.uiControl.symbol;
|
||||||
|
|
||||||
|
let pedalboard = this.pedalBoard.get();
|
||||||
|
if (!pedalboard) return;
|
||||||
|
|
||||||
|
let pedalboardItem = pedalboard.getItem(currentUiControl.instanceId);
|
||||||
|
|
||||||
|
let uiPlugin = this.getUiPlugin(pedalboardItem.uri);
|
||||||
|
if (!uiPlugin) return;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
let ix = -1;
|
||||||
|
for (i = 0; i < uiPlugin.controls.length; ++i)
|
||||||
|
{
|
||||||
|
if (uiPlugin.controls[i].symbol === currentSymbol) {
|
||||||
|
ix = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ix === -1) return;
|
||||||
|
|
||||||
|
++ix;
|
||||||
|
if (ix >= uiPlugin.controls.length) return;
|
||||||
|
|
||||||
|
this.zoomUiControl(currentUiControl.source,currentUiControl.instanceId,uiPlugin.controls[ix]);
|
||||||
|
}
|
||||||
|
onNextZoomedControl() : void
|
||||||
|
{
|
||||||
|
let currentUiControl = this.zoomedUiControl.get();
|
||||||
|
if (!currentUiControl) return;
|
||||||
|
|
||||||
|
let currentSymbol = currentUiControl.uiControl.symbol;
|
||||||
|
|
||||||
|
let pedalboard = this.pedalBoard.get();
|
||||||
|
if (!pedalboard) return;
|
||||||
|
|
||||||
|
let pedalboardItem = pedalboard.getItem(currentUiControl.instanceId);
|
||||||
|
|
||||||
|
let uiPlugin = this.getUiPlugin(pedalboardItem.uri);
|
||||||
|
if (!uiPlugin) return;
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
let ix = -1;
|
||||||
|
for (i = 0; i < uiPlugin.controls.length; ++i)
|
||||||
|
{
|
||||||
|
if (uiPlugin.controls[i].symbol === currentSymbol) {
|
||||||
|
ix = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ix === -1) return;
|
||||||
|
|
||||||
|
--ix;
|
||||||
|
if (ix < 0) return;
|
||||||
|
|
||||||
|
this.zoomUiControl(currentUiControl.source,currentUiControl.instanceId,uiPlugin.controls[ix]);
|
||||||
|
}
|
||||||
|
|
||||||
clearZoomedControl(): void {
|
clearZoomedControl(): void {
|
||||||
this.zoomedUiControl.set(undefined);
|
this.zoomedUiControl.set(undefined);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022 Robin Davies
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
// 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
|
// this software and associated documentation files (the "Software"), to deal in
|
||||||
|
|||||||
+170
-51
@@ -17,22 +17,42 @@
|
|||||||
// 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 React, {SyntheticEvent} from 'react';
|
import React, {ReactNode, SyntheticEvent } from 'react';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
import Switch from '@mui/material/Switch';
|
||||||
|
import { UiControl, ScalePoint } from './Lv2Plugin';
|
||||||
import { Theme } from '@mui/material/styles';
|
import { Theme } from '@mui/material/styles';
|
||||||
import { WithStyles,withStyles } from '@mui/styles';
|
import { WithStyles, withStyles } from '@mui/styles';
|
||||||
import createStyles from '@mui/styles/createStyles';
|
import createStyles from '@mui/styles/createStyles';
|
||||||
import { ZoomedControlInfo } from './PiPedalModel';
|
import { ZoomedControlInfo } from './PiPedalModel';
|
||||||
import DialogEx from './DialogEx';
|
import DialogEx from './DialogEx';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { PiPedalModelFactory,PiPedalModel } from './PiPedalModel';
|
import { PiPedalModelFactory, PiPedalModel } from './PiPedalModel';
|
||||||
import ZoomedDial from './ZoomedDial';
|
import ZoomedDial from './ZoomedDial';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import NavigateBeforeIcon from '@mui/icons-material/NavigateBefore';
|
||||||
|
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
|
||||||
|
|
||||||
|
|
||||||
const styles = (theme: Theme) => createStyles({
|
const styles = (theme: Theme) => createStyles({
|
||||||
|
switchTrack: {
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
borderRadius: 14 / 2,
|
||||||
|
zIndex: -1,
|
||||||
|
transition: theme.transitions.create(['opacity', 'background-color'], {
|
||||||
|
duration: theme.transitions.duration.shortest
|
||||||
|
}),
|
||||||
|
backgroundColor: theme.palette.secondary.main,
|
||||||
|
opacity: theme.palette.mode === 'light' ? 0.38 : 0.3
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
interface ZoomedUiControlProps extends WithStyles<typeof styles> {
|
interface ZoomedUiControlProps extends WithStyles<typeof styles> {
|
||||||
|
theme: Theme;
|
||||||
dialogOpen: boolean;
|
dialogOpen: boolean;
|
||||||
onDialogClose: () => void;
|
onDialogClose: () => void;
|
||||||
onDialogClosed: () => void;
|
onDialogClosed: () => void;
|
||||||
@@ -59,8 +79,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
|||||||
|
|
||||||
model: PiPedalModel;
|
model: PiPedalModel;
|
||||||
|
|
||||||
constructor(props: ZoomedUiControlProps)
|
constructor(props: ZoomedUiControlProps) {
|
||||||
{
|
|
||||||
super(props);
|
super(props);
|
||||||
this.model = PiPedalModelFactory.getInstance();
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -69,25 +88,45 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrentValue(): number {
|
getCurrentValue(): number {
|
||||||
if (!this.props.controlInfo)
|
if (!this.props.controlInfo) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
let uiControl = this.props.controlInfo.uiControl;
|
let uiControl = this.props.controlInfo.uiControl;
|
||||||
let instanceId = this.props.controlInfo.instanceId;
|
let instanceId = this.props.controlInfo.instanceId;
|
||||||
if (instanceId === -1) return 0;
|
if (instanceId === -1) return 0;
|
||||||
let pedalBoardItem = this.model.pedalBoard.get()?.getItem(instanceId);
|
let pedalBoardItem = this.model.pedalBoard.get()?.getItem(instanceId);
|
||||||
let value: number = pedalBoardItem?.getControlValue(uiControl.symbol)??0;
|
let value: number = pedalBoardItem?.getControlValue(uiControl.symbol) ?? 0;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasControlChanged(oldProps: ZoomedUiControlProps, newProps: ZoomedUiControlProps)
|
|
||||||
{
|
|
||||||
if (oldProps.controlInfo === null)
|
onSelectChanged(val: string | number) {
|
||||||
{
|
let v = Number.parseFloat(val.toString());
|
||||||
|
this.setState({ value: v });
|
||||||
|
if (this.props.controlInfo) {
|
||||||
|
this.model.setPedalBoardControlValue(
|
||||||
|
this.props.controlInfo.instanceId,
|
||||||
|
this.props.controlInfo.uiControl.symbol,
|
||||||
|
v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCheckChanged(checked: boolean): void {
|
||||||
|
let v = checked ? 1: 0;
|
||||||
|
this.setState({ value: v });
|
||||||
|
if (this.props.controlInfo) {
|
||||||
|
this.model.setPedalBoardControlValue(
|
||||||
|
this.props.controlInfo.instanceId,
|
||||||
|
this.props.controlInfo.uiControl.symbol,
|
||||||
|
v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasControlChanged(oldProps: ZoomedUiControlProps, newProps: ZoomedUiControlProps) {
|
||||||
|
if (oldProps.controlInfo === null) {
|
||||||
return newProps.controlInfo !== null;
|
return newProps.controlInfo !== null;
|
||||||
} else if (newProps.controlInfo === null)
|
} else if (newProps.controlInfo === null) {
|
||||||
{
|
|
||||||
return oldProps.controlInfo !== null;
|
return oldProps.controlInfo !== null;
|
||||||
} else {
|
} else {
|
||||||
if (newProps.controlInfo?.instanceId !== oldProps.controlInfo?.instanceId) return true;
|
if (newProps.controlInfo?.instanceId !== oldProps.controlInfo?.instanceId) return true;
|
||||||
@@ -97,14 +136,11 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(oldProps: ZoomedUiControlProps, oldState: ZoomedUiControlState)
|
componentDidUpdate(oldProps: ZoomedUiControlProps, oldState: ZoomedUiControlState) {
|
||||||
{
|
if (this.hasControlChanged(oldProps, this.props)) {
|
||||||
if (this.hasControlChanged(oldProps,this.props))
|
|
||||||
{
|
|
||||||
let currentValue = this.getCurrentValue();
|
let currentValue = this.getCurrentValue();
|
||||||
if (this.state.value !== currentValue)
|
if (this.state.value !== currentValue) {
|
||||||
{
|
this.setState({ value: this.getCurrentValue() });
|
||||||
this.setState({value: this.getCurrentValue()});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,46 +151,129 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeSelect(control: UiControl, value: number): ReactNode {
|
||||||
|
if (control.isOnOffSwitch()) {
|
||||||
|
// normal gray unchecked state.
|
||||||
|
return (
|
||||||
|
<Switch checked={value !== 0} color="secondary"
|
||||||
|
onChange={(event) => {
|
||||||
|
this.onCheckChanged(event.target.checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (control.isAbToggle()) {
|
||||||
|
// unchecked color is not gray.
|
||||||
|
return (
|
||||||
|
<Switch checked={value !== 0} color="secondary"
|
||||||
|
onChange={(event) => {
|
||||||
|
this.onCheckChanged(event.target.checked);
|
||||||
|
}}
|
||||||
|
classes={{
|
||||||
|
track: this.props.classes.switchTrack
|
||||||
|
}}
|
||||||
|
style={{ color: this.props.theme.palette.secondary.main }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Select variant="standard"
|
||||||
|
value={control.clampSelectValue(value)}
|
||||||
|
onChange={(e)=> this.onSelectChanged(e.target.value)}
|
||||||
|
inputProps={{
|
||||||
|
name: control.name,
|
||||||
|
id: 'id' + control.symbol,
|
||||||
|
style: { fontSize: "1.0em" }
|
||||||
|
}}
|
||||||
|
style={{ marginLeft: 4, marginRight: 4, width: 140 }}
|
||||||
|
>
|
||||||
|
{control.scale_points.map((scale_point: ScalePoint) => (
|
||||||
|
<MenuItem key={scale_point.value} value={scale_point.value}>{scale_point.label}</MenuItem>
|
||||||
|
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let displayValue = this.props.controlInfo?.uiControl.formatDisplayValue(this.state.value)??"";
|
if (!this.props.controlInfo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let uiControl = this.props.controlInfo.uiControl;
|
||||||
|
|
||||||
|
let displayValue = uiControl.formatDisplayValue(this.state.value) ?? "";
|
||||||
|
if (uiControl.isOnOffSwitch())
|
||||||
|
{
|
||||||
|
displayValue = this.state.value !== 0 ? "On": "Off";
|
||||||
|
} else if (uiControl.isSelect())
|
||||||
|
{
|
||||||
|
displayValue = "\u00A0";
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<DialogEx tag="zoomedControlDlg" open={this.props.dialogOpen}
|
<DialogEx tag="zoomedControlDlg" open={this.props.dialogOpen}
|
||||||
onClose={()=> { this.props.onDialogClose()}}
|
onClose={() => { this.props.onDialogClose() }}
|
||||||
onAbort={()=> { this.props.onDialogClose()}}
|
onAbort={() => { this.props.onDialogClose() }}
|
||||||
>
|
>
|
||||||
<div style={{ width: 300, height: 300, background: "#FFF",
|
<div style={{
|
||||||
display: "flex", flexFlow: "column", alignItems: "center", alignContent: "center", justifyContent: "center"
|
width: 380, height: 300, background: "FFFF",
|
||||||
|
display: "flex", flexFlow: "row", alignItems: "center", alignContent: " center", justifyContent: "center"
|
||||||
|
}}>
|
||||||
|
<IconButton sx={{ height: "100%", width: 48, borderRadius: "0% 50% 50% 0%" }} onClick={
|
||||||
|
() => {
|
||||||
|
this.model.onNextZoomedControl();
|
||||||
|
}
|
||||||
|
} >
|
||||||
|
<NavigateBeforeIcon />
|
||||||
|
</IconButton>
|
||||||
|
<div style={{
|
||||||
|
width: 200, flexGrow: 1, height: 300, background: "#FFF",
|
||||||
|
display: "flex", flexFlow: "column", alignItems: "center", alignContent: "center", justifyContent: "center"
|
||||||
|
|
||||||
}}
|
}}
|
||||||
onDrag={this.onDrag}
|
onDrag={this.onDrag}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
display="block" variant="h6" color="textPrimary" style={{textAlign: "center"}}
|
display="block" variant="h6" color="textPrimary" style={{ textAlign: "center" }}
|
||||||
>
|
>
|
||||||
{this.props.controlInfo?.uiControl.name??""}
|
{this.props.controlInfo.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<ZoomedDial size={200} controlInfo={this.props.controlInfo}
|
{uiControl.isDial() ? (
|
||||||
onPreviewValue={(v)=> {
|
|
||||||
this.setState({value: v});
|
<ZoomedDial size={200} controlInfo={this.props.controlInfo}
|
||||||
}}
|
onPreviewValue={(v) => {
|
||||||
onSetValue={(v)=> {
|
this.setState({ value: v });
|
||||||
this.setState({value: v});
|
}}
|
||||||
if (this.props.controlInfo)
|
onSetValue={(v) => {
|
||||||
{
|
this.setState({ value: v });
|
||||||
this.model.setPedalBoardControlValue(
|
if (this.props.controlInfo) {
|
||||||
this.props.controlInfo.instanceId,
|
this.model.setPedalBoardControlValue(
|
||||||
this.props.controlInfo.uiControl.symbol,
|
this.props.controlInfo.instanceId,
|
||||||
v);
|
this.props.controlInfo.uiControl.symbol,
|
||||||
}
|
v);
|
||||||
}}
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
) :
|
||||||
<Typography
|
<div style={{height: 200, paddingTop: 80}}>
|
||||||
display="block" variant="h6" color="textPrimary" style={{textAlign: "center"}}
|
{this.makeSelect(uiControl,this.state.value)}
|
||||||
>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
display="block" variant="h6" color="textPrimary" style={{ textAlign: "center" }}
|
||||||
|
>
|
||||||
{displayValue}
|
{displayValue}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<IconButton sx={{ height: "100%", width: 48, borderRadius: "50% 0% 0% 50%" }}
|
||||||
|
onClick={() => {
|
||||||
|
this.model.onPreviousZoomedControl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<NavigateNextIcon />
|
||||||
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</DialogEx>
|
</DialogEx>
|
||||||
|
|||||||
+4
-7
@@ -64,7 +64,8 @@ bool AdminClient::WriteMessage(const char *message)
|
|||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
Lv2Log::error(SS("Failed to connect to PiPedal Admin service."));
|
// Socket permissions require membership in pipedal_d group.
|
||||||
|
Lv2Log::error(SS("Failed to connect to PiPedal Admin service. " << e.what()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +169,7 @@ void AdminClient::MonitorGovernor(const std::string &governor)
|
|||||||
bool result = WriteMessage(cmd.str().c_str());
|
bool result = WriteMessage(cmd.str().c_str());
|
||||||
if (!result)
|
if (!result)
|
||||||
{ // unexpected. Should throw exception on failure.
|
{ // unexpected. Should throw exception on failure.
|
||||||
throw PiPedalException("Operation failed.");
|
Lv2Log::warning("Not monitoring CPU governor status.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void AdminClient::UnmonitorGovernor()
|
void AdminClient::UnmonitorGovernor()
|
||||||
@@ -180,9 +181,5 @@ void AdminClient::UnmonitorGovernor()
|
|||||||
std::stringstream cmd;
|
std::stringstream cmd;
|
||||||
cmd << "UnmonitorGovernor";
|
cmd << "UnmonitorGovernor";
|
||||||
cmd << '\n';
|
cmd << '\n';
|
||||||
bool result = WriteMessage(cmd.str().c_str());
|
bool ignored = WriteMessage(cmd.str().c_str());
|
||||||
if (!result)
|
|
||||||
{ // unexpected. Should throw exception on failure.
|
|
||||||
throw PiPedalException("Operation failed.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,6 @@ set (USE_PCH 1)
|
|||||||
include(FindPkgConfig)
|
include(FindPkgConfig)
|
||||||
|
|
||||||
|
|
||||||
# apt install libsdbus-c++-dev
|
|
||||||
# apt install libsdbus-c++-bin
|
|
||||||
find_package(sdbus-c++ REQUIRED)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Can't get the pkg_check to work.
|
# Can't get the pkg_check to work.
|
||||||
# pkg_check_modules(LIBNL3 "nl-genl-3")
|
# pkg_check_modules(LIBNL3 "nl-genl-3")
|
||||||
|
|||||||
+30
-11
@@ -75,7 +75,7 @@ using namespace pipedal;
|
|||||||
#define PIPEDAL_P2PD_SERVICE "pipedal_p2pd"
|
#define PIPEDAL_P2PD_SERVICE "pipedal_p2pd"
|
||||||
#define JACK_SERVICE "jack"
|
#define JACK_SERVICE "jack"
|
||||||
|
|
||||||
#define REMOVE_OLD_SERVICE 1 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind)
|
#define REMOVE_OLD_SERVICE 0 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind)
|
||||||
#define OLD_SHUTDOWN_SERVICE "pipedalshutdownd"
|
#define OLD_SHUTDOWN_SERVICE "pipedalshutdownd"
|
||||||
|
|
||||||
std::filesystem::path GetServiceFileName(const std::string &serviceName)
|
std::filesystem::path GetServiceFileName(const std::string &serviceName)
|
||||||
@@ -112,11 +112,11 @@ void EnableService()
|
|||||||
{
|
{
|
||||||
if (sysExec(SYSTEMCTL_BIN " enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to enable the " NATIVE_SERVICE " service.";
|
cout << "Error: Failed to enable the " NATIVE_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
if (sysExec(SYSTEMCTL_BIN " enable " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " enable " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to enable the " ADMIN_SERVICE " service.";
|
cout << "Error: Failed to enable the " ADMIN_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void DisableService()
|
void DisableService()
|
||||||
@@ -131,16 +131,16 @@ void DisableService()
|
|||||||
#endif
|
#endif
|
||||||
if (sysExec(SYSTEMCTL_BIN " disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to disable the " NATIVE_SERVICE " service.";
|
cout << "Error: Failed to disable the " NATIVE_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
if (sysExec(SYSTEMCTL_BIN " disable " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " disable " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to disable the " ADMIN_SERVICE " service.";
|
cout << "Error: Failed to disable the " ADMIN_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
#if REMOVE_OLD_SERVICE
|
#if REMOVE_OLD_SERVICE
|
||||||
if (sysExec(SYSTEMCTL_BIN " disable " OLD_SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " disable " OLD_SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to disable the " OLD_SHUTDOWN_SERVICE " service.";
|
cout << "Error: Failed to disable the " OLD_SHUTDOWN_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -149,18 +149,18 @@ void StopService(bool excludeShutdownService = false)
|
|||||||
{
|
{
|
||||||
if (sysExec(SYSTEMCTL_BIN " stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to stop the " NATIVE_SERVICE " service.";
|
cout << "Error: Failed to stop the " NATIVE_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
if (!excludeShutdownService)
|
if (!excludeShutdownService)
|
||||||
{
|
{
|
||||||
if (sysExec(SYSTEMCTL_BIN " stop " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " stop " ADMIN_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to stop the " ADMIN_SERVICE " service.";
|
cout << "Error: Failed to stop the " ADMIN_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
#if REMOVE_OLD_SERVICE
|
#if REMOVE_OLD_SERVICE
|
||||||
if (sysExec(SYSTEMCTL_BIN " stop " OLD_SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " stop " OLD_SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
cout << "Error: Failed to stop the " OLD_SHUTDOWN_SERVICE " service.";
|
cout << "Error: Failed to stop the " OLD_SHUTDOWN_SERVICE " service.\n";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ void StopService(bool excludeShutdownService = false)
|
|||||||
if (sysExec(SYSTEMCTL_BIN " stop " JACK_SERVICE ".service") != EXIT_SUCCESS)
|
if (sysExec(SYSTEMCTL_BIN " stop " JACK_SERVICE ".service") != EXIT_SUCCESS)
|
||||||
{
|
{
|
||||||
#if INSTALL_JACK_SERVICE
|
#if INSTALL_JACK_SERVICE
|
||||||
throw PiPedalException("Failed to stop the " JACK_SERVICE " service.");
|
cout << PiPedalException("Failed to stop the " JACK_SERVICE " service.");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -551,9 +551,24 @@ static void PrepareDeviceidFile()
|
|||||||
{
|
{
|
||||||
DeviceIdFile deviceIdFile;
|
DeviceIdFile deviceIdFile;
|
||||||
|
|
||||||
deviceIdFile.deviceName = "PiPedal-" + RandomChars(2);
|
deviceIdFile.deviceName = "PiPedal";
|
||||||
deviceIdFile.uuid = MakeUuid();
|
deviceIdFile.uuid = MakeUuid();
|
||||||
deviceIdFile.Save();
|
deviceIdFile.Save();
|
||||||
|
} else {
|
||||||
|
DeviceIdFile deviceIdFile;
|
||||||
|
if (deviceIdFile.deviceName == "" || deviceIdFile.uuid == "")
|
||||||
|
{
|
||||||
|
if (deviceIdFile.deviceName == "")
|
||||||
|
{
|
||||||
|
deviceIdFile.deviceName = "PiPedal";
|
||||||
|
}
|
||||||
|
if (deviceIdFile.uuid == "")
|
||||||
|
{
|
||||||
|
deviceIdFile.uuid = MakeUuid();
|
||||||
|
}
|
||||||
|
deviceIdFile.Save();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,6 +578,10 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
|||||||
{
|
{
|
||||||
throw PiPedalException("Failed to create audio service group.");
|
throw PiPedalException("Failed to create audio service group.");
|
||||||
}
|
}
|
||||||
|
if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
|
||||||
|
{
|
||||||
|
throw PiPedalException("Failed to create pipedald service group.");
|
||||||
|
}
|
||||||
|
|
||||||
PrepareDeviceidFile();
|
PrepareDeviceidFile();
|
||||||
InstallJackService();
|
InstallJackService();
|
||||||
|
|||||||
+9
-10
@@ -39,16 +39,16 @@ const char DeviceIdFile::DEVICEID_FILE_NAME[] = "/etc/pipedal/config/device_uuid
|
|||||||
|
|
||||||
void DeviceIdFile::Load()
|
void DeviceIdFile::Load()
|
||||||
{
|
{
|
||||||
ifstream f;
|
|
||||||
|
|
||||||
f.open(DEVICEID_FILE_NAME);
|
|
||||||
if (!f.is_open())
|
|
||||||
{
|
{
|
||||||
throw invalid_argument("Can't open file " + std::string(DEVICEID_FILE_NAME));
|
ifstream f;
|
||||||
}
|
|
||||||
|
|
||||||
std::getline(f, uuid);
|
f.open(DEVICEID_FILE_NAME);
|
||||||
std::getline(f, deviceName);
|
if (f.is_open())
|
||||||
|
{
|
||||||
|
std::getline(f, uuid);
|
||||||
|
std::getline(f, deviceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void DeviceIdFile::Save()
|
void DeviceIdFile::Save()
|
||||||
{
|
{
|
||||||
@@ -67,10 +67,9 @@ void DeviceIdFile::Save()
|
|||||||
{
|
{
|
||||||
throw logic_error("Group not found: pipedal_d");
|
throw logic_error("Group not found: pipedal_d");
|
||||||
}
|
}
|
||||||
std::ignore = chown(path.c_str(),-1,group_->gr_gid);
|
std::ignore = chown(path.c_str(), -1, group_->gr_gid);
|
||||||
std::ignore = chmod(path.c_str(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
|
std::ignore = chmod(path.c_str(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
|
||||||
|
|
||||||
f << uuid << endl;
|
f << uuid << endl;
|
||||||
f << deviceName << endl;
|
f << deviceName << endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,9 @@ void JackConfiguration::JackInitialize()
|
|||||||
|
|
||||||
AddPorts(client, &this->inputAudioPorts_, "system", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput);
|
AddPorts(client, &this->inputAudioPorts_, "system", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput);
|
||||||
AddPorts(client, &this->outputAudioPorts_, "system", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
|
AddPorts(client, &this->outputAudioPorts_, "system", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
|
||||||
isValid_ = true;
|
AddPorts(client, &this->inputMidiPorts_, "system", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput);
|
||||||
|
AddPorts(client, &this->outputMidiPorts_, "system", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput);
|
||||||
|
isValid_ = (this->inputAudioPorts_.size() > 0 && this->outputAudioPorts_.size() > 0);
|
||||||
this->errorStatus_ = "";
|
this->errorStatus_ = "";
|
||||||
jack_client_close(client);
|
jack_client_close(client);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -704,7 +704,15 @@ void PiPedalModel::UpdateDnsSd()
|
|||||||
|
|
||||||
DeviceIdFile deviceIdFile;
|
DeviceIdFile deviceIdFile;
|
||||||
deviceIdFile.Load();
|
deviceIdFile.Load();
|
||||||
avahiService.Announce(webPort,deviceIdFile.deviceName,deviceIdFile.uuid,"pipedal");
|
if (deviceIdFile.deviceName != "" && deviceIdFile.uuid != "")
|
||||||
|
{
|
||||||
|
avahiService.Announce(webPort,deviceIdFile.deviceName,deviceIdFile.uuid,"pipedal");
|
||||||
|
} else {
|
||||||
|
// device_uuid file is written at install time. This warning is harmless if you're debugging.
|
||||||
|
// Without it, we can't pulblish the website via dnsDS.
|
||||||
|
// Run "pipedalconfig --install" to create the file.
|
||||||
|
Lv2Log::warning("Cant read device_uuid file. dnsSD announcement skipped.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings)
|
void PiPedalModel::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings)
|
||||||
|
|||||||
@@ -488,7 +488,8 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
|||||||
|
|
||||||
dhcpcd.InsertLine(line++, "interface p2p-wlan0-0");
|
dhcpcd.InsertLine(line++, "interface p2p-wlan0-0");
|
||||||
dhcpcd.InsertLine(line++, " static ip_address=" P2P_INTERFACE_ADDR);
|
dhcpcd.InsertLine(line++, " static ip_address=" P2P_INTERFACE_ADDR);
|
||||||
dhcpcd.InsertLine(line++, " domain_name_servers=" P2P_IP_ADDRESS);
|
dhcpcd.InsertLine(line++, " nohook wpa_supplicant");
|
||||||
|
//dhcpcd.InsertLine(line++, " domain_name_servers=" P2P_IP_ADDRESS);
|
||||||
dhcpcd.Save(dhcpcdConfig);
|
dhcpcd.Save(dhcpcdConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -425,12 +425,18 @@ public:
|
|||||||
}
|
}
|
||||||
std::string GetConfig(const std::string &fromAddress)
|
std::string GetConfig(const std::string &fromAddress)
|
||||||
{
|
{
|
||||||
std::string linkLocalAddress = GetLinkLocalAddress(fromAddress);
|
#define LINK_LOCAL_WEB_SOCKET 1
|
||||||
|
#if LINK_LOCAL_WEB_SOCKET
|
||||||
|
std::string webSocketAddress = GetLinkLocalAddress(fromAddress);
|
||||||
|
Lv2Log::info(SS("Web Socket Adddress: " << webSocketAddress << ":" << portNumber));
|
||||||
|
#else
|
||||||
|
std::string webSocketAddress = "*";
|
||||||
|
#endif
|
||||||
|
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
|
|
||||||
s << "{ \"socket_server_port\": " << portNumber
|
s << "{ \"socket_server_port\": " << portNumber
|
||||||
<< ", \"socket_server_address\": \"" << linkLocalAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
<< ", \"socket_server_address\": \"" << webSocketAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||||
|
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user