Merge pull request #215 from rerdavies/dev

v1.3.55
This commit is contained in:
Robin Davies
2024-10-11 12:20:04 +01:00
committed by GitHub
19 changed files with 371 additions and 248 deletions
+2 -2
View File
@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.16.0) cmake_minimum_required(VERSION 3.16.0)
project(pipedal project(pipedal
VERSION 1.3.54 VERSION 1.3.55
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
HOMEPAGE_URL "https://rerdavies.github.io/pipedal" HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
) )
set (DISPLAY_VERSION "PiPedal v1.3.54-Release") set (DISPLAY_VERSION "PiPedal v1.3.55-Release")
set (PACKAGE_ARCHITECTURE "arm64") set (PACKAGE_ARCHITECTURE "arm64")
set (CMAKE_INSTALL_PREFIX "/usr/") set (CMAKE_INSTALL_PREFIX "/usr/")
+1 -1
View File
@@ -20,7 +20,7 @@ static int ToOsSignalType(SignalHandler::SignalType signalType)
case SignalHandler::Hangup: result = SIGHUP; break; case SignalHandler::Hangup: result = SIGHUP; break;
default: default:
throw std::runtime_error("INvalid signal type"); throw std::runtime_error("Invalid signal type");
} }
return result; return result;
} }
+2 -2
View File
@@ -6,13 +6,13 @@
<a href="https://rerdavies.github.io/pipedal/LicensePiPedal.html"><img src="https://img.shields.io/badge/MIT-MIT?label=license&color=%23808080"/></a> <a href="https://rerdavies.github.io/pipedal/LicensePiPedal.html"><img src="https://img.shields.io/badge/MIT-MIT?label=license&color=%23808080"/></a>
<a href="https://github.com/rerdavies/pipedal/actions"><img src="https://img.shields.io/github/actions/workflow/status/rerdavies/pipedal/cmake.yml?branch=main"/></a> <a href="https://github.com/rerdavies/pipedal/actions"><img src="https://img.shields.io/github/actions/workflow/status/rerdavies/pipedal/cmake.yml?branch=main"/></a>
Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v1.3.54</a> Download:&nbsp;<a href='https://rerdavies.github.io/pipedal/download.html'>v1.3.55</a>
Website:&nbsp;[https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Website:&nbsp;[https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
Documentation:&nbsp;[https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html). Documentation:&nbsp;[https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).
&nbsp; &nbsp;
#### NEW version 1.3.54 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. #### NEW version 1.3.55 Release, providing [snapshots](https://rerdavies.github.io/pipedal/Snaphots.html), and a new Performance View. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
&nbsp; &nbsp;
+3 -3
View File
@@ -13,17 +13,17 @@ page_icon: img/Install4.jpg
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- [Raspberry Pi OS bookworm (64-bit) v1.3.54](https://github.com/rerdavies/pipedal/releases/download/) - [Raspberry Pi OS bookworm (64-bit) v1.3.55](https://github.com/rerdavies/pipedal/releases/download/)
- [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) - [Ubuntu/Raspberry Pi OS bullseyeye (64-bit) v1.2.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb)
Version 1.3.54 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31. Version 1.3.55 has not yet been tested on Ubuntu or Raspberry Pi OS bullseye. On these platforms, we recommend that you use version 1.1.31.
Install the package by running Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install pipedal_1.3.54_arm64.deb sudo apt-get install pipedal_1.3.55_arm64.deb
``` ```
Adjust accordingly if you have downloaded v1.1.31. Adjust accordingly if you have downloaded v1.1.31.
+11 -1
View File
@@ -1,4 +1,14 @@
# Release Notes # Release Notes
## PiPedal 1.3.55 Release
More snapshot problems.
Bug fixes:
- Crashes related to snapshots and split controls.
- Loading/reloading/error screens go on top of Snapshot dialogs.
## PiPedal 1.3.54 Release ## PiPedal 1.3.54 Release
Improvements to and fixes for hotspot functionality. Fixes for problems with snapshots. Improvements to and fixes for hotspot functionality. Fixes for problems with snapshots.
@@ -8,7 +18,7 @@ Minor features;
- Uploaded .zip files create a top-level directory with the name of the zip file if the zip file doesn't contain a single root-level directory. (released in 1.3.53) - Uploaded .zip files create a top-level directory with the name of the zip file if the zip file doesn't contain a single root-level directory. (released in 1.3.53)
Bug fixes. Bug fixes:
- Various crashes related to snapshots. - Various crashes related to snapshots.
- Applying changes to Wi-Fi hotspot configuration would not change the configuration until PiPedal was rebooted (a regression). - Applying changes to Wi-Fi hotspot configuration would not change the configuration until PiPedal was rebooted (a regression).
+2 -2
View File
@@ -4,7 +4,7 @@
Download the most recent Debian (.deb) package for your platform: Download the most recent Debian (.deb) package for your platform:
- <a href="https://github.com/rerdavies/pipedal/releases/download/v1.3.54/pipedal_1.3.54_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.3.54</a> - <a href="https://github.com/rerdavies/pipedal/releases/download/v1.3.55/pipedal_1.3.55_arm64.deb">Raspberry Pi OS Bookworm (64-bit) v1.3.55</a>
Install the package by running Install the package by running
@@ -12,7 +12,7 @@ Install the package by running
``` ```
sudo apt update sudo apt update
cd ~/Downloads cd ~/Downloads
sudo apt-get install ./pipedal_1.3.54_arm64.deb sudo apt-get install ./pipedal_1.3.55_arm64.deb
``` ```
Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation. Follow the instructions in [_Configuring PiPedal After Installation_](https://rerdavies.github.io/pipedal/Configuring.html) to complete the installation.
+2 -2
View File
@@ -1,7 +1,7 @@
<img src="GithubBanner.png" width="100%"/> <img src="GithubBanner.png" width="100%"/>
<a href="Installing.html"><i>v1.3.54</i></a> <a href="Installing.html"><i>v1.3.55</i></a>
&nbsp; &nbsp;
@@ -9,7 +9,7 @@ To download PiPedal, click [here](download.md).
To view PiPedal documentation, click [here](Documentation.md). To view PiPedal documentation, click [here](Documentation.md).
#### NEW version 1.3.54 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. #### NEW version 1.3.55 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details.
&nbsp; &nbsp;
+136 -123
View File
@@ -17,12 +17,12 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { SyntheticEvent } from 'react';
import { WithStyles } from '@mui/styles'; import { WithStyles } from '@mui/styles';
import './AppThemed.css'; import './AppThemed.css';
//import {alpha} from '@mui/material/styles';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Modal from '@mui/material/Modal';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import CssBaseline from '@mui/material/CssBaseline'; import CssBaseline from '@mui/material/CssBaseline';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
@@ -36,7 +36,9 @@ import FullscreenIcon from '@mui/icons-material/Fullscreen';
import FullscreenExitIcon from '@mui/icons-material/FullscreenExit'; import FullscreenExitIcon from '@mui/icons-material/FullscreenExit';
import List from '@mui/material/List'; import List from '@mui/material/List';
import Divider from '@mui/material/Divider'; import Divider from '@mui/material/Divider';
import ListItem from '@mui/material/ListItem'; // import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText'; import ListItemText from '@mui/material/ListItemText';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
@@ -92,6 +94,17 @@ const appStyles = (theme: Theme) => createStyles({
listSubheader: { listSubheader: {
backgroundImage: "linear-gradient(255,255,255,0.15),rgba(255,255,255,0.15)" backgroundImage: "linear-gradient(255,255,255,0.15),rgba(255,255,255,0.15)"
}, },
loadingMask: {
position: "absolute",
minHeight: "10em",
left: "0px",
top: "0px",
right: "0px",
bottom: "0px",
opacity: 0.8,
background:
isDarkMode() ? "#222" : "#DDD",
},
loadingContent: { loadingContent: {
display: "block", display: "block",
position: "absolute", position: "absolute",
@@ -100,7 +113,6 @@ const appStyles = (theme: Theme) => createStyles({
top: "0px", top: "0px",
width: "100%", width: "100%",
height: "100%", height: "100%",
background: isDarkMode() ? "#222" : "#DDD",
opacity: "0.95", opacity: "0.95",
justifyContent: "center", justifyContent: "center",
textAlign: "center", textAlign: "center",
@@ -166,22 +178,22 @@ const appStyles = (theme: Theme) => createStyles({
}, },
loadingBox: { loadingBox: {
position: "relative", display: "flex",
flexFlow: "column nowrap",
position: "absolute",
top: "20%", top: "20%",
left: 0, right: 0,
color: isDarkMode() ? theme.palette.text.secondary : "#888", color: isDarkMode() ? theme.palette.text.secondary : "#888",
// border: "3px solid #888", // border: "3px solid #888",
borderRadius: "12px", alignItems: "center",
padding: "12px",
justifyContent: "center",
textAlign: "center", textAlign: "center",
opacity: 0.8, opacity: 0.8,
zIndex: 2010
}, },
loadingBoxItem: { loadingBoxItem: {
justifyContent: "center", display: "flex", flexFlow: "row nowrap",
alignItems: "center",
textAlign: "center", textAlign: "center",
zIndex: 2010
}, },
@@ -247,9 +259,8 @@ function setFullScreen(value: boolean) {
if (docEl.requestFullscren) // the latest offical api. if (docEl.requestFullscren) // the latest offical api.
{ {
if (value) if (value) {
{ window.document.documentElement.requestFullscreen({ navigationUI: "show" });
window.document.documentElement.requestFullscreen({navigationUI: "show"});
} else { } else {
window.document.exitFullscreen(); window.document.exitFullscreen();
} }
@@ -267,10 +278,10 @@ function setFullScreen(value: boolean) {
} }
function preventDefault(e: SyntheticEvent): void { // function preventDefault(e: SyntheticEvent): void {
e.stopPropagation(); // e.stopPropagation();
e.preventDefault(); // e.preventDefault();
} // }
type AppState = { type AppState = {
zoomedControlInfo: ZoomedControlInfo | undefined; zoomedControlInfo: ZoomedControlInfo | undefined;
@@ -403,7 +414,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
return false; return false;
} }
onOpenBank(bankId: number) { handleSpecificBank(bankId: number) {
this.model_.openBank(bankId) this.model_.openBank(bankId)
.catch((error) => this.model_.showAlert(error.toString())); .catch((error) => this.model_.showAlert(error.toString()));
@@ -491,17 +503,15 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
} }
handleDrawerSelectBank() { handleDrawerSelectBank() {
this.setState({ this.setState({
isDrawerOpen: false,
bankDialogOpen: true, bankDialogOpen: true,
editBankDialogOpen: false editBankDialogOpen: false
}); });
} }
handleDrawerDonationClick() { handleDrawerDonationClick() {
this.setState({ this.hideDrawer(false);
isDrawerOpen: false,
});
if (this.model_.isAndroidHosted()) { if (this.model_.isAndroidHosted()) {
this.model_.showAndroidDonationActivity(); this.model_.showAndroidDonationActivity();
} else { } else {
@@ -514,14 +524,12 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
handleDrawerAboutClick() { handleDrawerAboutClick() {
this.setState({ this.setState({
isDrawerOpen: false,
aboutDialogOpen: true aboutDialogOpen: true
}); });
} }
handleDrawerRenameBank() { handleDrawerRenameBank() {
this.setState({ this.setState({
isDrawerOpen: false,
renameBankDialogOpen: true, renameBankDialogOpen: true,
saveBankAsDialogOpen: false saveBankAsDialogOpen: false
}); });
@@ -529,7 +537,6 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
} }
handleDrawerSaveBankAs() { handleDrawerSaveBankAs() {
this.setState({ this.setState({
isDrawerOpen: false,
renameBankDialogOpen: false, renameBankDialogOpen: false,
saveBankAsDialogOpen: true saveBankAsDialogOpen: true
}); });
@@ -657,6 +664,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
let bankEntries = Math.floor((height - K) / ENTRY_HEIGHT); let bankEntries = Math.floor((height - K) / ENTRY_HEIGHT);
if (bankEntries < 1) bankEntries = 1; if (bankEntries < 1) bankEntries = 1;
if (bankEntries > 7) bankEntries = 7; if (bankEntries > 7) bankEntries = 7;
if (bankEntries === 2) bankEntries = 1;
this.setState({ bankDisplayItems: bankEntries }); this.setState({ bankDisplayItems: bankEntries });
} }
@@ -686,27 +695,33 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
} }
shortBankList(banks: BankIndex): BankIndexEntry[] { shortBankList(banks: BankIndex): BankIndexEntry[] {
let n = this.state.bankDisplayItems; let nDisplayEntries = this.state.bankDisplayItems;
let entries = banks.entries; let entries = banks.entries;
if (entries.length < n + 1) { // +1 for the .... entry. let nListEntries = entries.length;
return entries;
}
let result: BankIndexEntry[] = []; let result: BankIndexEntry[] = [];
let selectedIndex = -1;
for (let i = 0; i < entries.length; ++i) { if (nListEntries <= nDisplayEntries) {
if (entries[i].instanceId === banks.selectedBank) { for (let i = 0; i < nListEntries; ++i) {
selectedIndex = i;
break;
}
}
if (n > entries.length) n = entries.length;
if (selectedIndex > n) {
for (let i = 0; i < n - 1; ++i) {
result.push(entries[i]); result.push(entries[i]);
} }
result.push(entries[selectedIndex]);
} else { } else {
for (let i = 0; i < n; ++i) { // a subset of the list CENTERED on the currently selected entry.
let selectedIndex = 0;
for (let i = 0; i < nListEntries; ++i) {
if (entries[i].instanceId === banks.selectedBank) {
selectedIndex = i;
break;
}
}
let minN = selectedIndex - Math.floor(nDisplayEntries / 2);
if (minN < 0) minN = 0;
let maxN = minN + nDisplayEntries;
if (maxN > entries.length) {
maxN = entries.length;
}
for (let i = minN; i < maxN; ++i) {
result.push(entries[i]); result.push(entries[i]);
} }
} }
@@ -747,7 +762,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<div style={{ <div style={{
colorScheme: isDarkMode() ? "dark" : "light", // affects scrollbar color colorScheme: isDarkMode() ? "dark" : "light", // affects scrollbar color
minHeight: 300, minWidth: 300, minHeight: 300, minWidth: 300,
position: "absolute", left:0, top: 0, right:0,bottom:0, position: "absolute", left: 0, top: 0, right: 0, bottom: 0,
overscrollBehavior: this.state.isDebug ? "auto" : "none" overscrollBehavior: this.state.isDebug ? "auto" : "none"
}} }}
onContextMenu={(e) => { onContextMenu={(e) => {
@@ -831,11 +846,11 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</div> </div>
)} )}
<TemporaryDrawer position='left' title="PiPedal" <TemporaryDrawer position='left' title="PiPedal"
is_open={this.state.isDrawerOpen} onClose={() => { this.hideDrawer(); }} > is_open={this.state.isDrawerOpen} onClose={() => { this.hideDrawer(false); }} >
<List> <List>
<ListItem button key='PerformanceView' <ListItemButton key='PerformanceView'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.setState({ performanceView: true }); this.setState({ performanceView: true });
@@ -844,7 +859,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<FxAmplifierIcon color='inherit' className={classes.menuIcon} style={{ width: 24, height: 24 }} /> <FxAmplifierIcon color='inherit' className={classes.menuIcon} style={{ width: 24, height: 24 }} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Performance View' /> <ListItemText primary='Performance View' />
</ListItem> </ListItemButton>
</List> </List>
<Divider /> <Divider />
<ListSubheader className="listSubheader" component="div" id="xnested-list-subheader" style={{ lineHeight: "24px", height: 24, background: "rgba(12,12,12,0.0)" }} <ListSubheader className="listSubheader" component="div" id="xnested-list-subheader" style={{ lineHeight: "24px", height: 24, background: "rgba(12,12,12,0.0)" }}
@@ -856,20 +871,24 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
{ {
shortBankList.map((bank) => { shortBankList.map((bank) => {
return ( return (
<ListItem button key={'bank' + bank.instanceId} selected={bank.instanceId === this.state.banks.selectedBank} <ListItemButton key={'bank' + bank.instanceId} selected={bank.instanceId === this.state.banks.selectedBank}
onClick={() => this.onOpenBank(bank.instanceId)} onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(false);
this.handleSpecificBank(bank.instanceId);
}}
> >
<ListItemText primary={bank.name} /> <ListItemText primary={bank.name} />
</ListItem> </ListItemButton>
); );
}) })
} }
{ {
showBankSelectDialog && ( showBankSelectDialog && (
<ListItem button key={'bankDOTDOTDOT'} selected={false} <ListItemButton key={'bankDOTDOTDOT'} selected={false}
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.handleDrawerSelectBank(); this.handleDrawerSelectBank();
@@ -877,7 +896,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
> >
<ListItemText primary={"..."} /> <ListItemText primary={"..."} />
</ListItem> </ListItemButton>
) )
@@ -885,8 +904,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</List> </List>
<Divider /> <Divider />
<List> <List>
<ListItem button key='RenameBank' <ListItemButton key='RenameBank'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.handleDrawerRenameBank() this.handleDrawerRenameBank()
@@ -895,9 +914,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<RenameOutlineIcon color='inherit' className={classes.menuIcon} /> <RenameOutlineIcon color='inherit' className={classes.menuIcon} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Rename bank' /> <ListItemText primary='Rename bank' />
</ListItem> </ListItemButton>
<ListItem button key='SaveBank' <ListItemButton key='SaveBank'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.handleDrawerSaveBankAs(); this.handleDrawerSaveBankAs();
@@ -906,9 +925,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<SaveBankAsIcon color="inherit" className={classes.menuIcon} /> <SaveBankAsIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Save as new bank' /> <ListItemText primary='Save as new bank' />
</ListItem> </ListItemButton>
<ListItem button key='EditBanks' <ListItemButton key='EditBanks'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.handleDrawerManageBanks(); this.handleDrawerManageBanks();
@@ -917,12 +936,12 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<EditBanksIcon color="inherit" className={classes.menuIcon} /> <EditBanksIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Manage banks...' /> <ListItemText primary='Manage banks...' />
</ListItem> </ListItemButton>
</List> </List>
<Divider /> <Divider />
<List> <List>
<ListItem button key='Settings' <ListItemButton key='Settings'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.handleDrawerSettingsClick() this.handleDrawerSettingsClick()
@@ -931,9 +950,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<SettingsIcon color="inherit" className={classes.menuIcon} /> <SettingsIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Settings' /> <ListItemText primary='Settings' />
</ListItem> </ListItemButton>
<ListItem button key='About' <ListItemButton key='About'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true); this.hideDrawer(true);
this.handleDrawerAboutClick(); this.handleDrawerAboutClick();
@@ -942,18 +961,17 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<HelpOutlineIcon color="inherit" className={classes.menuIcon} /> <HelpOutlineIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='About' /> <ListItemText primary='About' />
</ListItem> </ListItemButton>
<ListItem button key='Donations' <ListItemButton key='Donations'
onClick={(ev) => { onClick={(ev: any) => {
ev.stopPropagation(); ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerDonationClick(); this.handleDrawerDonationClick();
}}> }}>
<ListItemIcon > <ListItemIcon >
<VolunteerActivismIcon className={classes.menuIcon} color="inherit" /> <VolunteerActivismIcon className={classes.menuIcon} color="inherit" />
</ListItemIcon> </ListItemIcon>
<ListItemText primary='Donations' /> <ListItemText primary='Donations' />
</ListItem> </ListItemButton>
</List> </List>
</TemporaryDrawer> </TemporaryDrawer>
@@ -1040,67 +1058,62 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</DialogEx> </DialogEx>
<div className={classes.errorContent} style={{ zIndex: 1200, display: this.state.displayState === State.Error ? "flex" : "none" }} <Modal open={this.state.displayState === State.Error}
onMouseDown={preventDefault} onKeyDown={preventDefault} aria-label="fatal-error"
aria-describedby="aria-error-text"
> >
<div className={classes.errorContentMask} /> <div style={{
<div style={{ flex: "2 2 3px", height: 20 }} >&nbsp;</div> display: "flex", flexFlow: "column nowrap",
<div className={classes.errorMessageBox} style={{ position: "relative" }} > position: "absolute", top: 0, left: 0, right: 0, bottom: 0
<div style={{ fontSize: "30px", position: "absolute", left: 0, top: 3, color: "#A00" }}> }}
<ErrorOutlineIcon color="inherit" fontSize="inherit" style={{ float: "left", marginRight: "12px" }} /> >
</div> <div className={classes.loadingMask} />
<div style={{ marginLeft: 40, marginTop: 3 }}> <div style={{ flex: "2 2 3px", height: 20 }} >&nbsp;</div>
<p className={classes.errorText}> <div className={classes.errorMessageBox} style={{ position: "relative" }} >
Error: {this.state.errorMessage} <div style={{ fontSize: "30px", position: "absolute", left: 0, top: 3, color: "#A00" }}>
</p> <ErrorOutlineIcon color="inherit" fontSize="inherit" style={{ float: "left", marginRight: "12px" }} />
</div> </div>
<div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}> <div style={{ marginLeft: 40, marginTop: 3 }}>
<Button variant='contained' color="primary" <p className={classes.errorText} id="aria-error-text">
onClick={() => this.handleReload()} > Error: {this.state.errorMessage}
Reload </p>
</Button> </div>
<div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}>
<Button variant='contained' color="primary"
onClick={() => this.handleReload()} >
Reload
</Button>
</div>
</div> </div>
<div style={{ flex: "5 5 auto", height: 20 }} >&nbsp;</div>
</div> </div>
<div style={{ flex: "5 5 auto", height: 20 }} >&nbsp;</div> </Modal >
</div>
{/* initial load mask*/}
<div className={classes.errorContent} style={{ display: this.state.displayState === State.Loading ? "block" : "none",zIndex: 1201 }}>
<div className={classes.errorContentMask} />
<div className={classes.loadingBox}>
<div className={classes.loadingBoxItem}>
<CircularProgress color="inherit" className={classes.loadingBoxItem} />
</div>
<Typography noWrap variant="body2" className={classes.loadingBoxItem}>
Loading...
</Typography>
</div>
</div>
{/* Reloading mask */} {/* Reloading mask */}
<div className={classes.errorContent} style={{ < Modal
zIndex: 1201, open={wantsReloadingScreen(this.state.displayState) || this.state.displayState === State.Loading}
display: ( aria-label="loading"
wantsReloadingScreen(this.state.displayState) aria-describedby="reloading-modal-description"
? "block" : "none"
)
}}
> >
<div className={classes.errorContentMask} /> <div style={{display: "flex",flexFlow: "column nowrap", alignItems: "center"}}>
<div className={classes.loadingMask} />
<div className={classes.loadingBox}> <div className={classes.loadingBox}>
<div className={classes.loadingBoxItem}> <div className={classes.loadingBoxItem}>
<CircularProgress color="inherit" className={classes.loadingBoxItem} /> <CircularProgress color="inherit" className={classes.loadingBoxItem} />
</div>
<Typography id="reloading-modal-description" display="block" noWrap variant="body2" className={classes.progressText}>
{
this.state.displayState === State.Loading ?
"Loading..."
:this.getReloadingMessage()
}
</Typography>
</div> </div>
<Typography display="block" noWrap variant="body2" className={classes.progressText}>
{this.getReloadingMessage()}
</Typography>
</div> </div>
</div> </Modal >
</div > </div >
); );
} }
}); });
+1
View File
@@ -206,6 +206,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
export class SnapshotValue { export class SnapshotValue {
deserialize(input: any): SnapshotValue { deserialize(input: any): SnapshotValue {
this.isEnabled = input.isEnabled;
this.instanceId = input.instanceId; this.instanceId = input.instanceId;
this.controlValues = ControlValue.deserializeArray(input.controlValues); this.controlValues = ControlValue.deserializeArray(input.controlValues);
this.lv2State = input.lv2state; this.lv2State = input.lv2state;
+5 -1
View File
@@ -135,7 +135,7 @@ namespace pipedal
{ {
auto maxInputControl = effect->GetMaxInputControl(); auto maxInputControl = effect->GetMaxInputControl();
inputControlValues.resize(maxInputControl); inputControlValues.resize(maxInputControl);
this->enabled = true;
for (uint64_t i = 0; i < maxInputControl; ++i) for (uint64_t i = 0; i < maxInputControl; ++i)
{ {
bool isInputControl = effect->IsInputControl(i); bool isInputControl = effect->IsInputControl(i);
@@ -150,6 +150,7 @@ namespace pipedal
} }
if (snapshotValue) if (snapshotValue)
{ {
this->enabled = snapshotValue->isEnabled_;
for (auto &controlValue : snapshotValue->controlValues_) for (auto &controlValue : snapshotValue->controlValues_)
{ {
auto index = effect->GetControlIndex(controlValue.key()); auto index = effect->GetControlIndex(controlValue.key());
@@ -202,6 +203,8 @@ namespace pipedal
} }
void ApplyValues(IEffect *effect) void ApplyValues(IEffect *effect)
{ {
effect->SetBypass(this->enabled);
if (effect != pEffect) if (effect != pEffect)
{ {
throw std::runtime_error("Wrong effect"); throw std::runtime_error("Wrong effect");
@@ -226,6 +229,7 @@ namespace pipedal
private: private:
IEffect *pEffect; IEffect *pEffect;
Lv2PluginState lv2State; Lv2PluginState lv2State;
bool enabled;
std::vector<InputControlEntry> inputControlValues; std::vector<InputControlEntry> inputControlValues;
std::vector<PathPatchProperty> pathPatchProperties; std::vector<PathPatchProperty> pathPatchProperties;
}; };
+4 -2
View File
@@ -482,8 +482,8 @@ void AvahiService::Wait()
{ {
default: default:
case ServiceState::Unitialized: case ServiceState::Unitialized:
throw std::runtime_error("Invalid state"); done = true;
break;
case ServiceState::Initializing: case ServiceState::Initializing:
case ServiceState::Settling: case ServiceState::Settling:
case ServiceState::Requested: case ServiceState::Requested:
@@ -503,6 +503,8 @@ void AvahiService::Wait()
if (clock::now() > waitTime) if (clock::now() > waitTime)
{ {
Lv2Log::error("DNS/SD announcement timed out."); Lv2Log::error("DNS/SD announcement timed out.");
done = true;
break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(20)); std::this_thread::sleep_for(std::chrono::milliseconds(20));
+71 -59
View File
@@ -155,6 +155,49 @@ void DisableService()
#endif #endif
} }
bool disableAvahiConfigLine(SystemConfigFile &avahi, const std::string &section, const std::string &lineStart)
{
bool changed = false;
// use-ipv6=no
int line = avahi.GetLineThatStartsWith(lineStart + "yes");
if (line != -1)
{
avahi.UndoableReplaceLine(line, lineStart + "no");
changed = true;
}
else
{
if (avahi.GetLineThatStartsWith(lineStart + "no") == -1)
{
line = avahi.GetLineThatStartsWith(section);
if (line == -1)
{
throw std::runtime_error("Unable to find [server] section.");
}
{
++line;
// increment to end of section.
while (line < avahi.GetLineCount())
{
const auto &txt = avahi.Get(line);
if (txt.empty())
{
break;
}
if (txt.starts_with("[")) // start of next section.
{
break;
}
++line;
}
}
avahi.UndoableAddLine(line,lineStart+"no");
changed = true;
}
}
return changed;
}
static void RestartAvahiService() static void RestartAvahiService()
{ {
silentSysExec(SS(SYSTEMCTL_BIN << " restart avahi-daemon.service").c_str()); silentSysExec(SS(SYSTEMCTL_BIN << " restart avahi-daemon.service").c_str());
@@ -169,41 +212,10 @@ static void AvahiInstall()
SystemConfigFile avahi(avahiConfig); SystemConfigFile avahi(avahiConfig);
bool changed = avahi.RemoveUndoableActions(); bool changed = avahi.RemoveUndoableActions();
int line = avahi.GetLineThatStartsWith("use-ipv6=yes");
if (line != -1) changed |= disableAvahiConfigLine(avahi, "[server]", "use-ipv6=");
{ changed |= disableAvahiConfigLine(avahi, "[publish]", "publish-aaaa-on-ipv4=");
avahi.UndoableReplaceLine(line, "use-ipv6=no");
changed = true;
}
else
{
if (avahi.GetLineThatStartsWith("use-ipv6=no") == -1)
{
line = avahi.GetLineThatStartsWith("[server]");
if (line == 1)
{
throw std::runtime_error("Unable to find [server] section.");
}
{
// increment to end of section.
while (line < avahi.GetLineCount())
{
const auto &txt = avahi.Get(line);
if (txt.empty())
{
break;
}
if (txt.starts_with("[")) // start of next section.
{
break;
}
++line;
}
}
avahi.UndoableAddLine(avahi.GetLineCount(), "use-ipv6=no");
changed = true;
}
}
if (changed) if (changed)
{ {
avahi.Save(); avahi.Save();
@@ -914,7 +926,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
try try
{ {
// apply policy changes we dropped into the polkit configuration files (allows pipedal_d to use NetworkManager dbus apis). // apply policy changes we dropped into the polkit configuration files (allows pipedal_d to use NetworkManager dbus apis).
silentSysExec(SYSTEMCTL_BIN " restart polkit"); silentSysExec(SYSTEMCTL_BIN " restart polkit");
DeployVarConfig(); DeployVarConfig();
@@ -995,7 +1007,6 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
// add to netdev group // add to netdev group
sysExec(USERMOD_BIN " -a -G " NETDEV_GROUP_NAME " " SERVICE_ACCOUNT_NAME); sysExec(USERMOD_BIN " -a -G " NETDEV_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// create and configure /var directory. // create and configure /var directory.
fs::path varDirectory("/var/pipedal"); fs::path varDirectory("/var/pipedal");
@@ -1211,11 +1222,11 @@ static void PrintHelp()
<< "\n\n" << "\n\n"
<< "One of the following hotspot options can be specifed. If no hotspot option is given, the hotspot will always be enabled. " << "One of the following hotspot options can be specifed. If no hotspot option is given, the hotspot will always be enabled. "
<< "If one of the hotspot options are given, the PiPedal server will turn the hotspot on or off automatically, as conditions change." << "If one of the hotspot options are given, the PiPedal server will turn the hotspot on or off automatically, as conditions change."
<< "\n\n" << "\n\n"
<< "--home-network <wifi-ssid>\n" << "--home-network <wifi-ssid>\n"
<< AddIndent(4) << "Hotspot is disabled if the specificed Wi-Fi network is detected.\n" << AddIndent(4) << "Hotspot is disabled if the specificed Wi-Fi network is detected.\n"
<< AddIndent(-4) << AddIndent(-4)
<< "--no-ethernet\n" << "--no-ethernet\n"
<< AddIndent(4) << "Hotspot is disabled if an ethernet network is connected.\n" << AddIndent(4) << "Hotspot is disabled if an ethernet network is connected.\n"
<< AddIndent(-4) << AddIndent(-4)
<< "--no-wifi\n" << "--no-wifi\n"
@@ -1336,9 +1347,9 @@ int main(int argc, char **argv)
parser.AddOption("--port", &portOption); parser.AddOption("--port", &portOption);
parser.AddOption("--enable-hotspot", &enable_hotspot); parser.AddOption("--enable-hotspot", &enable_hotspot);
parser.AddOption("--disable-hotspot", &disable_hotspot); parser.AddOption("--disable-hotspot", &disable_hotspot);
parser.AddOption("--home-network",&homeNetwork); parser.AddOption("--home-network", &homeNetwork);
parser.AddOption("--no-ethernet",&noEthernet); parser.AddOption("--no-ethernet", &noEthernet);
parser.AddOption("--no-wifi",&noWifi); parser.AddOption("--no-wifi", &noWifi);
try try
{ {
parser.Parse(argc, (const char **)argv); parser.Parse(argc, (const char **)argv);
@@ -1367,9 +1378,7 @@ int main(int argc, char **argv)
} }
} }
int hotspotOptionCount = int hotspotOptionCount =
(homeNetwork.length() != 0 ? 1: 0) (homeNetwork.length() != 0 ? 1 : 0) + noEthernet + noWifi;
+ noEthernet
+ noWifi;
if (enable_hotspot) if (enable_hotspot)
{ {
@@ -1377,7 +1386,9 @@ int main(int argc, char **argv)
{ {
throw std::runtime_error("Only one hotspot option at a time can be specified."); throw std::runtime_error("Only one hotspot option at a time can be specified.");
} }
} else { }
else
{
if (hotspotOptionCount > 0) if (hotspotOptionCount > 0)
{ {
throw std::runtime_error("Hotspot options only only valid when the --enable-hotspot option has been supplied."); throw std::runtime_error("Hotspot options only only valid when the --enable-hotspot option has been supplied.");
@@ -1432,7 +1443,8 @@ int main(int argc, char **argv)
} }
if (install) if (install)
{ {
try { try
{
fs::path prefix; fs::path prefix;
if (prefixOption.length() != 0) if (prefixOption.length() != 0)
{ {
@@ -1465,8 +1477,8 @@ int main(int argc, char **argv)
} }
Install(prefix, portOption); Install(prefix, portOption);
FileSystemSync(); FileSystemSync();
}
} catch (const std::exception&e) catch (const std::exception &e)
{ {
cout << "ERROR: " << e.what() << endl; cout << "ERROR: " << e.what() << endl;
FileSystemSync(); FileSystemSync();
@@ -1475,10 +1487,12 @@ int main(int argc, char **argv)
} }
else if (uninstall) else if (uninstall)
{ {
try { try
{
Uninstall(); Uninstall();
FileSystemSync(); FileSystemSync();
} catch (const std::exception &e) }
catch (const std::exception &e)
{ {
cout << "ERROR: " << e.what() << endl; cout << "ERROR: " << e.what() << endl;
FileSystemSync(); FileSystemSync();
@@ -1489,7 +1503,6 @@ int main(int argc, char **argv)
{ {
RequireNetworkManager(); RequireNetworkManager();
StopService(); StopService();
} }
else if (start) else if (start)
{ {
@@ -1506,14 +1519,12 @@ int main(int argc, char **argv)
RequireNetworkManager(); RequireNetworkManager();
EnableService(); EnableService();
FileSystemSync(); FileSystemSync();
} }
else if (disable) else if (disable)
{ {
RequireNetworkManager(); RequireNetworkManager();
DisableService(); DisableService();
FileSystemSync(); FileSystemSync();
} }
else if (enable_p2p) else if (enable_p2p)
{ {
@@ -1541,8 +1552,7 @@ int main(int argc, char **argv)
settings.Load(); settings.Load();
settings.enable_ = false; settings.enable_ = false;
SetWifiDirectConfig(settings); SetWifiDirectConfig(settings);
RestartService(true); RestartService(true);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@@ -1557,15 +1567,17 @@ int main(int argc, char **argv)
if (homeNetwork.length() != 0) if (homeNetwork.length() != 0)
{ {
startMode = HotspotAutoStartMode::NotAtHome; startMode = HotspotAutoStartMode::NotAtHome;
} else if (noEthernet) }
else if (noEthernet)
{ {
startMode = HotspotAutoStartMode::NoEthernetConnection; startMode = HotspotAutoStartMode::NoEthernetConnection;
} else if (noWifi) }
else if (noWifi)
{ {
startMode = HotspotAutoStartMode::NoRememberedWifiConections; startMode = HotspotAutoStartMode::NoRememberedWifiConections;
} }
settings.ParseArguments(argv,startMode,homeNetwork); settings.ParseArguments(argv, startMode, homeNetwork);
if (settings.hasPassword_) if (settings.hasPassword_)
{ {
+4 -1
View File
@@ -293,7 +293,10 @@ namespace pipedal
virtual float GetOutputControlValue(int portIndex) const virtual float GetOutputControlValue(int portIndex) const
{ {
return controlValues[portIndex]; if (portIndex >= 0 && portIndex < controlValues.size()) {
return controlValues[portIndex];
}
return 0;
} }
virtual void SetBypass(bool bypass) virtual void SetBypass(bool bypass)
+87 -32
View File
@@ -20,6 +20,9 @@
#include "pch.h" #include "pch.h"
#include "Pedalboard.hpp" #include "Pedalboard.hpp"
#include "AtomConverter.hpp" #include "AtomConverter.hpp"
#include "PluginHost.hpp"
#include "AtomConverter.hpp"
#include "SplitEffect.hpp"
using namespace pipedal; using namespace pipedal;
@@ -87,6 +90,19 @@ ControlValue* PedalboardItem::GetControlValue(const std::string&symbol)
return nullptr; return nullptr;
} }
bool PedalboardItem::SetControlValue(const std::string&symbol, float value)
{
ControlValue*controlValue = GetControlValue(symbol);
if (controlValue == nullptr) return false;
if (controlValue->value() != value)
{
controlValue->value(value);
return true;
}
return false;
}
const ControlValue* PedalboardItem::GetControlValue(const std::string&symbol) const const ControlValue* PedalboardItem::GetControlValue(const std::string&symbol) const
{ {
for (size_t i = 0; i < this->controlValues().size(); ++i) for (size_t i = 0; i < this->controlValues().size(); ++i)
@@ -117,14 +133,7 @@ bool Pedalboard::SetControlValue(int64_t pedalItemId, const std::string &symbol,
{ {
PedalboardItem*item = GetItem(pedalItemId); PedalboardItem*item = GetItem(pedalItemId);
if (!item) return false; if (!item) return false;
ControlValue*controlValue = item->GetControlValue(symbol); return item->SetControlValue(symbol,value);
if (controlValue == nullptr) return false;
if (controlValue->value() != value)
{
controlValue->value(value);
return true;
}
return false;
} }
@@ -190,12 +199,12 @@ bool IsPedalboardSplitItem(const PedalboardItem*self, const std::vector<Pedalboa
return self->uri() == SPLIT_PEDALBOARD_ITEM_URI; return self->uri() == SPLIT_PEDALBOARD_ITEM_URI;
} }
bool Pedalboard::ApplySnapshot(int64_t snapshotIndex) bool Pedalboard::ApplySnapshot(int64_t snapshotIndex, PluginHost&pluginHost)
{ {
if (snapshotIndex < 0 || if (snapshotIndex < 0 ||
snapshotIndex >= this->snapshots_.size() || snapshotIndex >= this->snapshots_.size() ||
this->snapshots_[snapshotIndex] == nullptr || this->snapshots_[snapshotIndex] == nullptr
this->selectedSnapshot() == snapshotIndex) )
{ {
return false; return false;
} }
@@ -210,15 +219,47 @@ bool Pedalboard::ApplySnapshot(int64_t snapshotIndex)
auto plugins = this->GetAllPlugins(); auto plugins = this->GetAllPlugins();
for (PedalboardItem *pedalboardItem: plugins) for (PedalboardItem *pedalboardItem: plugins)
{ {
SnapshotValue*snapshotValue = indexedValues[pedalboardItem->instanceId()]; if (!pedalboardItem->isEmpty())
if (snapshotValue)
{ {
pedalboardItem->ApplySnapshotValue(snapshotValue); SnapshotValue*snapshotValue = indexedValues[pedalboardItem->instanceId()];
if (snapshotValue)
{
pedalboardItem->ApplySnapshotValue(snapshotValue);
} else {
pedalboardItem->ApplyDefaultValues(pluginHost);
}
} }
} }
return true; return true;
} }
void PedalboardItem::ApplyDefaultValues(PluginHost&pluginHost)
{
if (isEmpty()) return;
auto pluginInfo = pluginHost.GetPluginInfo(this->uri());
if (!pluginInfo)
{
if (this->isSplit())
{
pluginInfo = GetSplitterPluginInfo();
}
}
this->isEnabled(true);
if (pluginInfo)
{
for (auto &port: pluginInfo->ports())
{
this->SetControlValue(port->symbol(),port->default_value());
}
// a cheat. this isn't actually true, but close enough.
for (auto &pathProperty: this->pathProperties_)
{
pathProperties_[pathProperty.first] = AtomConverter::EmptyPathstring();
}
}
}
void PedalboardItem::ApplySnapshotValue(SnapshotValue*snapshotValue) void PedalboardItem::ApplySnapshotValue(SnapshotValue*snapshotValue)
{ {
std::map<std::string,float> cumulativeValues; std::map<std::string,float> cumulativeValues;
@@ -240,6 +281,16 @@ void PedalboardItem::ApplySnapshotValue(SnapshotValue*snapshotValue)
this->lv2State(snapshotValue->lv2State_); this->lv2State(snapshotValue->lv2State_);
this->stateUpdateCount(this->stateUpdateCount()+1); this->stateUpdateCount(this->stateUpdateCount()+1);
} }
for (auto&property: snapshotValue->pathProperties_)
{
if (property.second == "null")
{
this->pathProperties_[property.first] = AtomConverter::EmptyPathstring();
} else {
this->pathProperties_[property.first] = property.second;
}
}
this->isEnabled(snapshotValue->isEnabled_); this->isEnabled(snapshotValue->isEnabled_);
} }
@@ -278,17 +329,19 @@ bool PedalboardItem::IsStructurallyIdentical(const PedalboardItem&other) const
} }
if (this->isSplit()) // so is the other by virtue of idential uris. if (this->isSplit()) // so is the other by virtue of idential uris.
{ {
auto myValue = this->GetControlValue("splitType"); // provisionally, it seems ok to change the split type.
auto otherValue = other.GetControlValue("splitType"); // auto myValue = this->GetControlValue("splitType");
if (myValue == nullptr || otherValue == nullptr) // actually an error. // auto otherValue = other.GetControlValue("splitType");
{ // if (myValue == nullptr || otherValue == nullptr) // actually an error.
return false; // {
} // return false;
// split type changes potentially trigger buffer allocation changes, // }
// so different split types are not structurally identical.
if (myValue->value() != otherValue->value()) { // // split type changes potentially trigger buffer allocation changes,
return false; // // so different split types are not structurally identical.
} // if (myValue->value() != otherValue->value()) {
// return false;
// }
if (topChain().size() != other.topChain().size()) if (topChain().size() != other.topChain().size())
{ {
return false; return false;
@@ -407,17 +460,19 @@ Snapshot Pedalboard::MakeSnapshotFromCurrentSettings(const Pedalboard &previousP
{ {
Snapshot snapshot; Snapshot snapshot;
// name and color don't matter. this is strictly for loading purposes. // name and color don't matter. this is strictly for loading purposes.
for (auto &item : this->items()) auto items = this->GetAllPlugins();
for (auto item : items)
{ {
item.AddToSnapshotFromCurrentSettings(snapshot); item->AddToSnapshotFromCurrentSettings(snapshot);
} }
// a neccesary precondition: the previous pedalboard must have identical structure, // a neccesary precondition: the previous pedalboard must have identical structure,
// so we can just // so we can just
size_t index = 0; // auto items = this->GetAllPlugins();
for (auto&item: previousPedalboard.items_)
{ // for (auto&item: previousPedalboard.items_)
item.AddResetsForMissingProperties(snapshot,&index); // {
} // item.AddResetsForMissingProperties(snapshot,&index);
// }
return snapshot; return snapshot;
} }
+5 -1
View File
@@ -28,6 +28,7 @@
namespace pipedal { namespace pipedal {
class SnapshotValue; class SnapshotValue;
class Snapshot; class Snapshot;
class PluginHost;
#define SPLIT_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Split" #define SPLIT_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Split"
#define EMPTY_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Empty" #define EMPTY_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Empty"
@@ -102,10 +103,13 @@ public:
public: public:
ControlValue*GetControlValue(const std::string&symbol); ControlValue*GetControlValue(const std::string&symbol);
const ControlValue*GetControlValue(const std::string&symbol) const; const ControlValue*GetControlValue(const std::string&symbol) const;
bool SetControlValue(const std::string&key, float value);
bool IsStructurallyIdentical(const PedalboardItem&other) const; bool IsStructurallyIdentical(const PedalboardItem&other) const;
void ApplySnapshotValue(SnapshotValue*snapshotValue); void ApplySnapshotValue(SnapshotValue*snapshotValue);
void ApplyDefaultValues(PluginHost&pluginHost);
bool hasLv2State() const { bool hasLv2State() const {
return lv2State_.isValid_ != 0; return lv2State_.isValid_ != 0;
} }
@@ -203,7 +207,7 @@ public:
std::vector<PedalboardItem*>GetAllPlugins(); std::vector<PedalboardItem*>GetAllPlugins();
bool HasItem(int64_t pedalItemid) const { return GetItem(pedalItemid) != nullptr; } bool HasItem(int64_t pedalItemid) const { return GetItem(pedalItemid) != nullptr; }
bool ApplySnapshot(int64_t snapshotIndex); bool ApplySnapshot(int64_t snapshotIndex, PluginHost &pluginHost);
GETTER_SETTER_REF(name) GETTER_SETTER_REF(name)
GETTER_SETTER_VEC(items) GETTER_SETTER_VEC(items)
+16 -15
View File
@@ -535,23 +535,17 @@ 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);
if (this->pedalboard.ApplySnapshot(selectedSnapshot)) if (this->pedalboard.ApplySnapshot(selectedSnapshot, pluginHost))
{ {
this->pedalboard.SetCurrentSnapshotModified(false);
this->FireSnapshotModified(selectedSnapshot,false);
if (this->audioHost)
{
if (this->previousPedalboardLoaded && this->pedalboard.IsStructureIdentical(this->previousPedalboard))
{
this->audioHost->LoadSnapshot(*(this->pedalboard.snapshots()[selectedSnapshot]), this->pluginHost); // no longer own it.
} else {
LoadCurrentPedalboard();
}
}
SetPresetChanged(-1, true, false);
this->pedalboard.selectedSnapshot(selectedSnapshot); this->pedalboard.selectedSnapshot(selectedSnapshot);
FirePedalboardChanged(-1, false); for (auto snapshot: this->pedalboard.snapshots())
{
if (snapshot)
{
snapshot->isModified_ = false;
}
}
FirePedalboardChanged(-1, true);
} }
} }
@@ -567,6 +561,13 @@ void PiPedalModel::SetSnapshots(std::vector<std::shared_ptr<Snapshot>> &snapshot
if (selectedSnapshot != -1) if (selectedSnapshot != -1)
{ {
this->pedalboard.selectedSnapshot(selectedSnapshot); this->pedalboard.selectedSnapshot(selectedSnapshot);
for (auto &snapshot: pedalboard.snapshots())
{
if (snapshot)
{
snapshot->isModified_ = false;
}
}
} }
this->FirePedalboardChanged(-1, false); // notify clients (but don't change the running pedalboard, because it's still the same) this->FirePedalboardChanged(-1, false); // notify clients (but don't change the running pedalboard, because it's still the same)
+1
View File
@@ -182,6 +182,7 @@ SplitEffect::SplitEffect(
Lv2PluginInfo::ptr puginInfo = g_splitterPluginInfo; Lv2PluginInfo::ptr puginInfo = g_splitterPluginInfo;
defaultInputControlValues.resize(MAX_INPUT_CONTROL);
for (auto&port: puginInfo->ports()) for (auto&port: puginInfo->ports())
{ {
if (port->is_control_port() && port->is_input()) if (port->is_control_port() && port->is_input())
-1
View File
@@ -358,7 +358,6 @@ namespace pipedal
virtual void SetBypass(bool enabled) virtual void SetBypass(bool enabled)
{ {
throw PiPedalArgumentException("Not implmented. Should not have been called.");
} }
virtual float GetOutputControlValue(int index) const { virtual float GetOutputControlValue(int index) const {
+18
View File
@@ -1,3 +1,21 @@
Loading shields need to be of Modal type.
MOD fileTypes
- audioloop: Audio Loops, meant to be used for looper-style plugins
- audiorecording: Audio Recordings, triggered by plugins and stored in the unit
- audiosample: One-shot Audio Samples, meant to be used for sampler-style plugins
- audiotrack: Audio Tracks, meant to be used as full-performance/song or backtrack
- cabsim: Speaker Cabinets, meant as small IR audio files
- h2drumkit: Hydrogen Drumkits, must use h2drumkit file extension
- ir: Impulse Responses
- midiclip: MIDI Clips, to be used in sync with host tempo, must have mid or midi file extension
- midisong: MIDI Songs, meant to be used as full-performance/song or backtrack
- sf2: SF2 Instruments, must have sf2 or sf3 file extension
- sfz: SFZ Instruments, must have sfz file extension
Main menu on Pixel 5 client. Main menu on Pixel 5 client.
x1 bank menu (landscape pixel 5) should show current bank. x1 bank menu (landscape pixel 5) should show current bank.