mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
Split VST2 specific functionality into Vst2Logger
This commit is contained in:
@@ -85,6 +85,7 @@ shared_library(
|
|||||||
'src/common/serialization/vst2.cpp',
|
'src/common/serialization/vst2.cpp',
|
||||||
'src/common/configuration.cpp',
|
'src/common/configuration.cpp',
|
||||||
'src/common/logging/common.cpp',
|
'src/common/logging/common.cpp',
|
||||||
|
'src/common/logging/vst2.cpp',
|
||||||
'src/common/plugins.cpp',
|
'src/common/plugins.cpp',
|
||||||
'src/common/utils.cpp',
|
'src/common/utils.cpp',
|
||||||
'src/plugin/bridges/vst2.cpp',
|
'src/plugin/bridges/vst2.cpp',
|
||||||
@@ -204,6 +205,7 @@ if with_vst3
|
|||||||
'yabridge-vst3',
|
'yabridge-vst3',
|
||||||
[
|
[
|
||||||
'src/common/logging/common.cpp',
|
'src/common/logging/common.cpp',
|
||||||
|
'src/common/logging/vst2.cpp',
|
||||||
'src/plugin/vst3-plugin.cpp',
|
'src/plugin/vst3-plugin.cpp',
|
||||||
version_header,
|
version_header,
|
||||||
],
|
],
|
||||||
@@ -229,6 +231,7 @@ host_sources = [
|
|||||||
'src/common/serialization/vst2.cpp',
|
'src/common/serialization/vst2.cpp',
|
||||||
'src/common/configuration.cpp',
|
'src/common/configuration.cpp',
|
||||||
'src/common/logging/common.cpp',
|
'src/common/logging/common.cpp',
|
||||||
|
'src/common/logging/vst2.cpp',
|
||||||
'src/common/plugins.cpp',
|
'src/common/plugins.cpp',
|
||||||
'src/common/utils.cpp',
|
'src/common/utils.cpp',
|
||||||
'src/wine-host/bridges/vst2.cpp',
|
'src/wine-host/bridges/vst2.cpp',
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <bitsery/adapter/buffer.h>
|
#include <bitsery/adapter/buffer.h>
|
||||||
#include <bitsery/bitsery.h>
|
#include <bitsery/bitsery.h>
|
||||||
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
#ifdef __WINE__
|
#ifdef __WINE__
|
||||||
#include "../wine-host/boost-fix.h"
|
#include "../wine-host/boost-fix.h"
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include "../logging/common.h"
|
#include "../logging/vst2.h"
|
||||||
|
#include "../serialization/vst2.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -151,7 +152,7 @@ class EventHandler : public AdHocSocketHandler<Thread> {
|
|||||||
*/
|
*/
|
||||||
template <typename D>
|
template <typename D>
|
||||||
intptr_t send_event(D& data_converter,
|
intptr_t send_event(D& data_converter,
|
||||||
std::optional<std::pair<Logger&, bool>> logging,
|
std::optional<std::pair<Vst2Logger&, bool>> logging,
|
||||||
int opcode,
|
int opcode,
|
||||||
int index,
|
int index,
|
||||||
intptr_t value,
|
intptr_t value,
|
||||||
@@ -226,7 +227,7 @@ class EventHandler : public AdHocSocketHandler<Thread> {
|
|||||||
* @relates passthrough_event
|
* @relates passthrough_event
|
||||||
*/
|
*/
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void receive_events(std::optional<std::pair<Logger&, bool>> logging,
|
void receive_events(std::optional<std::pair<Vst2Logger&, bool>> logging,
|
||||||
F callback) {
|
F callback) {
|
||||||
// Reading, processing, and writing back event data from the sockets
|
// Reading, processing, and writing back event data from the sockets
|
||||||
// works in the same way regardless of which socket we're using
|
// works in the same way regardless of which socket we're using
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ constexpr char logging_verbosity_environment_variable[] =
|
|||||||
Logger::Logger(std::shared_ptr<std::ostream> stream,
|
Logger::Logger(std::shared_ptr<std::ostream> stream,
|
||||||
Verbosity verbosity_level,
|
Verbosity verbosity_level,
|
||||||
std::string prefix)
|
std::string prefix)
|
||||||
: stream(stream), verbosity(verbosity_level), prefix(prefix) {}
|
: verbosity(verbosity_level), stream(stream), prefix(prefix) {}
|
||||||
|
|
||||||
Logger Logger::create_from_environment(std::string prefix) {
|
Logger Logger::create_from_environment(std::string prefix) {
|
||||||
auto env = boost::this_process::environment();
|
auto env = boost::this_process::environment();
|
||||||
@@ -108,514 +108,3 @@ void Logger::log_trace(const std::string& message) {
|
|||||||
log(message);
|
log(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::log_get_parameter(int index) {
|
|
||||||
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
|
||||||
std::ostringstream message;
|
|
||||||
message << ">> getParameter() " << index;
|
|
||||||
|
|
||||||
log(message.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::log_get_parameter_response(float value) {
|
|
||||||
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
|
||||||
std::ostringstream message;
|
|
||||||
message << " getParameter() :: " << value;
|
|
||||||
|
|
||||||
log(message.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::log_set_parameter(int index, float value) {
|
|
||||||
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
|
||||||
std::ostringstream message;
|
|
||||||
message << ">> setParameter() " << index << " = " << value;
|
|
||||||
|
|
||||||
log(message.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::log_set_parameter_response() {
|
|
||||||
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
|
||||||
log(" setParameter() :: OK");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::log_event(bool is_dispatch,
|
|
||||||
int opcode,
|
|
||||||
int index,
|
|
||||||
intptr_t value,
|
|
||||||
const EventPayload& payload,
|
|
||||||
float option,
|
|
||||||
const std::optional<EventPayload>& value_payload) {
|
|
||||||
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
|
||||||
if (should_filter_event(is_dispatch, opcode)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostringstream message;
|
|
||||||
if (is_dispatch) {
|
|
||||||
message << ">> dispatch() ";
|
|
||||||
} else {
|
|
||||||
message << ">> audioMasterCallback() ";
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto opcode_name = opcode_to_string(is_dispatch, opcode);
|
|
||||||
if (opcode_name) {
|
|
||||||
message << *opcode_name;
|
|
||||||
} else {
|
|
||||||
message << "<opcode = " << opcode << ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
message << "(index = " << index << ", value = " << value
|
|
||||||
<< ", option = " << option << ", data = ";
|
|
||||||
|
|
||||||
// Only used during `effSetSpeakerArrangement` and
|
|
||||||
// `effGetSpeakerArrangement`
|
|
||||||
if (value_payload) {
|
|
||||||
std::visit(
|
|
||||||
overload{
|
|
||||||
[&](auto) {},
|
|
||||||
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
|
||||||
message << "<" << speaker_arrangement.speakers.size()
|
|
||||||
<< " input_speakers>, ";
|
|
||||||
}},
|
|
||||||
*value_payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::visit(
|
|
||||||
overload{
|
|
||||||
[&](const std::nullptr_t&) { message << "<nullptr>"; },
|
|
||||||
[&](const std::string& s) {
|
|
||||||
if (s.size() < 32) {
|
|
||||||
message << "\"" << s << "\"";
|
|
||||||
} else {
|
|
||||||
// Long strings contain binary data that we probably
|
|
||||||
// don't want to print
|
|
||||||
message << "<" << s.size() << " bytes>";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&](const ChunkData& chunk) {
|
|
||||||
message << "<" << chunk.buffer.size() << " byte chunk>";
|
|
||||||
},
|
|
||||||
[&](const native_size_t& window_id) {
|
|
||||||
message << "<window " << window_id << ">";
|
|
||||||
},
|
|
||||||
[&](const AEffect&) { message << "<nullptr>"; },
|
|
||||||
[&](const DynamicVstEvents& events) {
|
|
||||||
message << "<" << events.events.size() << " midi_events>";
|
|
||||||
},
|
|
||||||
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
|
||||||
message << "<" << speaker_arrangement.speakers.size()
|
|
||||||
<< " output_speakers>";
|
|
||||||
},
|
|
||||||
[&](const VstIOProperties&) { message << "<io_properties>"; },
|
|
||||||
[&](const VstMidiKeyName&) { message << "<key_name>"; },
|
|
||||||
[&](const VstParameterProperties&) {
|
|
||||||
message << "<writable_buffer>";
|
|
||||||
},
|
|
||||||
[&](const WantsAEffectUpdate&) { message << "<nullptr>"; },
|
|
||||||
[&](const WantsChunkBuffer&) {
|
|
||||||
message << "<writable_buffer>";
|
|
||||||
},
|
|
||||||
[&](const WantsVstRect&) { message << "<writable_buffer>"; },
|
|
||||||
[&](const WantsVstTimeInfo&) { message << "<nullptr>"; },
|
|
||||||
[&](const WantsString&) { message << "<writable_string>"; }},
|
|
||||||
payload);
|
|
||||||
|
|
||||||
message << ")";
|
|
||||||
|
|
||||||
log(message.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::log_event_response(
|
|
||||||
bool is_dispatch,
|
|
||||||
int opcode,
|
|
||||||
intptr_t return_value,
|
|
||||||
const EventResultPayload& payload,
|
|
||||||
const std::optional<EventResultPayload>& value_payload) {
|
|
||||||
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
|
||||||
if (should_filter_event(is_dispatch, opcode)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostringstream message;
|
|
||||||
if (is_dispatch) {
|
|
||||||
message << " dispatch() :: ";
|
|
||||||
} else {
|
|
||||||
message << " audioMasterCallback() :: ";
|
|
||||||
}
|
|
||||||
|
|
||||||
message << return_value;
|
|
||||||
|
|
||||||
// Only used during `effSetSpeakerArrangement` and
|
|
||||||
// `effGetSpeakerArrangement`
|
|
||||||
if (value_payload) {
|
|
||||||
std::visit(
|
|
||||||
overload{
|
|
||||||
[&](auto) {},
|
|
||||||
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
|
||||||
message << ", <" << speaker_arrangement.speakers.size()
|
|
||||||
<< " input_speakers>";
|
|
||||||
}},
|
|
||||||
*value_payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::visit(
|
|
||||||
overload{
|
|
||||||
[&](const std::nullptr_t&) {},
|
|
||||||
[&](const std::string& s) {
|
|
||||||
if (s.size() < 32) {
|
|
||||||
message << ", \"" << s << "\"";
|
|
||||||
} else {
|
|
||||||
// Long strings contain binary data that we probably
|
|
||||||
// don't want to print
|
|
||||||
message << ", <" << s.size() << " bytes>";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&](const ChunkData& chunk) {
|
|
||||||
message << ", <" << chunk.buffer.size() << " byte chunk>";
|
|
||||||
},
|
|
||||||
[&](const AEffect&) { message << ", <AEffect_object>"; },
|
|
||||||
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
|
||||||
message << ", <" << speaker_arrangement.speakers.size()
|
|
||||||
<< " output_speakers>";
|
|
||||||
},
|
|
||||||
[&](const VstIOProperties&) { message << ", <io_properties>"; },
|
|
||||||
[&](const VstMidiKeyName&) { message << ", <key_name>"; },
|
|
||||||
[&](const VstParameterProperties& props) {
|
|
||||||
message << ", <parameter_properties for '" << props.label
|
|
||||||
<< "'>";
|
|
||||||
},
|
|
||||||
[&](const VstRect& rect) {
|
|
||||||
message << ", {l: " << rect.left << ", t: " << rect.top
|
|
||||||
<< ", r: " << rect.right << ", b: " << rect.bottom
|
|
||||||
<< "}";
|
|
||||||
},
|
|
||||||
[&](const VstTimeInfo& info) {
|
|
||||||
message << ", <"
|
|
||||||
<< "quarter_notes = " << info.ppqPos
|
|
||||||
<< ", samples = " << info.samplePos << ">";
|
|
||||||
}},
|
|
||||||
payload);
|
|
||||||
|
|
||||||
log(message.str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Logger::should_filter_event(bool is_dispatch, int opcode) const {
|
|
||||||
if (verbosity >= Verbosity::all_events) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter out log messages related to these events by default since they are
|
|
||||||
// called tens of times per second
|
|
||||||
// TODO: Figure out what opcode 52 is
|
|
||||||
if ((is_dispatch &&
|
|
||||||
(opcode == effEditIdle || opcode == 52 || opcode == effIdle)) ||
|
|
||||||
(!is_dispatch && (opcode == audioMasterGetTime ||
|
|
||||||
opcode == audioMasterGetCurrentProcessLevel))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<std::string> opcode_to_string(bool is_dispatch, int opcode) {
|
|
||||||
if (is_dispatch) {
|
|
||||||
// Opcodes for a plugin's dispatch function
|
|
||||||
switch (opcode) {
|
|
||||||
case effOpen:
|
|
||||||
return "effOpen";
|
|
||||||
break;
|
|
||||||
case effClose:
|
|
||||||
return "effClose";
|
|
||||||
break;
|
|
||||||
case effSetProgram:
|
|
||||||
return "effSetProgram";
|
|
||||||
break;
|
|
||||||
case effGetProgram:
|
|
||||||
return "effGetProgram";
|
|
||||||
break;
|
|
||||||
case effSetProgramName:
|
|
||||||
return "effSetProgramName";
|
|
||||||
break;
|
|
||||||
case effGetProgramName:
|
|
||||||
return "effGetProgramName";
|
|
||||||
break;
|
|
||||||
case effGetParamLabel:
|
|
||||||
return "effGetParamLabel";
|
|
||||||
break;
|
|
||||||
case effGetParamDisplay:
|
|
||||||
return "effGetParamDisplay";
|
|
||||||
break;
|
|
||||||
case effGetParamName:
|
|
||||||
return "effGetParamName";
|
|
||||||
break;
|
|
||||||
case effSetSampleRate:
|
|
||||||
return "effSetSampleRate";
|
|
||||||
break;
|
|
||||||
case effSetBlockSize:
|
|
||||||
return "effSetBlockSize";
|
|
||||||
break;
|
|
||||||
case effMainsChanged:
|
|
||||||
return "effMainsChanged";
|
|
||||||
break;
|
|
||||||
case effEditGetRect:
|
|
||||||
return "effEditGetRect";
|
|
||||||
break;
|
|
||||||
case effEditOpen:
|
|
||||||
return "effEditOpen";
|
|
||||||
break;
|
|
||||||
case effEditClose:
|
|
||||||
return "effEditClose";
|
|
||||||
break;
|
|
||||||
case effEditIdle:
|
|
||||||
return "effEditIdle";
|
|
||||||
break;
|
|
||||||
case effEditTop:
|
|
||||||
return "effEditTop";
|
|
||||||
break;
|
|
||||||
case effIdentify:
|
|
||||||
return "effIdentify";
|
|
||||||
break;
|
|
||||||
case effGetChunk:
|
|
||||||
return "effGetChunk";
|
|
||||||
break;
|
|
||||||
case effSetChunk:
|
|
||||||
return "effSetChunk";
|
|
||||||
break;
|
|
||||||
case effProcessEvents:
|
|
||||||
return "effProcessEvents";
|
|
||||||
break;
|
|
||||||
case effCanBeAutomated:
|
|
||||||
return "effCanBeAutomated";
|
|
||||||
break;
|
|
||||||
case effGetProgramNameIndexed:
|
|
||||||
return "effGetProgramNameIndexed";
|
|
||||||
break;
|
|
||||||
case effGetPlugCategory:
|
|
||||||
return "effGetPlugCategory";
|
|
||||||
break;
|
|
||||||
case effGetEffectName:
|
|
||||||
return "effGetEffectName";
|
|
||||||
break;
|
|
||||||
case effGetParameterProperties:
|
|
||||||
return "effGetParameterProperties";
|
|
||||||
break;
|
|
||||||
case effGetVendorString:
|
|
||||||
return "effGetVendorString";
|
|
||||||
break;
|
|
||||||
case effGetProductString:
|
|
||||||
return "effGetProductString";
|
|
||||||
break;
|
|
||||||
case effGetVendorVersion:
|
|
||||||
return "effGetVendorVersion";
|
|
||||||
break;
|
|
||||||
case effCanDo:
|
|
||||||
return "effCanDo";
|
|
||||||
break;
|
|
||||||
case effIdle:
|
|
||||||
return "effIdle";
|
|
||||||
break;
|
|
||||||
case effGetVstVersion:
|
|
||||||
return "effGetVstVersion";
|
|
||||||
break;
|
|
||||||
case effBeginSetProgram:
|
|
||||||
return "effBeginSetProgram";
|
|
||||||
break;
|
|
||||||
case effEndSetProgram:
|
|
||||||
return "effEndSetProgram";
|
|
||||||
break;
|
|
||||||
case effShellGetNextPlugin:
|
|
||||||
return "effShellGetNextPlugin";
|
|
||||||
break;
|
|
||||||
case effBeginLoadBank:
|
|
||||||
return "effBeginLoadBank";
|
|
||||||
break;
|
|
||||||
case effBeginLoadProgram:
|
|
||||||
return "effBeginLoadProgram";
|
|
||||||
break;
|
|
||||||
case effStartProcess:
|
|
||||||
return "effStartProcess";
|
|
||||||
break;
|
|
||||||
case effStopProcess:
|
|
||||||
return "effStopProcess";
|
|
||||||
break;
|
|
||||||
case effGetInputProperties:
|
|
||||||
return "effGetInputProperties";
|
|
||||||
break;
|
|
||||||
case effGetOutputProperties:
|
|
||||||
return "effGetOutputProperties";
|
|
||||||
break;
|
|
||||||
case effGetMidiKeyName:
|
|
||||||
return "effGetMidiKeyName";
|
|
||||||
break;
|
|
||||||
case effSetSpeakerArrangement:
|
|
||||||
return "effSetSpeakerArrangement";
|
|
||||||
break;
|
|
||||||
case effGetSpeakerArrangement:
|
|
||||||
return "effGetSpeakerArrangement ";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return std::nullopt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Opcodes for the host callback
|
|
||||||
switch (opcode) {
|
|
||||||
case audioMasterAutomate:
|
|
||||||
return "audioMasterAutomate";
|
|
||||||
break;
|
|
||||||
case audioMasterVersion:
|
|
||||||
return "audioMasterVersion";
|
|
||||||
break;
|
|
||||||
case audioMasterCurrentId:
|
|
||||||
return "audioMasterCurrentId";
|
|
||||||
break;
|
|
||||||
case audioMasterIdle:
|
|
||||||
return "audioMasterIdle";
|
|
||||||
break;
|
|
||||||
case audioMasterPinConnected:
|
|
||||||
return "audioMasterPinConnected";
|
|
||||||
break;
|
|
||||||
case audioMasterWantMidi:
|
|
||||||
return "audioMasterWantMidi";
|
|
||||||
break;
|
|
||||||
case audioMasterGetTime:
|
|
||||||
return "audioMasterGetTime";
|
|
||||||
break;
|
|
||||||
case audioMasterProcessEvents:
|
|
||||||
return "audioMasterProcessEvents";
|
|
||||||
break;
|
|
||||||
case audioMasterSetTime:
|
|
||||||
return "audioMasterSetTime";
|
|
||||||
break;
|
|
||||||
case audioMasterTempoAt:
|
|
||||||
return "audioMasterTempoAt";
|
|
||||||
break;
|
|
||||||
case audioMasterGetNumAutomatableParameters:
|
|
||||||
return "audioMasterGetNumAutomatableParameters";
|
|
||||||
break;
|
|
||||||
case audioMasterGetParameterQuantization:
|
|
||||||
return "audioMasterGetParameterQuantization";
|
|
||||||
break;
|
|
||||||
case audioMasterIOChanged:
|
|
||||||
return "audioMasterIOChanged";
|
|
||||||
break;
|
|
||||||
case audioMasterNeedIdle:
|
|
||||||
return "audioMasterNeedIdle";
|
|
||||||
break;
|
|
||||||
case audioMasterSizeWindow:
|
|
||||||
return "audioMasterSizeWindow";
|
|
||||||
break;
|
|
||||||
case audioMasterGetSampleRate:
|
|
||||||
return "audioMasterGetSampleRate";
|
|
||||||
break;
|
|
||||||
case audioMasterGetBlockSize:
|
|
||||||
return "audioMasterGetBlockSize";
|
|
||||||
break;
|
|
||||||
case audioMasterGetInputLatency:
|
|
||||||
return "audioMasterGetInputLatency";
|
|
||||||
break;
|
|
||||||
case audioMasterGetOutputLatency:
|
|
||||||
return "audioMasterGetOutputLatency";
|
|
||||||
break;
|
|
||||||
case audioMasterGetPreviousPlug:
|
|
||||||
return "audioMasterGetPreviousPlug";
|
|
||||||
break;
|
|
||||||
case audioMasterGetNextPlug:
|
|
||||||
return "audioMasterGetNextPlug";
|
|
||||||
break;
|
|
||||||
case audioMasterWillReplaceOrAccumulate:
|
|
||||||
return "audioMasterWillReplaceOrAccumulate";
|
|
||||||
break;
|
|
||||||
case audioMasterGetCurrentProcessLevel:
|
|
||||||
return "audioMasterGetCurrentProcessLevel";
|
|
||||||
break;
|
|
||||||
case audioMasterGetAutomationState:
|
|
||||||
return "audioMasterGetAutomationState";
|
|
||||||
break;
|
|
||||||
case audioMasterOfflineStart:
|
|
||||||
return "audioMasterOfflineStart";
|
|
||||||
break;
|
|
||||||
case audioMasterOfflineRead:
|
|
||||||
return "audioMasterOfflineRead";
|
|
||||||
break;
|
|
||||||
case audioMasterOfflineWrite:
|
|
||||||
return "audioMasterOfflineWrite";
|
|
||||||
break;
|
|
||||||
case audioMasterOfflineGetCurrentPass:
|
|
||||||
return "audioMasterOfflineGetCurrentPass";
|
|
||||||
break;
|
|
||||||
case audioMasterOfflineGetCurrentMetaPass:
|
|
||||||
return "audioMasterOfflineGetCurrentMetaPass";
|
|
||||||
break;
|
|
||||||
case audioMasterSetOutputSampleRate:
|
|
||||||
return "audioMasterSetOutputSampleRate";
|
|
||||||
break;
|
|
||||||
case audioMasterGetSpeakerArrangement:
|
|
||||||
return "audioMasterGetSpeakerArrangement";
|
|
||||||
break;
|
|
||||||
case audioMasterGetVendorString:
|
|
||||||
return "audioMasterGetVendorString";
|
|
||||||
break;
|
|
||||||
case audioMasterGetProductString:
|
|
||||||
return "audioMasterGetProductString";
|
|
||||||
break;
|
|
||||||
case audioMasterGetVendorVersion:
|
|
||||||
return "audioMasterGetVendorVersion";
|
|
||||||
break;
|
|
||||||
case audioMasterVendorSpecific:
|
|
||||||
return "audioMasterVendorSpecific";
|
|
||||||
break;
|
|
||||||
case audioMasterSetIcon:
|
|
||||||
return "audioMasterSetIcon";
|
|
||||||
break;
|
|
||||||
case audioMasterCanDo:
|
|
||||||
return "audioMasterCanDo";
|
|
||||||
break;
|
|
||||||
case audioMasterGetLanguage:
|
|
||||||
return "audioMasterGetLanguage";
|
|
||||||
break;
|
|
||||||
case audioMasterOpenWindow:
|
|
||||||
return "audioMasterOpenWindow";
|
|
||||||
break;
|
|
||||||
case audioMasterCloseWindow:
|
|
||||||
return "audioMasterCloseWindow";
|
|
||||||
break;
|
|
||||||
case audioMasterGetDirectory:
|
|
||||||
return "audioMasterGetDirectory";
|
|
||||||
break;
|
|
||||||
case audioMasterUpdateDisplay:
|
|
||||||
return "audioMasterUpdateDisplay";
|
|
||||||
break;
|
|
||||||
case audioMasterBeginEdit:
|
|
||||||
return "audioMasterBeginEdit";
|
|
||||||
break;
|
|
||||||
case audioMasterEndEdit:
|
|
||||||
return "audioMasterEndEdit";
|
|
||||||
break;
|
|
||||||
case audioMasterOpenFileSelector:
|
|
||||||
return "audioMasterOpenFileSelector";
|
|
||||||
break;
|
|
||||||
case audioMasterCloseFileSelector:
|
|
||||||
return "audioMasterCloseFileSelector";
|
|
||||||
break;
|
|
||||||
case audioMasterEditFile:
|
|
||||||
return "audioMasterEditFile";
|
|
||||||
break;
|
|
||||||
case audioMasterGetChunkFile:
|
|
||||||
return "audioMasterGetChunkFile";
|
|
||||||
break;
|
|
||||||
case audioMasterGetInputSpeakerArrangement:
|
|
||||||
return "audioMasterGetInputSpeakerArrangement";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return std::nullopt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,10 +20,6 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
// TODO: Split up the plugin API specific logging functions so we don't have to
|
|
||||||
// include a bunch of stuff we don't need
|
|
||||||
#include "../serialization/vst2.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Super basic logging facility meant for debugging malfunctioning VST
|
* Super basic logging facility meant for debugging malfunctioning VST
|
||||||
* plugins. This is also used to redirect the output of the Wine process
|
* plugins. This is also used to redirect the output of the Wine process
|
||||||
@@ -97,29 +93,6 @@ class Logger {
|
|||||||
*/
|
*/
|
||||||
void log(const std::string& message);
|
void log(const std::string& message);
|
||||||
|
|
||||||
// The following functions are for logging specific events, they are only
|
|
||||||
// enabled for verbosity levels higher than 1 (i.e. `Verbosity::events`)
|
|
||||||
void log_get_parameter(int index);
|
|
||||||
void log_get_parameter_response(float vlaue);
|
|
||||||
void log_set_parameter(int index, float value);
|
|
||||||
void log_set_parameter_response();
|
|
||||||
// If `is_dispatch` is `true`, then use opcode names from the plugin's
|
|
||||||
// dispatch function. Otherwise use names for the host callback function
|
|
||||||
// opcodes.
|
|
||||||
void log_event(bool is_dispatch,
|
|
||||||
int opcode,
|
|
||||||
int index,
|
|
||||||
intptr_t value,
|
|
||||||
const EventPayload& payload,
|
|
||||||
float option,
|
|
||||||
const std::optional<EventPayload>& value_payload);
|
|
||||||
void log_event_response(
|
|
||||||
bool is_dispatch,
|
|
||||||
int opcode,
|
|
||||||
intptr_t return_value,
|
|
||||||
const EventResultPayload& payload,
|
|
||||||
const std::optional<EventResultPayload>& value_payload);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log a message that should only be printed when the `verbosity` is set to
|
* Log a message that should only be printed when the `verbosity` is set to
|
||||||
* `all_events`. This should only be used for simple primitive messages
|
* `all_events`. This should only be used for simple primitive messages
|
||||||
@@ -130,38 +103,20 @@ class Logger {
|
|||||||
*/
|
*/
|
||||||
void log_trace(const std::string& message);
|
void log_trace(const std::string& message);
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* Determine whether an event should be filtered based on the current
|
* The verbosity level of this logger instance. Based on this certain
|
||||||
* verbosity level.
|
* messages may or may not be shown.
|
||||||
*/
|
*/
|
||||||
bool should_filter_event(bool is_dispatch, int opcode) const;
|
const Verbosity verbosity;
|
||||||
|
|
||||||
|
private:
|
||||||
/**
|
/**
|
||||||
* The output stream to write the log messages to. Typically either STDERR
|
* The output stream to write the log messages to. Typically either STDERR
|
||||||
* or a file stream.
|
* or a file stream.
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<std::ostream> stream;
|
std::shared_ptr<std::ostream> stream;
|
||||||
/**
|
|
||||||
* The verbosity level of this logger instance. Based on this certain
|
|
||||||
* messages may or may not be shown.
|
|
||||||
*/
|
|
||||||
Verbosity verbosity;
|
|
||||||
/**
|
/**
|
||||||
* A prefix that gets prepended before every message.
|
* A prefix that gets prepended before every message.
|
||||||
*/
|
*/
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an event opcode to a human readable string for debugging purposes.
|
|
||||||
* See `src/include/vestige/aeffectx.h` for a complete list of these opcodes.
|
|
||||||
*
|
|
||||||
* @param is_dispatch Whether to use opcodes for the `dispatch` function. Will
|
|
||||||
* use the names from the host callback function if set to false.
|
|
||||||
* @param opcode The opcode of the event.
|
|
||||||
*
|
|
||||||
* @return Either the name from `aeffectx.h`, or a nullopt if it was not listed
|
|
||||||
* there.
|
|
||||||
*/
|
|
||||||
std::optional<std::string> opcode_to_string(bool is_dispatch, int opcode);
|
|
||||||
|
|||||||
@@ -0,0 +1,530 @@
|
|||||||
|
// yabridge: a Wine VST bridge
|
||||||
|
// Copyright (C) 2020 Robbert van der Helm
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "vst2.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
std::optional<std::string> opcode_to_string(bool is_dispatch, int opcode) {
|
||||||
|
if (is_dispatch) {
|
||||||
|
// Opcodes for a plugin's dispatch function
|
||||||
|
switch (opcode) {
|
||||||
|
case effOpen:
|
||||||
|
return "effOpen";
|
||||||
|
break;
|
||||||
|
case effClose:
|
||||||
|
return "effClose";
|
||||||
|
break;
|
||||||
|
case effSetProgram:
|
||||||
|
return "effSetProgram";
|
||||||
|
break;
|
||||||
|
case effGetProgram:
|
||||||
|
return "effGetProgram";
|
||||||
|
break;
|
||||||
|
case effSetProgramName:
|
||||||
|
return "effSetProgramName";
|
||||||
|
break;
|
||||||
|
case effGetProgramName:
|
||||||
|
return "effGetProgramName";
|
||||||
|
break;
|
||||||
|
case effGetParamLabel:
|
||||||
|
return "effGetParamLabel";
|
||||||
|
break;
|
||||||
|
case effGetParamDisplay:
|
||||||
|
return "effGetParamDisplay";
|
||||||
|
break;
|
||||||
|
case effGetParamName:
|
||||||
|
return "effGetParamName";
|
||||||
|
break;
|
||||||
|
case effSetSampleRate:
|
||||||
|
return "effSetSampleRate";
|
||||||
|
break;
|
||||||
|
case effSetBlockSize:
|
||||||
|
return "effSetBlockSize";
|
||||||
|
break;
|
||||||
|
case effMainsChanged:
|
||||||
|
return "effMainsChanged";
|
||||||
|
break;
|
||||||
|
case effEditGetRect:
|
||||||
|
return "effEditGetRect";
|
||||||
|
break;
|
||||||
|
case effEditOpen:
|
||||||
|
return "effEditOpen";
|
||||||
|
break;
|
||||||
|
case effEditClose:
|
||||||
|
return "effEditClose";
|
||||||
|
break;
|
||||||
|
case effEditIdle:
|
||||||
|
return "effEditIdle";
|
||||||
|
break;
|
||||||
|
case effEditTop:
|
||||||
|
return "effEditTop";
|
||||||
|
break;
|
||||||
|
case effIdentify:
|
||||||
|
return "effIdentify";
|
||||||
|
break;
|
||||||
|
case effGetChunk:
|
||||||
|
return "effGetChunk";
|
||||||
|
break;
|
||||||
|
case effSetChunk:
|
||||||
|
return "effSetChunk";
|
||||||
|
break;
|
||||||
|
case effProcessEvents:
|
||||||
|
return "effProcessEvents";
|
||||||
|
break;
|
||||||
|
case effCanBeAutomated:
|
||||||
|
return "effCanBeAutomated";
|
||||||
|
break;
|
||||||
|
case effGetProgramNameIndexed:
|
||||||
|
return "effGetProgramNameIndexed";
|
||||||
|
break;
|
||||||
|
case effGetPlugCategory:
|
||||||
|
return "effGetPlugCategory";
|
||||||
|
break;
|
||||||
|
case effGetEffectName:
|
||||||
|
return "effGetEffectName";
|
||||||
|
break;
|
||||||
|
case effGetParameterProperties:
|
||||||
|
return "effGetParameterProperties";
|
||||||
|
break;
|
||||||
|
case effGetVendorString:
|
||||||
|
return "effGetVendorString";
|
||||||
|
break;
|
||||||
|
case effGetProductString:
|
||||||
|
return "effGetProductString";
|
||||||
|
break;
|
||||||
|
case effGetVendorVersion:
|
||||||
|
return "effGetVendorVersion";
|
||||||
|
break;
|
||||||
|
case effCanDo:
|
||||||
|
return "effCanDo";
|
||||||
|
break;
|
||||||
|
case effIdle:
|
||||||
|
return "effIdle";
|
||||||
|
break;
|
||||||
|
case effGetVstVersion:
|
||||||
|
return "effGetVstVersion";
|
||||||
|
break;
|
||||||
|
case effBeginSetProgram:
|
||||||
|
return "effBeginSetProgram";
|
||||||
|
break;
|
||||||
|
case effEndSetProgram:
|
||||||
|
return "effEndSetProgram";
|
||||||
|
break;
|
||||||
|
case effShellGetNextPlugin:
|
||||||
|
return "effShellGetNextPlugin";
|
||||||
|
break;
|
||||||
|
case effBeginLoadBank:
|
||||||
|
return "effBeginLoadBank";
|
||||||
|
break;
|
||||||
|
case effBeginLoadProgram:
|
||||||
|
return "effBeginLoadProgram";
|
||||||
|
break;
|
||||||
|
case effStartProcess:
|
||||||
|
return "effStartProcess";
|
||||||
|
break;
|
||||||
|
case effStopProcess:
|
||||||
|
return "effStopProcess";
|
||||||
|
break;
|
||||||
|
case effGetInputProperties:
|
||||||
|
return "effGetInputProperties";
|
||||||
|
break;
|
||||||
|
case effGetOutputProperties:
|
||||||
|
return "effGetOutputProperties";
|
||||||
|
break;
|
||||||
|
case effGetMidiKeyName:
|
||||||
|
return "effGetMidiKeyName";
|
||||||
|
break;
|
||||||
|
case effSetSpeakerArrangement:
|
||||||
|
return "effSetSpeakerArrangement";
|
||||||
|
break;
|
||||||
|
case effGetSpeakerArrangement:
|
||||||
|
return "effGetSpeakerArrangement ";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return std::nullopt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Opcodes for the host callback
|
||||||
|
switch (opcode) {
|
||||||
|
case audioMasterAutomate:
|
||||||
|
return "audioMasterAutomate";
|
||||||
|
break;
|
||||||
|
case audioMasterVersion:
|
||||||
|
return "audioMasterVersion";
|
||||||
|
break;
|
||||||
|
case audioMasterCurrentId:
|
||||||
|
return "audioMasterCurrentId";
|
||||||
|
break;
|
||||||
|
case audioMasterIdle:
|
||||||
|
return "audioMasterIdle";
|
||||||
|
break;
|
||||||
|
case audioMasterPinConnected:
|
||||||
|
return "audioMasterPinConnected";
|
||||||
|
break;
|
||||||
|
case audioMasterWantMidi:
|
||||||
|
return "audioMasterWantMidi";
|
||||||
|
break;
|
||||||
|
case audioMasterGetTime:
|
||||||
|
return "audioMasterGetTime";
|
||||||
|
break;
|
||||||
|
case audioMasterProcessEvents:
|
||||||
|
return "audioMasterProcessEvents";
|
||||||
|
break;
|
||||||
|
case audioMasterSetTime:
|
||||||
|
return "audioMasterSetTime";
|
||||||
|
break;
|
||||||
|
case audioMasterTempoAt:
|
||||||
|
return "audioMasterTempoAt";
|
||||||
|
break;
|
||||||
|
case audioMasterGetNumAutomatableParameters:
|
||||||
|
return "audioMasterGetNumAutomatableParameters";
|
||||||
|
break;
|
||||||
|
case audioMasterGetParameterQuantization:
|
||||||
|
return "audioMasterGetParameterQuantization";
|
||||||
|
break;
|
||||||
|
case audioMasterIOChanged:
|
||||||
|
return "audioMasterIOChanged";
|
||||||
|
break;
|
||||||
|
case audioMasterNeedIdle:
|
||||||
|
return "audioMasterNeedIdle";
|
||||||
|
break;
|
||||||
|
case audioMasterSizeWindow:
|
||||||
|
return "audioMasterSizeWindow";
|
||||||
|
break;
|
||||||
|
case audioMasterGetSampleRate:
|
||||||
|
return "audioMasterGetSampleRate";
|
||||||
|
break;
|
||||||
|
case audioMasterGetBlockSize:
|
||||||
|
return "audioMasterGetBlockSize";
|
||||||
|
break;
|
||||||
|
case audioMasterGetInputLatency:
|
||||||
|
return "audioMasterGetInputLatency";
|
||||||
|
break;
|
||||||
|
case audioMasterGetOutputLatency:
|
||||||
|
return "audioMasterGetOutputLatency";
|
||||||
|
break;
|
||||||
|
case audioMasterGetPreviousPlug:
|
||||||
|
return "audioMasterGetPreviousPlug";
|
||||||
|
break;
|
||||||
|
case audioMasterGetNextPlug:
|
||||||
|
return "audioMasterGetNextPlug";
|
||||||
|
break;
|
||||||
|
case audioMasterWillReplaceOrAccumulate:
|
||||||
|
return "audioMasterWillReplaceOrAccumulate";
|
||||||
|
break;
|
||||||
|
case audioMasterGetCurrentProcessLevel:
|
||||||
|
return "audioMasterGetCurrentProcessLevel";
|
||||||
|
break;
|
||||||
|
case audioMasterGetAutomationState:
|
||||||
|
return "audioMasterGetAutomationState";
|
||||||
|
break;
|
||||||
|
case audioMasterOfflineStart:
|
||||||
|
return "audioMasterOfflineStart";
|
||||||
|
break;
|
||||||
|
case audioMasterOfflineRead:
|
||||||
|
return "audioMasterOfflineRead";
|
||||||
|
break;
|
||||||
|
case audioMasterOfflineWrite:
|
||||||
|
return "audioMasterOfflineWrite";
|
||||||
|
break;
|
||||||
|
case audioMasterOfflineGetCurrentPass:
|
||||||
|
return "audioMasterOfflineGetCurrentPass";
|
||||||
|
break;
|
||||||
|
case audioMasterOfflineGetCurrentMetaPass:
|
||||||
|
return "audioMasterOfflineGetCurrentMetaPass";
|
||||||
|
break;
|
||||||
|
case audioMasterSetOutputSampleRate:
|
||||||
|
return "audioMasterSetOutputSampleRate";
|
||||||
|
break;
|
||||||
|
case audioMasterGetSpeakerArrangement:
|
||||||
|
return "audioMasterGetSpeakerArrangement";
|
||||||
|
break;
|
||||||
|
case audioMasterGetVendorString:
|
||||||
|
return "audioMasterGetVendorString";
|
||||||
|
break;
|
||||||
|
case audioMasterGetProductString:
|
||||||
|
return "audioMasterGetProductString";
|
||||||
|
break;
|
||||||
|
case audioMasterGetVendorVersion:
|
||||||
|
return "audioMasterGetVendorVersion";
|
||||||
|
break;
|
||||||
|
case audioMasterVendorSpecific:
|
||||||
|
return "audioMasterVendorSpecific";
|
||||||
|
break;
|
||||||
|
case audioMasterSetIcon:
|
||||||
|
return "audioMasterSetIcon";
|
||||||
|
break;
|
||||||
|
case audioMasterCanDo:
|
||||||
|
return "audioMasterCanDo";
|
||||||
|
break;
|
||||||
|
case audioMasterGetLanguage:
|
||||||
|
return "audioMasterGetLanguage";
|
||||||
|
break;
|
||||||
|
case audioMasterOpenWindow:
|
||||||
|
return "audioMasterOpenWindow";
|
||||||
|
break;
|
||||||
|
case audioMasterCloseWindow:
|
||||||
|
return "audioMasterCloseWindow";
|
||||||
|
break;
|
||||||
|
case audioMasterGetDirectory:
|
||||||
|
return "audioMasterGetDirectory";
|
||||||
|
break;
|
||||||
|
case audioMasterUpdateDisplay:
|
||||||
|
return "audioMasterUpdateDisplay";
|
||||||
|
break;
|
||||||
|
case audioMasterBeginEdit:
|
||||||
|
return "audioMasterBeginEdit";
|
||||||
|
break;
|
||||||
|
case audioMasterEndEdit:
|
||||||
|
return "audioMasterEndEdit";
|
||||||
|
break;
|
||||||
|
case audioMasterOpenFileSelector:
|
||||||
|
return "audioMasterOpenFileSelector";
|
||||||
|
break;
|
||||||
|
case audioMasterCloseFileSelector:
|
||||||
|
return "audioMasterCloseFileSelector";
|
||||||
|
break;
|
||||||
|
case audioMasterEditFile:
|
||||||
|
return "audioMasterEditFile";
|
||||||
|
break;
|
||||||
|
case audioMasterGetChunkFile:
|
||||||
|
return "audioMasterGetChunkFile";
|
||||||
|
break;
|
||||||
|
case audioMasterGetInputSpeakerArrangement:
|
||||||
|
return "audioMasterGetInputSpeakerArrangement";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return std::nullopt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst2Logger::log_get_parameter(int index) {
|
||||||
|
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
||||||
|
std::ostringstream message;
|
||||||
|
message << ">> getParameter() " << index;
|
||||||
|
|
||||||
|
log(message.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst2Logger::log_get_parameter_response(float value) {
|
||||||
|
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
||||||
|
std::ostringstream message;
|
||||||
|
message << " getParameter() :: " << value;
|
||||||
|
|
||||||
|
log(message.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst2Logger::log_set_parameter(int index, float value) {
|
||||||
|
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
||||||
|
std::ostringstream message;
|
||||||
|
message << ">> setParameter() " << index << " = " << value;
|
||||||
|
|
||||||
|
log(message.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst2Logger::log_set_parameter_response() {
|
||||||
|
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
||||||
|
log(" setParameter() :: OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst2Logger::log_event(bool is_dispatch,
|
||||||
|
int opcode,
|
||||||
|
int index,
|
||||||
|
intptr_t value,
|
||||||
|
const EventPayload& payload,
|
||||||
|
float option,
|
||||||
|
const std::optional<EventPayload>& value_payload) {
|
||||||
|
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
||||||
|
if (should_filter_event(is_dispatch, opcode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream message;
|
||||||
|
if (is_dispatch) {
|
||||||
|
message << ">> dispatch() ";
|
||||||
|
} else {
|
||||||
|
message << ">> audioMasterCallback() ";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto opcode_name = opcode_to_string(is_dispatch, opcode);
|
||||||
|
if (opcode_name) {
|
||||||
|
message << *opcode_name;
|
||||||
|
} else {
|
||||||
|
message << "<opcode = " << opcode << ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
message << "(index = " << index << ", value = " << value
|
||||||
|
<< ", option = " << option << ", data = ";
|
||||||
|
|
||||||
|
// Only used during `effSetSpeakerArrangement` and
|
||||||
|
// `effGetSpeakerArrangement`
|
||||||
|
if (value_payload) {
|
||||||
|
std::visit(
|
||||||
|
overload{
|
||||||
|
[&](auto) {},
|
||||||
|
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
||||||
|
message << "<" << speaker_arrangement.speakers.size()
|
||||||
|
<< " input_speakers>, ";
|
||||||
|
}},
|
||||||
|
*value_payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
overload{
|
||||||
|
[&](const std::nullptr_t&) { message << "<nullptr>"; },
|
||||||
|
[&](const std::string& s) {
|
||||||
|
if (s.size() < 32) {
|
||||||
|
message << "\"" << s << "\"";
|
||||||
|
} else {
|
||||||
|
// Long strings contain binary data that we probably
|
||||||
|
// don't want to print
|
||||||
|
message << "<" << s.size() << " bytes>";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ChunkData& chunk) {
|
||||||
|
message << "<" << chunk.buffer.size() << " byte chunk>";
|
||||||
|
},
|
||||||
|
[&](const native_size_t& window_id) {
|
||||||
|
message << "<window " << window_id << ">";
|
||||||
|
},
|
||||||
|
[&](const AEffect&) { message << "<nullptr>"; },
|
||||||
|
[&](const DynamicVstEvents& events) {
|
||||||
|
message << "<" << events.events.size() << " midi_events>";
|
||||||
|
},
|
||||||
|
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
||||||
|
message << "<" << speaker_arrangement.speakers.size()
|
||||||
|
<< " output_speakers>";
|
||||||
|
},
|
||||||
|
[&](const VstIOProperties&) { message << "<io_properties>"; },
|
||||||
|
[&](const VstMidiKeyName&) { message << "<key_name>"; },
|
||||||
|
[&](const VstParameterProperties&) {
|
||||||
|
message << "<writable_buffer>";
|
||||||
|
},
|
||||||
|
[&](const WantsAEffectUpdate&) { message << "<nullptr>"; },
|
||||||
|
[&](const WantsChunkBuffer&) {
|
||||||
|
message << "<writable_buffer>";
|
||||||
|
},
|
||||||
|
[&](const WantsVstRect&) { message << "<writable_buffer>"; },
|
||||||
|
[&](const WantsVstTimeInfo&) { message << "<nullptr>"; },
|
||||||
|
[&](const WantsString&) { message << "<writable_string>"; }},
|
||||||
|
payload);
|
||||||
|
|
||||||
|
message << ")";
|
||||||
|
|
||||||
|
log(message.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vst2Logger::log_event_response(
|
||||||
|
bool is_dispatch,
|
||||||
|
int opcode,
|
||||||
|
intptr_t return_value,
|
||||||
|
const EventResultPayload& payload,
|
||||||
|
const std::optional<EventResultPayload>& value_payload) {
|
||||||
|
if (BOOST_UNLIKELY(verbosity >= Verbosity::most_events)) {
|
||||||
|
if (should_filter_event(is_dispatch, opcode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostringstream message;
|
||||||
|
if (is_dispatch) {
|
||||||
|
message << " dispatch() :: ";
|
||||||
|
} else {
|
||||||
|
message << " audioMasterCallback() :: ";
|
||||||
|
}
|
||||||
|
|
||||||
|
message << return_value;
|
||||||
|
|
||||||
|
// Only used during `effSetSpeakerArrangement` and
|
||||||
|
// `effGetSpeakerArrangement`
|
||||||
|
if (value_payload) {
|
||||||
|
std::visit(
|
||||||
|
overload{
|
||||||
|
[&](auto) {},
|
||||||
|
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
||||||
|
message << ", <" << speaker_arrangement.speakers.size()
|
||||||
|
<< " input_speakers>";
|
||||||
|
}},
|
||||||
|
*value_payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
overload{
|
||||||
|
[&](const std::nullptr_t&) {},
|
||||||
|
[&](const std::string& s) {
|
||||||
|
if (s.size() < 32) {
|
||||||
|
message << ", \"" << s << "\"";
|
||||||
|
} else {
|
||||||
|
// Long strings contain binary data that we probably
|
||||||
|
// don't want to print
|
||||||
|
message << ", <" << s.size() << " bytes>";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](const ChunkData& chunk) {
|
||||||
|
message << "<" << chunk.buffer.size() << " byte chunk>";
|
||||||
|
},
|
||||||
|
[&](const AEffect&) { message << ", <AEffect_object>"; },
|
||||||
|
[&](const DynamicSpeakerArrangement& speaker_arrangement) {
|
||||||
|
message << ", <" << speaker_arrangement.speakers.size()
|
||||||
|
<< " output_speakers>";
|
||||||
|
},
|
||||||
|
[&](const VstIOProperties&) { message << ", <io_properties>"; },
|
||||||
|
[&](const VstMidiKeyName&) { message << ", <key_name>"; },
|
||||||
|
[&](const VstParameterProperties& props) {
|
||||||
|
message << ", <parameter_properties for '" << props.label
|
||||||
|
<< "'>";
|
||||||
|
},
|
||||||
|
[&](const VstRect& rect) {
|
||||||
|
message << ", {l: " << rect.left << ", t: " << rect.top
|
||||||
|
<< ", r: " << rect.right << ", b: " << rect.bottom
|
||||||
|
<< "}";
|
||||||
|
},
|
||||||
|
[&](const VstTimeInfo& info) {
|
||||||
|
message << ", <"
|
||||||
|
<< "quarter_notes = " << info.ppqPos
|
||||||
|
<< ", samples = " << info.samplePos << ">";
|
||||||
|
}},
|
||||||
|
payload);
|
||||||
|
|
||||||
|
log(message.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vst2Logger::should_filter_event(bool is_dispatch, int opcode) const {
|
||||||
|
if (verbosity >= Verbosity::all_events) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out log messages related to these events by default since they are
|
||||||
|
// called tens of times per second
|
||||||
|
// TODO: Figure out what opcode 52 is
|
||||||
|
if ((is_dispatch &&
|
||||||
|
(opcode == effEditIdle || opcode == 52 || opcode == effIdle)) ||
|
||||||
|
(!is_dispatch && (opcode == audioMasterGetTime ||
|
||||||
|
opcode == audioMasterGetCurrentProcessLevel))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// yabridge: a Wine VST bridge
|
||||||
|
// Copyright (C) 2020 Robbert van der Helm
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../serialization/vst2.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an event opcode to a human readable string for debugging purposes.
|
||||||
|
* See `src/include/vestige/aeffectx.h` for a complete list of these opcodes.
|
||||||
|
*
|
||||||
|
* @param is_dispatch Whether to use opcodes for the `dispatch` function. Will
|
||||||
|
* use the names from the host callback function if set to false.
|
||||||
|
* @param opcode The opcode of the event.
|
||||||
|
*
|
||||||
|
* @return Either the name from `aeffectx.h`, or a nullopt if it was not listed
|
||||||
|
* there.
|
||||||
|
*/
|
||||||
|
std::optional<std::string> opcode_to_string(bool is_dispatch, int opcode);
|
||||||
|
|
||||||
|
class Vst2Logger : public Logger {
|
||||||
|
public:
|
||||||
|
// The following functions are for logging specific events, they are only
|
||||||
|
// enabled for verbosity levels higher than 1 (i.e. `Verbosity::events`)
|
||||||
|
void log_get_parameter(int index);
|
||||||
|
void log_get_parameter_response(float vlaue);
|
||||||
|
void log_set_parameter(int index, float value);
|
||||||
|
void log_set_parameter_response();
|
||||||
|
// If `is_dispatch` is `true`, then use opcode names from the plugin's
|
||||||
|
// dispatch function. Otherwise use names for the host callback function
|
||||||
|
// opcodes.
|
||||||
|
void log_event(bool is_dispatch,
|
||||||
|
int opcode,
|
||||||
|
int index,
|
||||||
|
intptr_t value,
|
||||||
|
const EventPayload& payload,
|
||||||
|
float option,
|
||||||
|
const std::optional<EventPayload>& value_payload);
|
||||||
|
void log_event_response(
|
||||||
|
bool is_dispatch,
|
||||||
|
int opcode,
|
||||||
|
intptr_t return_value,
|
||||||
|
const EventResultPayload& payload,
|
||||||
|
const std::optional<EventResultPayload>& value_payload);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Determine whether an event should be filtered based on the current
|
||||||
|
* verbosity level.
|
||||||
|
*/
|
||||||
|
bool should_filter_event(bool is_dispatch, int opcode) const;
|
||||||
|
};
|
||||||
@@ -127,7 +127,7 @@ Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
|
|||||||
// lockstep anyway
|
// lockstep anyway
|
||||||
host_callback_handler = std::jthread([&]() {
|
host_callback_handler = std::jthread([&]() {
|
||||||
sockets.vst_host_callback.receive_events(
|
sockets.vst_host_callback.receive_events(
|
||||||
std::pair<Logger&, bool>(logger, false),
|
std::pair<Vst2Logger&, bool>(logger, false),
|
||||||
[&](Event& event, bool /*on_main_thread*/) {
|
[&](Event& event, bool /*on_main_thread*/) {
|
||||||
// MIDI events sent from the plugin back to the host are a
|
// MIDI events sent from the plugin back to the host are a
|
||||||
// special case here. They have to sent during the
|
// special case here. They have to sent during the
|
||||||
@@ -431,8 +431,8 @@ intptr_t Vst2PluginBridge::dispatch(AEffect* /*plugin*/,
|
|||||||
try {
|
try {
|
||||||
// TODO: Add some kind of timeout?
|
// TODO: Add some kind of timeout?
|
||||||
return_value = sockets.host_vst_dispatch.send_event(
|
return_value = sockets.host_vst_dispatch.send_event(
|
||||||
converter, std::pair<Logger&, bool>(logger, true), opcode,
|
converter, std::pair<Vst2Logger&, bool>(logger, true),
|
||||||
index, value, data, option);
|
opcode, index, value, data, option);
|
||||||
} catch (const boost::system::system_error& a) {
|
} catch (const boost::system::system_error& a) {
|
||||||
// Thrown when the socket gets closed because the VST plugin
|
// Thrown when the socket gets closed because the VST plugin
|
||||||
// loaded into the Wine process crashed during shutdown
|
// loaded into the Wine process crashed during shutdown
|
||||||
@@ -483,8 +483,8 @@ intptr_t Vst2PluginBridge::dispatch(AEffect* /*plugin*/,
|
|||||||
// receiving function temporarily allocate a large enough buffer rather than
|
// receiving function temporarily allocate a large enough buffer rather than
|
||||||
// to have a bunch of allocated memory sitting around doing nothing.
|
// to have a bunch of allocated memory sitting around doing nothing.
|
||||||
return sockets.host_vst_dispatch.send_event(
|
return sockets.host_vst_dispatch.send_event(
|
||||||
converter, std::pair<Logger&, bool>(logger, true), opcode, index, value,
|
converter, std::pair<Vst2Logger&, bool>(logger, true), opcode, index,
|
||||||
data, option);
|
value, data, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, bool replacing>
|
template <typename T, bool replacing>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "../../common/communication/vst2.h"
|
#include "../../common/communication/vst2.h"
|
||||||
#include "../../common/configuration.h"
|
#include "../../common/configuration.h"
|
||||||
#include "../../common/logging/common.h"
|
#include "../../common/logging/vst2.h"
|
||||||
#include "../host-process.h"
|
#include "../host-process.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -171,7 +171,7 @@ class Vst2PluginBridge {
|
|||||||
*
|
*
|
||||||
* @see Logger::create_from_env
|
* @see Logger::create_from_env
|
||||||
*/
|
*/
|
||||||
Logger logger;
|
Vst2Logger logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The version of Wine currently in use. Used in the debug output on plugin
|
* The version of Wine currently in use. Used in the debug output on plugin
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "../common/communication/common.h"
|
#include "../common/communication/common.h"
|
||||||
#include "../common/logging/common.h"
|
#include "../common/logging/common.h"
|
||||||
#include "../common/plugins.h"
|
#include "../common/plugins.h"
|
||||||
|
#include "../common/serialization/common.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
#include "../../common/communication/vst2.h"
|
#include "../../common/communication/vst2.h"
|
||||||
#include "../../common/configuration.h"
|
#include "../../common/configuration.h"
|
||||||
#include "../../common/logging/common.h"
|
|
||||||
#include "../editor.h"
|
#include "../editor.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user