Skip to content

Commit

Permalink
A simple standalone save/retrieve (#190)
Browse files Browse the repository at this point in the history
- Standalone tries to save and retrieve state on start and stop
- Requires an OS specific default path which is only coded on macos now
- Currently uses use the raw data stream; obviously we want to expand
  this with an envelope for standalone settings in the near future
  • Loading branch information
baconpaul authored Oct 28, 2023
1 parent 957b155 commit 143be1b
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmake/wrap_standalone.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ function(target_add_standalone_wrapper)
target_sources(${SA_TARGET} PRIVATE
"${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/wrapasstandalone.mm"
${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/detail/standalone/macos/AppDelegate.mm
${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/detail/standalone/macos/StandaloneFunctions.mm
${GEN_XIB}
)

Expand Down
38 changes: 38 additions & 0 deletions src/detail/standalone/entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ std::shared_ptr<Clap::Plugin> mainCreatePlugin(const clap_plugin_entry *ee, cons

plugin->initialize();

auto pt = getStandaloneSettingsPath();
if (pt.has_value())
{
auto loadPath = *pt / plugin->_plugin->desc->id;
try
{
if (fs::exists(loadPath / "settings.clapwrapper"))
{
LOG << "Trying to load from clap wrapper settings" << std::endl;
standaloneHost->tryLoadStandaloneAndPluginSettings(loadPath, "settings.clapwrapper");
}
}
catch (const fs::filesystem_error &e)
{
// Oh well - whatcha gonna do?
}
}

plugin->setSampleRate(48000);
plugin->setBlockSizes(32, 1024);
plugin->activate();
Expand Down Expand Up @@ -96,6 +114,26 @@ int mainFinish()
standaloneHost->stopAudioThread();
standaloneHost->stopMIDIThread();

auto pt = getStandaloneSettingsPath();
if (pt.has_value())
{
auto savePath = *pt / plugin->_plugin->desc->id;
LOG << "Saving settings to '" << savePath << "'" << std::endl;
try
{
fs::create_directories(savePath);
standaloneHost->saveStandaloneAndPluginSettings(savePath, "settings.clapwrapper");
}
catch (const fs::filesystem_error &e)
{
// Oh well - whatcha gonna do?
}
}
else
{
LOG << "No Standalone Settings Path; not streaming" << std::endl;
}

plugin->deactivate();
}
plugin.reset();
Expand Down
20 changes: 20 additions & 0 deletions src/detail/standalone/macos/StandaloneFunctions.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@


#include <Foundation/Foundation.h>
#include "detail/standalone/standalone_host.h"

namespace freeaudio::clap_wrapper::standalone
{
std::optional<fs::path> getStandaloneSettingsPath()
{
auto *fileManager = [NSFileManager defaultManager];
auto *resultURLs = [fileManager URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask];
if (resultURLs)
{
auto *u = [resultURLs objectAtIndex:0];
return fs::path{[u fileSystemRepresentation]} / "clap-wrapper-standalone";
}
return std::nullopt;
}
} // namespace freeaudio::clap_wrapper::standalone
80 changes: 80 additions & 0 deletions src/detail/standalone/standalone_host.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include <cassert>
#include "standalone_host.h"
#include <fstream>

#if LIN
#if CLAP_WRAPPER_HAS_GTK3
Expand All @@ -10,6 +11,15 @@

namespace freeaudio::clap_wrapper::standalone
{

#if !MAC
std::optional<fs::path> getStandaloneSettingsPath()
{
TRACE;
return std::nullopt;
}
#endif

StandaloneHost::~StandaloneHost()
{
}
Expand Down Expand Up @@ -234,4 +244,74 @@ bool StandaloneHost::unregister_timer(clap_id timer_id)
}
#endif

static int64_t clapwrite(const clap_ostream *s, const void *buffer, uint64_t size)
{
auto ofs = static_cast<std::ofstream *>(s->ctx);
ofs->write((const char *)buffer, size);
return size;
}

static int64_t clapread(const struct clap_istream *s, void *buffer, uint64_t size)
{
auto ifs = static_cast<std::ifstream *>(s->ctx);

// Oh this API is so terrible. I think this is right?
ifs->read(static_cast<char *>(buffer), size);
if (ifs->rdstate() == std::ios::goodbit || ifs->rdstate() == std::ios::eofbit) return ifs->gcount();

if (ifs->rdstate() & std::ios::eofbit) return ifs->gcount();

return -1;
}

bool StandaloneHost::saveStandaloneAndPluginSettings(const fs::path &intoDir, const fs::path &withName)
{
// This should obviously be a more robust file format. What we
// want is an envelope containing the standalone settings and then
// the streamed plugin data. What we have here is just the streamed
// plugin data with no settings space for audio port selection etc...

std::ofstream ofs(intoDir / withName, std::ios::out | std::ios::binary);
if (!ofs.is_open())
{
LOG << "Unable to open for writing " << (intoDir / withName).u8string() << std::endl;
return false;
}
if (!clapPlugin || !clapPlugin->_ext._state)
{
return false;
}
clap_ostream cos{};
cos.ctx = &ofs;
cos.write = clapwrite;
clapPlugin->_ext._state->save(clapPlugin->_plugin, &cos);
ofs.close();

return true;
}

bool StandaloneHost::tryLoadStandaloneAndPluginSettings(const fs::path &fromDir,
const fs::path &withName)
{
// see comment above on this file format being not just the
// raw stream in the future
auto fsp = fromDir / withName;
std::ifstream ifs(fsp, std::ios::in | std::ios::binary);
if (!ifs.is_open())
{
LOG << "Unable to open for reading " << fsp.u8string() << std::endl;
return false;
}
if (!clapPlugin || !clapPlugin->_ext._state)
{
return false;
}
clap_istream cis{};
cis.ctx = &ifs;
cis.read = clapread;
clapPlugin->_ext._state->load(clapPlugin->_plugin, &cis);
ifs.close();
return true;
}

} // namespace freeaudio::clap_wrapper::standalone
8 changes: 8 additions & 0 deletions src/detail/standalone/standalone_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
#include <unordered_set>
#include <thread>
#include <mutex>
#include <optional>

#include "standalone_details.h"

#include "detail/clap/fsutil.h"

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall" // other peoples errors are outside my scope
Expand Down Expand Up @@ -43,6 +46,8 @@ struct Win32Gui;
#endif
#endif

std::optional<fs::path> getStandaloneSettingsPath();

struct StandaloneHost : Clap::IHost
{
StandaloneHost()
Expand Down Expand Up @@ -129,6 +134,9 @@ struct StandaloneHost : Clap::IHost
TRACE;
}

bool saveStandaloneAndPluginSettings(const fs::path &intoDir, const fs::path &withName);
bool tryLoadStandaloneAndPluginSettings(const fs::path &fromDir, const fs::path &withName);

uint32_t numAudioInputs{0}, numAudioOutputs{0};
std::vector<uint32_t> inputChannelByBus;
std::vector<uint32_t> outputChannelByBus;
Expand Down

0 comments on commit 143be1b

Please sign in to comment.