Fix fiile uploads for Toob ML and Toob Convolution Reversbs.

This commit is contained in:
Robin E. R. Davies
2024-11-22 15:58:08 -05:00
parent 33dc523ae3
commit 1c071ba7f3
13 changed files with 150 additions and 53 deletions
+17 -9
View File
@@ -32,7 +32,7 @@ import Button from '@mui/material/Button';
import FileUploadIcon from '@mui/icons-material/FileUpload'; import FileUploadIcon from '@mui/icons-material/FileUpload';
import AudioFileIcon from '@mui/icons-material/AudioFile'; import AudioFileIcon from '@mui/icons-material/AudioFile';
import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import FolderIcon from '@mui/icons-material/Folder'; import FolderOutlinedIcon from '@mui/icons-material/FolderOutlined';
import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined'; import InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import DialogActions from '@mui/material/DialogActions'; import DialogActions from '@mui/material/DialogActions';
@@ -105,6 +105,7 @@ export interface FilePropertyDialogState {
canDelete: boolean; canDelete: boolean;
fileResult: FileRequestResult; fileResult: FileRequestResult;
navDirectory: string; navDirectory: string;
uploadDirectory: string;
isProtectedDirectory: boolean; isProtectedDirectory: boolean;
columns: number; columns: number;
columnWidth: number; columnWidth: number;
@@ -187,12 +188,14 @@ export default withStyles(styles, { withTheme: true })(
this.model = PiPedalModelFactory.getInstance(); this.model = PiPedalModelFactory.getInstance();
let selectedFile = props.selectedFile;
this.state = { this.state = {
fullScreen: this.getFullScreen(), fullScreen: this.getFullScreen(),
selectedFile: props.selectedFile, selectedFile: selectedFile,
selectedFileProtected: true, selectedFileProtected: true,
selectedFileIsDirectory: false, selectedFileIsDirectory: false,
navDirectory: this.getNavDirectoryFromFile(props.selectedFile, props.fileProperty), navDirectory: this.getNavDirectoryFromFile(selectedFile, props.fileProperty),
uploadDirectory: "",
hasSelection: false, hasSelection: false,
canDelete: false, canDelete: false,
columns: 0, columns: 0,
@@ -256,7 +259,8 @@ export default withStyles(styles, { withTheme: true })(
fileResult: filesResult, fileResult: filesResult,
hasSelection: !!fileEntry, hasSelection: !!fileEntry,
selectedFileProtected: fileEntry ? fileEntry.isProtected: true, selectedFileProtected: fileEntry ? fileEntry.isProtected: true,
navDirectory: navPath navDirectory: navPath,
uploadDirectory: filesResult.currentDirectory
}); });
} }
}).catch((error) => { }).catch((error) => {
@@ -300,6 +304,8 @@ export default withStyles(styles, { withTheme: true })(
componentDidMount() { componentDidMount() {
super.componentDidMount(); super.componentDidMount();
this.mounted = true; this.mounted = true;
this.requestFiles(this.state.navDirectory)
this.requestScroll = true;
} }
componentWillUnmount() { componentWillUnmount() {
super.componentWillUnmount(); super.componentWillUnmount();
@@ -310,14 +316,16 @@ export default withStyles(styles, { withTheme: true })(
super.componentDidUpdate?.(prevProps, prevState, snapshot); super.componentDidUpdate?.(prevProps, prevState, snapshot);
if (prevProps.open !== this.props.open || prevProps.fileProperty !== this.props.fileProperty || prevProps.selectedFile !== this.props.selectedFile) { if (prevProps.open !== this.props.open || prevProps.fileProperty !== this.props.fileProperty || prevProps.selectedFile !== this.props.selectedFile) {
if (this.props.open) { if (this.props.open) {
let navDirectory = this.getNavDirectoryFromFile(this.props.selectedFile, this.props.fileProperty); let selectedFile = this.props.selectedFile;
let navDirectory = this.getNavDirectoryFromFile(selectedFile, this.props.fileProperty);
this.setState({ this.setState({
selectedFile: this.props.selectedFile, selectedFile: selectedFile,
selectedFileIsDirectory: false, selectedFileIsDirectory: false,
selectedFileProtected: true, selectedFileProtected: true,
newFolderDialogOpen: false, newFolderDialogOpen: false,
renameDialogOpen: false, renameDialogOpen: false,
moveDialogOpen: false moveDialogOpen: false,
navDirectory: navDirectory
}); });
this.requestFiles(navDirectory) this.requestFiles(navDirectory)
this.requestScroll = true; this.requestScroll = true;
@@ -549,7 +557,7 @@ export default withStyles(styles, { withTheme: true })(
} }
if (fileEntry.isDirectory) { if (fileEntry.isDirectory) {
return ( return (
<FolderIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} /> <FolderOutlinedIcon style={{ flex: "0 0 auto", opacity: 0.7, marginRight: 8, marginLeft: 8 }} />
); );
} }
if (isAudioFile(fileEntry.pathname)) { if (isAudioFile(fileEntry.pathname)) {
@@ -741,7 +749,7 @@ export default withStyles(styles, { withTheme: true })(
} }
} }
uploadPage={ uploadPage={
"uploadUserFile?directory=" + encodeURIComponent(this.state.navDirectory) "uploadUserFile?directory=" + encodeURIComponent(this.state.uploadDirectory)
+ "&ext=" + "&ext="
+ encodeURIComponent(this.getFileExtensionList(this.props.fileProperty)) + encodeURIComponent(this.getFileExtensionList(this.props.fileProperty))
} }
+1
View File
@@ -99,6 +99,7 @@ export class FileRequestResult {
files: FileEntry[] = []; files: FileEntry[] = [];
isProtected: boolean = false; isProtected: boolean = false;
breadcrumbs: BreadcrumbEntry[] = []; breadcrumbs: BreadcrumbEntry[] = [];
currentDirectory: string = "";
}; };
export type PluginPresetsChangedHandler = (pluginUri: string) => void; export type PluginPresetsChangedHandler = (pluginUri: string) => void;
+32 -29
View File
@@ -23,7 +23,7 @@ import { WithStyles } from '@mui/styles';
import createStyles from '@mui/styles/createStyles'; import createStyles from '@mui/styles/createStyles';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
import { UiPlugin, UiControl, UiFileProperty,UiFrequencyPlot, ScalePoint } from './Lv2Plugin'; import { UiPlugin, UiControl, UiFileProperty, UiFrequencyPlot, ScalePoint } from './Lv2Plugin';
import { import {
Pedalboard, PedalboardItem, ControlValue Pedalboard, PedalboardItem, ControlValue
} from './Pedalboard'; } from './Pedalboard';
@@ -247,8 +247,7 @@ type PluginControlViewState = {
const PluginControlView = const PluginControlView =
withStyles(styles, { withTheme: true })( withStyles(styles, { withTheme: true })(
class extends ResizeResponsiveComponent<PluginControlViewProps, PluginControlViewState> class extends ResizeResponsiveComponent<PluginControlViewProps, PluginControlViewState> {
{
model: PiPedalModel; model: PiPedalModel;
constructor(props: PluginControlViewProps) { constructor(props: PluginControlViewProps) {
@@ -526,7 +525,7 @@ const PluginControlView =
return false; return false;
} }
controlKeyIndex : number = 0; controlKeyIndex: number = 0;
controlNodesToNodes(nodes: (ReactNode | ControlGroup)[]): ReactNode[] { controlNodesToNodes(nodes: (ReactNode | ControlGroup)[]): ReactNode[] {
let classes = this.props.classes; let classes = this.props.classes;
let isLandscapeGrid = this.state.landscapeGrid; let isLandscapeGrid = this.state.landscapeGrid;
@@ -543,7 +542,7 @@ const PluginControlView =
let item = controlGroup.controls[j]; let item = controlGroup.controls[j];
controls.push( controls.push(
( (
<div key={"ctl"+(this.controlKeyIndex++)} className={classes.controlPadding}> <div key={"ctl" + (this.controlKeyIndex++)} className={classes.controlPadding}>
{item} {item}
</div> </div>
@@ -552,7 +551,7 @@ const PluginControlView =
} }
result.push(( result.push((
<div key={"ctl"+(this.controlKeyIndex++)} className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}> <div key={"ctl" + (this.controlKeyIndex++)} className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}>
<div className={classes.portGroupTitle}> <div className={classes.portGroupTitle}>
<Typography noWrap variant="caption" >{controlGroup.name}</Typography> <Typography noWrap variant="caption" >{controlGroup.name}</Typography>
</div> </div>
@@ -566,7 +565,7 @@ const PluginControlView =
} else { } else {
result.push(( result.push((
<div key={"ctl"+(this.controlKeyIndex++)} className={hasGroups ? classes.portgroupControlPadding : classes.controlPadding} > <div key={"ctl" + (this.controlKeyIndex++)} className={hasGroups ? classes.portgroupControlPadding : classes.controlPadding} >
{node as ReactNode} {node as ReactNode}
</div> </div>
)); ));
@@ -584,7 +583,7 @@ const PluginControlView =
render(): ReactNode { render(): ReactNode {
this.controlKeyIndex = 0; this.controlKeyIndex = 0;
let classes = this.props.classes; let classes = this.props.classes;
let pedalboardItem: PedalboardItem; let pedalboardItem: PedalboardItem;
let pedalboard = this.model.pedalboard.get(); let pedalboard = this.model.pedalboard.get();
@@ -650,29 +649,33 @@ const PluginControlView =
) )
} }
</div> </div>
<FilePropertyDialog open={this.state.showFileDialog} {this.state.showFileDialog && (
fileProperty={this.state.dialogFileProperty}
selectedFile={this.state.dialogFileValue}
onCancel={() => {
this.setState({ showFileDialog: false });
}}
onOk={(fileProperty, selectedFile) => {
this.model.setPatchProperty( <FilePropertyDialog open={this.state.showFileDialog}
this.props.instanceId, fileProperty={this.state.dialogFileProperty}
fileProperty.patchProperty, selectedFile={this.state.dialogFileValue}
JsonAtom.Path(selectedFile) onCancel={() => {
) this.setState({ showFileDialog: false });
.then(() => { }}
onOk={(fileProperty, selectedFile) => {
this.model.setPatchProperty(
this.props.instanceId,
fileProperty.patchProperty,
JsonAtom.Path(selectedFile)
)
.then(() => {
})
.catch((error) => {
this.model.showAlert("Unable to complete the operation. Audio is not running." + error);
});
this.setState({ showFileDialog: false });
}
}
/>
)}
})
.catch((error) => {
this.model.showAlert("Unable to complete the operation. Audio is not running." + error);
});
this.setState({ showFileDialog: false });
}
}
/>
<FullScreenIME uiControl={this.state.imeUiControl} value={this.state.imeValue} <FullScreenIME uiControl={this.state.imeUiControl} value={this.state.imeValue}
onChange={(key, value) => this.onImeValueChange(key, value)} onChange={(key, value) => this.onImeValueChange(key, value)}
+1
View File
@@ -38,4 +38,5 @@ JSON_MAP_BEGIN(FileRequestResult)
JSON_MAP_REFERENCE(FileRequestResult,files) JSON_MAP_REFERENCE(FileRequestResult,files)
JSON_MAP_REFERENCE(FileRequestResult,isProtected) JSON_MAP_REFERENCE(FileRequestResult,isProtected)
JSON_MAP_REFERENCE(FileRequestResult,breadcrumbs) JSON_MAP_REFERENCE(FileRequestResult,breadcrumbs)
JSON_MAP_REFERENCE(FileRequestResult,currentDirectory)
JSON_MAP_END() JSON_MAP_END()
+1
View File
@@ -52,6 +52,7 @@ namespace pipedal {
std::vector<FileEntry> files_; std::vector<FileEntry> files_;
bool isProtected_ = false; bool isProtected_ = false;
std::vector<BreadcrumbEntry> breadcrumbs_; std::vector<BreadcrumbEntry> breadcrumbs_;
std::string currentDirectory_;
DECLARE_JSON_MAP(FileRequestResult); DECLARE_JSON_MAP(FileRequestResult);
}; };
+37 -1
View File
@@ -43,9 +43,21 @@
#include "RingBufferReader.hpp" #include "RingBufferReader.hpp"
using namespace pipedal; using namespace pipedal;
namespace fs = std::filesystem;
const float BYPASS_TIME_S = 0.1f; const float BYPASS_TIME_S = 0.1f;
static fs::path makeAbsolutePath(const std::filesystem::path &path, const std::filesystem::path &parentPath)
{
if (path.is_absolute())
{
return path;
}
return parentPath / path;
}
Lv2Effect::Lv2Effect( Lv2Effect::Lv2Effect(
IHost *pHost_, IHost *pHost_,
const std::shared_ptr<Lv2PluginInfo> &info_, const std::shared_ptr<Lv2PluginInfo> &info_,
@@ -69,7 +81,6 @@ Lv2Effect::Lv2Effect(
this->pathProperties.push_back(filePropertyUrid); this->pathProperties.push_back(filePropertyUrid);
this->pathPropertyWriters.push_back(PatchPropertyWriter(instanceId, filePropertyUrid)); this->pathPropertyWriters.push_back(PatchPropertyWriter(instanceId, filePropertyUrid));
std::vector<PatchPropertyWriter> pathPropertyWriters;
} }
} }
for (auto &pathProperty: pedalboardItem.pathProperties_) for (auto &pathProperty: pedalboardItem.pathProperties_)
@@ -84,8 +95,10 @@ Lv2Effect::Lv2Effect(
const LilvPlugins *plugins = lilv_world_get_all_plugins(pWorld); const LilvPlugins *plugins = lilv_world_get_all_plugins(pWorld);
// xxx: could we not stash the pPlugin in the plugin info?
auto uriNode = lilv_new_uri(pWorld, pedalboardItem.uri().c_str()); auto uriNode = lilv_new_uri(pWorld, pedalboardItem.uri().c_str());
const LilvPlugin *pPlugin = lilv_plugins_get_by_uri(plugins, uriNode); const LilvPlugin *pPlugin = lilv_plugins_get_by_uri(plugins, uriNode);
lilv_node_free(uriNode); lilv_node_free(uriNode);
{ {
AutoLilvNode bundleUri = lilv_plugin_get_bundle_uri(pPlugin); AutoLilvNode bundleUri = lilv_plugin_get_bundle_uri(pPlugin);
@@ -98,6 +111,25 @@ Lv2Effect::Lv2Effect(
logFeature.GetLog(), logFeature.GetLog(),
bundleUriString, bundleUriString,
storagePath); storagePath);
mapPathFeature.Prepare(&(pHost_->GetMapFeature()));
mapPathFeature.SetPluginStoragePath(pHost_->GetPluginStoragePath());
if (info->piPedalUI())
{
const auto &fileProperties = info_->piPedalUI()->fileProperties();
for (const auto &fileProperty : fileProperties)
{
if (!fileProperty->resourceDirectory().empty())
{
mapPathFeature.AddResourceFileMapping({
makeAbsolutePath(fileProperty->resourceDirectory(),bundleUriString),
makeAbsolutePath(fileProperty->directory(),pHost_->GetPluginStoragePath())
});
}
}
}
lilv_free(bundleUriString); lilv_free(bundleUriString);
} }
@@ -109,6 +141,10 @@ Lv2Effect::Lv2Effect(
{ {
this->features.push_back(*p); this->features.push_back(*p);
} }
this->features.push_back(mapPathFeature.GetMapPathFeature());
this->features.push_back(mapPathFeature.GetMakePathFeature());
this->features.push_back(mapPathFeature.GetFreePathFeature());
this->features.push_back(this->fileBrowserFilesFeature.GetFeature()); this->features.push_back(this->fileBrowserFilesFeature.GetFeature());
+2 -1
View File
@@ -27,6 +27,7 @@
#include "FileBrowserFilesFeature.hpp" #include "FileBrowserFilesFeature.hpp"
#include "PatchPropertyWriter.hpp" #include "PatchPropertyWriter.hpp"
#include <unordered_map> #include <unordered_map>
#include "MapPathFeature.hpp"
#include "IEffect.hpp" #include "IEffect.hpp"
#include "Worker.hpp" #include "Worker.hpp"
@@ -90,7 +91,7 @@ namespace pipedal
std::vector<char *> outputAtomBuffers; std::vector<char *> outputAtomBuffers;
std::vector<const LV2_Feature *> features; std::vector<const LV2_Feature *> features;
LV2_Feature *work_schedule_feature = nullptr; LV2_Feature *work_schedule_feature = nullptr;
MapPathFeature mapPathFeature;
uint64_t maxInputControlPort = 0; uint64_t maxInputControlPort = 0;
std::vector<bool> isInputControlPort; std::vector<bool> isInputControlPort;
+1 -2
View File
@@ -26,8 +26,7 @@
using namespace pipedal; using namespace pipedal;
MapPathFeature::MapPathFeature(const std::filesystem::path &storagePath) MapPathFeature::MapPathFeature()
:storagePath(storagePath)
{ {
lv2_state_map_path.handle = (LV2_State_Map_Path_Handle *)this; lv2_state_map_path.handle = (LV2_State_Map_Path_Handle *)this;
lv2_state_map_path.absolute_path = FnAbsolutePath; lv2_state_map_path.absolute_path = FnAbsolutePath;
+13 -1
View File
@@ -24,12 +24,23 @@
namespace pipedal namespace pipedal
{ {
struct ResourceFileMapping {
std::string resourcePath; // absolute path of the resource directory.
std::string storagePath; // absolute path of where resource directory files get placed.
};
class MapPathFeature class MapPathFeature
{ {
public: public:
MapPathFeature(const std::filesystem::path &storagePath); MapPathFeature();
void Prepare(MapFeature* map); void Prepare(MapFeature* map);
void SetPluginStoragePath(const std::string&path) { storagePath = path;} void SetPluginStoragePath(const std::string&path) { storagePath = path;}
void AddResourceFileMapping(const ResourceFileMapping &resourceFileMapping)
{
this->resourceFileMappings.push_back(resourceFileMapping);
}
const std::vector<ResourceFileMapping> &GetResourceFileMappings() const { return resourceFileMappings; }
const std::string&GetPluginStoragePath() const { return storagePath; } const std::string&GetPluginStoragePath() const { return storagePath; }
const LV2_Feature*GetMapPathFeature() { return &mapPathFeature;} const LV2_Feature*GetMapPathFeature() { return &mapPathFeature;}
const LV2_Feature*GetMakePathFeature() { return &makePathFeature;} const LV2_Feature*GetMakePathFeature() { return &makePathFeature;}
@@ -60,5 +71,6 @@ namespace pipedal
private: private:
std::string storagePath; std::string storagePath;
std::vector<ResourceFileMapping> resourceFileMappings;
}; };
} }
+3 -8
View File
@@ -243,16 +243,15 @@ static float nodeAsFloat(const LilvNode *node, float default_ = 0)
void PluginHost::SetPluginStoragePath(const std::filesystem::path &path) void PluginHost::SetPluginStoragePath(const std::filesystem::path &path)
{ {
mapPathFeature.SetPluginStoragePath(path); pluginStoragePath = path;
} }
std::string PluginHost::GetPluginStoragePath() const std::string PluginHost::GetPluginStoragePath() const
{ {
return mapPathFeature.GetPluginStoragePath(); return pluginStoragePath;
} }
PluginHost::PluginHost() PluginHost::PluginHost()
: mapPathFeature("")
{ {
pWorld = nullptr; pWorld = nullptr;
@@ -260,13 +259,9 @@ PluginHost::PluginHost()
lv2Features.push_back(mapFeature.GetUnmapFeature()); lv2Features.push_back(mapFeature.GetUnmapFeature());
optionsFeature.Prepare(mapFeature, 44100, this->GetMaxAudioBufferSize(), this->GetAtomBufferSize()); optionsFeature.Prepare(mapFeature, 44100, this->GetMaxAudioBufferSize(), this->GetAtomBufferSize());
mapPathFeature.Prepare(&mapFeature);
lv2Features.push_back(mapPathFeature.GetMapPathFeature());
lv2Features.push_back(mapPathFeature.GetMakePathFeature());
lv2Features.push_back(mapPathFeature.GetFreePathFeature());
lv2Features.push_back(optionsFeature.GetFeature()); lv2Features.push_back(optionsFeature.GetFeature());
lv2Features.push_back(nullptr); lv2Features.push_back(nullptr);
this->urids = new Urids(mapFeature); this->urids = new Urids(mapFeature);
+1 -1
View File
@@ -757,7 +757,7 @@ namespace pipedal
std::vector<const LV2_Feature *> lv2Features; std::vector<const LV2_Feature *> lv2Features;
MapFeature mapFeature; MapFeature mapFeature;
OptionsFeature optionsFeature; OptionsFeature optionsFeature;
MapPathFeature mapPathFeature; std::string pluginStoragePath;
static void fn_LilvSetPortValueFunc(const char *port_symbol, static void fn_LilvSetPortValueFunc(const char *port_symbol,
void *user_data, void *user_data,
+36 -1
View File
@@ -1770,6 +1770,7 @@ FileRequestResult Storage::GetModFileList2(const std::string &relativePath, cons
FileEntry(uploadsDirectory / fileProperty.directory(), fs::path(fileProperty.directory()).filename().string(), true, true)); FileEntry(uploadsDirectory / fileProperty.directory(), fs::path(fileProperty.directory()).filename().string(), true, true));
} }
result.breadcrumbs_.push_back({"", "Home"}); result.breadcrumbs_.push_back({"", "Home"});
result.currentDirectory_ = relativePath;
return result; return result;
} }
fs::path modDirectoryPath; fs::path modDirectoryPath;
@@ -1824,9 +1825,23 @@ FileRequestResult Storage::GetModFileList2(const std::string &relativePath, cons
} }
AddFilesToResult(result, fileProperty, relativePath); AddFilesToResult(result, fileProperty, relativePath);
result.currentDirectory_ = relativePath;
return result; return result;
} }
static bool IsChildDirectory(const fs::path& child, const fs::path&parent) {
auto iChild = child.begin();
for (auto i = parent.begin(); i != parent.end(); ++i)
{
if (iChild == child.end() || (*i) != *iChild)
{
return false;
}
++iChild;
}
return true;
}
FileRequestResult Storage::GetFileList2(const std::string &relativePath_, const UiFileProperty &fileProperty) FileRequestResult Storage::GetFileList2(const std::string &relativePath_, const UiFileProperty &fileProperty)
{ {
std::string absolutePath = relativePath_; std::string absolutePath = relativePath_;
@@ -1843,15 +1858,35 @@ FileRequestResult Storage::GetFileList2(const std::string &relativePath_, const
if (fileProperty.directory().empty()) if (fileProperty.directory().empty())
{ {
throw std::runtime_error("fileProperty.directory() not specified."); throw std::runtime_error("fileProperty.directory() not specified.");
} }
std::filesystem::path pluginRootDirectory = this->GetPluginUploadDirectory() / fileProperty.directory(); std::filesystem::path pluginRootDirectory = this->GetPluginUploadDirectory() / fileProperty.directory();
if (absolutePath == "") if (absolutePath.empty())
{ {
absolutePath = pluginRootDirectory.string(); absolutePath = pluginRootDirectory.string();
} }
// handle resource directories.
if (!fileProperty.resourceDirectory().empty())
{ {
if (fileProperty.resourceDirectory() == absolutePath)
{
absolutePath = pluginRootDirectory;
}
}
if (!IsChildDirectory(absolutePath,pluginRootDirectory))
{
absolutePath = pluginRootDirectory;
}
result.currentDirectory_ = absolutePath;
{
// watch out for resource files!!!
result.breadcrumbs_.push_back({"", "Home"}); result.breadcrumbs_.push_back({"", "Home"});
fs::path fsAbsolutePath{absolutePath}; fs::path fsAbsolutePath{absolutePath};
auto iAbsolutePath = fsAbsolutePath.begin(); auto iAbsolutePath = fsAbsolutePath.begin();
+5
View File
@@ -398,6 +398,11 @@ int main(int argc, char *argv[])
} }
Lv2Log::info("Shutdown complete."); Lv2Log::info("Shutdown complete.");
if (systemd)
{
sd_notify(0, "STOPPING=1");
}
if (g_restart) if (g_restart)
return EXIT_FAILURE; // indicate to systemd that we want a restart. return EXIT_FAILURE; // indicate to systemd that we want a restart.
} }