+2
-2
@@ -1,10 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.16.0)
|
cmake_minimum_required(VERSION 3.16.0)
|
||||||
project(pipedal
|
project(pipedal
|
||||||
VERSION 1.2.33
|
VERSION 1.2.34
|
||||||
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
||||||
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
||||||
)
|
)
|
||||||
set (DISPLAY_VERSION "v1.2.31beta1")
|
set (DISPLAY_VERSION "v1.2.34beta2")
|
||||||
|
|
||||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
<img src='docs/GithubBanner.png' width="100%" /><br/>
|
<img src='docs/GithubBanner.png' width="100%" /><br/>
|
||||||
|
|
||||||
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.2.33 Beta1</a>
|
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.2.34 Beta1</a>
|
||||||
|
|
||||||
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
|
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
|
||||||
|
|
||||||
|
|
||||||
> NEW version 1.2.33 beta1 release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
|
> NEW version 1.2.34 beta2 release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
|
||||||
|
|
||||||
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
|
Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet.
|
||||||
PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
|
PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats.
|
||||||
|
|||||||
+3
-3
@@ -4,17 +4,17 @@
|
|||||||
|
|
||||||
Download the most recent Debian (.deb) package for your platform:
|
Download the most recent Debian (.deb) package for your platform:
|
||||||
|
|
||||||
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.2.33/pipedal_1.2.33_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.2.33 Beta1</a>
|
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.2.34/pipedal_1.2.34_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.2.34 Beta2</a>
|
||||||
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb">Ubuntu 21.04 or Raspberry Pi OS Buster (64-bit) v1.1.31</a>
|
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb">Ubuntu 21.04 or Raspberry Pi OS Buster (64-bit) v1.1.31</a>
|
||||||
|
|
||||||
v1.2.33 Beta1 is does not currently support Ubuntu 21.04, or older versions of Raspberry Pi OS.
|
v1.2.34 Beta1 is does not currently support Ubuntu 21.04, or older versions of Raspberry Pi OS.
|
||||||
|
|
||||||
Install the package by running
|
Install the package by running
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
cd ~/Downloads
|
cd ~/Downloads
|
||||||
sudo apt-get install ./pipedal_1.2.33_arm64.deb
|
sudo apt-get install ./pipedal_1.2.34_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.
|
||||||
|
|||||||
@@ -29,13 +29,14 @@ import IControlViewFactory from './IControlViewFactory';
|
|||||||
import { GxTunerViewFactory } from './GxTunerView';
|
import { GxTunerViewFactory } from './GxTunerView';
|
||||||
import ToobPowerstage2ViewFactory from './ToobPowerStage2View';
|
import ToobPowerstage2ViewFactory from './ToobPowerStage2View';
|
||||||
import ToobSpectrumAnalyzerViewFactory from './ToobSpectrumAnalyzerView';
|
import ToobSpectrumAnalyzerViewFactory from './ToobSpectrumAnalyzerView';
|
||||||
// import ToobMLViewFactory from './ToobMLView';
|
import ToobMLViewFactory from './ToobMLView';
|
||||||
|
|
||||||
|
|
||||||
let pluginFactories: IControlViewFactory[] = [
|
let pluginFactories: IControlViewFactory[] = [
|
||||||
new GxTunerViewFactory(),
|
new GxTunerViewFactory(),
|
||||||
new ToobPowerstage2ViewFactory(),
|
new ToobPowerstage2ViewFactory(),
|
||||||
new ToobSpectrumAnalyzerViewFactory(),
|
new ToobSpectrumAnalyzerViewFactory(),
|
||||||
//new ToobMLViewFactory()
|
new ToobMLViewFactory()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+145
-3
@@ -506,7 +506,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
this.controlType = ControlType.Vu;
|
this.controlType = ControlType.Vu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (this.isValidEnumeration())
|
if (this.isValidEnumeration())
|
||||||
{
|
{
|
||||||
this.controlType = ControlType.Select;
|
this.controlType = ControlType.Select;
|
||||||
if (this.scale_points.length === 2)
|
if (this.scale_points.length === 2)
|
||||||
@@ -520,7 +520,10 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
}
|
||||||
|
applyProperties(properties: Partial<UiControl>): UiControl
|
||||||
|
{
|
||||||
|
return {...this,...properties};
|
||||||
}
|
}
|
||||||
private hasScalePoint(value: number): boolean {
|
private hasScalePoint(value: number): boolean {
|
||||||
for (let scale_point of this.scale_points)
|
for (let scale_point of this.scale_points)
|
||||||
@@ -726,7 +729,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
text += "s";
|
text += "s";
|
||||||
break;
|
break;
|
||||||
// Midinote: not handled.
|
// Midinote: not handled.
|
||||||
// semitone12TET not handled.
|
// semitone12TET not handled.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -759,6 +762,7 @@ export class UiControl implements Deserializable<UiControl> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class UiPlugin implements Deserializable<UiPlugin> {
|
export class UiPlugin implements Deserializable<UiPlugin> {
|
||||||
deserialize(input: any): UiPlugin
|
deserialize(input: any): UiPlugin
|
||||||
{
|
{
|
||||||
@@ -802,6 +806,11 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSplit(): boolean {
|
||||||
|
return this.uri === "uri://two-play/pipedal/pedalboard#Split";
|
||||||
|
|
||||||
|
}
|
||||||
getControl(key: string): UiControl | undefined {
|
getControl(key: string): UiControl | undefined {
|
||||||
for (let i = 0; i < this.controls.length; ++i)
|
for (let i = 0; i < this.controls.length; ++i)
|
||||||
{
|
{
|
||||||
@@ -860,3 +869,136 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
|||||||
is_vst3 : boolean = false;
|
is_vst3 : boolean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function makeSplitUiPlugin(): UiPlugin
|
||||||
|
{
|
||||||
|
|
||||||
|
return new UiPlugin().deserialize({
|
||||||
|
uri: "uri://two-play/pipedal/pedalboard#Split",
|
||||||
|
name: "Split",
|
||||||
|
brand: "",
|
||||||
|
label: "",
|
||||||
|
plugin_type: PluginType.SplitA,
|
||||||
|
plugin_display_type: "Split",
|
||||||
|
author_name: "",
|
||||||
|
author_homepage: "",
|
||||||
|
audio_inputs: 1,
|
||||||
|
audio_outputs: 1,
|
||||||
|
has_midi_input: 0,
|
||||||
|
has_midi_output: 0,
|
||||||
|
description: "",
|
||||||
|
controls: [
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "splitType",
|
||||||
|
name: "Type",
|
||||||
|
index: 0,
|
||||||
|
is_input: true,
|
||||||
|
min_value: 0.0,
|
||||||
|
max_value: 2.0,
|
||||||
|
enumeration_property: true,
|
||||||
|
scale_points: [
|
||||||
|
new ScalePoint().deserialize({value: 0, label: "A/B"}),
|
||||||
|
new ScalePoint().deserialize({value: 1, label: "mix"}),
|
||||||
|
new ScalePoint().deserialize({value: 1, label: "L/R"}),
|
||||||
|
],
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
|
||||||
|
}) ,
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "select",
|
||||||
|
name: "Select",
|
||||||
|
index: 1,
|
||||||
|
is_input: true,
|
||||||
|
min_value: 0.0,
|
||||||
|
max_value: 1.0,
|
||||||
|
enumeration_property: true,
|
||||||
|
scale_points: [
|
||||||
|
new ScalePoint().deserialize({value: 0, label: "A"}),
|
||||||
|
new ScalePoint().deserialize({value: 1, label: "B"}),
|
||||||
|
],
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
|
||||||
|
}) ,
|
||||||
|
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "mix",
|
||||||
|
name: "Mix",
|
||||||
|
index: 2,
|
||||||
|
is_input: true,
|
||||||
|
min_value: -1.0,
|
||||||
|
max_value: 1.0,
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
|
||||||
|
}) ,
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "panL",
|
||||||
|
name: "Pan Top",
|
||||||
|
index: 3,
|
||||||
|
is_input: true,
|
||||||
|
min_value: -1.0,
|
||||||
|
max_value: 1.0,
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
|
||||||
|
}) ,
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "volL",
|
||||||
|
name: "Vol Top",
|
||||||
|
index: 4,
|
||||||
|
is_input: true,
|
||||||
|
min_value: -60.0,
|
||||||
|
max_value: 12.0,
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
|
||||||
|
}) ,
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "panR",
|
||||||
|
name: "Pan Bottom",
|
||||||
|
index: 5,
|
||||||
|
is_input: true,
|
||||||
|
min_value: -1.0,
|
||||||
|
max_value: 1.0,
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
|
||||||
|
}) ,
|
||||||
|
new UiControl().applyProperties({
|
||||||
|
symbol: "volR",
|
||||||
|
name: "Vol Bottom",
|
||||||
|
index: 6,
|
||||||
|
is_input: true,
|
||||||
|
min_value: -60.0,
|
||||||
|
max_value: 12.0,
|
||||||
|
is_bypass: false,
|
||||||
|
is_program_controller: false,
|
||||||
|
custom_units: "",
|
||||||
|
connection_optional: false,
|
||||||
|
})
|
||||||
|
],
|
||||||
|
port_groups: [],
|
||||||
|
fileProperties: [],
|
||||||
|
frequencyPlots: [],
|
||||||
|
is_vst3 : false,
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import MicNoneOutlinedIcon from '@mui/icons-material/MicNoneOutlined';
|
|||||||
import MicOutlinedIcon from '@mui/icons-material/MicOutlined';
|
import MicOutlinedIcon from '@mui/icons-material/MicOutlined';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import NumericInput from './NumericInput';
|
import NumericInput from './NumericInput';
|
||||||
|
import { UiPlugin } from './Lv2Plugin';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ interface MidiBindingViewProps extends WithStyles<typeof styles> {
|
|||||||
instanceId: number;
|
instanceId: number;
|
||||||
listen: boolean;
|
listen: boolean;
|
||||||
midiBinding: MidiBinding;
|
midiBinding: MidiBinding;
|
||||||
|
uiPlugin: UiPlugin;
|
||||||
onChange: (instanceId: number, newBinding: MidiBinding) => void;
|
onChange: (instanceId: number, newBinding: MidiBinding) => void;
|
||||||
onListen: (instanceId: number, key: string, listenForControl: boolean) => void;
|
onListen: (instanceId: number, key: string, listenForControl: boolean) => void;
|
||||||
}
|
}
|
||||||
@@ -139,8 +141,7 @@ const MidiBindingView =
|
|||||||
render() {
|
render() {
|
||||||
let classes = this.props.classes;
|
let classes = this.props.classes;
|
||||||
let midiBinding = this.props.midiBinding;
|
let midiBinding = this.props.midiBinding;
|
||||||
let pedalboardItem = this.model.pedalboard.get().getItem(this.props.instanceId);
|
let uiPlugin = this.props.uiPlugin;
|
||||||
let uiPlugin = this.model.getUiPlugin(pedalboardItem.uri);
|
|
||||||
if (!uiPlugin) {
|
if (!uiPlugin) {
|
||||||
return (<div />);
|
return (<div />);
|
||||||
}
|
}
|
||||||
@@ -258,7 +259,11 @@ const MidiBindingView =
|
|||||||
value={midiBinding.switchControlType}
|
value={midiBinding.switchControlType}
|
||||||
>
|
>
|
||||||
<MenuItem value={MidiBinding.LATCH_CONTROL_TYPE}>Toggle</MenuItem>
|
<MenuItem value={MidiBinding.LATCH_CONTROL_TYPE}>Toggle</MenuItem>
|
||||||
<MenuItem value={MidiBinding.MOMENTARY_CONTROL_TYPE}>Momentary</MenuItem>
|
<MenuItem value={MidiBinding.MOMENTARY_CONTROL_TYPE}>{
|
||||||
|
(midiBinding.bindingType === MidiBinding.BINDING_TYPE_NOTE) ?
|
||||||
|
"Note on/off"
|
||||||
|
: "Control value"
|
||||||
|
}</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import IconButton from '@mui/material/IconButton';
|
|||||||
import MidiBinding from './MidiBinding';
|
import MidiBinding from './MidiBinding';
|
||||||
import MidiBindingView from './MidiBindingView';
|
import MidiBindingView from './MidiBindingView';
|
||||||
import Snackbar from '@mui/material/Snackbar';
|
import Snackbar from '@mui/material/Snackbar';
|
||||||
|
import { UiPlugin,makeSplitUiPlugin } from './Lv2Plugin';
|
||||||
|
|
||||||
const styles = (theme: Theme) => createStyles({
|
const styles = (theme: Theme) => createStyles({
|
||||||
dialogAppBar: {
|
dialogAppBar: {
|
||||||
@@ -62,6 +63,10 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function not_null<T>(value: T | null) {
|
||||||
|
if (!value) throw Error("Unexpected null value");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MidiBindingDialogProps extends WithStyles<typeof styles> {
|
export interface MidiBindingDialogProps extends WithStyles<typeof styles> {
|
||||||
open: boolean,
|
open: boolean,
|
||||||
@@ -189,7 +194,43 @@ export const MidiBindingDialog =
|
|||||||
let item = v.value;
|
let item = v.value;
|
||||||
|
|
||||||
|
|
||||||
let plugin = this.model.getUiPlugin(item.uri);
|
let isSplit = item.uri === "uri://two-play/pipedal/pedalboard#Split";
|
||||||
|
let plugin : UiPlugin | null = this.model.getUiPlugin(item.uri);
|
||||||
|
if (plugin === null && isSplit)
|
||||||
|
{
|
||||||
|
plugin = makeSplitUiPlugin();
|
||||||
|
let splitType = item.getControlValue("splitType");
|
||||||
|
not_null(plugin.getControl("splitType")).not_on_gui = true;
|
||||||
|
switch (splitType)
|
||||||
|
{
|
||||||
|
case 0: // A/B
|
||||||
|
not_null(plugin.getControl("select")).not_on_gui = false;
|
||||||
|
not_null(plugin.getControl("mix")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("volL")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("panL")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("volR")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("panR")).not_on_gui = true;
|
||||||
|
break;
|
||||||
|
case 1: //mixer
|
||||||
|
not_null(plugin.getControl("select")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("mix")).not_on_gui = false;
|
||||||
|
not_null(plugin.getControl("volL")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("panL")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("volR")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("panR")).not_on_gui = true;
|
||||||
|
break;
|
||||||
|
case 2: // L/R
|
||||||
|
not_null(plugin.getControl("select")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("mix")).not_on_gui = true;
|
||||||
|
not_null(plugin.getControl("volL")).not_on_gui = false;
|
||||||
|
not_null(plugin.getControl("panL")).not_on_gui = false;
|
||||||
|
not_null(plugin.getControl("volR")).not_on_gui = false;
|
||||||
|
not_null(plugin.getControl("panR")).not_on_gui = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xxx
|
||||||
|
}
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
result.push(
|
result.push(
|
||||||
<tr>
|
<tr>
|
||||||
@@ -200,29 +241,33 @@ export const MidiBindingDialog =
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
result.push(
|
if (!isSplit)
|
||||||
<tr>
|
{
|
||||||
<td className={classes.nameTd}>
|
result.push(
|
||||||
<Typography noWrap style={{ verticalAlign: "center", height: 48 }}>
|
<tr>
|
||||||
Bypass
|
<td className={classes.nameTd}>
|
||||||
</Typography>
|
<Typography noWrap style={{ verticalAlign: "center", height: 48 }}>
|
||||||
</td>
|
Bypass
|
||||||
<td className={classes.bindingTd}>
|
</Typography>
|
||||||
<MidiBindingView instanceId={item.instanceId} midiBinding={item.getMidiBinding("__bypass")}
|
</td>
|
||||||
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
<td className={classes.bindingTd}>
|
||||||
if (instanceId === -2)
|
<MidiBindingView instanceId={item.instanceId} midiBinding={item.getMidiBinding("__bypass")}
|
||||||
{
|
uiPlugin={plugin}
|
||||||
this.cancelListenForControl();
|
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
||||||
} else {
|
if (instanceId === -2)
|
||||||
this.handleListenForControl(instanceId, symbol, listenForControl);
|
{
|
||||||
}
|
this.cancelListenForControl();
|
||||||
}}
|
} else {
|
||||||
listen={item.instanceId === this.state.listenInstanceId && this.state.listenSymbol === "__bypass"}
|
this.handleListenForControl(instanceId, symbol, listenForControl);
|
||||||
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
|
}
|
||||||
/>
|
}}
|
||||||
</td>
|
listen={item.instanceId === this.state.listenInstanceId && this.state.listenSymbol === "__bypass"}
|
||||||
</tr>
|
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
|
||||||
);
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < plugin.controls.length; ++i) {
|
for (let i = 0; i < plugin.controls.length; ++i) {
|
||||||
let control = plugin.controls[i];
|
let control = plugin.controls[i];
|
||||||
@@ -244,6 +289,7 @@ export const MidiBindingDialog =
|
|||||||
</td>
|
</td>
|
||||||
<td className={classes.bindingTd}>
|
<td className={classes.bindingTd}>
|
||||||
<MidiBindingView instanceId={item.instanceId}
|
<MidiBindingView instanceId={item.instanceId}
|
||||||
|
uiPlugin={plugin}
|
||||||
midiBinding={item.getMidiBinding(symbol)}
|
midiBinding={item.getMidiBinding(symbol)}
|
||||||
listen={item.instanceId === this.state.listenInstanceId && this.state.listenSymbol === symbol}
|
listen={item.instanceId === this.state.listenInstanceId && this.state.listenSymbol === symbol}
|
||||||
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
||||||
|
|||||||
@@ -367,12 +367,14 @@ const PedalboardView =
|
|||||||
|
|
||||||
frameRef: React.RefObject<HTMLDivElement>;
|
frameRef: React.RefObject<HTMLDivElement>;
|
||||||
scrollRef: React.RefObject<HTMLDivElement>;
|
scrollRef: React.RefObject<HTMLDivElement>;
|
||||||
|
private bgColor: string;
|
||||||
|
|
||||||
constructor(props: PedalboardProps) {
|
constructor(props: PedalboardProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.model = PiPedalModelFactory.getInstance();
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
|
|
||||||
|
this.bgColor = props.theme.palette.background.default
|
||||||
|
|
||||||
if (!props.selectedId) props.selectedId = -1;
|
if (!props.selectedId) props.selectedId = -1;
|
||||||
this.state = {
|
this.state = {
|
||||||
pedalboard: this.model.pedalboard.get(),
|
pedalboard: this.model.pedalboard.get(),
|
||||||
@@ -692,6 +694,7 @@ const PedalboardView =
|
|||||||
let y_ = item.bounds.y + CELL_HEIGHT / 2;
|
let y_ = item.bounds.y + CELL_HEIGHT / 2;
|
||||||
let numberOfOutputs = item.numberOfOutputs;
|
let numberOfOutputs = item.numberOfOutputs;
|
||||||
let color = enabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR;
|
let color = enabled ? ENABLED_CONNECTOR_COLOR : DISABLED_CONNECTOR_COLOR;
|
||||||
|
let stereoCenterColor = this.bgColor;
|
||||||
let svgPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_ + CELL_WIDTH, y_).toString();
|
let svgPath = new SvgPathBuilder().moveTo(x_, y_).lineTo(x_ + CELL_WIDTH, y_).toString();
|
||||||
|
|
||||||
if (numberOfOutputs === 2) {
|
if (numberOfOutputs === 2) {
|
||||||
@@ -699,7 +702,7 @@ const PedalboardView =
|
|||||||
<path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={svgPath} stroke={color} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
output.push((
|
output.push((
|
||||||
<path key={this.renderKey++} d={svgPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={svgPath} stroke={stereoCenterColor} strokeWidth={SVG_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
} else if (numberOfOutputs === 1) {
|
} else if (numberOfOutputs === 1) {
|
||||||
output.push((
|
output.push((
|
||||||
@@ -727,14 +730,14 @@ const PedalboardView =
|
|||||||
|
|
||||||
if (item.numberOfInputs === 2 && item.topChildren[0].numberOfInputs === 2) {
|
if (item.numberOfInputs === 2 && item.topChildren[0].numberOfInputs === 2) {
|
||||||
output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />));
|
output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />));
|
||||||
output.push((<path key={this.renderKey++} d={topStartPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />));
|
output.push((<path key={this.renderKey++} d={topStartPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />));
|
||||||
} else if (item.numberOfInputs !== 0 && item.topChildren[0].numberOfInputs !== 0) {
|
} else if (item.numberOfInputs !== 0 && item.topChildren[0].numberOfInputs !== 0) {
|
||||||
output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STROKE_WIDTH} />));
|
output.push((<path key={this.renderKey++} d={topStartPath} stroke={topColor} strokeWidth={SVG_STROKE_WIDTH} />));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.numberOfInputs === 2 && item.bottomChildren[0].numberOfInputs === 2) {
|
if (item.numberOfInputs === 2 && item.bottomChildren[0].numberOfInputs === 2) {
|
||||||
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />));
|
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />));
|
||||||
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />));
|
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />));
|
||||||
|
|
||||||
} else if (item.numberOfInputs !== 0 && item.bottomChildren[0].numberOfInputs !== 0) {
|
} else if (item.numberOfInputs !== 0 && item.bottomChildren[0].numberOfInputs !== 0) {
|
||||||
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STROKE_WIDTH} />));
|
output.push((<path key={this.renderKey++} d={bottomStartPath} stroke={bottomColor} strokeWidth={SVG_STROKE_WIDTH} />));
|
||||||
@@ -824,7 +827,7 @@ const PedalboardView =
|
|||||||
<path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={firstPath} stroke={firstPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
output.push((
|
output.push((
|
||||||
<path key={this.renderKey++} d={firstPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={firstPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
} else if (!firstPathAbsent) {
|
} else if (!firstPathAbsent) {
|
||||||
output.push((
|
output.push((
|
||||||
@@ -836,7 +839,7 @@ const PedalboardView =
|
|||||||
<path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={secondPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
output.push((
|
output.push((
|
||||||
<path key={this.renderKey++} d={secondPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={secondPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
} else if (!secondPathAbsent) {
|
} else if (!secondPathAbsent) {
|
||||||
output.push((
|
output.push((
|
||||||
@@ -868,12 +871,12 @@ const PedalboardView =
|
|||||||
// draw stereo inner lines.
|
// draw stereo inner lines.
|
||||||
if (firstPathStereo) {
|
if (firstPathStereo) {
|
||||||
output.push((
|
output.push((
|
||||||
<path key={this.renderKey++} d={firstPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={firstPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (secondPathStereo) {
|
if (secondPathStereo) {
|
||||||
output.push((
|
output.push((
|
||||||
<path key={this.renderKey++} d={secondPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={secondPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -885,7 +888,7 @@ const PedalboardView =
|
|||||||
<path key={this.renderKey++} d={thirdPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={thirdPath} stroke={secondPathColor} strokeWidth={SVG_STEREO_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
output.push((
|
output.push((
|
||||||
<path key={this.renderKey++} d={thirdPath} stroke="white" strokeWidth={SVG_STROKE_WIDTH} />
|
<path key={this.renderKey++} d={thirdPath} stroke={this.bgColor} strokeWidth={SVG_STROKE_WIDTH} />
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
||||||
@@ -958,7 +961,7 @@ const PedalboardView =
|
|||||||
let outputs: ReactNode[] = [];
|
let outputs: ReactNode[] = [];
|
||||||
this.renderConnectors(outputs, layoutChain, true, false);
|
this.renderConnectors(outputs, layoutChain, true, false);
|
||||||
return (
|
return (
|
||||||
<div style={{width: layoutSize.width, height: layoutSize.height, overflow: "hidden"}}>
|
<div key="connectors" style={{width: layoutSize.width, height: layoutSize.height, overflow: "hidden"}}>
|
||||||
<svg width={layoutSize.width} height={layoutSize.height}
|
<svg width={layoutSize.width} height={layoutSize.height}
|
||||||
xmlns="http://www.w3.org/2000/svg" viewBox={"0 0 " + layoutSize.width + " " + layoutSize.height}>
|
xmlns="http://www.w3.org/2000/svg" viewBox={"0 0 " + layoutSize.width + " " + layoutSize.height}>
|
||||||
<g fill="none">
|
<g fill="none">
|
||||||
|
|||||||
@@ -423,6 +423,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
//if (retry !== 0) {
|
//if (retry !== 0) {
|
||||||
if (this.restartExpected) {
|
if (this.restartExpected) {
|
||||||
this.setState(State.ApplyingChanges);
|
this.setState(State.ApplyingChanges);
|
||||||
|
this.restartExpected = false;
|
||||||
} else {
|
} else {
|
||||||
this.setState(State.Reconnecting);
|
this.setState(State.Reconnecting);
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-42
@@ -25,12 +25,10 @@ import createStyles from '@mui/styles/createStyles';
|
|||||||
import withStyles from '@mui/styles/withStyles';
|
import withStyles from '@mui/styles/withStyles';
|
||||||
|
|
||||||
import IControlViewFactory from './IControlViewFactory';
|
import IControlViewFactory from './IControlViewFactory';
|
||||||
import { PiPedalModelFactory, PiPedalModel,MonitorPortHandle } from "./PiPedalModel";
|
import { PiPedalModelFactory, PiPedalModel, MonitorPortHandle } from "./PiPedalModel";
|
||||||
import { PedalboardItem } from './Pedalboard';
|
import { PedalboardItem } from './Pedalboard';
|
||||||
import PluginControlView, { ControlGroup,ControlViewCustomization } from './PluginControlView';
|
import PluginControlView, { ControlGroup, ControlViewCustomization } from './PluginControlView';
|
||||||
import ToobFrequencyResponseView from './ToobFrequencyResponseView';
|
// import ToobFrequencyResponseView from './ToobFrequencyResponseView';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const styles = (theme: Theme) => createStyles({
|
const styles = (theme: Theme) => createStyles({
|
||||||
});
|
});
|
||||||
@@ -46,13 +44,12 @@ interface ToobMLState {
|
|||||||
|
|
||||||
const ToobMLView =
|
const ToobMLView =
|
||||||
withStyles(styles, { withTheme: true })(
|
withStyles(styles, { withTheme: true })(
|
||||||
class extends React.Component<ToobMLProps, ToobMLState>
|
class extends React.Component<ToobMLProps, ToobMLState>
|
||||||
implements ControlViewCustomization
|
implements ControlViewCustomization {
|
||||||
{
|
|
||||||
model: PiPedalModel;
|
model: PiPedalModel;
|
||||||
gainRef: React.RefObject<HTMLDivElement>;
|
gainRef: React.RefObject<HTMLDivElement>;
|
||||||
|
|
||||||
customizationId: number = 1;
|
customizationId: number = 1;
|
||||||
|
|
||||||
constructor(props: ToobMLProps) {
|
constructor(props: ToobMLProps) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -65,57 +62,75 @@ const ToobMLView =
|
|||||||
|
|
||||||
subscribedId?: number = undefined;
|
subscribedId?: number = undefined;
|
||||||
monitorPortHandle?: MonitorPortHandle = undefined;
|
monitorPortHandle?: MonitorPortHandle = undefined;
|
||||||
removeGainEnabledSubscription()
|
removeGainEnabledSubscription() {
|
||||||
{
|
if (this.monitorPortHandle) {
|
||||||
if (this.monitorPortHandle)
|
|
||||||
{
|
|
||||||
this.model.unmonitorPort(this.monitorPortHandle);
|
this.model.unmonitorPort(this.monitorPortHandle);
|
||||||
this.monitorPortHandle = undefined;
|
this.monitorPortHandle = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addGainEnabledSubscription(instanceId: number)
|
addGainEnabledSubscription(instanceId: number) {
|
||||||
{
|
|
||||||
this.removeGainEnabledSubscription();
|
this.removeGainEnabledSubscription();
|
||||||
this.subscribedId = instanceId;
|
this.subscribedId = instanceId;
|
||||||
this.monitorPortHandle = this.model.monitorPort(instanceId,"gainEnable",0.1,
|
this.monitorPortHandle = this.model.monitorPort(instanceId, "gainEnable", 0.1,
|
||||||
(value: number) => {
|
(value: number) => {
|
||||||
if (this.gainRef.current)
|
if (this.gainRef.current) {
|
||||||
{
|
this.gainRef.current.style.opacity = value !== 0.0 ? "1.0" : "0.4";
|
||||||
this.gainRef.current.style.opacity = value !== 0.0? "1.0": "0.4";
|
if (value !== 0.0) {
|
||||||
|
this.gainRef.current.style.pointerEvents = 'auto';
|
||||||
|
} else {
|
||||||
|
this.gainRef.current.style.pointerEvents = 'none';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.setState({gainEnabled: value !== 0.0 });
|
this.setState({ gainEnabled: value !== 0.0 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate()
|
// componentDidUpdate() {
|
||||||
{
|
// if (this.props.instanceId !== this.subscribedId) {
|
||||||
if (this.props.instanceId !== this.subscribedId)
|
// this.removeGainEnabledSubscription();
|
||||||
{
|
// this.addGainEnabledSubscription(this.props.instanceId);
|
||||||
this.removeGainEnabledSubscription();
|
|
||||||
this.addGainEnabledSubscription(this.props.instanceId);
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
componentDidMount() {
|
||||||
|
this.addGainEnabledSubscription(this.props.instanceId);
|
||||||
|
if (this.gainRef.current) {
|
||||||
|
this.gainRef.current.style.opacity = '0.4';
|
||||||
|
this.gainRef.current.style.pointerEvents = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount()
|
componentWillUnmount() {
|
||||||
{
|
|
||||||
this.addGainEnabledSubscription(this.props.instanceId);
|
|
||||||
}
|
|
||||||
componentWillUnmount()
|
|
||||||
{
|
|
||||||
this.removeGainEnabledSubscription();
|
this.removeGainEnabledSubscription();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModifyControls(controls: (React.ReactNode| ControlGroup)[]): (React.ReactNode| ControlGroup)[]
|
ModifyControls(controls: (React.ReactNode | ControlGroup)[]): (React.ReactNode | ControlGroup)[] {
|
||||||
{
|
// Find EQ group
|
||||||
let group = controls[4] as ControlGroup;
|
// let group = controls.find((control) => typeof control !== 'string' && (control as ControlGroup).name === "EQ") as ControlGroup;
|
||||||
group.controls.splice(0,0,
|
// if (group) {
|
||||||
( <ToobFrequencyResponseView instanceId={this.props.instanceId} />)
|
// group.controls.splice(0,0,
|
||||||
);
|
// ( <ToobFrequencyResponseView
|
||||||
|
// instanceId={this.props.instanceId}
|
||||||
let gainControl: React.ReactElement = controls[2] as React.ReactElement;
|
// />)
|
||||||
if (gainControl)
|
// );
|
||||||
|
// }
|
||||||
|
let controlIndex: number = -1;
|
||||||
|
let controlValues = this.props.item.controlValues
|
||||||
|
for (let i:number = 0; i < controlValues.length; ++i)
|
||||||
{
|
{
|
||||||
controls[2] = (<div ref={this.gainRef}> { gainControl} </div>);
|
let ctl: any = controls[i];
|
||||||
|
let key: any = ctl?.props?.uiControl?.symbol??"";
|
||||||
|
|
||||||
|
if (key === "gain")
|
||||||
|
{
|
||||||
|
controlIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controlIndex !== -1 ) {
|
||||||
|
|
||||||
|
let gainControl: React.ReactElement = controls[controlIndex] as React.ReactElement;
|
||||||
|
controls[controlIndex] = (<div ref={this.gainRef}> {gainControl} </div>);
|
||||||
}
|
}
|
||||||
return controls;
|
return controls;
|
||||||
}
|
}
|
||||||
|
|||||||
+105
-2
@@ -37,6 +37,7 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include "AudioConfig.hpp"
|
#include "AudioConfig.hpp"
|
||||||
#include "WifiChannelSelectors.hpp"
|
#include "WifiChannelSelectors.hpp"
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
#if JACK_HOST
|
#if JACK_HOST
|
||||||
#define INSTALL_JACK_SERVICE 1
|
#define INSTALL_JACK_SERVICE 1
|
||||||
@@ -592,6 +593,100 @@ static std::string RandomChars(int nchars)
|
|||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetVarPermissions(
|
||||||
|
const std::filesystem::path &path,
|
||||||
|
std::filesystem::perms directoryPermissions,
|
||||||
|
std::filesystem::perms filePermissions,
|
||||||
|
uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::filesystem;
|
||||||
|
try {
|
||||||
|
if (fs::exists(path)) {
|
||||||
|
|
||||||
|
if (fs::is_directory(path)) {
|
||||||
|
fs::permissions(path, directoryPermissions, fs::perm_options::replace);
|
||||||
|
for (const auto& entry : fs::recursive_directory_iterator(path)) {
|
||||||
|
try {
|
||||||
|
if (fs::is_directory(entry))
|
||||||
|
{
|
||||||
|
fs::permissions(entry.path(), directoryPermissions, fs::perm_options::replace);
|
||||||
|
} else {
|
||||||
|
fs::permissions(entry.path(),filePermissions, fs::perm_options::replace);
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
std::cout << "Error: failed to set permissions on file " << entry.path() << std::endl;
|
||||||
|
}
|
||||||
|
if (chown(path.c_str(),uid,gid) != 0)
|
||||||
|
{
|
||||||
|
std::cout << "Error: failed to set ownership of file " << entry.path() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fs::permissions(path,filePermissions, fs::perm_options::replace);
|
||||||
|
chown(path.c_str(),uid,gid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Error: Path does not exist: " << path << std::endl;
|
||||||
|
}
|
||||||
|
} catch (const std::filesystem::filesystem_error& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void FixPermissions()
|
||||||
|
{
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::filesystem;
|
||||||
|
|
||||||
|
fs::create_directories("/var/pipedal");
|
||||||
|
|
||||||
|
fs::perms directoryPermissions =
|
||||||
|
fs::perms::owner_read | fs::perms::owner_write | fs::perms::owner_exec |
|
||||||
|
fs::perms::group_read | fs::perms::group_write | fs::perms::group_exec |
|
||||||
|
fs::perms::others_read | fs::perms::others_exec |
|
||||||
|
fs::perms::set_gid;
|
||||||
|
|
||||||
|
fs::perms filePermissions =
|
||||||
|
fs::perms::owner_read | fs::perms::owner_write |
|
||||||
|
fs::perms::group_read | fs::perms::group_write |
|
||||||
|
fs::perms::others_read ;
|
||||||
|
|
||||||
|
uid_t uid;
|
||||||
|
struct passwd *passwd;
|
||||||
|
if ((passwd = getpwnam("pipedal_d")) == nullptr)
|
||||||
|
{
|
||||||
|
cout << "Error: " << "User 'pipedal_d' does not exist." << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uid = passwd->pw_uid;
|
||||||
|
gid_t gid = passwd->pw_gid;
|
||||||
|
SetVarPermissions("/var/pipedal",directoryPermissions,filePermissions,uid,gid);
|
||||||
|
|
||||||
|
fs::perms wpa_supplicant_perms =
|
||||||
|
fs::perms::owner_read | fs::perms::owner_write |
|
||||||
|
fs::perms::group_read | fs::perms::group_write;
|
||||||
|
|
||||||
|
std::filesystem::path wpa_config_path{ "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"};
|
||||||
|
try {
|
||||||
|
fs::permissions(wpa_config_path,wpa_supplicant_perms, fs::perm_options::replace);
|
||||||
|
|
||||||
|
struct group*grp = getgrnam("netdev");
|
||||||
|
if (grp != nullptr)
|
||||||
|
{
|
||||||
|
if (chown(wpa_config_path.c_str(),0,grp->gr_gid) != 0)
|
||||||
|
{
|
||||||
|
cout << "Error: Failed to change ownership of " << wpa_config_path << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception&e)
|
||||||
|
{
|
||||||
|
cout << "Error: Failed to set permissions on " << wpa_config_path << ". " << e.what() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
static void PrepareServiceConfigurationFile(uint16_t portNumber)
|
static void PrepareServiceConfigurationFile(uint16_t portNumber)
|
||||||
{
|
{
|
||||||
ServiceConfiguration serviceConfiguration;
|
ServiceConfiguration serviceConfiguration;
|
||||||
@@ -827,6 +922,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
|||||||
|
|
||||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||||
|
|
||||||
|
FixPermissions();
|
||||||
RestartService(false);
|
RestartService(false);
|
||||||
EnableService();
|
EnableService();
|
||||||
}
|
}
|
||||||
@@ -1070,6 +1166,7 @@ int main(int argc, char **argv)
|
|||||||
bool enable_p2p = false, disable_p2p = false;
|
bool enable_p2p = false, disable_p2p = false;
|
||||||
bool list_p2p_channels = false;
|
bool list_p2p_channels = false;
|
||||||
bool get_current_port = false;
|
bool get_current_port = false;
|
||||||
|
bool fix_permissions = false;
|
||||||
bool nosudo = false;
|
bool nosudo = false;
|
||||||
bool excludeShutdownService = false;
|
bool excludeShutdownService = false;
|
||||||
std::string prefixOption;
|
std::string prefixOption;
|
||||||
@@ -1092,7 +1189,8 @@ int main(int argc, char **argv)
|
|||||||
parser.AddOption("--enable-p2p", &enable_p2p);
|
parser.AddOption("--enable-p2p", &enable_p2p);
|
||||||
parser.AddOption("--disable-p2p", &disable_p2p);
|
parser.AddOption("--disable-p2p", &disable_p2p);
|
||||||
parser.AddOption("--list-p2p-channels", &list_p2p_channels);
|
parser.AddOption("--list-p2p-channels", &list_p2p_channels);
|
||||||
|
parser.AddOption("--fix-permissions", &fix_permissions);
|
||||||
|
|
||||||
|
|
||||||
parser.AddOption("--get-current-port", &get_current_port); // private. For debug use only.
|
parser.AddOption("--get-current-port", &get_current_port); // private. For debug use only.
|
||||||
|
|
||||||
@@ -1104,7 +1202,7 @@ int main(int argc, char **argv)
|
|||||||
int actionCount =
|
int actionCount =
|
||||||
help + get_current_port + install + uninstall + stop + start + enable + disable
|
help + get_current_port + install + uninstall + stop + start + enable + disable
|
||||||
+ enable_ap + disable_ap + restart + enable_p2p + disable_p2p
|
+ enable_ap + disable_ap + restart + enable_p2p + disable_p2p
|
||||||
+ list_p2p_channels
|
+ list_p2p_channels + fix_permissions
|
||||||
;
|
;
|
||||||
if (actionCount > 1)
|
if (actionCount > 1)
|
||||||
{
|
{
|
||||||
@@ -1169,6 +1267,11 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (fix_permissions)
|
||||||
|
{
|
||||||
|
FixPermissions();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
if (install)
|
if (install)
|
||||||
{
|
{
|
||||||
std::filesystem::path prefix;
|
std::filesystem::path prefix;
|
||||||
|
|||||||
+9
-20
@@ -261,15 +261,15 @@ void Lv2Pedalboard::PrepareMidiMap(const PedalboardItem &pedalboardItem)
|
|||||||
{
|
{
|
||||||
if (pedalboardItem.midiBindings().size() != 0)
|
if (pedalboardItem.midiBindings().size() != 0)
|
||||||
{
|
{
|
||||||
auto pluginInfo = pHost->GetPluginInfo(pedalboardItem.uri());
|
Lv2PluginInfo::ptr pluginInfo;
|
||||||
const Lv2PluginInfo *pPluginInfo;
|
if (pedalboardItem.uri() == SPLIT_PEDALBOARD_ITEM_URI)
|
||||||
if (pluginInfo == nullptr && pedalboardItem.uri() == SPLIT_PEDALBOARD_ITEM_URI)
|
|
||||||
{
|
{
|
||||||
pPluginInfo = GetSplitterPluginInfo();
|
pluginInfo = GetSplitterPluginInfo();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pPluginInfo = pluginInfo.get();
|
pluginInfo = pHost->GetPluginInfo(pedalboardItem.uri());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int effectIndex = this->GetIndexOfInstanceId(pedalboardItem.instanceId());
|
int effectIndex = this->GetIndexOfInstanceId(pedalboardItem.instanceId());
|
||||||
@@ -351,21 +351,10 @@ void Lv2Pedalboard::PrepareMidiMap(const Pedalboard &pedalboard)
|
|||||||
auto &item = pedalboard.items()[i];
|
auto &item = pedalboard.items()[i];
|
||||||
PrepareMidiMap(item);
|
PrepareMidiMap(item);
|
||||||
|
|
||||||
auto pluginInfo = pHost->GetPluginInfo(item.uri());
|
|
||||||
|
|
||||||
if (pluginInfo)
|
|
||||||
{
|
|
||||||
for (size_t bindingIndex = 0; bindingIndex < item.midiBindings().size(); ++bindingIndex)
|
|
||||||
{
|
|
||||||
auto &binding = item.midiBindings()[i];
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::sort(this->midiMappings.begin(), this->midiMappings.end(),
|
|
||||||
[](const MidiMapping &left, const MidiMapping &right)
|
|
||||||
{ return left.key < right.key; });
|
|
||||||
}
|
}
|
||||||
|
std::sort(this->midiMappings.begin(), this->midiMappings.end(),
|
||||||
|
[](const MidiMapping &left, const MidiMapping &right)
|
||||||
|
{ return left.key < right.key; });
|
||||||
}
|
}
|
||||||
void Lv2Pedalboard::Activate()
|
void Lv2Pedalboard::Activate()
|
||||||
{
|
{
|
||||||
@@ -606,7 +595,7 @@ void Lv2Pedalboard::OnMidiMessage(size_t size, uint8_t *message,
|
|||||||
if (size < 3)
|
if (size < 3)
|
||||||
return;
|
return;
|
||||||
index = message[1];
|
index = message[1];
|
||||||
value = 127;
|
value = message[2] == 0? 0: 127; // zero velocity = note off.
|
||||||
}
|
}
|
||||||
else if (cmd == 0xB0) // midi control.
|
else if (cmd == 0xB0) // midi control.
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1266,21 +1266,20 @@ void PiPedalModel::OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, f
|
|||||||
PedalboardItem *item = this->pedalboard.GetItem(instanceId);
|
PedalboardItem *item = this->pedalboard.GetItem(instanceId);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
const Lv2PluginInfo *pPluginInfo;
|
Lv2PluginInfo::ptr pPluginInfo;
|
||||||
if (item->uri() == SPLIT_PEDALBOARD_ITEM_URI)
|
if (item->uri() == SPLIT_PEDALBOARD_ITEM_URI)
|
||||||
{
|
{
|
||||||
pPluginInfo = GetSplitterPluginInfo();
|
pPluginInfo = GetSplitterPluginInfo();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto pluginInfo = lv2Host.GetPluginInfo(item->uri());
|
pPluginInfo = lv2Host.GetPluginInfo(item->uri());
|
||||||
pPluginInfo = pluginInfo.get();
|
|
||||||
}
|
}
|
||||||
if (pPluginInfo)
|
if (pPluginInfo)
|
||||||
{
|
{
|
||||||
if (portIndex == -1)
|
if (portIndex == -1)
|
||||||
{
|
{
|
||||||
// bypass!
|
// bypass! yyy this->value!!!
|
||||||
this->pedalboard.SetItemEnabled(instanceId, value != 0);
|
this->pedalboard.SetItemEnabled(instanceId, value != 0);
|
||||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||||
@@ -1675,16 +1674,15 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
|||||||
|
|
||||||
void PiPedalModel::UpdateDefaults(PedalboardItem *pedalboardItem)
|
void PiPedalModel::UpdateDefaults(PedalboardItem *pedalboardItem)
|
||||||
{
|
{
|
||||||
std::shared_ptr<Lv2PluginInfo> t = lv2Host.GetPluginInfo(pedalboardItem->uri());
|
std::shared_ptr<Lv2PluginInfo> pPlugin = lv2Host.GetPluginInfo(pedalboardItem->uri());
|
||||||
const Lv2PluginInfo *pPlugin = t.get();
|
if (!pPlugin)
|
||||||
if (pPlugin == nullptr)
|
|
||||||
{
|
{
|
||||||
if (pedalboardItem->uri() == SPLIT_PEDALBOARD_ITEM_URI)
|
if (pedalboardItem->uri() == SPLIT_PEDALBOARD_ITEM_URI)
|
||||||
{
|
{
|
||||||
pPlugin = GetSplitterPluginInfo();
|
pPlugin = GetSplitterPluginInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pPlugin != nullptr)
|
if (pPlugin)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < pPlugin->ports().size(); ++i)
|
for (size_t i = 0; i < pPlugin->ports().size(); ++i)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1353,6 +1353,10 @@ Lv2PortGroup::Lv2PortGroup(PluginHost *lv2Host, const std::string &groupUri)
|
|||||||
name_ = nodeAsString(nameNode);
|
name_ = nodeAsString(nameNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Lv2PluginInfo::isSplit() const
|
||||||
|
{
|
||||||
|
return uri_ == SPLIT_PEDALBOARD_ITEM_URI;
|
||||||
|
}
|
||||||
std::shared_ptr<HostWorkerThread> PluginHost::GetHostWorkerThread()
|
std::shared_ptr<HostWorkerThread> PluginHost::GetHostWorkerThread()
|
||||||
{
|
{
|
||||||
return pHostWorkerThread;
|
return pHostWorkerThread;
|
||||||
|
|||||||
@@ -337,8 +337,10 @@ namespace pipedal
|
|||||||
friend class PluginHost;
|
friend class PluginHost;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
using ptr = std::shared_ptr<Lv2PluginInfo>;
|
||||||
Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvPlugin *);
|
Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvPlugin *);
|
||||||
Lv2PluginInfo() {}
|
Lv2PluginInfo() {}
|
||||||
|
bool isSplit() const ;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<PiPedalUI> FindWritablePathProperties(PluginHost *lv2Host, const LilvPlugin *pPlugin);
|
std::shared_ptr<PiPedalUI> FindWritablePathProperties(PluginHost *lv2Host, const LilvPlugin *pPlugin);
|
||||||
|
|||||||
+4
-2
@@ -33,6 +33,8 @@ static std::shared_ptr<Lv2PortInfo> MakeBypassPortInfo()
|
|||||||
bypassPortInfo->is_input(true);
|
bypassPortInfo->is_input(true);
|
||||||
bypassPortInfo->is_control_port(true);
|
bypassPortInfo->is_control_port(true);
|
||||||
bypassPortInfo->index(-1);
|
bypassPortInfo->index(-1);
|
||||||
|
|
||||||
|
|
||||||
bypassPortInfo->min_value(0);
|
bypassPortInfo->min_value(0);
|
||||||
bypassPortInfo->max_value(1);
|
bypassPortInfo->max_value(1);
|
||||||
bypassPortInfo->default_value(1);
|
bypassPortInfo->default_value(1);
|
||||||
@@ -159,9 +161,9 @@ static Lv2PluginInfo makeSplitterPluginInfo()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lv2PluginInfo g_splitterPluginInfo = makeSplitterPluginInfo();
|
Lv2PluginInfo::ptr g_splitterPluginInfo = std::make_shared<Lv2PluginInfo>(makeSplitterPluginInfo());
|
||||||
|
|
||||||
const Lv2PluginInfo *pipedal::GetSplitterPluginInfo() { return &g_splitterPluginInfo; }
|
Lv2PluginInfo::ptr pipedal::GetSplitterPluginInfo() { return g_splitterPluginInfo; }
|
||||||
|
|
||||||
int SplitEffect::GetControlIndex(const std::string &symbol) const
|
int SplitEffect::GetControlIndex(const std::string &symbol) const
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ namespace pipedal
|
|||||||
class Lv2PluginInfo;
|
class Lv2PluginInfo;
|
||||||
class Lv2PortInfo;
|
class Lv2PortInfo;
|
||||||
|
|
||||||
const Lv2PluginInfo *GetSplitterPluginInfo();
|
std::shared_ptr<Lv2PluginInfo> GetSplitterPluginInfo();
|
||||||
|
|
||||||
const Lv2PortInfo *GetBypassPortInfo();
|
const Lv2PortInfo *GetBypassPortInfo();
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -1624,14 +1624,19 @@ std::string Storage::UploadUserFile(const std::string &directory, const std::str
|
|||||||
throw std::logic_error("patchProperty directory not implemented.");
|
throw std::logic_error("patchProperty directory not implemented.");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::filesystem::create_directories(path.parent_path());
|
try {
|
||||||
|
std::filesystem::create_directories(path.parent_path());
|
||||||
|
|
||||||
std::ofstream f(path, std::ios_base::trunc | std::ios_base::binary);
|
std::ofstream f(path, std::ios_base::trunc | std::ios_base::binary);
|
||||||
if (!f.is_open())
|
if (!f.is_open())
|
||||||
|
{
|
||||||
|
throw std::logic_error(SS("Can't create file " << path << "."));
|
||||||
|
}
|
||||||
|
f.write(fileBody.c_str(), fileBody.length());
|
||||||
|
} catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
throw std::logic_error(SS("Can't create file " << path << "."));
|
Lv2Log::error(SS("Upload failed. " << e.what()));
|
||||||
}
|
}
|
||||||
f.write(fileBody.c_str(), fileBody.length());
|
|
||||||
}
|
}
|
||||||
return path.string();
|
return path.string();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user