From 632b96eeffd2b2eec07de893be67e17a0a26c490 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Mon, 14 Oct 2024 16:12:32 -0400 Subject: [PATCH 1/4] Update-to-same version dialog immediately after updating. --- src/Updater.cpp | 51 ++++++++++++++++++++++++++++++++++++------- src/UpdaterStatus.hpp | 13 ++++++++--- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/Updater.cpp b/src/Updater.cpp index 18c0db6..9b64974 100644 --- a/src/Updater.cpp +++ b/src/Updater.cpp @@ -68,7 +68,7 @@ public: virtual void SetUpdatePolicy(UpdatePolicyT updatePolicy) override; virtual void ForceUpdateCheck() override; virtual void DownloadUpdate(const std::string &url, std::filesystem::path *file, std::filesystem::path *signatureFile) override; - virtual UpdateStatus GetCurrentStatus() const override { return this->currentResult; } + virtual UpdateStatus GetCurrentStatus() const override; virtual UpdateStatus GetReleaseGeneratorStatus() override; private: @@ -156,7 +156,7 @@ UpdateStatus UpdaterImpl::GetCachedUpdateStatus() reader.read(&status); // cached curruent version might come from a different version. - status.ResetCurrentVersion(); + status.UpdateForCurrentVersion(); return status; } } @@ -416,6 +416,36 @@ static int compareVersions(const std::string &l, const std::string &r) } return 0; } + +void UpdateRelease::UpdateForCurrentVersion(const std::string¤tVersion) +{ + if (compareVersions(currentVersion,this->UpgradeVersion()) >= 0) + { + this->updateAvailable_ = false; + } +} + +bool UpdateStatus::UpdateAvailable() const +{ + if (!isValid_) return false; + + switch (this->UpdatePolicy()) + { + case UpdatePolicyT::Development: + return this->devRelease_.UpdateAvailable(); + break; + case UpdatePolicyT::ReleaseOnly: + return this->releaseOnlyRelease_.UpdateAvailable(); + case UpdatePolicyT::ReleaseOrBeta: + this->releaseOrBetaRelease_.UpdateAvailable(); + default: + case UpdatePolicyT::Disabled: + return false; + } + +} + + static std::string normalizeReleaseName(const std::string &releaseName) { // e.g. "PiPedal 1.2.34 Release" -> "PiPedal v1.2.34-Release" @@ -897,16 +927,20 @@ UpdateStatus::UpdateStatus() #endif } -void UpdateStatus::ResetCurrentVersion() +void UpdateStatus::UpdateForCurrentVersion() { currentVersion_ = PROJECT_VER; currentVersionDisplayName_ = PROJECT_DISPLAY_VERSION; -#ifdef TEST_UPDATE +#if defined(TEST_UPDATE) && defined(DEBUG) // uncomment this line to test upgrading. currentVersion_ = "1.2.39"; - currentVersionDisplayName_ = "PiPedal 1.2.39-Debug"; + currentVersionDisplayName_ = "PiPedal 1.2.39-Fictional"; #endif + + this->devRelease_.UpdateForCurrentVersion(currentVersion_);; + this->releaseOnlyRelease_.UpdateForCurrentVersion(currentVersion_); + this->releaseOrBetaRelease_.UpdateForCurrentVersion(currentVersion_); } std::chrono::system_clock::time_point UpdateStatus::LastUpdateTime() const @@ -953,9 +987,6 @@ const GithubAsset *GithubRelease::GetDownloadForCurrentArchitecture() const return nullptr; } -UpdateRelease::UpdateRelease() -{ -} std::string UpdaterImpl::GetSignatureUrl(const std::string &url) { @@ -1327,6 +1358,10 @@ void UpdaterImpl::DownloadUpdate(const std::string &url, std::filesystem::path * } } +UpdateStatus UpdaterImpl::GetCurrentStatus() const { + return this->currentResult; +} + void UpdateStatus::AddRelease(const std::string&packageName) { diff --git a/src/UpdaterStatus.hpp b/src/UpdaterStatus.hpp index 4d50326..f4acf1c 100644 --- a/src/UpdaterStatus.hpp +++ b/src/UpdaterStatus.hpp @@ -22,7 +22,9 @@ #include "json.hpp" namespace pipedal { - enum class UpdatePolicyT + class UpdateStatus; + + enum class UpdatePolicyT { // ordinal values must not change, as files depend on them. // must match declaration in Updater.tsx @@ -37,14 +39,15 @@ namespace pipedal { { private: friend class UpdaterImpl; + friend class UpdateStatus; bool updateAvailable_ = false; std::string upgradeVersion_; // just the version. std::string upgradeVersionDisplayName_; // display name for the version. std::string assetName_; // filename only std::string updateUrl_; // url from which to download the .deb file. std::string gpgSignatureUrl_; // url from which to download the .deb.asc file. + void UpdateForCurrentVersion(const std::string¤tVersion); public: - UpdateRelease(); bool UpdateAvailable() const { return updateAvailable_; } const std::string &UpgradeVersion() const { return upgradeVersion_; } @@ -78,8 +81,12 @@ namespace pipedal { std::chrono::system_clock::time_point LastUpdateTime() const; void LastUpdateTime(const std::chrono::system_clock::time_point &timePoint); - void ResetCurrentVersion(); + + void UpdateForCurrentVersion(); bool IsValid() const { return isValid_; } + + bool UpdateAvailable() const; + const std::string &ErrorMessage() const { return errorMessage_; } bool IsOnline() const { return isOnline_; } const std::string &CurrentVersion() const { return currentVersion_; } From bfbe9a5fa427ddc47b12cd278f00b5c610656087 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Mon, 14 Oct 2024 19:54:42 -0400 Subject: [PATCH 2/4] File property directories with '.' in name. --- react/src/FilePropertyDialog.tsx | 60 ++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/react/src/FilePropertyDialog.tsx b/react/src/FilePropertyDialog.tsx index 7fdeecc..c387b8f 100644 --- a/react/src/FilePropertyDialog.tsx +++ b/react/src/FilePropertyDialog.tsx @@ -33,6 +33,7 @@ import AudioFileIcon from '@mui/icons-material/AudioFile'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import FolderIcon from '@mui/icons-material/Folder'; import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; import DialogActions from '@mui/material/DialogActions'; import DialogTitle from '@mui/material/DialogTitle'; import DialogContent from '@mui/material/DialogContent'; @@ -60,6 +61,32 @@ const styles = (theme: Theme) => createStyles({ }, }); +const audioFileExtensions: {[name: string]: boolean} = { + ".wav": true, + ".flac": true, + ".ogg": true, + ".aac": true, + ".au": true, + ".snd": true, + ".mid": true, + ".rmi": true, + ".mp3": true, + ".mp4": true, + ".aif": true, + ".aifc": true, + ".aiff": true, + ".ra": true +}; + +function isAudioFile(filename: string) { + let npos = filename.lastIndexOf('.'); + let nposSlash = filename.lastIndexOf('/'); + if (nposSlash >= npos) { + return false; + } + let extension = filename.substring(npos); + return audioFileExtensions[extension] !== undefined; +} export interface FilePropertyDialogProps extends WithStyles { open: boolean, @@ -470,6 +497,25 @@ export default withStyles(styles, { withTheme: true })( } return result; } + private getIcon(fileEntry: FileEntry) + { + if (fileEntry.filename === "") + { + return (); + } + if (fileEntry.isDirectory) + { + return ( + + ); + } + if (isAudioFile(fileEntry.filename)) + { + return (); + } + return (); + } + render() { let classes = this.props.classes; let columnWidth = this.state.columnWidth; @@ -571,12 +617,11 @@ export default withStyles(styles, { withTheme: true })( (this.state.columns !== 0) && // don't render until we have number of columns derived from layout. this.state.fileEntries.map( (value: FileEntry, index: number) => { - let isDefault = this.props.fileProperty.directory.startsWith("default"); let displayValue = value.filename; if (displayValue === "") { displayValue = ""; } else { - if (isDefault) + if (value.isDirectory) { displayValue = pathFileName(displayValue); } else { @@ -601,14 +646,7 @@ export default withStyles(styles, { withTheme: true })( >
- {value.filename === "" ? - () - : ( - value.isDirectory ? ( - - ) : ( - - ))} + {this.getIcon(value)} {displayValue}
@@ -725,7 +763,7 @@ export default withStyles(styles, { withTheme: true })( } openSelectedFile(): void { if (this.isDirectory(this.state.selectedFile)) { - let directoryName = pathFileNameOnly(this.state.selectedFile); + let directoryName = pathFileName(this.state.selectedFile); let navDirectory = pathConcat(this.state.navDirectory, directoryName); this.requestFiles(navDirectory); this.setState({ navDirectory: navDirectory }); From 0950ec496f978f370865c9dcc51cf15cf3ef918a Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Mon, 14 Oct 2024 19:55:28 -0400 Subject: [PATCH 3/4] pipedalProfilePlugin - report lv1 cache misses. --- .vscode/launch.json | 32 +++++++ install.sh | 3 + src/ArmPerformanceCounters.hpp | 147 +++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 19 +++-- src/profilePluginMain.cpp | 89 ++++++++++++++++---- 5 files changed, 268 insertions(+), 22 deletions(-) create mode 100644 src/ArmPerformanceCounters.hpp diff --git a/.vscode/launch.json b/.vscode/launch.json index 7b833ab..98ec492 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -205,6 +205,38 @@ } ] }, + { + "name": "(gdb) pipedalProfilePlugin", + "type": "cppdbg", + "request": "launch", + // Resolved by CMake Tools: + "program": "${command:cmake.launchTargetPath}", + + "args": [ "--no-profile", "-w", "TooB NAM"], + + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [ + { + "name": "PATH", + "value": "$PATH:${command:cmake.launchTargetDirectory}" + }, + { + "name": "OTHER_VALUE", + "value": "Something something" + } + ], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + { "name": "(gdb) processCopyrights Launch", diff --git a/install.sh b/install.sh index 620618d..8c249ea 100755 --- a/install.sh +++ b/install.sh @@ -3,3 +3,6 @@ cmake --install build --prefix /usr --config Release -v # Done as an install action by the debian package. sudo /usr/bin/pipedalconfig --install +# copy pipedalPluginProfile as well. +sudo cp build/src/pipedalProfilePlugin /usr/bin/pipedalProfilePlugin +chmod +X /usr/bin/pipedalProfilePlugin diff --git a/src/ArmPerformanceCounters.hpp b/src/ArmPerformanceCounters.hpp new file mode 100644 index 0000000..8437dc8 --- /dev/null +++ b/src/ArmPerformanceCounters.hpp @@ -0,0 +1,147 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pipedal +{ + class CacheMissCounter + { + private: + int fd_l1; + int fd_l2; + bool affinity_set = false; + cpu_set_t original_cpu_set; + + static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, + int cpu, int group_fd, unsigned long flags) + { + return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); + } + + void setup_counter(int &fd, uint64_t config, const std::string &name) + { + struct perf_event_attr pe; + memset(&pe, 0, sizeof(struct perf_event_attr)); + pe.type = PERF_TYPE_HW_CACHE; + pe.size = sizeof(struct perf_event_attr); + pe.config = config; + pe.disabled = 1; + pe.exclude_kernel = 1; + pe.exclude_hv = 1; + + fd = perf_event_open(&pe, 0, -1, -1, 0); + } + + public: + CacheMissCounter() : fd_l1(-1), fd_l2(-1) + { + uint64_t l1_config = (PERF_COUNT_HW_CACHE_L1D << 0) | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16); + uint64_t l2_config = (PERF_COUNT_HW_CACHE_LL << 0) | + (PERF_COUNT_HW_CACHE_OP_READ << 8) | + (PERF_COUNT_HW_CACHE_RESULT_MISS << 16); + + setup_counter(fd_l1, l1_config, "L1"); + setup_counter(fd_l2, l2_config, "L2"); + + int32_t cpu = 1; + if (cpu >= 0) + { + if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &original_cpu_set) != 0) + { + throw std::runtime_error("Failed to get thread affinity"); + } + + cpu_set_t cpu_set; + CPU_ZERO(&cpu_set); + CPU_SET(cpu, &cpu_set); + if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu_set) != 0) + { + throw std::runtime_error("Failed to set thread affinity"); + } + affinity_set = true; + } + } + + ~CacheMissCounter() + { + if (fd_l1 != -1) + close(fd_l1); + if (fd_l2 != -1) + close(fd_l2); + if (affinity_set) + { + pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &original_cpu_set); + } + } + + void start() + { + ioctl(fd_l1, PERF_EVENT_IOC_RESET, 0); + ioctl(fd_l2, PERF_EVENT_IOC_RESET, 0); + ioctl(fd_l1, PERF_EVENT_IOC_ENABLE, 0); + ioctl(fd_l2, PERF_EVENT_IOC_ENABLE, 0); + } + + void stop() + { + ioctl(fd_l1, PERF_EVENT_IOC_DISABLE, 0); + ioctl(fd_l2, PERF_EVENT_IOC_DISABLE, 0); + } + + long long get_l1_misses() + { + long long count; + read(fd_l1, &count, sizeof(long long)); + return count; + } + + long long get_l2_misses() + { + if (fd_l2 == -1) + { + return -1; + } + long long count; + read(fd_l2, &count, sizeof(long long)); + return count; + } + }; + + // // Example usage + // int main() { + // try { + // CacheMissCounter counter; + + // counter.start(); + + // // Your code to measure goes here + // // For example, let's do some memory operations + // volatile int* array = new int[1000000]; + // for (int i = 0; i < 1000000; i++) { + // array[i] = i; + // } + // delete[] array; + + // counter.stop(); + + // std::cout << "L1 cache misses: " << counter.get_l1_misses() << std::endl; + // std::cout << "L2 cache misses: " << counter.get_l2_misses() << std::endl; + + // } catch (const std::exception& e) { + // std::cerr << "Error: " << e.what() << std::endl; + // return 1; + // } + + // return 0; + // } +} \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6c17cd..d753aaf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -134,6 +134,9 @@ if (ENABLE_BACKTRACE) endif() + + + # message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") # set(CMAKE_ENABLE_EXPORTS 1) @@ -351,15 +354,19 @@ set_target_properties(pipedaltest PROPERTIES EXCLUDE_FROM_ALL true) if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action servers. - add_executable(profilePlugin - profilePluginMain.cpp - ) - target_link_libraries(profilePlugin PRIVATE profiler ${PIPEDAL_LIBS}) - target_include_directories(profilePlugin PRIVATE ${PIPEDAL_INCLUDES} + add_executable(pipedalProfilePlugin + profilePluginMain.cpp ArmPerformanceCounters.hpp ) + target_link_libraries(pipedalProfilePlugin PRIVATE profiler ${PIPEDAL_LIBS}) + + target_include_directories(pipedalProfilePlugin PRIVATE ${PIPEDAL_INCLUDES} + ) + if (${DEBIAN_ARCHITECTURE} MATCHES arm64) + target_compile_definitions(pipedalProfilePlugin PRIVATE "PIPEDAL_AARCH64") + endif() + - set_target_properties(profilePlugin PROPERTIES EXCLUDE_FROM_ALL true) endif() add_executable(jsonTest diff --git a/src/profilePluginMain.cpp b/src/profilePluginMain.cpp index e75eff4..d3a012c 100644 --- a/src/profilePluginMain.cpp +++ b/src/profilePluginMain.cpp @@ -6,9 +6,11 @@ #include "CommandLineParser.hpp" #include #include +#include "ss.hpp" // apt install google-perftools #include +#include "ArmPerformanceCounters.hpp" using namespace pipedal; using namespace std; @@ -79,6 +81,7 @@ private: struct ProfileOptions { std::string presetName; + std::string presetFileName; float benchmark_seconds = 20; std::string outputFilename = "/tmp/profilePlugin.perf"; bool noProfile = false; @@ -88,6 +91,11 @@ struct ProfileOptions void profilePlugin(const ProfileOptions &profileOptions) { + +#ifdef PIPEDAL_AARCH64 + CacheMissCounter cacheMissCounter; +#endif + size_t nFrames = profileOptions.frameSize; Lv2Log::log_level(LogLevel::Info); @@ -113,25 +121,54 @@ void profilePlugin(const ProfileOptions &profileOptions) // model.Load(); don't start audio. /* *** Load the preset. */ - PresetIndex presetIndex; - model.GetPresets(&presetIndex); - int64_t presetIndexId = 0; - bool presetIndexFound = false; - for (const auto &preset : presetIndex.presets()) + bool presetValid = false; + + if (profileOptions.presetName.length() != 0) { - if (preset.name() == profileOptions.presetName) + PresetIndex presetIndex; + model.GetPresets(&presetIndex); + + int64_t presetIndexId = 0; + bool presetIndexFound = false; + for (const auto &preset : presetIndex.presets()) { - presetIndexId = preset.instanceId(); - presetIndexFound = true; - break; + if (preset.name() == profileOptions.presetName) + { + presetIndexId = preset.instanceId(); + presetIndexFound = true; + break; + } + } + if (!presetIndexFound) + { + throw std::runtime_error("Preset not found."); + } + model.LoadPreset(-1, presetIndexId); + } + else if (profileOptions.presetFileName.length() != 0) + { + std::ifstream f(profileOptions.presetFileName); + if (!f.is_open()) + { + throw std::runtime_error(SS("Unable to load preset file " << profileOptions.presetFileName << ".")); + } + try + { + json_reader reader(f); + Pedalboard pedalboard; + reader.read(&pedalboard); + model.SetPedalboard(-1, pedalboard); + } + catch (const std::exception &e) + { + throw std::runtime_error(SS("Invalid file format: " << profileOptions.presetFileName << ".")); } } - if (!presetIndexFound) + else { - throw std::runtime_error("Preset not found."); + throw std::runtime_error("You must specify either a preset name or a preset file."); } - model.LoadPreset(-1, presetIndexId); auto pedalboard = model.GetCurrentPedalboardCopy(); cout << "uri: " << pedalboard.items()[0].uri() << endl; @@ -153,7 +190,6 @@ void profilePlugin(const ProfileOptions &profileOptions) RingBufferSink ringBufferSink(writerRingbuffer); - // run once to get memory allocations in NAM and ML out of the way. lv2Pedalboard->Run(inputBuffers, outputBuffers, nFrames, &ringBufferWriter); @@ -184,6 +220,10 @@ void profilePlugin(const ProfileOptions &profileOptions) { ProfilerStart(profileOptions.outputFilename.c_str()); } +#ifdef PIPEDAL_AARCH64 + cacheMissCounter.start(); +#endif + auto startTime = std::chrono::system_clock::now(); size_t repetitions = static_cast(48000 * profileOptions.benchmark_seconds / nFrames); @@ -193,12 +233,21 @@ void profilePlugin(const ProfileOptions &profileOptions) } auto elapsedTime = std::chrono::high_resolution_clock::now() - startTime; + +#ifdef PIPEDAL_AARCH64 + cacheMissCounter.stop(); +#endif if (!profileOptions.noProfile) { ProfilerStop(); } std::chrono::milliseconds us = std::chrono::duration_cast(elapsedTime); std::cout << "Ellapsed time: " << (us.count() / 1000.0) << "s" << endl; +#ifdef PIPEDAL_AARCH64 + std::cout << "L1 Cache Misses: " << cacheMissCounter.get_l1_misses() << endl; + // non-functional on Raspberry PI OS. + // std::cout << "L2 Cache Misses: " << cacheMissCounter.get_l2_misses() << endl; +#endif ringBufferSink.Close(); @@ -212,8 +261,10 @@ int main(int argc, char **argv) ProfileOptions profileOptions; bool help = false; CommandLineParser commandLineParser; + std::string presetFileName; commandLineParser.AddOption("w", "wait-for-work", &profileOptions.waitForWork); commandLineParser.AddOption("", "no-profile", &profileOptions.noProfile); + commandLineParser.AddOption("p", "preset-file", &presetFileName); commandLineParser.AddOption("o", "output", &profileOptions.outputFilename); commandLineParser.AddOption("s", "seconds", &profileOptions.benchmark_seconds); commandLineParser.AddOption("h", "help", &help); @@ -225,7 +276,7 @@ int main(int argc, char **argv) cout << "profilePlugin - Generate profiling data for LV2 Plugins" << endl; cout << "Copyright (c) 2024 Robin E. R. Davies" << endl; cout << endl; - cout << "Syntax: profilePlugin preset_name [options...]" << endl; + cout << "Syntax: profilePlugin [preset_name] [options...]" << endl; cout << " where preset_name is the name of a PiPedal preset." << endl; cout << endl; cout << " A google-perf profile capture will be written to " << endl; @@ -234,6 +285,8 @@ int main(int argc, char **argv) cout << "Options:" << endl; cout << " --no-profile:" << endl; cout << " do NOT generate a perf file." << endl; + cout << " -p, --preset-file filename:" << endl; + cout << " Load the specified preset file. " << endl; cout << " -o, --output filename:" << endl; cout << " The file to which profiler data is written. " << endl; cout << " Defaults to /tmp/profilePlugin.perf" << endl; @@ -241,12 +294,16 @@ int main(int argc, char **argv) cout << " Assume that the plugin will load data on the LV2 scheduler thread." << endl; cout << " -s, --seconds time_in_seconds: " << endl; cout << " The number of seconds of audio to process." << endl; - cout << " -h, --help: display this message." << endl; + cout << " -h, --help: display this message." << endl; cout << endl; return help ? EXIT_SUCCESS : EXIT_FAILURE; } - profileOptions.presetName = commandLineParser.Arguments()[0]; + if (commandLineParser.Arguments().size() == 1) + { + profileOptions.presetName = commandLineParser.Arguments()[0]; + } + profileOptions.presetFileName = presetFileName; profilePlugin(profileOptions); } From 8704580289bae3022372ce4416f9b25291a17438 Mon Sep 17 00:00:00 2001 From: Robin Davies Date: Wed, 16 Oct 2024 09:18:19 -0400 Subject: [PATCH 4/4] funding.json --- .vscode/launch.json | 6 +- docs/.well-known/funding-manifest-urls | 4 ++ docs/funding.json | 83 ++++++++++++++++++++++++++ src/profilePluginMain.cpp | 25 ++++++-- 4 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 docs/.well-known/funding-manifest-urls create mode 100644 docs/funding.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 98ec492..89fa735 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -212,7 +212,11 @@ // Resolved by CMake Tools: "program": "${command:cmake.launchTargetPath}", - "args": [ "--no-profile", "-w", "TooB NAM"], + "args": [ + "--no-profile", "-w", + // "TooB NAM" + "--preset-file", "/tmp/namPreset.preset" + ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/docs/.well-known/funding-manifest-urls b/docs/.well-known/funding-manifest-urls new file mode 100644 index 0000000..a212e0f --- /dev/null +++ b/docs/.well-known/funding-manifest-urls @@ -0,0 +1,4 @@ +https://rerdavies.github.io/pipedal/funding.json +https://github.com/rerdavies/ToobAmp +https://github.com/rerdavies/pipedal +https://github.com/sponsors/rerdavies \ No newline at end of file diff --git a/docs/funding.json b/docs/funding.json new file mode 100644 index 0000000..7d354e7 --- /dev/null +++ b/docs/funding.json @@ -0,0 +1,83 @@ +{ + "version": "v1.0.0", + "entity": { + "type": "individual", + "role": "maintainer", + "name": "Robin E. R. Davies", + "email": "rerdavies@gmail.com", + "phone": "1-613-857-8382", + "description": "I'm a developer, and jazz musician, interested in developing Raspbery Pi software for use in live performance.\n\nPiPedal started as a pandemic project, to see if I could build what I wanted to use when I perform. It has since grown into something beautiful and true, so I would like to make it available for everyone.", + "webpageUrl": { + "url": "https://github.com/rerdavies", + "wellKnown": "https://github.com/rerdavies/pipedal/blob/master/docs/.well-known/funding-manifest-urls" + } + }, + "projects": [{ + "guid": "com-twoplay-pipedal", + "name": "The PiPedal Project", + "description": "PiPedal is a guitar stomp box that runs on a Raspberry Pi (Raspberry Pi 4 or later). PiPedal is controlled remotely via a web application, or using the Android PiPedal Remote app.\n\nPipedal's user interface has been specifically designed with Phone and Tablet user interfaces in mind. Clip your phone or tablet onto a microphone stand, plugin your Raspberry Pi, and you're set to play!\n\nPiPedal started as Pandemic Project. I spent two years developing PiPedal full time during the pandemic. I would very much like to continue working on it full time, but I need your help to do so.", + "webpageUrl": { + "url": "https://rerdavies.github.io/pipedal/", + "wellKnown": "https://rerdavies.github.io/pipedal/.well-known/funding-manifest-urls" + }, + "repositoryUrl": { + "url": "https://github.com/rerdavies/pipedal", + "wellKnown": "https://github.com/rerdavies/pipedal/blob/master/docs/.well-known/funding-manifest-urls" + }, + "licenses": ["spdx:MIT"], + "tags": ["audio", "effects-pedal", "guitar", "raspberry-pi", "lv2-plugin"] + }], + "funding": { + "channels": [ + { + "guid": "mybank", + "type": "bank", + "address": "", + "description": "Will accept direct bank transfers. Please e-mail me for details." + }, + { + "guid": "github-sponsors", + "type": "payment-provider", + "address": "https://github.com/sponsors/rerdavies", + "description": "Pay with your debit/credit card through through GitHub Sponsors, or set up a monthly payment play.." + } + ], + "plans": [ + { + "guid": "hosting-monthly", + "status": "active", + "name": "Hosting support", + "description": "This will cover the monthly server hosting costs for the projects.", + "amount": 60, + "currency": "USD", + "frequency": "monthly", + "channels": ["mybank","github-sponsors"] + }, + { + "guid": "developer-time", + "status": "active", + "name": "Developer compensation", + "description": "This will cover the cost of one developer working full-time on the projects.", + "amount": 2000, + "currency": "USD", + "frequency": "monthly", + "channels": ["mybank","github-sponsors"] + }, + { + "guid": "angel-plan", + "status": "active", + "name": "Goodwill plan", + "description": "Pay anything you wish to show your goodwill for the project.", + "amount": 0, + "currency": "USD", + "frequency": "one-time", + "channels": ["mybank", "github-sponsors"] + } + ], + "history": [ + {"year": 2022, "income": 0, "expenses": 0, "taxes": 0, "currency": "USD", "description": ""}, + {"year": 2023, "income": 0, "expenses": 0, "taxes": 0, "currency": "USD", "description": ""}, + {"year": 2024, "income": 47.00, "expenses": 0, "taxes": 0, "currency": "USD", "description": ""} + ] + } +} \ No newline at end of file diff --git a/src/profilePluginMain.cpp b/src/profilePluginMain.cpp index d3a012c..7c04c20 100644 --- a/src/profilePluginMain.cpp +++ b/src/profilePluginMain.cpp @@ -101,6 +101,7 @@ void profilePlugin(const ProfileOptions &profileOptions) /*** Initialize the model */ PiPedalModel model; + Lv2Log::log_level(LogLevel::Error); fs::path doc_root = "/etc/pipedal/config"; PiPedalConfiguration configuration; try @@ -156,13 +157,18 @@ void profilePlugin(const ProfileOptions &profileOptions) try { json_reader reader(f); - Pedalboard pedalboard; - reader.read(&pedalboard); - model.SetPedalboard(-1, pedalboard); + BankFile bankFile; + reader.read(&bankFile); + if (bankFile.presets().size() != 1) + { + throw new std::runtime_error(SS("Invalid preset file. Expection one preset, but " << bankFile.presets().size() << " presets were found.")); + } + Pedalboard pedalboard = (bankFile.presets()[0]->preset()); + model.SetPedalboard(-1,pedalboard); } catch (const std::exception &e) { - throw std::runtime_error(SS("Invalid file format: " << profileOptions.presetFileName << ".")); + throw std::runtime_error(SS("Invalid file format: " << profileOptions.presetFileName << ". " << e.what() )); } } else @@ -271,7 +277,14 @@ int main(int argc, char **argv) commandLineParser.Parse(argc, (const char **)argv); - if (commandLineParser.Arguments().size() != 1 || help) + bool argumentError = false; + if (commandLineParser.Arguments().size() == 1 && presetFileName.length() == 0) + { + cerr << "Error: You must supply either a preset name, or a preset file name" << endl; + argumentError = true; + } + + if (argumentError || help) { cout << "profilePlugin - Generate profiling data for LV2 Plugins" << endl; cout << "Copyright (c) 2024 Robin E. R. Davies" << endl; @@ -299,7 +312,7 @@ int main(int argc, char **argv) return help ? EXIT_SUCCESS : EXIT_FAILURE; } - if (commandLineParser.Arguments().size() == 1) + if (commandLineParser.Arguments().size() != 0) { profileOptions.presetName = commandLineParser.Arguments()[0]; }