diff --git a/CMakeLists.txt b/CMakeLists.txt index 564358c..1d6f9bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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/") diff --git a/NetworkManagerP2P/src/SignalHandler.cpp b/NetworkManagerP2P/src/SignalHandler.cpp index 35357cc..f1fe2fc 100644 --- a/NetworkManagerP2P/src/SignalHandler.cpp +++ b/NetworkManagerP2P/src/SignalHandler.cpp @@ -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; } diff --git a/README.md b/README.md index 86f94e4..7375c72 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,13 @@ -Download: v1.3.54 +Download: v1.3.55 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).   -#### 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.   diff --git a/docs/Installing.md b/docs/Installing.md index 083e737..f875466 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -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. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 9d76cfa..df6523f 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -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). diff --git a/docs/download.md b/docs/download.md index b1ebd8b..e8782e7 100644 --- a/docs/download.md +++ b/docs/download.md @@ -4,7 +4,7 @@ Download the most recent Debian (.deb) package for your platform: -- Raspberry Pi OS Bookworm (64-bit) v1.3.54 +- Raspberry Pi OS Bookworm (64-bit) v1.3.55 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. diff --git a/docs/index.md b/docs/index.md index 5e19088..6d15d6a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -v1.3.54 +v1.3.55   @@ -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.   diff --git a/react/src/AppThemed.tsx b/react/src/AppThemed.tsx index 4845347..3b54b8e 100644 --- a/react/src/AppThemed.tsx +++ b/react/src/AppThemed.tsx @@ -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<
{ @@ -831,11 +846,11 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
)} { this.hideDrawer(); }} > + is_open={this.state.isDrawerOpen} onClose={() => { this.hideDrawer(false); }} > - { + { ev.stopPropagation(); this.hideDrawer(true); this.setState({ performanceView: true }); @@ -844,7 +859,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - + { return ( - this.onOpenBank(bank.instanceId)} + { + ev.stopPropagation(); + this.hideDrawer(false); + this.handleSpecificBank(bank.instanceId); + }} > - + ); }) } { showBankSelectDialog && ( - { + { ev.stopPropagation(); this.hideDrawer(true); this.handleDrawerSelectBank(); @@ -877,7 +896,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< > - + ) @@ -885,8 +904,8 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - { + { ev.stopPropagation(); this.hideDrawer(true); this.handleDrawerRenameBank() @@ -895,9 +914,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - - { + + { ev.stopPropagation(); this.hideDrawer(true); this.handleDrawerSaveBankAs(); @@ -906,9 +925,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - - { + + { ev.stopPropagation(); this.hideDrawer(true); this.handleDrawerManageBanks(); @@ -917,12 +936,12 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - + - { + { ev.stopPropagation(); this.hideDrawer(true); this.handleDrawerSettingsClick() @@ -931,9 +950,9 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - - { + + { ev.stopPropagation(); this.hideDrawer(true); this.handleDrawerAboutClick(); @@ -942,18 +961,17 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< - - { + + { ev.stopPropagation(); - this.hideDrawer(true); this.handleDrawerDonationClick(); }}> - + @@ -1040,67 +1058,62 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< -
-
-
 
-
-
- -
-
-

- Error: {this.state.errorMessage} -

-
-
- +
+
+
 
+
+
+ +
+
+

+ Error: {this.state.errorMessage} +

+
+
+ +
- +
 
-
 
- -
- {/* initial load mask*/} -
-
-
-
- -
- - Loading... - -
-
+ {/* Reloading mask */} -
-
- -
-
- +
+
+
+
+ +
+ + { + this.state.displayState === State.Loading ? + "Loading..." + :this.getReloadingMessage() + } +
- - {this.getReloadingMessage()} -
-
- +
+ ); } }); diff --git a/react/src/Pedalboard.tsx b/react/src/Pedalboard.tsx index 414d060..f1d6faf 100644 --- a/react/src/Pedalboard.tsx +++ b/react/src/Pedalboard.tsx @@ -206,6 +206,7 @@ export class PedalboardItem implements Deserializable { 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; diff --git a/src/AudioHost.cpp b/src/AudioHost.cpp index 0e559b4..f909380 100644 --- a/src/AudioHost.cpp +++ b/src/AudioHost.cpp @@ -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 inputControlValues; std::vector pathPatchProperties; }; diff --git a/src/AvahiService.cpp b/src/AvahiService.cpp index 02f54cc..b56d432 100644 --- a/src/AvahiService.cpp +++ b/src/AvahiService.cpp @@ -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)); diff --git a/src/ConfigMain.cpp b/src/ConfigMain.cpp index 9c953ca..6b5e159 100644 --- a/src/ConfigMain.cpp +++ b/src/ConfigMain.cpp @@ -155,6 +155,49 @@ void DisableService() #endif } +bool disableAvahiConfigLine(SystemConfigFile &avahi, const std::string §ion, 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 \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_) { diff --git a/src/Lv2Effect.hpp b/src/Lv2Effect.hpp index 2fed630..a85e5ae 100644 --- a/src/Lv2Effect.hpp +++ b/src/Lv2Effect.hpp @@ -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) diff --git a/src/Pedalboard.cpp b/src/Pedalboard.cpp index 5349a96..77a334a 100644 --- a/src/Pedalboard.cpp +++ b/src/Pedalboard.cpp @@ -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::vectoruri() == 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 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; } diff --git a/src/Pedalboard.hpp b/src/Pedalboard.hpp index 7e67f67..9ae3565 100644 --- a/src/Pedalboard.hpp +++ b/src/Pedalboard.hpp @@ -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::vectorGetAllPlugins(); 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) diff --git a/src/PiPedalModel.cpp b/src/PiPedalModel.cpp index e1d46e3..8860bfe 100644 --- a/src/PiPedalModel.cpp +++ b/src/PiPedalModel.cpp @@ -535,23 +535,17 @@ void PiPedalModel::SetPedalboard(int64_t clientId, Pedalboard &pedalboard) void PiPedalModel::SetSnapshot(int64_t selectedSnapshot) { std::lock_guard 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> &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) diff --git a/src/SplitEffect.cpp b/src/SplitEffect.cpp index cf06c7e..2f2dcc7 100644 --- a/src/SplitEffect.cpp +++ b/src/SplitEffect.cpp @@ -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()) diff --git a/src/SplitEffect.hpp b/src/SplitEffect.hpp index e408a0e..b85fdc2 100644 --- a/src/SplitEffect.hpp +++ b/src/SplitEffect.hpp @@ -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 { diff --git a/todo.txt b/todo.txt index 8dc7b59..ffdaf18 100644 --- a/todo.txt +++ b/todo.txt @@ -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.