Audio stability, snapshots
This commit is contained in:
Vendored
+3
-123
@@ -11,33 +11,6 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
{
|
|
||||||
"name": "Attach to Edge",
|
|
||||||
"port": 9222,
|
|
||||||
"request": "attach",
|
|
||||||
"type": "msedge",
|
|
||||||
"webRoot": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "(gdb) Attach",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "attach",
|
|
||||||
"program": "enter program name, for example ${workspaceFolder}/a.out",
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"setupCommands": [
|
|
||||||
{
|
|
||||||
"description": "Enable pretty-printing for gdb",
|
|
||||||
"text": "-enable-pretty-printing",
|
|
||||||
"ignoreFailures": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Set Disassembly Flavor to Intel",
|
|
||||||
"text": "-gdb-set disassembly-flavor intel",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -67,57 +40,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "(gdb) makeRelease",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
// Resolved by CMake Tools:
|
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
|
||||||
"args": [ ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"cwd": "${workspaceFolder}/../..",
|
|
||||||
"environment": [
|
|
||||||
{
|
|
||||||
"name": "PATH",
|
|
||||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"externalConsole": true,
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"setupCommands": [
|
|
||||||
{
|
|
||||||
"description": "Enable pretty-printing for gdb",
|
|
||||||
"text": "-enable-pretty-printing",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "(gdb) downloadCounts",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
// Resolved by CMake Tools:
|
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
|
||||||
"args": [ "--downloads" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"cwd": "${workspaceFolder}/../..",
|
|
||||||
"environment": [
|
|
||||||
{
|
|
||||||
"name": "PATH",
|
|
||||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"externalConsole": true,
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"setupCommands": [
|
|
||||||
{
|
|
||||||
"description": "Enable pretty-printing for gdb",
|
|
||||||
"text": "-enable-pretty-printing",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "(gdb) pipedal_nm_p2pd",
|
"name": "(gdb) pipedal_nm_p2pd",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
@@ -174,13 +96,7 @@
|
|||||||
"description": "Enable pretty-printing for gdb",
|
"description": "Enable pretty-printing for gdb",
|
||||||
"text": "-enable-pretty-printing",
|
"text": "-enable-pretty-printing",
|
||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Add alsa source directories.",
|
|
||||||
"text": "directory $cd:$cwd:/usr/src/alsa-lib-1.2.8",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -196,7 +112,7 @@
|
|||||||
//"[json_variants]" // subtest of your choice, or none to run all of the tests.
|
//"[json_variants]" // subtest of your choice, or none to run all of the tests.
|
||||||
//"[inverting_mutex_test]"
|
//"[inverting_mutex_test]"
|
||||||
// "[utf8_to_utf32]"
|
// "[utf8_to_utf32]"
|
||||||
"[updater]"
|
"[wifi_channels_test]"
|
||||||
],
|
],
|
||||||
|
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
@@ -256,38 +172,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "(gdb) profilePlugin Launch",
|
|
||||||
"type": "cppdbg",
|
|
||||||
"request": "launch",
|
|
||||||
// Resolved by CMake Tools:
|
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
|
||||||
|
|
||||||
"args": [ "ToobNam_Profile", "--no-profile","-w" ],
|
|
||||||
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"environment": [
|
|
||||||
{
|
|
||||||
"name": "PATH",
|
|
||||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "OTHER_VALUE",
|
|
||||||
"value": "Something something"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"externalConsole": false,
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"setupCommands": [
|
|
||||||
{
|
|
||||||
"description": "Enable pretty-printing for gdb",
|
|
||||||
"text": "-enable-pretty-printing",
|
|
||||||
"ignoreFailures": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -373,15 +257,11 @@
|
|||||||
// Resolved by CMake Tools:
|
// Resolved by CMake Tools:
|
||||||
"program": "${command:cmake.launchTargetPath}",
|
"program": "${command:cmake.launchTargetPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--prefix",
|
|
||||||
"/usr/sbin",
|
|
||||||
"--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.)
|
"--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.)
|
||||||
"--install"
|
|
||||||
|
|
||||||
//"--get-current-port"
|
//"--get-current-port"
|
||||||
//"--install"
|
// "--uninstall"
|
||||||
//"--enable-p2p" , "CA", "PiPedalTest","12345678","14"
|
//"--enable-p2p" , "CA", "PiPedalTest","12345678","14"
|
||||||
//"--list-p2p-channels"
|
"--list-p2p-channels"
|
||||||
],
|
],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
|
|||||||
Vendored
+2
-1
@@ -97,7 +97,8 @@
|
|||||||
"strstream": "cpp",
|
"strstream": "cpp",
|
||||||
"p2p_i.h": "c",
|
"p2p_i.h": "c",
|
||||||
"p2p.h": "c",
|
"p2p.h": "c",
|
||||||
"hash_set": "cpp"
|
"hash_set": "cpp",
|
||||||
|
"barrier": "cpp"
|
||||||
},
|
},
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Guitarix",
|
"Guitarix",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
|||||||
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||||
message(STATUS "Debug build")
|
message(STATUS "Debug build")
|
||||||
|
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -DDEBUG" )
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -DDEBUG -D_GLIBCXX_DEBUG" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Can't get the pkg_check to work.
|
# Can't get the pkg_check to work.
|
||||||
|
|||||||
@@ -61,3 +61,10 @@ export class FakeAndroidHost implements AndroidHostInterface
|
|||||||
return this.theme;
|
return this.theme;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export function isAndroidHosted(): boolean {
|
||||||
|
return ((window as any).AndroidHost as AndroidHostInterface) !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAndroidHost(): AndroidHostInterface | undefined {
|
||||||
|
return ((window as any).AndroidHost as AndroidHostInterface);
|
||||||
|
}
|
||||||
@@ -624,7 +624,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
let atomJson = body.atomJson as any;
|
let atomJson = body.atomJson as any;
|
||||||
this.handleNotifyPathPatchPropertyChanged(instanceId, propertyUri, atomJson);
|
this.handleNotifyPathPatchPropertyChanged(instanceId, propertyUri, atomJson);
|
||||||
if (header.replyTo) {
|
if (header.replyTo) {
|
||||||
this.webSocket?.reply(header.replyTo, "onNotifyPatchProperty", true);
|
this.webSocket?.reply(header.replyTo, "onNotifyPathPatchPropertyChanged", true);
|
||||||
}
|
}
|
||||||
} else if (message === "onNotifyPatchProperty") {
|
} else if (message === "onNotifyPatchProperty") {
|
||||||
let clientHandle = body.clientHandle as number;
|
let clientHandle = body.clientHandle as number;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import SelectThemeDialog from './SelectThemeDialog';
|
|||||||
import Slide, { SlideProps } from '@mui/material/Slide';
|
import Slide, { SlideProps } from '@mui/material/Slide';
|
||||||
import { createStyles, Theme } from '@mui/material/styles';
|
import { createStyles, Theme } from '@mui/material/styles';
|
||||||
import { WithStyles, withStyles } from '@mui/styles';
|
import { WithStyles, withStyles } from '@mui/styles';
|
||||||
|
import { canScaleWindow, getWindowScaleText } from './WindowScale';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -466,8 +467,15 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
midiSummary(): string {
|
midiSummary(): string {
|
||||||
let ports = this.state.jackSettings.inputMidiDevices;
|
let ports = this.state.jackSettings.inputMidiDevices;
|
||||||
if (ports.length === 0) return "Disabled";
|
if (ports.length === 0) return "Disabled";
|
||||||
if (ports.length === 1) return ports[0].description;
|
|
||||||
return ports.length + " channels";
|
let result = "";
|
||||||
|
for (let port of ports) {
|
||||||
|
if (result.length !== 0) {
|
||||||
|
result += ", ";
|
||||||
|
}
|
||||||
|
result += port.description;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
handleShowWifiConfigDialog() {
|
handleShowWifiConfigDialog() {
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -571,7 +579,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
(
|
(
|
||||||
<div>
|
<div>
|
||||||
<Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
|
<Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
|
||||||
Select and configure an audio device. You may optionally configure MIDI inputs, and configure up a Wi-Fi Auto-Hotspot as well.
|
Select and configure an audio device. You may optionally configure MIDI inputs, and configure a Wi-Fi Auto-Hotspot as well.
|
||||||
The Auto-Hotspot feature allows you to connect to Pipedal even if you don't have access to a Wi-Fi router.
|
The Auto-Hotspot feature allows you to connect to Pipedal even if you don't have access to a Wi-Fi router.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
|
<Typography display="block" variant="body1" color="textSecondary" style={{ paddingLeft: 24, paddingBottom: 8 }}>
|
||||||
@@ -678,6 +686,79 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Divider />
|
||||||
|
{(!this.props.onboarding) &&
|
||||||
|
(
|
||||||
|
<div>
|
||||||
|
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||||
|
DISPLAY
|
||||||
|
</Typography>
|
||||||
|
<ButtonBase
|
||||||
|
className={classes.setting}
|
||||||
|
onClick={() => { this.handleThemeSelection(); }} >
|
||||||
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
|
<div style={{ width: "100%" }}>
|
||||||
|
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||||
|
Color theme</Typography>
|
||||||
|
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>
|
||||||
|
{this.model.getTheme() === ColorTheme.Dark ? "Dark" :
|
||||||
|
(this.model.getTheme() === ColorTheme.Light ? "Light" : "System")}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</ButtonBase>
|
||||||
|
|
||||||
|
{(canScaleWindow()) &&
|
||||||
|
(
|
||||||
|
<ButtonBase
|
||||||
|
className={classes.setting}
|
||||||
|
onClick={() => { this.handleThemeSelection(); }} >
|
||||||
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
|
<div style={{ width: "100%" }}>
|
||||||
|
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||||
|
Scale</Typography>
|
||||||
|
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>
|
||||||
|
{getWindowScaleText()}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</ButtonBase>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<ButtonBase
|
||||||
|
className={classes.setting}
|
||||||
|
onClick={() => {
|
||||||
|
this.model.setShowStatusMonitor(!this.state.showStatusMonitor)
|
||||||
|
}} >
|
||||||
|
<SelectHoverBackground selected={false} showHover={true} />
|
||||||
|
<div style={{ width: "100%" }}>
|
||||||
|
<div style={{
|
||||||
|
width: "100%", display: "flex", flexDirection: "row", flexWrap: "nowrap",
|
||||||
|
alignItems: "center", maxWidth: 400
|
||||||
|
}}>
|
||||||
|
<div style={{ flex: "1 1 auto" }}>
|
||||||
|
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||||
|
Show status monitor on main screen.</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ flex: "0 0 auto" }}>
|
||||||
|
<Switch
|
||||||
|
checked={this.state.showStatusMonitor}
|
||||||
|
onChange={
|
||||||
|
(e) => { this.model.setShowStatusMonitor(e.target.checked); }
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ButtonBase>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<div >
|
<div >
|
||||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">CONNECTION</Typography>
|
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">CONNECTION</Typography>
|
||||||
@@ -720,65 +801,6 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
|||||||
<Divider />
|
<Divider />
|
||||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
|
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">SYSTEM</Typography>
|
||||||
|
|
||||||
<ButtonBase
|
|
||||||
style={{ display: "none" }}
|
|
||||||
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
|
||||||
onClick={() => this.handleShowGovernorSettingsDialogDialog()} >
|
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
|
||||||
<div style={{ width: "100%" }}>
|
|
||||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
|
||||||
CPU Governor</Typography>
|
|
||||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
|
||||||
{this.state.governorSettings.governor}
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</ButtonBase>
|
|
||||||
|
|
||||||
<ButtonBase
|
|
||||||
className={classes.setting}
|
|
||||||
onClick={() => { this.handleThemeSelection(); }} >
|
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
|
||||||
<div style={{ width: "100%" }}>
|
|
||||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
|
||||||
Color theme</Typography>
|
|
||||||
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>
|
|
||||||
{this.model.getTheme() === ColorTheme.Dark ? "Dark" :
|
|
||||||
(this.model.getTheme() === ColorTheme.Light ? "Light" : "System")}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</ButtonBase>
|
|
||||||
|
|
||||||
|
|
||||||
<ButtonBase
|
|
||||||
className={classes.setting}
|
|
||||||
onClick={() => {
|
|
||||||
this.model.setShowStatusMonitor(!this.state.showStatusMonitor)
|
|
||||||
}} >
|
|
||||||
<SelectHoverBackground selected={false} showHover={true} />
|
|
||||||
<div style={{ width: "100%" }}>
|
|
||||||
<div style={{
|
|
||||||
width: "100%", display: "flex", flexDirection: "row", flexWrap: "nowrap",
|
|
||||||
alignItems: "center", maxWidth: 400
|
|
||||||
}}>
|
|
||||||
<div style={{ flex: "1 1 auto" }}>
|
|
||||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
|
||||||
Show status monitor on main screen.</Typography>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{ flex: "0 0 auto" }}>
|
|
||||||
<Switch
|
|
||||||
checked={this.state.showStatusMonitor}
|
|
||||||
onChange={
|
|
||||||
(e) => { this.model.setShowStatusMonitor(e.target.checked); }
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ButtonBase>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
this.model.enableAutoUpdate && (
|
this.model.enableAutoUpdate && (
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ export default class SnapshotPanel extends ResizeResponsiveComponent<SnapshotPan
|
|||||||
} else {
|
} else {
|
||||||
return window.innerWidth < 800;
|
return window.innerWidth < 800;
|
||||||
}
|
}
|
||||||
return window.innerWidth < 500;
|
|
||||||
}
|
}
|
||||||
getPortraitOrientation() {
|
getPortraitOrientation() {
|
||||||
return window.innerWidth * 2 < window.innerHeight * 3;
|
return window.innerWidth * 2 < window.innerHeight * 3;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
flex: "1 1 auto",
|
flex: "1 1 auto",
|
||||||
},
|
},
|
||||||
pluginTable: {
|
pluginTable: {
|
||||||
border: "collapse",
|
borderCollapse: "collapse",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -66,6 +66,13 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
verticalAlign: "top",
|
verticalAlign: "top",
|
||||||
paddingTop: 12
|
paddingTop: 12
|
||||||
},
|
},
|
||||||
|
plainRow: {
|
||||||
|
borderWidth: "1px 0px 0px 0px", borderStyle: "solid", borderColor: "transparent"
|
||||||
|
},
|
||||||
|
dividerRow: {
|
||||||
|
borderWidth: "1px 0px 0px 0px", borderStyle: "solid", borderColor: theme.palette.divider
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -118,40 +125,53 @@ export const SystemMidiBindingDialog =
|
|||||||
|
|
||||||
createBindings(): BindingEntry[] {
|
createBindings(): BindingEntry[] {
|
||||||
let result: BindingEntry[] = [];
|
let result: BindingEntry[] = [];
|
||||||
for (var item of this.model.systemMidiBindings.get())
|
let listenInstanceId = 0;
|
||||||
{
|
for (var item of this.model.systemMidiBindings.get()) {
|
||||||
let displayName = "";
|
let displayName = "";
|
||||||
let instanceId = -1;
|
let found = true;
|
||||||
|
if (item.symbol === "nextBank") {
|
||||||
if (item.symbol === "prevProgram")
|
displayName = "Next Bank";
|
||||||
{
|
|
||||||
displayName = "Previous Preset";
|
|
||||||
instanceId = 1;
|
|
||||||
} else if (item.symbol === "nextProgram")
|
|
||||||
{
|
|
||||||
displayName = "Next Preset";
|
|
||||||
instanceId = 2;
|
|
||||||
} else if (item.symbol === "startHotspot")
|
|
||||||
{
|
|
||||||
displayName = "Enable Hotspot";
|
|
||||||
instanceId = 3;
|
|
||||||
} else if (item.symbol === "stopHotspot")
|
|
||||||
{
|
|
||||||
displayName = "Disable Hotspot";
|
|
||||||
instanceId = 4;
|
|
||||||
} else if (item.symbol === "shutdown")
|
|
||||||
{
|
|
||||||
displayName = "Shutdown";
|
|
||||||
instanceId = 5;
|
|
||||||
} else if (item.symbol === "reboot")
|
|
||||||
{
|
|
||||||
displayName = "Reboot";
|
|
||||||
instanceId = 6;
|
|
||||||
}
|
}
|
||||||
|
else if (item.symbol === "prevBank") {
|
||||||
if (instanceId !== -1)
|
displayName = "Previous Bank";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "nextProgram") {
|
||||||
|
displayName = "Next Preset";
|
||||||
|
}else if (item.symbol === "prevProgram") {
|
||||||
|
displayName = "Previous Preset";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "snapshot1") {
|
||||||
|
displayName = "Snapshot 1";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "snapshot2") {
|
||||||
|
displayName = "Snapshot 2";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "snapshot3") {
|
||||||
|
displayName = "Snapshot 3";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "snapshot4") {
|
||||||
|
displayName = "Snapshot 4";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "snapshot5") {
|
||||||
|
displayName = "Snapshot 5";
|
||||||
|
}
|
||||||
|
else if (item.symbol === "snapshot6") {
|
||||||
|
displayName = "Snapshot 6";
|
||||||
|
} else if (item.symbol === "startHotspot") {
|
||||||
|
displayName = "Enable Hotspot";
|
||||||
|
} else if (item.symbol === "stopHotspot") {
|
||||||
|
displayName = "Disable Hotspot";
|
||||||
|
} else if (item.symbol === "shutdown") {
|
||||||
|
displayName = "Shutdown";
|
||||||
|
} else if (item.symbol === "reboot") {
|
||||||
|
displayName = "Reboot";
|
||||||
|
} else {
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
{
|
{
|
||||||
result.push(new BindingEntry(displayName,instanceId,item));
|
result.push(new BindingEntry(displayName, listenInstanceId, item));
|
||||||
|
++listenInstanceId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -174,8 +194,7 @@ export const SystemMidiBindingDialog =
|
|||||||
clearTimeout(this.listenTimeoutHandle);
|
clearTimeout(this.listenTimeoutHandle);
|
||||||
this.listenTimeoutHandle = undefined;
|
this.listenTimeoutHandle = undefined;
|
||||||
}
|
}
|
||||||
if (this.listenHandle)
|
if (this.listenHandle) {
|
||||||
{
|
|
||||||
this.model.cancelListenForMidiEvent(this.listenHandle)
|
this.model.cancelListenForMidiEvent(this.listenHandle)
|
||||||
this.listenHandle = undefined;
|
this.listenHandle = undefined;
|
||||||
}
|
}
|
||||||
@@ -184,14 +203,11 @@ export const SystemMidiBindingDialog =
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleListenSucceeded(instanceId: number, symbol: string, isNote: boolean, noteOrControl: number)
|
handleListenSucceeded(instanceId: number, symbol: string, isNote: boolean, noteOrControl: number) {
|
||||||
{
|
|
||||||
this.cancelListenForControl();
|
this.cancelListenForControl();
|
||||||
|
|
||||||
for (var binding of this.state.systemMidiBindings)
|
for (var binding of this.state.systemMidiBindings) {
|
||||||
{
|
if (binding.instanceId === instanceId) {
|
||||||
if (binding.instanceId === instanceId)
|
|
||||||
{
|
|
||||||
let newBinding = binding.midiBinding.clone();
|
let newBinding = binding.midiBinding.clone();
|
||||||
|
|
||||||
if (isNote) {
|
if (isNote) {
|
||||||
@@ -258,6 +274,16 @@ export const SystemMidiBindingDialog =
|
|||||||
let items = this.state.systemMidiBindings;
|
let items = this.state.systemMidiBindings;
|
||||||
|
|
||||||
for (var item of items) {
|
for (var item of items) {
|
||||||
|
let symbol = item.midiBinding.symbol;
|
||||||
|
let hasDivider = symbol === "snapshot1" || symbol === "stopHotspot" || symbol === "shotdown";
|
||||||
|
if (hasDivider)
|
||||||
|
{
|
||||||
|
result.push(
|
||||||
|
<tr>
|
||||||
|
<td colSpan={2} className={classes.dividerRow}><div style={{height: 1}} /></td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
result.push(
|
result.push(
|
||||||
<tr key={item.instanceId} >
|
<tr key={item.instanceId} >
|
||||||
<td className={classes.nameTd}>
|
<td className={classes.nameTd}>
|
||||||
@@ -268,8 +294,7 @@ export const SystemMidiBindingDialog =
|
|||||||
<td className={classes.bindingTd}>
|
<td className={classes.bindingTd}>
|
||||||
<SystemMidiBindingView instanceId={item.instanceId} midiBinding={item.midiBinding}
|
<SystemMidiBindingView instanceId={item.instanceId} midiBinding={item.midiBinding}
|
||||||
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
onListen={(instanceId: number, symbol: string, listenForControl: boolean) => {
|
||||||
if (instanceId === -2)
|
if (instanceId === -2) {
|
||||||
{
|
|
||||||
this.cancelListenForControl();
|
this.cancelListenForControl();
|
||||||
} else {
|
} else {
|
||||||
this.handleListenForControl(instanceId, symbol, listenForControl);
|
this.handleListenForControl(instanceId, symbol, listenForControl);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
// converts android handling of the virtual keyboard to use pan instead of zoom.
|
// converts android handling of the virtual keyboard to use pan instead of zoom.
|
||||||
|
|
||||||
|
import { isAndroidHosted } from './AndroidHost';
|
||||||
import Rectangle from './Rectangle';
|
import Rectangle from './Rectangle';
|
||||||
|
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ export default class VirtualKeyboardHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('visualViewport' in window) {
|
if ('visualViewport' in window && isAndroidHosted()) {
|
||||||
window.visualViewport?.addEventListener('resize', this.handleVisualViewportResize.bind(this));
|
window.visualViewport?.addEventListener('resize', this.handleVisualViewportResize.bind(this));
|
||||||
} else {
|
} else {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import {isAndroidHosted} from './AndroidHost';
|
||||||
|
|
||||||
|
|
||||||
|
var validScales = [1.0,1.10,1.25,1.35,1.50,1.75,2.0,2.5];
|
||||||
|
|
||||||
|
export function canScaleWindow(): boolean {
|
||||||
|
return getValidWindowScales().length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getValidWindowScales(): number[]
|
||||||
|
{
|
||||||
|
if (isAndroidHosted())
|
||||||
|
{
|
||||||
|
return [1.0];
|
||||||
|
}
|
||||||
|
let result: number[] = [];
|
||||||
|
let minDimension = Math.min(window.innerHeight,window.innerWidth);
|
||||||
|
|
||||||
|
for (let validScale of validScales)
|
||||||
|
{
|
||||||
|
if (minDimension/validScale > 400)
|
||||||
|
{
|
||||||
|
result.push(validScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setWindowScale(scale: number): void {
|
||||||
|
localStorage.setItem("pipedalWindowScale", scale.toString());
|
||||||
|
}
|
||||||
|
export function getWindowScale(): number {
|
||||||
|
const strvalue = localStorage.getItem("pipedalWindowScale");
|
||||||
|
return strvalue ? parseFloat(strvalue) : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWindowScaleText(scale?: number)
|
||||||
|
{
|
||||||
|
let value: number;
|
||||||
|
if (scale)
|
||||||
|
{
|
||||||
|
value = scale;
|
||||||
|
} else {
|
||||||
|
value = getWindowScale();
|
||||||
|
}
|
||||||
|
let iValue = Math.round(value*100);
|
||||||
|
return iValue.toString() + "%";
|
||||||
|
}
|
||||||
+153
-153
@@ -189,14 +189,23 @@ namespace pipedal
|
|||||||
|
|
||||||
AudioDriverHost *driverHost = nullptr;
|
AudioDriverHost *driverHost = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
void validate_capture_handle() { // leftover debugging for a buffer overrun :-/
|
||||||
|
// if (snd_pcm_type(captureHandle) != SND_PCM_TYPE_HW)
|
||||||
|
// {
|
||||||
|
// throw std::runtime_error("Capture handle has been overwritten");
|
||||||
|
// }
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
AlsaDriverImpl(AudioDriverHost *driverHost)
|
AlsaDriverImpl(AudioDriverHost *driverHost)
|
||||||
: driverHost(driverHost)
|
: driverHost(driverHost)
|
||||||
{
|
{
|
||||||
#ifdef ALSADRIVER_CONFIG_DBG
|
midiEventMemory.resize(MAX_MIDI_EVENT * MAX_MIDI_EVENT_SIZE);
|
||||||
snd_output_stdio_attach(&snd_output, stdout, 0);
|
midiEvents.resize(MAX_MIDI_EVENT);
|
||||||
snd_pcm_status_malloc(&snd_status);
|
for (size_t i = 0; i < midiEvents.size(); ++i)
|
||||||
#endif
|
{
|
||||||
|
midiEvents[i].buffer = midiEventMemory.data() + i * MAX_MIDI_EVENT_SIZE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
virtual ~AlsaDriverImpl()
|
virtual ~AlsaDriverImpl()
|
||||||
{
|
{
|
||||||
@@ -302,15 +311,14 @@ namespace pipedal
|
|||||||
snd_pcm_sw_params_free(playbackSwParams);
|
snd_pcm_sw_params_free(playbackSwParams);
|
||||||
playbackSwParams = nullptr;
|
playbackSwParams = nullptr;
|
||||||
}
|
}
|
||||||
for (auto *midiState : this->midiStates)
|
for (auto &midiState : this->midiDevices)
|
||||||
{
|
{
|
||||||
if (midiState != nullptr)
|
if (midiState)
|
||||||
{
|
{
|
||||||
midiState->Close();
|
midiState->Close();
|
||||||
delete midiState;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
midiStates.resize(0);
|
midiDevices.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string discover_alsa_using_apps()
|
std::string discover_alsa_using_apps()
|
||||||
@@ -1234,17 +1242,25 @@ namespace pipedal
|
|||||||
|
|
||||||
void FillOutputBuffer()
|
void FillOutputBuffer()
|
||||||
{
|
{
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
memset(rawPlaybackBuffer.data(), 0, playbackFrameSize * bufferSize);
|
memset(rawPlaybackBuffer.data(), 0, playbackFrameSize * bufferSize);
|
||||||
|
int retry = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto avail = snd_pcm_avail(this->playbackHandle);
|
auto avail = snd_pcm_avail(this->playbackHandle);
|
||||||
if (avail < 0)
|
if (avail < 0)
|
||||||
{
|
{
|
||||||
|
if (++retry >= 5) // kinda sus code. let's make sure we don't spin forever.
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Timed out trying to fill the audio output buffer.");
|
||||||
|
}
|
||||||
int err = snd_pcm_prepare(playbackHandle);
|
int err = snd_pcm_prepare(playbackHandle);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
throw PiPedalStateException(SS("Audio playback failed. " << snd_strerror(err)));
|
throw PiPedalStateException(SS("Audio playback failed. " << snd_strerror(err)));
|
||||||
}
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (avail == 0)
|
if (avail == 0)
|
||||||
@@ -1258,9 +1274,12 @@ namespace pipedal
|
|||||||
throw PiPedalStateException(SS("Audio playback failed. " << snd_strerror(err)));
|
throw PiPedalStateException(SS("Audio playback failed. " << snd_strerror(err)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
}
|
}
|
||||||
void recover_from_output_underrun(snd_pcm_t *capture_handle, snd_pcm_t *playback_handle, int err)
|
void recover_from_output_underrun(snd_pcm_t *capture_handle, snd_pcm_t *playback_handle, int err)
|
||||||
{
|
{
|
||||||
|
validate_capture_handle();
|
||||||
if (err == -EPIPE)
|
if (err == -EPIPE)
|
||||||
{
|
{
|
||||||
err = snd_pcm_prepare(playback_handle);
|
err = snd_pcm_prepare(playback_handle);
|
||||||
@@ -1269,13 +1288,17 @@ namespace pipedal
|
|||||||
throw PiPedalStateException(SS("Can't recover from ALSA output underrun. (" << snd_strerror(err) << ")"));
|
throw PiPedalStateException(SS("Can't recover from ALSA output underrun. (" << snd_strerror(err) << ")"));
|
||||||
}
|
}
|
||||||
FillOutputBuffer();
|
FillOutputBuffer();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
throw PiPedalStateException(SS("Can't recover from ALSA output error. (" << snd_strerror(err) << ")"));
|
throw PiPedalStateException(SS("Can't recover from ALSA output error. (" << snd_strerror(err) << ")"));
|
||||||
}
|
}
|
||||||
|
validate_capture_handle();
|
||||||
}
|
}
|
||||||
void recover_from_input_underrun(snd_pcm_t *capture_handle, snd_pcm_t *playback_handle, int err)
|
void recover_from_input_underrun(snd_pcm_t *capture_handle, snd_pcm_t *playback_handle, int err)
|
||||||
{
|
{
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
if (err == -EPIPE)
|
if (err == -EPIPE)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1317,10 +1340,13 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
throw std::runtime_error(SS("Cannot restart capture stream: " << snd_strerror(err)));
|
throw std::runtime_error(SS("Cannot restart capture stream: " << snd_strerror(err)));
|
||||||
}
|
}
|
||||||
|
validate_capture_handle();
|
||||||
}
|
}
|
||||||
else if (err == ESTRPIPE)
|
else if (err == ESTRPIPE)
|
||||||
{
|
{
|
||||||
audioRunning = false;
|
audioRunning = false;
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
while ((err = snd_pcm_resume(capture_handle)) == -EAGAIN)
|
while ((err = snd_pcm_resume(capture_handle)) == -EAGAIN)
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
@@ -1334,9 +1360,11 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
audioRunning = true;
|
audioRunning = true;
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
throw std::runtime_error(SS("Can't restart audio: " << snd_strerror(err)));
|
throw std::runtime_error(SS("Can't restart audio: " << snd_strerror(err)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1359,9 +1387,10 @@ namespace pipedal
|
|||||||
// transcode to jack format.
|
// transcode to jack format.
|
||||||
// expand running status if neccessary.
|
// expand running status if neccessary.
|
||||||
// deal with regular and sysex messages split across
|
// deal with regular and sysex messages split across
|
||||||
// buffer boundaries.
|
// buffer boundaries (but discard them)
|
||||||
snd_pcm_sframes_t framesRead;
|
snd_pcm_sframes_t framesRead;
|
||||||
|
|
||||||
|
|
||||||
auto state = snd_pcm_state(handle);
|
auto state = snd_pcm_state(handle);
|
||||||
auto frame_bytes = this->captureFrameSize;
|
auto frame_bytes = this->captureFrameSize;
|
||||||
do
|
do
|
||||||
@@ -1384,6 +1413,18 @@ namespace pipedal
|
|||||||
return framesRead;
|
return framesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReadMidiData(uint32_t audioFrame)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < midiDevices.size(); ++i)
|
||||||
|
{
|
||||||
|
size_t nRead = midiDevices[i]->ReadMidiEvents(
|
||||||
|
this->midiEvents,
|
||||||
|
midiEventCount,
|
||||||
|
audioFrame);
|
||||||
|
midiEventCount += nRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long WriteBuffer(snd_pcm_t *handle, uint8_t *buf, size_t frames)
|
long WriteBuffer(snd_pcm_t *handle, uint8_t *buf, size_t frames)
|
||||||
{
|
{
|
||||||
long framesRead;
|
long framesRead;
|
||||||
@@ -1448,25 +1489,31 @@ namespace pipedal
|
|||||||
cpuUse.SetStartTime(cpuUse.Now());
|
cpuUse.SetStartTime(cpuUse.Now());
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
validate_capture_handle();
|
||||||
cpuUse.UpdateCpuUse();
|
cpuUse.UpdateCpuUse();
|
||||||
|
|
||||||
if (terminateAudio())
|
if (terminateAudio())
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this->midiEventCount = 0;
|
||||||
|
|
||||||
// snd_pcm_wait(captureHandle, 1);
|
// snd_pcm_wait(captureHandle, 1);
|
||||||
ssize_t framesToRead = bufferSize;
|
ssize_t framesToRead = bufferSize;
|
||||||
ssize_t framesRead = 0;
|
ssize_t framesRead = 0;
|
||||||
bool xrun = false;
|
bool xrun = false;
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
while (framesToRead != 0)
|
while (framesToRead != 0)
|
||||||
{
|
{
|
||||||
|
ReadMidiData((uint32_t)framesRead);
|
||||||
|
|
||||||
ssize_t thisTime = framesToRead;
|
ssize_t thisTime = framesToRead;
|
||||||
ssize_t nFrames;
|
ssize_t nFrames;
|
||||||
if ((nFrames = ReadBuffer(
|
if ((nFrames = ReadBuffer(
|
||||||
captureHandle,
|
captureHandle,
|
||||||
this->rawCaptureBuffer.data() + this->captureFrameSize * framesRead,
|
this->rawCaptureBuffer.data() + this->captureFrameSize * framesRead,
|
||||||
bufferSize)) < 0)
|
framesToRead)) < 0)
|
||||||
{
|
{
|
||||||
this->driverHost->OnUnderrun();
|
this->driverHost->OnUnderrun();
|
||||||
recover_from_input_underrun(captureHandle, playbackHandle, nFrames);
|
recover_from_input_underrun(captureHandle, playbackHandle, nFrames);
|
||||||
@@ -1476,6 +1523,8 @@ namespace pipedal
|
|||||||
framesRead += nFrames;
|
framesRead += nFrames;
|
||||||
framesToRead -= nFrames;
|
framesToRead -= nFrames;
|
||||||
}
|
}
|
||||||
|
validate_capture_handle();
|
||||||
|
|
||||||
if (xrun)
|
if (xrun)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -1618,11 +1667,16 @@ namespace pipedal
|
|||||||
Lv2Log::debug("Audio thread joined.");
|
Lv2Log::debug("Audio thread joined.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr size_t MAX_MIDI_EVENT_SIZE = 3;
|
||||||
static constexpr size_t MIDI_BUFFER_SIZE = 16 * 1024;
|
static constexpr size_t MIDI_BUFFER_SIZE = 16 * 1024;
|
||||||
static constexpr size_t MAX_MIDI_EVENT = 4 * 1024;
|
static constexpr size_t MAX_MIDI_EVENT = 4 * 1024;
|
||||||
|
|
||||||
|
size_t midiEventCount = 0;
|
||||||
|
std::vector<MidiEvent> midiEvents;
|
||||||
|
std::vector<uint8_t> midiEventMemory;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class MidiState
|
class AlsaMidiDeviceImpl
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
snd_rawmidi_t *hIn = nullptr;
|
snd_rawmidi_t *hIn = nullptr;
|
||||||
@@ -1637,15 +1691,12 @@ namespace pipedal
|
|||||||
size_t data0 = 0;
|
size_t data0 = 0;
|
||||||
size_t data1 = 0;
|
size_t data1 = 0;
|
||||||
|
|
||||||
size_t eventCount = 0;
|
bool inputProcessingSysex = false;
|
||||||
MidiEvent events[MAX_MIDI_EVENT];
|
size_t inputSysexBufferCount = 0;
|
||||||
size_t bufferCount = 0;
|
std::vector<uint8_t> inputSysexBuffer;
|
||||||
uint8_t buffer[MIDI_BUFFER_SIZE];
|
|
||||||
|
|
||||||
uint8_t readBuffer[1024];
|
uint8_t readBuffer[1024];
|
||||||
|
|
||||||
ssize_t sysexStartIndex = -1;
|
|
||||||
|
|
||||||
void checkError(int result, const char *message)
|
void checkError(int result, const char *message)
|
||||||
{
|
{
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
@@ -1655,12 +1706,16 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
AlsaMidiDeviceImpl()
|
||||||
|
{
|
||||||
|
inputSysexBuffer.resize(1024);
|
||||||
|
}
|
||||||
void Open(const AlsaMidiDeviceInfo &device)
|
void Open(const AlsaMidiDeviceInfo &device)
|
||||||
{
|
{
|
||||||
bufferCount = 0;
|
|
||||||
eventCount = 0;
|
|
||||||
sysexStartIndex = -1;
|
|
||||||
runningStatus = 0;
|
runningStatus = 0;
|
||||||
|
inputProcessingSysex = false;
|
||||||
|
inputSysexBufferCount = 0;
|
||||||
|
|
||||||
dataIndex = 0;
|
dataIndex = 0;
|
||||||
dataLength = 0;
|
dataLength = 0;
|
||||||
|
|
||||||
@@ -1701,73 +1756,29 @@ namespace pipedal
|
|||||||
return sDataLength[cc >> 4];
|
return sDataLength[cc >> 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetMidiInputEventCount()
|
|
||||||
{
|
|
||||||
return eventCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NextEventBuffer()
|
|
||||||
{
|
|
||||||
// xxx preserve unflushed sysex data.
|
|
||||||
if (sysexStartIndex != -1)
|
|
||||||
{
|
|
||||||
int end = bufferCount;
|
|
||||||
bufferCount = 0;
|
|
||||||
eventCount = 0;
|
|
||||||
for (int i = sysexStartIndex; i < end; ++i)
|
|
||||||
{
|
|
||||||
buffer[bufferCount++] = buffer[i];
|
|
||||||
}
|
|
||||||
sysexStartIndex = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bufferCount = 0;
|
|
||||||
eventCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool GetMidiInputEvent(MidiEvent *event, size_t nFrame)
|
|
||||||
{
|
|
||||||
if (nFrame >= eventCount)
|
|
||||||
return false;
|
|
||||||
*event = this->events[nFrame];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiPut(uint8_t cc, uint8_t d0, uint8_t d1)
|
void MidiPut(uint8_t cc, uint8_t d0, uint8_t d1)
|
||||||
{
|
{
|
||||||
if (cc == 0)
|
if (cc == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// check for overrun.
|
// check for overrun.
|
||||||
if (bufferCount + 1 + dataLength >= sizeof(buffer))
|
if (inputEventBufferIndex >= pInputEventBuffer->size())
|
||||||
{
|
|
||||||
bufferCount = sizeof(buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (eventCount >= MAX_MIDI_EVENT)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *event = &(this->events[eventCount++]);
|
auto &event = (*pInputEventBuffer)[inputEventBufferIndex];
|
||||||
|
|
||||||
event->time = 0;
|
event.time = inputSampleFrame;
|
||||||
event->buffer = &buffer[bufferCount];
|
event.size = dataLength + 1;
|
||||||
event->size = dataLength + 1;
|
assert(dataLength + 1 <= MAX_MIDI_EVENT_SIZE);
|
||||||
|
event.buffer[0] = cc;
|
||||||
buffer[bufferCount++] = cc;
|
event.buffer[1] = d0;
|
||||||
if (dataLength >= 1)
|
event.buffer[2] = d1;
|
||||||
{
|
++inputEventBufferIndex;
|
||||||
buffer[bufferCount++] = d0;
|
|
||||||
if (dataLength >= 2)
|
|
||||||
{
|
|
||||||
buffer[bufferCount++] = d1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillBuffer()
|
void FillInputBuffer()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -1778,23 +1789,42 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
checkError(nRead, SS(this->deviceName << "MIDI event read failed. (" << snd_strerror(nRead)).c_str());
|
checkError(nRead, SS(this->deviceName << "MIDI event read failed. (" << snd_strerror(nRead)).c_str());
|
||||||
}
|
}
|
||||||
WriteBuffer(readBuffer, nRead); // expose write to test code.
|
ProcessInputBuffer(readBuffer, nRead); // expose write to test code.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t inputSampleFrame = -1;
|
||||||
|
size_t inputEventBufferIndex;
|
||||||
|
std::vector<MidiEvent> *pInputEventBuffer = nullptr;
|
||||||
|
|
||||||
|
size_t ReadMidiEvents(
|
||||||
|
std::vector<MidiEvent> &outputBuffer,
|
||||||
|
size_t startIndex,
|
||||||
|
uint32_t sampleFrame)
|
||||||
|
{
|
||||||
|
inputSampleFrame = sampleFrame;
|
||||||
|
inputEventBufferIndex = startIndex;
|
||||||
|
pInputEventBuffer = &outputBuffer;
|
||||||
|
FillInputBuffer();
|
||||||
|
pInputEventBuffer = nullptr;
|
||||||
|
return inputEventBufferIndex - startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
void FlushSysex()
|
void FlushSysex()
|
||||||
{
|
{
|
||||||
if (sysexStartIndex != -1)
|
if (inputProcessingSysex)
|
||||||
{
|
{
|
||||||
if (this->eventCount != MAX_MIDI_EVENT)
|
// just discard it. :-/
|
||||||
{
|
// if (this->eventCount != MAX_MIDI_EVENT)
|
||||||
auto *event = &(events[eventCount++]);
|
// {
|
||||||
event->size = this->bufferCount - sysexStartIndex;
|
// auto *event = &(events[eventCount++]);
|
||||||
event->buffer = &(this->buffer[this->sysexStartIndex]);
|
// event->size = this->bufferCount - sysexStartIndex;
|
||||||
event->time = 0;
|
// event->buffer = &(this->buffer[this->sysexStartIndex]);
|
||||||
}
|
// event->time = 0;
|
||||||
sysexStartIndex = -1;
|
// }
|
||||||
|
// sysexStartIndex = -1;
|
||||||
}
|
}
|
||||||
|
inputProcessingSysex = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetSystemCommonLength(uint8_t cc)
|
int GetSystemCommonLength(uint8_t cc)
|
||||||
@@ -1802,7 +1832,7 @@ namespace pipedal
|
|||||||
static int sizes[] = {-1, 1, 2, 1, -1, -1, 0, 0};
|
static int sizes[] = {-1, 1, 2, 1, -1, -1, 0, 0};
|
||||||
return sizes[(cc >> 4) & 0x07];
|
return sizes[(cc >> 4) & 0x07];
|
||||||
}
|
}
|
||||||
void WriteBuffer(uint8_t *readBuffer, size_t nRead)
|
void ProcessInputBuffer(uint8_t *readBuffer, size_t nRead)
|
||||||
{
|
{
|
||||||
for (ssize_t i = 0; i < nRead; ++i)
|
for (ssize_t i = 0; i < nRead; ++i)
|
||||||
{
|
{
|
||||||
@@ -1814,13 +1844,10 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
if (v == 0xF0)
|
if (v == 0xF0)
|
||||||
{
|
{
|
||||||
if (bufferCount == sizeof(buffer))
|
inputProcessingSysex = true;
|
||||||
{
|
inputSysexBufferCount = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
sysexStartIndex = bufferCount;
|
|
||||||
|
|
||||||
buffer[bufferCount++] = 0xF0;
|
inputSysexBuffer[inputSysexBufferCount++] = 0xF0;
|
||||||
|
|
||||||
runningStatus = 0; // discard subsequent data.
|
runningStatus = 0; // discard subsequent data.
|
||||||
dataLength = -2; // indefinitely.
|
dataLength = -2; // indefinitely.
|
||||||
@@ -1863,11 +1890,11 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sysexStartIndex != -1)
|
if (inputProcessingSysex)
|
||||||
{
|
{
|
||||||
if (bufferCount != sizeof(buffer))
|
if (inputSysexBufferCount != inputSysexBuffer.size())
|
||||||
{
|
{
|
||||||
buffer[bufferCount++] = v;
|
inputSysexBuffer[inputSysexBufferCount++] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1888,7 +1915,7 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dataIndex == dataLength)
|
if (dataIndex == dataLength && dataLength >= 0 && runningStatus != 0)
|
||||||
{
|
{
|
||||||
MidiPut(runningStatus, data0, data1);
|
MidiPut(runningStatus, data0, data1);
|
||||||
dataIndex = 0;
|
dataIndex = 0;
|
||||||
@@ -1897,70 +1924,40 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<MidiState *> midiStates;
|
std::vector<std::unique_ptr<AlsaMidiDeviceImpl>> midiDevices;
|
||||||
|
|
||||||
void OpenMidi(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
void OpenMidi(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
||||||
{
|
{
|
||||||
const auto &devices = channelSelection.GetInputMidiDevices();
|
const auto &devices = channelSelection.GetInputMidiDevices();
|
||||||
|
|
||||||
midiStates.reserve(devices.size());
|
midiDevices.reserve(devices.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < devices.size(); ++i)
|
for (size_t i = 0; i < devices.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto &device = devices[i];
|
const auto &device = devices[i];
|
||||||
MidiState *midiState = nullptr;
|
auto midiDevice = std::make_unique<AlsaMidiDeviceImpl>();
|
||||||
try
|
midiDevice->Open(device);
|
||||||
{
|
midiDevices.push_back(std::move(midiDevice));
|
||||||
midiState = new MidiState();
|
|
||||||
midiState->Open(device);
|
|
||||||
midiStates.push_back(midiState);
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
// logged already.
|
|
||||||
delete midiState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t MidiInputBufferCount() const
|
|
||||||
{
|
|
||||||
return this->midiStates.size();
|
|
||||||
}
|
|
||||||
virtual void *GetMidiInputBuffer(size_t channel, size_t nFrames)
|
|
||||||
{
|
|
||||||
return (void *)midiStates[channel];
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t GetMidiInputEventCount(void *portBuffer)
|
|
||||||
{
|
|
||||||
MidiState *state = (MidiState *)portBuffer;
|
|
||||||
return state->GetMidiInputEventCount();
|
|
||||||
}
|
|
||||||
virtual bool GetMidiInputEvent(MidiEvent *event, void *portBuf, size_t nFrame)
|
|
||||||
{
|
|
||||||
MidiState *state = (MidiState *)portBuf;
|
|
||||||
return state->GetMidiInputEvent(event, nFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void FillMidiBuffers()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < this->midiStates.size(); ++i)
|
|
||||||
{
|
|
||||||
auto *state = midiStates[i];
|
|
||||||
state->NextEventBuffer();
|
|
||||||
state->FillBuffer();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t InputBufferCount() const { return activeCaptureBuffers.size(); }
|
virtual size_t InputBufferCount() const { return activeCaptureBuffers.size(); }
|
||||||
virtual float *GetInputBuffer(size_t channel, size_t nFrames)
|
virtual float *GetInputBuffer(size_t channel) override
|
||||||
{
|
{
|
||||||
return activeCaptureBuffers[channel];
|
return activeCaptureBuffers[channel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual size_t GetMidiInputEventCount() override
|
||||||
|
{
|
||||||
|
return midiEventCount;
|
||||||
|
}
|
||||||
|
virtual MidiEvent *GetMidiEvents() override
|
||||||
|
{
|
||||||
|
return this->midiEvents.data();
|
||||||
|
}
|
||||||
|
|
||||||
virtual size_t OutputBufferCount() const { return activePlaybackBuffers.size(); }
|
virtual size_t OutputBufferCount() const { return activePlaybackBuffers.size(); }
|
||||||
virtual float *GetOutputBuffer(size_t channel, size_t nFrames)
|
virtual float *GetOutputBuffer(size_t channel) override
|
||||||
{
|
{
|
||||||
return activePlaybackBuffers[channel];
|
return activePlaybackBuffers[channel];
|
||||||
}
|
}
|
||||||
@@ -2158,7 +2155,8 @@ namespace pipedal
|
|||||||
throw PiPedalStateException("Assert failed.");
|
throw PiPedalStateException("Assert failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExpectEvent(AlsaDriverImpl::MidiState &m, int event, const std::vector<uint8_t> message)
|
#ifdef JUNK
|
||||||
|
static void ExpectEvent(AlsaDriverImpl::AlsaMidiDeviceImpl &m, int event, const std::vector<uint8_t> message)
|
||||||
{
|
{
|
||||||
MidiEvent e;
|
MidiEvent e;
|
||||||
m.GetMidiInputEvent(&e, event);
|
m.GetMidiInputEvent(&e, event);
|
||||||
@@ -2168,6 +2166,7 @@ namespace pipedal
|
|||||||
AlsaAssert(message[i] == e.buffer[i]);
|
AlsaAssert(message[i] == e.buffer[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void AlsaDriverImpl::TestFormatEncodeDecode(snd_pcm_format_t captureFormat)
|
void AlsaDriverImpl::TestFormatEncodeDecode(snd_pcm_format_t captureFormat)
|
||||||
{
|
{
|
||||||
@@ -2243,8 +2242,8 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
void MidiDecoderTest()
|
void MidiDecoderTest()
|
||||||
{
|
{
|
||||||
|
#ifdef JUNK
|
||||||
AlsaDriverImpl::MidiState midiState;
|
AlsaDriverImpl::AlsaMidiDeviceImpl midiState;
|
||||||
|
|
||||||
MidiEvent event;
|
MidiEvent event;
|
||||||
|
|
||||||
@@ -2252,7 +2251,7 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
static uint8_t m0[] = {0x80, 0x1, 0x2, 0x3, 0x4, 0x5};
|
static uint8_t m0[] = {0x80, 0x1, 0x2, 0x3, 0x4, 0x5};
|
||||||
midiState.NextEventBuffer();
|
midiState.NextEventBuffer();
|
||||||
midiState.WriteBuffer(m0, sizeof(m0));
|
midiState.ProcessInputBuffer(m0, sizeof(m0));
|
||||||
AlsaAssert(midiState.GetMidiInputEventCount() == 2);
|
AlsaAssert(midiState.GetMidiInputEventCount() == 2);
|
||||||
AlsaAssert(midiState.GetMidiInputEvent(&event, 0));
|
AlsaAssert(midiState.GetMidiInputEvent(&event, 0));
|
||||||
|
|
||||||
@@ -2261,7 +2260,7 @@ namespace pipedal
|
|||||||
|
|
||||||
static uint8_t m1[] = {0x06, 0xC0, 0x1, 0x2};
|
static uint8_t m1[] = {0x06, 0xC0, 0x1, 0x2};
|
||||||
midiState.NextEventBuffer();
|
midiState.NextEventBuffer();
|
||||||
midiState.WriteBuffer(m1, sizeof(m1));
|
midiState.ProcessInputBuffer(m1, sizeof(m1));
|
||||||
AlsaAssert(midiState.GetMidiInputEventCount() == 3);
|
AlsaAssert(midiState.GetMidiInputEventCount() == 3);
|
||||||
ExpectEvent(midiState, 0, {0x80, 0x05, 0x06});
|
ExpectEvent(midiState, 0, {0x80, 0x05, 0x06});
|
||||||
ExpectEvent(midiState, 1, {0xC0, 0x1});
|
ExpectEvent(midiState, 1, {0xC0, 0x1});
|
||||||
@@ -2272,7 +2271,7 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
static uint8_t m0[] = {0xF0, 0x76, 0xF7, 0xA};
|
static uint8_t m0[] = {0xF0, 0x76, 0xF7, 0xA};
|
||||||
midiState.NextEventBuffer();
|
midiState.NextEventBuffer();
|
||||||
midiState.WriteBuffer(m0, 4);
|
midiState.ProcessInputBuffer(m0, 4);
|
||||||
AlsaAssert(midiState.GetMidiInputEventCount() == 2);
|
AlsaAssert(midiState.GetMidiInputEventCount() == 2);
|
||||||
AlsaAssert(midiState.GetMidiInputEvent(&event, 0));
|
AlsaAssert(midiState.GetMidiInputEvent(&event, 0));
|
||||||
AlsaAssert(event.size == 2);
|
AlsaAssert(event.size == 2);
|
||||||
@@ -2284,11 +2283,11 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
static uint8_t m0[] = {0xF0, 0x76, 0x3B};
|
static uint8_t m0[] = {0xF0, 0x76, 0x3B};
|
||||||
midiState.NextEventBuffer();
|
midiState.NextEventBuffer();
|
||||||
midiState.WriteBuffer(m0, sizeof(m0));
|
midiState.ProcessInputBuffer(m0, sizeof(m0));
|
||||||
AlsaAssert(midiState.GetMidiInputEventCount() == 0);
|
AlsaAssert(midiState.GetMidiInputEventCount() == 0);
|
||||||
static uint8_t m1[] = {0x77, 0xF7};
|
static uint8_t m1[] = {0x77, 0xF7};
|
||||||
midiState.NextEventBuffer();
|
midiState.NextEventBuffer();
|
||||||
midiState.WriteBuffer(m1, sizeof(m1));
|
midiState.ProcessInputBuffer(m1, sizeof(m1));
|
||||||
AlsaAssert(midiState.GetMidiInputEventCount() == 2);
|
AlsaAssert(midiState.GetMidiInputEventCount() == 2);
|
||||||
|
|
||||||
AlsaAssert(midiState.GetMidiInputEvent(&event, 0));
|
AlsaAssert(midiState.GetMidiInputEvent(&event, 0));
|
||||||
@@ -2298,5 +2297,6 @@ namespace pipedal
|
|||||||
AlsaAssert(event.buffer[2] == 0x3B);
|
AlsaAssert(event.buffer[2] == 0x3B);
|
||||||
AlsaAssert(event.buffer[3] == 0x77);
|
AlsaAssert(event.buffer[3] == 0x77);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
+6
-12
@@ -38,11 +38,9 @@ namespace pipedal {
|
|||||||
|
|
||||||
struct MidiEvent
|
struct MidiEvent
|
||||||
{
|
{
|
||||||
/* BINARY COMPATIBLE WITH jack_midi_event_t;! (in case we ever want to resurrect Jack support) */
|
uint32_t time; /**< Sample frame at which event is valid */
|
||||||
uint32_t time; /**< Sample index at which event is valid */
|
uint32_t size; /**< Number of bytes of data in \a buffer */
|
||||||
size_t size; /**< Number of bytes of data in \a buffer */
|
|
||||||
uint8_t *buffer; /**< Raw MIDI data */
|
uint8_t *buffer; /**< Raw MIDI data */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -65,19 +63,15 @@ namespace pipedal {
|
|||||||
|
|
||||||
virtual uint32_t GetSampleRate() = 0;
|
virtual uint32_t GetSampleRate() = 0;
|
||||||
|
|
||||||
virtual size_t MidiInputBufferCount() const = 0;
|
virtual size_t GetMidiInputEventCount() = 0;
|
||||||
virtual void*GetMidiInputBuffer(size_t channel, size_t nFrames) = 0;
|
virtual MidiEvent*GetMidiEvents() = 0;
|
||||||
virtual size_t GetMidiInputEventCount(void*buffer) = 0;
|
|
||||||
virtual bool GetMidiInputEvent(MidiEvent*event, void*portBuf, size_t nFrame) = 0;
|
|
||||||
|
|
||||||
virtual void FillMidiBuffers() = 0;
|
|
||||||
|
|
||||||
virtual size_t InputBufferCount() const = 0;
|
virtual size_t InputBufferCount() const = 0;
|
||||||
virtual float*GetInputBuffer(size_t channel, size_t nFrames) = 0;
|
virtual float*GetInputBuffer(size_t channel) = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual size_t OutputBufferCount() const = 0;
|
virtual size_t OutputBufferCount() const = 0;
|
||||||
virtual float*GetOutputBuffer(size_t channel, size_t nFrames) = 0;
|
virtual float*GetOutputBuffer(size_t channe) = 0;
|
||||||
|
|
||||||
virtual void Open(const JackServerSettings & jackServerSettings,const JackChannelSelection &channelSelection) = 0;
|
virtual void Open(const JackServerSettings & jackServerSettings,const JackChannelSelection &channelSelection) = 0;
|
||||||
|
|
||||||
|
|||||||
+212
-103
@@ -291,6 +291,10 @@ public:
|
|||||||
|
|
||||||
bool SystemMidiBinding::IsTriggered(const MidiEvent &event)
|
bool SystemMidiBinding::IsTriggered(const MidiEvent &event)
|
||||||
{
|
{
|
||||||
|
if (!IsMatch(event))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
switch (currentBinding.bindingType())
|
switch (currentBinding.bindingType())
|
||||||
{
|
{
|
||||||
case BINDING_TYPE_NOTE:
|
case BINDING_TYPE_NOTE:
|
||||||
@@ -374,6 +378,9 @@ private:
|
|||||||
uint8_t deferredMidiMessages[DEFERRED_MIDI_BUFFER_SIZE];
|
uint8_t deferredMidiMessages[DEFERRED_MIDI_BUFFER_SIZE];
|
||||||
size_t deferredMidiMessageCount = 0;
|
size_t deferredMidiMessageCount = 0;
|
||||||
bool midiProgramChangePending = false;
|
bool midiProgramChangePending = false;
|
||||||
|
bool midiSnapshotRequestPending = false;
|
||||||
|
int64_t snapshotRequestId = 0;
|
||||||
|
|
||||||
int selectedBank = -1;
|
int selectedBank = -1;
|
||||||
int64_t midiProgramChangeId = 0;
|
int64_t midiProgramChangeId = 0;
|
||||||
|
|
||||||
@@ -462,8 +469,18 @@ private:
|
|||||||
HostRingBufferReader hostReader;
|
HostRingBufferReader hostReader;
|
||||||
HostRingBufferWriter hostWriter;
|
HostRingBufferWriter hostWriter;
|
||||||
|
|
||||||
SystemMidiBinding nextMidiBinding;
|
SystemMidiBinding prevBankMidiBinding;
|
||||||
SystemMidiBinding prevMidiBinding;
|
SystemMidiBinding nextBankMidiBinding;
|
||||||
|
SystemMidiBinding nextPresetMidiBinding;
|
||||||
|
SystemMidiBinding prevPresetMidiBinding;
|
||||||
|
|
||||||
|
SystemMidiBinding snapshot1MidiBinding;
|
||||||
|
SystemMidiBinding snapshot2MidiBinding;
|
||||||
|
SystemMidiBinding snapshot3MidiBinding;
|
||||||
|
SystemMidiBinding snapshot4MidiBinding;
|
||||||
|
SystemMidiBinding snapshot5MidiBinding;
|
||||||
|
SystemMidiBinding snapshot6MidiBinding;
|
||||||
|
|
||||||
SystemMidiBinding startHotspotMidiBinding;
|
SystemMidiBinding startHotspotMidiBinding;
|
||||||
SystemMidiBinding stopHotspotMidiBinding;
|
SystemMidiBinding stopHotspotMidiBinding;
|
||||||
SystemMidiBinding rebootMidiBinding;
|
SystemMidiBinding rebootMidiBinding;
|
||||||
@@ -478,8 +495,6 @@ private:
|
|||||||
std::vector<std::shared_ptr<Lv2Pedalboard>> activePedalboards; // pedalboards that have been sent to the audio queue.
|
std::vector<std::shared_ptr<Lv2Pedalboard>> activePedalboards; // pedalboards that have been sent to the audio queue.
|
||||||
Lv2Pedalboard *realtimeActivePedalboard = nullptr;
|
Lv2Pedalboard *realtimeActivePedalboard = nullptr;
|
||||||
|
|
||||||
std::vector<uint8_t *> midiLv2Buffers;
|
|
||||||
|
|
||||||
uint32_t sampleRate = 0;
|
uint32_t sampleRate = 0;
|
||||||
uint64_t currentSample = 0;
|
uint64_t currentSample = 0;
|
||||||
|
|
||||||
@@ -558,11 +573,6 @@ private:
|
|||||||
this->inputRingBuffer.reset();
|
this->inputRingBuffer.reset();
|
||||||
this->outputRingBuffer.reset();
|
this->outputRingBuffer.reset();
|
||||||
|
|
||||||
for (size_t i = 0; i < midiLv2Buffers.size(); ++i)
|
|
||||||
{
|
|
||||||
delete[] midiLv2Buffers[i];
|
|
||||||
}
|
|
||||||
midiLv2Buffers.resize(0);
|
|
||||||
audioDriver = nullptr;
|
audioDriver = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,7 +589,7 @@ private:
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < audioDriver->OutputBufferCount(); ++i)
|
for (size_t i = 0; i < audioDriver->OutputBufferCount(); ++i)
|
||||||
{
|
{
|
||||||
float *out = (float *)audioDriver->GetOutputBuffer(i, nframes);
|
float *out = (float *)audioDriver->GetOutputBuffer(i);
|
||||||
if (out)
|
if (out)
|
||||||
{
|
{
|
||||||
ZeroBuffer(out, nframes);
|
ZeroBuffer(out, nframes);
|
||||||
@@ -774,6 +784,16 @@ private:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case RingBufferCommand::AckMidiSnapshotRequest:
|
||||||
|
{
|
||||||
|
int64_t requestId;
|
||||||
|
realtimeReader.readComplete(&requestId);
|
||||||
|
if (requestId == this->snapshotRequestId)
|
||||||
|
{
|
||||||
|
this->midiSnapshotRequestPending = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case RingBufferCommand::LoadSnapshot:
|
case RingBufferCommand::LoadSnapshot:
|
||||||
{
|
{
|
||||||
IndexedSnapshot *snapshot;
|
IndexedSnapshot *snapshot;
|
||||||
@@ -851,6 +871,10 @@ private:
|
|||||||
{
|
{
|
||||||
hostWriter.AckMidiProgramRequest(requestId);
|
hostWriter.AckMidiProgramRequest(requestId);
|
||||||
}
|
}
|
||||||
|
virtual void AckSnapshotRequest(uint64_t snapshotRequestId)
|
||||||
|
{
|
||||||
|
hostWriter.AckMidiSnapshotRequest(snapshotRequestId);
|
||||||
|
}
|
||||||
|
|
||||||
void OnMidiValueChanged(uint64_t instanceId, int controlIndex, float value)
|
void OnMidiValueChanged(uint64_t instanceId, int controlIndex, float value)
|
||||||
{
|
{
|
||||||
@@ -867,7 +891,7 @@ private:
|
|||||||
|
|
||||||
bool onMidiEvent(Lv2EventBufferWriter &eventBufferWriter, Lv2EventBufferWriter::LV2_EvBuf_Iterator &iterator, MidiEvent &event)
|
bool onMidiEvent(Lv2EventBufferWriter &eventBufferWriter, Lv2EventBufferWriter::LV2_EvBuf_Iterator &iterator, MidiEvent &event)
|
||||||
{
|
{
|
||||||
eventBufferWriter.writeMidiEvent(iterator, 0, event.size, event.buffer);
|
//eventBufferWriter.writeMidiEvent(iterator, 0, event.size, event.buffer);
|
||||||
|
|
||||||
this->realtimeActivePedalboard->OnMidiMessage(event.size, event.buffer, this, fnMidiValueChanged);
|
this->realtimeActivePedalboard->OnMidiMessage(event.size, event.buffer, this, fnMidiValueChanged);
|
||||||
if (listenForMidiEvent)
|
if (listenForMidiEvent)
|
||||||
@@ -886,50 +910,14 @@ private:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessMidiInput()
|
void OnSnapshotTriggered(int snapshotIndex)
|
||||||
{
|
{
|
||||||
Lv2EventBufferWriter eventBufferWriter(this->eventBufferUrids);
|
// midiProgramChangePending = true;
|
||||||
|
this->midiSnapshotRequestPending = true;
|
||||||
size_t midiInputBufferCount = audioDriver->MidiInputBufferCount();
|
this->realtimeWriter.OnRealtimeMidiSnapshotRequest(snapshotIndex, ++snapshotRequestId);
|
||||||
|
|
||||||
audioDriver->FillMidiBuffers();
|
|
||||||
|
|
||||||
for (size_t midiDeviceIx = 0; midiDeviceIx < midiInputBufferCount; ++midiDeviceIx)
|
|
||||||
{
|
|
||||||
|
|
||||||
void *portBuffer = audioDriver->GetMidiInputBuffer(midiDeviceIx, 0);
|
|
||||||
if (portBuffer)
|
|
||||||
{
|
|
||||||
uint8_t *lv2Buffer = this->midiLv2Buffers[midiDeviceIx];
|
|
||||||
size_t n = audioDriver->GetMidiInputEventCount(portBuffer);
|
|
||||||
|
|
||||||
eventBufferWriter.Reset(lv2Buffer, MIDI_LV2_BUFFER_SIZE);
|
|
||||||
Lv2EventBufferWriter::LV2_EvBuf_Iterator iterator = eventBufferWriter.begin();
|
|
||||||
MidiEvent event;
|
|
||||||
|
|
||||||
// write all deferred midi messages.
|
|
||||||
if (deferredMidiMessageCount != 0 && !midiProgramChangePending)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < deferredMidiMessageCount; /**/)
|
|
||||||
{
|
|
||||||
int8_t deviceIndex = deferredMidiMessages[i++];
|
|
||||||
int8_t messageCount = deferredMidiMessages[i++];
|
|
||||||
if (deviceIndex == midiDeviceIx)
|
|
||||||
{
|
|
||||||
event.size = messageCount;
|
|
||||||
event.buffer = deferredMidiMessages + i;
|
|
||||||
event.time = 0;
|
|
||||||
|
|
||||||
onMidiEvent(eventBufferWriter, iterator, event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i += messageCount;
|
void ProcessMidiEvent(Lv2EventBufferWriter &eventBufferWriter, Lv2EventBufferWriter::LV2_EvBuf_Iterator &iterator, MidiEvent &event)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t frame = 0; frame < n; ++frame)
|
|
||||||
{
|
|
||||||
if (audioDriver->GetMidiInputEvent(&event, portBuffer, frame))
|
|
||||||
{
|
{
|
||||||
uint8_t midiCommand = (uint8_t)(event.buffer[0] & 0xF0);
|
uint8_t midiCommand = (uint8_t)(event.buffer[0] & 0xF0);
|
||||||
if (midiCommand == 0xC0) // midi program change.
|
if (midiCommand == 0xC0) // midi program change.
|
||||||
@@ -943,69 +931,147 @@ private:
|
|||||||
{
|
{
|
||||||
this->selectedBank = event.buffer[2];
|
this->selectedBank = event.buffer[2];
|
||||||
}
|
}
|
||||||
else if (this->nextMidiBinding.IsMatch(event))
|
else if (this->nextBankMidiBinding.IsTriggered(event))
|
||||||
{
|
{
|
||||||
if (nextMidiBinding.IsTriggered(event))
|
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
|
||||||
|
midiProgramChangePending = true;
|
||||||
|
|
||||||
|
this->realtimeWriter.OnNextMidiBank(++(this->midiProgramChangeId), 1);
|
||||||
|
}
|
||||||
|
else if (this->prevBankMidiBinding.IsTriggered(event))
|
||||||
{
|
{
|
||||||
|
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
|
||||||
|
midiProgramChangePending = true;
|
||||||
|
|
||||||
|
this->realtimeWriter.OnNextMidiBank(++(this->midiProgramChangeId), -1);
|
||||||
|
}
|
||||||
|
else if (nextPresetMidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
|
||||||
|
midiProgramChangePending = true;
|
||||||
|
|
||||||
midiProgramChangePending = true;
|
midiProgramChangePending = true;
|
||||||
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId), 1);
|
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId), 1);
|
||||||
}
|
}
|
||||||
}
|
else if (prevPresetMidiBinding.IsTriggered(event))
|
||||||
else if (this->prevMidiBinding.IsMatch(event))
|
|
||||||
{
|
|
||||||
if (prevMidiBinding.IsTriggered(event))
|
|
||||||
{
|
{
|
||||||
|
this->deferredMidiMessageCount = 0; // we can discard previous control changes.
|
||||||
midiProgramChangePending = true;
|
midiProgramChangePending = true;
|
||||||
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId), -1);
|
this->realtimeWriter.OnNextMidiProgram(++(this->midiProgramChangeId), -1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (this->shutdownMidiBinding.IsMatch(event))
|
else if (shutdownMidiBinding.IsTriggered(event))
|
||||||
{
|
|
||||||
if (shutdownMidiBinding.IsTriggered(event))
|
|
||||||
{
|
{
|
||||||
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::Shutdown);
|
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::Shutdown);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (this->rebootMidiBinding.IsMatch(event))
|
|
||||||
{
|
|
||||||
if (rebootMidiBinding.IsTriggered(event))
|
if (rebootMidiBinding.IsTriggered(event))
|
||||||
{
|
{
|
||||||
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::Reboot);
|
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::Reboot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (this->startHotspotMidiBinding.IsMatch(event))
|
|
||||||
{
|
|
||||||
if (startHotspotMidiBinding.IsTriggered(event))
|
if (startHotspotMidiBinding.IsTriggered(event))
|
||||||
{
|
{
|
||||||
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::StartHotspot);
|
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::StartHotspot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (this->stopHotspotMidiBinding.IsMatch(event))
|
|
||||||
{
|
|
||||||
if (stopHotspotMidiBinding.IsTriggered(event))
|
if (stopHotspotMidiBinding.IsTriggered(event))
|
||||||
{
|
{
|
||||||
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::StopHotspot);
|
this->realtimeWriter.OnRealtimeMidiEvent(RealtimeMidiEventType::StopHotspot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (midiProgramChangePending)
|
else if (midiProgramChangePending)
|
||||||
{
|
{
|
||||||
// defer the message for processing after the program change has completed.
|
// defer the message for processing after the program change has completed discarding messages that don't fit in our buffer.
|
||||||
if (event.size > 0 && event.size < 128 && event.size + 2 + this->deferredMidiMessageCount < DEFERRED_MIDI_BUFFER_SIZE)
|
if (event.size > 0 && event.size < 128 && event.size + 2 + this->deferredMidiMessageCount < DEFERRED_MIDI_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
this->deferredMidiMessages[deferredMidiMessageCount++] = midiDeviceIx;
|
|
||||||
this->deferredMidiMessages[deferredMidiMessageCount++] = (uint8_t)event.size;
|
this->deferredMidiMessages[deferredMidiMessageCount++] = (uint8_t)event.size;
|
||||||
for (size_t i = 0; i < event.size; ++i)
|
for (size_t i = 0; i < event.size; ++i)
|
||||||
{
|
{
|
||||||
this->deferredMidiMessages[deferredMidiMessageCount++] = event.buffer[i];
|
this->deferredMidiMessages[deferredMidiMessageCount++] = event.buffer[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (this->snapshot1MidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
OnSnapshotTriggered(0);
|
||||||
|
}
|
||||||
|
else if (this->snapshot2MidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
OnSnapshotTriggered(1);
|
||||||
|
}
|
||||||
|
else if (this->snapshot3MidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
OnSnapshotTriggered(2);
|
||||||
|
}
|
||||||
|
else if (this->snapshot4MidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
OnSnapshotTriggered(3);
|
||||||
|
}
|
||||||
|
else if (this->snapshot5MidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
OnSnapshotTriggered(4);
|
||||||
|
}
|
||||||
|
else if (this->snapshot6MidiBinding.IsTriggered(event))
|
||||||
|
{
|
||||||
|
OnSnapshotTriggered(5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
onMidiEvent(eventBufferWriter, iterator, event);
|
onMidiEvent(eventBufferWriter, iterator, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessDeferredMidiMessages(
|
||||||
|
Lv2EventBufferWriter eventBufferWriter,
|
||||||
|
Lv2EventBufferWriter::LV2_EvBuf_Iterator &iterator)
|
||||||
|
{
|
||||||
|
MidiEvent event;
|
||||||
|
|
||||||
|
// write all deferred midi messages.
|
||||||
|
if (!midiProgramChangePending && !midiSnapshotRequestPending)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < deferredMidiMessageCount; /**/)
|
||||||
|
{
|
||||||
|
int8_t deviceIndex = deferredMidiMessages[i++];
|
||||||
|
int8_t messageCount = deferredMidiMessages[i++];
|
||||||
|
event.size = messageCount;
|
||||||
|
event.buffer = deferredMidiMessages + i;
|
||||||
|
event.time = 0;
|
||||||
|
|
||||||
|
ProcessMidiEvent(eventBufferWriter, iterator, event);
|
||||||
|
|
||||||
|
if (midiProgramChangePending)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
i += messageCount;
|
||||||
|
|
||||||
|
if (midiSnapshotRequestPending)
|
||||||
|
{
|
||||||
|
// consume what has been written so far, leaving what follows for future processing.
|
||||||
|
size_t remaining = deferredMidiMessageCount - i;
|
||||||
|
for (size_t j = 0; j < remaining; ++i)
|
||||||
|
{
|
||||||
|
deferredMidiMessages[j] = deferredMidiMessages[i + j];
|
||||||
|
}
|
||||||
|
deferredMidiMessageCount = remaining;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ProcessMidiInput()
|
||||||
|
{
|
||||||
|
Lv2EventBufferWriter eventBufferWriter(this->eventBufferUrids);
|
||||||
|
Lv2EventBufferWriter::LV2_EvBuf_Iterator iterator = eventBufferWriter.begin();
|
||||||
|
|
||||||
|
ProcessDeferredMidiMessages(eventBufferWriter, iterator);
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t n = audioDriver->GetMidiInputEventCount();
|
||||||
|
MidiEvent *events = audioDriver->GetMidiEvents();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
ProcessMidiEvent(eventBufferWriter, iterator, events[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1062,7 +1128,7 @@ private:
|
|||||||
bool buffersValid = true;
|
bool buffersValid = true;
|
||||||
for (int i = 0; i < audioDriver->InputBufferCount(); ++i)
|
for (int i = 0; i < audioDriver->InputBufferCount(); ++i)
|
||||||
{
|
{
|
||||||
float *input = (float *)audioDriver->GetInputBuffer(i, nframes);
|
float *input = (float *)audioDriver->GetInputBuffer(i);
|
||||||
if (input == nullptr)
|
if (input == nullptr)
|
||||||
{
|
{
|
||||||
buffersValid = false;
|
buffersValid = false;
|
||||||
@@ -1074,7 +1140,7 @@ private:
|
|||||||
|
|
||||||
for (int i = 0; i < audioDriver->OutputBufferCount(); ++i)
|
for (int i = 0; i < audioDriver->OutputBufferCount(); ++i)
|
||||||
{
|
{
|
||||||
float *output = audioDriver->GetOutputBuffer(i, nframes);
|
float *output = audioDriver->GetOutputBuffer(i);
|
||||||
if (output == nullptr)
|
if (output == nullptr)
|
||||||
{
|
{
|
||||||
buffersValid = false;
|
buffersValid = false;
|
||||||
@@ -1393,7 +1459,7 @@ public:
|
|||||||
{
|
{
|
||||||
LV2_URID propertyUrid = ((LV2_Atom_URID *)property)->body;
|
LV2_URID propertyUrid = ((LV2_Atom_URID *)property)->body;
|
||||||
this->pNotifyCallbacks->OnPatchSetReply(instanceId, propertyUrid, value);
|
this->pNotifyCallbacks->OnPatchSetReply(instanceId, propertyUrid, value);
|
||||||
this->pNotifyCallbacks->OnNotifyMaybeLv2StateChanged(instanceId);
|
//this->pNotifyCallbacks->OnNotifyMaybeLv2StateChanged(instanceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1449,12 +1515,27 @@ public:
|
|||||||
hostReader.read(&request);
|
hostReader.read(&request);
|
||||||
pNotifyCallbacks->OnNotifyNextMidiProgram(request);
|
pNotifyCallbacks->OnNotifyNextMidiProgram(request);
|
||||||
}
|
}
|
||||||
|
else if (command == RingBufferCommand::NextMidiBank)
|
||||||
|
{
|
||||||
|
RealtimeNextMidiProgramRequest request;
|
||||||
|
hostReader.read(&request);
|
||||||
|
pNotifyCallbacks->OnNotifyNextMidiBank(request);
|
||||||
|
}
|
||||||
|
|
||||||
else if (command == RingBufferCommand::RealtimeMidiEvent)
|
else if (command == RingBufferCommand::RealtimeMidiEvent)
|
||||||
{
|
{
|
||||||
RealtimeMidiEventRequest request;
|
RealtimeMidiEventRequest request;
|
||||||
hostReader.read(&request);
|
hostReader.read(&request);
|
||||||
pNotifyCallbacks->OnNotifyMidiRealtimeEvent(request.eventType);
|
pNotifyCallbacks->OnNotifyMidiRealtimeEvent(request.eventType);
|
||||||
}
|
}
|
||||||
|
else if (command == RingBufferCommand::RealtimeMidiSnapshotRequest)
|
||||||
|
{
|
||||||
|
RealtimeMidiSnapshotRequest request;
|
||||||
|
hostReader.read(&request);
|
||||||
|
pNotifyCallbacks->OnNotifyMidiRealtimeSnapshotRequest(
|
||||||
|
request.snapshotIndex,
|
||||||
|
request.snapshotRequestId);
|
||||||
|
}
|
||||||
else if (command == RingBufferCommand::Lv2ErrorMessage)
|
else if (command == RingBufferCommand::Lv2ErrorMessage)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -1579,12 +1660,6 @@ public:
|
|||||||
this->overrunGracePeriodSamples = (uint64_t)(((uint64_t)this->sampleRate) * OVERRUN_GRACE_PERIOD_S);
|
this->overrunGracePeriodSamples = (uint64_t)(((uint64_t)this->sampleRate) * OVERRUN_GRACE_PERIOD_S);
|
||||||
this->vuSamplesPerUpdate = (size_t)(sampleRate * VU_UPDATE_RATE_S);
|
this->vuSamplesPerUpdate = (size_t)(sampleRate * VU_UPDATE_RATE_S);
|
||||||
|
|
||||||
midiLv2Buffers.resize(audioDriver->MidiInputBufferCount());
|
|
||||||
for (size_t i = 0; i < audioDriver->MidiInputBufferCount(); ++i)
|
|
||||||
{
|
|
||||||
midiLv2Buffers[i] = AllocateRealtimeBuffer(MIDI_LV2_BUFFER_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
active = true;
|
active = true;
|
||||||
audioStopped = false;
|
audioStopped = false;
|
||||||
audioDriver->Activate();
|
audioDriver->Activate();
|
||||||
@@ -1855,7 +1930,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual bool UpdatePluginStates(Pedalboard &pedalboard) override;
|
//virtual bool UpdatePluginStates(Pedalboard &pedalboard) override;
|
||||||
virtual bool UpdatePluginState(PedalboardItem &pedalboardItem) override;
|
virtual bool UpdatePluginState(PedalboardItem &pedalboardItem) override;
|
||||||
|
|
||||||
class RestartThread
|
class RestartThread
|
||||||
@@ -2040,13 +2115,21 @@ void AudioHostImpl::SetSystemMidiBindings(const std::vector<MidiBinding> &bindin
|
|||||||
for (auto i = bindings.begin(); i != bindings.end(); ++i)
|
for (auto i = bindings.begin(); i != bindings.end(); ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (i->symbol() == "nextProgram")
|
if (i->symbol() == "nextBank")
|
||||||
{
|
{
|
||||||
this->nextMidiBinding.SetBinding(*i);
|
this->nextBankMidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "prevBank")
|
||||||
|
{
|
||||||
|
this->prevBankMidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "nextProgram")
|
||||||
|
{
|
||||||
|
this->nextPresetMidiBinding.SetBinding(*i);
|
||||||
}
|
}
|
||||||
else if (i->symbol() == "prevProgram")
|
else if (i->symbol() == "prevProgram")
|
||||||
{
|
{
|
||||||
this->prevMidiBinding.SetBinding(*i);
|
this->prevPresetMidiBinding.SetBinding(*i);
|
||||||
}
|
}
|
||||||
else if (i->symbol() == "startHotspot")
|
else if (i->symbol() == "startHotspot")
|
||||||
{
|
{
|
||||||
@@ -2064,6 +2147,30 @@ void AudioHostImpl::SetSystemMidiBindings(const std::vector<MidiBinding> &bindin
|
|||||||
{
|
{
|
||||||
this->shutdownMidiBinding.SetBinding(*i);
|
this->shutdownMidiBinding.SetBinding(*i);
|
||||||
}
|
}
|
||||||
|
else if (i->symbol() == "snapshot1")
|
||||||
|
{
|
||||||
|
this->snapshot1MidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "snapshot2")
|
||||||
|
{
|
||||||
|
this->snapshot2MidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "snapshot3")
|
||||||
|
{
|
||||||
|
this->snapshot3MidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "snapshot4")
|
||||||
|
{
|
||||||
|
this->snapshot4MidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "snapshot5")
|
||||||
|
{
|
||||||
|
this->snapshot5MidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
|
else if (i->symbol() == "snapshot6")
|
||||||
|
{
|
||||||
|
this->snapshot6MidiBinding.SetBinding(*i);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Lv2Log::error(SS("Invalid system midi binding: " << i->symbol()));
|
Lv2Log::error(SS("Invalid system midi binding: " << i->symbol()));
|
||||||
@@ -2076,22 +2183,24 @@ AudioHost *AudioHost::CreateInstance(IHost *pHost)
|
|||||||
return new AudioHostImpl(pHost);
|
return new AudioHostImpl(pHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioHostImpl::UpdatePluginStates(Pedalboard &pedalboard)
|
// Removed because any updates to state have to be sent to clients as well,
|
||||||
{
|
// so this functionality was moved to PiPedalModel::SyncLv2States();
|
||||||
bool changed = false;
|
// bool AudioHostImpl::UpdatePluginStates(Pedalboard &pedalboard)
|
||||||
auto pedalboardItems = pedalboard.GetAllPlugins();
|
// {
|
||||||
for (PedalboardItem *item : pedalboardItems)
|
// bool changed = false;
|
||||||
{
|
// auto pedalboardItems = pedalboard.GetAllPlugins();
|
||||||
if (!item->isSplit())
|
// for (PedalboardItem *item : pedalboardItems)
|
||||||
{
|
// {
|
||||||
if (UpdatePluginState(*item))
|
// if (!item->isSplit())
|
||||||
{
|
// {
|
||||||
changed = true;
|
// if (UpdatePluginState(*item))
|
||||||
}
|
// {
|
||||||
}
|
// changed = true;
|
||||||
}
|
// }
|
||||||
return true;
|
// }
|
||||||
}
|
// }
|
||||||
|
// return changed;
|
||||||
|
// }
|
||||||
|
|
||||||
void AudioHostImpl::OnNotifyPathPatchPropertyReceived(
|
void AudioHostImpl::OnNotifyPathPatchPropertyReceived(
|
||||||
int64_t instanceId,
|
int64_t instanceId,
|
||||||
|
|||||||
+5
-1
@@ -166,8 +166,10 @@ namespace pipedal
|
|||||||
|
|
||||||
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest) = 0;
|
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest) = 0;
|
||||||
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request) = 0;
|
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request) = 0;
|
||||||
|
virtual void OnNotifyNextMidiBank(const RealtimeNextMidiProgramRequest &request) = 0;
|
||||||
virtual void OnNotifyLv2RealtimeError(int64_t instanceId, const std::string &error) = 0;
|
virtual void OnNotifyLv2RealtimeError(int64_t instanceId, const std::string &error) = 0;
|
||||||
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) = 0;
|
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) = 0;
|
||||||
|
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JackHostStatus
|
class JackHostStatus
|
||||||
@@ -206,7 +208,7 @@ namespace pipedal
|
|||||||
virtual void SetListenForMidiEvent(bool listen) = 0;
|
virtual void SetListenForMidiEvent(bool listen) = 0;
|
||||||
virtual void SetListenForAtomOutput(bool listen) = 0;
|
virtual void SetListenForAtomOutput(bool listen) = 0;
|
||||||
|
|
||||||
virtual bool UpdatePluginStates(Pedalboard &pedalboard) = 0;
|
//virtual bool UpdatePluginStates(Pedalboard &pedalboard) = 0;
|
||||||
virtual bool UpdatePluginState(PedalboardItem &pedalboardItem) = 0;
|
virtual bool UpdatePluginState(PedalboardItem &pedalboardItem) = 0;
|
||||||
|
|
||||||
virtual std::string AtomToJson(const LV2_Atom *atom) = 0;
|
virtual std::string AtomToJson(const LV2_Atom *atom) = 0;
|
||||||
@@ -235,6 +237,8 @@ namespace pipedal
|
|||||||
|
|
||||||
virtual void sendRealtimeParameterRequest(RealtimePatchPropertyRequest *pParameterRequest) = 0;
|
virtual void sendRealtimeParameterRequest(RealtimePatchPropertyRequest *pParameterRequest) = 0;
|
||||||
virtual void AckMidiProgramRequest(uint64_t requestId) = 0;
|
virtual void AckMidiProgramRequest(uint64_t requestId) = 0;
|
||||||
|
virtual void AckSnapshotRequest(uint64_t snapshotRequestId) = 0;
|
||||||
|
|
||||||
|
|
||||||
virtual JackHostStatus getJackStatus() = 0;
|
virtual JackHostStatus getJackStatus() = 0;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -113,7 +113,7 @@ add_compile_definitions(DEBIAN_ARCHITECTURE="${DEBIAN_ARCHITECTURE}")
|
|||||||
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
if (CMAKE_BUILD_TYPE MATCHES Debug)
|
||||||
message(STATUS "Debug build")
|
message(STATUS "Debug build")
|
||||||
|
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -DDEBUG" )
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -DDEBUG -D_GLIBCXX_DEBUG" )
|
||||||
if (USE_SANITIZE)
|
if (USE_SANITIZE)
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -static-libasan " )
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -static-libasan " )
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
+10
-114
@@ -150,6 +150,14 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual size_t GetMidiInputEventCount() override {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
virtual MidiEvent*GetMidiEvents() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JackChannelSelection channelSelection;
|
JackChannelSelection channelSelection;
|
||||||
bool open = false;
|
bool open = false;
|
||||||
virtual void Open(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
virtual void Open(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
||||||
@@ -166,7 +174,6 @@ namespace pipedal
|
|||||||
open = true;
|
open = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OpenMidi(jackServerSettings, channelSelection);
|
|
||||||
OpenAudio(jackServerSettings, channelSelection);
|
OpenAudio(jackServerSettings, channelSelection);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
@@ -348,128 +355,17 @@ namespace pipedal
|
|||||||
static constexpr size_t MAX_MIDI_EVENT = 4 * 1024;
|
static constexpr size_t MAX_MIDI_EVENT = 4 * 1024;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class MidiState
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
snd_rawmidi_t *hIn = nullptr;
|
|
||||||
snd_rawmidi_params_t *hInParams = nullptr;
|
|
||||||
std::string deviceName;
|
|
||||||
|
|
||||||
// running status state.
|
|
||||||
uint8_t runningStatus = 0;
|
|
||||||
int dataLength = 0;
|
|
||||||
int dataIndex = 0;
|
|
||||||
size_t statusBytesRemaining = 0;
|
|
||||||
size_t data0;
|
|
||||||
size_t data1;
|
|
||||||
|
|
||||||
size_t eventCount = 0;
|
|
||||||
MidiEvent events[MAX_MIDI_EVENT];
|
|
||||||
size_t bufferCount = 0;
|
|
||||||
uint8_t buffer[MIDI_BUFFER_SIZE];
|
|
||||||
|
|
||||||
uint8_t readBuffer[1024];
|
|
||||||
|
|
||||||
ssize_t sysexStartIndex = -1;
|
|
||||||
|
|
||||||
void checkError(int result, const char *message)
|
|
||||||
{
|
|
||||||
if (result < 0)
|
|
||||||
{
|
|
||||||
throw PiPedalStateException(SS("Unexpected error: " << message << " (" << this->deviceName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void Open(const AlsaMidiDeviceInfo &device)
|
|
||||||
{
|
|
||||||
bufferCount = 0;
|
|
||||||
eventCount = 0;
|
|
||||||
sysexStartIndex = -1;
|
|
||||||
runningStatus = 0;
|
|
||||||
dataIndex = 0;
|
|
||||||
dataLength = 0;
|
|
||||||
|
|
||||||
this->deviceName = device.description_;
|
|
||||||
|
|
||||||
}
|
|
||||||
void Close()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t GetMidiInputEventCount()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetMidiInputEvent(MidiEvent *event, size_t nFrame)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MidiPut(uint8_t cc, uint8_t d0, uint8_t d1)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FillBuffer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteBuffer(uint8_t *readBuffer, size_t nRead)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<MidiState *> midiStates;
|
|
||||||
|
|
||||||
void OpenMidi(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection)
|
|
||||||
{
|
|
||||||
const auto &devices = channelSelection.GetInputMidiDevices();
|
|
||||||
|
|
||||||
midiStates.resize(devices.size());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < devices.size(); ++i)
|
|
||||||
{
|
|
||||||
const auto &device = devices[i];
|
|
||||||
MidiState *state = new MidiState();
|
|
||||||
midiStates[i] = state;
|
|
||||||
state->Open(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t MidiInputBufferCount() const
|
|
||||||
{
|
|
||||||
return this->midiStates.size();
|
|
||||||
}
|
|
||||||
virtual void *GetMidiInputBuffer(size_t channel, size_t nFrames)
|
|
||||||
{
|
|
||||||
return (void *)midiStates[channel];
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t GetMidiInputEventCount(void *portBuffer)
|
|
||||||
{
|
|
||||||
MidiState *state = (MidiState *)portBuffer;
|
|
||||||
return state->GetMidiInputEventCount();
|
|
||||||
}
|
|
||||||
virtual bool GetMidiInputEvent(MidiEvent *event, void *portBuf, size_t nFrame)
|
|
||||||
{
|
|
||||||
MidiState *state = (MidiState *)portBuf;
|
|
||||||
return state->GetMidiInputEvent(event, nFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void FillMidiBuffers()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t InputBufferCount() const { return activeCaptureBuffers.size(); }
|
virtual size_t InputBufferCount() const { return activeCaptureBuffers.size(); }
|
||||||
virtual float *GetInputBuffer(size_t channel, size_t nFrames)
|
virtual float *GetInputBuffer(size_t channel)
|
||||||
{
|
{
|
||||||
return activeCaptureBuffers[channel];
|
return activeCaptureBuffers[channel];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t OutputBufferCount() const { return activePlaybackBuffers.size(); }
|
virtual size_t OutputBufferCount() const { return activePlaybackBuffers.size(); }
|
||||||
virtual float *GetOutputBuffer(size_t channel, size_t nFrames)
|
virtual float *GetOutputBuffer(size_t channel)
|
||||||
{
|
{
|
||||||
return activePlaybackBuffers[channel];
|
return activePlaybackBuffers[channel];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ using namespace dbus::networkmanager;
|
|||||||
namespace pipedal::impl
|
namespace pipedal::impl
|
||||||
{
|
{
|
||||||
|
|
||||||
constexpr std::string PIPEDAL_HOTSPOT_NAME = "PiPedal Hotspot";
|
#define PIPEDAL_HOTSPOT_NAME "PiPedal Hotspot"
|
||||||
|
|
||||||
class HotspotManagerImpl : public HotspotManager
|
class HotspotManagerImpl : public HotspotManager
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -358,11 +358,11 @@ public:
|
|||||||
|
|
||||||
for (size_t i = 0; i < inputs; ++i)
|
for (size_t i = 0; i < inputs; ++i)
|
||||||
{
|
{
|
||||||
inputBuffers[i] = audioDriver->GetInputBuffer(i, nFrames);
|
inputBuffers[i] = audioDriver->GetInputBuffer(i);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < outputs; ++i)
|
for (size_t i = 0; i < outputs; ++i)
|
||||||
{
|
{
|
||||||
outputBuffers[i] = audioDriver->GetOutputBuffer(i, nFrames);
|
outputBuffers[i] = audioDriver->GetOutputBuffer(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < nFrames; ++i)
|
for (size_t i = 0; i < nFrames; ++i)
|
||||||
|
|||||||
+91
-14
@@ -349,6 +349,7 @@ void PiPedalModel::PreviewControl(int64_t clientId, int64_t pedalItemId, const s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we were explicitly told that the state was changed by the plugin
|
||||||
void PiPedalModel::OnNotifyLv2StateChanged(uint64_t instanceId)
|
void PiPedalModel::OnNotifyLv2StateChanged(uint64_t instanceId)
|
||||||
{
|
{
|
||||||
// a sent PATCH_Set, or an explicit state changed notification.
|
// a sent PATCH_Set, or an explicit state changed notification.
|
||||||
@@ -356,6 +357,7 @@ void PiPedalModel::OnNotifyLv2StateChanged(uint64_t instanceId)
|
|||||||
this->SetPresetChanged(-1, true, false);
|
this->SetPresetChanged(-1, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The plugin notified us that a path path property changed. The state *purrobably changed.
|
||||||
void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
||||||
{
|
{
|
||||||
// one or more received PATCH_Sets, which MAY change the state.
|
// one or more received PATCH_Sets, which MAY change the state.
|
||||||
@@ -363,7 +365,9 @@ void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
|||||||
PedalboardItem *item = pedalboard.GetItem(instanceId);
|
PedalboardItem *item = pedalboard.GetItem(instanceId);
|
||||||
if (item != nullptr)
|
if (item != nullptr)
|
||||||
{
|
{
|
||||||
|
if (!audioHost) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool changed = this->audioHost->UpdatePluginState(*item);
|
bool changed = this->audioHost->UpdatePluginState(*item);
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
@@ -371,11 +375,8 @@ void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
|||||||
item->stateUpdateCount(item->stateUpdateCount() + 1);
|
item->stateUpdateCount(item->stateUpdateCount() + 1);
|
||||||
|
|
||||||
Lv2PluginState newState = item->lv2State();
|
Lv2PluginState newState = item->lv2State();
|
||||||
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
|
||||||
for (auto &subscriber : t)
|
FireLv2StateChanged(instanceId,newState);
|
||||||
{
|
|
||||||
subscriber->OnLv2StateChanged(instanceId, newState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,6 +510,8 @@ void PiPedalModel::SetPedalboard(int64_t clientId, Pedalboard &pedalboard)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::SetSnapshot(int64_t selectedSnapshot)
|
void PiPedalModel::SetSnapshot(int64_t selectedSnapshot)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||||
@@ -723,12 +726,43 @@ void PiPedalModel::UpdateVst3Settings(Pedalboard &pedalboard)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::FireLv2StateChanged(int64_t instanceId, const Lv2PluginState &lv2State) {
|
||||||
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
|
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
||||||
|
|
||||||
|
for (auto &subscriber : t)
|
||||||
|
{
|
||||||
|
subscriber->OnLv2StateChanged(instanceId,lv2State);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// referesh the plugin state for all plugins.
|
||||||
|
bool PiPedalModel::SyncLv2State()
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
auto pedalboardItems = pedalboard.GetAllPlugins();
|
||||||
|
for (PedalboardItem *item : pedalboardItems)
|
||||||
|
{
|
||||||
|
if (!item->isSplit())
|
||||||
|
{
|
||||||
|
if (audioHost->UpdatePluginState(*item))
|
||||||
|
{
|
||||||
|
FireLv2StateChanged(item->instanceId(),item->lv2State());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
|
||||||
|
}
|
||||||
void PiPedalModel::SaveCurrentPreset(int64_t clientId)
|
void PiPedalModel::SaveCurrentPreset(int64_t clientId)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
|
|
||||||
UpdateVst3Settings(this->pedalboard);
|
UpdateVst3Settings(this->pedalboard);
|
||||||
this->audioHost->UpdatePluginStates(this->pedalboard);
|
SyncLv2State();
|
||||||
|
|
||||||
storage.SaveCurrentPreset(this->pedalboard);
|
storage.SaveCurrentPreset(this->pedalboard);
|
||||||
this->SetPresetChanged(clientId, false);
|
this->SetPresetChanged(clientId, false);
|
||||||
}
|
}
|
||||||
@@ -761,6 +795,7 @@ int64_t PiPedalModel::SaveCurrentPresetAs(int64_t clientId, const std::string &n
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
|
|
||||||
|
SyncLv2State();
|
||||||
auto pedalboard = this->pedalboard;
|
auto pedalboard = this->pedalboard;
|
||||||
UpdateVst3Settings(pedalboard);
|
UpdateVst3Settings(pedalboard);
|
||||||
pedalboard.name(name);
|
pedalboard.name(name);
|
||||||
@@ -880,7 +915,7 @@ void PiPedalModel::OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
if (request.direction < 0)
|
if (request.direction >= 0)
|
||||||
{
|
{
|
||||||
NextPreset();
|
NextPreset();
|
||||||
}
|
}
|
||||||
@@ -900,6 +935,47 @@ void PiPedalModel::OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
SetSnapshot((int64_t)snapshotIndex);
|
||||||
|
} catch (const std::exception&e)
|
||||||
|
{
|
||||||
|
Lv2Log::error(SS("SetSnapshot failed. " << e.what()));
|
||||||
|
}
|
||||||
|
if (this->audioHost)
|
||||||
|
{
|
||||||
|
this->audioHost->AckSnapshotRequest(snapshotRequestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PiPedalModel::OnNotifyNextMidiBank(const RealtimeNextMidiProgramRequest &request)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (request.direction >= 0)
|
||||||
|
{
|
||||||
|
NextBank();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PreviousBank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Lv2Log::error(e.what());
|
||||||
|
}
|
||||||
|
if (this->audioHost)
|
||||||
|
{
|
||||||
|
this->audioHost->AckMidiProgramRequest(request.requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest)
|
void PiPedalModel::OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> guard{mutex};
|
std::lock_guard<std::recursive_mutex> guard{mutex};
|
||||||
@@ -1953,16 +2029,16 @@ void PiPedalModel::OnPatchSetReply(uint64_t instanceId, LV2_URID patchSetPropert
|
|||||||
atom_object atomObject{atomValue};
|
atom_object atomObject{atomValue};
|
||||||
|
|
||||||
PedalboardItem::PropertyMap &properties = item->PatchProperties();
|
PedalboardItem::PropertyMap &properties = item->PatchProperties();
|
||||||
if (properties.contains(propertyUri))
|
if (properties.contains(propertyUri) && properties[propertyUri] == atomObject)
|
||||||
{
|
{
|
||||||
if (properties[propertyUri] == atomObject)
|
// do noting.
|
||||||
{
|
} else {
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
properties[propertyUri] = std::move(atomObject);
|
properties[propertyUri] = std::move(atomObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnNotifyMaybeLv2StateChanged(instanceId);
|
||||||
|
}
|
||||||
|
|
||||||
bool hasAtomJson = false;
|
bool hasAtomJson = false;
|
||||||
std::string atomJson;
|
std::string atomJson;
|
||||||
|
|
||||||
@@ -2509,6 +2585,7 @@ void PiPedalModel::OnNetworkChanged(bool ethernetConnected, bool hotspotConnecte
|
|||||||
FireNetworkChanged();
|
FireNetworkChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PiPedalModel::OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType)
|
void PiPedalModel::OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace pipedal
|
|||||||
class Lv2PluginChangeMonitor;
|
class Lv2PluginChangeMonitor;
|
||||||
class Updater;
|
class Updater;
|
||||||
class AvahiService;
|
class AvahiService;
|
||||||
|
class Lv2PluginState;
|
||||||
|
|
||||||
class IPiPedalModelSubscriber
|
class IPiPedalModelSubscriber
|
||||||
{
|
{
|
||||||
@@ -187,7 +188,7 @@ namespace pipedal
|
|||||||
void FireChannelSelectionChanged(int64_t clientId);
|
void FireChannelSelectionChanged(int64_t clientId);
|
||||||
void FireBanksChanged(int64_t clientId);
|
void FireBanksChanged(int64_t clientId);
|
||||||
void FireJackConfigurationChanged(const JackConfiguration &jackConfiguration);
|
void FireJackConfigurationChanged(const JackConfiguration &jackConfiguration);
|
||||||
|
void FireLv2StateChanged(int64_t instanceId, const Lv2PluginState &lv2State);
|
||||||
void UpdateDefaults(Snapshot *snapshot, std::unordered_map<int64_t, PedalboardItem *> &itemMap);
|
void UpdateDefaults(Snapshot *snapshot, std::unordered_map<int64_t, PedalboardItem *> &itemMap);
|
||||||
void UpdateDefaults(PedalboardItem *pedalboardItem, std::unordered_map<int64_t, PedalboardItem *> &itemMap);
|
void UpdateDefaults(PedalboardItem *pedalboardItem, std::unordered_map<int64_t, PedalboardItem *> &itemMap);
|
||||||
void UpdateDefaults(Pedalboard *pedalboard);
|
void UpdateDefaults(Pedalboard *pedalboard);
|
||||||
@@ -211,7 +212,7 @@ namespace pipedal
|
|||||||
|
|
||||||
IPiPedalModelSubscriber *GetNotificationSubscriber(int64_t clientId);
|
IPiPedalModelSubscriber *GetNotificationSubscriber(int64_t clientId);
|
||||||
std::atomic<bool> closed = false;
|
std::atomic<bool> closed = false;
|
||||||
|
bool SyncLv2State();
|
||||||
private: // IAudioHostCallbacks
|
private: // IAudioHostCallbacks
|
||||||
virtual void OnNotifyLv2StateChanged(uint64_t instanceId) override;
|
virtual void OnNotifyLv2StateChanged(uint64_t instanceId) override;
|
||||||
virtual void OnNotifyMaybeLv2StateChanged(uint64_t instanceId) override;
|
virtual void OnNotifyMaybeLv2StateChanged(uint64_t instanceId) override;
|
||||||
@@ -221,6 +222,7 @@ namespace pipedal
|
|||||||
virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl) override;
|
virtual void OnNotifyMidiListen(bool isNote, uint8_t noteOrControl) override;
|
||||||
virtual void OnPatchSetReply(uint64_t instanceId, LV2_URID patchSetProperty, const LV2_Atom *atomValue) override;
|
virtual void OnPatchSetReply(uint64_t instanceId, LV2_URID patchSetProperty, const LV2_Atom *atomValue) override;
|
||||||
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) override;
|
virtual void OnNotifyMidiRealtimeEvent(RealtimeMidiEventType eventType) override;
|
||||||
|
virtual void OnNotifyMidiRealtimeSnapshotRequest(int32_t snapshotIndex,int64_t snapshotRequestId) override;
|
||||||
|
|
||||||
void OnNotifyPathPatchPropertyReceived(
|
void OnNotifyPathPatchPropertyReceived(
|
||||||
int64_t instanceId,
|
int64_t instanceId,
|
||||||
@@ -229,6 +231,7 @@ namespace pipedal
|
|||||||
|
|
||||||
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest) override;
|
virtual void OnNotifyMidiProgramChange(RealtimeMidiProgramRequest &midiProgramRequest) override;
|
||||||
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request) override;
|
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest &request) override;
|
||||||
|
virtual void OnNotifyNextMidiBank(const RealtimeNextMidiProgramRequest &request) override;
|
||||||
virtual void OnNotifyLv2RealtimeError(int64_t instanceId, const std::string &error) override;
|
virtual void OnNotifyLv2RealtimeError(int64_t instanceId, const std::string &error) override;
|
||||||
|
|
||||||
PostHandle networkChangingDelayHandle = 0;
|
PostHandle networkChangingDelayHandle = 0;
|
||||||
|
|||||||
@@ -23,7 +23,16 @@ namespace pipedal {
|
|||||||
Shutdown,
|
Shutdown,
|
||||||
Reboot,
|
Reboot,
|
||||||
StartHotspot,
|
StartHotspot,
|
||||||
StopHotspot
|
StopHotspot,
|
||||||
|
NextBank,
|
||||||
|
PrevBank,
|
||||||
|
Snapshot1,
|
||||||
|
Snapshot2,
|
||||||
|
Snapshot3,
|
||||||
|
Snapshot4,
|
||||||
|
Snapshot5,
|
||||||
|
Snapshot6,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
+39
-25
@@ -27,8 +27,6 @@
|
|||||||
#include "RealtimeMidiEventType.hpp"
|
#include "RealtimeMidiEventType.hpp"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace pipedal
|
namespace pipedal
|
||||||
{
|
{
|
||||||
class IndexedSnapshot;
|
class IndexedSnapshot;
|
||||||
@@ -65,8 +63,10 @@ namespace pipedal
|
|||||||
|
|
||||||
MidiProgramChange, // program change requested via midi.
|
MidiProgramChange, // program change requested via midi.
|
||||||
AckMidiProgramChange,
|
AckMidiProgramChange,
|
||||||
|
AckMidiSnapshotRequest,
|
||||||
|
|
||||||
NextMidiProgram,
|
NextMidiProgram,
|
||||||
|
NextMidiBank,
|
||||||
|
|
||||||
Lv2StateChanged,
|
Lv2StateChanged,
|
||||||
MaybeLv2StateChanged,
|
MaybeLv2StateChanged,
|
||||||
@@ -75,28 +75,36 @@ namespace pipedal
|
|||||||
Lv2ErrorMessage,
|
Lv2ErrorMessage,
|
||||||
|
|
||||||
RealtimeMidiEvent,
|
RealtimeMidiEvent,
|
||||||
|
RealtimeMidiSnapshotRequest,
|
||||||
|
|
||||||
SendPathPropertyBuffer,
|
SendPathPropertyBuffer,
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RealtimeMidiEventRequest
|
||||||
struct RealtimeMidiEventRequest {
|
{
|
||||||
RealtimeMidiEventType eventType;
|
RealtimeMidiEventType eventType;
|
||||||
};
|
};
|
||||||
struct RealtimeNextMidiProgramRequest {
|
|
||||||
|
struct RealtimeMidiSnapshotRequest
|
||||||
|
{
|
||||||
|
int32_t snapshotIndex;
|
||||||
|
int64_t snapshotRequestId;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RealtimeNextMidiProgramRequest
|
||||||
|
{
|
||||||
int64_t requestId;
|
int64_t requestId;
|
||||||
int32_t direction;
|
int32_t direction;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RealtimeMidiProgramRequest {
|
struct RealtimeMidiProgramRequest
|
||||||
|
{
|
||||||
int64_t requestId;
|
int64_t requestId;
|
||||||
int8_t bank;
|
int8_t bank;
|
||||||
uint8_t program;
|
uint8_t program;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class RealtimeMonitorPortSubscription
|
class RealtimeMonitorPortSubscription
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -169,7 +177,6 @@ namespace pipedal
|
|||||||
float value;
|
float value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class SetControlValueBody
|
class SetControlValueBody
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -215,7 +222,8 @@ namespace pipedal
|
|||||||
void Reset() { ringBuffer->reset(); }
|
void Reset() { ringBuffer->reset(); }
|
||||||
// 0 -> ready. -1: timed out. -2: closing.
|
// 0 -> ready. -1: timed out. -2: closing.
|
||||||
template <class Rep, class Period>
|
template <class Rep, class Period>
|
||||||
RingBufferStatus wait_for(const std::chrono::duration<Rep,Period>& timeout) {
|
RingBufferStatus wait_for(const std::chrono::duration<Rep, Period> &timeout)
|
||||||
|
{
|
||||||
return ringBuffer->readWait_for(timeout);
|
return ringBuffer->readWait_for(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +238,8 @@ namespace pipedal
|
|||||||
return ringBuffer->readWait_until(size, time_point);
|
return ringBuffer->readWait_until(size, time_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait() {
|
bool wait()
|
||||||
|
{
|
||||||
return ringBuffer->readWait();
|
return ringBuffer->readWait();
|
||||||
}
|
}
|
||||||
size_t readSpace() const
|
size_t readSpace() const
|
||||||
@@ -254,7 +263,6 @@ namespace pipedal
|
|||||||
throw PiPedalStateException("Ringbuffer read failed. Did you forget to check for space?");
|
throw PiPedalStateException("Ringbuffer read failed. Did you forget to check for space?");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void readComplete(T *output)
|
void readComplete(T *output)
|
||||||
@@ -264,9 +272,6 @@ namespace pipedal
|
|||||||
throw PiPedalStateException("Ringbuffer read failed. Did you forget to check for space?");
|
throw PiPedalStateException("Ringbuffer read failed. Did you forget to check for space?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -319,7 +324,6 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
Lv2Log::error("No space in audio service ringbuffer.");
|
Lv2Log::error("No space in audio service ringbuffer.");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -333,7 +337,6 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
Lv2Log::error("No space in audio service ringbuffer.");
|
Lv2Log::error("No space in audio service ringbuffer.");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Lv2StateChanged(uint64_t instanceId)
|
void Lv2StateChanged(uint64_t instanceId)
|
||||||
@@ -369,9 +372,11 @@ namespace pipedal
|
|||||||
write(RingBufferCommand::MidiValueChanged, body);
|
write(RingBufferCommand::MidiValueChanged, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnMidiListen(bool isNote, uint8_t noteOrControl) {
|
void OnMidiListen(bool isNote, uint8_t noteOrControl)
|
||||||
|
{
|
||||||
uint16_t msg = noteOrControl;
|
uint16_t msg = noteOrControl;
|
||||||
if (isNote) msg |= 0x100;
|
if (isNote)
|
||||||
|
msg |= 0x100;
|
||||||
write(RingBufferCommand::OnMidiListen, msg);
|
write(RingBufferCommand::OnMidiListen, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +390,6 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
RealtimeMidiProgramRequest msg{requestId : _requestId, bank : _bank, program : _program};
|
RealtimeMidiProgramRequest msg{requestId : _requestId, bank : _bank, program : _program};
|
||||||
|
|
||||||
|
|
||||||
write(RingBufferCommand::MidiProgramChange, msg);
|
write(RingBufferCommand::MidiProgramChange, msg);
|
||||||
}
|
}
|
||||||
void OnRealtimeMidiEvent(RealtimeMidiEventType eventType)
|
void OnRealtimeMidiEvent(RealtimeMidiEventType eventType)
|
||||||
@@ -393,11 +397,23 @@ namespace pipedal
|
|||||||
RealtimeMidiEventRequest msg{eventType};
|
RealtimeMidiEventRequest msg{eventType};
|
||||||
write(RingBufferCommand::RealtimeMidiEvent, msg);
|
write(RingBufferCommand::RealtimeMidiEvent, msg);
|
||||||
}
|
}
|
||||||
|
void OnRealtimeMidiSnapshotRequest(int32_t snapshotIndex, int64_t snapshotRequestId)
|
||||||
|
{
|
||||||
|
RealtimeMidiSnapshotRequest msg{snapshotIndex, snapshotRequestId};
|
||||||
|
|
||||||
|
write(RingBufferCommand::RealtimeMidiSnapshotRequest, msg);
|
||||||
|
}
|
||||||
|
|
||||||
void OnNextMidiProgram(int64_t requestId, int32_t direction)
|
void OnNextMidiProgram(int64_t requestId, int32_t direction)
|
||||||
{
|
{
|
||||||
RealtimeNextMidiProgramRequest msg{requestId : requestId, direction : direction};
|
RealtimeNextMidiProgramRequest msg{requestId : requestId, direction : direction};
|
||||||
write(RingBufferCommand::NextMidiProgram, msg);
|
write(RingBufferCommand::NextMidiProgram, msg);
|
||||||
}
|
}
|
||||||
|
void OnNextMidiBank(int64_t requestId, int32_t direction)
|
||||||
|
{
|
||||||
|
RealtimeNextMidiProgramRequest msg{requestId : requestId, direction : direction};
|
||||||
|
write(RingBufferCommand::NextMidiBank, msg);
|
||||||
|
}
|
||||||
|
|
||||||
void SetControlValue(int effectIndex, int controlIndex, float value)
|
void SetControlValue(int effectIndex, int controlIndex, float value)
|
||||||
{
|
{
|
||||||
@@ -420,7 +436,6 @@ namespace pipedal
|
|||||||
write(RingBufferCommand::SetOutputVolume, body);
|
write(RingBufferCommand::SetOutputVolume, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FreeVuSubscriptions(RealtimeVuBuffers *configuration)
|
void FreeVuSubscriptions(RealtimeVuBuffers *configuration)
|
||||||
{
|
{
|
||||||
write(RingBufferCommand::FreeVuSubscriptions, configuration);
|
write(RingBufferCommand::FreeVuSubscriptions, configuration);
|
||||||
@@ -468,6 +483,9 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
write(RingBufferCommand::AckMidiProgramChange, requestId);
|
write(RingBufferCommand::AckMidiProgramChange, requestId);
|
||||||
}
|
}
|
||||||
|
void AckMidiSnapshotRequest(uint64_t snapshotRequestId) {
|
||||||
|
write(RingBufferCommand::AckMidiSnapshotRequest, snapshotRequestId);
|
||||||
|
}
|
||||||
|
|
||||||
void SetMonitorPortSubscriptions(RealtimeMonitorPortSubscriptions *subscriptions)
|
void SetMonitorPortSubscriptions(RealtimeMonitorPortSubscriptions *subscriptions)
|
||||||
{
|
{
|
||||||
@@ -531,10 +549,6 @@ namespace pipedal
|
|||||||
: RingBufferWriter<false, true>(ringBuffer)
|
: RingBufferWriter<false, true>(ringBuffer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
+1
-1
@@ -295,7 +295,7 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint64_t instanceId;
|
uint64_t instanceId;
|
||||||
virtual bool IsLv2Effect() const override { return true; }
|
virtual bool IsLv2Effect() const override { return false; }
|
||||||
|
|
||||||
virtual uint8_t *GetAtomInputBuffer() { return nullptr; }
|
virtual uint8_t *GetAtomInputBuffer() { return nullptr; }
|
||||||
virtual uint8_t *GetAtomOutputBuffer() { return nullptr; }
|
virtual uint8_t *GetAtomOutputBuffer() { return nullptr; }
|
||||||
|
|||||||
@@ -1418,6 +1418,17 @@ void Storage::SetSystemMidiBindings(const std::vector<MidiBinding> &bindings)
|
|||||||
writer.write(bindings);
|
writer.write(bindings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static bool hasBinding(std::vector<MidiBinding> &bindings, const std::string&name)
|
||||||
|
{
|
||||||
|
for (auto&binding: bindings)
|
||||||
|
{
|
||||||
|
if (binding.symbol() == name)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||||
{
|
{
|
||||||
std::vector<MidiBinding> result;
|
std::vector<MidiBinding> result;
|
||||||
@@ -1441,6 +1452,20 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
|||||||
result.push_back(MidiBinding::SystemBinding("shutdown"));
|
result.push_back(MidiBinding::SystemBinding("shutdown"));
|
||||||
result.push_back(MidiBinding::SystemBinding("reboot"));
|
result.push_back(MidiBinding::SystemBinding("reboot"));
|
||||||
}
|
}
|
||||||
|
if (!hasBinding(result,"prevBank"))
|
||||||
|
{
|
||||||
|
result.insert(result.begin(),MidiBinding::SystemBinding("nextBank")); // reverse order.
|
||||||
|
result.insert(result.begin(),MidiBinding::SystemBinding("prevBank"));
|
||||||
|
}
|
||||||
|
if (!hasBinding(result,"snapshot1"))
|
||||||
|
{
|
||||||
|
auto position = 4;
|
||||||
|
for (int i = 0; i < 6; ++i)
|
||||||
|
{
|
||||||
|
result.insert(result.begin()+position,MidiBinding::SystemBinding(SS("snapshot" << (i+1))));
|
||||||
|
++position;
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (const std::exception&e)
|
catch (const std::exception&e)
|
||||||
@@ -1449,8 +1474,18 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.clear();
|
result.clear();
|
||||||
|
result.push_back(MidiBinding::SystemBinding("prevBank"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("nextBank"));
|
||||||
result.push_back(MidiBinding::SystemBinding("prevProgram"));
|
result.push_back(MidiBinding::SystemBinding("prevProgram"));
|
||||||
result.push_back(MidiBinding::SystemBinding("nextProgram"));
|
result.push_back(MidiBinding::SystemBinding("nextProgram"));
|
||||||
|
|
||||||
|
result.push_back(MidiBinding::SystemBinding("snapshot1"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("snapshot2"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("snapshot3"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("snapshot4"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("snapshot5"));
|
||||||
|
result.push_back(MidiBinding::SystemBinding("snapshot6"));
|
||||||
|
|
||||||
result.push_back(MidiBinding::SystemBinding("stopHotspot"));
|
result.push_back(MidiBinding::SystemBinding("stopHotspot"));
|
||||||
result.push_back(MidiBinding::SystemBinding("startHotspot"));
|
result.push_back(MidiBinding::SystemBinding("startHotspot"));
|
||||||
result.push_back(MidiBinding::SystemBinding("shutdown"));
|
result.push_back(MidiBinding::SystemBinding("shutdown"));
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ class Copyrights {
|
|||||||
static std::string trim(const std::string&value)
|
static std::string trim(const std::string&value)
|
||||||
{
|
{
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
while (start < value.length() && value[start] == ' ' || value[start] == '\t')
|
while (start < value.length() && (value[start] == ' ' || value[start] == '\t'))
|
||||||
{
|
{
|
||||||
++start;
|
++start;
|
||||||
}
|
}
|
||||||
size_t end = value.length();
|
size_t end = value.length();
|
||||||
while (end > start && value[end-1] == ' ' || value[end-1] == '\t')
|
while (end > start && (value[end-1] == ' ' || value[end-1] == '\t'))
|
||||||
{
|
{
|
||||||
--end;
|
--end;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
ToobFreeverb has a big memory leak!
|
|
||||||
|
|
||||||
Review state changing code. Do we need this anymmore? I think not. It is a bit sus.
|
|
||||||
|
|
||||||
|
|
||||||
Review current handleNotifyPatchProperty. I tink server-side support needs to be
|
Review current handleNotifyPatchProperty. I tink server-side support needs to be
|
||||||
removed, and rely on handleNotifyPathPatchPropertyChanged instead.
|
removed, and rely on handleNotifyPathPatchPropertyChanged instead.
|
||||||
@@ -10,26 +6,18 @@ removed, and rely on handleNotifyPathPatchPropertyChanged instead.
|
|||||||
|
|
||||||
Midi bindings.
|
Midi bindings.
|
||||||
|
|
||||||
SEGV at void PiPedalModel::OnNotifyMaybeLv2StateChanged(uint64_t instanceId)
|
|
||||||
bool changed = this->audioHost->UpdatePluginState(*item);
|
|
||||||
PiPedalModel.cpp:375
|
|
||||||
|
|
||||||
because audioHost is gone.
|
|
||||||
revamp shutdown procedure for the audio thread.
|
revamp shutdown procedure for the audio thread.
|
||||||
write a marker on exit, and don't release
|
write a marker on exit, and don't release
|
||||||
audioHost UNTIL the service thread has read the close marker.
|
audioHost UNTIL the service thread has read the close marker.
|
||||||
|
|
||||||
- continuing corrupt memory.
|
|
||||||
|
|
||||||
|
|
||||||
- verify that scanning doesn't cause overruns.
|
|
||||||
- verify address change behaviour in client
|
|
||||||
-verify clean removal of dhcpcd and nm_p2p2d
|
-verify clean removal of dhcpcd and nm_p2p2d
|
||||||
|
|
||||||
X Review docs changes once we go live.
|
X Review docs changes once we go live.
|
||||||
|
|
||||||
- Localisation: support non-UTF8 code pages.
|
- Localisation: support non-UTF8 code pages.
|
||||||
- unicode commandline arguments.
|
- unicode commandline arguments. (probably the hotspot name)
|
||||||
- review unicode filenames (this is probably ok)
|
- review unicode filenames (this is probably ok)
|
||||||
|
|
||||||
- BUG: gcs when we have an animated output control
|
- BUG: gcs when we have an animated output control
|
||||||
|
|||||||
Reference in New Issue
Block a user