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)
project(pipedal
VERSION 1.3.54
VERSION 1.3.55
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
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 (CMAKE_INSTALL_PREFIX "/usr/")
+1 -1
View File
@@ -20,7 +20,7 @@ static int ToOsSignalType(SignalHandler::SignalType signalType)
case SignalHandler::Hangup: result = SIGHUP; break;
default:
throw std::runtime_error("INvalid signal type");
throw std::runtime_error("Invalid signal type");
}
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://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).
Documentation:&nbsp;[https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).
&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;
+3 -3
View File
@@ -13,17 +13,17 @@ page_icon: img/Install4.jpg
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)
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
```
sudo apt update
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.
+11 -1
View File
@@ -1,4 +1,14 @@
# 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
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)
Bug fixes.
Bug fixes:
- Various crashes related to snapshots.
- 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:
- <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
@@ -12,7 +12,7 @@ Install the package by running
```
sudo apt update
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.
+2 -2
View File
@@ -1,7 +1,7 @@
<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;
@@ -9,7 +9,7 @@ To download PiPedal, click [here](download.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;
+136 -123
View File
@@ -17,12 +17,12 @@
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import { SyntheticEvent } from 'react';
import { WithStyles } from '@mui/styles';
import './AppThemed.css';
//import {alpha} from '@mui/material/styles';
import AppBar from '@mui/material/AppBar';
import Modal from '@mui/material/Modal';
import Toolbar from '@mui/material/Toolbar';
import CssBaseline from '@mui/material/CssBaseline';
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 List from '@mui/material/List';
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 ListItemText from '@mui/material/ListItemText';
import CircularProgress from '@mui/material/CircularProgress';
@@ -92,6 +94,17 @@ const appStyles = (theme: Theme) => createStyles({
listSubheader: {
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: {
display: "block",
position: "absolute",
@@ -100,7 +113,6 @@ const appStyles = (theme: Theme) => createStyles({
top: "0px",
width: "100%",
height: "100%",
background: isDarkMode() ? "#222" : "#DDD",
opacity: "0.95",
justifyContent: "center",
textAlign: "center",
@@ -166,22 +178,22 @@ const appStyles = (theme: Theme) => createStyles({
},
loadingBox: {
position: "relative",
display: "flex",
flexFlow: "column nowrap",
position: "absolute",
top: "20%",
left: 0, right: 0,
color: isDarkMode() ? theme.palette.text.secondary : "#888",
// border: "3px solid #888",
borderRadius: "12px",
padding: "12px",
justifyContent: "center",
alignItems: "center",
textAlign: "center",
opacity: 0.8,
zIndex: 2010
},
loadingBoxItem: {
justifyContent: "center",
display: "flex", flexFlow: "row nowrap",
alignItems: "center",
textAlign: "center",
zIndex: 2010
},
@@ -247,9 +259,8 @@ function setFullScreen(value: boolean) {
if (docEl.requestFullscren) // the latest offical api.
{
if (value)
{
window.document.documentElement.requestFullscreen({navigationUI: "show"});
if (value) {
window.document.documentElement.requestFullscreen({ navigationUI: "show" });
} else {
window.document.exitFullscreen();
}
@@ -267,10 +278,10 @@ function setFullScreen(value: boolean) {
}
function preventDefault(e: SyntheticEvent): void {
e.stopPropagation();
e.preventDefault();
}
// function preventDefault(e: SyntheticEvent): void {
// e.stopPropagation();
// e.preventDefault();
// }
type AppState = {
zoomedControlInfo: ZoomedControlInfo | undefined;
@@ -403,7 +414,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
return false;
}
onOpenBank(bankId: number) {
handleSpecificBank(bankId: number) {
this.model_.openBank(bankId)
.catch((error) => this.model_.showAlert(error.toString()));
@@ -491,17 +503,15 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
}
handleDrawerSelectBank() {
this.setState({
isDrawerOpen: false,
bankDialogOpen: true,
editBankDialogOpen: false
});
}
handleDrawerDonationClick() {
this.setState({
isDrawerOpen: false,
});
this.hideDrawer(false);
if (this.model_.isAndroidHosted()) {
this.model_.showAndroidDonationActivity();
} else {
@@ -514,14 +524,12 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
handleDrawerAboutClick() {
this.setState({
isDrawerOpen: false,
aboutDialogOpen: true
});
}
handleDrawerRenameBank() {
this.setState({
isDrawerOpen: false,
renameBankDialogOpen: true,
saveBankAsDialogOpen: false
});
@@ -529,7 +537,6 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
}
handleDrawerSaveBankAs() {
this.setState({
isDrawerOpen: false,
renameBankDialogOpen: false,
saveBankAsDialogOpen: true
});
@@ -657,6 +664,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
let bankEntries = Math.floor((height - K) / ENTRY_HEIGHT);
if (bankEntries < 1) bankEntries = 1;
if (bankEntries > 7) bankEntries = 7;
if (bankEntries === 2) bankEntries = 1;
this.setState({ bankDisplayItems: bankEntries });
}
@@ -686,27 +695,33 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
}
shortBankList(banks: BankIndex): BankIndexEntry[] {
let n = this.state.bankDisplayItems;
let nDisplayEntries = this.state.bankDisplayItems;
let entries = banks.entries;
if (entries.length < n + 1) { // +1 for the .... entry.
return entries;
}
let nListEntries = entries.length;
let result: BankIndexEntry[] = [];
let selectedIndex = -1;
for (let i = 0; i < entries.length; ++i) {
if (entries[i].instanceId === banks.selectedBank) {
selectedIndex = i;
break;
}
}
if (n > entries.length) n = entries.length;
if (selectedIndex > n) {
for (let i = 0; i < n - 1; ++i) {
if (nListEntries <= nDisplayEntries) {
for (let i = 0; i < nListEntries; ++i) {
result.push(entries[i]);
}
result.push(entries[selectedIndex]);
} 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]);
}
}
@@ -747,7 +762,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<div style={{
colorScheme: isDarkMode() ? "dark" : "light", // affects scrollbar color
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"
}}
onContextMenu={(e) => {
@@ -831,11 +846,11 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</div>
)}
<TemporaryDrawer position='left' title="PiPedal"
is_open={this.state.isDrawerOpen} onClose={() => { this.hideDrawer(); }} >
is_open={this.state.isDrawerOpen} onClose={() => { this.hideDrawer(false); }} >
<List>
<ListItem button key='PerformanceView'
onClick={(ev) => {
<ListItemButton key='PerformanceView'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(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 }} />
</ListItemIcon>
<ListItemText primary='Performance View' />
</ListItem>
</ListItemButton>
</List>
<Divider />
<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) => {
return (
<ListItem button key={'bank' + bank.instanceId} selected={bank.instanceId === this.state.banks.selectedBank}
onClick={() => this.onOpenBank(bank.instanceId)}
<ListItemButton key={'bank' + bank.instanceId} selected={bank.instanceId === this.state.banks.selectedBank}
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(false);
this.handleSpecificBank(bank.instanceId);
}}
>
<ListItemText primary={bank.name} />
</ListItem>
</ListItemButton>
);
})
}
{
showBankSelectDialog && (
<ListItem button key={'bankDOTDOTDOT'} selected={false}
onClick={(ev) => {
<ListItemButton key={'bankDOTDOTDOT'} selected={false}
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerSelectBank();
@@ -877,7 +896,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
>
<ListItemText primary={"..."} />
</ListItem>
</ListItemButton>
)
@@ -885,8 +904,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</List>
<Divider />
<List>
<ListItem button key='RenameBank'
onClick={(ev) => {
<ListItemButton key='RenameBank'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerRenameBank()
@@ -895,9 +914,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<RenameOutlineIcon color='inherit' className={classes.menuIcon} />
</ListItemIcon>
<ListItemText primary='Rename bank' />
</ListItem>
<ListItem button key='SaveBank'
onClick={(ev) => {
</ListItemButton>
<ListItemButton key='SaveBank'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerSaveBankAs();
@@ -906,9 +925,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<SaveBankAsIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon>
<ListItemText primary='Save as new bank' />
</ListItem>
<ListItem button key='EditBanks'
onClick={(ev) => {
</ListItemButton>
<ListItemButton key='EditBanks'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerManageBanks();
@@ -917,12 +936,12 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<EditBanksIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon>
<ListItemText primary='Manage banks...' />
</ListItem>
</ListItemButton>
</List>
<Divider />
<List>
<ListItem button key='Settings'
onClick={(ev) => {
<ListItemButton key='Settings'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerSettingsClick()
@@ -931,9 +950,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<SettingsIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon>
<ListItemText primary='Settings' />
</ListItem>
<ListItem button key='About'
onClick={(ev) => {
</ListItemButton>
<ListItemButton key='About'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerAboutClick();
@@ -942,18 +961,17 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<HelpOutlineIcon color="inherit" className={classes.menuIcon} />
</ListItemIcon>
<ListItemText primary='About' />
</ListItem>
<ListItem button key='Donations'
onClick={(ev) => {
</ListItemButton>
<ListItemButton key='Donations'
onClick={(ev: any) => {
ev.stopPropagation();
this.hideDrawer(true);
this.handleDrawerDonationClick();
}}>
<ListItemIcon >
<VolunteerActivismIcon className={classes.menuIcon} color="inherit" />
</ListItemIcon>
<ListItemText primary='Donations' />
</ListItem>
</ListItemButton>
</List>
</TemporaryDrawer>
@@ -1040,67 +1058,62 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</DialogEx>
<div className={classes.errorContent} style={{ zIndex: 1200, display: this.state.displayState === State.Error ? "flex" : "none" }}
onMouseDown={preventDefault} onKeyDown={preventDefault}
<Modal open={this.state.displayState === State.Error}
aria-label="fatal-error"
aria-describedby="aria-error-text"
>
<div className={classes.errorContentMask} />
<div style={{ flex: "2 2 3px", height: 20 }} >&nbsp;</div>
<div className={classes.errorMessageBox} style={{ position: "relative" }} >
<div style={{ fontSize: "30px", position: "absolute", left: 0, top: 3, color: "#A00" }}>
<ErrorOutlineIcon color="inherit" fontSize="inherit" style={{ float: "left", marginRight: "12px" }} />
</div>
<div style={{ marginLeft: 40, marginTop: 3 }}>
<p className={classes.errorText}>
Error: {this.state.errorMessage}
</p>
</div>
<div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}>
<Button variant='contained' color="primary"
onClick={() => this.handleReload()} >
Reload
</Button>
<div style={{
display: "flex", flexFlow: "column nowrap",
position: "absolute", top: 0, left: 0, right: 0, bottom: 0
}}
>
<div className={classes.loadingMask} />
<div style={{ flex: "2 2 3px", height: 20 }} >&nbsp;</div>
<div className={classes.errorMessageBox} style={{ position: "relative" }} >
<div style={{ fontSize: "30px", position: "absolute", left: 0, top: 3, color: "#A00" }}>
<ErrorOutlineIcon color="inherit" fontSize="inherit" style={{ float: "left", marginRight: "12px" }} />
</div>
<div style={{ marginLeft: 40, marginTop: 3 }}>
<p className={classes.errorText} id="aria-error-text">
Error: {this.state.errorMessage}
</p>
</div>
<div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}>
<Button variant='contained' color="primary"
onClick={() => this.handleReload()} >
Reload
</Button>
</div>
</div>
<div style={{ flex: "5 5 auto", height: 20 }} >&nbsp;</div>
</div>
<div style={{ flex: "5 5 auto", height: 20 }} >&nbsp;</div>
</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>
</Modal >
{/* Reloading mask */}
<div className={classes.errorContent} style={{
zIndex: 1201,
display: (
wantsReloadingScreen(this.state.displayState)
? "block" : "none"
)
}}
< Modal
open={wantsReloadingScreen(this.state.displayState) || this.state.displayState === State.Loading}
aria-label="loading"
aria-describedby="reloading-modal-description"
>
<div className={classes.errorContentMask} />
<div className={classes.loadingBox}>
<div className={classes.loadingBoxItem}>
<CircularProgress color="inherit" className={classes.loadingBoxItem} />
<div style={{display: "flex",flexFlow: "column nowrap", alignItems: "center"}}>
<div className={classes.loadingMask} />
<div className={classes.loadingBox}>
<div 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>
<Typography display="block" noWrap variant="body2" className={classes.progressText}>
{this.getReloadingMessage()}
</Typography>
</div>
</div>
</Modal >
</div >
);
}
});
+1
View File
@@ -206,6 +206,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
export class SnapshotValue {
deserialize(input: any): SnapshotValue {
this.isEnabled = input.isEnabled;
this.instanceId = input.instanceId;
this.controlValues = ControlValue.deserializeArray(input.controlValues);
this.lv2State = input.lv2state;
+5 -1
View File
@@ -135,7 +135,7 @@ namespace pipedal
{
auto maxInputControl = effect->GetMaxInputControl();
inputControlValues.resize(maxInputControl);
this->enabled = true;
for (uint64_t i = 0; i < maxInputControl; ++i)
{
bool isInputControl = effect->IsInputControl(i);
@@ -150,6 +150,7 @@ namespace pipedal
}
if (snapshotValue)
{
this->enabled = snapshotValue->isEnabled_;
for (auto &controlValue : snapshotValue->controlValues_)
{
auto index = effect->GetControlIndex(controlValue.key());
@@ -202,6 +203,8 @@ namespace pipedal
}
void ApplyValues(IEffect *effect)
{
effect->SetBypass(this->enabled);
if (effect != pEffect)
{
throw std::runtime_error("Wrong effect");
@@ -226,6 +229,7 @@ namespace pipedal
private:
IEffect *pEffect;
Lv2PluginState lv2State;
bool enabled;
std::vector<InputControlEntry> inputControlValues;
std::vector<PathPatchProperty> pathPatchProperties;
};
+4 -2
View File
@@ -482,8 +482,8 @@ void AvahiService::Wait()
{
default:
case ServiceState::Unitialized:
throw std::runtime_error("Invalid state");
done = true;
break;
case ServiceState::Initializing:
case ServiceState::Settling:
case ServiceState::Requested:
@@ -503,6 +503,8 @@ void AvahiService::Wait()
if (clock::now() > waitTime)
{
Lv2Log::error("DNS/SD announcement timed out.");
done = true;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
+71 -59
View File
@@ -155,6 +155,49 @@ void DisableService()
#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()
{
silentSysExec(SS(SYSTEMCTL_BIN << " restart avahi-daemon.service").c_str());
@@ -169,41 +212,10 @@ static void AvahiInstall()
SystemConfigFile avahi(avahiConfig);
bool changed = avahi.RemoveUndoableActions();
int line = avahi.GetLineThatStartsWith("use-ipv6=yes");
if (line != -1)
{
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;
}
}
changed |= disableAvahiConfigLine(avahi, "[server]", "use-ipv6=");
changed |= disableAvahiConfigLine(avahi, "[publish]", "publish-aaaa-on-ipv4=");
if (changed)
{
avahi.Save();
@@ -914,7 +926,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
try
{
// 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();
@@ -995,7 +1007,6 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
// add to netdev group
sysExec(USERMOD_BIN " -a -G " NETDEV_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// create and configure /var directory.
fs::path varDirectory("/var/pipedal");
@@ -1211,11 +1222,11 @@ static void PrintHelp()
<< "\n\n"
<< "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."
<< "\n\n"
<< "\n\n"
<< "--home-network <wifi-ssid>\n"
<< AddIndent(4) << "Hotspot is disabled if the specificed Wi-Fi network is detected.\n"
<< AddIndent(-4)
<< "--no-ethernet\n"
<< "--no-ethernet\n"
<< AddIndent(4) << "Hotspot is disabled if an ethernet network is connected.\n"
<< AddIndent(-4)
<< "--no-wifi\n"
@@ -1336,9 +1347,9 @@ int main(int argc, char **argv)
parser.AddOption("--port", &portOption);
parser.AddOption("--enable-hotspot", &enable_hotspot);
parser.AddOption("--disable-hotspot", &disable_hotspot);
parser.AddOption("--home-network",&homeNetwork);
parser.AddOption("--no-ethernet",&noEthernet);
parser.AddOption("--no-wifi",&noWifi);
parser.AddOption("--home-network", &homeNetwork);
parser.AddOption("--no-ethernet", &noEthernet);
parser.AddOption("--no-wifi", &noWifi);
try
{
parser.Parse(argc, (const char **)argv);
@@ -1367,9 +1378,7 @@ int main(int argc, char **argv)
}
}
int hotspotOptionCount =
(homeNetwork.length() != 0 ? 1: 0)
+ noEthernet
+ noWifi;
(homeNetwork.length() != 0 ? 1 : 0) + noEthernet + noWifi;
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.");
}
} else {
}
else
{
if (hotspotOptionCount > 0)
{
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)
{
try {
try
{
fs::path prefix;
if (prefixOption.length() != 0)
{
@@ -1465,8 +1477,8 @@ int main(int argc, char **argv)
}
Install(prefix, portOption);
FileSystemSync();
} catch (const std::exception&e)
}
catch (const std::exception &e)
{
cout << "ERROR: " << e.what() << endl;
FileSystemSync();
@@ -1475,10 +1487,12 @@ int main(int argc, char **argv)
}
else if (uninstall)
{
try {
try
{
Uninstall();
FileSystemSync();
} catch (const std::exception &e)
}
catch (const std::exception &e)
{
cout << "ERROR: " << e.what() << endl;
FileSystemSync();
@@ -1489,7 +1503,6 @@ int main(int argc, char **argv)
{
RequireNetworkManager();
StopService();
}
else if (start)
{
@@ -1506,14 +1519,12 @@ int main(int argc, char **argv)
RequireNetworkManager();
EnableService();
FileSystemSync();
}
else if (disable)
{
RequireNetworkManager();
DisableService();
FileSystemSync();
}
else if (enable_p2p)
{
@@ -1541,8 +1552,7 @@ int main(int argc, char **argv)
settings.Load();
settings.enable_ = false;
SetWifiDirectConfig(settings);
RestartService(true);
return EXIT_SUCCESS;
}
@@ -1557,15 +1567,17 @@ int main(int argc, char **argv)
if (homeNetwork.length() != 0)
{
startMode = HotspotAutoStartMode::NotAtHome;
} else if (noEthernet)
}
else if (noEthernet)
{
startMode = HotspotAutoStartMode::NoEthernetConnection;
} else if (noWifi)
}
else if (noWifi)
{
startMode = HotspotAutoStartMode::NoRememberedWifiConections;
}
settings.ParseArguments(argv,startMode,homeNetwork);
settings.ParseArguments(argv, startMode, homeNetwork);
if (settings.hasPassword_)
{
+4 -1
View File
@@ -293,7 +293,10 @@ namespace pipedal
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)
+87 -32
View File
@@ -20,6 +20,9 @@
#include "pch.h"
#include "Pedalboard.hpp"
#include "AtomConverter.hpp"
#include "PluginHost.hpp"
#include "AtomConverter.hpp"
#include "SplitEffect.hpp"
using namespace pipedal;
@@ -87,6 +90,19 @@ ControlValue* PedalboardItem::GetControlValue(const std::string&symbol)
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
{
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);
if (!item) return false;
ControlValue*controlValue = item->GetControlValue(symbol);
if (controlValue == nullptr) return false;
if (controlValue->value() != value)
{
controlValue->value(value);
return true;
}
return false;
return item->SetControlValue(symbol,value);
}
@@ -190,12 +199,12 @@ bool IsPedalboardSplitItem(const PedalboardItem*self, const std::vector<Pedalboa
return self->uri() == SPLIT_PEDALBOARD_ITEM_URI;
}
bool Pedalboard::ApplySnapshot(int64_t snapshotIndex)
bool Pedalboard::ApplySnapshot(int64_t snapshotIndex, PluginHost&pluginHost)
{
if (snapshotIndex < 0 ||
snapshotIndex >= this->snapshots_.size() ||
this->snapshots_[snapshotIndex] == nullptr ||
this->selectedSnapshot() == snapshotIndex)
this->snapshots_[snapshotIndex] == nullptr
)
{
return false;
}
@@ -210,15 +219,47 @@ bool Pedalboard::ApplySnapshot(int64_t snapshotIndex)
auto plugins = this->GetAllPlugins();
for (PedalboardItem *pedalboardItem: plugins)
{
SnapshotValue*snapshotValue = indexedValues[pedalboardItem->instanceId()];
if (snapshotValue)
if (!pedalboardItem->isEmpty())
{
pedalboardItem->ApplySnapshotValue(snapshotValue);
SnapshotValue*snapshotValue = indexedValues[pedalboardItem->instanceId()];
if (snapshotValue)
{
pedalboardItem->ApplySnapshotValue(snapshotValue);
} else {
pedalboardItem->ApplyDefaultValues(pluginHost);
}
}
}
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)
{
std::map<std::string,float> cumulativeValues;
@@ -240,6 +281,16 @@ void PedalboardItem::ApplySnapshotValue(SnapshotValue*snapshotValue)
this->lv2State(snapshotValue->lv2State_);
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_);
}
@@ -278,17 +329,19 @@ bool PedalboardItem::IsStructurallyIdentical(const PedalboardItem&other) const
}
if (this->isSplit()) // so is the other by virtue of idential uris.
{
auto myValue = this->GetControlValue("splitType");
auto otherValue = other.GetControlValue("splitType");
if (myValue == nullptr || otherValue == nullptr) // actually an error.
{
return false;
}
// split type changes potentially trigger buffer allocation changes,
// so different split types are not structurally identical.
if (myValue->value() != otherValue->value()) {
return false;
}
// provisionally, it seems ok to change the split type.
// auto myValue = this->GetControlValue("splitType");
// auto otherValue = other.GetControlValue("splitType");
// if (myValue == nullptr || otherValue == nullptr) // actually an error.
// {
// return false;
// }
// // split type changes potentially trigger buffer allocation changes,
// // so different split types are not structurally identical.
// if (myValue->value() != otherValue->value()) {
// return false;
// }
if (topChain().size() != other.topChain().size())
{
return false;
@@ -407,17 +460,19 @@ Snapshot Pedalboard::MakeSnapshotFromCurrentSettings(const Pedalboard &previousP
{
Snapshot snapshot;
// 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,
// so we can just
size_t index = 0;
for (auto&item: previousPedalboard.items_)
{
item.AddResetsForMissingProperties(snapshot,&index);
}
// auto items = this->GetAllPlugins();
// for (auto&item: previousPedalboard.items_)
// {
// item.AddResetsForMissingProperties(snapshot,&index);
// }
return snapshot;
}
+5 -1
View File
@@ -28,6 +28,7 @@
namespace pipedal {
class SnapshotValue;
class Snapshot;
class PluginHost;
#define SPLIT_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Split"
#define EMPTY_PEDALBOARD_ITEM_URI "uri://two-play/pipedal/pedalboard#Empty"
@@ -102,10 +103,13 @@ public:
public:
ControlValue*GetControlValue(const std::string&symbol);
const ControlValue*GetControlValue(const std::string&symbol) const;
bool SetControlValue(const std::string&key, float value);
bool IsStructurallyIdentical(const PedalboardItem&other) const;
void ApplySnapshotValue(SnapshotValue*snapshotValue);
void ApplyDefaultValues(PluginHost&pluginHost);
bool hasLv2State() const {
return lv2State_.isValid_ != 0;
}
@@ -203,7 +207,7 @@ public:
std::vector<PedalboardItem*>GetAllPlugins();
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_VEC(items)
+16 -15
View File
@@ -535,23 +535,17 @@ void PiPedalModel::SetPedalboard(int64_t clientId, Pedalboard &pedalboard)
void PiPedalModel::SetSnapshot(int64_t selectedSnapshot)
{
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);
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)
{
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)
+1
View File
@@ -182,6 +182,7 @@ SplitEffect::SplitEffect(
Lv2PluginInfo::ptr puginInfo = g_splitterPluginInfo;
defaultInputControlValues.resize(MAX_INPUT_CONTROL);
for (auto&port: puginInfo->ports())
{
if (port->is_control_port() && port->is_input())
-1
View File
@@ -358,7 +358,6 @@ namespace pipedal
virtual void SetBypass(bool enabled)
{
throw PiPedalArgumentException("Not implmented. Should not have been called.");
}
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.
x1 bank menu (landscape pixel 5) should show current bank.