mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-08 04:20:13 +02:00
Add compatibility option to force flushing to zero
This prevents Kush Audio REDDI from taking down the DAW when the host passes it denormalized audio to process. I've discovered that the issue with this plugin had to do with denormals in the issue linked below, but I didn't realize that we can just enable the FTZ flag for plugins that don't already do so. https://github.com/osxmidi/LinVst/issues/174
This commit is contained in:
@@ -108,6 +108,12 @@ Configuration::Configuration(const fs::path& config_path,
|
||||
} else {
|
||||
invalid_options.push_back(key);
|
||||
}
|
||||
} else if (key == "force_ftz") {
|
||||
if (const auto parsed_value = value.as_boolean()) {
|
||||
force_ftz = parsed_value->get();
|
||||
} else {
|
||||
invalid_options.push_back(key);
|
||||
}
|
||||
} else if (key == "frame_rate") {
|
||||
if (const auto parsed_value = value.as_floating_point()) {
|
||||
frame_rate = parsed_value->get();
|
||||
|
||||
@@ -126,6 +126,15 @@ class Configuration {
|
||||
*/
|
||||
bool editor_xembed = false;
|
||||
|
||||
/**
|
||||
* When using this option, we'll enable the flush-to-zero flag during audio
|
||||
* processing. This can be useful when the host passes denormals to a plugin
|
||||
* that doesn't handle those well. An example of such a plugin is REDDI by
|
||||
* Kush Audio. Some hosts, like Bitwig, will already snap denormals to zero
|
||||
* for us so this may not be necessary with every host.
|
||||
*/
|
||||
bool force_ftz = false;
|
||||
|
||||
/**
|
||||
* The number of times per second we'll handle the event loop. In most
|
||||
* plugins this also controls the plugin editor GUI's refresh rate.
|
||||
@@ -205,6 +214,7 @@ class Configuration {
|
||||
s.value1b(editor_double_embed);
|
||||
s.value1b(editor_force_dnd);
|
||||
s.value1b(editor_xembed);
|
||||
s.value1b(force_ftz);
|
||||
s.ext(frame_rate, bitsery::ext::StdOptional(),
|
||||
[](S& s, auto& v) { s.value4b(v); });
|
||||
s.value1b(hide_daw);
|
||||
|
||||
+1
-3
@@ -90,15 +90,13 @@ bool set_realtime_priority(bool sched_fifo, int priority = 5);
|
||||
* previously when it drops out of scope.
|
||||
*/
|
||||
class ScopedFlushToZero {
|
||||
public:
|
||||
ScopedFlushToZero();
|
||||
~ScopedFlushToZero();
|
||||
|
||||
ScopedFlushToZero(const ScopedFlushToZero&) = delete;
|
||||
ScopedFlushToZero& operator=(const ScopedFlushToZero&) = delete;
|
||||
|
||||
ScopedFlushToZero(ScopedFlushToZero&&) = delete;
|
||||
ScopedFlushToZero& operator=(ScopedFlushToZero&&) = delete;
|
||||
|
||||
private:
|
||||
/**
|
||||
* The previous FTZ mode. When we use this on the Wine side, this should
|
||||
|
||||
@@ -187,6 +187,9 @@ class PluginBridge {
|
||||
if (config.editor_xembed) {
|
||||
other_options.push_back("editor: XEmbed");
|
||||
}
|
||||
if (config.force_ftz) {
|
||||
other_options.push_back("hack: force flush-to-zero");
|
||||
}
|
||||
if (config.frame_rate) {
|
||||
std::ostringstream option;
|
||||
option << "frame rate: " << std::setprecision(2)
|
||||
|
||||
@@ -180,6 +180,12 @@ Vst2Bridge::Vst2Bridge(MainContext& main_context,
|
||||
|
||||
sockets.host_vst_process_replacing.receive_multi<AudioBuffers>(
|
||||
[&](AudioBuffers request, std::vector<uint8_t>& buffer) {
|
||||
// HACK: When a plugin doesn't handle denormals properly, we can
|
||||
// force the FTZ flag to be set to work around this
|
||||
std::optional<ScopedFlushToZero> ftz_guard =
|
||||
config.force_ftz ? std::make_optional<ScopedFlushToZero>()
|
||||
: std::nullopt;
|
||||
|
||||
// As suggested by Jack Winter, we'll synchronize this thread's
|
||||
// audio processing priority with that of the host's audio
|
||||
// thread every once in a while
|
||||
|
||||
@@ -1211,6 +1211,14 @@ size_t Vst3Bridge::register_object_instance(
|
||||
},
|
||||
[&](YaAudioProcessor::Process& request)
|
||||
-> YaAudioProcessor::Process::Response {
|
||||
// HACK: When a plugin doesn't handle denormals
|
||||
// properly, we can force the FTZ flag to be set
|
||||
// to work around this
|
||||
std::optional<ScopedFlushToZero> ftz_guard =
|
||||
config.force_ftz
|
||||
? std::make_optional<ScopedFlushToZero>()
|
||||
: std::nullopt;
|
||||
|
||||
// As suggested by Jack Winter, we'll synchronize this
|
||||
// thread's audio processing priority with that of the
|
||||
// host's audio thread every once in a while
|
||||
|
||||
Reference in New Issue
Block a user