Plugin Presets.
This commit is contained in:
Executable
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
|
||||
<path d="M19.495,8.991l-0.003-3.993c0-1.1-0.891-2-1.99-2h-4h-3h-4c-1.1,0-1.99,0.9-1.99,2L4.509,8.991L4.502,8.998v10
|
||||
c0,1.1,0.891,2,1.99,2h0.01h11h0.01c1.1,0,1.99-0.9,1.99-2v-10L19.495,8.991z M17.502,9.998v9h-11v-9v-5h5h1h5V9.998z"/>
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="6.002" y1="11.998" x2="12.002" y2="11.998"/>
|
||||
<line fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="15.261" y1="11.998" x2="18.066" y2="11.998"/>
|
||||
<path d="M12.002,7.998c-1.474,0-2.75,0.81-3.443,2h3.443c1.103,0,2,0.896,2,2s-0.897,2-2,2H8.558c0.694,1.189,1.97,2,3.444,2
|
||||
c2.206,0,4-1.794,4-4S14.208,7.998,12.002,7.998z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"socket_server_port": 80,
|
||||
"socket_server_port": 8080,
|
||||
"socket_server_address": "*",
|
||||
|
||||
"max_upload_size": 1048576,
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
]
|
||||
|
||||
}
|
||||
}
|
||||
@@ -801,7 +801,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
|
||||
<div className={classes.errorContentMask} />
|
||||
<div style={{ flex: "2 2 3px", height: 20 }} > </div>
|
||||
<div className={classes.errorMessageBox} style={{ position: "relative" }} >
|
||||
<div style={{ fontSize: "30px", position: "absolute", left: 0, top: 0, color: "#A00" }}>
|
||||
<div style={{ fontSize: "30px", position: "absolute", left: 0, top: 3, color: "#A00" }}>
|
||||
<ErrorOutlineIcon color="inherit" fontSize="inherit" style={{ float: "left", marginRight: "12px" }} />
|
||||
</div>
|
||||
<div style={{ marginLeft: 40, marginTop: 3 }}>
|
||||
|
||||
@@ -32,7 +32,7 @@ import ToobCabSimViewFactory from './ToobCabSimView';
|
||||
import ToobPowerStage2Factory from './ToobPowerStage2View';
|
||||
import ToobSpectrumAnalyzerViewFactory from './ToobSpectrumAnalyzerView';
|
||||
import ToobMLViewFactory from './ToobMLView';
|
||||
import {ToobTunerViewFactory,GxTunerViewFactory> from './GxTunerView';
|
||||
import {ToobTunerViewFactory,GxTunerViewFactory} from './GxTunerView';
|
||||
|
||||
|
||||
let pluginFactories: IControlViewFactory[] = [
|
||||
|
||||
@@ -41,6 +41,7 @@ const styles = (theme: Theme) => createStyles({
|
||||
interface GxTunerProps extends WithStyles<typeof styles> {
|
||||
instanceId: number;
|
||||
item: PedalBoardItem;
|
||||
isToobTuner: boolean;
|
||||
|
||||
}
|
||||
interface GxTunerState {
|
||||
@@ -79,6 +80,11 @@ const GxTunerView =
|
||||
{
|
||||
let refFreqIndex = this.getControlIndex("REFFREQ");
|
||||
let thresholdIndex = this.getControlIndex("THRESHOLD");
|
||||
let muteIndex = -1;
|
||||
if (this.props.isToobTuner)
|
||||
{
|
||||
muteIndex = this.getControlIndex("MUTE")
|
||||
}
|
||||
|
||||
let result: (React.ReactNode | ControlGroup)[] = [];
|
||||
|
||||
@@ -87,6 +93,10 @@ const GxTunerView =
|
||||
|
||||
result.push(controls[refFreqIndex]);
|
||||
result.push(controls[thresholdIndex]);
|
||||
if (muteIndex !== -1)
|
||||
{
|
||||
result.push(controls[muteIndex]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
render() {
|
||||
@@ -102,26 +112,24 @@ const GxTunerView =
|
||||
|
||||
|
||||
|
||||
class GxTunerViewFactory implements IControlViewFactory {
|
||||
export class GxTunerViewFactory implements IControlViewFactory {
|
||||
uri: string = GXTUNER_URI;
|
||||
|
||||
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
|
||||
return (<GxTunerView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
|
||||
return (<GxTunerView isToobTuner={false} instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// ToobTuner uses the same controls and control semantics.
|
||||
class ToobTunerViewFactory implements IControlViewFactory {
|
||||
export class ToobTunerViewFactory implements IControlViewFactory {
|
||||
uri: string = TOOBTUNER_URI;
|
||||
|
||||
Create(model: PiPedalModel, pedalBoardItem: PedalBoardItem): React.ReactNode {
|
||||
return (<GxTunerView instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
|
||||
return (<GxTunerView isToobTuner={true} instanceId={pedalBoardItem.instanceId} item={pedalBoardItem} />);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export ToobTunerViewFactory;
|
||||
export GxTunerViewFactory;
|
||||
@@ -55,8 +55,6 @@ const NARROW_DISPLAY_THRESHOLD = 600;
|
||||
const FILTER_STORAGE_KEY = "com.twoplay.pipedal.load_dlg.filter";
|
||||
|
||||
|
||||
let lastClickTime: number = 0;
|
||||
|
||||
|
||||
const pluginGridStyles = (theme: Theme) => createStyles({
|
||||
frame: {
|
||||
@@ -327,7 +325,8 @@ export const LoadPluginDialog =
|
||||
}
|
||||
|
||||
onDoubleClick(e: SyntheticEvent, uri: string): void {
|
||||
this.props.onOk(uri);
|
||||
// handled with onClick e.detail which provides better behaviour on Chrome.
|
||||
// this.props.onOk(uri);
|
||||
}
|
||||
|
||||
|
||||
@@ -342,18 +341,15 @@ export const LoadPluginDialog =
|
||||
}
|
||||
|
||||
|
||||
onClick(e: SyntheticEvent, uri: string): void {
|
||||
onClick(e: React.MouseEvent<HTMLDivElement>, uri: string): void {
|
||||
e.preventDefault();
|
||||
|
||||
let currentTime = Date.now();
|
||||
let dt = currentTime-lastClickTime;
|
||||
let DOUBLE_CLICK_TIME = 500;
|
||||
let isDoubleClick = dt < DOUBLE_CLICK_TIME;
|
||||
lastClickTime = currentTime;
|
||||
|
||||
|
||||
this.setState({ selected_uri: uri });
|
||||
|
||||
// a better doubleclick: tracks how many recent clicks in the same area.
|
||||
// regardless of whether we re-rendered in the interrim.
|
||||
let isDoubleClick = e.detail === 2;
|
||||
// we have to synthesize double clicks because
|
||||
// DOM rewrites interfere with natural double click.
|
||||
if (isDoubleClick)
|
||||
|
||||
@@ -184,8 +184,8 @@ export const MainPage =
|
||||
|
||||
}
|
||||
}
|
||||
handleSelectPluginPreset(instanceId: number, presetName: string) {
|
||||
this.model.loadPluginPreset(instanceId, presetName);
|
||||
handleSelectPluginPreset(instanceId: number, presetInstanceId: number) {
|
||||
this.model.loadPluginPreset(instanceId, presetInstanceId);
|
||||
}
|
||||
onPedalBoardChanged(value: PedalBoard) {
|
||||
this.setState({ pedalBoard: value });
|
||||
@@ -325,12 +325,11 @@ export const MainPage =
|
||||
<span className={classes.author}>{author}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<div style={{ flex: "0 0 auto", verticalAlign: "center" }}>
|
||||
<PluginInfoDialog plugin_uri={pluginUri} />
|
||||
</div>
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<PluginPresetSelector pluginUri={presetsUri}
|
||||
onSelectPreset={(presetName) => this.handleSelectPluginPreset(pedalBoardItem!.instanceId, presetName)}
|
||||
<PluginPresetSelector pluginUri={presetsUri} instanceId={pedalBoardItem?.instanceId ?? 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -133,7 +133,7 @@ export class PedalBoardItem implements Deserializable<PedalBoardItem> {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
throw new PiPedalArgumentError("Control not found.");
|
||||
return false;
|
||||
}
|
||||
setMidiBinding(midiBinding: MidiBinding): boolean {
|
||||
if (this.midiBindings)
|
||||
|
||||
+106
-16
@@ -31,7 +31,7 @@ import { BankIndex } from './Banks';
|
||||
import JackHostStatus from './JackHostStatus';
|
||||
import JackServerSettings from './JackServerSettings';
|
||||
import MidiBinding from './MidiBinding';
|
||||
import PluginPreset from './PluginPreset';
|
||||
import {PluginUiPresets} from './PluginPreset';
|
||||
import WifiConfigSettings from './WifiConfigSettings';
|
||||
import WifiChannel from './WifiChannel';
|
||||
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
||||
@@ -47,6 +47,16 @@ export enum State {
|
||||
|
||||
export type ControlValueChangedHandler = (key: string, value: number) => void;
|
||||
|
||||
|
||||
export type PluginPresetsChangedHandler = (pluginUri: string) => void;
|
||||
|
||||
export interface PluginPresetsChangedHandle {
|
||||
_id: number;
|
||||
_handler: PluginPresetsChangedHandler;
|
||||
|
||||
};
|
||||
|
||||
|
||||
export interface ZoomedControlInfo {
|
||||
source: HTMLElement;
|
||||
instanceId: number;
|
||||
@@ -72,7 +82,6 @@ export interface ControlValueChangedHandle {
|
||||
_ControlValueChangedHandle: number;
|
||||
|
||||
};
|
||||
|
||||
interface ControlValueChangeItem {
|
||||
handle: number;
|
||||
instanceId: number;
|
||||
@@ -341,6 +350,8 @@ export interface PiPedalModel {
|
||||
saveCurrentPreset(): void;
|
||||
saveCurrentPresetAs(newName: string): void;
|
||||
|
||||
saveCurrentPluginPresetAs(pluginInstanceId: number,newName: string): void;
|
||||
|
||||
loadPreset(instanceId: number): void;
|
||||
updatePresets(presets: PresetIndex): Promise<void>;
|
||||
deletePresetItem(instanceId: number): Promise<number>;
|
||||
@@ -372,8 +383,10 @@ export interface PiPedalModel {
|
||||
|
||||
getJackStatus(): Promise<JackHostStatus>;
|
||||
|
||||
getPluginPresets(uri: string): Promise<PluginPreset[]>;
|
||||
loadPluginPreset(instanceId: number, presetName: string): void;
|
||||
getPluginPresets(uri: string): Promise<PluginUiPresets>;
|
||||
loadPluginPreset(pluginInstanceId: number, presetInstanceId: number): void;
|
||||
updatePluginPresets(uri: string, presets: PluginUiPresets): Promise<void>;
|
||||
duplicatePluginPreset(uri: string, instanceId: number): Promise<number>;
|
||||
|
||||
shutdown(): Promise<void>;
|
||||
restart(): Promise<void>;
|
||||
@@ -384,14 +397,17 @@ export interface PiPedalModel {
|
||||
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle
|
||||
removeControlValueChangeListener(handle: ControlValueChangedHandle): void;
|
||||
|
||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler) : PluginPresetsChangedHandle;
|
||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void;
|
||||
|
||||
listenForAtomOutput(instanceId: number, onComplete: (instanceId: number, atomOutput: any) => void): ListenHandle;
|
||||
cancelListenForAtomOutput(listenHandle: ListenHandle): void;
|
||||
|
||||
|
||||
|
||||
download(targetType: string, isntanceId: number): void;
|
||||
download(targetType: string, isntanceId: number|string): void;
|
||||
|
||||
uploadPreset(file: File, uploadAfter: number): Promise<number>;
|
||||
uploadPreset(uploadPage: string,file: File, uploadAfter: number): Promise<number>;
|
||||
uploadBank(file: File, uploadAfter: number): Promise<number>;
|
||||
|
||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void>;
|
||||
@@ -500,6 +516,9 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
let presetsChangedBody = body as PresetsChangedBody;
|
||||
let presets = new PresetIndex().deserialize(presetsChangedBody.presets);
|
||||
this.presets.set(presets);
|
||||
} else if (message === "onPluginPresetsChanged") {
|
||||
let pluginUri = body as string;
|
||||
this.handlePluginPresetsChanged(pluginUri);
|
||||
} else if (message === "onJackConfigurationChanged") {
|
||||
this.jackConfiguration.set(new JackConfiguration().deserialize(body));
|
||||
} else if (message === "onLoadPluginPreset") {
|
||||
@@ -973,6 +992,41 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
}
|
||||
}
|
||||
|
||||
_pluginPresetsChangedHandles: PluginPresetsChangedHandle[] = [];
|
||||
|
||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler) : PluginPresetsChangedHandle {
|
||||
let handle = ++this.nextListenHandle;
|
||||
let t: PluginPresetsChangedHandle = {
|
||||
_id: handle,
|
||||
_handler: onPluginPresetsChanged
|
||||
};
|
||||
this._pluginPresetsChangedHandles.push(t);
|
||||
return t;
|
||||
}
|
||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void
|
||||
{
|
||||
let pos = -1;
|
||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i)
|
||||
{
|
||||
if (this._pluginPresetsChangedHandles[i]._id === handle._id)
|
||||
{
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos !== -1)
|
||||
{
|
||||
this._pluginPresetsChangedHandles.splice(pos,1);
|
||||
}
|
||||
}
|
||||
firePluginPresetsChanged(pluginUri: string): void {
|
||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i)
|
||||
{
|
||||
this._pluginPresetsChangedHandles[i]._handler(pluginUri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
_setPedalBoardControlValue(instanceId: number, key: string, value: number, notifyServer: boolean): void {
|
||||
let pedalBoard = this.pedalBoard.get();
|
||||
@@ -1244,6 +1298,18 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
saveCurrentPluginPresetAs(pluginInstanceId: number,newName: string): Promise<number> {
|
||||
// default behaviour is to save after the currently selected preset.
|
||||
let request: any = {
|
||||
instanceId: pluginInstanceId,
|
||||
name: newName,
|
||||
};
|
||||
return nullCast(this.webSocket)
|
||||
.request<number>("savePluginPresetAs", request)
|
||||
.then((data) => {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
loadPreset(instanceId: number): void {
|
||||
@@ -1473,18 +1539,22 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
return result;
|
||||
}
|
||||
|
||||
presetCache: { [uri: string]: PluginPreset[]; } = {};
|
||||
presetCache: { [uri: string]: PluginUiPresets } = {};
|
||||
|
||||
|
||||
getPluginPresets(uri: string): Promise<PluginPreset[]> {
|
||||
return new Promise<PluginPreset[]>((resolve, reject) => {
|
||||
uncachePluginPreset(pluginUri: string): void {
|
||||
delete this.presetCache[pluginUri];
|
||||
}
|
||||
getPluginPresets(uri: string): Promise<PluginUiPresets> {
|
||||
return new Promise<PluginUiPresets>((resolve, reject) => {
|
||||
if (this.presetCache[uri] !== undefined) {
|
||||
resolve(this.presetCache[uri]);
|
||||
} else {
|
||||
this.webSocket!.request<any>("getPluginPresets", uri)
|
||||
.then((result) => {
|
||||
this.presetCache[uri] = PluginPreset.deserialize_array(result);
|
||||
resolve(result);
|
||||
let presets = new PluginUiPresets().deserialize(result);
|
||||
this.presetCache[uri] = presets;
|
||||
resolve(presets);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
@@ -1493,10 +1563,30 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
});
|
||||
}
|
||||
|
||||
loadPluginPreset(instanceId: number, presetName: string): void {
|
||||
this.webSocket?.send("loadPluginPreset", { instanceId: instanceId, presetName: presetName });
|
||||
loadPluginPreset(pluginInstanceId: number, presetInstanceId: number): void {
|
||||
this.webSocket?.send("loadPluginPreset", { pluginInstanceId: pluginInstanceId, presetInstanceId: presetInstanceId });
|
||||
}
|
||||
|
||||
handlePluginPresetsChanged(pluginUri: string):void {
|
||||
this.uncachePluginPreset(pluginUri);
|
||||
this.firePluginPresetsChanged(pluginUri);
|
||||
}
|
||||
|
||||
|
||||
updatePluginPresets(pluginUri: string, presets: PluginUiPresets): Promise<void>
|
||||
{
|
||||
this.presetCache[pluginUri] = presets;
|
||||
this.firePluginPresetsChanged(pluginUri);
|
||||
return nullCast(this.webSocket).request<void>("updatePluginPresets", presets);
|
||||
}
|
||||
duplicatePluginPreset(pluginUri: string, instanceId: number): Promise<number>
|
||||
{
|
||||
return nullCast(this.webSocket).request<number>("copyPluginPreset", {
|
||||
pluginUri: pluginUri, instanceId: instanceId });
|
||||
|
||||
}
|
||||
|
||||
|
||||
shutdown(): Promise<void> {
|
||||
return this.webSocket!.request<void>("shutdown");
|
||||
}
|
||||
@@ -1596,19 +1686,19 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
this.webSocket?.send("cancelListenForAtomOutput", listenHandle._handle);
|
||||
}
|
||||
|
||||
download(targetType: string, instanceId: number): void {
|
||||
download(targetType: string, instanceId: number | string): void {
|
||||
if (instanceId === -1) return;
|
||||
let url = this.varServerUrl + targetType + "?id=" + instanceId;
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
uploadPreset(file: File, uploadAfter: number): Promise<number> {
|
||||
uploadPreset(uploadPage: string,file: File, uploadAfter: number): Promise<number> {
|
||||
let result = new Promise<number>((resolve, reject) => {
|
||||
try {
|
||||
if (file.size > this.maxUploadSize) {
|
||||
reject("File is too large.");
|
||||
}
|
||||
let url = this.varServerUrl + "uploadPreset";
|
||||
let url = this.varServerUrl + uploadPage;
|
||||
if (uploadAfter && uploadAfter !== -1) {
|
||||
url += "?uploadAfter=" + uploadAfter;
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => {
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
style={{ display: (props.plugin_uri !== "") ? "block" : "none" }}
|
||||
style={{ display: (props.plugin_uri !== "") ? "inline-flex" : "none" }}
|
||||
onClick={handleClickOpen}
|
||||
size="large">
|
||||
<InfoOutlinedIcon />
|
||||
|
||||
@@ -19,21 +19,69 @@
|
||||
|
||||
|
||||
|
||||
export default class PluginPreset {
|
||||
deserialize(input: any): PluginPreset {
|
||||
this.presetUri = input.presetUri;
|
||||
this.name = input.name;
|
||||
export class PluginUiPreset {
|
||||
deserialize(input: any): PluginUiPreset {
|
||||
this.instanceId = input.instanceId;
|
||||
this.label = input.label;
|
||||
return this;
|
||||
}
|
||||
static deserialize_array(input: any) : PluginPreset[] {
|
||||
let result: PluginPreset[] = [];
|
||||
static deserialize_array(input: any) : PluginUiPreset[] {
|
||||
let result: PluginUiPreset[] = [];
|
||||
for (let i = 0; i < input.length; ++i)
|
||||
{
|
||||
result.push(new PluginPreset().deserialize(input[i]));
|
||||
result.push(new PluginUiPreset().deserialize(input[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
presetUri: string = "";
|
||||
name: string = "";
|
||||
instanceId: number = -1;
|
||||
label: string = "";
|
||||
|
||||
static equals(left: PluginUiPreset, right: PluginUiPreset): boolean
|
||||
{
|
||||
return left.instanceId === right.instanceId && left.label === right.label;
|
||||
}
|
||||
}
|
||||
|
||||
export class PluginUiPresets {
|
||||
deserialize(input: any): PluginUiPresets {
|
||||
this.pluginUri = input.pluginUri;
|
||||
this.presets = PluginUiPreset.deserialize_array(input.presets);
|
||||
return this;
|
||||
}
|
||||
|
||||
clone(): PluginUiPresets {
|
||||
return new PluginUiPresets().deserialize(this);
|
||||
}
|
||||
movePreset(from: number, to: number): void
|
||||
{
|
||||
let t = this.presets[from];
|
||||
this.presets.splice(from,1);
|
||||
this.presets.splice(to,0,t);
|
||||
}
|
||||
getItem(instanceId: number): PluginUiPreset | undefined {
|
||||
for (let i = 0; i < this.presets.length; ++i)
|
||||
{
|
||||
if (this.presets[i].instanceId === instanceId)
|
||||
{
|
||||
return this.presets[i];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
static equals(left: PluginUiPresets,right: PluginUiPresets): boolean
|
||||
{
|
||||
if (left.pluginUri !== right.pluginUri) return false;
|
||||
if (left.presets.length !== right.presets.length) return false;
|
||||
for (let i = 0; i < left.presets.length; ++i)
|
||||
{
|
||||
if (!PluginUiPreset.equals(left.presets[i],right.presets[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
pluginUri: string = "";
|
||||
presets: PluginUiPreset[] = [];
|
||||
}
|
||||
@@ -19,30 +19,31 @@
|
||||
|
||||
import { SyntheticEvent, Component } from 'react';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||
import { PiPedalModel, PiPedalModelFactory, PluginPresetsChangedHandle } 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 PresetDialog from './PresetDialog';
|
||||
import PluginPresetsDialog from './PluginPresetsDialog';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Fade from '@mui/material/Fade';
|
||||
import RenameDialog from './RenameDialog'
|
||||
import PluginPreset from './PluginPreset';
|
||||
import {PluginUiPresets} from './PluginPreset';
|
||||
|
||||
import Divider from "@mui/material/Divider";
|
||||
|
||||
|
||||
interface PluginPresetSelectorProps extends WithStyles<typeof styles> {
|
||||
pluginUri?: string;
|
||||
|
||||
onSelectPreset: (presetName: string) => void;
|
||||
instanceId: number;
|
||||
}
|
||||
|
||||
|
||||
interface PluginPresetSelectorState {
|
||||
presets: PluginPreset[] | null;
|
||||
presets : PluginUiPresets;
|
||||
enabled: boolean;
|
||||
presetChanged: boolean;
|
||||
showPresetsDialog: boolean;
|
||||
showEditPresetsDialog: boolean;
|
||||
presetsMenuAnchorRef: HTMLElement | null;
|
||||
@@ -52,10 +53,15 @@ interface PluginPresetSelectorState {
|
||||
renameDialogActionName: string;
|
||||
renameDialogOnOk?: (name: string) => void;
|
||||
|
||||
saveAsName: string;
|
||||
}
|
||||
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
itemIcon: {
|
||||
width: 24, height: 24, marginRight: "4px", opacity: 0.6
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -69,25 +75,27 @@ const PluginPresetSelector =
|
||||
super(props);
|
||||
this.model = PiPedalModelFactory.getInstance();
|
||||
this.state = {
|
||||
presets: null,
|
||||
presets: new PluginUiPresets(),
|
||||
enabled: false,
|
||||
presetChanged: false,
|
||||
showPresetsDialog: false,
|
||||
showEditPresetsDialog: false,
|
||||
presetsMenuAnchorRef: null,
|
||||
renameDialogOpen: false,
|
||||
renameDialogDefaultName: "",
|
||||
renameDialogActionName: "",
|
||||
renameDialogOnOk: undefined
|
||||
renameDialogOnOk: undefined,
|
||||
saveAsName: ""
|
||||
|
||||
};
|
||||
this.handleDialogClose = this.handleDialogClose.bind(this);
|
||||
this.handlePresetsMenuClose = this.handlePresetsMenuClose.bind(this);
|
||||
}
|
||||
|
||||
handleLoadPluginPreset(presetName: string)
|
||||
handleLoadPluginPreset(instanceId: number)
|
||||
{
|
||||
this.handlePresetsMenuClose();
|
||||
this.props.onSelectPreset(presetName);
|
||||
this.model.loadPluginPreset(this.props.instanceId,instanceId);
|
||||
}
|
||||
|
||||
handlePresetMenuClick(e: SyntheticEvent): void {
|
||||
@@ -97,24 +105,16 @@ const PluginPresetSelector =
|
||||
this.setState({ presetsMenuAnchorRef: null });
|
||||
}
|
||||
|
||||
handlePresetsMenuSave(e: SyntheticEvent): void {
|
||||
handlePluginPresetsMenuSaveAs(e: SyntheticEvent): void {
|
||||
this.handlePresetsMenuClose();
|
||||
e.stopPropagation();
|
||||
|
||||
this.model.saveCurrentPreset();
|
||||
}
|
||||
handlePresetsMenuSaveAs(e: SyntheticEvent): void {
|
||||
this.handlePresetsMenuClose();
|
||||
e.stopPropagation();
|
||||
|
||||
let currentPresets = this.model.presets.get();
|
||||
let item = currentPresets.getItem(currentPresets.selectedInstanceId);
|
||||
if (item == null) return;
|
||||
let name = item.name;
|
||||
let name = this.state.saveAsName;
|
||||
|
||||
this.renameDialogOpen(name, "Save As")
|
||||
.then((newName) => {
|
||||
return this.model.saveCurrentPresetAs(newName);
|
||||
this.setState({saveAsName: newName});
|
||||
return this.model.saveCurrentPluginPresetAs(this.props.instanceId,newName);
|
||||
})
|
||||
.then((newInstanceId) => {
|
||||
// s'fine. dealt with by updates, but we do need error handling.
|
||||
@@ -125,26 +125,6 @@ const PluginPresetSelector =
|
||||
;
|
||||
}
|
||||
|
||||
handlePresetsMenuRename(e: SyntheticEvent): void {
|
||||
this.handlePresetsMenuClose();
|
||||
e.stopPropagation();
|
||||
|
||||
let currentPresets = this.model.presets.get();
|
||||
let item = currentPresets.getItem(currentPresets.selectedInstanceId);
|
||||
if (item == null) return;
|
||||
let name = item.name;
|
||||
|
||||
this.renameDialogOpen(name, "Rename")
|
||||
.then((newName) => {
|
||||
if (newName === name) return;
|
||||
return this.model.renamePresetItem(this.model.presets.get().selectedInstanceId, newName);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.showError(error);
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
showError(error: string) {
|
||||
this.model.showAlert(error);
|
||||
}
|
||||
@@ -168,6 +148,49 @@ const PluginPresetSelector =
|
||||
return result;
|
||||
}
|
||||
|
||||
loadPresets():void {
|
||||
if (!this.currentUri) return;
|
||||
let captureUri: string = this.currentUri;
|
||||
this.model.getPluginPresets(captureUri)
|
||||
.then((presets: PluginUiPresets) => {
|
||||
if (captureUri === this.currentUri)
|
||||
{
|
||||
this.setState({presets: presets});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (captureUri === this.currentUri)
|
||||
{
|
||||
this.setState({presets: new PluginUiPresets()});
|
||||
}
|
||||
});
|
||||
}
|
||||
onPluginPresetsChanged(pluginUri: string): void {
|
||||
if (pluginUri === this.props.pluginUri)
|
||||
{
|
||||
this.loadPresets();
|
||||
|
||||
}
|
||||
}
|
||||
_pluginPresetsChangedHandle?: PluginPresetsChangedHandle;
|
||||
|
||||
componentDidMount()
|
||||
{
|
||||
this._pluginPresetsChangedHandle = this.model.addPluginPresetsChangedListener(
|
||||
(pluginUri: string) => {
|
||||
this.onPluginPresetsChanged(pluginUri);
|
||||
}
|
||||
);
|
||||
}
|
||||
componentWillUnmount()
|
||||
{
|
||||
if (this._pluginPresetsChangedHandle)
|
||||
{
|
||||
this.model.removePluginPresetsChangedListener(this._pluginPresetsChangedHandle);
|
||||
this._pluginPresetsChangedHandle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
currentUri?: string = "";
|
||||
componentDidUpdate()
|
||||
{
|
||||
@@ -176,23 +199,9 @@ const PluginPresetSelector =
|
||||
this.currentUri = this.props.pluginUri;
|
||||
if (!this.props.pluginUri)
|
||||
{
|
||||
this.setState({presets: null});
|
||||
this.setState({presets: new PluginUiPresets()});
|
||||
} else {
|
||||
this.setState({presets: null});
|
||||
let captureUri = this.currentUri;
|
||||
this.model.getPluginPresets(this.props.pluginUri)
|
||||
.then((presets: PluginPreset[]) => {
|
||||
if (captureUri === this.currentUri)
|
||||
{
|
||||
this.setState({presets: presets});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (captureUri === this.currentUri)
|
||||
{
|
||||
this.setState({presets: null});
|
||||
}
|
||||
});
|
||||
this.loadPresets();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,9 +223,9 @@ const PluginPresetSelector =
|
||||
}
|
||||
|
||||
|
||||
handleMenuEditPresets(): void {
|
||||
handleMenuEditPluginPresets(): void {
|
||||
this.handlePresetsMenuClose();
|
||||
this.showEditPresetsDialog(true);
|
||||
this.showEditPluginPresetsDialog(true);
|
||||
}
|
||||
|
||||
handleSave() {
|
||||
@@ -229,7 +238,7 @@ const PluginPresetSelector =
|
||||
showEditPresetsDialog: false
|
||||
});
|
||||
}
|
||||
showEditPresetsDialog(show: boolean) {
|
||||
showEditPluginPresetsDialog(show: boolean) {
|
||||
this.setState({
|
||||
showPresetsDialog: show,
|
||||
showEditPresetsDialog: true
|
||||
@@ -252,9 +261,11 @@ const PluginPresetSelector =
|
||||
}
|
||||
|
||||
render() {
|
||||
let classes = this.props.classes;
|
||||
|
||||
//let classes = this.props.classes;
|
||||
//let classes = this.props.classes;
|
||||
if ((!this.props.pluginUri) || (!this.state.presets) ||this.state.presets.length === 0)
|
||||
if ((!this.props.pluginUri))
|
||||
{
|
||||
return (<div/>);
|
||||
}
|
||||
@@ -276,23 +287,27 @@ const PluginPresetSelector =
|
||||
}
|
||||
|
||||
>
|
||||
<Typography variant="caption" color="textSecondary" style={{marginLeft: 16,marginTop:4,marginBottom: 4}}>Plugin presets</Typography>
|
||||
<MenuItem onClick={(e) => this.handlePluginPresetsMenuSaveAs(e)}>Save plugin preset...</MenuItem>
|
||||
<MenuItem onClick={(e) => this.handleMenuEditPluginPresets()}>Manage plugin presets...</MenuItem>
|
||||
|
||||
{ this.state.presets.presets.length !== 0 &&
|
||||
(<Divider/>)
|
||||
}
|
||||
{
|
||||
this.state.presets.map((preset) => {
|
||||
return (<MenuItem key={preset.presetUri}
|
||||
onClick={(e) => this.handleLoadPluginPreset(preset.presetUri)}>{preset.name}</MenuItem>);
|
||||
this.state.presets.presets.map((preset) => {
|
||||
return (<MenuItem key={preset.instanceId}
|
||||
onClick={(e) => this.handleLoadPluginPreset(preset.instanceId)}
|
||||
><img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" />
|
||||
{preset.label}</MenuItem>);
|
||||
})
|
||||
}
|
||||
{/*
|
||||
<Divider />
|
||||
<MenuItem onClick={(e) => this.handlePresetsMenuSave(e)}>Save plugin preset</MenuItem>
|
||||
<MenuItem onClick={(e) => this.handlePresetsMenuSaveAs(e)}>Save plugin preset as...</MenuItem>
|
||||
<MenuItem onClick={(e) => this.handlePresetsMenuRename(e)}>Rename...</MenuItem>
|
||||
<MenuItem onClick={(e) => this.handleMenuEditPresets()}>Manage presets...</MenuItem>
|
||||
*/}
|
||||
|
||||
</Menu>
|
||||
<PresetDialog show={this.state.showPresetsDialog} isEditDialog={this.state.showEditPresetsDialog} onDialogClose={() => this.handleDialogClose()} />
|
||||
<PluginPresetsDialog
|
||||
instanceId={this.props.instanceId}
|
||||
presets={this.state.presets}
|
||||
show={this.state.showPresetsDialog}
|
||||
isEditDialog={this.state.showEditPresetsDialog}
|
||||
onDialogClose={() => this.handleDialogClose()} />
|
||||
<RenameDialog open={this.state.renameDialogOpen}
|
||||
defaultName={this.state.renameDialogDefaultName}
|
||||
acceptActionName={this.state.renameDialogActionName}
|
||||
|
||||
@@ -0,0 +1,488 @@
|
||||
// Copyright (c) 2021 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React, { SyntheticEvent,Component } from 'react';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||
import Button from "@mui/material/Button";
|
||||
import ButtonBase from "@mui/material/ButtonBase";
|
||||
import DialogEx from './DialogEx';
|
||||
import AppBar from '@mui/material/AppBar';
|
||||
import Toolbar from '@mui/material/Toolbar';
|
||||
import DraggableGrid, { ScrollDirection } from './DraggableGrid';
|
||||
import MoreVertIcon from '@mui/icons-material//MoreVert';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
import Menu from '@mui/material/Menu';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Fade from '@mui/material/Fade';
|
||||
import UploadDialog from './UploadDialog';
|
||||
import {PluginUiPresets,PluginUiPreset} from './PluginPreset';
|
||||
|
||||
import SelectHoverBackground from './SelectHoverBackground';
|
||||
import CloseIcon from '@mui/icons-material//Close';
|
||||
import ArrowBackIcon from '@mui/icons-material//ArrowBack';
|
||||
import EditIcon from '@mui/icons-material//Edit';
|
||||
import RenameDialog from './RenameDialog';
|
||||
|
||||
import Slide, {SlideProps} from '@mui/material/Slide';
|
||||
import { createStyles, Theme } from '@mui/material/styles';
|
||||
import { WithStyles, withStyles} from '@mui/styles';
|
||||
|
||||
|
||||
|
||||
interface PluginPresetsDialogProps extends WithStyles<typeof styles> {
|
||||
show: boolean;
|
||||
isEditDialog: boolean;
|
||||
instanceId: number;
|
||||
presets :PluginUiPresets;
|
||||
|
||||
onDialogClose: () => void;
|
||||
|
||||
};
|
||||
|
||||
interface PluginPresetsDialogState {
|
||||
|
||||
showActionBar: boolean;
|
||||
|
||||
selectedItem: number;
|
||||
|
||||
renameOpen: boolean;
|
||||
|
||||
moreMenuAnchorEl: HTMLElement | null;
|
||||
openUploadDialog: boolean;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
dialogAppBar: {
|
||||
position: 'relative',
|
||||
top: 0, left: 0
|
||||
},
|
||||
dialogActionBar: {
|
||||
position: 'relative',
|
||||
top: 0, left: 0,
|
||||
background: "black"
|
||||
},
|
||||
dialogTitle: {
|
||||
marginLeft: theme.spacing(2),
|
||||
flex: 1,
|
||||
},
|
||||
itemFrame: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
flexWrap: "nowrap",
|
||||
width: "100%",
|
||||
height: "56px",
|
||||
alignItems: "center",
|
||||
textAlign: "left",
|
||||
justifyContent: "center",
|
||||
paddingLeft: 8
|
||||
},
|
||||
iconFrame: {
|
||||
flex: "0 0 auto",
|
||||
|
||||
},
|
||||
itemIcon: {
|
||||
width: 24, height: 24, margin: 12, opacity: 0.6
|
||||
},
|
||||
itemLabel: {
|
||||
flex: "1 1 1px",
|
||||
marginLeft: 8
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
const Transition = React.forwardRef(function Transition(
|
||||
props: SlideProps, ref: React.Ref<unknown>
|
||||
) {
|
||||
return (<Slide direction="up" ref={ref} {...props} />);
|
||||
});
|
||||
|
||||
|
||||
const PluginPresetsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
class extends Component<PluginPresetsDialogProps, PluginPresetsDialogState> {
|
||||
|
||||
model: PiPedalModel;
|
||||
|
||||
|
||||
|
||||
constructor(props: PluginPresetsDialogProps) {
|
||||
super(props);
|
||||
this.model = PiPedalModelFactory.getInstance();
|
||||
|
||||
this.handleDialogClose = this.handleDialogClose.bind(this);
|
||||
this.state = {
|
||||
showActionBar: false,
|
||||
selectedItem: -1,
|
||||
renameOpen: false,
|
||||
moreMenuAnchorEl: null,
|
||||
openUploadDialog: false
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
selectItemAtIndex(index: number) {
|
||||
let instanceId = this.props.presets.presets[index].instanceId;
|
||||
this.setState({ selectedItem: instanceId });
|
||||
}
|
||||
isEditMode() {
|
||||
return this.state.showActionBar || this.props.isEditDialog;
|
||||
}
|
||||
|
||||
onMoreClick(e: SyntheticEvent): void {
|
||||
this.setState({ moreMenuAnchorEl: e.currentTarget as HTMLElement })
|
||||
}
|
||||
|
||||
handleDownloadPresets() {
|
||||
this.handleMoreClose();
|
||||
if (this.props.presets.pluginUri !== "")
|
||||
{
|
||||
this.model.download("downloadPluginPresets", this.props.presets.pluginUri);
|
||||
}
|
||||
}
|
||||
handleUploadPresets() {
|
||||
this.handleMoreClose();
|
||||
this.setState({ openUploadDialog: true });
|
||||
|
||||
}
|
||||
handleMoreClose(): void {
|
||||
this.setState({ moreMenuAnchorEl: null });
|
||||
|
||||
}
|
||||
|
||||
|
||||
componentDidUpdate()
|
||||
{
|
||||
if (!this.props.presets.getItem(this.state.selectedItem))
|
||||
{
|
||||
if (this.props.presets.presets.length !== 0)
|
||||
{
|
||||
this.setState({selectedItem: this.props.presets.presets[0].instanceId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
// scroll selected item into view.
|
||||
}
|
||||
componentWillUnmount() {
|
||||
}
|
||||
|
||||
getSelectedIndex() {
|
||||
let instanceId = this.state.selectedItem;
|
||||
let presets = this.props.presets;
|
||||
for (let i = 0; i < presets.presets.length; ++i) {
|
||||
if (presets.presets[i].instanceId === instanceId) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
handleDeleteClick() {
|
||||
let selectedItem = this.state.selectedItem;
|
||||
if (selectedItem !== -1) {
|
||||
let newPresets = this.props.presets.clone();
|
||||
for (let i = 0; i < newPresets.presets.length; ++i)
|
||||
{
|
||||
if (newPresets.presets[i].instanceId === selectedItem)
|
||||
{
|
||||
newPresets.presets.splice(i,1);
|
||||
this.model.updatePluginPresets(newPresets.pluginUri,newPresets)
|
||||
.catch((error) => {
|
||||
this.model.showAlert(error);
|
||||
|
||||
});
|
||||
let newPos = i;
|
||||
if (newPos >= newPresets.presets.length) {
|
||||
--i;
|
||||
}
|
||||
let newSelection = i < 0? -1: newPresets.presets[i].instanceId;
|
||||
this.setState({selectedItem: newSelection});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handleDialogClose() {
|
||||
this.props.onDialogClose();
|
||||
}
|
||||
|
||||
handleItemClick(instanceId: number): void {
|
||||
if (this.isEditMode()) {
|
||||
this.setState({ selectedItem: instanceId });
|
||||
} else {
|
||||
this.model.loadPreset(instanceId);
|
||||
this.props.onDialogClose();
|
||||
}
|
||||
}
|
||||
showActionBar(show: boolean): void {
|
||||
this.setState({ showActionBar: show });
|
||||
|
||||
}
|
||||
|
||||
|
||||
mapElement(el: any): React.ReactNode {
|
||||
let presetEntry = el as PluginUiPreset;
|
||||
let classes = this.props.classes;
|
||||
let selectedItem = this.state.selectedItem;
|
||||
return (
|
||||
<div key={presetEntry.instanceId} style={{ background: "white" }} >
|
||||
|
||||
<ButtonBase style={{ width: "100%", height: 48 }}
|
||||
onClick={() => this.handleItemClick(presetEntry.instanceId)}
|
||||
>
|
||||
<SelectHoverBackground selected={presetEntry.instanceId === selectedItem} showHover={true} />
|
||||
<div className={classes.itemFrame}>
|
||||
<div className={classes.iconFrame}>
|
||||
<img src="img/ic_pluginpreset2.svg" className={classes.itemIcon} alt="" />
|
||||
</div>
|
||||
<div className={classes.itemLabel}>
|
||||
<Typography>
|
||||
{presetEntry.label}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</ButtonBase>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
updateServerPluginPresets(newPresets: PluginUiPresets) {
|
||||
newPresets = newPresets.clone();
|
||||
this.model.updatePluginPresets(this.getPluginUri(),newPresets)
|
||||
.catch((error) => {
|
||||
this.model.showAlert(error);
|
||||
});
|
||||
}
|
||||
moveElement(from: number, to: number): void {
|
||||
let newPresets: PluginUiPresets = this.props.presets.clone();
|
||||
newPresets.movePreset(from, to);
|
||||
this.setState({
|
||||
selectedItem: newPresets.presets[to].instanceId
|
||||
});
|
||||
this.updateServerPluginPresets(newPresets);
|
||||
}
|
||||
|
||||
getSelectedName(): string {
|
||||
let item = this.props.presets.getItem(this.state.selectedItem);
|
||||
if (item) return item.label;
|
||||
return "";
|
||||
}
|
||||
|
||||
handleRenameClick() {
|
||||
let item = this.props.presets.getItem(this.state.selectedItem);
|
||||
if (item) {
|
||||
this.setState({ renameOpen: true });
|
||||
}
|
||||
}
|
||||
handleRenameOk(text: string) {
|
||||
let item = this.props.presets.getItem(this.state.selectedItem);
|
||||
if (!item) return;
|
||||
if (item.label !== text) {
|
||||
let newPresets = this.props.presets.clone();
|
||||
let newItem = newPresets.getItem(this.state.selectedItem);
|
||||
if (!newItem) return;
|
||||
newItem.label = text;
|
||||
this.updateServerPluginPresets(newPresets);
|
||||
}
|
||||
|
||||
this.setState({ renameOpen: false });
|
||||
}
|
||||
getPluginUri() : string {
|
||||
let pedalBoardItem = this.model.pedalBoard.get().getItem(this.props.instanceId);
|
||||
return pedalBoardItem.uri;
|
||||
}
|
||||
handleCopy() {
|
||||
let item = this.props.presets.getItem(this.state.selectedItem);
|
||||
if (!item) return;
|
||||
|
||||
this.model.duplicatePluginPreset(this.getPluginUri(),this.state.selectedItem)
|
||||
.then((newId) => {
|
||||
this.setState({ selectedItem: newId });
|
||||
}).catch((error) => {
|
||||
this.onError(error);
|
||||
});
|
||||
}
|
||||
|
||||
onError(error: string): void {
|
||||
this.model?.showAlert(error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
let classes = this.props.classes;
|
||||
|
||||
let actionBarClass = this.props.isEditDialog ? classes.dialogAppBar : classes.dialogActionBar;
|
||||
let defaultSelectedIndex = this.getSelectedIndex();
|
||||
let title: string = "";
|
||||
let pluginUri = this.getPluginUri();
|
||||
let plugin = this.model.getUiPlugin(pluginUri);
|
||||
if (plugin) {
|
||||
title = "Presets - " + plugin.name;
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<DialogEx tag="PluginPresetsDialog" fullScreen open={this.props.show}
|
||||
onClose={() => { this.handleDialogClose() }} TransitionComponent={Transition}
|
||||
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} style={{ display: this.isEditMode() ? "none" : "block" }} >
|
||||
<Toolbar>
|
||||
<IconButton edge="start" color="inherit" onClick={this.handleDialogClose} aria-label="back"
|
||||
disabled={this.isEditMode()}
|
||||
>
|
||||
<ArrowBackIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" className={classes.dialogTitle}>
|
||||
{title}
|
||||
</Typography>
|
||||
<IconButton color="inherit" onClick={(e) => this.showActionBar(true)} >
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
<AppBar className={actionBarClass} style={{ display: this.isEditMode() ? "block" : "none" }}
|
||||
onClick={(e) => { e.stopPropagation(); e.preventDefault(); }}
|
||||
>
|
||||
<Toolbar>
|
||||
{(!this.props.isEditDialog) ? (
|
||||
<IconButton edge="start" color="inherit" onClick={(e) => this.showActionBar(false)} aria-label="close">
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
) : (
|
||||
<IconButton edge="start" color="inherit" onClick={this.handleDialogClose} aria-label="back"
|
||||
>
|
||||
<ArrowBackIcon />
|
||||
</IconButton>
|
||||
|
||||
)}
|
||||
<Typography variant="h6" className={classes.dialogTitle}>
|
||||
{ title }
|
||||
</Typography>
|
||||
{(this.props.presets.getItem(this.state.selectedItem) != null)
|
||||
&& (
|
||||
|
||||
<div style={{ flex: "0 0 auto" }}>
|
||||
<Button color="inherit" onClick={(e) => this.handleCopy()}>
|
||||
Copy
|
||||
</Button>
|
||||
<Button color="inherit" onClick={() => this.handleRenameClick()}>
|
||||
Rename
|
||||
</Button>
|
||||
<RenameDialog
|
||||
open={this.state.renameOpen}
|
||||
defaultName={this.getSelectedName()}
|
||||
acceptActionName={"Rename"}
|
||||
onClose={() => { this.setState({ renameOpen: false }) }}
|
||||
onOk={(text: string) => {
|
||||
this.handleRenameOk(text);
|
||||
}
|
||||
}
|
||||
/>
|
||||
<IconButton color="inherit" onClick={(e) => this.handleDeleteClick()} >
|
||||
<img src="/img/old_delete_outline_white_24dp.svg" alt="Delete" style={{ width: 24, height: 24, opacity: 0.6 }} />
|
||||
</IconButton>
|
||||
<IconButton color="inherit" onClick={(e) => { this.onMoreClick(e) }} >
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id="more-menu"
|
||||
anchorEl={this.state.moreMenuAnchorEl}
|
||||
keepMounted
|
||||
open={Boolean(this.state.moreMenuAnchorEl)}
|
||||
onClose={() => this.handleMoreClose()}
|
||||
TransitionComponent={Fade}
|
||||
>
|
||||
<MenuItem onClick={() => { this.handleDownloadPresets(); }}
|
||||
disabled={this.props.presets.presets.length === 0}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<img src="img/file_download_black_24dp.svg" style={{ width: 24, height: 24, opacity: 0.6 }} alt="" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Download presets
|
||||
</ListItemText>
|
||||
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => { this.handleUploadPresets() }}>
|
||||
<ListItemIcon>
|
||||
<img src="img/file_upload_black_24dp.svg" style={{ width: 24, height: 24, opacity: 0.6 }} alt="" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
Upload presets
|
||||
</ListItemText>
|
||||
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Toolbar>
|
||||
|
||||
</AppBar>
|
||||
</div>
|
||||
<div style={{ flex: "1 1 auto", position: "relative", overflow: "hidden" }} >
|
||||
<DraggableGrid
|
||||
onLongPress={(item) => this.showActionBar(true)}
|
||||
canDrag={this.isEditMode()}
|
||||
onDragStart={(index, x, y) => { this.selectItemAtIndex(index) }}
|
||||
moveElement={(from, to) => { this.moveElement(from, to); }}
|
||||
scroll={ScrollDirection.Y}
|
||||
defaultSelectedIndex={defaultSelectedIndex}
|
||||
>
|
||||
{
|
||||
this.props.presets.presets.map((element) => {
|
||||
return this.mapElement(element);
|
||||
})
|
||||
}
|
||||
</DraggableGrid>
|
||||
</div>
|
||||
</div>
|
||||
<UploadDialog
|
||||
title="Upload Plugin Presets"
|
||||
extension='.piPluginPresets'
|
||||
uploadPage='uploadPluginPresets'
|
||||
onUploaded={(instanceId) => {} }
|
||||
uploadAfter={this.state.selectedItem}
|
||||
open={this.state.openUploadDialog}
|
||||
onClose={() => { this.setState({ openUploadDialog: false }) }} />
|
||||
|
||||
</DialogEx>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
export default PluginPresetsDialog;
|
||||
@@ -446,6 +446,9 @@ const PresetDialog = withStyles(styles, { withTheme: true })(
|
||||
</div>
|
||||
</div>
|
||||
<UploadDialog
|
||||
title='Upload preset'
|
||||
extension='.piPreset'
|
||||
uploadPage='uploadPreset'
|
||||
onUploaded={(instanceId) => this.setState({selectedItem: instanceId}) }
|
||||
uploadAfter={this.state.selectedItem}
|
||||
open={this.state.openUploadDialog}
|
||||
|
||||
@@ -369,7 +369,11 @@ const PresetSelector =
|
||||
acceptActionName={this.state.renameDialogActionName}
|
||||
onClose={() => this.handleRenameDialogClose()}
|
||||
onOk={(name: string) => this.handleRenameDialogOk(name)} />
|
||||
<UploadDialog onUploaded={(instanceId) => { this.model.loadPreset(instanceId); }}
|
||||
<UploadDialog
|
||||
title='Upload preset'
|
||||
extension='.piPreset'
|
||||
uploadPage='uploadPreset'
|
||||
onUploaded={(instanceId) => { this.model.loadPreset(instanceId); }}
|
||||
open={this.state.openUploadDialog}
|
||||
uploadAfter={-1}
|
||||
onClose={() => { this.setState({ openUploadDialog: false }) }} />
|
||||
|
||||
@@ -85,6 +85,8 @@ export default class RenameDialog extends ResizeResponsiveComponent<RenameDialog
|
||||
|
||||
const handleOk = () => {
|
||||
let text = nullCast(this.refText.current).value;
|
||||
text = text.trim();
|
||||
if (text.length === 0) return;
|
||||
onOk(text);
|
||||
}
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {
|
||||
|
||||
@@ -29,14 +29,18 @@ import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
|
||||
const PRESET_EXTENSION = ".piPreset";
|
||||
const BANK_EXTENSION = ".piBank";
|
||||
// const PRESET_EXTENSION = ".piPreset";
|
||||
// const BANK_EXTENSION = ".piBank";
|
||||
// const PLUGIN_PRESETS_EXTENSION = ".piPluginPresets";
|
||||
|
||||
export interface UploadDialogProps {
|
||||
open: boolean,
|
||||
onClose: () => void,
|
||||
uploadAfter: number,
|
||||
onUploaded: (instanceId: number) => void
|
||||
onUploaded: (instanceId: number) => void,
|
||||
title: string,
|
||||
extension: string,
|
||||
uploadPage: string
|
||||
|
||||
};
|
||||
|
||||
@@ -94,11 +98,11 @@ export default class UploadDialog extends ResizeResponsiveComponent<UploadDialog
|
||||
let uploadAfter = this.props.uploadAfter;
|
||||
for (let i = 0; i < fileList.length; ++i)
|
||||
{
|
||||
uploadAfter = await this.model.uploadPreset(fileList[i],uploadAfter);
|
||||
uploadAfter = await this.model.uploadPreset(this.props.uploadPage,fileList[i],uploadAfter);
|
||||
}
|
||||
this.props.onUploaded(uploadAfter);
|
||||
} catch(error) {
|
||||
this.model.showAlert(error);
|
||||
this.model.showAlert(error +"");
|
||||
};
|
||||
this.props.onClose();
|
||||
}
|
||||
@@ -132,7 +136,7 @@ export default class UploadDialog extends ResizeResponsiveComponent<UploadDialog
|
||||
for (let i = 0; i < fileList.files.length; ++i) {
|
||||
let file = fileList.files[i];
|
||||
let extension = this.getFileExtension(file.name);
|
||||
if (extension !== PRESET_EXTENSION && extension !== BANK_EXTENSION) return false;
|
||||
if (extension !== this.props.extension) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -157,7 +161,7 @@ export default class UploadDialog extends ResizeResponsiveComponent<UploadDialog
|
||||
fullScreen={this.state.fullScreen}
|
||||
style={{userSelect: "none"}}
|
||||
>
|
||||
<DialogTitle>Upload preset</DialogTitle>
|
||||
<DialogTitle>{this.props.title}</DialogTitle>
|
||||
<DialogContent>
|
||||
<div style={{
|
||||
width: "100%", height: 100, marginBottom: 0,
|
||||
@@ -188,7 +192,7 @@ export default class UploadDialog extends ResizeResponsiveComponent<UploadDialog
|
||||
<input
|
||||
type="file"
|
||||
hidden
|
||||
accept=".piPreset"
|
||||
accept={this.props.extension}
|
||||
multiple
|
||||
onChange={(e)=> this.handleButtonSelect(e)}
|
||||
/>
|
||||
|
||||
+529
-467
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -58,7 +58,8 @@ public:
|
||||
constexpr static const char* content_disposition = "Content-Disposition";
|
||||
constexpr static const char* access_control_allow_origin = "Access-Control-Allow-Origin";
|
||||
constexpr static const char* access_control_allow_methods= "Access-Control-Allow-Methods";
|
||||
constexpr static const char* access_control_allow_headers = "Acess-Control-Allow-Headers";
|
||||
constexpr static const char* access_control_allow_headers = "Access-Control-Allow-Headers";
|
||||
constexpr static const char* access_control_request_headers = "Access-Control-Request-Headers";
|
||||
constexpr static const char* origin = "Origin";
|
||||
constexpr static const char* date = "Date";
|
||||
};
|
||||
|
||||
@@ -101,6 +101,7 @@ add_custom_command(
|
||||
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
PluginPreset.cpp PluginPreset.hpp
|
||||
SysExec.cpp SysExec.hpp
|
||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||
|
||||
+62
-37
@@ -123,6 +123,9 @@ void Lv2Host::LilvUris::Initialize(LilvWorld*pWorld)
|
||||
time_beatsPerMinute = lilv_new_uri(pWorld, LV2_TIME__beatsPerMinute);
|
||||
time_speed = lilv_new_uri(pWorld, LV2_TIME__speed);
|
||||
|
||||
appliesTo = lilv_new_uri(pWorld,LV2_CORE__appliesTo);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -151,6 +154,8 @@ void Lv2Host::LilvUris::Free()
|
||||
time_beatsPerMinute.Free();
|
||||
time_speed.Free();
|
||||
|
||||
appliesTo.Free();
|
||||
isA.Free();
|
||||
}
|
||||
|
||||
static std::string nodeAsString(const LilvNode *node)
|
||||
@@ -535,8 +540,24 @@ static bool ports_sort_compare(std::shared_ptr<Lv2PortInfo> &p1, const std::shar
|
||||
return p1->index() < p2->index();
|
||||
}
|
||||
|
||||
bool Lv2PluginInfo::HasFactoryPresets(Lv2Host*lv2Host, const LilvPlugin*plugin)
|
||||
{
|
||||
NodesAutoFree nodes = lilv_plugin_get_related(plugin,lv2Host->lilvUris.pset_Preset);
|
||||
bool result = false;
|
||||
LILV_FOREACH(nodes, iNode, nodes)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Lv2PluginInfo::Lv2PluginInfo(Lv2Host *lv2Host, const LilvPlugin *pPlugin)
|
||||
{
|
||||
const LilvNode* pluginUri = lilv_plugin_get_uri(pPlugin);
|
||||
|
||||
this->has_factory_presets_ = HasFactoryPresets(lv2Host,pPlugin);
|
||||
|
||||
this->uri_ = nodeAsString(lilv_plugin_get_uri(pPlugin));
|
||||
|
||||
NodeAutoFree name = (lilv_plugin_get_name(pPlugin));
|
||||
@@ -606,7 +627,10 @@ Lv2PluginInfo::Lv2PluginInfo(Lv2Host *lv2Host, const LilvPlugin *pPlugin)
|
||||
}
|
||||
|
||||
std::sort(ports_.begin(), ports_.end(), ports_sort_compare);
|
||||
|
||||
|
||||
this->is_valid_ = isValid;
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::string> supportedFeatures = {
|
||||
@@ -947,7 +971,8 @@ void Lv2Host::fn_LilvSetPortValueFunc(const char* port_symbol,
|
||||
|
||||
|
||||
|
||||
std::vector<ControlValue> Lv2Host::LoadPluginPreset(PedalBoardItem*pedalBoardItem, const std::string&presetUri)
|
||||
std::vector<ControlValue> Lv2Host::LoadFactoryPluginPreset(
|
||||
PedalBoardItem*pedalBoardItem, const std::string&presetUri)
|
||||
{
|
||||
|
||||
std::vector<ControlValue> result;
|
||||
@@ -1005,10 +1030,26 @@ std::vector<ControlValue> Lv2Host::LoadPluginPreset(PedalBoardItem*pedalBoardIte
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Lv2PluginPreset> Lv2Host::GetPluginPresets(const std::string &pluginUri)
|
||||
{
|
||||
std::vector<Lv2PluginPreset> result;
|
||||
struct PresetCallbackState {
|
||||
Lv2Host *pHost;
|
||||
std::map<std::string,float> *values;
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
void Lv2Host::PortValueCallback(const char*symbol,void*user_data,const void* value,uint32_t size, uint32_t type)
|
||||
{
|
||||
PresetCallbackState *pState = static_cast<PresetCallbackState*>(user_data);
|
||||
Lv2Host*pHost = pState->pHost;
|
||||
|
||||
if (type == pHost->urids->atom_Float)
|
||||
{
|
||||
(*pState->values)[symbol] = *static_cast<const float*>(value);
|
||||
} else {
|
||||
pState->failed = true;
|
||||
}
|
||||
}
|
||||
PluginPresets Lv2Host::GetFactoryPluginPresets(const std::string &pluginUri)
|
||||
{
|
||||
const LilvPlugins*plugins = lilv_world_get_all_plugins(this->pWorld);
|
||||
|
||||
NodeAutoFree uriNode = lilv_new_uri(pWorld, pluginUri.c_str());
|
||||
@@ -1021,42 +1062,31 @@ std::vector<Lv2PluginPreset> Lv2Host::GetPluginPresets(const std::string &plugin
|
||||
throw PiPedalStateException("No such plugin.");
|
||||
}
|
||||
|
||||
|
||||
PluginPresets result;
|
||||
result.pluginUri_ = pluginUri;
|
||||
|
||||
LilvNodes* presets = lilv_plugin_get_related(plugin, lilvUris.pset_Preset);
|
||||
LILV_FOREACH(nodes, i, presets) {
|
||||
const LilvNode* preset = lilv_nodes_get(presets, i);
|
||||
lilv_world_load_resource(pWorld, preset);
|
||||
|
||||
LilvNodes* labels = lilv_world_find_nodes(
|
||||
pWorld, preset, lilvUris.rdfs_label, NULL);
|
||||
if (labels) {
|
||||
const LilvNode* label = lilv_nodes_get_first(labels);
|
||||
std::string presetName = nodeAsString(label);
|
||||
result.push_back(Lv2PluginPreset(nodeAsString(preset),presetName));
|
||||
lilv_nodes_free(labels);
|
||||
} else {
|
||||
std::stringstream s;
|
||||
s << "Preset <" << nodeAsString(lilv_nodes_get(presets,i)) << "> has no rdfs:label.";
|
||||
LilvState *state = lilv_state_new_from_world(pWorld,this->mapFeature.GetMap(),preset);
|
||||
if (state != nullptr)
|
||||
{
|
||||
std::string label = lilv_state_get_label(state);
|
||||
std::map<std::string,float> controlValues;
|
||||
PresetCallbackState cbData { this, &controlValues,false};
|
||||
lilv_state_emit_port_values(state,PortValueCallback,(void*)&cbData);
|
||||
lilv_state_free(state);
|
||||
|
||||
Lv2Log::warning(s.str());
|
||||
}
|
||||
if (!cbData.failed)
|
||||
{
|
||||
result.presets_.push_back(PluginPreset(result.nextInstanceId_++,std::move(label),std::move(controlValues)));
|
||||
}
|
||||
}
|
||||
}
|
||||
lilv_nodes_free(presets);
|
||||
|
||||
auto& collation = std::use_facet<std::collate<char> >(std::locale());
|
||||
|
||||
auto compare = [&collation] (const Lv2PluginPreset&left, const Lv2PluginPreset&right)
|
||||
{
|
||||
return collation.compare(
|
||||
left.name_.c_str(),
|
||||
left.name_.c_str()+left.name_.size(),
|
||||
right.name_.c_str(),
|
||||
right.name_.c_str()+right.name_.size()) < 0;
|
||||
};
|
||||
|
||||
std::sort(result.begin(),result.end(),compare);
|
||||
return result;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@@ -1162,7 +1192,7 @@ json_map::storage_type<Lv2PluginInfo> Lv2PluginInfo::jmap{{
|
||||
json_map::reference("ports", &Lv2PluginInfo::ports_),
|
||||
json_map::reference("port_groups", &Lv2PluginInfo::port_groups_),
|
||||
json_map::reference("is_valid", &Lv2PluginInfo::is_valid_),
|
||||
|
||||
json_map::reference("has_factory_presets", &Lv2PluginInfo::has_factory_presets_),
|
||||
}};
|
||||
|
||||
json_map::storage_type<Lv2PluginUiInfo> Lv2PluginUiInfo::jmap{{
|
||||
@@ -1217,8 +1247,3 @@ json_map::storage_type<Lv2PluginUiPortGroup> Lv2PluginUiPortGroup::jmap{{
|
||||
MAP_REF(Lv2PluginUiPortGroup, name),
|
||||
}};
|
||||
|
||||
JSON_MAP_BEGIN(Lv2PluginPreset)
|
||||
JSON_MAP_REFERENCE(Lv2PluginPreset,presetUri)
|
||||
JSON_MAP_REFERENCE(Lv2PluginPreset,name)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
+11
-21
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "lv2.h"
|
||||
#include "Units.hpp"
|
||||
|
||||
#include "PluginPreset.hpp"
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
@@ -60,23 +60,6 @@ class JackChannelSelection;
|
||||
|
||||
|
||||
|
||||
class Lv2PluginPreset {
|
||||
public:
|
||||
Lv2PluginPreset(const std::string &presetUri, const std::string&name)
|
||||
: presetUri_(presetUri),
|
||||
name_(name)
|
||||
{
|
||||
|
||||
}
|
||||
Lv2PluginPreset() { }
|
||||
|
||||
std::string presetUri_;
|
||||
std::string name_;
|
||||
|
||||
DECLARE_JSON_MAP(Lv2PluginPreset);
|
||||
};
|
||||
|
||||
|
||||
class Lv2PluginClass {
|
||||
public:
|
||||
friend class Lv2Host;
|
||||
@@ -321,6 +304,7 @@ public:
|
||||
Lv2PluginInfo(Lv2Host*lv2Host,const LilvPlugin*);
|
||||
Lv2PluginInfo() { }
|
||||
private:
|
||||
bool HasFactoryPresets(Lv2Host*lv2Host, const LilvPlugin*plugin);
|
||||
std::string uri_;
|
||||
std::string name_;
|
||||
std::string plugin_class_;
|
||||
@@ -328,6 +312,7 @@ private:
|
||||
std::vector<std::string> required_features_;
|
||||
std::vector<std::string> optional_features_;
|
||||
std::vector<std::string> extensions_;
|
||||
bool has_factory_presets_ = false;
|
||||
|
||||
std::string author_name_;
|
||||
std::string author_homepage_;
|
||||
@@ -353,6 +338,7 @@ public:
|
||||
LV2_PROPERTY_GETSET(ports)
|
||||
LV2_PROPERTY_GETSET(is_valid)
|
||||
LV2_PROPERTY_GETSET(port_groups)
|
||||
LV2_PROPERTY_GETSET(has_factory_presets)
|
||||
|
||||
const Lv2PortInfo& getPort(const std::string&symbol)
|
||||
{
|
||||
@@ -623,6 +609,9 @@ private:
|
||||
LilvNodePtr time_beatsPerMinute;
|
||||
LilvNodePtr time_speed;
|
||||
|
||||
LilvNodePtr appliesTo;
|
||||
LilvNodePtr isA;
|
||||
|
||||
|
||||
};
|
||||
LilvUris lilvUris;
|
||||
@@ -682,6 +671,7 @@ private:
|
||||
virtual LV2_URID_Map* GetLv2UridMap() {
|
||||
return this->mapFeature.GetMap();
|
||||
}
|
||||
static void PortValueCallback(const char*symbol,void*user_data,const void* value,uint32_t size, uint32_t type);
|
||||
|
||||
virtual Lv2Effect*CreateEffect(const PedalBoardItem &pedalBoardItem);
|
||||
void LoadPluginClassesFromLilv();
|
||||
@@ -733,9 +723,9 @@ public:
|
||||
return this->mapFeature.UridToString(urid);
|
||||
}
|
||||
|
||||
std::vector<Lv2PluginPreset> GetPluginPresets(const std::string &pluginUri);
|
||||
std::vector<ControlValue> LoadPluginPreset(PedalBoardItem*pedalBoardItem, const std::string&presetUri);
|
||||
|
||||
PluginPresets GetFactoryPluginPresets(const std::string &pluginUri);
|
||||
std::vector<ControlValue> LoadFactoryPluginPreset(PedalBoardItem*pedalBoardItem,
|
||||
const std::string&presetUri);
|
||||
|
||||
|
||||
};
|
||||
|
||||
+212
-124
@@ -18,7 +18,7 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#include <sched.h>
|
||||
#include "PiPedalModel.hpp"
|
||||
#include "JackHost.hpp"
|
||||
#include "Lv2Log.hpp"
|
||||
@@ -92,6 +92,10 @@ PiPedalModel::~PiPedalModel()
|
||||
|
||||
void PiPedalModel::LoadLv2PluginInfo(const PiPedalConfiguration&configuration)
|
||||
{
|
||||
|
||||
storage.SetDataRoot(configuration.GetLocalStoragePath().c_str());
|
||||
storage.Initialize();
|
||||
|
||||
// Not all Lv2 directories have the lv2 base declarations. Load a full set of plugin classes generated on a default /usr/local/lib/lv2 directory.
|
||||
std::filesystem::path pluginClassesPath = configuration.GetDocRoot() / "plugin_classes.json";
|
||||
try
|
||||
@@ -109,6 +113,20 @@ void PiPedalModel::LoadLv2PluginInfo(const PiPedalConfiguration&configuration)
|
||||
|
||||
lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||
|
||||
// Copy all presets out of Lilv data to json files
|
||||
// so that we can close lilv while we're actually
|
||||
// running.
|
||||
for (const auto&plugin: lv2Host.GetPlugins())
|
||||
{
|
||||
if (plugin->has_factory_presets())
|
||||
{
|
||||
if (!storage.HasPluginPresets(plugin->uri()))
|
||||
{
|
||||
PluginPresets pluginPresets = lv2Host.GetFactoryPluginPresets(plugin->uri());
|
||||
storage.SavePluginPresets(plugin->uri(),pluginPresets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
@@ -117,8 +135,6 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
this->jackServerSettings.ReadJackConfiguration();
|
||||
|
||||
|
||||
storage.SetDataRoot(configuration.GetLocalStoragePath().c_str());
|
||||
storage.Initialize();
|
||||
|
||||
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||
|
||||
@@ -131,7 +147,7 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
this->pedalBoard = currentPreset.preset_;
|
||||
this->hasPresetChanged = currentPreset.modified_;
|
||||
}
|
||||
updateDefaults(&this->pedalBoard);
|
||||
UpdateDefaults(&this->pedalBoard);
|
||||
|
||||
std::unique_ptr<JackHost> p{JackHost::CreateInstance(lv2Host.asIHost())};
|
||||
this->jackHost = std::move(p);
|
||||
@@ -150,6 +166,11 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
#endif
|
||||
}
|
||||
|
||||
struct sched_param scheduler_params;
|
||||
scheduler_params.sched_priority = 10;
|
||||
memset(&scheduler_params,0,sizeof(sched_param));
|
||||
sched_setscheduler(0,SCHED_RR,&scheduler_params);
|
||||
|
||||
this->jackConfiguration = jackHost->GetServerConfiguration();
|
||||
if (this->jackConfiguration.isValid())
|
||||
{
|
||||
@@ -204,8 +225,8 @@ void PiPedalModel::RemoveNotificationSubsription(IPiPedalModelSubscriber *pSubsc
|
||||
}
|
||||
int64_t clientId = pSubscriber->GetClientId();
|
||||
|
||||
this->deleteMidiListeners(clientId);
|
||||
this->deleteAtomOutputListeners(clientId);
|
||||
this->DeleteMidiListeners(clientId);
|
||||
this->DeleteAtomOutputListeners(clientId);
|
||||
|
||||
for (int i = 0; i < this->outstandingParameterRequests.size(); ++i)
|
||||
{
|
||||
@@ -218,17 +239,17 @@ void PiPedalModel::RemoveNotificationSubsription(IPiPedalModelSubscriber *pSubsc
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::previewControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value)
|
||||
void PiPedalModel::PreviewControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value)
|
||||
{
|
||||
|
||||
jackHost->SetControlValue(pedalItemId, symbol, value);
|
||||
}
|
||||
|
||||
void PiPedalModel::setControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value)
|
||||
void PiPedalModel::SetControl(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
previewControl(clientId, pedalItemId, symbol, value);
|
||||
PreviewControl(clientId, pedalItemId, symbol, value);
|
||||
this->pedalBoard.SetControlValue(pedalItemId, symbol, value);
|
||||
{
|
||||
|
||||
@@ -245,12 +266,12 @@ void PiPedalModel::setControl(int64_t clientId, int64_t pedalItemId, const std::
|
||||
}
|
||||
delete[] t;
|
||||
|
||||
this->setPresetChanged(clientId, true);
|
||||
this->SetPresetChanged(clientId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::fireJackConfigurationChanged(const JackConfiguration &jackConfiguration)
|
||||
void PiPedalModel::FireJackConfigurationChanged(const JackConfiguration &jackConfiguration)
|
||||
{
|
||||
// noify subscribers.
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
@@ -266,7 +287,7 @@ void PiPedalModel::fireJackConfigurationChanged(const JackConfiguration &jackCon
|
||||
delete[] t;
|
||||
}
|
||||
|
||||
void PiPedalModel::fireBanksChanged(int64_t clientId)
|
||||
void PiPedalModel::FireBanksChanged(int64_t clientId)
|
||||
{
|
||||
// noify subscribers.
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
@@ -282,7 +303,7 @@ void PiPedalModel::fireBanksChanged(int64_t clientId)
|
||||
delete[] t;
|
||||
}
|
||||
|
||||
void PiPedalModel::firePedalBoardChanged(int64_t clientId)
|
||||
void PiPedalModel::FirePedalBoardChanged(int64_t clientId)
|
||||
{
|
||||
// noify subscribers.
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
@@ -303,25 +324,25 @@ void PiPedalModel::firePedalBoardChanged(int64_t clientId)
|
||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||
this->lv2PedalBoard = lv2PedalBoard;
|
||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
||||
updateRealtimeVuSubscriptions();
|
||||
updateRealtimeMonitorPortSubscriptions();
|
||||
UpdateRealtimeVuSubscriptions();
|
||||
UpdateRealtimeMonitorPortSubscriptions();
|
||||
}
|
||||
}
|
||||
void PiPedalModel::setPedalBoard(int64_t clientId, PedalBoard &pedalBoard)
|
||||
void PiPedalModel::SetPedalBoard(int64_t clientId, PedalBoard &pedalBoard)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
this->pedalBoard = pedalBoard;
|
||||
updateDefaults(&this->pedalBoard);
|
||||
UpdateDefaults(&this->pedalBoard);
|
||||
|
||||
this->firePedalBoardChanged(clientId);
|
||||
this->setPresetChanged(clientId, true);
|
||||
this->FirePedalBoardChanged(clientId);
|
||||
this->SetPresetChanged(clientId, true);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::setPedalBoardItemEnable(int64_t clientId, int64_t pedalItemId, bool enabled)
|
||||
void PiPedalModel::SetPedalBoardItemEnable(int64_t clientId, int64_t pedalItemId, bool enabled)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
{
|
||||
this->pedalBoard.SetItemEnabled(pedalItemId, enabled);
|
||||
|
||||
@@ -337,14 +358,14 @@ void PiPedalModel::setPedalBoardItemEnable(int64_t clientId, int64_t pedalItemId
|
||||
t[i]->OnItemEnabledChanged(clientId, pedalItemId, enabled);
|
||||
}
|
||||
delete[] t;
|
||||
this->setPresetChanged(clientId, true);
|
||||
this->SetPresetChanged(clientId, true);
|
||||
|
||||
// Notify audo thread.
|
||||
this->jackHost->SetBypass(pedalItemId, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::getPresets(PresetIndex *pResult)
|
||||
void PiPedalModel::GetPresets(PresetIndex *pResult)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
@@ -352,29 +373,29 @@ void PiPedalModel::getPresets(PresetIndex *pResult)
|
||||
pResult->presetChanged(this->hasPresetChanged);
|
||||
}
|
||||
|
||||
PedalBoard PiPedalModel::getPreset(int64_t instanceId)
|
||||
PedalBoard PiPedalModel::GetPreset(int64_t instanceId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
return this->storage.GetPreset(instanceId);
|
||||
}
|
||||
void PiPedalModel::getBank(int64_t instanceId, BankFile *pResult)
|
||||
void PiPedalModel::GetBank(int64_t instanceId, BankFile *pResult)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
this->storage.GetBankFile(instanceId, pResult);
|
||||
}
|
||||
|
||||
void PiPedalModel::setPresetChanged(int64_t clientId, bool value)
|
||||
void PiPedalModel::SetPresetChanged(int64_t clientId, bool value)
|
||||
{
|
||||
if (value != this->hasPresetChanged)
|
||||
{
|
||||
hasPresetChanged = value;
|
||||
firePresetsChanged(clientId);
|
||||
FirePresetsChanged(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::firePresetsChanged(int64_t clientId)
|
||||
void PiPedalModel::FirePresetsChanged(int64_t clientId)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
{
|
||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
@@ -385,7 +406,7 @@ void PiPedalModel::firePresetsChanged(int64_t clientId)
|
||||
size_t n = this->subscribers.size();
|
||||
|
||||
PresetIndex presets;
|
||||
getPresets(&presets);
|
||||
GetPresets(&presets);
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
@@ -394,66 +415,125 @@ void PiPedalModel::firePresetsChanged(int64_t clientId)
|
||||
delete[] t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PiPedalModel::saveCurrentPreset(int64_t clientId)
|
||||
void PiPedalModel::FirePluginPresetsChanged(const std::string & pluginUri)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
{
|
||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t[i] = this->subscribers[i];
|
||||
}
|
||||
size_t n = this->subscribers.size();
|
||||
|
||||
storage.saveCurrentPreset(this->pedalBoard);
|
||||
this->setPresetChanged(clientId, false);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->OnPluginPresetsChanged(pluginUri);
|
||||
}
|
||||
delete[] t;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::saveCurrentPresetAs(int64_t clientId, const std::string &name, int64_t saveAfterInstanceId)
|
||||
|
||||
void PiPedalModel::SaveCurrentPreset(int64_t clientId)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
storage.SaveCurrentPreset(this->pedalBoard);
|
||||
this->SetPresetChanged(clientId, false);
|
||||
}
|
||||
|
||||
uint64_t PiPedalModel::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId)
|
||||
{
|
||||
uint64_t result = storage.CopyPluginPreset(pluginUri,presetId);
|
||||
FirePluginPresetsChanged(pluginUri);
|
||||
return result;
|
||||
}
|
||||
|
||||
void PiPedalModel::UpdatePluginPresets(const PluginUiPresets&pluginPresets)
|
||||
{
|
||||
storage.UpdatePluginPresets(pluginPresets);
|
||||
FirePluginPresetsChanged(pluginPresets.pluginUri_);
|
||||
}
|
||||
int64_t PiPedalModel::SavePluginPresetAs(int64_t instanceId, const std::string&name)
|
||||
{
|
||||
auto *item = this->pedalBoard.GetItem(instanceId);
|
||||
if (!item)
|
||||
{
|
||||
throw PiPedalException("Plugin not found.");
|
||||
}
|
||||
std::map<std::string,float> values;
|
||||
for (const auto & controlValue: item->controlValues())
|
||||
{
|
||||
values[controlValue.key()] = controlValue.value();
|
||||
}
|
||||
uint64_t presetId = storage.SavePluginPreset(item->uri(),name,values);
|
||||
FirePluginPresetsChanged(item->uri());
|
||||
return presetId;
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::SaveCurrentPresetAs(int64_t clientId, const std::string &name, int64_t saveAfterInstanceId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
int64_t result = storage.saveCurrentPresetAs(this->pedalBoard, name, saveAfterInstanceId);
|
||||
this->hasPresetChanged = false;
|
||||
firePresetsChanged(clientId);
|
||||
FirePresetsChanged(clientId);
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::uploadPreset(const BankFile &bankFile, int64_t uploadAfter)
|
||||
void PiPedalModel::UploadPluginPresets(const PluginPresets&pluginPresets)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
if (pluginPresets.pluginUri_.length() == 0)
|
||||
{
|
||||
throw PiPedalException("Invalid plugin presets.");
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
storage.SavePluginPresets(pluginPresets.pluginUri_,pluginPresets);
|
||||
FirePluginPresetsChanged(pluginPresets.pluginUri_);
|
||||
|
||||
}
|
||||
int64_t PiPedalModel::UploadPreset(const BankFile &bankFile, int64_t uploadAfter)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
int64_t newPreset = this->storage.UploadPreset(bankFile, uploadAfter);
|
||||
firePresetsChanged(-1);
|
||||
FirePresetsChanged(-1);
|
||||
return newPreset;
|
||||
}
|
||||
int64_t PiPedalModel::uploadBank(BankFile &bankFile, int64_t uploadAfter)
|
||||
int64_t PiPedalModel::UploadBank(BankFile &bankFile, int64_t uploadAfter)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
int64_t newPreset = this->storage.UploadBank(bankFile, uploadAfter);
|
||||
fireBanksChanged(-1);
|
||||
FireBanksChanged(-1);
|
||||
return newPreset;
|
||||
}
|
||||
|
||||
void PiPedalModel::loadPreset(int64_t clientId, int64_t instanceId)
|
||||
void PiPedalModel::LoadPreset(int64_t clientId, int64_t instanceId)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
if (storage.LoadPreset(instanceId))
|
||||
{
|
||||
this->pedalBoard = storage.GetCurrentPreset();
|
||||
updateDefaults(&this->pedalBoard);
|
||||
UpdateDefaults(&this->pedalBoard);
|
||||
|
||||
this->hasPresetChanged = false; // no fire.
|
||||
this->firePedalBoardChanged(clientId);
|
||||
this->firePresetsChanged(clientId); // fire now.
|
||||
this->FirePedalBoardChanged(clientId);
|
||||
this->FirePresetsChanged(clientId); // fire now.
|
||||
}
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::copyPreset(int64_t clientId, int64_t from, int64_t to)
|
||||
int64_t PiPedalModel::CopyPreset(int64_t clientId, int64_t from, int64_t to)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
int64_t result = storage.CopyPreset(from, to);
|
||||
if (result != -1)
|
||||
{
|
||||
this->firePresetsChanged(clientId); // fire now.
|
||||
this->FirePresetsChanged(clientId); // fire now.
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -461,51 +541,51 @@ int64_t PiPedalModel::copyPreset(int64_t clientId, int64_t from, int64_t to)
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool PiPedalModel::updatePresets(int64_t clientId, const PresetIndex &presets)
|
||||
bool PiPedalModel::UpdatePresets(int64_t clientId, const PresetIndex &presets)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
storage.SetPresetIndex(presets);
|
||||
firePresetsChanged(clientId);
|
||||
FirePresetsChanged(clientId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PiPedalModel::moveBank(int64_t clientId, int from, int to)
|
||||
void PiPedalModel::MoveBank(int64_t clientId, int from, int to)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
storage.MoveBank(from, to);
|
||||
fireBanksChanged(clientId);
|
||||
FireBanksChanged(clientId);
|
||||
}
|
||||
int64_t PiPedalModel::deleteBank(int64_t clientId, int64_t instanceId)
|
||||
int64_t PiPedalModel::DeleteBank(int64_t clientId, int64_t instanceId)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
int64_t selectedBank = this->storage.GetBanks().selectedBank();
|
||||
int64_t newSelection = storage.DeleteBank(instanceId);
|
||||
|
||||
int64_t newSelectedBank = this->storage.GetBanks().selectedBank();
|
||||
|
||||
this->fireBanksChanged(clientId); // fire now.
|
||||
this->FireBanksChanged(clientId); // fire now.
|
||||
|
||||
if (newSelectedBank != selectedBank)
|
||||
{
|
||||
this->openBank(clientId, newSelectedBank);
|
||||
this->OpenBank(clientId, newSelectedBank);
|
||||
}
|
||||
return newSelection;
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::deletePreset(int64_t clientId, int64_t instanceId)
|
||||
int64_t PiPedalModel::DeletePreset(int64_t clientId, int64_t instanceId)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
|
||||
int64_t newSelection = storage.DeletePreset(instanceId);
|
||||
this->firePresetsChanged(clientId); // fire now.
|
||||
this->FirePresetsChanged(clientId); // fire now.
|
||||
return newSelection;
|
||||
}
|
||||
bool PiPedalModel::renamePreset(int64_t clientId, int64_t instanceId, const std::string &name)
|
||||
bool PiPedalModel::RenamePreset(int64_t clientId, int64_t instanceId, const std::string &name)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
if (storage.RenamePreset(instanceId, name))
|
||||
{
|
||||
this->firePresetsChanged(clientId);
|
||||
this->FirePresetsChanged(clientId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -514,7 +594,7 @@ bool PiPedalModel::renamePreset(int64_t clientId, int64_t instanceId, const std:
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::setWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
@@ -539,23 +619,23 @@ void PiPedalModel::setWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
|
||||
delete[] t;
|
||||
}
|
||||
}
|
||||
WifiConfigSettings PiPedalModel::getWifiConfigSettings()
|
||||
WifiConfigSettings PiPedalModel::GetWifiConfigSettings()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
return this->storage.GetWifiConfigSettings();
|
||||
}
|
||||
|
||||
JackConfiguration PiPedalModel::getJackConfiguration()
|
||||
JackConfiguration PiPedalModel::GetJackConfiguration()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex); // copy atomically.
|
||||
return this->jackConfiguration;
|
||||
}
|
||||
|
||||
void PiPedalModel::setJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
||||
void PiPedalModel::SetJackChannelSelection(int64_t clientId, const JackChannelSelection &channelSelection)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex); // copy atomically.
|
||||
this->storage.SetJackChannelSelection(channelSelection);
|
||||
this->fireChannelSelectionChanged(clientId);
|
||||
this->FireChannelSelectionChanged(clientId);
|
||||
|
||||
this->lv2Host.OnConfigurationChanged(jackConfiguration, channelSelection);
|
||||
if (this->jackHost->IsOpen())
|
||||
@@ -568,13 +648,13 @@ void PiPedalModel::setJackChannelSelection(int64_t clientId, const JackChannelSe
|
||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||
this->lv2PedalBoard = lv2PedalBoard;
|
||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
||||
this->updateRealtimeVuSubscriptions();
|
||||
this->UpdateRealtimeVuSubscriptions();
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::fireChannelSelectionChanged(int64_t clientId)
|
||||
void PiPedalModel::FireChannelSelectionChanged(int64_t clientId)
|
||||
{
|
||||
std::lock_guard(this->mutex);
|
||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||
{
|
||||
// take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us)
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
@@ -594,7 +674,7 @@ void PiPedalModel::fireChannelSelectionChanged(int64_t clientId)
|
||||
}
|
||||
}
|
||||
|
||||
JackChannelSelection PiPedalModel::getJackChannelSelection()
|
||||
JackChannelSelection PiPedalModel::GetJackChannelSelection()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
JackChannelSelection t = this->storage.GetJackChannelSelection(this->jackConfiguration);
|
||||
@@ -605,17 +685,17 @@ JackChannelSelection PiPedalModel::getJackChannelSelection()
|
||||
return t;
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::addVuSubscription(int64_t instanceId)
|
||||
int64_t PiPedalModel::AddVuSubscription(int64_t instanceId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
int64_t subscriptionId = ++nextSubscriptionId;
|
||||
activeVuSubscriptions.push_back(VuSubscription{subscriptionId, instanceId});
|
||||
|
||||
updateRealtimeVuSubscriptions();
|
||||
UpdateRealtimeVuSubscriptions();
|
||||
|
||||
return subscriptionId;
|
||||
}
|
||||
void PiPedalModel::removeVuSubscription(int64_t subscriptionHandle)
|
||||
void PiPedalModel::RemoveVuSubscription(int64_t subscriptionHandle)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
for (auto i = activeVuSubscriptions.begin(); i != activeVuSubscriptions.end(); ++i)
|
||||
@@ -626,7 +706,7 @@ void PiPedalModel::removeVuSubscription(int64_t subscriptionHandle)
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateRealtimeVuSubscriptions();
|
||||
UpdateRealtimeVuSubscriptions();
|
||||
}
|
||||
|
||||
void PiPedalModel::OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, float value)
|
||||
@@ -664,7 +744,7 @@ void PiPedalModel::OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, f
|
||||
}
|
||||
delete[] t;
|
||||
|
||||
this->setPresetChanged(-1, true);
|
||||
this->SetPresetChanged(-1, true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -692,7 +772,7 @@ void PiPedalModel::OnNotifyMidiValueChanged(int64_t instanceId, int portIndex, f
|
||||
}
|
||||
delete[] t;
|
||||
|
||||
this->setPresetChanged(-1, true);
|
||||
this->SetPresetChanged(-1, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -721,7 +801,7 @@ void PiPedalModel::OnNotifyVusSubscription(const std::vector<VuUpdate> &updates)
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::updateRealtimeVuSubscriptions()
|
||||
void PiPedalModel::UpdateRealtimeVuSubscriptions()
|
||||
{
|
||||
std::set<int64_t> addedInstances;
|
||||
|
||||
@@ -737,23 +817,23 @@ void PiPedalModel::updateRealtimeVuSubscriptions()
|
||||
jackHost->SetVuSubscriptions(instanceids);
|
||||
}
|
||||
|
||||
void PiPedalModel::updateRealtimeMonitorPortSubscriptions()
|
||||
void PiPedalModel::UpdateRealtimeMonitorPortSubscriptions()
|
||||
{
|
||||
jackHost->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)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
int64_t subscriptionId = ++nextSubscriptionId;
|
||||
activeMonitorPortSubscriptions.push_back(
|
||||
MonitorPortSubscription{subscriptionId, instanceId, key, updateInterval, onUpdate});
|
||||
|
||||
updateRealtimeMonitorPortSubscriptions();
|
||||
UpdateRealtimeMonitorPortSubscriptions();
|
||||
|
||||
return subscriptionId;
|
||||
}
|
||||
void PiPedalModel::unmonitorPort(int64_t subscriptionHandle)
|
||||
void PiPedalModel::UnmonitorPort(int64_t subscriptionHandle)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
@@ -762,7 +842,7 @@ void PiPedalModel::unmonitorPort(int64_t subscriptionHandle)
|
||||
if ((*i).subscriptionHandle == subscriptionHandle)
|
||||
{
|
||||
activeMonitorPortSubscriptions.erase(i);
|
||||
updateRealtimeMonitorPortSubscriptions();
|
||||
UpdateRealtimeMonitorPortSubscriptions();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -785,7 +865,7 @@ void PiPedalModel::OnNotifyMonitorPort(const MonitorPortUpdate &update)
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::getLv2Parameter(
|
||||
void PiPedalModel::GetLv2Parameter(
|
||||
int64_t clientId,
|
||||
int64_t instanceId,
|
||||
const std::string uri,
|
||||
@@ -837,40 +917,40 @@ void PiPedalModel::getLv2Parameter(
|
||||
this->jackHost->getRealtimeParameter(request);
|
||||
}
|
||||
|
||||
BankIndex PiPedalModel::getBankIndex() const
|
||||
BankIndex PiPedalModel::GetBankIndex() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(const_cast<std::recursive_mutex&>(mutex));
|
||||
return storage.GetBanks();
|
||||
}
|
||||
|
||||
void PiPedalModel::renameBank(int64_t clientId, int64_t bankId, const std::string &newName)
|
||||
void PiPedalModel::RenameBank(int64_t clientId, int64_t bankId, const std::string &newName)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
storage.RenameBank(bankId, newName);
|
||||
fireBanksChanged(clientId);
|
||||
FireBanksChanged(clientId);
|
||||
}
|
||||
|
||||
int64_t PiPedalModel::saveBankAs(int64_t clientId, int64_t bankId, const std::string &newName)
|
||||
int64_t PiPedalModel::SaveBankAs(int64_t clientId, int64_t bankId, const std::string &newName)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
int64_t newId = storage.SaveBankAs(bankId, newName);
|
||||
fireBanksChanged(clientId);
|
||||
FireBanksChanged(clientId);
|
||||
return newId;
|
||||
}
|
||||
|
||||
void PiPedalModel::openBank(int64_t clientId, int64_t bankId)
|
||||
void PiPedalModel::OpenBank(int64_t clientId, int64_t bankId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
storage.LoadBank(bankId);
|
||||
fireBanksChanged(clientId);
|
||||
FireBanksChanged(clientId);
|
||||
|
||||
firePresetsChanged(clientId);
|
||||
FirePresetsChanged(clientId);
|
||||
|
||||
this->pedalBoard = storage.GetCurrentPreset();
|
||||
updateDefaults(&this->pedalBoard);
|
||||
UpdateDefaults(&this->pedalBoard);
|
||||
this->hasPresetChanged = false;
|
||||
this->firePedalBoardChanged(clientId);
|
||||
this->FirePedalBoardChanged(clientId);
|
||||
}
|
||||
|
||||
JackServerSettings PiPedalModel::GetJackServerSettings()
|
||||
@@ -914,7 +994,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
||||
storage.SaveCurrentPreset(currentPreset);
|
||||
|
||||
this->jackConfiguration.SetIsRestarting(true);
|
||||
fireJackConfigurationChanged(this->jackConfiguration);
|
||||
FireJackConfigurationChanged(this->jackConfiguration);
|
||||
this->jackHost->UpdateServerConfiguration(
|
||||
jackServerSettings,
|
||||
[this](bool success, const std::string &errorMessage)
|
||||
@@ -931,7 +1011,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
||||
{
|
||||
this->jackConfiguration.SetIsRestarting(false);
|
||||
this->jackConfiguration.SetErrorStatus(errorMessage);
|
||||
fireJackConfigurationChanged(this->jackConfiguration);
|
||||
FireJackConfigurationChanged(this->jackConfiguration);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -939,22 +1019,22 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
||||
// so just sit tight and wait for the restart.
|
||||
#ifdef JUNK
|
||||
this->jackConfiguration.SetErrorStatus("");
|
||||
fireJackConfigurationChanged(this->jackConfiguration);
|
||||
FireJackConfigurationChanged(this->jackConfiguration);
|
||||
|
||||
// restart the pedalboard on a new instance.
|
||||
std::shared_ptr<Lv2PedalBoard> lv2PedalBoard{this->lv2Host.CreateLv2PedalBoard(this->pedalBoard)};
|
||||
this->lv2PedalBoard = lv2PedalBoard;
|
||||
|
||||
jackHost->SetPedalBoard(lv2PedalBoard);
|
||||
updateRealtimeVuSubscriptions();
|
||||
updateRealtimeMonitorPortSubscriptions();
|
||||
UpdateRealtimeVuSubscriptions();
|
||||
UpdateRealtimeMonitorPortSubscriptions();
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::updateDefaults(PedalBoardItem *pedalBoardItem)
|
||||
void PiPedalModel::UpdateDefaults(PedalBoardItem *pedalBoardItem)
|
||||
{
|
||||
std::shared_ptr<Lv2PluginInfo> t = lv2Host.GetPluginInfo(pedalBoardItem->uri());
|
||||
const Lv2PluginInfo *pPlugin = t.get();
|
||||
@@ -984,42 +1064,50 @@ void PiPedalModel::updateDefaults(PedalBoardItem *pedalBoardItem)
|
||||
}
|
||||
for (size_t i = 0; i < pedalBoardItem->topChain().size(); ++i)
|
||||
{
|
||||
updateDefaults(&(pedalBoardItem->topChain()[i]));
|
||||
UpdateDefaults(&(pedalBoardItem->topChain()[i]));
|
||||
}
|
||||
for (size_t i = 0; i < pedalBoardItem->bottomChain().size(); ++i)
|
||||
{
|
||||
updateDefaults(&(pedalBoardItem->bottomChain()[i]));
|
||||
UpdateDefaults(&(pedalBoardItem->bottomChain()[i]));
|
||||
}
|
||||
}
|
||||
void PiPedalModel::updateDefaults(PedalBoard *pedalBoard)
|
||||
void PiPedalModel::UpdateDefaults(PedalBoard *pedalBoard)
|
||||
{
|
||||
for (size_t i = 0; i < pedalBoard->items().size(); ++i)
|
||||
{
|
||||
updateDefaults(&(pedalBoard->items()[i]));
|
||||
UpdateDefaults(&(pedalBoard->items()[i]));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Lv2PluginPreset> PiPedalModel::GetPluginPresets(std::string pluginUri)
|
||||
PluginPresets PiPedalModel::GetPluginPresets(const std::string& pluginUri)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
return lv2Host.GetPluginPresets(pluginUri);
|
||||
return storage.GetPluginPresets(pluginUri);
|
||||
|
||||
}
|
||||
|
||||
void PiPedalModel::LoadPluginPreset(int64_t instanceId, const std::string &presetUri)
|
||||
PluginUiPresets PiPedalModel::GetPluginUiPresets(const std::string& pluginUri)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
PedalBoardItem *pedalBoardItem = this->pedalBoard.GetItem(instanceId);
|
||||
return storage.GetPluginUiPresets(pluginUri);
|
||||
}
|
||||
|
||||
void PiPedalModel::LoadPluginPreset(int64_t pluginInstanceId, uint64_t presetInstanceId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
PedalBoardItem *pedalBoardItem = this->pedalBoard.GetItem(pluginInstanceId);
|
||||
if (pedalBoardItem != nullptr)
|
||||
{
|
||||
std::vector<ControlValue> controlValues = lv2Host.LoadPluginPreset(pedalBoardItem, presetUri);
|
||||
jackHost->SetPluginPreset(instanceId, controlValues);
|
||||
std::vector<ControlValue> controlValues = storage.GetPluginPresetValues(pedalBoardItem->uri(), presetInstanceId);
|
||||
jackHost->SetPluginPreset(pluginInstanceId, controlValues);
|
||||
|
||||
for (size_t i = 0; i < controlValues.size(); ++i)
|
||||
{
|
||||
const ControlValue &value = controlValues[i];
|
||||
this->pedalBoard.SetControlValue(instanceId, value.key(), value.value());
|
||||
this->pedalBoard.SetControlValue(pluginInstanceId, value.key(), value.value());
|
||||
}
|
||||
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
@@ -1030,13 +1118,13 @@ void PiPedalModel::LoadPluginPreset(int64_t instanceId, const std::string &prese
|
||||
size_t n = this->subscribers.size();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->OnLoadPluginPreset(instanceId, controlValues);
|
||||
t[i]->OnLoadPluginPreset(pluginInstanceId, controlValues);
|
||||
}
|
||||
delete[] t;
|
||||
}
|
||||
}
|
||||
|
||||
void PiPedalModel::deleteAtomOutputListeners(int64_t clientId)
|
||||
void PiPedalModel::DeleteAtomOutputListeners(int64_t clientId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
for (size_t i = 0; i < atomOutputListeners.size(); ++i)
|
||||
@@ -1050,7 +1138,7 @@ void PiPedalModel::deleteAtomOutputListeners(int64_t clientId)
|
||||
jackHost->SetListenForAtomOutput(atomOutputListeners.size() != 0);
|
||||
}
|
||||
|
||||
void PiPedalModel::deleteMidiListeners(int64_t clientId)
|
||||
void PiPedalModel::DeleteMidiListeners(int64_t clientId)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
for (size_t i = 0; i < midiEventListeners.size(); ++i)
|
||||
@@ -1111,7 +1199,7 @@ void PiPedalModel::OnNotifyMidiListen(bool isNote, uint8_t noteOrControl)
|
||||
jackHost->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)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
MidiListener listener{clientId, clientHandle, listenForControlsOnly};
|
||||
@@ -1119,7 +1207,7 @@ void PiPedalModel::listenForMidiEvent(int64_t clientId, int64_t clientHandle, bo
|
||||
jackHost->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)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
AtomOutputListener listener{clientId, clientHandle, instanceId};
|
||||
@@ -1127,7 +1215,7 @@ void PiPedalModel::listenForAtomOutputs(int64_t clientId, int64_t clientHandle,
|
||||
jackHost->SetListenForAtomOutput(true);
|
||||
}
|
||||
|
||||
void PiPedalModel::cancelListenForMidiEvent(int64_t clientId, int64_t clientHandle)
|
||||
void PiPedalModel::CancelListenForMidiEvent(int64_t clientId, int64_t clientHandle)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
for (size_t i = 0; i < midiEventListeners.size(); ++i)
|
||||
@@ -1144,7 +1232,7 @@ void PiPedalModel::cancelListenForMidiEvent(int64_t clientId, int64_t clientHand
|
||||
jackHost->SetListenForMidiEvent(false);
|
||||
}
|
||||
}
|
||||
void PiPedalModel::cancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle)
|
||||
void PiPedalModel::CancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
for (size_t i = 0; i < atomOutputListeners.size(); ++i)
|
||||
|
||||
+64
-55
@@ -46,6 +46,7 @@ public:
|
||||
virtual void OnControlChanged(int64_t clientId, int64_t pedalItemId, const std::string &symbol, float value) = 0;
|
||||
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard) = 0;
|
||||
virtual void OnPresetsChanged(int64_t clientId, const PresetIndex&presets) = 0;
|
||||
virtual void OnPluginPresetsChanged(const std::string&pluginUri) = 0;
|
||||
virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection&channelSelection) = 0;
|
||||
virtual void OnVuMeterUpdate(const std::vector<VuUpdate>& updates) = 0;
|
||||
virtual void OnBankIndexChanged(const BankIndex& bankIndex) = 0;
|
||||
@@ -77,8 +78,8 @@ private:
|
||||
int64_t clientHandle;
|
||||
uint64_t instanceId;
|
||||
};
|
||||
void deleteMidiListeners(int64_t clientId);
|
||||
void deleteAtomOutputListeners(int64_t clientId);
|
||||
void DeleteMidiListeners(int64_t clientId);
|
||||
void DeleteAtomOutputListeners(int64_t clientId);
|
||||
|
||||
std::vector<MidiListener> midiEventListeners;
|
||||
std::vector<AtomOutputListener> atomOutputListeners;
|
||||
@@ -96,15 +97,16 @@ private:
|
||||
|
||||
|
||||
std::vector<IPiPedalModelSubscriber*> subscribers;
|
||||
void setPresetChanged(int64_t clientId,bool value);
|
||||
void firePresetsChanged(int64_t clientId);
|
||||
void firePedalBoardChanged(int64_t clientId);
|
||||
void fireChannelSelectionChanged(int64_t clientId);
|
||||
void fireBanksChanged(int64_t clientId);
|
||||
void fireJackConfigurationChanged(const JackConfiguration&jackConfiguration);
|
||||
void SetPresetChanged(int64_t clientId,bool value);
|
||||
void FirePresetsChanged(int64_t clientId);
|
||||
void FirePluginPresetsChanged(const std::string &pluginUri);
|
||||
void FirePedalBoardChanged(int64_t clientId);
|
||||
void FireChannelSelectionChanged(int64_t clientId);
|
||||
void FireBanksChanged(int64_t clientId);
|
||||
void FireJackConfigurationChanged(const JackConfiguration&jackConfiguration);
|
||||
|
||||
void updateDefaults(PedalBoardItem*pedalBoardItem);
|
||||
void updateDefaults(PedalBoard*pedalBoard);
|
||||
void UpdateDefaults(PedalBoardItem*pedalBoardItem);
|
||||
void UpdateDefaults(PedalBoard*pedalBoard);
|
||||
|
||||
|
||||
class VuSubscription {
|
||||
@@ -117,8 +119,8 @@ private:
|
||||
|
||||
std::vector<MonitorPortSubscription> activeMonitorPortSubscriptions;
|
||||
|
||||
void updateRealtimeVuSubscriptions();
|
||||
void updateRealtimeMonitorPortSubscriptions();
|
||||
void UpdateRealtimeVuSubscriptions();
|
||||
void UpdateRealtimeMonitorPortSubscriptions();
|
||||
void OnVuUpdate(const std::vector<VuUpdate>& updates);
|
||||
|
||||
std::vector<RealtimeParameterRequest*> outstandingParameterRequests;
|
||||
@@ -140,61 +142,68 @@ public:
|
||||
void LoadLv2PluginInfo(const PiPedalConfiguration&configuration);
|
||||
void Load(const PiPedalConfiguration&configuration);
|
||||
|
||||
const Lv2Host& getPlugins() const { return lv2Host; }
|
||||
PedalBoard getCurrentPedalBoardCopy() {
|
||||
const Lv2Host& GetLv2Host() const { return lv2Host; }
|
||||
PedalBoard GetCurrentPedalBoardCopy()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
return pedalBoard;
|
||||
return pedalBoard; // can return a referece because we'd lose mutex protection
|
||||
}
|
||||
std::vector<Lv2PluginPreset> GetPluginPresets(std::string pluginUri);
|
||||
void LoadPluginPreset(int64_t instanceId,const std::string &presetUri);
|
||||
PluginUiPresets GetPluginUiPresets(const std::string& pluginUri);
|
||||
PluginPresets GetPluginPresets(const std::string&pluginUri);
|
||||
|
||||
void LoadPluginPreset(int64_t pluginInstanceId,uint64_t presetInstanceId);
|
||||
|
||||
void AddNotificationSubscription(IPiPedalModelSubscriber* pSubscriber);
|
||||
void RemoveNotificationSubsription(IPiPedalModelSubscriber* pSubscriber);
|
||||
|
||||
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 previewControl(int64_t clientId,int64_t pedalItemId, const std::string&symbol,float value);
|
||||
void setPedalBoard(int64_t clientId,PedalBoard &pedalBoard);
|
||||
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 PreviewControl(int64_t clientId,int64_t pedalItemId, const std::string&symbol,float value);
|
||||
void SetPedalBoard(int64_t clientId,PedalBoard &pedalBoard);
|
||||
|
||||
void getPresets(PresetIndex*pResult);
|
||||
PedalBoard getPreset(int64_t instanceId);
|
||||
void getBank(int64_t instanceId, BankFile*pBank);
|
||||
void GetPresets(PresetIndex*pResult);
|
||||
PedalBoard GetPreset(int64_t instanceId);
|
||||
void GetBank(int64_t instanceId, BankFile*pBank);
|
||||
|
||||
int64_t uploadBank(BankFile&bankFile, int64_t uploadAfter = -1);
|
||||
int64_t uploadPreset(const BankFile&bankFile, int64_t uploadAfter = -1);
|
||||
void saveCurrentPreset(int64_t clientId);
|
||||
int64_t saveCurrentPresetAs(int64_t clientId, const std::string& name,int64_t saveAfterInstanceId = -1);
|
||||
int64_t UploadBank(BankFile&bankFile, int64_t uploadAfter = -1);
|
||||
int64_t UploadPreset(const BankFile&bankFile, int64_t uploadAfter = -1);
|
||||
void UploadPluginPresets(const PluginPresets&pluginPresets);
|
||||
void SaveCurrentPreset(int64_t clientId);
|
||||
int64_t SaveCurrentPresetAs(int64_t clientId, const std::string& name,int64_t saveAfterInstanceId = -1);
|
||||
int64_t SavePluginPresetAs(int64_t instanceId, const std::string&name);
|
||||
|
||||
void loadPreset(int64_t clientId, int64_t instanceId);
|
||||
bool updatePresets(int64_t clientId,const PresetIndex&presets);
|
||||
int64_t deletePreset(int64_t clientId,int64_t instanceId);
|
||||
bool renamePreset(int64_t clientId,int64_t instanceId,const std::string&name);
|
||||
int64_t copyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex);
|
||||
void LoadPreset(int64_t clientId, int64_t instanceId);
|
||||
bool UpdatePresets(int64_t clientId,const PresetIndex&presets);
|
||||
void UpdatePluginPresets(const PluginUiPresets&pluginPresets);
|
||||
int64_t DeletePreset(int64_t clientId,int64_t instanceId);
|
||||
bool RenamePreset(int64_t clientId,int64_t instanceId,const std::string&name);
|
||||
int64_t CopyPreset(int64_t clientId, int64_t fromIndex, int64_t toIndex);
|
||||
uint64_t CopyPluginPreset(const std::string&pluginUri,uint64_t presetId);
|
||||
|
||||
void moveBank(int64_t clientId,int from, int to);
|
||||
int64_t deleteBank(int64_t clientId, int64_t instanceId);
|
||||
void MoveBank(int64_t clientId,int from, int to);
|
||||
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);
|
||||
JackChannelSelection getJackChannelSelection();
|
||||
void SetJackChannelSelection(int64_t clientId,const JackChannelSelection &channelSelection);
|
||||
JackChannelSelection GetJackChannelSelection();
|
||||
|
||||
void setWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
||||
WifiConfigSettings getWifiConfigSettings();
|
||||
void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
||||
WifiConfigSettings GetWifiConfigSettings();
|
||||
|
||||
|
||||
|
||||
int64_t addVuSubscription(int64_t instanceId);
|
||||
void removeVuSubscription(int64_t subscriptionHandle);
|
||||
int64_t AddVuSubscription(int64_t instanceId);
|
||||
void RemoveVuSubscription(int64_t subscriptionHandle);
|
||||
|
||||
|
||||
int64_t monitorPort(int64_t instanceId,const std::string &key,float updateInterval, PortMonitorCallback onUpdate);
|
||||
void unmonitorPort(int64_t subscriptionHandle);
|
||||
int64_t MonitorPort(int64_t instanceId,const std::string &key,float updateInterval, PortMonitorCallback onUpdate);
|
||||
void UnmonitorPort(int64_t subscriptionHandle);
|
||||
|
||||
void getLv2Parameter(
|
||||
void GetLv2Parameter(
|
||||
int64_t clientId,
|
||||
int64_t instanceId,
|
||||
const std::string uri,
|
||||
@@ -202,22 +211,22 @@ public:
|
||||
std::function<void (const std::string& error)> onError
|
||||
);
|
||||
|
||||
BankIndex getBankIndex() const;
|
||||
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);
|
||||
void openBank(int64_t clientId,int64_t bankId);
|
||||
BankIndex GetBankIndex() const;
|
||||
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);
|
||||
void OpenBank(int64_t clientId,int64_t bankId);
|
||||
|
||||
JackHostStatus getJackStatus() {
|
||||
JackHostStatus GetJackStatus() {
|
||||
return this->jackHost->getJackStatus();
|
||||
}
|
||||
JackServerSettings GetJackServerSettings();
|
||||
void SetJackServerSettings(const JackServerSettings& jackServerSettings);
|
||||
|
||||
void listenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly);
|
||||
void cancelListenForMidiEvent(int64_t clientId, int64_t clientHandle);
|
||||
void ListenForMidiEvent(int64_t clientId, int64_t clientHandle, bool listenForControlsOnly);
|
||||
void CancelListenForMidiEvent(int64_t clientId, int64_t clientHandle);
|
||||
|
||||
void listenForAtomOutputs(int64_t clientId, int64_t clientHandle, uint64_t instanceId);
|
||||
void cancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle);
|
||||
void ListenForAtomOutputs(int64_t clientId, int64_t clientHandle, uint64_t instanceId);
|
||||
void CancelListenForAtomOutputs(int64_t clientId, int64_t clientHandle);
|
||||
|
||||
std::vector<AlsaDeviceInfo> GetAlsaDevices();
|
||||
const std::filesystem::path& GetWebRoot() const;
|
||||
|
||||
+95
-44
@@ -108,14 +108,14 @@ JSON_MAP_END()
|
||||
|
||||
class LoadPluginPresetBody {
|
||||
public:
|
||||
int64_t instanceId_;
|
||||
std::string presetName_;
|
||||
uint64_t pluginInstanceId_;
|
||||
uint64_t presetInstanceId_;
|
||||
DECLARE_JSON_MAP(LoadPluginPresetBody);
|
||||
};
|
||||
|
||||
JSON_MAP_BEGIN(LoadPluginPresetBody)
|
||||
JSON_MAP_REFERENCE(LoadPluginPresetBody, instanceId)
|
||||
JSON_MAP_REFERENCE(LoadPluginPresetBody, presetName)
|
||||
JSON_MAP_REFERENCE(LoadPluginPresetBody, pluginInstanceId)
|
||||
JSON_MAP_REFERENCE(LoadPluginPresetBody, presetInstanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
class FromToBody
|
||||
@@ -189,6 +189,19 @@ JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, name)
|
||||
JSON_MAP_REFERENCE(SaveCurrentPresetAsBody, saveAfterInstanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
class SavePluginPresetAsBody
|
||||
{
|
||||
public:
|
||||
int64_t instanceId_ = -1;
|
||||
std::string name_;
|
||||
|
||||
DECLARE_JSON_MAP(SavePluginPresetAsBody);
|
||||
};
|
||||
JSON_MAP_BEGIN(SavePluginPresetAsBody)
|
||||
JSON_MAP_REFERENCE(SavePluginPresetAsBody, instanceId)
|
||||
JSON_MAP_REFERENCE(SavePluginPresetAsBody, name)
|
||||
JSON_MAP_END()
|
||||
|
||||
class RenameBankBody {
|
||||
public:
|
||||
int64_t bankId_;
|
||||
@@ -231,6 +244,19 @@ JSON_MAP_REFERENCE(CopyPresetBody, fromId)
|
||||
JSON_MAP_REFERENCE(CopyPresetBody, toId)
|
||||
JSON_MAP_END()
|
||||
|
||||
class CopyPluginPresetBody
|
||||
{
|
||||
public:
|
||||
std::string pluginUri_;
|
||||
uint64_t instanceId_;
|
||||
|
||||
DECLARE_JSON_MAP(CopyPluginPresetBody);
|
||||
};
|
||||
JSON_MAP_BEGIN(CopyPluginPresetBody)
|
||||
JSON_MAP_REFERENCE(CopyPluginPresetBody, pluginUri)
|
||||
JSON_MAP_REFERENCE(CopyPluginPresetBody, instanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
class PedalBoardItemEnabledBody
|
||||
{
|
||||
public:
|
||||
@@ -374,11 +400,11 @@ public:
|
||||
{
|
||||
for (int i = 0; i < this->activePortMonitors.size(); ++i)
|
||||
{
|
||||
model.unmonitorPort(activePortMonitors[i].subscriptionHandle);
|
||||
model.UnmonitorPort(activePortMonitors[i].subscriptionHandle);
|
||||
}
|
||||
for (int i = 0; i < this->activeVuSubscriptions.size(); ++i)
|
||||
{
|
||||
model.removeVuSubscription(activeVuSubscriptions[i].subscriptionHandle);
|
||||
model.RemoveVuSubscription(activeVuSubscriptions[i].subscriptionHandle);
|
||||
}
|
||||
|
||||
model.RemoveNotificationSubsription(this);
|
||||
@@ -708,42 +734,42 @@ public:
|
||||
{
|
||||
ControlChangedBody message;
|
||||
pReader->read(&message);
|
||||
this->model.previewControl(message.clientId_, message.instanceId_, message.symbol_, message.value_);
|
||||
this->model.PreviewControl(message.clientId_, message.instanceId_, message.symbol_, message.value_);
|
||||
}
|
||||
else if (message == "setControl")
|
||||
{
|
||||
ControlChangedBody message;
|
||||
pReader->read(&message);
|
||||
this->model.setControl(message.clientId_, message.instanceId_, message.symbol_, message.value_);
|
||||
this->model.SetControl(message.clientId_, message.instanceId_, message.symbol_, message.value_);
|
||||
}
|
||||
else if (message == "listenForMidiEvent")
|
||||
{
|
||||
ListenForMidiEventBody body;
|
||||
pReader->read(&body);
|
||||
this->model.listenForMidiEvent(this->clientId,body.handle_, body.listenForControlsOnly_);
|
||||
this->model.ListenForMidiEvent(this->clientId,body.handle_, body.listenForControlsOnly_);
|
||||
}
|
||||
else if (message == "cancelListenForMidiEvent")
|
||||
{
|
||||
uint64_t handle;
|
||||
pReader->read(&handle);
|
||||
this->model.cancelListenForMidiEvent(this->clientId,handle);
|
||||
this->model.CancelListenForMidiEvent(this->clientId,handle);
|
||||
}
|
||||
else if (message == "listenForAtomOutput")
|
||||
{
|
||||
ListenForAtomOutputBody body;
|
||||
pReader->read(&body);
|
||||
this->model.listenForAtomOutputs(this->clientId,body.handle_, body.instanceId_);
|
||||
this->model.ListenForAtomOutputs(this->clientId,body.handle_, body.instanceId_);
|
||||
}
|
||||
else if (message == "cancelListenForAtomOutput")
|
||||
{
|
||||
int64_t handle;
|
||||
pReader->read(&handle);
|
||||
this->model.cancelListenForMidiEvent(this->clientId,handle);
|
||||
this->model.CancelListenForMidiEvent(this->clientId,handle);
|
||||
}
|
||||
|
||||
else if (message == "getJackStatus")
|
||||
{
|
||||
JackHostStatus status = model.getJackStatus();
|
||||
JackHostStatus status = model.GetJackStatus();
|
||||
this->Reply(replyTo,"getJackStatus",status);
|
||||
} else if (message == "getAlsaDevices")
|
||||
{
|
||||
@@ -762,13 +788,13 @@ public:
|
||||
{
|
||||
std::string uri;
|
||||
pReader->read(&uri);
|
||||
this->Reply(replyTo,"getPluginPresets",this->model.GetPluginPresets(uri));
|
||||
this->Reply(replyTo,"getPluginPresets",this->model.GetPluginUiPresets(uri));
|
||||
}
|
||||
else if (message == "loadPluginPreset")
|
||||
{
|
||||
LoadPluginPresetBody body;
|
||||
pReader->read(&body);
|
||||
this->model.LoadPluginPreset(body.instanceId_,body.presetName_);
|
||||
this->model.LoadPluginPreset(body.pluginInstanceId_,body.presetInstanceId_);
|
||||
|
||||
}
|
||||
else if (message == "setJackServerSettings") {
|
||||
@@ -792,11 +818,11 @@ public:
|
||||
}
|
||||
|
||||
|
||||
this->model.setWifiConfigSettings(wifiConfigSettings);
|
||||
this->model.SetWifiConfigSettings(wifiConfigSettings);
|
||||
this->Reply(replyTo,"setWifiConfigSettings");
|
||||
}
|
||||
else if (message == "getWifiConfigSettings") {
|
||||
this->Reply(replyTo, "getWifiConfigSettings", model.getWifiConfigSettings());
|
||||
this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings());
|
||||
|
||||
}
|
||||
|
||||
@@ -805,42 +831,49 @@ public:
|
||||
|
||||
}
|
||||
else if (message == "getBankIndex") {
|
||||
BankIndex bankIndex = model.getBankIndex();
|
||||
BankIndex bankIndex = model.GetBankIndex();
|
||||
this->Reply(replyTo, "getBankIndex", bankIndex);
|
||||
|
||||
}
|
||||
else if (message == "getJackConfiguration")
|
||||
{
|
||||
JackConfiguration configuration = this->model.getJackConfiguration();
|
||||
JackConfiguration configuration = this->model.GetJackConfiguration();
|
||||
this->Reply(replyTo, "getJackConfiguration", configuration);
|
||||
}
|
||||
else if (message == "getJackSettings")
|
||||
{
|
||||
JackChannelSelection selection = this->model.getJackChannelSelection();
|
||||
JackChannelSelection selection = this->model.GetJackChannelSelection();
|
||||
this->Reply(replyTo, "getJackSettings", selection);
|
||||
}
|
||||
else if (message == "saveCurrentPreset")
|
||||
{
|
||||
this->model.saveCurrentPreset(this->clientId);
|
||||
this->model.SaveCurrentPreset(this->clientId);
|
||||
}
|
||||
else if (message == "saveCurrentPresetAs")
|
||||
{
|
||||
SaveCurrentPresetAsBody body;
|
||||
pReader->read(&body);
|
||||
int64_t result = this->model.saveCurrentPresetAs(this->clientId, body.name_, body.saveAfterInstanceId_);
|
||||
int64_t result = this->model.SaveCurrentPresetAs(this->clientId, body.name_, body.saveAfterInstanceId_);
|
||||
Reply(replyTo, "saveCurrentPresetsAs", result);
|
||||
}
|
||||
else if (message == "savePluginPresetAs")
|
||||
{
|
||||
SavePluginPresetAsBody body;
|
||||
pReader->read(&body);
|
||||
int64_t result = this->model.SavePluginPresetAs(body.instanceId_, body.name_);
|
||||
Reply(replyTo, "saveCurrentPresetsAs", result);
|
||||
}
|
||||
else if (message == "getPresets")
|
||||
{
|
||||
PresetIndex presets;
|
||||
this->model.getPresets(&presets);
|
||||
this->model.GetPresets(&presets);
|
||||
Reply(replyTo, "getPresets", presets);
|
||||
}
|
||||
else if (message == "setPedalBoardItemEnable")
|
||||
{
|
||||
PedalBoardItemEnabledBody body;
|
||||
pReader->read(&body);
|
||||
model.setPedalBoardItemEnable(body.clientId_, body.instanceId_, body.enabled_);
|
||||
model.SetPedalBoardItemEnable(body.clientId_, body.instanceId_, body.enabled_);
|
||||
}
|
||||
else if (message == "setCurrentPedalBoard")
|
||||
{
|
||||
@@ -848,22 +881,22 @@ public:
|
||||
SetCurrentPedalBoardBody body;
|
||||
|
||||
pReader->read(&body);
|
||||
this->model.setPedalBoard(body.clientId_, body.pedalBoard_);
|
||||
this->model.SetPedalBoard(body.clientId_, body.pedalBoard_);
|
||||
}
|
||||
}
|
||||
else if (message == "currentPedalBoard")
|
||||
{
|
||||
auto pedalBoard = model.getCurrentPedalBoardCopy();
|
||||
auto pedalBoard = model.GetCurrentPedalBoardCopy();
|
||||
Reply(replyTo, "currentPedalBoard", pedalBoard);
|
||||
}
|
||||
else if (message == "plugins")
|
||||
{
|
||||
auto ui_plugins = model.getPlugins().GetUiPlugins();
|
||||
auto ui_plugins = model.GetLv2Host().GetUiPlugins();
|
||||
Reply(replyTo, "plugins", ui_plugins);
|
||||
}
|
||||
else if (message == "pluginClasses")
|
||||
{
|
||||
auto classes = model.getPlugins().GetLv2PluginClass();
|
||||
auto classes = model.GetLv2Host().GetLv2PluginClass();
|
||||
Reply(replyTo, "pluginClasses", classes);
|
||||
}
|
||||
else if (message == "hello")
|
||||
@@ -875,7 +908,7 @@ public:
|
||||
{
|
||||
JackChannelSelection jackSettings;
|
||||
pReader->read(&jackSettings);
|
||||
this->model.setJackChannelSelection(this->clientId, jackSettings);
|
||||
this->model.SetJackChannelSelection(this->clientId, jackSettings);
|
||||
}
|
||||
else if (message == "version")
|
||||
{
|
||||
@@ -887,20 +920,27 @@ public:
|
||||
{
|
||||
int64_t instanceId = 0;
|
||||
pReader->read(&instanceId);
|
||||
model.loadPreset(this->clientId, instanceId);
|
||||
model.LoadPreset(this->clientId, instanceId);
|
||||
}
|
||||
else if (message == "updatePresets")
|
||||
{
|
||||
PresetIndex newIndex;
|
||||
pReader->read(&newIndex);
|
||||
bool result = model.updatePresets(this->clientId, newIndex);
|
||||
bool result = model.UpdatePresets(this->clientId, newIndex);
|
||||
this->Reply(replyTo, "updatePresets", result);
|
||||
}
|
||||
else if (message == "updatePluginPresets")
|
||||
{
|
||||
PluginUiPresets pluginPresets;
|
||||
pReader->read(&pluginPresets);
|
||||
model.UpdatePluginPresets(pluginPresets);
|
||||
this->Reply(replyTo, "updatePluginPresets", true);
|
||||
}
|
||||
else if (message == "moveBank")
|
||||
{
|
||||
FromToBody body;
|
||||
pReader->read(&body);
|
||||
model.moveBank(this->clientId, body.from_, body.to_);
|
||||
model.MoveBank(this->clientId, body.from_, body.to_);
|
||||
this->Reply(replyTo, "moveBank");
|
||||
}
|
||||
else if (message == "shutdown")
|
||||
@@ -920,14 +960,14 @@ public:
|
||||
{
|
||||
int64_t instanceId = 0;
|
||||
pReader->read(&instanceId);
|
||||
int64_t result = model.deletePreset(this->clientId, instanceId);
|
||||
int64_t result = model.DeletePreset(this->clientId, instanceId);
|
||||
this->Reply(replyTo, "deletePresetItem", result);
|
||||
}
|
||||
else if (message == "deleteBankItem")
|
||||
{
|
||||
int64_t instanceId = 0;
|
||||
pReader->read(&instanceId);
|
||||
uint64_t result = model.deleteBank(this->clientId, instanceId);
|
||||
uint64_t result = model.DeleteBank(this->clientId, instanceId);
|
||||
this->Reply(replyTo, "deleteBankItem", result);
|
||||
}
|
||||
else if (message == "renameBank")
|
||||
@@ -948,7 +988,7 @@ public:
|
||||
|
||||
|
||||
try {
|
||||
model.renameBank(this->clientId,body.bankId_, body.newName_);
|
||||
model.RenameBank(this->clientId,body.bankId_, body.newName_);
|
||||
this->Reply(replyTo, "renameBank");
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
@@ -960,7 +1000,7 @@ public:
|
||||
int64_t bankId = -1;
|
||||
pReader->read(&bankId);
|
||||
try {
|
||||
model.openBank(this->clientId,bankId);;
|
||||
model.OpenBank(this->clientId,bankId);;
|
||||
this->Reply(replyTo, "openBank");
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
@@ -972,7 +1012,7 @@ public:
|
||||
RenameBankBody body;
|
||||
pReader->read(&body);
|
||||
try {
|
||||
int64_t newId = model.saveBankAs(this->clientId,body.bankId_, body.newName_);
|
||||
int64_t newId = model.SaveBankAs(this->clientId,body.bankId_, body.newName_);
|
||||
this->Reply(replyTo, "saveBankAs",newId);
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
@@ -984,22 +1024,29 @@ public:
|
||||
RenamePresetBody body;
|
||||
pReader->read(&body);
|
||||
|
||||
bool result = model.renamePreset(body.clientId_, body.instanceId_, body.name_);
|
||||
bool result = model.RenamePreset(body.clientId_, body.instanceId_, body.name_);
|
||||
this->Reply(replyTo, "renamePresetItem", result);
|
||||
}
|
||||
else if (message == "copyPreset")
|
||||
{
|
||||
CopyPresetBody body;
|
||||
pReader->read(&body);
|
||||
int64_t result = model.copyPreset(body.clientId_, body.fromId_, body.toId_);
|
||||
int64_t result = model.CopyPreset(body.clientId_, body.fromId_, body.toId_);
|
||||
this->Reply(replyTo, "copyPreset", result);
|
||||
}
|
||||
else if (message == "copyPluginPreset")
|
||||
{
|
||||
CopyPluginPresetBody body;
|
||||
pReader->read(&body);
|
||||
uint64_t result = model.CopyPluginPreset(body.pluginUri_,body.instanceId_);
|
||||
this->Reply(replyTo, "copyPluginPreset", result);
|
||||
}
|
||||
else if (message =="getLv2Parameter")
|
||||
{
|
||||
GetLv2ParameterBody body;
|
||||
pReader->read(&body);
|
||||
|
||||
model.getLv2Parameter(
|
||||
model.GetLv2Parameter(
|
||||
this->clientId,
|
||||
body.instanceId_,
|
||||
body.uri_,
|
||||
@@ -1018,7 +1065,7 @@ public:
|
||||
MonitorPortBody body;
|
||||
pReader->read(&body);
|
||||
|
||||
int64_t subscriptionHandle = model.monitorPort(
|
||||
int64_t subscriptionHandle = model.MonitorPort(
|
||||
body.instanceId_,
|
||||
body.key_,
|
||||
body.updateRate_,
|
||||
@@ -1067,7 +1114,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
model.unmonitorPort(subscriptionHandle);
|
||||
model.UnmonitorPort(subscriptionHandle);
|
||||
}
|
||||
}
|
||||
else if (message == "addVuSubscription")
|
||||
@@ -1076,7 +1123,7 @@ public:
|
||||
|
||||
pReader->read(&instanceId);
|
||||
|
||||
int64_t subscriptionHandle = model.addVuSubscription(instanceId);
|
||||
int64_t subscriptionHandle = model.AddVuSubscription(instanceId);
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(subscriptionMutex);
|
||||
@@ -1100,7 +1147,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
model.removeVuSubscription(subscriptionHandle);
|
||||
model.RemoveVuSubscription(subscriptionHandle);
|
||||
}
|
||||
else if (message == "imageList")
|
||||
{
|
||||
@@ -1194,6 +1241,10 @@ public:
|
||||
body.presets_ = const_cast<PresetIndex *>(&presets);
|
||||
Send("onPresetsChanged", body);
|
||||
}
|
||||
virtual void OnPluginPresetsChanged(const std::string&pluginUri)
|
||||
{
|
||||
Send("onPluginPresetsChanged", pluginUri);
|
||||
}
|
||||
virtual void OnJackConfigurationChanged(const JackConfiguration &jackConfiguration)
|
||||
{
|
||||
Send("onJackConfigurationChanged", jackConfiguration);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "PluginPreset.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
JSON_MAP_BEGIN(PluginUiPreset)
|
||||
JSON_MAP_REFERENCE(PluginUiPreset,label)
|
||||
JSON_MAP_REFERENCE(PluginUiPreset,instanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
JSON_MAP_BEGIN(PluginUiPresets)
|
||||
JSON_MAP_REFERENCE(PluginUiPresets,pluginUri)
|
||||
JSON_MAP_REFERENCE(PluginUiPresets,presets)
|
||||
JSON_MAP_END()
|
||||
|
||||
JSON_MAP_BEGIN(PluginPresetIndexEntry)
|
||||
JSON_MAP_REFERENCE(PluginPresetIndexEntry,pluginUri)
|
||||
JSON_MAP_REFERENCE(PluginPresetIndexEntry,fileName)
|
||||
JSON_MAP_END()
|
||||
|
||||
JSON_MAP_BEGIN(PluginPresetIndex)
|
||||
JSON_MAP_REFERENCE(PluginPresetIndex,entries)
|
||||
JSON_MAP_REFERENCE(PluginPresetIndex,nextInstanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(PluginPreset)
|
||||
JSON_MAP_REFERENCE(PluginPreset,instanceId)
|
||||
JSON_MAP_REFERENCE(PluginPreset,label)
|
||||
JSON_MAP_REFERENCE(PluginPreset,controlValues)
|
||||
JSON_MAP_END()
|
||||
|
||||
JSON_MAP_BEGIN(PluginPresets)
|
||||
JSON_MAP_REFERENCE(PluginPresets,pluginUri)
|
||||
JSON_MAP_REFERENCE(PluginPresets,presets)
|
||||
JSON_MAP_REFERENCE(PluginPresets,nextInstanceId)
|
||||
JSON_MAP_END()
|
||||
|
||||
|
||||
|
||||
// JSON_MAP_BEGIN(PluginPreset)
|
||||
// JSON_MAP_REFERENCE(PluginPreset,presetUri)
|
||||
// JSON_MAP_REFERENCE(PluginPreset,name)
|
||||
// JSON_MAP_REFERENCE(PluginPreset,factoryPreset)
|
||||
// JSON_MAP_REFERENCE(PluginPreset,modified)
|
||||
// JSON_MAP_REFERENCE(PluginPreset,selected)
|
||||
// JSON_MAP_END()
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2021 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class PluginPresetIndexEntry {
|
||||
public:
|
||||
PluginPresetIndexEntry() { }
|
||||
PluginPresetIndexEntry(const std::string &pluginUri, const std::string&fileName)
|
||||
: pluginUri_(pluginUri),
|
||||
fileName_(fileName)
|
||||
{
|
||||
|
||||
}
|
||||
std::string pluginUri_;
|
||||
std::string fileName_;
|
||||
|
||||
|
||||
DECLARE_JSON_MAP(PluginPresetIndexEntry);
|
||||
|
||||
};
|
||||
|
||||
class PluginUiPreset {
|
||||
public:
|
||||
std::string label_;
|
||||
uint64_t instanceId_;
|
||||
DECLARE_JSON_MAP(PluginUiPreset);
|
||||
};
|
||||
|
||||
class PluginUiPresets {
|
||||
public:
|
||||
std::string pluginUri_;
|
||||
std::vector<PluginUiPreset> presets_;
|
||||
DECLARE_JSON_MAP(PluginUiPresets);
|
||||
};
|
||||
|
||||
|
||||
class PluginPresetIndex {
|
||||
public:
|
||||
std::vector<PluginPresetIndexEntry> entries_;
|
||||
uint64_t nextInstanceId_ = 1;
|
||||
DECLARE_JSON_MAP(PluginPresetIndex);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PluginPreset {
|
||||
public:
|
||||
PluginPreset() { }
|
||||
PluginPreset(uint64_t instanceId, std::string&&label, std::map<std::string,float> && controlValues)
|
||||
: instanceId_(instanceId),
|
||||
label_(std::forward<std::string>(label)),
|
||||
controlValues_(std::forward<std::map<std::string,float>>(controlValues))
|
||||
{
|
||||
}
|
||||
PluginPreset(uint64_t instanceId, const std::string&label, const std::map<std::string,float> & controlValues)
|
||||
: instanceId_(instanceId),
|
||||
label_(label),
|
||||
controlValues_(controlValues)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t instanceId_;
|
||||
std::string label_;
|
||||
std::map<std::string,float> controlValues_;
|
||||
DECLARE_JSON_MAP(PluginPreset);
|
||||
};
|
||||
|
||||
class PluginPresets {
|
||||
public:
|
||||
std::string pluginUri_;
|
||||
std::vector<PluginPreset> presets_;
|
||||
uint64_t nextInstanceId_ = 1;
|
||||
|
||||
const PluginPreset&GetPreset(uint64_t presetId) {
|
||||
for (const auto&preset: presets_)
|
||||
{
|
||||
if (preset.instanceId_ == presetId)
|
||||
{
|
||||
return preset;
|
||||
}
|
||||
}
|
||||
throw PiPedalException("Preset id not found.");
|
||||
}
|
||||
int Find(const std::string &label)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i].label_ == label)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
int Find(uint64_t instanceId)
|
||||
{
|
||||
for (size_t i = 0; i < presets_.size(); ++i)
|
||||
{
|
||||
if (presets_[i].instanceId_ == instanceId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
DECLARE_JSON_MAP(PluginPresets);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
+276
-1
@@ -165,11 +165,13 @@ void Storage::Initialize()
|
||||
try
|
||||
{
|
||||
std::filesystem::create_directories(this->GetPresetsDirectory());
|
||||
std::filesystem::create_directories(this->GetPluginPresetsDirectory());
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalStateException("Can't create presets directory. (" + (std::string)this->GetPresetsDirectory() + ") (" + e.what() + ")");
|
||||
}
|
||||
LoadPluginPresetIndex();
|
||||
LoadBankIndex();
|
||||
LoadCurrentBank();
|
||||
try
|
||||
@@ -205,6 +207,10 @@ std::filesystem::path Storage::GetPresetsDirectory() const
|
||||
{
|
||||
return this->dataRoot / "presets";
|
||||
}
|
||||
std::filesystem::path Storage::GetPluginPresetsDirectory() const
|
||||
{
|
||||
return this->dataRoot / "plugin_presets";
|
||||
}
|
||||
std::filesystem::path Storage::GetCurrentPresetPath() const
|
||||
{
|
||||
return this->dataRoot / "currentPreset.json";
|
||||
@@ -255,6 +261,43 @@ void Storage::LoadBankIndex()
|
||||
SaveBankIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::LoadPluginPresetIndex()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto path = GetPluginPresetsDirectory() / "index.json";
|
||||
std::ifstream s;
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
s.open(path);
|
||||
json_reader reader(s);
|
||||
reader.read(&pluginPresetIndex);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::SavePluginPresetIndex()
|
||||
{
|
||||
if (pluginPresetIndexChanged)
|
||||
{
|
||||
pluginPresetIndexChanged = false;
|
||||
std::ofstream os;
|
||||
auto path = GetPluginPresetsDirectory() / "index.json";
|
||||
os.open(path, std::ios_base::trunc);
|
||||
if (os.fail())
|
||||
{
|
||||
throw PiPedalException(SS("Can't write to " << path));
|
||||
}
|
||||
|
||||
json_writer writer(os);
|
||||
writer.write(this->pluginPresetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::SaveBankIndex()
|
||||
{
|
||||
std::ofstream os;
|
||||
@@ -374,7 +417,7 @@ bool Storage::LoadPreset(int64_t instanceId)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void Storage::saveCurrentPreset(const PedalBoard &pedalBoard)
|
||||
void Storage::SaveCurrentPreset(const PedalBoard &pedalBoard)
|
||||
{
|
||||
auto &item = currentBank.getItem(currentBank.selectedPreset());
|
||||
item.preset(pedalBoard);
|
||||
@@ -860,6 +903,238 @@ bool Storage::RestoreCurrentPreset(CurrentPreset*pResult)
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
bool Storage::HasPluginPresets(const std::string &pluginUri) const
|
||||
{
|
||||
for (const auto &entry: this->pluginPresetIndex.entries_)
|
||||
{
|
||||
if (entry.pluginUri_ == pluginUri)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path Storage::GetPluginPresetPath(const std::string &pluginUri) const
|
||||
{
|
||||
for (const auto &entry: this->pluginPresetIndex.entries_)
|
||||
{
|
||||
if (entry.pluginUri_ == pluginUri)
|
||||
{
|
||||
return this->GetPluginPresetsDirectory() / entry.fileName_;
|
||||
}
|
||||
}
|
||||
throw PiPedalArgumentException("Plugin preset file not found.");
|
||||
|
||||
}
|
||||
void Storage::SavePluginPresets(const std::string&pluginUri, const PluginPresets&presets)
|
||||
{
|
||||
std::string name;
|
||||
std::filesystem::path path;
|
||||
bool presetAdded = false;
|
||||
if (!HasPluginPresets(pluginUri))
|
||||
{
|
||||
name = SS(pluginPresetIndex.nextInstanceId_ << ".json");
|
||||
path = GetPluginPresetsDirectory() / name;
|
||||
presetAdded = true;
|
||||
} else {
|
||||
path = GetPluginPresetPath(pluginUri);
|
||||
}
|
||||
auto tempPath = path.string()+".$$$";
|
||||
{
|
||||
std::ofstream os;
|
||||
os.open(tempPath, std::ios_base::trunc);
|
||||
if (os.fail())
|
||||
{
|
||||
throw PiPedalException(SS("Can't write to " << path));
|
||||
}
|
||||
json_writer writer(os);
|
||||
writer.write(presets);
|
||||
}
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
std::filesystem::rename(tempPath,path);
|
||||
|
||||
if (presetAdded)
|
||||
{
|
||||
pluginPresetIndex.entries_.push_back(
|
||||
PluginPresetIndexEntry(
|
||||
pluginUri,name
|
||||
)
|
||||
);
|
||||
pluginPresetIndex.nextInstanceId_++;
|
||||
this->pluginPresetIndexChanged = true;
|
||||
SavePluginPresetIndex();
|
||||
}
|
||||
}
|
||||
|
||||
PluginPresets Storage::GetPluginPresets(const std::string&pluginUri) const
|
||||
{
|
||||
PluginPresets result;
|
||||
if (!HasPluginPresets(pluginUri))
|
||||
{
|
||||
result.pluginUri_ = pluginUri;
|
||||
return result;
|
||||
}
|
||||
std::filesystem::path path = GetPluginPresetPath(pluginUri);
|
||||
std::ifstream s;
|
||||
s.open(path);
|
||||
if (s.fail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
json_reader reader(s);
|
||||
reader.read(&result);
|
||||
return result;
|
||||
}
|
||||
PluginUiPresets Storage::GetPluginUiPresets(const std::string&pluginUri) const
|
||||
{
|
||||
PluginPresets presets = GetPluginPresets(pluginUri);
|
||||
PluginUiPresets result;
|
||||
result.pluginUri_ = presets.pluginUri_;
|
||||
for (size_t i = 0; i < presets.presets_.size(); ++i)
|
||||
{
|
||||
const auto& preset = presets.presets_[i];
|
||||
result.presets_.push_back(
|
||||
PluginUiPreset
|
||||
{
|
||||
preset.label_,
|
||||
preset.instanceId_
|
||||
}
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ControlValue> Storage::GetPluginPresetValues(const std::string&pluginUri, uint64_t instanceId)
|
||||
{
|
||||
auto presets = GetPluginPresets(pluginUri);
|
||||
for (const auto & preset: presets.presets_)
|
||||
{
|
||||
if (preset.instanceId_ == instanceId)
|
||||
{
|
||||
std::vector<ControlValue> result;
|
||||
for (const auto &valuePair: preset.controlValues_)
|
||||
{
|
||||
result.push_back(ControlValue(valuePair.first.c_str(),valuePair.second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw PiPedalException("Plugin preset not found.");
|
||||
}
|
||||
|
||||
uint64_t Storage::SavePluginPreset(
|
||||
const std::string&pluginUri,
|
||||
const std::string&name,
|
||||
const std::map<std::string,float> & values)
|
||||
{
|
||||
auto presets = GetPluginPresets(pluginUri);
|
||||
uint64_t result = -1;
|
||||
bool existing = false;
|
||||
for (size_t i = 0; i < presets.presets_.size(); ++i)
|
||||
{
|
||||
auto & preset = presets.presets_[i];
|
||||
if (preset.label_ == name)
|
||||
{
|
||||
preset.controlValues_ = values;
|
||||
existing = true;
|
||||
result = preset.instanceId_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!existing)
|
||||
{
|
||||
result = presets.nextInstanceId_++;
|
||||
presets.presets_.push_back(
|
||||
PluginPreset(
|
||||
result,
|
||||
name,
|
||||
values
|
||||
));
|
||||
}
|
||||
this->SavePluginPresets(pluginUri,presets);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Storage::UpdatePluginPresets(const PluginUiPresets &pluginPresets)
|
||||
{
|
||||
// handles deletions, renaming, and reordering only.
|
||||
// If you need to add a preset, you neet to call SavePluginPreset or DulicatePluginPreset instead.
|
||||
|
||||
PluginPresets presets = this->GetPluginPresets(pluginPresets.pluginUri_);
|
||||
PluginPresets newPresets;
|
||||
newPresets.pluginUri_ = pluginPresets.pluginUri_;
|
||||
newPresets.nextInstanceId_ = presets.nextInstanceId_;
|
||||
|
||||
for (const auto&preset: pluginPresets.presets_)
|
||||
{
|
||||
PluginPreset newPreset = presets.GetPreset(preset.instanceId_);
|
||||
newPreset.label_ = preset.label_;
|
||||
newPresets.presets_.push_back(std::move(newPreset));
|
||||
}
|
||||
SavePluginPresets(newPresets.pluginUri_,newPresets);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static std::string stripCopySuffix(const std::string &s)
|
||||
{
|
||||
int pos = s.length()-1;
|
||||
if (pos >= 0 && s[pos] == ')')
|
||||
{
|
||||
--pos;
|
||||
while (pos >= 0 && s[pos] >= '0' && s[pos] <= '9')
|
||||
{
|
||||
--pos;
|
||||
}
|
||||
if (pos >= 0 && s[pos] == '(')
|
||||
{
|
||||
--pos;
|
||||
}
|
||||
while (pos >= 0 && s[pos] == ' ')
|
||||
{
|
||||
--pos;
|
||||
}
|
||||
return s.substr(0,pos+1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
uint64_t Storage::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId)
|
||||
{
|
||||
PluginPresets presets = this->GetPluginPresets(pluginUri);
|
||||
size_t pos = presets.Find(presetId);
|
||||
if (pos == -1)
|
||||
{
|
||||
throw PiPedalException("Perset not found.");
|
||||
}
|
||||
PluginPreset t = presets.presets_[pos];
|
||||
t.instanceId_ = presets.nextInstanceId_++;
|
||||
std::string baseName = stripCopySuffix(t.label_);
|
||||
std::string name = baseName;
|
||||
if (presets.Find(name) != -1)
|
||||
{
|
||||
int nCopy = 1;
|
||||
while (true)
|
||||
{
|
||||
name = SS(baseName << " (" << nCopy << ")");
|
||||
if (presets.Find(name) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++nCopy;
|
||||
}
|
||||
}
|
||||
t.label_ = name;
|
||||
presets.presets_.insert(presets.presets_.begin()+pos+1,t);
|
||||
SavePluginPresets(presets.pluginUri_,presets);
|
||||
return t.instanceId_;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
JSON_MAP_BEGIN(CurrentPreset)
|
||||
|
||||
+18
-3
@@ -22,6 +22,7 @@
|
||||
#include <iostream>
|
||||
#include "PedalBoard.hpp"
|
||||
#include "Presets.hpp"
|
||||
#include "PluginPreset.hpp"
|
||||
#include "Banks.hpp"
|
||||
#include "JackConfiguration.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
@@ -45,17 +46,18 @@ private:
|
||||
std::filesystem::path dataRoot;
|
||||
BankIndex bankIndex;
|
||||
BankFile currentBank;
|
||||
PluginPresetIndex pluginPresetIndex;
|
||||
|
||||
private:
|
||||
static std::string SafeEncodeName(const std::string& name);
|
||||
static std::string SafeDecodeName(const std::string& name);
|
||||
std::filesystem::path GetPresetsDirectory() const;
|
||||
std::filesystem::path GetPluginPresetsDirectory() const;
|
||||
std::filesystem::path GetIndexFileName() const;
|
||||
std::filesystem::path GetBankFileName(const std::string & name) const;
|
||||
std::filesystem::path GetChannelSelectionFileName();
|
||||
std::filesystem::path GetCurrentPresetPath() const;
|
||||
|
||||
|
||||
void LoadBankIndex();
|
||||
void SaveBankIndex();
|
||||
void ReIndex();
|
||||
@@ -85,7 +87,7 @@ public:
|
||||
void LoadWifiConfigSettings();
|
||||
void LoadBank(int64_t instanceId);
|
||||
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);
|
||||
|
||||
void GetPresetIndex(PresetIndex*pResult);
|
||||
@@ -117,7 +119,20 @@ public:
|
||||
void SaveCurrentPreset(const CurrentPreset ¤tPreset);
|
||||
bool RestoreCurrentPreset(CurrentPreset*pResult);
|
||||
|
||||
|
||||
private:
|
||||
bool pluginPresetIndexChanged = false;
|
||||
void LoadPluginPresetIndex();
|
||||
void SavePluginPresetIndex();
|
||||
std::filesystem::path GetPluginPresetPath(const std::string &pluginUri) const;
|
||||
public:
|
||||
bool HasPluginPresets(const std::string&pluginUri) const;
|
||||
void SavePluginPresets(const std::string&pluginUri, const PluginPresets&presets);
|
||||
PluginPresets GetPluginPresets(const std::string&pluginUri) const;
|
||||
PluginUiPresets GetPluginUiPresets(const std::string&pluginUri) const;
|
||||
std::vector<ControlValue> GetPluginPresetValues(const std::string&pluginUri, uint64_t instanceId);
|
||||
uint64_t SavePluginPreset(const std::string&pluginUri, const std::string&name, const std::map<std::string,float> & values);
|
||||
void UpdatePluginPresets(const PluginUiPresets &pluginPresets);
|
||||
uint64_t CopyPluginPreset(const std::string&pluginUri,uint64_t presetId);
|
||||
|
||||
};
|
||||
|
||||
|
||||
+3
-3
@@ -614,7 +614,6 @@ void json_reader::throw_format_error(const char*error)
|
||||
} else {
|
||||
for (int i = 0; i < 40; ++i)
|
||||
{
|
||||
if (is_.peek()) break;
|
||||
int c = get();
|
||||
if (c == -1) break;
|
||||
if (c == '\r') {
|
||||
@@ -623,11 +622,12 @@ void json_reader::throw_format_error(const char*error)
|
||||
{
|
||||
s << "\\n";
|
||||
} else {
|
||||
s << c;
|
||||
s << (char)c;
|
||||
}
|
||||
}
|
||||
}
|
||||
s << "'.";
|
||||
throw PiPedalException(s.str());
|
||||
std::string message = s.str();
|
||||
throw PiPedalException(message);
|
||||
|
||||
}
|
||||
|
||||
+53
-1
@@ -278,7 +278,7 @@ public:
|
||||
os << text;
|
||||
}
|
||||
using string_view = boost::string_view;
|
||||
json_writer(std::ostream &os, bool compressed = false, bool allowNaN = true)
|
||||
json_writer(std::ostream &os, bool compressed = true, bool allowNaN = true)
|
||||
: os(os)
|
||||
, compressed(compressed)
|
||||
, allowNaN_(allowNaN)
|
||||
@@ -534,6 +534,26 @@ public:
|
||||
|
||||
end_object();
|
||||
}
|
||||
template <typename U>
|
||||
void write(const std::map<std::string,U> &map)
|
||||
{
|
||||
start_object();
|
||||
|
||||
bool firstTime = true;
|
||||
for (const auto&v : map)
|
||||
{
|
||||
if (!firstTime)
|
||||
{
|
||||
write_raw(",");
|
||||
write_raw(CRLF);
|
||||
}
|
||||
indent();
|
||||
firstTime = false;
|
||||
write_member(v.first.c_str(),v.second);
|
||||
}
|
||||
end_object();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -664,6 +684,38 @@ public:
|
||||
read(*pObject);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void read(std::map<std::string,U> *pMap)
|
||||
{
|
||||
char c;
|
||||
consume('{');
|
||||
|
||||
while (true)
|
||||
{
|
||||
c = peek();
|
||||
if (c == '}')
|
||||
{
|
||||
c = get();
|
||||
break;
|
||||
}
|
||||
std::string key = read_string();
|
||||
|
||||
consume(':');
|
||||
skip_whitespace();
|
||||
|
||||
U u;
|
||||
this->read(&u);
|
||||
(*pMap)[key] = u;
|
||||
skip_whitespace();
|
||||
|
||||
if (peek() == ',')
|
||||
{
|
||||
c = get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void read(std::unique_ptr<T> *pUniquePtr)
|
||||
{
|
||||
|
||||
+86
-20
@@ -43,6 +43,7 @@ using namespace pipedal;
|
||||
|
||||
#define PRESET_EXTENSION ".piPreset"
|
||||
#define BANK_EXTENSION ".piBank"
|
||||
#define PLUGIN_PRESETS_EXTENSION ".piPluginPresets"
|
||||
|
||||
sem_t signalSemaphore;
|
||||
|
||||
@@ -91,23 +92,32 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (request_uri.segment(1) == "downloadPreset")
|
||||
{
|
||||
std::string strInstanceId = request_uri.query("id");
|
||||
if (strInstanceId != "")
|
||||
return true;
|
||||
}
|
||||
else if (request_uri.segment(1) == "uploadPreset")
|
||||
std::string segment = request_uri.segment(1);
|
||||
if (segment == "uploadPluginPresets")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (request_uri.segment(1) == "downloadBank")
|
||||
if (segment == "downloadPluginPresets")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (segment == "downloadPreset")
|
||||
{
|
||||
std::string strInstanceId = request_uri.query("id");
|
||||
if (strInstanceId != "")
|
||||
return true;
|
||||
}
|
||||
else if (request_uri.segment(1) == "uploadBank")
|
||||
else if (segment == "uploadPreset")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (segment == "downloadBank")
|
||||
{
|
||||
std::string strInstanceId = request_uri.query("id");
|
||||
if (strInstanceId != "")
|
||||
return true;
|
||||
}
|
||||
else if (segment == "uploadBank")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -124,11 +134,24 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void GetPluginPresets(const uri &request_uri, std::string*pName,std::string *pContent)
|
||||
{
|
||||
std::string pluginUri = request_uri.query("id");
|
||||
auto plugin = model->GetLv2Host().GetPluginInfo(pluginUri);
|
||||
*pName = plugin->name();
|
||||
|
||||
PluginPresets pluginPresets = model->GetPluginPresets(pluginUri);
|
||||
|
||||
std::stringstream s;
|
||||
json_writer writer(s);
|
||||
writer.write(pluginPresets);
|
||||
*pContent = s.str();
|
||||
}
|
||||
void GetPreset(const uri &request_uri, std::string *pName, std::string *pContent)
|
||||
{
|
||||
std::string strInstanceId = request_uri.query("id");
|
||||
int64_t instanceId = std::stol(strInstanceId);
|
||||
auto pedalBoard = model->getPreset(instanceId);
|
||||
auto pedalBoard = model->GetPreset(instanceId);
|
||||
|
||||
// a certain elegance to using same file format for banks and presets.
|
||||
BankFile file;
|
||||
@@ -147,7 +170,7 @@ public:
|
||||
std::string strInstanceId = request_uri.query("id");
|
||||
int64_t instanceId = std::stol(strInstanceId);
|
||||
BankFile bank;
|
||||
model->getBank(instanceId, &bank);
|
||||
model->GetBank(instanceId, &bank);
|
||||
|
||||
std::stringstream s;
|
||||
json_writer writer(s, true); // do what we can to reduce the file size.
|
||||
@@ -164,7 +187,19 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
if (request_uri.segment(1) == "downloadPreset")
|
||||
std::string segment = request_uri.segment(1);
|
||||
if (segment == "downloadPluginPresets")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
GetPluginPresets(request_uri,&name,&content);
|
||||
res.set(HttpField::content_type, "application/octet-stream");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(content.length());
|
||||
res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PLUGIN_PRESETS_EXTENSION));
|
||||
return;
|
||||
}
|
||||
if (segment == "downloadPreset")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
@@ -176,7 +211,7 @@ public:
|
||||
res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION));
|
||||
return;
|
||||
}
|
||||
if (request_uri.segment(1) == "downloadBank")
|
||||
if (segment == "downloadBank")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
@@ -211,7 +246,19 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
if (request_uri.segment(1) == "downloadPreset")
|
||||
std::string segment = request_uri.segment(1);
|
||||
|
||||
if (segment == "downloadPluginPresets")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
GetPluginPresets(request_uri,&name,&content);
|
||||
res.set(HttpField::content_type, "application/octet-stream");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(content.length());
|
||||
res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PLUGIN_PRESETS_EXTENSION));
|
||||
res.setBody(content);
|
||||
} else if (segment == "downloadPreset")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
@@ -223,7 +270,7 @@ public:
|
||||
res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PRESET_EXTENSION));
|
||||
res.setBody(content);
|
||||
}
|
||||
else if (request_uri.segment(1) == "downloadBank")
|
||||
else if (segment == "downloadBank")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
@@ -260,7 +307,26 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
if (request_uri.segment(1) == "uploadPreset")
|
||||
std::string segment = request_uri.segment(1);
|
||||
|
||||
if (segment == "uploadPluginPresets")
|
||||
{
|
||||
const std::string& presetBody = req.body();
|
||||
std::stringstream s(presetBody);
|
||||
json_reader reader(s);
|
||||
PluginPresets presets;
|
||||
reader.read(&presets);
|
||||
model->UploadPluginPresets(presets);
|
||||
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
std::stringstream sResult;
|
||||
sResult << -1;
|
||||
std::string result = sResult.str();
|
||||
res.setContentLength(result.length());
|
||||
|
||||
res.setBody(result);
|
||||
} else if (segment == "uploadPreset")
|
||||
{
|
||||
const std::string& presetBody = req.body();
|
||||
std::stringstream s(presetBody);
|
||||
@@ -276,7 +342,7 @@ public:
|
||||
BankFile bankFile;
|
||||
reader.read(&bankFile);
|
||||
|
||||
uint64_t instanceId = model->uploadPreset(bankFile, uploadAfter);
|
||||
uint64_t instanceId = model->UploadPreset(bankFile, uploadAfter);
|
||||
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
@@ -287,7 +353,7 @@ public:
|
||||
|
||||
res.setBody(result);
|
||||
}
|
||||
else if (request_uri.segment(1) == "uploadBank")
|
||||
else if (segment == "uploadBank")
|
||||
{
|
||||
const std::string& presetBody = req.body();
|
||||
std::istringstream s(presetBody);
|
||||
@@ -303,7 +369,7 @@ public:
|
||||
BankFile bankFile;
|
||||
reader.read(&bankFile);
|
||||
|
||||
uint64_t instanceId = model->uploadBank(bankFile, uploadAfter);
|
||||
uint64_t instanceId = model->UploadBank(bankFile, uploadAfter);
|
||||
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
@@ -430,7 +496,7 @@ int main(int argc, char *argv[])
|
||||
if (help || parser.Arguments().size() == 0)
|
||||
{
|
||||
std::cout << "pipedald - Pipedal web socket server.\n"
|
||||
"Copyright (c) 2021 Robin Davies.\n"
|
||||
"Copyright (c) 2022 Robin Davies.\n"
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user