v1.0.18
- MIDI Program/Bank select. - MIDI next/previous program.
This commit is contained in:
+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.0.17
|
VERSION 1.0.18
|
||||||
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
||||||
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
||||||
)
|
)
|
||||||
set (DISPLAY_VERSION "v1.0.17")
|
set (DISPLAY_VERSION "v1.0.18")
|
||||||
|
|
||||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
Copyright 2021-2022 Robin Davies
|
Copyright 2021-2023 Robin Davies
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the "Software"),
|
a copy of this software and associated documentation files (the "Software"),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
<img src='docs/GithubBanner.png' width="100%" /><br/>
|
<img src='docs/GithubBanner.png' width="100%" /><br/>
|
||||||
|
|
||||||
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.0.17</a>
|
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.0.18</a>
|
||||||
|
|
||||||
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
|
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -9,6 +9,6 @@ Package: pipedal
|
|||||||
Pre-Depends: hostapd;authbind
|
Pre-Depends: hostapd;authbind
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Section: sound
|
Section: sound
|
||||||
Version: 1.0.17
|
Version: 1.0.18
|
||||||
Installed-Size: 15147
|
Installed-Size: 15147
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -13,14 +13,14 @@ page_icon: img/Install4.jpg
|
|||||||
|
|
||||||
Download the most recent Debian (.deb) package for your platform:
|
Download the most recent Debian (.deb) package for your platform:
|
||||||
|
|
||||||
- [Ubuntu/Raspberry Pi OS (64-bit) v1.0.17](https://github.com/rerdavies/pipedal/releases/download/v1.0.17/pipedal_1.0.17_arm64.deb)
|
- [Ubuntu/Raspberry Pi OS (64-bit) v1.0.18](https://github.com/rerdavies/pipedal/releases/download/v1.0.18/pipedal_1.0.18_arm64.deb)
|
||||||
|
|
||||||
Install the package by running
|
Install the package by running
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
cd ~/Downloads
|
cd ~/Downloads
|
||||||
sudo apt-get install ./pipedal_1.0.17_arm64.deb
|
sudo apt-get install ./pipedal_1.0.18_arm64.deb
|
||||||
```
|
```
|
||||||
On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager.
|
On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager.
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
Download the most recent Debian (.deb) package for your platform:
|
Download the most recent Debian (.deb) package for your platform:
|
||||||
|
|
||||||
- [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.0.17/pipedal_1.0.17_arm64.deb) v1.0.17
|
- [Ubuntu or Raspberry Pi OS (64-bit)](https://github.com/rerdavies/pipedal/releases/download/v1.0.18/pipedal_1.0.18_arm64.deb) v1.0.18
|
||||||
|
|
||||||
Install the package by running
|
Install the package by running
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
cd ~/Downloads
|
cd ~/Downloads
|
||||||
sudo apt-get install ./pipedal_1.0.17_arm64.deb
|
sudo apt-get install ./pipedal_1.0.18_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
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<img src="GithubBanner.png" width="100%"/>
|
<img src="GithubBanner.png" width="100%"/>
|
||||||
<a href="Installing.html"><i>v1.0.17</i></a>
|
<a href="Installing.html"><i>v1.0.18</i></a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ export default class MidiBinding {
|
|||||||
this.switchControlType = input.switchControlType;
|
this.switchControlType = input.switchControlType;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
static systemBinding(symbol: string): MidiBinding {
|
||||||
|
let result = new MidiBinding();
|
||||||
|
result.symbol = symbol;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
static deserialize_array(input: any): MidiBinding[] {
|
static deserialize_array(input: any): MidiBinding[] {
|
||||||
let result: MidiBinding[] = [];
|
let result: MidiBinding[] = [];
|
||||||
for (let i = 0; i < input.length; ++i)
|
for (let i = 0; i < input.length; ++i)
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ const MidiBindingView =
|
|||||||
onChange={(e, extra) => this.handleLatchControlTypeChange(e, extra)}
|
onChange={(e, extra) => this.handleLatchControlTypeChange(e, extra)}
|
||||||
value={midiBinding.switchControlType}
|
value={midiBinding.switchControlType}
|
||||||
>
|
>
|
||||||
<MenuItem value={MidiBinding.LATCH_CONTROL_TYPE}>Latch</MenuItem>
|
<MenuItem value={MidiBinding.LATCH_CONTROL_TYPE}>Toggle</MenuItem>
|
||||||
<MenuItem value={MidiBinding.MOMENTARY_CONTROL_TYPE}>Momentary</MenuItem>
|
<MenuItem value={MidiBinding.MOMENTARY_CONTROL_TYPE}>Momentary</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+59
-29
@@ -339,6 +339,7 @@ export interface PiPedalModel {
|
|||||||
favorites: ObservableProperty<FavoritesList>;
|
favorites: ObservableProperty<FavoritesList>;
|
||||||
|
|
||||||
presets: ObservableProperty<PresetIndex>;
|
presets: ObservableProperty<PresetIndex>;
|
||||||
|
systemMidiBindings: ObservableProperty<MidiBinding[]>;
|
||||||
|
|
||||||
|
|
||||||
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined>;
|
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined>;
|
||||||
@@ -409,6 +410,8 @@ export interface PiPedalModel {
|
|||||||
updatePluginPresets(uri: string, presets: PluginUiPresets): Promise<void>;
|
updatePluginPresets(uri: string, presets: PluginUiPresets): Promise<void>;
|
||||||
duplicatePluginPreset(uri: string, instanceId: number): Promise<number>;
|
duplicatePluginPreset(uri: string, instanceId: number): Promise<number>;
|
||||||
|
|
||||||
|
setSystemMidiBinding(instanceId: number, midiBinding: MidiBinding): void;
|
||||||
|
|
||||||
shutdown(): Promise<void>;
|
shutdown(): Promise<void>;
|
||||||
restart(): Promise<void>;
|
restart(): Promise<void>;
|
||||||
|
|
||||||
@@ -441,8 +444,8 @@ export interface PiPedalModel {
|
|||||||
|
|
||||||
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void;
|
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void;
|
||||||
|
|
||||||
onPreviousZoomedControl() : void;
|
onPreviousZoomedControl(): void;
|
||||||
onNextZoomedControl() : void;
|
onNextZoomedControl(): void;
|
||||||
clearZoomedControl(): void;
|
clearZoomedControl(): void;
|
||||||
|
|
||||||
setFavorite(pluginUrl: string, isFavorite: boolean): void;
|
setFavorite(pluginUrl: string, isFavorite: boolean): void;
|
||||||
@@ -495,7 +498,13 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
(
|
(
|
||||||
new PresetIndex()
|
new PresetIndex()
|
||||||
);
|
);
|
||||||
|
systemMidiBindings: ObservableProperty<MidiBinding[]> = new ObservableProperty<MidiBinding[]>
|
||||||
|
(
|
||||||
|
[
|
||||||
|
MidiBinding.systemBinding("prevProgram"),
|
||||||
|
MidiBinding.systemBinding("nextProgram")
|
||||||
|
]
|
||||||
|
);
|
||||||
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
|
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
|
||||||
|
|
||||||
svgImgUrl(svgImage: string): string {
|
svgImgUrl(svgImage: string): string {
|
||||||
@@ -682,7 +691,10 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
if (header.replyTo) {
|
if (header.replyTo) {
|
||||||
this.webSocket?.reply(header.replyTo, "onVuUpdate", true);
|
this.webSocket?.reply(header.replyTo, "onVuUpdate", true);
|
||||||
}
|
}
|
||||||
|
} else if (message === "onSystemMidiBindingsChanged")
|
||||||
|
{
|
||||||
|
let bindings = MidiBinding.deserialize_array(body);
|
||||||
|
this.systemMidiBindings.set(bindings);
|
||||||
} else {
|
} else {
|
||||||
throw new PiPedalStateError("Unrecognized message received from server: " + message);
|
throw new PiPedalStateError("Unrecognized message received from server: " + message);
|
||||||
}
|
}
|
||||||
@@ -815,6 +827,12 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.favorites.set(data);
|
this.favorites.set(data);
|
||||||
|
|
||||||
|
return this.getWebSocket().request<MidiBinding[]>("getSystemMidiBindings");
|
||||||
|
})
|
||||||
|
.then((data)=> {
|
||||||
|
let bindings = MidiBinding.deserialize_array(data);
|
||||||
|
this.systemMidiBindings.set(bindings);
|
||||||
|
|
||||||
this.setState(State.Ready);
|
this.setState(State.Ready);
|
||||||
})
|
})
|
||||||
.catch((what) => {
|
.catch((what) => {
|
||||||
@@ -977,6 +995,12 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.favorites.set(data);
|
this.favorites.set(data);
|
||||||
|
|
||||||
|
return this.getWebSocket().request<MidiBinding[]>("getSystemMidiBindings");
|
||||||
|
})
|
||||||
|
.then((data)=> {
|
||||||
|
let bindings = MidiBinding.deserialize_array(data);
|
||||||
|
this.systemMidiBindings.set(bindings);
|
||||||
|
|
||||||
if (this.webSocket) {
|
if (this.webSocket) {
|
||||||
// MUST not allow reconnect until at least one complete load has finished.
|
// MUST not allow reconnect until at least one complete load has finished.
|
||||||
this.webSocket.canReconnect = true;
|
this.webSocket.canReconnect = true;
|
||||||
@@ -1215,7 +1239,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
_setVst3PedalBoardControlValue(instanceId: number, key: string, value: number, state: string, notifyServer: boolean ): void {
|
_setVst3PedalBoardControlValue(instanceId: number, key: string, value: number, state: string, notifyServer: boolean): void {
|
||||||
let pedalBoard = this.pedalBoard.get();
|
let pedalBoard = this.pedalBoard.get();
|
||||||
if (pedalBoard === undefined) throw new PiPedalStateError("Pedalboard not ready.");
|
if (pedalBoard === undefined) throw new PiPedalStateError("Pedalboard not ready.");
|
||||||
let newPedalBoard = pedalBoard.clone();
|
let newPedalBoard = pedalBoard.clone();
|
||||||
@@ -1837,8 +1861,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVst3State(pedalBoard: PedalBoard)
|
updateVst3State(pedalBoard: PedalBoard) {
|
||||||
{
|
|
||||||
// let it = pedalBoard.itemsGenerator();
|
// let it = pedalBoard.itemsGenerator();
|
||||||
// while (true) {
|
// while (true) {
|
||||||
// let v = it.next();
|
// let v = it.next();
|
||||||
@@ -1862,6 +1885,23 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setSystemMidiBinding(instanceId: number, midiBinding: MidiBinding): void {
|
||||||
|
let currentBindings = this.systemMidiBindings.get();
|
||||||
|
|
||||||
|
let result: MidiBinding[] = [];
|
||||||
|
|
||||||
|
for (var binding of currentBindings)
|
||||||
|
{
|
||||||
|
if (binding.symbol === midiBinding.symbol)
|
||||||
|
{
|
||||||
|
result.push(midiBinding);
|
||||||
|
} else {
|
||||||
|
result.push(binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.systemMidiBindings.set(result);
|
||||||
|
this.webSocket?.send("setSystemMidiBindings",result);
|
||||||
|
}
|
||||||
midiListeners: MidiEventListener[] = [];
|
midiListeners: MidiEventListener[] = [];
|
||||||
atomOutputListeners: AtomOutputListener[] = [];
|
atomOutputListeners: AtomOutputListener[] = [];
|
||||||
|
|
||||||
@@ -1918,8 +1958,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
if (!found) {
|
||||||
{
|
|
||||||
console.log('cancelListenForMidiEvent: event not found.');
|
console.log('cancelListenForMidiEvent: event not found.');
|
||||||
}
|
}
|
||||||
this.webSocket?.send("cancelListenForMidiEvent", listenHandle._handle);
|
this.webSocket?.send("cancelListenForMidiEvent", listenHandle._handle);
|
||||||
@@ -2183,19 +2222,14 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
}
|
}
|
||||||
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void {
|
zoomUiControl(sourceElement: HTMLElement, instanceId: number, uiControl: UiControl): void {
|
||||||
let name = uiControl.name;
|
let name = uiControl.name;
|
||||||
if (uiControl.port_group !== "")
|
if (uiControl.port_group !== "") {
|
||||||
{
|
|
||||||
let pedalboard = this.pedalBoard.get();
|
let pedalboard = this.pedalBoard.get();
|
||||||
if (pedalboard)
|
if (pedalboard) {
|
||||||
{
|
|
||||||
let plugin = pedalboard.getItem(instanceId);
|
let plugin = pedalboard.getItem(instanceId);
|
||||||
let uiPlugin = this.getUiPlugin(plugin.uri);
|
let uiPlugin = this.getUiPlugin(plugin.uri);
|
||||||
if (uiPlugin)
|
if (uiPlugin) {
|
||||||
{
|
for (let i = 0; i < uiPlugin.port_groups.length; ++i) {
|
||||||
for (let i = 0; i < uiPlugin.port_groups.length; ++i)
|
if (uiPlugin.port_groups[i].symbol === uiControl.port_group) {
|
||||||
{
|
|
||||||
if (uiPlugin.port_groups[i].symbol === uiControl.port_group)
|
|
||||||
{
|
|
||||||
name = uiPlugin.port_groups[i].name + " / " + name;
|
name = uiPlugin.port_groups[i].name + " / " + name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2205,8 +2239,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
}
|
}
|
||||||
this.zoomedUiControl.set({ source: sourceElement, name: name, instanceId: instanceId, uiControl: uiControl });
|
this.zoomedUiControl.set({ source: sourceElement, name: name, instanceId: instanceId, uiControl: uiControl });
|
||||||
}
|
}
|
||||||
onPreviousZoomedControl() : void
|
onPreviousZoomedControl(): void {
|
||||||
{
|
|
||||||
let currentUiControl = this.zoomedUiControl.get();
|
let currentUiControl = this.zoomedUiControl.get();
|
||||||
if (!currentUiControl) return;
|
if (!currentUiControl) return;
|
||||||
|
|
||||||
@@ -2222,8 +2255,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let ix = -1;
|
let ix = -1;
|
||||||
for (i = 0; i < uiPlugin.controls.length; ++i)
|
for (i = 0; i < uiPlugin.controls.length; ++i) {
|
||||||
{
|
|
||||||
if (uiPlugin.controls[i].symbol === currentSymbol) {
|
if (uiPlugin.controls[i].symbol === currentSymbol) {
|
||||||
ix = i;
|
ix = i;
|
||||||
break;
|
break;
|
||||||
@@ -2234,10 +2266,9 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
++ix;
|
++ix;
|
||||||
if (ix >= uiPlugin.controls.length) return;
|
if (ix >= uiPlugin.controls.length) return;
|
||||||
|
|
||||||
this.zoomUiControl(currentUiControl.source,currentUiControl.instanceId,uiPlugin.controls[ix]);
|
this.zoomUiControl(currentUiControl.source, currentUiControl.instanceId, uiPlugin.controls[ix]);
|
||||||
}
|
}
|
||||||
onNextZoomedControl() : void
|
onNextZoomedControl(): void {
|
||||||
{
|
|
||||||
let currentUiControl = this.zoomedUiControl.get();
|
let currentUiControl = this.zoomedUiControl.get();
|
||||||
if (!currentUiControl) return;
|
if (!currentUiControl) return;
|
||||||
|
|
||||||
@@ -2253,8 +2284,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let ix = -1;
|
let ix = -1;
|
||||||
for (i = 0; i < uiPlugin.controls.length; ++i)
|
for (i = 0; i < uiPlugin.controls.length; ++i) {
|
||||||
{
|
|
||||||
if (uiPlugin.controls[i].symbol === currentSymbol) {
|
if (uiPlugin.controls[i].symbol === currentSymbol) {
|
||||||
ix = i;
|
ix = i;
|
||||||
break;
|
break;
|
||||||
@@ -2265,7 +2295,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
|||||||
--ix;
|
--ix;
|
||||||
if (ix < 0) return;
|
if (ix < 0) return;
|
||||||
|
|
||||||
this.zoomUiControl(currentUiControl.source,currentUiControl.instanceId,uiPlugin.controls[ix]);
|
this.zoomUiControl(currentUiControl.source, currentUiControl.instanceId, uiPlugin.controls[ix]);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearZoomedControl(): void {
|
clearZoomedControl(): void {
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import WifiDirectConfigDialog from './WifiDirectConfigDialog';
|
|||||||
import DialogEx from './DialogEx'
|
import DialogEx from './DialogEx'
|
||||||
import GovernorSettings from './GovernorSettings';
|
import GovernorSettings from './GovernorSettings';
|
||||||
import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo';
|
import { AlsaMidiDeviceInfo } from './AlsaMidiDeviceInfo';
|
||||||
|
import SystemMidiBindingsDialog from './SystemMidiBindingsDialog';
|
||||||
|
|
||||||
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';
|
||||||
@@ -84,6 +85,7 @@ interface SettingsDialogState {
|
|||||||
isAndroidHosted: boolean;
|
isAndroidHosted: boolean;
|
||||||
showRestartOkDialog: boolean;
|
showRestartOkDialog: boolean;
|
||||||
showShutdownOkDialog: boolean;
|
showShutdownOkDialog: boolean;
|
||||||
|
showSystemMidiBindingsDialog: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -182,6 +184,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
restarting: false,
|
restarting: false,
|
||||||
showShutdownOkDialog: false,
|
showShutdownOkDialog: false,
|
||||||
showRestartOkDialog: false,
|
showRestartOkDialog: false,
|
||||||
|
showSystemMidiBindingsDialog: false,
|
||||||
isAndroidHosted: this.model.isAndroidHosted()
|
isAndroidHosted: this.model.isAndroidHosted()
|
||||||
|
|
||||||
|
|
||||||
@@ -376,6 +379,12 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
showMidiSelectDialog: true
|
showMidiSelectDialog: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
handleMidiMessageSettings() {
|
||||||
|
this.setState({
|
||||||
|
showSystemMidiBindingsDialog: true
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
handleJackServerSettings() {
|
handleJackServerSettings() {
|
||||||
this.setState({
|
this.setState({
|
||||||
showJackServerSettingsDialog: true,
|
showJackServerSettingsDialog: true,
|
||||||
@@ -634,6 +643,14 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>{this.midiSummary()}</Typography>
|
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>{this.midiSummary()}</Typography>
|
||||||
</div>
|
</div>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
<ButtonBase className={classes.setting} disabled={!isConfigValid} onClick={() => this.handleMidiMessageSettings()} >
|
||||||
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
|
<div style={{ width: "100%" }}>
|
||||||
|
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>System MIDI Bindings</Typography>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ButtonBase>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -840,6 +857,10 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
onOk={() => { this.setState({ showShutdownOkDialog: false }); this.handleShutdownOk(); }}
|
onOk={() => { this.setState({ showShutdownOkDialog: false }); this.handleShutdownOk(); }}
|
||||||
onClose={() => { this.setState({ showShutdownOkDialog: false }); }}
|
onClose={() => { this.setState({ showShutdownOkDialog: false }); }}
|
||||||
/>
|
/>
|
||||||
|
<SystemMidiBindingsDialog
|
||||||
|
open={this.state.showSystemMidiBindingsDialog}
|
||||||
|
onClose={()=> { this.setState({showSystemMidiBindingsDialog: false});}}
|
||||||
|
/>
|
||||||
</DialogEx >
|
</DialogEx >
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2023 Robin E. R. Davies
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import { Component } from 'react';
|
||||||
|
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||||
|
import { Theme } from '@mui/material/styles';
|
||||||
|
import { WithStyles } from '@mui/styles';
|
||||||
|
import withStyles from '@mui/styles/withStyles';
|
||||||
|
import createStyles from '@mui/styles/createStyles';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
import MidiBinding from './MidiBinding';
|
||||||
|
import Utility from './Utility';
|
||||||
|
import MicNoneOutlinedIcon from '@mui/icons-material/MicNoneOutlined';
|
||||||
|
import MicOutlinedIcon from '@mui/icons-material/MicOutlined';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const styles = (theme: Theme) => createStyles({
|
||||||
|
controlDiv: { flex: "0 0 auto", marginRight: 12, verticalAlign: "center", height: 48, paddingTop: 8, paddingBottom: 8 },
|
||||||
|
controlDiv2: {
|
||||||
|
flex: "0 0 auto", marginRight: 12, verticalAlign: "center",
|
||||||
|
height: 48, paddingTop: 0, paddingBottom: 0, whiteSpace: "nowrap"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface SystemMidiBindingViewProps extends WithStyles<typeof styles> {
|
||||||
|
instanceId: number;
|
||||||
|
listen: boolean;
|
||||||
|
midiBinding: MidiBinding;
|
||||||
|
onChange: (instanceId: number, newBinding: MidiBinding) => void;
|
||||||
|
onListen: (instanceId: number, key: string, listenForControl: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface SystemMidiBindingViewState {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const SystemMidiBindingView =
|
||||||
|
withStyles(styles, { withTheme: true })(
|
||||||
|
class extends Component<SystemMidiBindingViewProps, SystemMidiBindingViewState> {
|
||||||
|
|
||||||
|
model: PiPedalModel;
|
||||||
|
|
||||||
|
constructor(props: SystemMidiBindingViewProps) {
|
||||||
|
super(props);
|
||||||
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTypeChange(e: any, extra: any) {
|
||||||
|
let newValue = parseInt(e.target.value);
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.bindingType = newValue;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleNoteChange(e: any, extra: any) {
|
||||||
|
let newValue = parseInt(e.target.value);
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.note = newValue;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleControlChange(e: any, extra: any) {
|
||||||
|
let newValue = parseInt(e.target.value);
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.control = newValue;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleLatchControlTypeChange(e: any, extra: any) {
|
||||||
|
let newValue = parseInt(e.target.value);
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.switchControlType = newValue;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleLinearControlTypeChange(e: any, extra: any) {
|
||||||
|
let newValue = parseInt(e.target.value);
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.linearControlType = newValue;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleMinChange(value: number): void {
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.minValue = value;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleMaxChange(value: number): void {
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.maxValue = value;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
handleScaleChange(value: number): void {
|
||||||
|
let newBinding = this.props.midiBinding.clone();
|
||||||
|
newBinding.rotaryScale = value;
|
||||||
|
this.props.onChange(this.props.instanceId, newBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
generateMidiSelects(): React.ReactNode[] {
|
||||||
|
let result: React.ReactNode[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 127; ++i) {
|
||||||
|
result.push(
|
||||||
|
<MenuItem value={i}>{Utility.midiNoteName(i)}</MenuItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
generateControlSelects(): React.ReactNode[] {
|
||||||
|
|
||||||
|
return Utility.validMidiControllers.map((control) => (
|
||||||
|
<MenuItem key={control.value} value={control.value}>{control.displayName}</MenuItem>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let classes = this.props.classes;
|
||||||
|
let midiBinding = this.props.midiBinding;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", flexDirection: "row", flexWrap: "wrap", justifyContent: "left", alignItems: "center", minHeight: 48 }}>
|
||||||
|
<div className={classes.controlDiv} >
|
||||||
|
<Select variant="standard"
|
||||||
|
style={{ width: 80, }}
|
||||||
|
onChange={(e, extra) => this.handleTypeChange(e, extra)}
|
||||||
|
value={midiBinding.bindingType}
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>None</MenuItem>
|
||||||
|
<MenuItem value={1}>Note</MenuItem>
|
||||||
|
<MenuItem value={2}>Control</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
(midiBinding.bindingType === MidiBinding.BINDING_TYPE_NOTE) &&
|
||||||
|
(
|
||||||
|
<div className={classes.controlDiv} >
|
||||||
|
<Select variant="standard"
|
||||||
|
style={{ width: 80, verticalAlign: 'center' }}
|
||||||
|
onChange={(e, extra) => this.handleNoteChange(e, extra)}
|
||||||
|
value={midiBinding.note}
|
||||||
|
|
||||||
|
>
|
||||||
|
{
|
||||||
|
this.generateMidiSelects()
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
(midiBinding.bindingType === MidiBinding.BINDING_TYPE_CONTROL) &&
|
||||||
|
(
|
||||||
|
<div className={classes.controlDiv} >
|
||||||
|
|
||||||
|
<Select variant="standard"
|
||||||
|
style={{ width: 80 }}
|
||||||
|
onChange={(e, extra) => this.handleControlChange(e, extra)}
|
||||||
|
value={midiBinding.control}
|
||||||
|
renderValue={(value) => { return "CC-" + value }}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
this.generateControlSelects()
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
if (this.props.listen) {
|
||||||
|
this.props.onListen(-2, "", false)
|
||||||
|
} else {
|
||||||
|
this.props.onListen(this.props.instanceId, this.props.midiBinding.symbol, false)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
size="large">
|
||||||
|
{this.props.listen ? (
|
||||||
|
<MicOutlinedIcon />
|
||||||
|
) : (
|
||||||
|
<MicNoneOutlinedIcon />
|
||||||
|
)}
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default SystemMidiBindingView;
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2023 Robin E. R. Davies
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import React, { SyntheticEvent } from 'react';
|
||||||
|
import DialogEx from './DialogEx';
|
||||||
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
|
import { PiPedalModel, PiPedalModelFactory, ListenHandle } from './PiPedalModel';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import { Theme } from '@mui/material/styles';
|
||||||
|
import { WithStyles } from '@mui/styles';
|
||||||
|
import createStyles from '@mui/styles/createStyles';
|
||||||
|
import withStyles from '@mui/styles/withStyles';
|
||||||
|
import AppBar from '@mui/material/AppBar';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import MidiBinding from './MidiBinding';
|
||||||
|
import SystemMidiBindingView from './SystemMidiBindingView';
|
||||||
|
import Snackbar from '@mui/material/Snackbar';
|
||||||
|
|
||||||
|
const styles = (theme: Theme) => createStyles({
|
||||||
|
dialogAppBar: {
|
||||||
|
position: 'relative',
|
||||||
|
top: 0, left: 0
|
||||||
|
},
|
||||||
|
dialogTitle: {
|
||||||
|
marginLeft: theme.spacing(2),
|
||||||
|
flex: "1 1 auto",
|
||||||
|
},
|
||||||
|
pluginTable: {
|
||||||
|
border: "collapse",
|
||||||
|
width: "100%",
|
||||||
|
|
||||||
|
},
|
||||||
|
pluginHead: {
|
||||||
|
borderTop: "1pt #DDD solid", paddingLeft: 22, paddingRight: 22
|
||||||
|
},
|
||||||
|
bindingTd: {
|
||||||
|
verticalAlign: "top",
|
||||||
|
paddingLeft: 12, paddingBottom: 8
|
||||||
|
},
|
||||||
|
nameTd: {
|
||||||
|
paddingLeft: 16,
|
||||||
|
verticalAlign: "top",
|
||||||
|
paddingTop: 12
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export interface SystemMidiBindingDialogProps extends WithStyles<typeof styles> {
|
||||||
|
open: boolean,
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
class BindingEntry {
|
||||||
|
constructor(
|
||||||
|
displayName: string,
|
||||||
|
instanceId: number,
|
||||||
|
midiBinding: MidiBinding,
|
||||||
|
) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
this.instanceId = instanceId;
|
||||||
|
this.midiBinding = midiBinding;
|
||||||
|
}
|
||||||
|
displayName: string;
|
||||||
|
instanceId: number;
|
||||||
|
midiBinding: MidiBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SystemMidiBindingDialogState {
|
||||||
|
listenInstanceId: number;
|
||||||
|
listenSymbol: string;
|
||||||
|
listenSnackbarOpen: boolean;
|
||||||
|
systemMidiBindings: BindingEntry[];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SystemMidiBindingDialog =
|
||||||
|
withStyles(styles, { withTheme: true })(
|
||||||
|
class extends ResizeResponsiveComponent<SystemMidiBindingDialogProps, SystemMidiBindingDialogState> {
|
||||||
|
|
||||||
|
model: PiPedalModel;
|
||||||
|
|
||||||
|
constructor(props: SystemMidiBindingDialogProps) {
|
||||||
|
super(props);
|
||||||
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
|
this.state = {
|
||||||
|
listenInstanceId: -2,
|
||||||
|
listenSymbol: "",
|
||||||
|
listenSnackbarOpen: false,
|
||||||
|
systemMidiBindings: this.createBindings()
|
||||||
|
};
|
||||||
|
this.handleClose = this.handleClose.bind(this);
|
||||||
|
this.onMidiBindingsChanged = this.onMidiBindingsChanged.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
createBindings(): BindingEntry[] {
|
||||||
|
let result: BindingEntry[] = [];
|
||||||
|
for (var item of this.model.systemMidiBindings.get())
|
||||||
|
{
|
||||||
|
let displayName = "";
|
||||||
|
let instanceId = -1;
|
||||||
|
|
||||||
|
if (item.symbol === "prevProgram")
|
||||||
|
{
|
||||||
|
displayName = "Previous Preset";
|
||||||
|
instanceId = 1;
|
||||||
|
} else if (item.symbol === "nextProgram")
|
||||||
|
{
|
||||||
|
displayName = "Next Preset";
|
||||||
|
instanceId = 2;
|
||||||
|
}
|
||||||
|
if (instanceId !== -1)
|
||||||
|
{
|
||||||
|
result.push(new BindingEntry(displayName,instanceId,item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
mounted: boolean = false;
|
||||||
|
|
||||||
|
hasHooks: boolean = false;
|
||||||
|
|
||||||
|
handleClose() {
|
||||||
|
this.cancelListenForControl();
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
listenTimeoutHandle?: NodeJS.Timeout;
|
||||||
|
|
||||||
|
listenHandle?: ListenHandle;
|
||||||
|
|
||||||
|
cancelListenForControl() {
|
||||||
|
if (this.listenTimeoutHandle) {
|
||||||
|
clearTimeout(this.listenTimeoutHandle);
|
||||||
|
this.listenTimeoutHandle = undefined;
|
||||||
|
}
|
||||||
|
if (this.listenHandle)
|
||||||
|
{
|
||||||
|
this.model.cancelListenForMidiEvent(this.listenHandle)
|
||||||
|
this.listenHandle = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ listenInstanceId: -2, listenSymbol: "" });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
handleListenSucceeded(instanceId: number, symbol: string, isNote: boolean, noteOrControl: number)
|
||||||
|
{
|
||||||
|
this.cancelListenForControl();
|
||||||
|
|
||||||
|
for (var binding of this.state.systemMidiBindings)
|
||||||
|
{
|
||||||
|
if (binding.instanceId === instanceId)
|
||||||
|
{
|
||||||
|
let newBinding = binding.midiBinding.clone();
|
||||||
|
|
||||||
|
if (isNote) {
|
||||||
|
newBinding.bindingType = MidiBinding.BINDING_TYPE_NOTE;
|
||||||
|
newBinding.note = noteOrControl;
|
||||||
|
} else {
|
||||||
|
newBinding.bindingType = MidiBinding.BINDING_TYPE_CONTROL;
|
||||||
|
newBinding.control = noteOrControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.model.setSystemMidiBinding(instanceId,newBinding);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleListenForControl(instanceId: number, symbol: string, listenForControl: boolean): void {
|
||||||
|
this.cancelListenForControl();
|
||||||
|
this.setState({ listenInstanceId: instanceId, listenSymbol: symbol, listenSnackbarOpen: true });
|
||||||
|
this.listenTimeoutHandle = setTimeout(() => {
|
||||||
|
this.cancelListenForControl();
|
||||||
|
}, 8000);
|
||||||
|
|
||||||
|
this.listenHandle = this.model.listenForMidiEvent(listenForControl,
|
||||||
|
(isNote: boolean, noteOrControl: number) => {
|
||||||
|
this.handleListenSucceeded(instanceId,symbol,isNote, noteOrControl);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onWindowSizeChanged(width: number, height: number): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
onMidiBindingsChanged() {
|
||||||
|
this.setState({systemMidiBindings: this.createBindings()});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
super.componentDidMount();
|
||||||
|
this.mounted = true;
|
||||||
|
|
||||||
|
this.model.systemMidiBindings.addOnChangedHandler(this.onMidiBindingsChanged);
|
||||||
|
this.onMidiBindingsChanged();
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
super.componentWillUnmount();
|
||||||
|
|
||||||
|
this.mounted = false;
|
||||||
|
this.model.systemMidiBindings.removeOnChangedHandler(this.onMidiBindingsChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
}
|
||||||
|
handleItemChanged(instanceId: number, newBinding: MidiBinding) {
|
||||||
|
this.model.setSystemMidiBinding(instanceId, newBinding);
|
||||||
|
}
|
||||||
|
generateTable(): React.ReactNode[] {
|
||||||
|
let classes = this.props.classes;
|
||||||
|
let result: React.ReactNode[] = [];
|
||||||
|
|
||||||
|
let items = this.state.systemMidiBindings;
|
||||||
|
|
||||||
|
for (var item of items) {
|
||||||
|
result.push(
|
||||||
|
<tr key={item.instanceId}>
|
||||||
|
<td className={classes.nameTd}>
|
||||||
|
<Typography noWrap style={{ verticalAlign: "center", height: 48 }}>
|
||||||
|
{item.displayName}
|
||||||
|
</Typography>
|
||||||
|
</td>
|
||||||
|
<td className={classes.bindingTd}>
|
||||||
|
<SystemMidiBindingView instanceId={item.instanceId} midiBinding={item.midiBinding}
|
||||||
|
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
||||||
|
if (instanceId === -2)
|
||||||
|
{
|
||||||
|
this.cancelListenForControl();
|
||||||
|
} else {
|
||||||
|
this.handleListenForControl(instanceId, symbol, listenForControl);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
listen={item.instanceId === this.state.listenInstanceId && this.state.listenSymbol === item.midiBinding.symbol}
|
||||||
|
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
supressDefault(e: SyntheticEvent) {
|
||||||
|
//e.preventDefault();
|
||||||
|
//e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let props = this.props;
|
||||||
|
let { open, classes } = props;
|
||||||
|
if (!open) {
|
||||||
|
return (<div />);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogEx tag="SystemMidiBindingsDialog" open={open} fullWidth onClose={this.handleClose} aria-labelledby="Rename-dialog-title"
|
||||||
|
fullScreen={true}
|
||||||
|
style={{userSelect: "none"}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
|
||||||
|
<div style={{ flex: "0 0 auto" }}>
|
||||||
|
<AppBar className={classes.dialogAppBar} >
|
||||||
|
<Toolbar>
|
||||||
|
<IconButton
|
||||||
|
edge="start"
|
||||||
|
color="inherit"
|
||||||
|
onClick={this.handleClose}
|
||||||
|
aria-label="back"
|
||||||
|
size="large">
|
||||||
|
<ArrowBackIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h6" className={classes.dialogTitle}>
|
||||||
|
System MIDI Bindings
|
||||||
|
</Typography>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
</div>
|
||||||
|
<div style={{ overflow: "auto", flex: "1 1 auto", width: "100%" }}>
|
||||||
|
<table className={classes.pluginTable} >
|
||||||
|
<colgroup>
|
||||||
|
<col style={{ width: "auto" }} />
|
||||||
|
<col style={{ width: "100%" }} />
|
||||||
|
</colgroup>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{this.generateTable()}
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Snackbar
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'left',
|
||||||
|
}}
|
||||||
|
open={this.state.listenSnackbarOpen}
|
||||||
|
autoHideDuration={1500}
|
||||||
|
onClose={() => this.setState({ listenSnackbarOpen: false })}
|
||||||
|
message="Listening for MIDI input"
|
||||||
|
/>
|
||||||
|
</DialogEx >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default SystemMidiBindingDialog;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2023 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
|
||||||
@@ -17,19 +17,17 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
|
|
||||||
#include "Lv2Log.hpp"
|
#include "Lv2Log.hpp"
|
||||||
|
|
||||||
#include "JackDriver.hpp"
|
#include "JackDriver.hpp"
|
||||||
#include "AlsaDriver.hpp"
|
#include "AlsaDriver.hpp"
|
||||||
|
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
#include "AudioConfig.hpp"
|
#include "AudioConfig.hpp"
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -66,17 +64,17 @@ using namespace pipedal;
|
|||||||
|
|
||||||
const int MIDI_LV2_BUFFER_SIZE = 16 * 1024;
|
const int MIDI_LV2_BUFFER_SIZE = 16 * 1024;
|
||||||
|
|
||||||
|
static void GetCpuFrequency(uint64_t *freqMin, uint64_t *freqMax)
|
||||||
static void GetCpuFrequency(uint64_t*freqMin,uint64_t*freqMax)
|
|
||||||
{
|
{
|
||||||
uint64_t fMax = 0;
|
uint64_t fMax = 0;
|
||||||
uint64_t fMin = UINT64_MAX;
|
uint64_t fMin = UINT64_MAX;
|
||||||
char deviceName[128];
|
char deviceName[128];
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
for (int i = 0; true; ++i)
|
for (int i = 0; true; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
snprintf(deviceName,sizeof(deviceName),"/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq",i);
|
snprintf(deviceName, sizeof(deviceName), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
|
||||||
std::ifstream f(deviceName);
|
std::ifstream f(deviceName);
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
@@ -84,15 +82,19 @@ static void GetCpuFrequency(uint64_t*freqMin,uint64_t*freqMax)
|
|||||||
}
|
}
|
||||||
uint64_t freq;
|
uint64_t freq;
|
||||||
f >> freq;
|
f >> freq;
|
||||||
if (!f) break;
|
if (!f)
|
||||||
if (freq < fMin) fMin = freq;
|
break;
|
||||||
if (freq > fMax) fMax = freq;
|
if (freq < fMin)
|
||||||
|
fMin = freq;
|
||||||
|
if (freq > fMax)
|
||||||
|
fMax = freq;
|
||||||
}
|
}
|
||||||
} catch (const std::exception &)
|
}
|
||||||
|
catch (const std::exception &)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
if (fMin == 0) fMax = 0;
|
if (fMin == 0)
|
||||||
|
fMax = 0;
|
||||||
*freqMin = fMin;
|
*freqMin = fMin;
|
||||||
*freqMax = fMax;
|
*freqMax = fMax;
|
||||||
}
|
}
|
||||||
@@ -102,12 +104,88 @@ static std::string GetGovernor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SystemMidiBinding {
|
||||||
|
private:
|
||||||
|
MidiBinding currentBinding;
|
||||||
|
bool controlState = false;
|
||||||
|
public:
|
||||||
|
void SetBinding(const MidiBinding&binding) { currentBinding = binding; controlState = false; }
|
||||||
|
|
||||||
class JackHostImpl : public JackHost, private AudioDriverHost
|
bool IsMatch(const MidiEvent&event);
|
||||||
|
bool IsTriggered(const MidiEvent&event);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool SystemMidiBinding::IsTriggered(const MidiEvent &event)
|
||||||
|
{
|
||||||
|
switch (currentBinding.bindingType())
|
||||||
|
{
|
||||||
|
case BINDING_TYPE_NOTE:
|
||||||
|
{
|
||||||
|
if (event.size != 3) return false;
|
||||||
|
auto command = event.buffer[0] & 0xF0;
|
||||||
|
if (command != 0x90) return false; // MIDI note on
|
||||||
|
if (event.buffer[1] != currentBinding.note()) return false;
|
||||||
|
return event.buffer[2] != 0; // note-on with velicity of zero is a note-off.
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BINDING_TYPE_CONTROL:
|
||||||
|
{
|
||||||
|
if (event.size != 3) return false;
|
||||||
|
auto command = event.buffer[0] & 0xF0;
|
||||||
|
if (command != 0xB0) return false;
|
||||||
|
if (event.buffer[1] != currentBinding.control()) return false;
|
||||||
|
bool state = event.buffer[2] >= 0x64;
|
||||||
|
if (state != this->controlState)
|
||||||
|
{
|
||||||
|
this->controlState = state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemMidiBinding::IsMatch(const MidiEvent&event)
|
||||||
|
{
|
||||||
|
switch (currentBinding.bindingType())
|
||||||
|
{
|
||||||
|
case BINDING_TYPE_NOTE:
|
||||||
|
{
|
||||||
|
if (event.size != 3) return false;
|
||||||
|
auto command = event.buffer[0] & 0xF0;
|
||||||
|
if (command != 0x80 && command != 0x90) return false; // note on/note off.
|
||||||
|
return event.buffer[1] == currentBinding.note();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BINDING_TYPE_CONTROL:
|
||||||
|
{
|
||||||
|
if (event.size != 3) return false;
|
||||||
|
auto command = event.buffer[0] & 0xF0;
|
||||||
|
if (command != 0xB0) return false;
|
||||||
|
return event.buffer[1] == currentBinding.control();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AudioHostImpl : public AudioHost, private AudioDriverHost
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
IHost *pHost = nullptr;
|
IHost *pHost = nullptr;
|
||||||
|
|
||||||
|
static constexpr size_t DEFERRED_MIDI_BUFFER_SIZE = 1024;
|
||||||
|
|
||||||
|
uint8_t deferredMidiMessages[DEFERRED_MIDI_BUFFER_SIZE];
|
||||||
|
size_t deferredMidiMessageCount;
|
||||||
|
bool midiProgramChangePending = false;
|
||||||
|
int selectedBank = -1;
|
||||||
|
int64_t midiProgramChangeId = 0;
|
||||||
|
|
||||||
class Uris
|
class Uris
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -124,7 +202,6 @@ private:
|
|||||||
atom_Vector = pHost->GetLv2Urid(LV2_ATOM__Vector);
|
atom_Vector = pHost->GetLv2Urid(LV2_ATOM__Vector);
|
||||||
atom_Object = pHost->GetLv2Urid(LV2_ATOM__Object);
|
atom_Object = pHost->GetLv2Urid(LV2_ATOM__Object);
|
||||||
|
|
||||||
|
|
||||||
atom_Sequence = pHost->GetLv2Urid(LV2_ATOM__Sequence);
|
atom_Sequence = pHost->GetLv2Urid(LV2_ATOM__Sequence);
|
||||||
atom_Chunk = pHost->GetLv2Urid(LV2_ATOM__Chunk);
|
atom_Chunk = pHost->GetLv2Urid(LV2_ATOM__Chunk);
|
||||||
atom_URID = pHost->GetLv2Urid(LV2_ATOM__URID);
|
atom_URID = pHost->GetLv2Urid(LV2_ATOM__URID);
|
||||||
@@ -135,12 +212,11 @@ private:
|
|||||||
patch_body = pHost->GetLv2Urid(LV2_PATCH__body);
|
patch_body = pHost->GetLv2Urid(LV2_PATCH__body);
|
||||||
patch_subject = pHost->GetLv2Urid(LV2_PATCH__subject);
|
patch_subject = pHost->GetLv2Urid(LV2_PATCH__subject);
|
||||||
patch_property = pHost->GetLv2Urid(LV2_PATCH__property);
|
patch_property = pHost->GetLv2Urid(LV2_PATCH__property);
|
||||||
//patch_accept = pHost->GetLv2Urid(LV2_PATCH__accept);
|
// patch_accept = pHost->GetLv2Urid(LV2_PATCH__accept);
|
||||||
patch_value = pHost->GetLv2Urid(LV2_PATCH__value);
|
patch_value = pHost->GetLv2Urid(LV2_PATCH__value);
|
||||||
unitsFrame = pHost->GetLv2Urid(LV2_UNITS__frame);
|
unitsFrame = pHost->GetLv2Urid(LV2_UNITS__frame);
|
||||||
|
|
||||||
}
|
}
|
||||||
//LV2_URID patch_accept;
|
// LV2_URID patch_accept;
|
||||||
|
|
||||||
LV2_URID unitsFrame;
|
LV2_URID unitsFrame;
|
||||||
LV2_URID pluginUri;
|
LV2_URID pluginUri;
|
||||||
@@ -171,16 +247,14 @@ private:
|
|||||||
|
|
||||||
Uris uris;
|
Uris uris;
|
||||||
|
|
||||||
|
AudioDriver *audioDriver = nullptr;
|
||||||
|
|
||||||
AudioDriver*audioDriver = nullptr;
|
|
||||||
|
|
||||||
inherit_priority_recursive_mutex mutex;
|
inherit_priority_recursive_mutex mutex;
|
||||||
int64_t overrunGracePeriodSamples = 0;
|
int64_t overrunGracePeriodSamples = 0;
|
||||||
|
|
||||||
IJackHostCallbacks *pNotifyCallbacks = nullptr;
|
IAudioHostCallbacks *pNotifyCallbacks = nullptr;
|
||||||
|
|
||||||
virtual void SetNotificationCallbacks(IJackHostCallbacks *pNotifyCallbacks)
|
virtual void SetNotificationCallbacks(IAudioHostCallbacks *pNotifyCallbacks)
|
||||||
{
|
{
|
||||||
this->pNotifyCallbacks = pNotifyCallbacks;
|
this->pNotifyCallbacks = pNotifyCallbacks;
|
||||||
}
|
}
|
||||||
@@ -190,13 +264,16 @@ private:
|
|||||||
RingBuffer<true, false> inputRingBuffer;
|
RingBuffer<true, false> inputRingBuffer;
|
||||||
RingBuffer<false, true> outputRingBuffer;
|
RingBuffer<false, true> outputRingBuffer;
|
||||||
|
|
||||||
RingBufferWriter<true,false> x;
|
RingBufferWriter<true, false> x;
|
||||||
|
|
||||||
RealtimeRingBufferReader realtimeReader;
|
RealtimeRingBufferReader realtimeReader;
|
||||||
RealtimeRingBufferWriter realtimeWriter;
|
RealtimeRingBufferWriter realtimeWriter;
|
||||||
HostRingBufferReader hostReader;
|
HostRingBufferReader hostReader;
|
||||||
HostRingBufferWriter hostWriter;
|
HostRingBufferWriter hostWriter;
|
||||||
|
|
||||||
|
SystemMidiBinding nextMidiBinding;
|
||||||
|
SystemMidiBinding prevMidiBinding;
|
||||||
|
|
||||||
JackChannelSelection channelSelection;
|
JackChannelSelection channelSelection;
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
|
||||||
@@ -213,27 +290,25 @@ private:
|
|||||||
std::atomic<std::chrono::system_clock::time_point> lastUnderrunTime =
|
std::atomic<std::chrono::system_clock::time_point> lastUnderrunTime =
|
||||||
std::chrono::system_clock::from_time_t(0);
|
std::chrono::system_clock::from_time_t(0);
|
||||||
|
|
||||||
|
std::string GetAtomObjectType(uint8_t *pData)
|
||||||
std::string GetAtomObjectType(uint8_t*pData)
|
|
||||||
{
|
{
|
||||||
LV2_Atom_Object *pAtom = (LV2_Atom_Object*)pData;
|
LV2_Atom_Object *pAtom = (LV2_Atom_Object *)pData;
|
||||||
if (pAtom->atom.type != uris.atom_Object)
|
if (pAtom->atom.type != uris.atom_Object)
|
||||||
{
|
{
|
||||||
throw std::invalid_argument("Not an Lv2 Object");
|
throw std::invalid_argument("Not an Lv2 Object");
|
||||||
}
|
}
|
||||||
return pHost->Lv2UriudToString(pAtom->body.otype);
|
return pHost->Lv2UriudToString(pAtom->body.otype);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteAtom(json_writer &writer, LV2_Atom*pAtom);
|
void WriteAtom(json_writer &writer, LV2_Atom *pAtom);
|
||||||
|
|
||||||
std::string AtomToJson(uint8_t*pData)
|
std::string AtomToJson(uint8_t *pData)
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
json_writer writer(s);
|
json_writer writer(s);
|
||||||
LV2_Atom *pAtom = (LV2_Atom*)pData;
|
LV2_Atom *pAtom = (LV2_Atom *)pData;
|
||||||
|
|
||||||
WriteAtom(writer,pAtom);
|
WriteAtom(writer, pAtom);
|
||||||
return s.str();
|
return s.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +318,6 @@ private:
|
|||||||
this->lastUnderrunTime = std::chrono::system_clock ::now();
|
this->lastUnderrunTime = std::chrono::system_clock ::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void Close()
|
virtual void Close()
|
||||||
{
|
{
|
||||||
std::lock_guard guard(mutex);
|
std::lock_guard guard(mutex);
|
||||||
@@ -286,13 +360,11 @@ private:
|
|||||||
this->inputRingBuffer.reset();
|
this->inputRingBuffer.reset();
|
||||||
this->outputRingBuffer.reset();
|
this->outputRingBuffer.reset();
|
||||||
|
|
||||||
|
|
||||||
for (size_t i = 0; i < midiLv2Buffers.size(); ++i)
|
for (size_t i = 0; i < midiLv2Buffers.size(); ++i)
|
||||||
{
|
{
|
||||||
delete[] midiLv2Buffers[i];
|
delete[] midiLv2Buffers[i];
|
||||||
}
|
}
|
||||||
midiLv2Buffers.resize(0);
|
midiLv2Buffers.resize(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZeroBuffer(float *buffer, size_t nframes)
|
void ZeroBuffer(float *buffer, size_t nframes)
|
||||||
@@ -341,6 +413,9 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void SetSystemMidiBindings(const std::vector<MidiBinding>&bindings);
|
||||||
|
|
||||||
void writeVu()
|
void writeVu()
|
||||||
{
|
{
|
||||||
// throttling: we send one; but won't send another until the host thread
|
// throttling: we send one; but won't send another until the host thread
|
||||||
@@ -459,6 +534,16 @@ private:
|
|||||||
this->realtimeMonitorPortSubscriptions = pSubscriptions;
|
this->realtimeMonitorPortSubscriptions = pSubscriptions;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case RingBufferCommand::AckMidiProgramChange:
|
||||||
|
{
|
||||||
|
int64_t requestId;
|
||||||
|
realtimeReader.readComplete(&requestId);
|
||||||
|
if (requestId == this->midiProgramChangeId)
|
||||||
|
{
|
||||||
|
this->midiProgramChangePending = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case RingBufferCommand::SetVuSubscriptions:
|
case RingBufferCommand::SetVuSubscriptions:
|
||||||
{
|
{
|
||||||
RealtimeVuBuffers *configuration;
|
RealtimeVuBuffers *configuration;
|
||||||
@@ -485,6 +570,8 @@ private:
|
|||||||
ReplaceEffectBody body;
|
ReplaceEffectBody body;
|
||||||
realtimeReader.readComplete(&body);
|
realtimeReader.readComplete(&body);
|
||||||
|
|
||||||
|
if (body.effect != nullptr)
|
||||||
|
{
|
||||||
auto oldValue = this->realtimeActivePedalBoard;
|
auto oldValue = this->realtimeActivePedalBoard;
|
||||||
this->realtimeActivePedalBoard = body.effect;
|
this->realtimeActivePedalBoard = body.effect;
|
||||||
|
|
||||||
@@ -493,6 +580,7 @@ private:
|
|||||||
// invalidate the possibly no-good subscriptions. Model will update them shortly.
|
// invalidate the possibly no-good subscriptions. Model will update them shortly.
|
||||||
freeRealtimeVuConfiguration();
|
freeRealtimeVuConfiguration();
|
||||||
freeRealtimeMonitorPortSubscriptions();
|
freeRealtimeMonitorPortSubscriptions();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -502,38 +590,25 @@ private:
|
|||||||
reEntered = false;
|
reEntered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void AckMidiProgramRequest(uint64_t requestId)
|
||||||
|
{
|
||||||
|
hostWriter.AckMidiProgramRequest(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
void OnMidiValueChanged(uint64_t instanceId, int controlIndex, float value)
|
void OnMidiValueChanged(uint64_t instanceId, int controlIndex, float value)
|
||||||
{
|
{
|
||||||
realtimeWriter.MidiValueChanged(instanceId, controlIndex, value);
|
realtimeWriter.MidiValueChanged(instanceId, controlIndex, value);
|
||||||
}
|
}
|
||||||
static void fnMidiValueChanged(void *data, uint64_t instanceId, int controlIndex, float value)
|
static void fnMidiValueChanged(void *data, uint64_t instanceId, int controlIndex, float value)
|
||||||
{
|
{
|
||||||
((JackHostImpl *)data)->OnMidiValueChanged(instanceId, controlIndex, value);
|
((AudioHostImpl *)data)->OnMidiValueChanged(instanceId, controlIndex, value);
|
||||||
}
|
}
|
||||||
void ProcessJackMidi()
|
static bool isBankChange(MidiEvent &event)
|
||||||
{
|
{
|
||||||
Lv2EventBufferWriter eventBufferWriter(this->eventBufferUrids);
|
return (event.size == 3 && event.buffer[0] == 0xB0 && event.buffer[1] == 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
size_t midiInputBufferCount = audioDriver->MidiInputBufferCount();
|
bool onMidiEvent(Lv2EventBufferWriter&eventBufferWriter, Lv2EventBufferWriter::LV2_EvBuf_Iterator &iterator, MidiEvent&event)
|
||||||
|
|
||||||
audioDriver->FillMidiBuffers();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < midiInputBufferCount; ++i)
|
|
||||||
{
|
|
||||||
|
|
||||||
void *portBuffer = audioDriver->GetMidiInputBuffer(i,0);
|
|
||||||
if (portBuffer)
|
|
||||||
{
|
|
||||||
uint8_t *lv2Buffer = this->midiLv2Buffers[i];
|
|
||||||
size_t n = audioDriver->GetMidiInputEventCount(portBuffer);
|
|
||||||
|
|
||||||
eventBufferWriter.Reset(lv2Buffer, MIDI_LV2_BUFFER_SIZE);
|
|
||||||
auto iterator = eventBufferWriter.begin();
|
|
||||||
|
|
||||||
for (size_t frame = 0; frame < n; ++frame)
|
|
||||||
{
|
|
||||||
MidiEvent event;
|
|
||||||
if (audioDriver->GetMidiInputEvent(&event,portBuffer,frame))
|
|
||||||
{
|
{
|
||||||
eventBufferWriter.writeMidiEvent(iterator, 0, event.size, event.buffer);
|
eventBufferWriter.writeMidiEvent(iterator, 0, event.size, event.buffer);
|
||||||
|
|
||||||
@@ -551,6 +626,102 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessMidiInput()
|
||||||
|
{
|
||||||
|
Lv2EventBufferWriter eventBufferWriter(this->eventBufferUrids);
|
||||||
|
|
||||||
|
size_t midiInputBufferCount = audioDriver->MidiInputBufferCount();
|
||||||
|
|
||||||
|
audioDriver->FillMidiBuffers();
|
||||||
|
|
||||||
|
for (size_t midiDeviceIx = 0; midiDeviceIx < midiInputBufferCount; ++midiDeviceIx)
|
||||||
|
{
|
||||||
|
|
||||||
|
void *portBuffer = audioDriver->GetMidiInputBuffer(midiDeviceIx, 0);
|
||||||
|
if (portBuffer)
|
||||||
|
{
|
||||||
|
uint8_t *lv2Buffer = this->midiLv2Buffers[midiDeviceIx];
|
||||||
|
size_t n = audioDriver->GetMidiInputEventCount(portBuffer);
|
||||||
|
|
||||||
|
eventBufferWriter.Reset(lv2Buffer, MIDI_LV2_BUFFER_SIZE);
|
||||||
|
Lv2EventBufferWriter::LV2_EvBuf_Iterator iterator = eventBufferWriter.begin();
|
||||||
|
MidiEvent event;
|
||||||
|
|
||||||
|
|
||||||
|
// write all deferred midi messages.
|
||||||
|
if (deferredMidiMessageCount != 0 && !midiProgramChangePending)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < deferredMidiMessageCount; /**/)
|
||||||
|
{
|
||||||
|
int8_t deviceIndex = deferredMidiMessages[i++];
|
||||||
|
int8_t messageCount = deferredMidiMessages[i++];
|
||||||
|
if (deviceIndex == midiDeviceIx)
|
||||||
|
{
|
||||||
|
event.size = messageCount;
|
||||||
|
event.buffer = deferredMidiMessages +i;
|
||||||
|
event.time = 0;
|
||||||
|
|
||||||
|
onMidiEvent(eventBufferWriter,iterator,event);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += messageCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t frame = 0; frame < n; ++frame)
|
||||||
|
{
|
||||||
|
if (audioDriver->GetMidiInputEvent(&event, portBuffer, frame))
|
||||||
|
{
|
||||||
|
uint8_t midiCommand = (uint8_t)(event.buffer[0] & 0xF0);
|
||||||
|
if (midiCommand == 0xC0) // midi program change.
|
||||||
|
{
|
||||||
|
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
|
||||||
|
midiProgramChangePending = true;
|
||||||
|
|
||||||
|
this->realtimeWriter.OnMidiProgramChange(++(this->midiProgramChangeId), selectedBank,event.buffer[1]);
|
||||||
|
}
|
||||||
|
else if (isBankChange(event))
|
||||||
|
{
|
||||||
|
this->selectedBank = event.buffer[2];
|
||||||
|
} else if (this->nextMidiBinding.IsMatch(event))
|
||||||
|
{
|
||||||
|
if (nextMidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
midiProgramChangePending = true;
|
||||||
|
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId),1);
|
||||||
|
}
|
||||||
|
} else if (this->prevMidiBinding.IsMatch(event))
|
||||||
|
{
|
||||||
|
if (prevMidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
midiProgramChangePending = true;
|
||||||
|
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId),-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (midiProgramChangePending)
|
||||||
|
{
|
||||||
|
// defer the message for processing after the program change has completed.
|
||||||
|
if (event.size > 0
|
||||||
|
&& event.size < 128
|
||||||
|
&& event.size + 2 + this->deferredMidiMessageCount < DEFERRED_MIDI_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
this->deferredMidiMessages[deferredMidiMessageCount++] = midiDeviceIx;
|
||||||
|
this->deferredMidiMessages[deferredMidiMessageCount++] = (uint8_t)event.size;
|
||||||
|
for (size_t i = 0; i < event.size; ++i)
|
||||||
|
{
|
||||||
|
this->deferredMidiMessages[deferredMidiMessageCount++] = event.buffer[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onMidiEvent(eventBufferWriter,iterator,event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,15 +734,14 @@ private:
|
|||||||
|
|
||||||
bool IsAudioActive()
|
bool IsAudioActive()
|
||||||
{
|
{
|
||||||
std::lock_guard lock { audioStoppedMutex};
|
std::lock_guard lock{audioStoppedMutex};
|
||||||
return this->active;
|
return this->active;
|
||||||
}
|
}
|
||||||
virtual void OnAudioStopped()
|
virtual void OnAudioStopped()
|
||||||
{
|
{
|
||||||
std::lock_guard lock { audioStoppedMutex};
|
std::lock_guard lock{audioStoppedMutex};
|
||||||
this->active = false;
|
this->active = false;
|
||||||
Lv2Log::info("Audio stopped.");
|
Lv2Log::info("Audio stopped.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnProcess(size_t nframes)
|
virtual void OnProcess(size_t nframes)
|
||||||
@@ -589,7 +759,7 @@ private:
|
|||||||
Lv2PedalBoard *pedalBoard = this->realtimeActivePedalBoard;
|
Lv2PedalBoard *pedalBoard = this->realtimeActivePedalBoard;
|
||||||
if (pedalBoard != nullptr)
|
if (pedalBoard != nullptr)
|
||||||
{
|
{
|
||||||
ProcessJackMidi();
|
ProcessMidiInput();
|
||||||
float *inputBuffers[4];
|
float *inputBuffers[4];
|
||||||
float *outputBuffers[4];
|
float *outputBuffers[4];
|
||||||
bool buffersValid = true;
|
bool buffersValid = true;
|
||||||
@@ -607,7 +777,7 @@ private:
|
|||||||
|
|
||||||
for (int i = 0; i < audioDriver->OutputBufferCount(); ++i)
|
for (int i = 0; i < audioDriver->OutputBufferCount(); ++i)
|
||||||
{
|
{
|
||||||
float *output = audioDriver->GetOutputBuffer(i,nframes);
|
float *output = audioDriver->GetOutputBuffer(i, nframes);
|
||||||
if (output == nullptr)
|
if (output == nullptr)
|
||||||
{
|
{
|
||||||
buffersValid = false;
|
buffersValid = false;
|
||||||
@@ -622,7 +792,7 @@ private:
|
|||||||
pedalBoard->ResetAtomBuffers();
|
pedalBoard->ResetAtomBuffers();
|
||||||
pedalBoard->ProcessParameterRequests(pParameterRequests);
|
pedalBoard->ProcessParameterRequests(pParameterRequests);
|
||||||
|
|
||||||
processed = pedalBoard->Run(inputBuffers, outputBuffers, (uint32_t)nframes,&realtimeWriter);
|
processed = pedalBoard->Run(inputBuffers, outputBuffers, (uint32_t)nframes, &realtimeWriter);
|
||||||
if (processed)
|
if (processed)
|
||||||
{
|
{
|
||||||
if (this->realtimeVuBuffers != nullptr)
|
if (this->realtimeVuBuffers != nullptr)
|
||||||
@@ -664,18 +834,16 @@ private:
|
|||||||
this->underruns = 0;
|
this->underruns = 0;
|
||||||
}
|
}
|
||||||
this->currentSample += nframes;
|
this->currentSample += nframes;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
Lv2Log::error("Fatal error while processing jack audio. (%s)", e.what());
|
Lv2Log::error("Fatal error while processing jack audio. (%s)", e.what());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JackHostImpl(IHost *pHost)
|
AudioHostImpl(IHost *pHost)
|
||||||
: inputRingBuffer(RING_BUFFER_SIZE),
|
: inputRingBuffer(RING_BUFFER_SIZE),
|
||||||
outputRingBuffer(RING_BUFFER_SIZE),
|
outputRingBuffer(RING_BUFFER_SIZE),
|
||||||
realtimeReader(&this->inputRingBuffer),
|
realtimeReader(&this->inputRingBuffer),
|
||||||
@@ -687,21 +855,19 @@ public:
|
|||||||
uris(pHost)
|
uris(pHost)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if JACK_HOST
|
#if JACK_HOST
|
||||||
audioDriver = CreateJackDriver(this);
|
audioDriver = CreateJackDriver(this);
|
||||||
#endif
|
#endif
|
||||||
#if ALSA_HOST
|
#if ALSA_HOST
|
||||||
audioDriver = CreateAlsaDriver(this);
|
audioDriver = CreateAlsaDriver(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
virtual ~JackHostImpl()
|
virtual ~AudioHostImpl()
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
CleanRestartThreads(true);
|
CleanRestartThreads(true);
|
||||||
|
|
||||||
delete audioDriver;
|
delete audioDriver;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual JackConfiguration GetServerConfiguration()
|
virtual JackConfiguration GetServerConfiguration()
|
||||||
@@ -717,6 +883,8 @@ public:
|
|||||||
return this->sampleRate;
|
return this->sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OnAudioComplete()
|
void OnAudioComplete()
|
||||||
{
|
{
|
||||||
// there is actually no compelling circumstance in which this should ever happen.
|
// there is actually no compelling circumstance in which this should ever happen.
|
||||||
@@ -878,7 +1046,8 @@ public:
|
|||||||
this->pNotifyCallbacks->OnNotifyVusSubscription(*updates);
|
this->pNotifyCallbacks->OnNotifyVusSubscription(*updates);
|
||||||
}
|
}
|
||||||
this->hostWriter.AckVuUpdate(); // please sir, can I have some more?
|
this->hostWriter.AckVuUpdate(); // please sir, can I have some more?
|
||||||
} else if (command == RingBufferCommand::AtomOutput)
|
}
|
||||||
|
else if (command == RingBufferCommand::AtomOutput)
|
||||||
{
|
{
|
||||||
uint64_t instanceId;
|
uint64_t instanceId;
|
||||||
hostReader.read(&instanceId);
|
hostReader.read(&instanceId);
|
||||||
@@ -888,15 +1057,14 @@ public:
|
|||||||
{
|
{
|
||||||
atomBuffer.resize(extraBytes);
|
atomBuffer.resize(extraBytes);
|
||||||
}
|
}
|
||||||
hostReader.read(extraBytes,&(atomBuffer[0]));
|
hostReader.read(extraBytes, &(atomBuffer[0]));
|
||||||
|
|
||||||
|
|
||||||
IEffect *pEffect = currentPedalBoard->GetEffect(instanceId);
|
IEffect *pEffect = currentPedalBoard->GetEffect(instanceId);
|
||||||
if (pEffect != nullptr &&this->pNotifyCallbacks && listenForAtomOutput)
|
if (pEffect != nullptr && this->pNotifyCallbacks && listenForAtomOutput)
|
||||||
{
|
{
|
||||||
std::string atomType = GetAtomObjectType(&atomBuffer[0]);
|
std::string atomType = GetAtomObjectType(&atomBuffer[0]);
|
||||||
auto json = AtomToJson(&(atomBuffer[0]));
|
auto json = AtomToJson(&(atomBuffer[0]));
|
||||||
this->pNotifyCallbacks->OnNotifyAtomOutput(instanceId,atomType,json);
|
this->pNotifyCallbacks->OnNotifyAtomOutput(instanceId, atomType, json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (command == RingBufferCommand::FreeVuSubscriptions)
|
else if (command == RingBufferCommand::FreeVuSubscriptions)
|
||||||
@@ -923,6 +1091,16 @@ public:
|
|||||||
hostReader.read(&body);
|
hostReader.read(&body);
|
||||||
OnAudioComplete();
|
OnAudioComplete();
|
||||||
return;
|
return;
|
||||||
|
} else if (command == RingBufferCommand::MidiProgramChange)
|
||||||
|
{
|
||||||
|
RealtimeMidiProgramRequest programRequest;
|
||||||
|
hostReader.read(&programRequest);
|
||||||
|
OnMidiProgramRequest(programRequest);
|
||||||
|
} else if (command == RingBufferCommand::NextMidiProgram)
|
||||||
|
{
|
||||||
|
RealtimeNextMidiProgramRequest request;
|
||||||
|
hostReader.read(&request);
|
||||||
|
pNotifyCallbacks->OnNotifyNextMidiProgram(request);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -982,13 +1160,11 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Open(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
||||||
virtual void Open(const JackServerSettings &jackServerSettings,const JackChannelSelection &channelSelection)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
std::lock_guard guard(mutex);
|
std::lock_guard guard(mutex);
|
||||||
if (channelSelection.GetInputAudioPorts().size() == 0
|
if (channelSelection.GetInputAudioPorts().size() == 0 || channelSelection.GetOutputAudioPorts().size() == 0)
|
||||||
|| channelSelection.GetOutputAudioPorts().size() == 0)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1009,27 +1185,25 @@ public:
|
|||||||
|
|
||||||
StartReaderThread();
|
StartReaderThread();
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
|
|
||||||
audioDriver->Open(jackServerSettings,this->channelSelection);
|
audioDriver->Open(jackServerSettings, this->channelSelection);
|
||||||
|
|
||||||
this->sampleRate = audioDriver->GetSampleRate();
|
this->sampleRate = audioDriver->GetSampleRate();
|
||||||
|
|
||||||
this->overrunGracePeriodSamples = (uint64_t)(((uint64_t)this->sampleRate)*OVERRUN_GRACE_PERIOD_S);
|
this->overrunGracePeriodSamples = (uint64_t)(((uint64_t)this->sampleRate) * OVERRUN_GRACE_PERIOD_S);
|
||||||
this->vuSamplesPerUpdate = (size_t)(sampleRate * VU_UPDATE_RATE_S);
|
this->vuSamplesPerUpdate = (size_t)(sampleRate * VU_UPDATE_RATE_S);
|
||||||
|
|
||||||
|
|
||||||
midiLv2Buffers.resize(audioDriver->MidiInputBufferCount());
|
midiLv2Buffers.resize(audioDriver->MidiInputBufferCount());
|
||||||
for (size_t i = 0; i < audioDriver->MidiInputBufferCount(); ++i)
|
for (size_t i = 0; i < audioDriver->MidiInputBufferCount(); ++i)
|
||||||
{
|
{
|
||||||
midiLv2Buffers[i] = AllocateRealtimeBuffer(MIDI_LV2_BUFFER_SIZE);
|
midiLv2Buffers[i] = AllocateRealtimeBuffer(MIDI_LV2_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
active = true;
|
active = true;
|
||||||
audioDriver->Activate();
|
audioDriver->Activate();
|
||||||
Lv2Log::info("Audio started.");
|
Lv2Log::info("Audio started.");
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@@ -1040,6 +1214,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnMidiProgramRequest(RealtimeMidiProgramRequest &programRequest)
|
||||||
|
{
|
||||||
|
pNotifyCallbacks->OnNotifyMidiProgramChange(programRequest);
|
||||||
|
}
|
||||||
void OnActivePedalBoardReleased(Lv2PedalBoard *pPedalBoard)
|
void OnActivePedalBoardReleased(Lv2PedalBoard *pPedalBoard)
|
||||||
{
|
{
|
||||||
if (pPedalBoard)
|
if (pPedalBoard)
|
||||||
@@ -1207,7 +1385,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
class RestartThread
|
class RestartThread
|
||||||
{
|
{
|
||||||
JackHostImpl *this_;
|
AudioHostImpl *this_;
|
||||||
JackServerSettings jackServerSettings;
|
JackServerSettings jackServerSettings;
|
||||||
std::function<void(bool success, const std::string &errorMessage)> onComplete;
|
std::function<void(bool success, const std::string &errorMessage)> onComplete;
|
||||||
std::atomic<bool> isComplete = false;
|
std::atomic<bool> isComplete = false;
|
||||||
@@ -1215,7 +1393,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
RestartThread(
|
RestartThread(
|
||||||
JackHostImpl *host,
|
AudioHostImpl *host,
|
||||||
const JackServerSettings &jackServerSettings_,
|
const JackServerSettings &jackServerSettings_,
|
||||||
std::function<void(bool success, const std::string &errorMessage)> onComplete_)
|
std::function<void(bool success, const std::string &errorMessage)> onComplete_)
|
||||||
: this_(host),
|
: this_(host),
|
||||||
@@ -1234,19 +1412,20 @@ private:
|
|||||||
{
|
{
|
||||||
this_->restarting = true;
|
this_->restarting = true;
|
||||||
// this_->Close(); (JackServerConfiguration now does a service restart.)
|
// this_->Close(); (JackServerConfiguration now does a service restart.)
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
AdminClient client;
|
AdminClient client;
|
||||||
|
|
||||||
client.SetJackServerConfiguration(jackServerSettings);
|
client.SetJackServerConfiguration(jackServerSettings);
|
||||||
|
|
||||||
|
// this_->Open(this_->channelSelection);
|
||||||
//this_->Open(this_->channelSelection);
|
|
||||||
this_->restarting = false;
|
this_->restarting = false;
|
||||||
onComplete(true, "");
|
onComplete(true, "");
|
||||||
isComplete = true;
|
isComplete = true;
|
||||||
} catch (const std::exception &e)
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
onComplete(false,e.what());
|
onComplete(false, e.what());
|
||||||
this_->restarting = false;
|
this_->restarting = false;
|
||||||
isComplete = true;
|
isComplete = true;
|
||||||
}
|
}
|
||||||
@@ -1349,7 +1528,7 @@ public:
|
|||||||
{
|
{
|
||||||
result.cpuUsage_ = audioDriver->CpuUse();
|
result.cpuUsage_ = audioDriver->CpuUse();
|
||||||
}
|
}
|
||||||
GetCpuFrequency(&result.cpuFreqMax_,&result.cpuFreqMin_);
|
GetCpuFrequency(&result.cpuFreqMax_, &result.cpuFreqMin_);
|
||||||
result.governor_ = GetGovernor();
|
result.governor_ = GetGovernor();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -1367,7 +1546,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string UriToFieldName(const std::string&uri){
|
static std::string UriToFieldName(const std::string &uri)
|
||||||
|
{
|
||||||
int pos;
|
int pos;
|
||||||
for (pos = uri.length(); pos >= 0; --pos)
|
for (pos = uri.length(); pos >= 0; --pos)
|
||||||
{
|
{
|
||||||
@@ -1377,10 +1557,10 @@ static std::string UriToFieldName(const std::string&uri){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return uri.substr(pos+1);
|
return uri.substr(pos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JackHostImpl::WriteAtom(json_writer &writer, LV2_Atom*pAtom)
|
void AudioHostImpl::WriteAtom(json_writer &writer, LV2_Atom *pAtom)
|
||||||
{
|
{
|
||||||
if (pAtom->type == uris.atom_Blank)
|
if (pAtom->type == uris.atom_Blank)
|
||||||
{
|
{
|
||||||
@@ -1389,86 +1569,95 @@ void JackHostImpl::WriteAtom(json_writer &writer, LV2_Atom*pAtom)
|
|||||||
else if (pAtom->type == uris.atom_float)
|
else if (pAtom->type == uris.atom_float)
|
||||||
{
|
{
|
||||||
writer.write(
|
writer.write(
|
||||||
((LV2_Atom_Float*)pAtom)->body
|
((LV2_Atom_Float *)pAtom)->body);
|
||||||
);
|
}
|
||||||
|
else if (pAtom->type == uris.atom_Int)
|
||||||
} else if (pAtom->type == uris.atom_Int)
|
|
||||||
{
|
{
|
||||||
writer.write(
|
writer.write(
|
||||||
((LV2_Atom_Int*)pAtom)->body
|
((LV2_Atom_Int *)pAtom)->body);
|
||||||
);
|
}
|
||||||
} else if (pAtom->type == uris.atom_Long)
|
else if (pAtom->type == uris.atom_Long)
|
||||||
{
|
{
|
||||||
writer.write(
|
writer.write(
|
||||||
((LV2_Atom_Long*)pAtom)->body
|
((LV2_Atom_Long *)pAtom)->body);
|
||||||
);
|
}
|
||||||
} else if (pAtom->type == uris.atom_Double)
|
else if (pAtom->type == uris.atom_Double)
|
||||||
{
|
{
|
||||||
writer.write(
|
writer.write(
|
||||||
((LV2_Atom_Double*)pAtom)->body
|
((LV2_Atom_Double *)pAtom)->body);
|
||||||
);
|
}
|
||||||
} else if (pAtom->type == uris.atom_Bool)
|
else if (pAtom->type == uris.atom_Bool)
|
||||||
{
|
{
|
||||||
writer.write(
|
writer.write(
|
||||||
((LV2_Atom_Bool*)pAtom)->body
|
((LV2_Atom_Bool *)pAtom)->body);
|
||||||
);
|
}
|
||||||
} else if (pAtom->type == uris.atom_String)
|
else if (pAtom->type == uris.atom_String)
|
||||||
{
|
{
|
||||||
const char *p = (((const char*) pAtom) + sizeof(LV2_Atom_String));
|
const char *p = (((const char *)pAtom) + sizeof(LV2_Atom_String));
|
||||||
writer.write(
|
writer.write(
|
||||||
p
|
p);
|
||||||
);
|
}
|
||||||
} else if (pAtom->type == uris.atom_Vector)
|
else if (pAtom->type == uris.atom_Vector)
|
||||||
{
|
{
|
||||||
LV2_Atom_Vector *pVector = (LV2_Atom_Vector*)pAtom;
|
LV2_Atom_Vector *pVector = (LV2_Atom_Vector *)pAtom;
|
||||||
writer.start_array();
|
writer.start_array();
|
||||||
{
|
{
|
||||||
size_t n = (pAtom->size-sizeof(pVector->body))/pVector->body.child_size;
|
size_t n = (pAtom->size - sizeof(pVector->body)) / pVector->body.child_size;
|
||||||
char *pItems = ((char*)pAtom) + sizeof(LV2_Atom_Vector);
|
char *pItems = ((char *)pAtom) + sizeof(LV2_Atom_Vector);
|
||||||
if (pVector->body.child_type == uris.atom_float)
|
if (pVector->body.child_type == uris.atom_float)
|
||||||
{
|
{
|
||||||
float *p = (float*)pItems;
|
float *p = (float *)pItems;
|
||||||
for (size_t i = 0; i < n; ++i)
|
for (size_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
if (i != 0) writer.write_raw(",");
|
if (i != 0)
|
||||||
|
writer.write_raw(",");
|
||||||
writer.write(*p++);
|
writer.write(*p++);
|
||||||
}
|
}
|
||||||
} else if (pVector->body.child_type == uris.atom_Int)
|
}
|
||||||
|
else if (pVector->body.child_type == uris.atom_Int)
|
||||||
{
|
{
|
||||||
int32_t *p = (int32_t*)pItems;
|
int32_t *p = (int32_t *)pItems;
|
||||||
for (size_t i = 0; i < n; ++i)
|
for (size_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
if (i != 0) writer.write_raw(",");
|
if (i != 0)
|
||||||
|
writer.write_raw(",");
|
||||||
writer.write(*p++);
|
writer.write(*p++);
|
||||||
}
|
}
|
||||||
} else if (pVector->body.child_type == uris.atom_Long)
|
}
|
||||||
|
else if (pVector->body.child_type == uris.atom_Long)
|
||||||
{
|
{
|
||||||
int64_t *p = (int64_t*)pItems;
|
int64_t *p = (int64_t *)pItems;
|
||||||
for (size_t i = 0; i < n; ++i)
|
for (size_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
if (i != 0) writer.write_raw(",");
|
if (i != 0)
|
||||||
|
writer.write_raw(",");
|
||||||
writer.write(*p++);
|
writer.write(*p++);
|
||||||
}
|
}
|
||||||
} else if (pVector->body.child_type == uris.atom_Double)
|
}
|
||||||
|
else if (pVector->body.child_type == uris.atom_Double)
|
||||||
{
|
{
|
||||||
double *p = (double*)pItems;
|
double *p = (double *)pItems;
|
||||||
for (size_t i = 0; i < n; ++i)
|
for (size_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
if (i != 0) writer.write_raw(",");
|
if (i != 0)
|
||||||
|
writer.write_raw(",");
|
||||||
writer.write(*p++);
|
writer.write(*p++);
|
||||||
}
|
}
|
||||||
} else if (pVector->body.child_type == uris.atom_Bool)
|
}
|
||||||
|
else if (pVector->body.child_type == uris.atom_Bool)
|
||||||
{
|
{
|
||||||
bool *p = (bool*)pItems;
|
bool *p = (bool *)pItems;
|
||||||
for (size_t i = 0; i < n; ++i)
|
for (size_t i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
if (i != 0) writer.write_raw(",");
|
if (i != 0)
|
||||||
|
writer.write_raw(",");
|
||||||
writer.write(*p++);
|
writer.write(*p++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.end_array();
|
writer.end_array();
|
||||||
} else if (pAtom->type == uris.atom_Object)
|
}
|
||||||
|
else if (pAtom->type == uris.atom_Object)
|
||||||
{
|
{
|
||||||
writer.start_object();
|
writer.start_object();
|
||||||
|
|
||||||
@@ -1477,14 +1666,14 @@ void JackHostImpl::WriteAtom(json_writer &writer, LV2_Atom*pAtom)
|
|||||||
if (obj->body.id != 0)
|
if (obj->body.id != 0)
|
||||||
{
|
{
|
||||||
std::string id = pHost->Lv2UriudToString(obj->body.id);
|
std::string id = pHost->Lv2UriudToString(obj->body.id);
|
||||||
writer.write_member("id",id.c_str());
|
writer.write_member("id", id.c_str());
|
||||||
firstMember = false;
|
firstMember = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->body.otype != 0)
|
if (obj->body.otype != 0)
|
||||||
{
|
{
|
||||||
std::string type = pHost->Lv2UriudToString(obj->body.otype);
|
std::string type = pHost->Lv2UriudToString(obj->body.otype);
|
||||||
writer.write_member("lv2Type",type.c_str());
|
writer.write_member("lv2Type", type.c_str());
|
||||||
if (!firstMember)
|
if (!firstMember)
|
||||||
{
|
{
|
||||||
writer.write_raw(",");
|
writer.write_raw(",");
|
||||||
@@ -1492,8 +1681,10 @@ void JackHostImpl::WriteAtom(json_writer &writer, LV2_Atom*pAtom)
|
|||||||
firstMember = false;
|
firstMember = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LV2_ATOM_OBJECT_FOREACH (obj, prop) {
|
LV2_ATOM_OBJECT_FOREACH(obj, prop)
|
||||||
if (!firstMember) {
|
{
|
||||||
|
if (!firstMember)
|
||||||
|
{
|
||||||
writer.write_raw(",");
|
writer.write_raw(",");
|
||||||
}
|
}
|
||||||
firstMember = false;
|
firstMember = false;
|
||||||
@@ -1502,17 +1693,30 @@ void JackHostImpl::WriteAtom(json_writer &writer, LV2_Atom*pAtom)
|
|||||||
writer.write(key);
|
writer.write(key);
|
||||||
writer.write_raw(": ");
|
writer.write_raw(": ");
|
||||||
LV2_Atom *value = &(prop->value);
|
LV2_Atom *value = &(prop->value);
|
||||||
WriteAtom(writer,value);
|
WriteAtom(writer, value);
|
||||||
}
|
}
|
||||||
writer.end_object();
|
writer.end_object();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JackHost *JackHost::CreateInstance(IHost *pHost)
|
void AudioHostImpl::SetSystemMidiBindings(const std::vector<MidiBinding>&bindings)
|
||||||
{
|
{
|
||||||
return new JackHostImpl(pHost);
|
for (auto i = bindings.begin(); i != bindings.end(); ++i)
|
||||||
|
{
|
||||||
|
if (i->symbol() == "nextProgram")
|
||||||
|
{
|
||||||
|
this->nextMidiBinding.SetBinding(*i);
|
||||||
|
} else if (i->symbol() == "prevProgram")
|
||||||
|
{
|
||||||
|
this->prevMidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AudioHost *AudioHost::CreateInstance(IHost *pHost)
|
||||||
|
{
|
||||||
|
return new AudioHostImpl(pHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_MAP_BEGIN(JackHostStatus)
|
JSON_MAP_BEGIN(JackHostStatus)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2023 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
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "Lv2PedalBoard.hpp"
|
#include "Lv2PedalBoard.hpp"
|
||||||
#include "VuUpdate.hpp"
|
#include "VuUpdate.hpp"
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
#include "JackServerSettings.hpp"
|
#include "JackServerSettings.hpp"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "PiPedalAlsa.hpp"
|
#include "PiPedalAlsa.hpp"
|
||||||
@@ -32,6 +32,8 @@
|
|||||||
namespace pipedal {
|
namespace pipedal {
|
||||||
|
|
||||||
|
|
||||||
|
struct RealtimeMidiProgramRequest;
|
||||||
|
struct RealtimeNextMidiProgramRequest;
|
||||||
|
|
||||||
using PortMonitorCallback = std::function<void (int64_t handle, float value)>;
|
using PortMonitorCallback = std::function<void (int64_t handle, float value)>;
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IJackHostCallbacks {
|
class IAudioHostCallbacks {
|
||||||
public:
|
public:
|
||||||
virtual void OnNotifyVusSubscription(const std::vector<VuUpdate> & updates) = 0;
|
virtual void OnNotifyVusSubscription(const std::vector<VuUpdate> & updates) = 0;
|
||||||
virtual void OnNotifyMonitorPort(const MonitorPortUpdate &update) = 0;
|
virtual void OnNotifyMonitorPort(const MonitorPortUpdate &update) = 0;
|
||||||
@@ -99,6 +101,8 @@ public:
|
|||||||
virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl) = 0;
|
virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl) = 0;
|
||||||
virtual void OnNotifyAtomOutput(uint64_t instanceId, const std::string&atomType,const std::string&atomJson) = 0;
|
virtual void OnNotifyAtomOutput(uint64_t instanceId, const std::string&atomType,const std::string&atomJson) = 0;
|
||||||
|
|
||||||
|
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest&midiProgramRequest) = 0;
|
||||||
|
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest&request) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,17 +128,17 @@ public:
|
|||||||
|
|
||||||
class IHost;
|
class IHost;
|
||||||
|
|
||||||
class JackHost {
|
class AudioHost {
|
||||||
protected:
|
protected:
|
||||||
JackHost() { }
|
AudioHost() { }
|
||||||
public:
|
public:
|
||||||
static JackHost*CreateInstance(IHost *pHost);
|
static AudioHost*CreateInstance(IHost *pHost);
|
||||||
virtual ~JackHost() { };
|
virtual ~AudioHost() { };
|
||||||
|
|
||||||
virtual void UpdateServerConfiguration(const JackServerSettings & jackServerSettings,
|
virtual void UpdateServerConfiguration(const JackServerSettings & jackServerSettings,
|
||||||
std::function<void(bool success, const std::string&errorMessage)> onComplete) = 0;
|
std::function<void(bool success, const std::string&errorMessage)> onComplete) = 0;
|
||||||
|
|
||||||
virtual void SetNotificationCallbacks(IJackHostCallbacks *pNotifyCallbacks) = 0;
|
virtual void SetNotificationCallbacks(IAudioHostCallbacks *pNotifyCallbacks) = 0;
|
||||||
|
|
||||||
virtual void SetListenForMidiEvent(bool listen) = 0;
|
virtual void SetListenForMidiEvent(bool listen) = 0;
|
||||||
virtual void SetListenForAtomOutput(bool listen) = 0;
|
virtual void SetListenForAtomOutput(bool listen) = 0;
|
||||||
@@ -158,7 +162,10 @@ public:
|
|||||||
virtual void SetVuSubscriptions(const std::vector<int64_t> &instanceIds) = 0;
|
virtual void SetVuSubscriptions(const std::vector<int64_t> &instanceIds) = 0;
|
||||||
virtual void SetMonitorPortSubscriptions(const std::vector<MonitorPortSubscription> &subscriptions) = 0;
|
virtual void SetMonitorPortSubscriptions(const std::vector<MonitorPortSubscription> &subscriptions) = 0;
|
||||||
|
|
||||||
|
virtual void SetSystemMidiBindings(const std::vector<MidiBinding>&bindings) = 0;
|
||||||
|
|
||||||
virtual void getRealtimeParameter(RealtimeParameterRequest*pParameterRequest) = 0;
|
virtual void getRealtimeParameter(RealtimeParameterRequest*pParameterRequest) = 0;
|
||||||
|
virtual void AckMidiProgramRequest(uint64_t requestId) = 0;
|
||||||
|
|
||||||
virtual JackHostStatus getJackStatus() = 0;
|
virtual JackHostStatus getJackStatus() = 0;
|
||||||
|
|
||||||
+3
-3
@@ -149,7 +149,7 @@ set (PIPEDAL_SOURCES
|
|||||||
CpuGovernor.cpp CpuGovernor.hpp
|
CpuGovernor.cpp CpuGovernor.hpp
|
||||||
GovernorSettings.cpp GovernorSettings.hpp
|
GovernorSettings.cpp GovernorSettings.hpp
|
||||||
SysExec.cpp SysExec.hpp
|
SysExec.cpp SysExec.hpp
|
||||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
WebServer.cpp WebServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||||
WifiDirectConfigSettings.hpp WifiDirectConfigSettings.cpp
|
WifiDirectConfigSettings.hpp WifiDirectConfigSettings.cpp
|
||||||
ConfigUtil.hpp ConfigUtil.cpp
|
ConfigUtil.hpp ConfigUtil.cpp
|
||||||
@@ -164,7 +164,7 @@ set (PIPEDAL_SOURCES
|
|||||||
Presets.hpp Presets.cpp
|
Presets.hpp Presets.cpp
|
||||||
Storage.hpp Storage.cpp
|
Storage.hpp Storage.cpp
|
||||||
Banks.hpp Banks.cpp
|
Banks.hpp Banks.cpp
|
||||||
JackHost.hpp JackHost.cpp
|
AudioHost.hpp AudioHost.cpp
|
||||||
JackConfiguration.hpp JackConfiguration.cpp
|
JackConfiguration.hpp JackConfiguration.cpp
|
||||||
defer.hpp
|
defer.hpp
|
||||||
Lv2Effect.cpp Lv2Effect.hpp
|
Lv2Effect.cpp Lv2Effect.hpp
|
||||||
@@ -264,7 +264,7 @@ add_executable(pipedaltest testMain.cpp
|
|||||||
|
|
||||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||||
SystemConfigFileTest.cpp
|
SystemConfigFileTest.cpp
|
||||||
BeastServerTest.cpp
|
WebServerTest.cpp
|
||||||
MemDebug.cpp
|
MemDebug.cpp
|
||||||
MemDebug.hpp
|
MemDebug.hpp
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@
|
|||||||
#include "lv2/parameters.lv2/parameters.h"
|
#include "lv2/parameters.lv2/parameters.h"
|
||||||
#include "lv2/units.lv2/units.h"
|
#include "lv2/units.lv2/units.h"
|
||||||
#include "lv2/atom.lv2/util.h"
|
#include "lv2/atom.lv2/util.h"
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include "RingBufferReader.hpp"
|
#include "RingBufferReader.hpp"
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#include "SplitEffect.hpp"
|
#include "SplitEffect.hpp"
|
||||||
#include "RingBufferReader.hpp"
|
#include "RingBufferReader.hpp"
|
||||||
#include "VuUpdate.hpp"
|
#include "VuUpdate.hpp"
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
#include "Lv2EventBufferWriter.hpp"
|
#include "Lv2EventBufferWriter.hpp"
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|||||||
+9
-3
@@ -58,15 +58,21 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string symbol_;
|
std::string symbol_;
|
||||||
int channel_ = -1;
|
int channel_ = -1;
|
||||||
int bindingType_;
|
int bindingType_ = BINDING_TYPE_NONE;
|
||||||
int note_ = 12*4+24;
|
int note_ = 12*4+24;
|
||||||
int control_ = 1;
|
int control_ = 1;
|
||||||
float minValue_ = 0;
|
float minValue_ = 0;
|
||||||
float maxValue_ = 1;
|
float maxValue_ = 1;
|
||||||
float rotaryScale_ = 1;
|
float rotaryScale_ = 1;
|
||||||
int linearControlType_ = 0;
|
int linearControlType_ = LINEAR_CONTROL_TYPE;
|
||||||
int switchControlType_ = 0;
|
int switchControlType_ = LATCH_CONTROL_TYPE;
|
||||||
public:
|
public:
|
||||||
|
static MidiBinding SystemBinding(const std::string&symbol)
|
||||||
|
{
|
||||||
|
MidiBinding result;
|
||||||
|
result.symbol_ = symbol;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
GETTER_SETTER(channel);
|
GETTER_SETTER(channel);
|
||||||
GETTER_SETTER_REF(symbol);
|
GETTER_SETTER_REF(symbol);
|
||||||
GETTER_SETTER(bindingType);
|
GETTER_SETTER(bindingType);
|
||||||
|
|||||||
+151
-34
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2023 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
|
||||||
@@ -23,13 +23,14 @@
|
|||||||
#include "ConfigUtil.hpp"
|
#include "ConfigUtil.hpp"
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include "PiPedalModel.hpp"
|
#include "PiPedalModel.hpp"
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
#include "Lv2Log.hpp"
|
#include "Lv2Log.hpp"
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "PiPedalConfiguration.hpp"
|
#include "PiPedalConfiguration.hpp"
|
||||||
#include "AdminClient.hpp"
|
#include "AdminClient.hpp"
|
||||||
#include "SplitEffect.hpp"
|
#include "SplitEffect.hpp"
|
||||||
#include "CpuGovernor.hpp"
|
#include "CpuGovernor.hpp"
|
||||||
|
#include "RingBufferReader.hpp"
|
||||||
|
|
||||||
#ifndef NO_MLOCK
|
#ifndef NO_MLOCK
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -84,9 +85,9 @@ void PiPedalModel::Close()
|
|||||||
}
|
}
|
||||||
delete[] t;
|
delete[] t;
|
||||||
|
|
||||||
if (jackHost)
|
if (audioHost)
|
||||||
{
|
{
|
||||||
jackHost->Close();
|
audioHost->Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,9 +114,9 @@ PiPedalModel::~PiPedalModel()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (jackHost)
|
if (audioHost)
|
||||||
{
|
{
|
||||||
jackHost->Close();
|
audioHost->Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
@@ -133,6 +134,8 @@ void PiPedalModel::Init(const PiPedalConfiguration &configuration)
|
|||||||
storage.SetDataRoot(configuration.GetLocalStoragePath());
|
storage.SetDataRoot(configuration.GetLocalStoragePath());
|
||||||
storage.Initialize();
|
storage.Initialize();
|
||||||
|
|
||||||
|
this->systemMidiBindings = storage.GetSystemMidiBindings();
|
||||||
|
|
||||||
this->jackServerSettings.ReadJackConfiguration();
|
this->jackServerSettings.ReadJackConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,10 +194,14 @@ void PiPedalModel::Load()
|
|||||||
}
|
}
|
||||||
UpdateDefaults(&this->pedalBoard);
|
UpdateDefaults(&this->pedalBoard);
|
||||||
|
|
||||||
std::unique_ptr<JackHost> p{JackHost::CreateInstance(lv2Host.asIHost())};
|
std::unique_ptr<AudioHost> p{AudioHost::CreateInstance(lv2Host.asIHost())};
|
||||||
this->jackHost = std::move(p);
|
this->audioHost = std::move(p);
|
||||||
|
|
||||||
this->jackHost->SetNotificationCallbacks(this);
|
this->audioHost->SetNotificationCallbacks(this);
|
||||||
|
|
||||||
|
this->systemMidiBindings = storage.GetSystemMidiBindings();
|
||||||
|
|
||||||
|
this->audioHost->SetSystemMidiBindings(this->systemMidiBindings);
|
||||||
|
|
||||||
if (configuration.GetMLock())
|
if (configuration.GetMLock())
|
||||||
{
|
{
|
||||||
@@ -226,11 +233,11 @@ void PiPedalModel::Load()
|
|||||||
this->lv2Host.OnConfigurationChanged(jackConfiguration, selection);
|
this->lv2Host.OnConfigurationChanged(jackConfiguration, selection);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
jackHost->Open(this->jackServerSettings, selection);
|
audioHost->Open(this->jackServerSettings, selection);
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||||
this->lv2PedalBoard = lv2PedalBoard;
|
this->lv2PedalBoard = lv2PedalBoard;
|
||||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
audioHost->SetPedalBoard(lv2PedalBoard);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
{
|
{
|
||||||
@@ -305,7 +312,7 @@ void PiPedalModel::PreviewControl(int64_t clientId, int64_t pedalItemId, const s
|
|||||||
effect->SetControl(index,value);;
|
effect->SetControl(index,value);;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
jackHost->SetControlValue(pedalItemId, symbol, value);
|
audioHost->SetControlValue(pedalItemId, symbol, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,11 +394,11 @@ void PiPedalModel::FirePedalBoardChanged(int64_t clientId)
|
|||||||
delete[] t;
|
delete[] t;
|
||||||
|
|
||||||
// notify the audio thread.
|
// notify the audio thread.
|
||||||
if (jackHost->IsOpen())
|
if (audioHost->IsOpen())
|
||||||
{
|
{
|
||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||||
this->lv2PedalBoard = lv2PedalBoard;
|
this->lv2PedalBoard = lv2PedalBoard;
|
||||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
audioHost->SetPedalBoard(lv2PedalBoard);
|
||||||
UpdateRealtimeVuSubscriptions();
|
UpdateRealtimeVuSubscriptions();
|
||||||
UpdateRealtimeMonitorPortSubscriptions();
|
UpdateRealtimeMonitorPortSubscriptions();
|
||||||
}
|
}
|
||||||
@@ -446,7 +453,7 @@ void PiPedalModel::SetPedalBoardItemEnable(int64_t clientId, int64_t pedalItemId
|
|||||||
this->SetPresetChanged(clientId, true);
|
this->SetPresetChanged(clientId, true);
|
||||||
|
|
||||||
// Notify audo thread.
|
// Notify audo thread.
|
||||||
this->jackHost->SetBypass(pedalItemId, enabled);
|
this->audioHost->SetBypass(pedalItemId, enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,6 +628,87 @@ int64_t PiPedalModel::UploadBank(BankFile &bankFile, int64_t uploadAfter)
|
|||||||
return newPreset;
|
return newPreset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest&request)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
|
try {
|
||||||
|
PresetIndex index;
|
||||||
|
storage.GetPresetIndex(&index);
|
||||||
|
auto currentPresetId = storage.GetCurrentPresetId();
|
||||||
|
size_t currentPresetIndex = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < index.presets().size(); ++i)
|
||||||
|
{
|
||||||
|
if (index.presets()[i].instanceId() == currentPresetId)
|
||||||
|
{
|
||||||
|
currentPresetIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index.presets().size() == 0)
|
||||||
|
{
|
||||||
|
throw PiPedalException("No presets loaded.");
|
||||||
|
}
|
||||||
|
if (request.direction < 0)
|
||||||
|
{
|
||||||
|
if (currentPresetIndex == 0)
|
||||||
|
{
|
||||||
|
currentPresetIndex = index.presets().size()-1;
|
||||||
|
} else {
|
||||||
|
--currentPresetIndex;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++currentPresetIndex;
|
||||||
|
if (currentPresetIndex >= index.presets().size())
|
||||||
|
{
|
||||||
|
currentPresetIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoadPreset(-1,index.presets()[currentPresetIndex].instanceId());
|
||||||
|
} catch (std::exception&e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Lv2Log::error(e.what());
|
||||||
|
}
|
||||||
|
if (this->audioHost)
|
||||||
|
{
|
||||||
|
this->audioHost->AckMidiProgramRequest(request.requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PiPedalModel::OnNotifyMidiProgramChange(RealtimeMidiProgramRequest&midiProgramRequest)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
|
try {
|
||||||
|
if (midiProgramRequest.bank >= 0)
|
||||||
|
{
|
||||||
|
int64_t bankId = storage.GetBankByMidiBankNumber(midiProgramRequest.bank);
|
||||||
|
if (bankId == -1) throw PiPedalException("Bank not found.");
|
||||||
|
if (bankId != this->storage.GetBanks().selectedBank())
|
||||||
|
{
|
||||||
|
storage.LoadBank(bankId);
|
||||||
|
|
||||||
|
FireBanksChanged(-1);
|
||||||
|
FirePresetsChanged(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int64_t presetId = storage.GetPresetByProgramNumber(midiProgramRequest.program);
|
||||||
|
if (presetId == -1) throw PiPedalException("No valid preset.");
|
||||||
|
LoadPreset(-1,presetId);
|
||||||
|
} catch (std::exception&e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Lv2Log::error(e.what());
|
||||||
|
}
|
||||||
|
if (this->audioHost)
|
||||||
|
{
|
||||||
|
this->audioHost->AckMidiProgramRequest(midiProgramRequest.requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::LoadPreset(int64_t clientId, int64_t instanceId)
|
void PiPedalModel::LoadPreset(int64_t clientId, int64_t instanceId)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
@@ -883,10 +971,10 @@ JackConfiguration PiPedalModel::GetJackConfiguration()
|
|||||||
|
|
||||||
void PiPedalModel::RestartAudio()
|
void PiPedalModel::RestartAudio()
|
||||||
{
|
{
|
||||||
if (this->jackHost->IsOpen())
|
if (this->audioHost->IsOpen())
|
||||||
{
|
{
|
||||||
|
|
||||||
this->jackHost->Close();
|
this->audioHost->Close();
|
||||||
}
|
}
|
||||||
// restarting is a bit dodgy. It was impossible with Jack, but
|
// restarting is a bit dodgy. It was impossible with Jack, but
|
||||||
// now very plausible with the ALSA audio stack.
|
// now very plausible with the ALSA audio stack.
|
||||||
@@ -899,7 +987,7 @@ void PiPedalModel::RestartAudio()
|
|||||||
|
|
||||||
// do a complete reload.
|
// do a complete reload.
|
||||||
|
|
||||||
this->jackHost->SetPedalBoard(nullptr);
|
this->audioHost->SetPedalBoard(nullptr);
|
||||||
|
|
||||||
this->jackConfiguration.AlsaInitialize(this->jackServerSettings);
|
this->jackConfiguration.AlsaInitialize(this->jackServerSettings);
|
||||||
|
|
||||||
@@ -928,13 +1016,13 @@ void PiPedalModel::RestartAudio()
|
|||||||
Lv2Log::error("Audio configuration not valid.");
|
Lv2Log::error("Audio configuration not valid.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->jackHost->Open(this->jackServerSettings, channelSelection);
|
this->audioHost->Open(this->jackServerSettings, channelSelection);
|
||||||
|
|
||||||
this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection);
|
this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection);
|
||||||
|
|
||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||||
this->lv2PedalBoard = lv2PedalBoard;
|
this->lv2PedalBoard = lv2PedalBoard;
|
||||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
audioHost->SetPedalBoard(lv2PedalBoard);
|
||||||
this->UpdateRealtimeVuSubscriptions();
|
this->UpdateRealtimeVuSubscriptions();
|
||||||
UpdateRealtimeMonitorPortSubscriptions();
|
UpdateRealtimeMonitorPortSubscriptions();
|
||||||
}
|
}
|
||||||
@@ -1121,12 +1209,12 @@ void PiPedalModel::UpdateRealtimeVuSubscriptions()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<int64_t> instanceids(addedInstances.begin(), addedInstances.end());
|
std::vector<int64_t> instanceids(addedInstances.begin(), addedInstances.end());
|
||||||
jackHost->SetVuSubscriptions(instanceids);
|
audioHost->SetVuSubscriptions(instanceids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::UpdateRealtimeMonitorPortSubscriptions()
|
void PiPedalModel::UpdateRealtimeMonitorPortSubscriptions()
|
||||||
{
|
{
|
||||||
jackHost->SetMonitorPortSubscriptions(this->activeMonitorPortSubscriptions);
|
audioHost->SetMonitorPortSubscriptions(this->activeMonitorPortSubscriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t PiPedalModel::MonitorPort(int64_t instanceId, const std::string &key, float updateInterval, PortMonitorCallback onUpdate)
|
int64_t PiPedalModel::MonitorPort(int64_t instanceId, const std::string &key, float updateInterval, PortMonitorCallback onUpdate)
|
||||||
@@ -1220,7 +1308,7 @@ void PiPedalModel::GetLv2Parameter(
|
|||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
outstandingParameterRequests.push_back(request);
|
outstandingParameterRequests.push_back(request);
|
||||||
this->jackHost->getRealtimeParameter(request);
|
this->audioHost->getRealtimeParameter(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
BankIndex PiPedalModel::GetBankIndex() const
|
BankIndex PiPedalModel::GetBankIndex() const
|
||||||
@@ -1254,6 +1342,7 @@ void PiPedalModel::OpenBank(int64_t clientId, int64_t bankId)
|
|||||||
FirePresetsChanged(clientId);
|
FirePresetsChanged(clientId);
|
||||||
|
|
||||||
this->pedalBoard = storage.GetCurrentPreset();
|
this->pedalBoard = storage.GetCurrentPreset();
|
||||||
|
|
||||||
UpdateDefaults(&this->pedalBoard);
|
UpdateDefaults(&this->pedalBoard);
|
||||||
this->hasPresetChanged = false;
|
this->hasPresetChanged = false;
|
||||||
this->FirePedalBoardChanged(clientId);
|
this->FirePedalBoardChanged(clientId);
|
||||||
@@ -1311,7 +1400,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
|||||||
|
|
||||||
this->jackConfiguration.SetIsRestarting(true);
|
this->jackConfiguration.SetIsRestarting(true);
|
||||||
FireJackConfigurationChanged(this->jackConfiguration);
|
FireJackConfigurationChanged(this->jackConfiguration);
|
||||||
this->jackHost->UpdateServerConfiguration(
|
this->audioHost->UpdateServerConfiguration(
|
||||||
jackServerSettings,
|
jackServerSettings,
|
||||||
[this](bool success, const std::string &errorMessage)
|
[this](bool success, const std::string &errorMessage)
|
||||||
{
|
{
|
||||||
@@ -1341,7 +1430,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
|||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||||
this->lv2PedalBoard = lv2PedalBoard;
|
this->lv2PedalBoard = lv2PedalBoard;
|
||||||
|
|
||||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
audioHost->SetPedalBoard(lv2PedalBoard);
|
||||||
UpdateRealtimeVuSubscriptions();
|
UpdateRealtimeVuSubscriptions();
|
||||||
UpdateRealtimeMonitorPortSubscriptions();
|
UpdateRealtimeMonitorPortSubscriptions();
|
||||||
#endif
|
#endif
|
||||||
@@ -1418,7 +1507,7 @@ void PiPedalModel::LoadPluginPreset(int64_t pluginInstanceId, uint64_t presetIns
|
|||||||
if (pedalBoardItem != nullptr)
|
if (pedalBoardItem != nullptr)
|
||||||
{
|
{
|
||||||
std::vector<ControlValue> controlValues = storage.GetPluginPresetValues(pedalBoardItem->uri(), presetInstanceId);
|
std::vector<ControlValue> controlValues = storage.GetPluginPresetValues(pedalBoardItem->uri(), presetInstanceId);
|
||||||
jackHost->SetPluginPreset(pluginInstanceId, controlValues);
|
audioHost->SetPluginPreset(pluginInstanceId, controlValues);
|
||||||
|
|
||||||
for (size_t i = 0; i < controlValues.size(); ++i)
|
for (size_t i = 0; i < controlValues.size(); ++i)
|
||||||
{
|
{
|
||||||
@@ -1451,7 +1540,7 @@ void PiPedalModel::DeleteAtomOutputListeners(int64_t clientId)
|
|||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jackHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
audioHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
||||||
@@ -1465,7 +1554,7 @@ void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
|||||||
--i;
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jackHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
audioHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyAtomOutput(uint64_t instanceId, const std::string &atomType, const std::string &atomJson)
|
void PiPedalModel::OnNotifyAtomOutput(uint64_t instanceId, const std::string &atomType, const std::string &atomJson)
|
||||||
@@ -1489,7 +1578,7 @@ void PiPedalModel::OnNotifyAtomOutput(uint64_t instanceId, const std::string &at
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jackHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
audioHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
||||||
@@ -1513,7 +1602,7 @@ void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jackHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
audioHost->SetListenForMidiEvent(midiEventListeners.size() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::ListenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly)
|
void PiPedalModel::ListenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly)
|
||||||
@@ -1521,7 +1610,7 @@ void PiPedalModel::ListenForMidiEvent(int64_t clientId, int64_t clientHandle, bo
|
|||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
MidiListener listener{clientId, clientHandle, listenForControlsOnly};
|
MidiListener listener{clientId, clientHandle, listenForControlsOnly};
|
||||||
midiEventListeners.push_back(listener);
|
midiEventListeners.push_back(listener);
|
||||||
jackHost->SetListenForMidiEvent(true);
|
audioHost->SetListenForMidiEvent(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::ListenForAtomOutputs(int64_t clientId, int64_t clientHandle, uint64_t instanceId)
|
void PiPedalModel::ListenForAtomOutputs(int64_t clientId, int64_t clientHandle, uint64_t instanceId)
|
||||||
@@ -1529,7 +1618,7 @@ void PiPedalModel::ListenForAtomOutputs(int64_t clientId, int64_t clientHandle,
|
|||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
AtomOutputListener listener{clientId, clientHandle, instanceId};
|
AtomOutputListener listener{clientId, clientHandle, instanceId};
|
||||||
atomOutputListeners.push_back(listener);
|
atomOutputListeners.push_back(listener);
|
||||||
jackHost->SetListenForAtomOutput(true);
|
audioHost->SetListenForAtomOutput(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PiPedalModel::CancelListenForMidiEvent(int64_t clientId, int64_t clientHandle)
|
void PiPedalModel::CancelListenForMidiEvent(int64_t clientId, int64_t clientHandle)
|
||||||
@@ -1546,7 +1635,7 @@ void PiPedalModel::CancelListenForMidiEvent(int64_t clientId, int64_t clientHand
|
|||||||
}
|
}
|
||||||
if (midiEventListeners.size() == 0)
|
if (midiEventListeners.size() == 0)
|
||||||
{
|
{
|
||||||
jackHost->SetListenForMidiEvent(false);
|
audioHost->SetListenForMidiEvent(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void PiPedalModel::CancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle)
|
void PiPedalModel::CancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle)
|
||||||
@@ -1563,7 +1652,7 @@ void PiPedalModel::CancelListenForAtomOutputs(int64_t clientId, int64_t clientHa
|
|||||||
}
|
}
|
||||||
if (midiEventListeners.size() == 0)
|
if (midiEventListeners.size() == 0)
|
||||||
{
|
{
|
||||||
jackHost->SetListenForMidiEvent(false);
|
audioHost->SetListenForMidiEvent(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<AlsaDeviceInfo> PiPedalModel::GetAlsaDevices()
|
std::vector<AlsaDeviceInfo> PiPedalModel::GetAlsaDevices()
|
||||||
@@ -1600,3 +1689,31 @@ void PiPedalModel::SetFavorites(const std::map<std::string, bool> &favorites)
|
|||||||
t[i]->OnFavoritesChanged(favorites);
|
t[i]->OnFavoritesChanged(favorites);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::vector<MidiBinding> PiPedalModel::GetSystemMidiBidings() {
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
return this->systemMidiBindings;
|
||||||
|
}
|
||||||
|
void PiPedalModel::SetSystemMidiBindings(std::vector<MidiBinding> &bindings)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
|
this->systemMidiBindings = bindings;
|
||||||
|
storage.SetSystemMidiBindings(bindings);
|
||||||
|
if (this->audioHost)
|
||||||
|
{
|
||||||
|
this->audioHost->SetSystemMidiBindings(bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||||
|
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||||
|
{
|
||||||
|
t[i] = this->subscribers[i];
|
||||||
|
}
|
||||||
|
size_t n = this->subscribers.size();
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
t[i]->OnSystemMidiBindingsChanged(bindings);
|
||||||
|
}
|
||||||
|
delete[] t;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+97
-93
@@ -25,7 +25,7 @@
|
|||||||
#include "Storage.hpp"
|
#include "Storage.hpp"
|
||||||
#include "Banks.hpp"
|
#include "Banks.hpp"
|
||||||
#include "JackConfiguration.hpp"
|
#include "JackConfiguration.hpp"
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
#include "VuUpdate.hpp"
|
#include "VuUpdate.hpp"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -38,45 +38,47 @@
|
|||||||
#include "AvahiService.hpp"
|
#include "AvahiService.hpp"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
namespace pipedal
|
||||||
|
{
|
||||||
|
|
||||||
|
struct RealtimeMidiProgramRequest;
|
||||||
|
struct RealtimeNextMidiProgramRequest;
|
||||||
|
|
||||||
|
class IPiPedalModelSubscriber
|
||||||
|
{
|
||||||
namespace pipedal {
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class IPiPedalModelSubscriber {
|
|
||||||
public:
|
|
||||||
virtual int64_t GetClientId() = 0;
|
virtual int64_t GetClientId() = 0;
|
||||||
virtual void OnItemEnabledChanged(int64_t clientId, int64_t pedalItemId, bool enabled) = 0;
|
virtual void OnItemEnabledChanged(int64_t clientId, int64_t pedalItemId, bool enabled) = 0;
|
||||||
virtual void OnControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value) = 0;
|
virtual void OnControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value) = 0;
|
||||||
virtual void OnVst3ControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value, const std::string&state) = 0;
|
virtual void OnVst3ControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value, const std::string &state) = 0;
|
||||||
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard) = 0;
|
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard) = 0;
|
||||||
virtual void OnPresetsChanged(int64_t clientId, const PresetIndex&presets) = 0;
|
virtual void OnPresetsChanged(int64_t clientId, const PresetIndex &presets) = 0;
|
||||||
virtual void OnPluginPresetsChanged(const std::string&pluginUri) = 0;
|
virtual void OnPluginPresetsChanged(const std::string &pluginUri) = 0;
|
||||||
virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection&channelSelection) = 0;
|
virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection &channelSelection) = 0;
|
||||||
virtual void OnVuMeterUpdate(const std::vector<VuUpdate>& updates) = 0;
|
virtual void OnVuMeterUpdate(const std::vector<VuUpdate> &updates) = 0;
|
||||||
virtual void OnBankIndexChanged(const BankIndex& bankIndex) = 0;
|
virtual void OnBankIndexChanged(const BankIndex &bankIndex) = 0;
|
||||||
virtual void OnJackServerSettingsChanged(const JackServerSettings& jackServerSettings) = 0;
|
virtual void OnJackServerSettingsChanged(const JackServerSettings &jackServerSettings) = 0;
|
||||||
virtual void OnJackConfigurationChanged(const JackConfiguration& jackServerConfiguration) = 0;
|
virtual void OnJackConfigurationChanged(const JackConfiguration &jackServerConfiguration) = 0;
|
||||||
virtual void OnLoadPluginPreset(int64_t instanceId,const std::vector<ControlValue>&controlValues) = 0;
|
virtual void OnLoadPluginPreset(int64_t instanceId, const std::vector<ControlValue> &controlValues) = 0;
|
||||||
virtual void OnMidiValueChanged(int64_t instanceId, const std::string&symbol, float value) = 0;
|
virtual void OnMidiValueChanged(int64_t instanceId, const std::string &symbol, float value) = 0;
|
||||||
virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0;
|
virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0;
|
||||||
virtual void OnNotifyAtomOutput(int64_t clientModel,uint64_t instanceId,const std::string&atomType, const std::string&atomJson) = 0;
|
virtual void OnNotifyAtomOutput(int64_t clientModel, uint64_t instanceId, const std::string &atomType, const std::string &atomJson) = 0;
|
||||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) = 0;
|
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings &wifiConfigSettings) = 0;
|
||||||
virtual void OnWifiDirectConfigSettingsChanged(const WifiDirectConfigSettings&wifiDirectConfigSettings) = 0;
|
virtual void OnWifiDirectConfigSettingsChanged(const WifiDirectConfigSettings &wifiDirectConfigSettings) = 0;
|
||||||
virtual void OnGovernorSettingsChanged(const std::string &governor) = 0;
|
virtual void OnGovernorSettingsChanged(const std::string &governor) = 0;
|
||||||
virtual void OnFavoritesChanged(const std::map<std::string,bool> &favorites) = 0;
|
virtual void OnFavoritesChanged(const std::map<std::string, bool> &favorites) = 0;
|
||||||
virtual void OnShowStatusMonitorChanged(bool show) = 0;
|
virtual void OnShowStatusMonitorChanged(bool show) = 0;
|
||||||
|
virtual void OnSystemMidiBindingsChanged(const std::vector<MidiBinding>&bindings) = 0;
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PiPedalModel: private IJackHostCallbacks {
|
class PiPedalModel : private IAudioHostCallbacks
|
||||||
private:
|
{
|
||||||
|
private:
|
||||||
std::unique_ptr<std::jthread> pingThread;
|
std::unique_ptr<std::jthread> pingThread;
|
||||||
|
|
||||||
|
std::vector<MidiBinding> systemMidiBindings;
|
||||||
|
|
||||||
AvahiService avahiService;
|
AvahiService avahiService;
|
||||||
uint16_t webPort;
|
uint16_t webPort;
|
||||||
|
|
||||||
@@ -85,14 +87,15 @@ private:
|
|||||||
|
|
||||||
AdminClient adminClient;
|
AdminClient adminClient;
|
||||||
|
|
||||||
|
class MidiListener
|
||||||
class MidiListener {
|
{
|
||||||
public:
|
public:
|
||||||
int64_t clientId;
|
int64_t clientId;
|
||||||
int64_t clientHandle;
|
int64_t clientHandle;
|
||||||
bool listenForControlsOnly;
|
bool listenForControlsOnly;
|
||||||
};
|
};
|
||||||
class AtomOutputListener {
|
class AtomOutputListener
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
int64_t clientId;
|
int64_t clientId;
|
||||||
int64_t clientHandle;
|
int64_t clientHandle;
|
||||||
@@ -110,26 +113,25 @@ private:
|
|||||||
Storage storage;
|
Storage storage;
|
||||||
bool hasPresetChanged = false;
|
bool hasPresetChanged = false;
|
||||||
|
|
||||||
std::unique_ptr<JackHost> jackHost;
|
std::unique_ptr<AudioHost> audioHost;
|
||||||
JackConfiguration jackConfiguration;
|
JackConfiguration jackConfiguration;
|
||||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard;
|
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard;
|
||||||
std::filesystem::path webRoot;
|
std::filesystem::path webRoot;
|
||||||
|
|
||||||
|
std::vector<IPiPedalModelSubscriber *> subscribers;
|
||||||
std::vector<IPiPedalModelSubscriber*> subscribers;
|
void SetPresetChanged(int64_t clientId, bool value);
|
||||||
void SetPresetChanged(int64_t clientId,bool value);
|
|
||||||
void FirePresetsChanged(int64_t clientId);
|
void FirePresetsChanged(int64_t clientId);
|
||||||
void FirePluginPresetsChanged(const std::string &pluginUri);
|
void FirePluginPresetsChanged(const std::string &pluginUri);
|
||||||
void FirePedalBoardChanged(int64_t clientId);
|
void FirePedalBoardChanged(int64_t clientId);
|
||||||
void FireChannelSelectionChanged(int64_t clientId);
|
void FireChannelSelectionChanged(int64_t clientId);
|
||||||
void FireBanksChanged(int64_t clientId);
|
void FireBanksChanged(int64_t clientId);
|
||||||
void FireJackConfigurationChanged(const JackConfiguration&jackConfiguration);
|
void FireJackConfigurationChanged(const JackConfiguration &jackConfiguration);
|
||||||
|
|
||||||
void UpdateDefaults(PedalBoardItem*pedalBoardItem);
|
void UpdateDefaults(PedalBoardItem *pedalBoardItem);
|
||||||
void UpdateDefaults(PedalBoard*pedalBoard);
|
void UpdateDefaults(PedalBoard *pedalBoard);
|
||||||
|
|
||||||
|
class VuSubscription
|
||||||
class VuSubscription {
|
{
|
||||||
public:
|
public:
|
||||||
int64_t subscriptionHandle;
|
int64_t subscriptionHandle;
|
||||||
int64_t instanceid;
|
int64_t instanceid;
|
||||||
@@ -141,25 +143,28 @@ private:
|
|||||||
|
|
||||||
void UpdateRealtimeVuSubscriptions();
|
void UpdateRealtimeVuSubscriptions();
|
||||||
void UpdateRealtimeMonitorPortSubscriptions();
|
void UpdateRealtimeMonitorPortSubscriptions();
|
||||||
void OnVuUpdate(const std::vector<VuUpdate>& updates);
|
void OnVuUpdate(const std::vector<VuUpdate> &updates);
|
||||||
|
|
||||||
void RestartAudio();
|
void RestartAudio();
|
||||||
|
|
||||||
std::vector<RealtimeParameterRequest*> outstandingParameterRequests;
|
std::vector<RealtimeParameterRequest *> outstandingParameterRequests;
|
||||||
|
|
||||||
IPiPedalModelSubscriber*GetNotificationSubscriber(int64_t clientId);
|
IPiPedalModelSubscriber *GetNotificationSubscriber(int64_t clientId);
|
||||||
|
|
||||||
private: // IJackHostCallbacks
|
private: // IAudioHostCallbacks
|
||||||
virtual void OnNotifyVusSubscription(const std::vector<VuUpdate> & updates);
|
virtual void OnNotifyVusSubscription(const std::vector<VuUpdate> &updates);
|
||||||
virtual void OnNotifyMonitorPort(const MonitorPortUpdate &update);
|
virtual void OnNotifyMonitorPort(const MonitorPortUpdate &update);
|
||||||
virtual void OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, float value);
|
virtual void OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, float value);
|
||||||
virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl);
|
virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl);
|
||||||
virtual void OnNotifyAtomOutput(uint64_t instanceId, const std::string&atomType,const std::string&atomJson);
|
virtual void OnNotifyAtomOutput(uint64_t instanceId, const std::string &atomType, const std::string &atomJson);
|
||||||
|
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest);
|
||||||
|
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest&request);
|
||||||
|
|
||||||
void UpdateVst3Settings(PedalBoard&pedalBoard);
|
void UpdateVst3Settings(PedalBoard &pedalBoard);
|
||||||
|
|
||||||
PiPedalConfiguration configuration;
|
PiPedalConfiguration configuration;
|
||||||
public:
|
|
||||||
|
public:
|
||||||
PiPedalModel();
|
PiPedalModel();
|
||||||
virtual ~PiPedalModel();
|
virtual ~PiPedalModel();
|
||||||
|
|
||||||
@@ -168,103 +173,102 @@ public:
|
|||||||
|
|
||||||
void UpdateDnsSd();
|
void UpdateDnsSd();
|
||||||
|
|
||||||
AdminClient&GetAdminClient() { return adminClient; }
|
AdminClient &GetAdminClient() { return adminClient; }
|
||||||
|
|
||||||
void Init(const PiPedalConfiguration&configuration);
|
void Init(const PiPedalConfiguration &configuration);
|
||||||
|
|
||||||
void LoadLv2PluginInfo();
|
void LoadLv2PluginInfo();
|
||||||
void Load();
|
void Load();
|
||||||
|
|
||||||
const PiPedalHost& GetLv2Host() const { return lv2Host; }
|
const PiPedalHost &GetLv2Host() const { return lv2Host; }
|
||||||
PedalBoard GetCurrentPedalBoardCopy()
|
PedalBoard GetCurrentPedalBoardCopy()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||||
return pedalBoard; // can return a referece because we'd lose mutex protection
|
return pedalBoard; // can return a referece because we'd lose mutex protection
|
||||||
}
|
}
|
||||||
PluginUiPresets GetPluginUiPresets(const std::string& pluginUri);
|
PluginUiPresets GetPluginUiPresets(const std::string &pluginUri);
|
||||||
PluginPresets GetPluginPresets(const std::string&pluginUri);
|
PluginPresets GetPluginPresets(const std::string &pluginUri);
|
||||||
|
|
||||||
void LoadPluginPreset(int64_t pluginInstanceId,uint64_t presetInstanceId);
|
void LoadPluginPreset(int64_t pluginInstanceId, uint64_t presetInstanceId);
|
||||||
|
|
||||||
void AddNotificationSubscription(IPiPedalModelSubscriber* pSubscriber);
|
void AddNotificationSubscription(IPiPedalModelSubscriber *pSubscriber);
|
||||||
void RemoveNotificationSubsription(IPiPedalModelSubscriber* pSubscriber);
|
void RemoveNotificationSubsription(IPiPedalModelSubscriber *pSubscriber);
|
||||||
|
|
||||||
void SetPedalBoardItemEnable(int64_t clientId, int64_t instanceId, bool enabled);
|
void SetPedalBoardItemEnable(int64_t clientId, int64_t instanceId, bool enabled);
|
||||||
void SetControl(int64_t clientId,int64_t pedalItemId, const std::string&symbol,float value);
|
void SetControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value);
|
||||||
void PreviewControl(int64_t clientId,int64_t pedalItemId, const std::string&symbol,float value);
|
void PreviewControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value);
|
||||||
void SetPedalBoard(int64_t clientId,PedalBoard &pedalBoard);
|
void SetPedalBoard(int64_t clientId, PedalBoard &pedalBoard);
|
||||||
void UpdateCurrentPedalBoard(int64_t clientId, PedalBoard &pedalBoard);
|
void UpdateCurrentPedalBoard(int64_t clientId, PedalBoard &pedalBoard);
|
||||||
|
|
||||||
|
void GetPresets(PresetIndex *pResult);
|
||||||
|
|
||||||
void GetPresets(PresetIndex*pResult);
|
|
||||||
PedalBoard GetPreset(int64_t instanceId);
|
PedalBoard GetPreset(int64_t instanceId);
|
||||||
void GetBank(int64_t instanceId, BankFile*pBank);
|
void GetBank(int64_t instanceId, BankFile *pBank);
|
||||||
|
|
||||||
int64_t UploadBank(BankFile&bankFile, int64_t uploadAfter = -1);
|
int64_t UploadBank(BankFile &bankFile, int64_t uploadAfter = -1);
|
||||||
int64_t UploadPreset(const BankFile&bankFile, int64_t uploadAfter = -1);
|
int64_t UploadPreset(const BankFile &bankFile, int64_t uploadAfter = -1);
|
||||||
void UploadPluginPresets(const PluginPresets&pluginPresets);
|
void UploadPluginPresets(const PluginPresets &pluginPresets);
|
||||||
void SaveCurrentPreset(int64_t clientId);
|
void SaveCurrentPreset(int64_t clientId);
|
||||||
int64_t SaveCurrentPresetAs(int64_t clientId, const std::string& name,int64_t saveAfterInstanceId = -1);
|
int64_t SaveCurrentPresetAs(int64_t clientId, const std::string &name, int64_t saveAfterInstanceId = -1);
|
||||||
int64_t SavePluginPresetAs(int64_t instanceId, const std::string&name);
|
int64_t SavePluginPresetAs(int64_t instanceId, const std::string &name);
|
||||||
|
|
||||||
void LoadPreset(int64_t clientId, int64_t instanceId);
|
void LoadPreset(int64_t clientId, int64_t instanceId);
|
||||||
bool UpdatePresets(int64_t clientId,const PresetIndex&presets);
|
bool UpdatePresets(int64_t clientId, const PresetIndex &presets);
|
||||||
void UpdatePluginPresets(const PluginUiPresets&pluginPresets);
|
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
||||||
int64_t DeletePreset(int64_t clientId,int64_t instanceId);
|
int64_t DeletePreset(int64_t clientId, int64_t instanceId);
|
||||||
bool RenamePreset(int64_t clientId,int64_t instanceId,const std::string&name);
|
bool RenamePreset(int64_t clientId, int64_t instanceId, const std::string &name);
|
||||||
int64_t CopyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex);
|
int64_t CopyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex);
|
||||||
uint64_t CopyPluginPreset(const std::string&pluginUri,uint64_t presetId);
|
uint64_t CopyPluginPreset(const std::string &pluginUri, uint64_t presetId);
|
||||||
|
|
||||||
void MoveBank(int64_t clientId,int from, int to);
|
void MoveBank(int64_t clientId, int from, int to);
|
||||||
int64_t DeleteBank(int64_t clientId, int64_t instanceId);
|
int64_t DeleteBank(int64_t clientId, int64_t instanceId);
|
||||||
|
|
||||||
|
int64_t DuplicatePreset(int64_t clientId, int64_t instanceId) { return CopyPreset(clientId, instanceId, -1); }
|
||||||
int64_t DuplicatePreset(int64_t clientId, int64_t instanceId) { return CopyPreset(clientId,instanceId,-1); }
|
|
||||||
|
|
||||||
JackConfiguration GetJackConfiguration();
|
JackConfiguration GetJackConfiguration();
|
||||||
|
|
||||||
void SetJackChannelSelection(int64_t clientId,const JackChannelSelection &channelSelection);
|
void SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection);
|
||||||
JackChannelSelection GetJackChannelSelection();
|
JackChannelSelection GetJackChannelSelection();
|
||||||
|
|
||||||
void SetShowStatusMonitor(bool show);
|
void SetShowStatusMonitor(bool show);
|
||||||
bool GetShowStatusMonitor();
|
bool GetShowStatusMonitor();
|
||||||
|
|
||||||
void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
void SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings);
|
||||||
WifiConfigSettings GetWifiConfigSettings();
|
WifiConfigSettings GetWifiConfigSettings();
|
||||||
|
|
||||||
void SetWifiDirectConfigSettings(const WifiDirectConfigSettings&wifiConfigSettings);
|
void SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiConfigSettings);
|
||||||
WifiDirectConfigSettings GetWifiDirectConfigSettings();
|
WifiDirectConfigSettings GetWifiDirectConfigSettings();
|
||||||
|
|
||||||
void SetGovernorSettings(const std::string& governor);
|
void SetGovernorSettings(const std::string &governor);
|
||||||
GovernorSettings GetGovernorSettings();
|
GovernorSettings GetGovernorSettings();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int64_t AddVuSubscription(int64_t instanceId);
|
int64_t AddVuSubscription(int64_t instanceId);
|
||||||
void RemoveVuSubscription(int64_t subscriptionHandle);
|
void RemoveVuSubscription(int64_t subscriptionHandle);
|
||||||
|
|
||||||
|
void SetSystemMidiBindings(std::vector<MidiBinding> &bindings);
|
||||||
|
std::vector<MidiBinding> GetSystemMidiBidings();
|
||||||
|
|
||||||
int64_t MonitorPort(int64_t instanceId,const std::string &key,float updateInterval, PortMonitorCallback onUpdate);
|
int64_t MonitorPort(int64_t instanceId, const std::string &key, float updateInterval, PortMonitorCallback onUpdate);
|
||||||
void UnmonitorPort(int64_t subscriptionHandle);
|
void UnmonitorPort(int64_t subscriptionHandle);
|
||||||
|
|
||||||
void GetLv2Parameter(
|
void GetLv2Parameter(
|
||||||
int64_t clientId,
|
int64_t clientId,
|
||||||
int64_t instanceId,
|
int64_t instanceId,
|
||||||
const std::string uri,
|
const std::string uri,
|
||||||
std::function<void (const std::string&jsonResjult)> onSuccess,
|
std::function<void(const std::string &jsonResjult)> onSuccess,
|
||||||
std::function<void (const std::string& error)> onError
|
std::function<void(const std::string &error)> onError);
|
||||||
);
|
|
||||||
|
|
||||||
BankIndex GetBankIndex() const;
|
BankIndex GetBankIndex() const;
|
||||||
void RenameBank(int64_t clientId,int64_t bankId, const std::string& newName);
|
void RenameBank(int64_t clientId, int64_t bankId, const std::string &newName);
|
||||||
int64_t SaveBankAs(int64_t clientId,int64_t bankId, const std::string& newName);
|
int64_t SaveBankAs(int64_t clientId, int64_t bankId, const std::string &newName);
|
||||||
void OpenBank(int64_t clientId,int64_t bankId);
|
void OpenBank(int64_t clientId, int64_t bankId);
|
||||||
|
|
||||||
JackHostStatus GetJackStatus() {
|
JackHostStatus GetJackStatus()
|
||||||
return this->jackHost->getJackStatus();
|
{
|
||||||
|
return this->audioHost->getJackStatus();
|
||||||
}
|
}
|
||||||
JackServerSettings GetJackServerSettings();
|
JackServerSettings GetJackServerSettings();
|
||||||
void SetJackServerSettings(const JackServerSettings& jackServerSettings);
|
void SetJackServerSettings(const JackServerSettings &jackServerSettings);
|
||||||
|
|
||||||
void ListenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly);
|
void ListenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly);
|
||||||
void CancelListenForMidiEvent(int64_t clientId, int64_t clientHandle);
|
void CancelListenForMidiEvent(int64_t clientId, int64_t clientHandle);
|
||||||
@@ -273,10 +277,10 @@ public:
|
|||||||
void CancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle);
|
void CancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle);
|
||||||
|
|
||||||
std::vector<AlsaDeviceInfo> GetAlsaDevices();
|
std::vector<AlsaDeviceInfo> GetAlsaDevices();
|
||||||
const std::filesystem::path& GetWebRoot() const;
|
const std::filesystem::path &GetWebRoot() const;
|
||||||
|
|
||||||
std::map<std::string,bool> GetFavorites() const;
|
std::map<std::string, bool> GetFavorites() const;
|
||||||
void SetFavorites(const std::map<std::string,bool> &favorites);
|
void SetFavorites(const std::map<std::string, bool> &favorites);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pipedal.
|
} // namespace pipedal.
|
||||||
+16
-1
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2023 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
|
||||||
@@ -1235,6 +1235,17 @@ public:
|
|||||||
pReader->read(&favorites);
|
pReader->read(&favorites);
|
||||||
this->model.SetFavorites(favorites);
|
this->model.SetFavorites(favorites);
|
||||||
}
|
}
|
||||||
|
else if (message == "setSystemMidiBindings")
|
||||||
|
{
|
||||||
|
std::vector<MidiBinding> bindings;
|
||||||
|
pReader->read(&bindings);
|
||||||
|
this->model.SetSystemMidiBindings(bindings);
|
||||||
|
}
|
||||||
|
else if (message == "getSystemMidiBindings")
|
||||||
|
{
|
||||||
|
std::vector<MidiBinding> bindings = this->model.GetSystemMidiBidings();
|
||||||
|
this->Reply(replyTo,"getSystemMidiBindings",bindings);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Lv2Log::error("Unknown message received: %s", message.c_str());
|
Lv2Log::error("Unknown message received: %s", message.c_str());
|
||||||
@@ -1308,6 +1319,10 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual void OnSystemMidiBindingsChanged(const std::vector<MidiBinding>&bindings) {
|
||||||
|
Send("onSystemMidiBindingsChanged",bindings);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void OnFavoritesChanged(const std::map<std::string, bool> &favorites)
|
virtual void OnFavoritesChanged(const std::map<std::string, bool> &favorites)
|
||||||
{
|
{
|
||||||
Send("onFavoritesChanged", favorites);
|
Send("onFavoritesChanged", favorites);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BeastServer.hpp"
|
#include "WebServer.hpp"
|
||||||
#include "PiPedalModel.hpp"
|
#include "PiPedalModel.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2023 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
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "PiPedalException.hpp"
|
#include "PiPedalException.hpp"
|
||||||
#include "Lv2Log.hpp"
|
#include "Lv2Log.hpp"
|
||||||
#include "VuUpdate.hpp"
|
#include "VuUpdate.hpp"
|
||||||
#include "JackHost.hpp"
|
#include "AudioHost.hpp"
|
||||||
namespace pipedal
|
namespace pipedal
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -51,8 +51,25 @@ namespace pipedal
|
|||||||
|
|
||||||
AtomOutput = 17,
|
AtomOutput = 17,
|
||||||
|
|
||||||
|
MidiProgramChange = 18, // program change requested via midi.
|
||||||
|
AckMidiProgramChange = 19,
|
||||||
|
|
||||||
|
NextMidiProgram = 20,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RealtimeNextMidiProgramRequest {
|
||||||
|
int64_t requestId;
|
||||||
|
int32_t direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RealtimeMidiProgramRequest {
|
||||||
|
int64_t requestId;
|
||||||
|
int8_t bank;
|
||||||
|
uint8_t program;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class RealtimeMonitorPortSubscription
|
class RealtimeMonitorPortSubscription
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -304,6 +321,25 @@ namespace pipedal
|
|||||||
write(RingBufferCommand::OnMidiListen, msg);
|
write(RingBufferCommand::OnMidiListen, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notify host of a midi program change request.
|
||||||
|
*
|
||||||
|
* @param bank MIDI bank number, or -1 for current bank.
|
||||||
|
* @param program MIDI program number.
|
||||||
|
*/
|
||||||
|
void OnMidiProgramChange(int64_t _requestId,int8_t _bank,uint8_t _program)
|
||||||
|
{
|
||||||
|
RealtimeMidiProgramRequest msg { requestId:_requestId, bank: _bank,program: _program};
|
||||||
|
|
||||||
|
|
||||||
|
write(RingBufferCommand::MidiProgramChange,msg);
|
||||||
|
}
|
||||||
|
void OnNextMidiProgram(int64_t requestId,int32_t direction)
|
||||||
|
{
|
||||||
|
RealtimeNextMidiProgramRequest msg { requestId: requestId, direction:direction};
|
||||||
|
write(RingBufferCommand::NextMidiProgram,msg);
|
||||||
|
}
|
||||||
|
|
||||||
void SetControlValue(int effectIndex, int controlIndex, float value)
|
void SetControlValue(int effectIndex, int controlIndex, float value)
|
||||||
{
|
{
|
||||||
SetControlValueBody body;
|
SetControlValueBody body;
|
||||||
@@ -351,6 +387,10 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
write(RingBufferCommand::SetVuSubscriptions, configuration);
|
write(RingBufferCommand::SetVuSubscriptions, configuration);
|
||||||
}
|
}
|
||||||
|
void AckMidiProgramRequest(int64_t requestId)
|
||||||
|
{
|
||||||
|
write(RingBufferCommand::AckMidiProgramChange,requestId);
|
||||||
|
}
|
||||||
|
|
||||||
void SetMonitorPortSubscriptions(RealtimeMonitorPortSubscriptions *subscriptions)
|
void SetMonitorPortSubscriptions(RealtimeMonitorPortSubscriptions *subscriptions)
|
||||||
{
|
{
|
||||||
|
|||||||
+52
-1
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2022 Robin Davies
|
// Copyright (c) 2022-2023 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
|
||||||
@@ -511,6 +511,7 @@ void Storage::SetPresetIndex(const PresetIndex &presets)
|
|||||||
this->currentBank = std::move(bankFile); // deleting any stray presets while we're at it.
|
this->currentBank = std::move(bankFile); // deleting any stray presets while we're at it.
|
||||||
this->SaveCurrentBank();
|
this->SaveCurrentBank();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Storage::GetPresetIndex(PresetIndex *pResult)
|
void Storage::GetPresetIndex(PresetIndex *pResult)
|
||||||
{
|
{
|
||||||
*pResult = PresetIndex();
|
*pResult = PresetIndex();
|
||||||
@@ -523,6 +524,15 @@ void Storage::GetPresetIndex(PresetIndex *pResult)
|
|||||||
pResult->presets().push_back(entry);
|
pResult->presets().push_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int64_t Storage::GetPresetByProgramNumber(uint8_t program)const
|
||||||
|
{
|
||||||
|
if (program >= currentBank.presets().size())
|
||||||
|
{
|
||||||
|
if (currentBank.presets().size() == 0) return -1;
|
||||||
|
program = (uint8_t)currentBank.presets().size()-1;
|
||||||
|
}
|
||||||
|
return currentBank.presets()[program]->instanceId();
|
||||||
|
}
|
||||||
|
|
||||||
PedalBoard Storage::GetPreset(int64_t instanceId) const
|
PedalBoard Storage::GetPreset(int64_t instanceId) const
|
||||||
{
|
{
|
||||||
@@ -736,6 +746,17 @@ void Storage::MoveBank(int from, int to)
|
|||||||
this->bankIndex.move(from, to);
|
this->bankIndex.move(from, to);
|
||||||
this->SaveBankIndex();
|
this->SaveBankIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64_t Storage::GetBankByMidiBankNumber(uint8_t bankNumber) {
|
||||||
|
auto &entries = this->bankIndex.entries();
|
||||||
|
if (bankNumber >= entries.size())
|
||||||
|
{
|
||||||
|
if (entries.size() == 0) return -1;
|
||||||
|
bankNumber = (uint8_t)(entries.size()-1);
|
||||||
|
}
|
||||||
|
return entries[bankNumber].instanceId();
|
||||||
|
}
|
||||||
int64_t Storage::DeleteBank(int64_t bankId)
|
int64_t Storage::DeleteBank(int64_t bankId)
|
||||||
{
|
{
|
||||||
auto &entries = this->bankIndex.entries();
|
auto &entries = this->bankIndex.entries();
|
||||||
@@ -1333,6 +1354,36 @@ void Storage::SetJackServerSettings(const pipedal::JackServerSettings &jackConfi
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Storage::SetSystemMidiBindings(const std::vector<MidiBinding>&bindings)
|
||||||
|
{
|
||||||
|
std::filesystem::path fileName = this->dataRoot / "SystemMidiBindings.json";
|
||||||
|
std::ofstream f;
|
||||||
|
f.open(fileName);
|
||||||
|
if (f.is_open())
|
||||||
|
{
|
||||||
|
json_writer writer(f);
|
||||||
|
writer.write(bindings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||||
|
{
|
||||||
|
std::vector<MidiBinding> result;
|
||||||
|
|
||||||
|
std::filesystem::path fileName = this->dataRoot / "SystemMidiBindings.json";
|
||||||
|
std::ifstream f;
|
||||||
|
f.open(fileName);
|
||||||
|
if (f.is_open())
|
||||||
|
{
|
||||||
|
json_reader reader(f);
|
||||||
|
reader.read(&result);
|
||||||
|
} else {
|
||||||
|
result.push_back(MidiBinding::SystemBinding("prevProgram"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("nextProgram"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JSON_MAP_BEGIN(UserSettings)
|
JSON_MAP_BEGIN(UserSettings)
|
||||||
JSON_MAP_REFERENCE(UserSettings, governor)
|
JSON_MAP_REFERENCE(UserSettings, governor)
|
||||||
JSON_MAP_REFERENCE(UserSettings, showStatusMonitor)
|
JSON_MAP_REFERENCE(UserSettings, showStatusMonitor)
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ public:
|
|||||||
void LoadUserSettings();
|
void LoadUserSettings();
|
||||||
void SaveUserSettings();
|
void SaveUserSettings();
|
||||||
void LoadBank(int64_t instanceId);
|
void LoadBank(int64_t instanceId);
|
||||||
|
int64_t GetBankByMidiBankNumber(uint8_t bankNumber);
|
||||||
const PedalBoard& GetCurrentPreset();
|
const PedalBoard& GetCurrentPreset();
|
||||||
void SaveCurrentPreset(const PedalBoard&pedalBoard);
|
void SaveCurrentPreset(const PedalBoard&pedalBoard);
|
||||||
int64_t SaveCurrentPresetAs(const PedalBoard&pedalBoard, const std::string&namne,int64_t saveAfterInstanceId = -1);
|
int64_t SaveCurrentPresetAs(const PedalBoard&pedalBoard, const std::string&namne,int64_t saveAfterInstanceId = -1);
|
||||||
@@ -116,6 +117,7 @@ public:
|
|||||||
void GetPresetIndex(PresetIndex*pResult);
|
void GetPresetIndex(PresetIndex*pResult);
|
||||||
void SetPresetIndex(const PresetIndex &presetIndex);
|
void SetPresetIndex(const PresetIndex &presetIndex);
|
||||||
PedalBoard GetPreset(int64_t instanceId) const;
|
PedalBoard GetPreset(int64_t instanceId) const;
|
||||||
|
int64_t GetPresetByProgramNumber(uint8_t program) const;
|
||||||
void GetBankFile(int64_t instanceId,BankFile*pResult) const;
|
void GetBankFile(int64_t instanceId,BankFile*pResult) const;
|
||||||
int64_t UploadPreset(const BankFile&bankFile, int64_t uploadAfter);
|
int64_t UploadPreset(const BankFile&bankFile, int64_t uploadAfter);
|
||||||
int64_t UploadBank(BankFile&bankFile, int64_t uploadAfter);
|
int64_t UploadBank(BankFile&bankFile, int64_t uploadAfter);
|
||||||
@@ -170,6 +172,8 @@ public:
|
|||||||
|
|
||||||
void SetShowStatusMonitor(bool show);
|
void SetShowStatusMonitor(bool show);
|
||||||
bool GetShowStatusMonitor() const;
|
bool GetShowStatusMonitor() const;
|
||||||
|
void SetSystemMidiBindings(const std::vector<MidiBinding>&bindings);
|
||||||
|
std::vector<MidiBinding> GetSystemMidiBindings();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include "Ipv6Helpers.hpp"
|
#include "Ipv6Helpers.hpp"
|
||||||
|
|
||||||
#include "BeastServer.hpp"
|
#include "WebServer.hpp"
|
||||||
|
|
||||||
#include "Uri.hpp"
|
#include "Uri.hpp"
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ std::string GetFromAddress(const tcp::socket &socket)
|
|||||||
namespace pipedal
|
namespace pipedal
|
||||||
{
|
{
|
||||||
|
|
||||||
class BeastServerImpl : public BeastServer
|
class WebServerImpl : public WebServer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int signalOnDone = -1;
|
int signalOnDone = -1;
|
||||||
@@ -200,7 +200,7 @@ namespace pipedal
|
|||||||
|
|
||||||
class WebSocketSession : public std::enable_shared_from_this<WebSocketSession>, public SocketHandler::IWriteCallback
|
class WebSocketSession : public std::enable_shared_from_this<WebSocketSession>, public SocketHandler::IWriteCallback
|
||||||
{
|
{
|
||||||
BeastServerImpl *pServer;
|
WebServerImpl *pServer;
|
||||||
server::connection_ptr webSocket;
|
server::connection_ptr webSocket;
|
||||||
std::string fromAddress;
|
std::string fromAddress;
|
||||||
std::shared_ptr<SocketHandler> socketHandler;
|
std::shared_ptr<SocketHandler> socketHandler;
|
||||||
@@ -224,7 +224,7 @@ namespace pipedal
|
|||||||
Lv2Log::info("WebSocketSession closed.");
|
Lv2Log::info("WebSocketSession closed.");
|
||||||
}
|
}
|
||||||
using ptr = std::shared_ptr<WebSocketSession>;
|
using ptr = std::shared_ptr<WebSocketSession>;
|
||||||
WebSocketSession(BeastServerImpl *pServer, server::connection_ptr &webSocket)
|
WebSocketSession(WebServerImpl *pServer, server::connection_ptr &webSocket)
|
||||||
: pServer(pServer),
|
: pServer(pServer),
|
||||||
webSocket(webSocket)
|
webSocket(webSocket)
|
||||||
{
|
{
|
||||||
@@ -599,9 +599,9 @@ namespace pipedal
|
|||||||
using websocketpp::lib::placeholders::_1;
|
using websocketpp::lib::placeholders::_1;
|
||||||
using websocketpp::lib::placeholders::_2;
|
using websocketpp::lib::placeholders::_2;
|
||||||
|
|
||||||
m_endpoint.set_open_handler(bind(&BeastServerImpl::on_open, this, _1));
|
m_endpoint.set_open_handler(bind(&WebServerImpl::on_open, this, _1));
|
||||||
m_endpoint.set_close_handler(bind(&BeastServerImpl::on_close, this, _1));
|
m_endpoint.set_close_handler(bind(&WebServerImpl::on_close, this, _1));
|
||||||
m_endpoint.set_http_handler(bind(&BeastServerImpl::on_http, this, _1));
|
m_endpoint.set_http_handler(bind(&WebServerImpl::on_http, this, _1));
|
||||||
|
|
||||||
std::string hostName = getHostName();
|
std::string hostName = getHostName();
|
||||||
if (hostName.length() != 0)
|
if (hostName.length() != 0)
|
||||||
@@ -660,7 +660,7 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ThreadProc(BeastServerImpl *server)
|
static void ThreadProc(WebServerImpl *server)
|
||||||
{
|
{
|
||||||
server->Run();
|
server->Run();
|
||||||
}
|
}
|
||||||
@@ -717,7 +717,7 @@ namespace pipedal
|
|||||||
this->pBgThread = new std::thread(ThreadProc, this);
|
this->pBgThread = new std::thread(ThreadProc, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
BeastServerImpl(const std::string &address, int port, const char *rootPath, int threads)
|
WebServerImpl(const std::string &address, int port, const char *rootPath, int threads)
|
||||||
: address(address),
|
: address(address),
|
||||||
rootPath(rootPath),
|
rootPath(rootPath),
|
||||||
port(port),
|
port(port),
|
||||||
@@ -727,7 +727,7 @@ namespace pipedal
|
|||||||
};
|
};
|
||||||
} // namespace pipedal
|
} // namespace pipedal
|
||||||
|
|
||||||
std::shared_ptr<ISocketFactory> BeastServerImpl::GetSocketFactory(const uri &requestUri)
|
std::shared_ptr<ISocketFactory> WebServerImpl::GetSocketFactory(const uri &requestUri)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (auto factory : this->socket_factories)
|
for (auto factory : this->socket_factories)
|
||||||
@@ -740,7 +740,7 @@ std::shared_ptr<ISocketFactory> BeastServerImpl::GetSocketFactory(const uri &req
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<BeastServer> pipedal::createBeastServer(const boost::asio::ip::address &address, int port, const char *rootPath, int threads)
|
std::shared_ptr<WebServer> pipedal::WebServer::create(const boost::asio::ip::address &address, int port, const char *rootPath, int threads)
|
||||||
{
|
{
|
||||||
return std::shared_ptr<BeastServer>(new BeastServerImpl(address.to_string(), port, rootPath, threads));
|
return std::shared_ptr<WebServer>(new WebServerImpl(address.to_string(), port, rootPath, threads));
|
||||||
}
|
}
|
||||||
@@ -68,10 +68,10 @@ public:
|
|||||||
//xxx move this to HtmlHelpers.
|
//xxx move this to HtmlHelpers.
|
||||||
std::string last_modified(const std::filesystem::path& path);
|
std::string last_modified(const std::filesystem::path& path);
|
||||||
|
|
||||||
class BeastServerImpl;
|
class WebServerImpl;
|
||||||
|
|
||||||
class SocketHandler {
|
class SocketHandler {
|
||||||
friend class BeastServerImpl;
|
friend class WebServerImpl;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class IWriteCallback {
|
class IWriteCallback {
|
||||||
@@ -213,9 +213,9 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BeastServer {
|
class WebServer {
|
||||||
public:
|
public:
|
||||||
virtual ~BeastServer() { }
|
virtual ~WebServer() { }
|
||||||
|
|
||||||
virtual void SetLogHttpRequests(bool enableLogging) = 0;
|
virtual void SetLogHttpRequests(bool enableLogging) = 0;
|
||||||
|
|
||||||
@@ -227,10 +227,17 @@ public:
|
|||||||
|
|
||||||
// signalOnDone: fire the specified POSIX signal when the service thread terminates. -1 for no signal.
|
// signalOnDone: fire the specified POSIX signal when the service thread terminates. -1 for no signal.
|
||||||
virtual void RunInBackground(int signalOnDone = -1) = 0;
|
virtual void RunInBackground(int signalOnDone = -1) = 0;
|
||||||
|
|
||||||
|
static std::shared_ptr<WebServer> create(
|
||||||
|
const boost::asio::ip::address &address,
|
||||||
|
int port,
|
||||||
|
const char *rootPath,
|
||||||
|
int threads);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<BeastServer> createBeastServer(const boost::asio::ip::address &address, int port, const char *rootPath, int threads);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -19,13 +19,13 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
#include "BeastServer.hpp"
|
#include "WebServer.hpp"
|
||||||
#include "MemDebug.hpp"
|
#include "MemDebug.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace pipedal;
|
using namespace pipedal;
|
||||||
|
|
||||||
TEST_CASE("BeastServer shutdown", "[beastServerShutdown][Build][Dev]")
|
TEST_CASE("WebServer shutdown", "[webServerShutdown][Build][Dev]")
|
||||||
{
|
{
|
||||||
MemStats initialMemory = GetMemStats();
|
MemStats initialMemory = GetMemStats();
|
||||||
{
|
{
|
||||||
@@ -34,7 +34,7 @@ TEST_CASE("BeastServer shutdown", "[beastServerShutdown][Build][Dev]")
|
|||||||
std::string doc_root = ".";
|
std::string doc_root = ".";
|
||||||
auto const threads = 3;
|
auto const threads = 3;
|
||||||
|
|
||||||
auto server = createBeastServer(
|
auto server = WebServer::create(
|
||||||
address, port, doc_root.c_str(), threads);
|
address, port, doc_root.c_str(), threads);
|
||||||
server->RunInBackground();
|
server->RunInBackground();
|
||||||
sleep(5);
|
sleep(5);
|
||||||
+3
-3
@@ -20,7 +20,7 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
#include "AudioConfig.hpp"
|
#include "AudioConfig.hpp"
|
||||||
#include "BeastServer.hpp"
|
#include "WebServer.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Lv2Log.hpp"
|
#include "Lv2Log.hpp"
|
||||||
#include "ServiceConfiguration.hpp"
|
#include "ServiceConfiguration.hpp"
|
||||||
@@ -601,7 +601,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
std::shared_ptr<BeastServer> server;
|
std::shared_ptr<WebServer> server;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto const address = boost::asio::ip::make_address(configuration.GetSocketServerAddress());
|
auto const address = boost::asio::ip::make_address(configuration.GetSocketServerAddress());
|
||||||
@@ -609,7 +609,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
auto const threads = std::max<int>(1, configuration.GetThreads());
|
auto const threads = std::max<int>(1, configuration.GetThreads());
|
||||||
|
|
||||||
server = createBeastServer(
|
server = WebServer::create(
|
||||||
address, port, web_root.c_str(), threads);
|
address, port, web_root.c_str(), threads);
|
||||||
|
|
||||||
Lv2Log::info("Document root: %s Threads: %d", doc_root.c_str(), (int)threads);
|
Lv2Log::info("Document root: %s Threads: %d", doc_root.c_str(), (int)threads);
|
||||||
|
|||||||
+2
-2
@@ -42,8 +42,8 @@ add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY)
|
|||||||
add_executable(piddletest main.cpp pch.h UriTest.cpp JsonTest.cpp
|
add_executable(piddletest main.cpp pch.h UriTest.cpp JsonTest.cpp
|
||||||
|
|
||||||
|
|
||||||
../src/Uri.cpp ../src/Uri.hpp ../src/HtmlHelper.cpp ../src/HtmlHelper.hpp BeastServerTest.cpp
|
../src/Uri.cpp ../src/Uri.hpp ../src/HtmlHelper.cpp ../src/HtmlHelper.hpp WebServerTest.cpp
|
||||||
../src/BeastServer.cpp ../src/BeastServer.hpp ../src/json.hpp ../src/json.cpp
|
../src/WebServer.cpp ../src/WebServer.hpp ../src/json.hpp ../src/json.cpp
|
||||||
../src/Lv2Host.cpp ../src/Lv2Host.hpp
|
../src/Lv2Host.cpp ../src/Lv2Host.hpp
|
||||||
../src/Lv2Log.hpp ../src/Lv2Log.cpp
|
../src/Lv2Log.hpp ../src/Lv2Log.cpp
|
||||||
../src/PluginType.hpp ../src/PluginType.cpp
|
../src/PluginType.hpp ../src/PluginType.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user