Split VST2 specific functionality into Vst2Logger

This commit is contained in:
Robbert van der Helm
2020-12-01 21:42:33 +01:00
parent 2230b5099f
commit f9a1bcd7bd
11 changed files with 617 additions and 572 deletions
+3
View File
@@ -85,6 +85,7 @@ shared_library(
'src/common/serialization/vst2.cpp',
'src/common/configuration.cpp',
'src/common/logging/common.cpp',
'src/common/logging/vst2.cpp',
'src/common/plugins.cpp',
'src/common/utils.cpp',
'src/plugin/bridges/vst2.cpp',
@@ -204,6 +205,7 @@ if with_vst3
'yabridge-vst3',
[
'src/common/logging/common.cpp',
'src/common/logging/vst2.cpp',
'src/plugin/vst3-plugin.cpp',
version_header,
],
@@ -229,6 +231,7 @@ host_sources = [
'src/common/serialization/vst2.cpp',
'src/common/configuration.cpp',
'src/common/logging/common.cpp',
'src/common/logging/vst2.cpp',
'src/common/plugins.cpp',
'src/common/utils.cpp',
'src/wine-host/bridges/vst2.cpp',
+1
View File
@@ -18,6 +18,7 @@
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/traits/vector.h>
#ifdef __WINE__
#include "../wine-host/boost-fix.h"
+4 -3
View File
@@ -18,7 +18,8 @@
#include <atomic>
#include "../logging/common.h"
#include "../logging/vst2.h"
#include "../serialization/vst2.h"
#include "common.h"
/**
@@ -151,7 +152,7 @@ class EventHandler : public AdHocSocketHandler<Thread> {
*/
template <typename D>
intptr_t send_event(D& data_converter,
std::optional<std::pair<Logger&, bool>> logging,
std::optional<std::pair<Vst2Logger&, bool>> logging,
int opcode,
int index,
intptr_t value,
@@ -226,7 +227,7 @@ class EventHandler : public AdHocSocketHandler<Thread> {
* @relates passthrough_event
*/
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) {
// Reading, processing, and writing back event data from the sockets
// works in the same way regardless of which socket we're using
+1 -512
View File
@@ -46,7 +46,7 @@ constexpr char logging_verbosity_environment_variable[] =
Logger::Logger(std::shared_ptr<std::ostream> stream,
Verbosity verbosity_level,
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) {
auto env = boost::this_process::environment();
@@ -108,514 +108,3 @@ void Logger::log_trace(const std::string& 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;
}
}
}
+4 -49
View File
@@ -20,10 +20,6 @@
#include <optional>
#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
* 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);
// 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
* `all_events`. This should only be used for simple primitive messages
@@ -130,38 +103,20 @@ class Logger {
*/
void log_trace(const std::string& message);
private:
/**
* Determine whether an event should be filtered based on the current
* verbosity level.
* The verbosity level of this logger instance. Based on this certain
* 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
* or a file 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.
*/
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);
+530
View File
@@ -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;
}
+66
View File
@@ -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;
};
+5 -5
View File
@@ -127,7 +127,7 @@ Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
// lockstep anyway
host_callback_handler = std::jthread([&]() {
sockets.vst_host_callback.receive_events(
std::pair<Logger&, bool>(logger, false),
std::pair<Vst2Logger&, bool>(logger, false),
[&](Event& event, bool /*on_main_thread*/) {
// MIDI events sent from the plugin back to the host are a
// special case here. They have to sent during the
@@ -431,8 +431,8 @@ intptr_t Vst2PluginBridge::dispatch(AEffect* /*plugin*/,
try {
// TODO: Add some kind of timeout?
return_value = sockets.host_vst_dispatch.send_event(
converter, std::pair<Logger&, bool>(logger, true), opcode,
index, value, data, option);
converter, std::pair<Vst2Logger&, bool>(logger, true),
opcode, index, value, data, option);
} catch (const boost::system::system_error& a) {
// Thrown when the socket gets closed because the VST plugin
// 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
// to have a bunch of allocated memory sitting around doing nothing.
return sockets.host_vst_dispatch.send_event(
converter, std::pair<Logger&, bool>(logger, true), opcode, index, value,
data, option);
converter, std::pair<Vst2Logger&, bool>(logger, true), opcode, index,
value, data, option);
}
template <typename T, bool replacing>
+2 -2
View File
@@ -25,7 +25,7 @@
#include "../../common/communication/vst2.h"
#include "../../common/configuration.h"
#include "../../common/logging/common.h"
#include "../../common/logging/vst2.h"
#include "../host-process.h"
/**
@@ -171,7 +171,7 @@ class Vst2PluginBridge {
*
* @see Logger::create_from_env
*/
Logger logger;
Vst2Logger logger;
/**
* The version of Wine currently in use. Used in the debug output on plugin
+1
View File
@@ -28,6 +28,7 @@
#include "../common/communication/common.h"
#include "../common/logging/common.h"
#include "../common/plugins.h"
#include "../common/serialization/common.h"
#include "utils.h"
/**
-1
View File
@@ -31,7 +31,6 @@
#include "../../common/communication/vst2.h"
#include "../../common/configuration.h"
#include "../../common/logging/common.h"
#include "../editor.h"
#include "../utils.h"