Skip to content

Commit

Permalink
Improve Linux standalone
Browse files Browse the repository at this point in the history
- Make it compile on ubuntu 22 again!
- Resize, parent in a sub-element, title is correct
- Startup path doesn't crash with surge
- Command lines work for input, output, and sample rate (but still
  hardcode block, still hardcode midi and still use channels 0 and 1)
  • Loading branch information
baconpaul committed Mar 24, 2024
1 parent 5526acb commit fe01b0d
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 20 deletions.
9 changes: 8 additions & 1 deletion src/detail/standalone/entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ std::shared_ptr<Clap::Plugin> mainCreatePlugin(const clap_plugin_entry *ee, cons
return nullptr;
}

standaloneHost = std::make_unique<StandaloneHost>();
if (!standaloneHost)
{
standaloneHost = std::make_unique<StandaloneHost>();
}

if (clapId.empty())
{
Expand Down Expand Up @@ -86,6 +89,10 @@ std::shared_ptr<Clap::Plugin> getMainPlugin()

StandaloneHost *getStandaloneHost()
{
if (!standaloneHost)
{
standaloneHost = std::make_unique<StandaloneHost>();
}
return standaloneHost.get();
}

Expand Down
139 changes: 135 additions & 4 deletions src/detail/standalone/linux/gtkutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,70 @@

#include "gtkutils.h"
#include "detail/standalone/standalone_details.h"
#include "detail/standalone/standalone_host.h"
#include "detail/standalone/entry.h"

#include <cassert>

namespace freeaudio::clap_wrapper::standalone::linux
namespace freeaudio::clap_wrapper::standalone::linux_standalone
{

static void activate(GtkApplication *app, gpointer user_data)
{
GdkDisplay *display = gdk_display_get_default();

if (!GDK_IS_X11_DISPLAY(display))
{
std::cout << "clap-wrapper standalone requires GDK X11 backend" << std::endl;
std::terminate();
}

auto g = (GtkGui *)user_data;
g->setupPlugin(app);
}

static gboolean onResize(GtkWidget *wid, GdkEventConfigure *event, gpointer user_data)
{
auto g = (GtkGui *)user_data;
return g->resizePlugin(wid, event->width, event->height);
}

bool GtkGui::resizePlugin(GtkWidget *wid, uint32_t w, uint32_t h)
{
if (plugin->_ext._gui)
{
auto gui = plugin->_ext._gui;
auto p = plugin->_plugin;

if (!gui->can_resize(p))
{
gui->get_size(p, &w, &h);
gtk_window_resize(GTK_WINDOW(wid), w, h);
return TRUE;
}

#if 1
gui->set_size(p, w, h);
#else
// For some reason, this freaks out with drags in surge on gtk on linux.
auto adj = false;
auto aw = w, ah = h;
gui->adjust_size(p, &aw, &ah);
gui->set_size(p, aw, ah);
if (aw != w || ah != h) adj = true;
w = aw;
h = ah;
gtk_window_resize(GTK_WINDOW(wid), w, h);
return adj;
#endif
}
return FALSE;
}

void GtkGui::setupPlugin(_GtkApplication *app)
{
GtkWidget *window;
Expand All @@ -34,15 +86,27 @@ void GtkGui::setupPlugin(_GtkApplication *app)

uint32_t w, h;
ui->get_size(p, &w, &h);
ui->adjust_size(p, &w, &h);

window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Standalone Window");
gtk_window_set_title(GTK_WINDOW(window), p->desc->name);
gtk_window_set_default_size(GTK_WINDOW(window), w, h);

GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);

// Create the 'inner window'
GtkWidget *frame = gtk_frame_new("Inner 'Window'");
gtk_widget_set_size_request(frame, w, h);
gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);

g_signal_connect(window, "configure-event", G_CALLBACK(onResize), this);

gtk_widget_show_all(window);

clap_window win;
win.api = CLAP_WINDOW_API_X11;
auto gw = gtk_widget_get_window(GTK_WIDGET(window));
auto gw = gtk_widget_get_window(GTK_WIDGET(frame));
win.x11 = GDK_WINDOW_XID(gw);
ui->set_parent(p, &win);
ui->show(p);
Expand Down Expand Up @@ -162,6 +226,73 @@ int GtkGui::runFD(int fd, clap_posix_fd_flags_t flags)
return true;
}

} // namespace freeaudio::clap_wrapper::standalone::linux
bool GtkGui::parseCommandLine(int argc, char **argv)
{
auto sah = freeaudio::clap_wrapper::standalone::getStandaloneHost();

auto [i, o, s] = sah->getDefaultAudioInOutSampleRate();

bool list_devices{false};
int sampleRate{s};
unsigned int inId{i}, outId{o};

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored \
"-Wmissing-field-initializers" // other peoples errors are outside my scope
#endif
const GOptionEntry entries[] = {
{"list-devices", 'l', 0, G_OPTION_ARG_NONE, &list_devices, "List Input Output and MIDI Devices",
nullptr},
{"sample-rate", 's', 0, G_OPTION_ARG_INT, &sampleRate, "Sample Rate", nullptr},
{"input-device", 'i', 0, G_OPTION_ARG_INT, &inId, "Input Device (0 for no input)", nullptr},
{"output-device", 'o', 0, G_OPTION_ARG_INT, &outId, "Output Device (0 for no input)", nullptr},
{NULL}};
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

GOptionContext *context;
GError *error = nullptr;

context = g_option_context_new("Clap Wrapper Standalone");
g_option_context_add_main_entries(context, entries, NULL);

g_option_context_add_group(context, gtk_get_option_group(TRUE));
if (!g_option_context_parse(context, &argc, &argv, &error))
{
g_print("Failed to parse options: %s\n", error->message);
g_error_free(error);
return false;
}

if (list_devices)
{
std::cout << "\n\nAvailable Audio Interfaces:\n\nOutput:\n";
auto outD = sah->getOutputAudioDevices();
for (auto &d : outD)
{
std::cout << " - " << d.name << " (id=" << d.ID << " channels=" << d.outputChannels << ")"
<< std::endl;
}

std::cout << "\nInput:\n";
auto inD = sah->getInputAudioDevices();
for (auto &d : inD)
{
std::cout << " - " << d.name << " (id=" << d.ID << " channels=" << d.outputChannels << ")"
<< std::endl;
}
return false;
}

LOG << "Post Argument Parse: inId=" << inId << " outId=" << outId << " sampleRate=" << sampleRate
<< std::endl;
sah->setStartupAudio(inId, outId, sampleRate);

return true;
}

} // namespace freeaudio::clap_wrapper::standalone::linux_standalone

#endif
11 changes: 8 additions & 3 deletions src/detail/standalone/linux/gtkutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@
#include "detail/standalone/standalone_host.h"

struct _GtkApplication; // sigh their typedef screws up forward decls
namespace freeaudio::clap_wrapper::standalone::linux
struct _GtkWidget;

namespace freeaudio::clap_wrapper::standalone::linux_standalone
{
struct GtkGui
{
_GtkApplication *app{nullptr};
std::shared_ptr<Clap::Plugin> plugin;

bool parseCommandLine(int argc, char **argv);

void initialize(freeaudio::clap_wrapper::standalone::StandaloneHost *);
void setPlugin(std::shared_ptr<Clap::Plugin>);
void runloop(int argc, char **argv);
void shutdown();

void setupPlugin(_GtkApplication *app);
bool resizePlugin(_GtkWidget *wid, uint32_t w, uint32_t h);

clap_id currTimer{8675309};
std::mutex cbMutex;
std::mutex cbMutex{};

struct TimerCB
{
Expand All @@ -47,4 +52,4 @@ struct GtkGui
bool unregister_fd(int fd);
int runFD(int fd, clap_posix_fd_flags_t flags);
};
} // namespace freeaudio::clap_wrapper::standalone::linux
} // namespace freeaudio::clap_wrapper::standalone::linux_standalone
1 change: 1 addition & 0 deletions src/detail/standalone/standalone_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ const char *StandaloneHost::host_get_name()
bool StandaloneHost::register_timer(uint32_t period_ms, clap_id *timer_id)
{
#if LIN && CLAP_WRAPPER_HAS_GTK3
assert(gtkGui);
return gtkGui->register_timer(period_ms, timer_id);
#else
return false;
Expand Down
15 changes: 13 additions & 2 deletions src/detail/standalone/standalone_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace freeaudio::clap_wrapper::standalone
{
#if LIN
#if CLAP_WRAPPER_HAS_GTK3
namespace linux
namespace linux_standalone
{
struct GtkGui;
}
Expand Down Expand Up @@ -183,7 +183,7 @@ struct StandaloneHost : Clap::IHost

#if LIN
#if CLAP_WRAPPER_HAS_GTK3
freeaudio::clap_wrapper::standalone::linux::GtkGui *gtkGui{nullptr};
freeaudio::clap_wrapper::standalone::linux_standalone::GtkGui *gtkGui{nullptr};
#endif
#endif

Expand Down Expand Up @@ -247,6 +247,17 @@ struct StandaloneHost : Clap::IHost
int32_t sampleRate);
void stopAudioThread();

bool startupAudioSet{false};
unsigned int startAudioIn{0}, startAudioOut{0};
int startSampleRate{0};
void setStartupAudio(unsigned int in, unsigned int out, int sr)
{
startupAudioSet = true;
startAudioIn = in;
startAudioOut = out;
startSampleRate = sr;
}

void activatePlugin(int32_t sr, int32_t minBlock, int32_t maxBlock);
bool isActive{false};

Expand Down
38 changes: 31 additions & 7 deletions src/detail/standalone/standalone_host_audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,27 @@ int rtaCallback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrame
return 0;
}

void rtaErrorCallback(RtAudioErrorType, const std::string &errorText)
void rtaErrorCallback(RtAudioErrorType errorType, const std::string &errorText)
{
LOG << "[ERROR] RtAudio reports '" << errorText << "'" << std::endl;
auto ae = getStandaloneHost()->displayAudioError;
if (ae)
if (errorType != RTAUDIO_OUTPUT_UNDERFLOW && errorType != RTAUDIO_INPUT_OVERFLOW)
{
ae(errorText);
LOG << "[ERROR] RtAudio reports '" << errorText << "'"
<< " " << errorType << std::endl;
auto ae = getStandaloneHost()->displayAudioError;
if (ae)
{
ae(errorText);
}
}
else
{
static bool reported = false;
if (!reported)
{
LOG << "[ERROR] RtAudio reports '" << errorText << "'" << std::endl;
LOG << "[ERROR] Supressing future underflow reports" << std::endl;
reported = true;
}
}
}

Expand Down Expand Up @@ -64,8 +78,18 @@ void StandaloneHost::startAudioThread()
{
guaranteeRtAudioDAC();

auto [in, out, sr] = getDefaultAudioInOutSampleRate();
startAudioThreadOn(in, 2, numAudioInputs > 0, out, 2, numAudioOutputs > 0, sr);
if (startupAudioSet)
{
auto in = startAudioIn;
auto out = startAudioOut;
auto sr = startSampleRate;
startAudioThreadOn(in, 2, in > 0 && numAudioInputs > 0, out, 2, out > 0 && numAudioOutputs > 0, sr);
}
else
{
auto [in, out, sr] = getDefaultAudioInOutSampleRate();
startAudioThreadOn(in, 2, numAudioInputs > 0, out, 2, numAudioOutputs > 0, sr);
}
}

std::vector<RtAudio::DeviceInfo> filterDevicesBy(const std::unique_ptr<RtAudio> &rtaDac,
Expand Down
15 changes: 12 additions & 3 deletions src/wrapasstandalone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ int main(int argc, char **argv)
}
}

#endif

#if LIN
#if CLAP_WRAPPER_HAS_GTK3
freeaudio::clap_wrapper::standalone::linux_standalone::GtkGui gtkGui{};

if (!gtkGui.parseCommandLine(argc, argv))
{
return 1;
}
gtkGui.initialize(freeaudio::clap_wrapper::standalone::getStandaloneHost());
#endif
#endif

if (!entry)
Expand All @@ -54,9 +66,6 @@ int main(int argc, char **argv)

#if LIN
#if CLAP_WRAPPER_HAS_GTK3
freeaudio::clap_wrapper::standalone::linux::GtkGui gtkGui{};

gtkGui.initialize(freeaudio::clap_wrapper::standalone::getStandaloneHost());
gtkGui.setPlugin(plugin);
gtkGui.runloop(argc, argv);
gtkGui.shutdown();
Expand Down

0 comments on commit fe01b0d

Please sign in to comment.