Merge branch 'sfztools:develop' into develop
This commit is contained in:
commit
2198711123
22 changed files with 306 additions and 112 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -13,7 +13,7 @@
|
||||||
shallow = true
|
shallow = true
|
||||||
[submodule "vst/external/VST_SDK/VST3_SDK/public.sdk"]
|
[submodule "vst/external/VST_SDK/VST3_SDK/public.sdk"]
|
||||||
path = plugins/vst/external/VST_SDK/VST3_SDK/public.sdk
|
path = plugins/vst/external/VST_SDK/VST3_SDK/public.sdk
|
||||||
url = https://github.com/sfztools/vst3_public_sdk.git
|
url = https://github.com/steinbergmedia/vst3_public_sdk.git
|
||||||
shallow = true
|
shallow = true
|
||||||
[submodule "vst/external/VST_SDK/VST3_SDK/vstgui4"]
|
[submodule "vst/external/VST_SDK/VST3_SDK/vstgui4"]
|
||||||
path = plugins/editor/external/vstgui4
|
path = plugins/editor/external/vstgui4
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ std::string getDescriptionBlob(sfizz_synth_t* handle)
|
||||||
synth.sendMessage(*client, 0, "/key/slots", "", nullptr);
|
synth.sendMessage(*client, 0, "/key/slots", "", nullptr);
|
||||||
synth.sendMessage(*client, 0, "/sw/last/slots", "", nullptr);
|
synth.sendMessage(*client, 0, "/sw/last/slots", "", nullptr);
|
||||||
synth.sendMessage(*client, 0, "/cc/slots", "", nullptr);
|
synth.sendMessage(*client, 0, "/cc/slots", "", nullptr);
|
||||||
|
synth.sendMessage(*client, 0, "/sustain_or_sostenuto/slots", "", nullptr);
|
||||||
|
|
||||||
blob.shrink_to_fit();
|
blob.shrink_to_fit();
|
||||||
return blob;
|
return blob;
|
||||||
|
|
@ -152,6 +153,8 @@ InstrumentDescription parseDescriptionBlob(absl::string_view blob)
|
||||||
copyArgToBitSpan(args[0], desc.keyswitchUsed.span());
|
copyArgToBitSpan(args[0], desc.keyswitchUsed.span());
|
||||||
else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b"))
|
else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b"))
|
||||||
copyArgToBitSpan(args[0], desc.ccUsed.span());
|
copyArgToBitSpan(args[0], desc.ccUsed.span());
|
||||||
|
else if (Messages::matchOSC("/sustain_or_sostenuto/slots", path, indices) && !strcmp(sig, "b"))
|
||||||
|
copyArgToBitSpan(args[0], desc.sustainOrSostenuto.span());
|
||||||
else if (Messages::matchOSC("/key&/label", path, indices) && !strcmp(sig, "s"))
|
else if (Messages::matchOSC("/key&/label", path, indices) && !strcmp(sig, "s"))
|
||||||
desc.keyLabel[indices[0]] = args[0].s;
|
desc.keyLabel[indices[0]] = args[0].s;
|
||||||
else if (Messages::matchOSC("/sw/last/&/label", path, indices) && !strcmp(sig, "s"))
|
else if (Messages::matchOSC("/sw/last/&/label", path, indices) && !strcmp(sig, "s"))
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ struct InstrumentDescription {
|
||||||
std::string image;
|
std::string image;
|
||||||
BitArray<128> keyUsed {};
|
BitArray<128> keyUsed {};
|
||||||
BitArray<128> keyswitchUsed {};
|
BitArray<128> keyswitchUsed {};
|
||||||
|
BitArray<128> sustainOrSostenuto {};
|
||||||
BitArray<sfz::config::numCCs> ccUsed {};
|
BitArray<sfz::config::numCCs> ccUsed {};
|
||||||
std::array<std::string, 128> keyLabel {};
|
std::array<std::string, 128> keyLabel {};
|
||||||
std::array<std::string, 128> keyswitchLabel {};
|
std::array<std::string, 128> keyswitchLabel {};
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ sfizz_lv2_map_required_uris(sfizz_plugin_t *self)
|
||||||
self->sfizz_num_voices_uri = map->map(map->handle, SFIZZ__numVoices);
|
self->sfizz_num_voices_uri = map->map(map->handle, SFIZZ__numVoices);
|
||||||
self->sfizz_preload_size_uri = map->map(map->handle, SFIZZ__preloadSize);
|
self->sfizz_preload_size_uri = map->map(map->handle, SFIZZ__preloadSize);
|
||||||
self->sfizz_oversampling_uri = map->map(map->handle, SFIZZ__oversampling);
|
self->sfizz_oversampling_uri = map->map(map->handle, SFIZZ__oversampling);
|
||||||
|
self->sfizz_last_keyswitch_uri = map->map(map->handle, SFIZZ__lastKeyswitch);
|
||||||
self->sfizz_log_status_uri = map->map(map->handle, SFIZZ__logStatus);
|
self->sfizz_log_status_uri = map->map(map->handle, SFIZZ__logStatus);
|
||||||
self->sfizz_check_modification_uri = map->map(map->handle, SFIZZ__checkModification);
|
self->sfizz_check_modification_uri = map->map(map->handle, SFIZZ__checkModification);
|
||||||
self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob);
|
self->sfizz_osc_blob_uri = map->map(map->handle, SFIZZ__OSCBlob);
|
||||||
|
|
@ -323,6 +324,14 @@ sfizz_lv2_receive_message(void* data, int delay, const char* path, const char* s
|
||||||
|
|
||||||
sfizz_plugin_t *self = (sfizz_plugin_t *)data;
|
sfizz_plugin_t *self = (sfizz_plugin_t *)data;
|
||||||
|
|
||||||
|
if (!strcmp(path, "/sw/last/current") && sig)
|
||||||
|
{
|
||||||
|
if (sig[0] == 'i')
|
||||||
|
self->last_keyswitch = args[0].i;
|
||||||
|
else if (sig[0] == 'N')
|
||||||
|
self->last_keyswitch = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// transmit to UI as OSC blob
|
// transmit to UI as OSC blob
|
||||||
uint8_t *osc_temp = self->osc_temp;
|
uint8_t *osc_temp = self->osc_temp;
|
||||||
uint32_t osc_size = sfizz_prepare_message(osc_temp, OSC_TEMP_SIZE, path, sig, args);
|
uint32_t osc_size = sfizz_prepare_message(osc_temp, OSC_TEMP_SIZE, path, sig, args);
|
||||||
|
|
@ -683,6 +692,12 @@ sfizz_lv2_handle_atom_object(sfizz_plugin_t *self, int delay, const LV2_Atom_Obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
sfizz_is_sustain_or_sostenuto(sfizz_plugin_t* self, unsigned cc)
|
||||||
|
{
|
||||||
|
return (self->sustain_or_sostenuto[cc / 8] & (1 << (cc % 8)));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev)
|
sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev)
|
||||||
{
|
{
|
||||||
|
|
@ -704,14 +719,23 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev)
|
||||||
(int)msg[1],
|
(int)msg[1],
|
||||||
msg[2]);
|
msg[2]);
|
||||||
break;
|
break;
|
||||||
// Note(jpc) CC must be mapped by host, not handled here.
|
|
||||||
// See LV2 midi:binding.
|
|
||||||
#if defined(SFIZZ_LV2_PSA)
|
|
||||||
case LV2_MIDI_MSG_CONTROLLER:
|
case LV2_MIDI_MSG_CONTROLLER:
|
||||||
{
|
{
|
||||||
unsigned cc = msg[1];
|
unsigned cc = msg[1];
|
||||||
float value = float(msg[2]) * (1.0f / 127.0f);
|
float value = float(msg[2]) * (1.0f / 127.0f);
|
||||||
|
|
||||||
|
// Send
|
||||||
|
if (sfizz_is_sustain_or_sostenuto(self, cc)) {
|
||||||
|
sfizz_automate_hdcc(self->synth,
|
||||||
|
(int)ev->time.frames,
|
||||||
|
(int)cc,
|
||||||
|
value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note(jpc) CC must be mapped by host, not handled here.
|
||||||
|
// See LV2 midi:binding.
|
||||||
|
#if defined(SFIZZ_LV2_PSA)
|
||||||
switch (cc)
|
switch (cc)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
|
|
@ -733,9 +757,9 @@ sfizz_lv2_process_midi_event(sfizz_plugin_t *self, const LV2_Atom_Event *ev)
|
||||||
sfizz_all_sound_off(self->synth);
|
sfizz_all_sound_off(self->synth);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case LV2_MIDI_MSG_CHANNEL_PRESSURE:
|
case LV2_MIDI_MSG_CHANNEL_PRESSURE:
|
||||||
sfizz_send_channel_aftertouch(self->synth,
|
sfizz_send_channel_aftertouch(self->synth,
|
||||||
(int)ev->time.frames,
|
(int)ev->time.frames,
|
||||||
|
|
@ -1218,7 +1242,7 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self)
|
||||||
//
|
//
|
||||||
const InstrumentDescription desc = parseDescriptionBlob(blob);
|
const InstrumentDescription desc = parseDescriptionBlob(blob);
|
||||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||||
if (desc.ccUsed.test(cc)) {
|
if (desc.ccUsed.test(cc) && !desc.sustainOrSostenuto.test(cc)) {
|
||||||
// Mark all the used CCs for automation with default values
|
// Mark all the used CCs for automation with default values
|
||||||
self->ccauto[cc] = desc.ccDefault[cc];
|
self->ccauto[cc] = desc.ccDefault[cc];
|
||||||
self->have_ccauto = true;
|
self->have_ccauto = true;
|
||||||
|
|
@ -1226,6 +1250,9 @@ sfizz_lv2_update_sfz_info(sfizz_plugin_t *self)
|
||||||
self->cc_current[cc] = desc.ccDefault[cc];
|
self->cc_current[cc] = desc.ccDefault[cc];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(self->sustain_or_sostenuto, desc.sustainOrSostenuto.data(),
|
||||||
|
sizeof(self->sustain_or_sostenuto));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
@ -1283,6 +1310,7 @@ restore(LV2_Handle instance,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
|
self->last_keyswitch = -1;
|
||||||
sfizz_lv2_get_default_sfz_path(self, self->sfz_file_path, MAX_PATH_SIZE);
|
sfizz_lv2_get_default_sfz_path(self, self->sfz_file_path, MAX_PATH_SIZE);
|
||||||
sfizz_lv2_get_default_scala_path(self, self->scala_file_path, MAX_PATH_SIZE);
|
sfizz_lv2_get_default_scala_path(self, self->scala_file_path, MAX_PATH_SIZE);
|
||||||
|
|
||||||
|
|
@ -1333,6 +1361,13 @@ restore(LV2_Handle instance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value = retrieve(handle, self->sfizz_last_keyswitch_uri, &size, &type, &val_flags);
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
int last_keyswitch = *(const int*)value;
|
||||||
|
self->last_keyswitch = last_keyswitch;
|
||||||
|
}
|
||||||
|
|
||||||
// Collect all CC values present in the state
|
// Collect all CC values present in the state
|
||||||
std::unique_ptr<absl::optional<float>[]> cc_values(
|
std::unique_ptr<absl::optional<float>[]> cc_values(
|
||||||
new absl::optional<float>[sfz::config::numCCs]);
|
new absl::optional<float>[sfz::config::numCCs]);
|
||||||
|
|
@ -1387,6 +1422,11 @@ restore(LV2_Handle instance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self->last_keyswitch >= 0 && self->last_keyswitch <= 127) {
|
||||||
|
sfizz_send_hd_note_on(self->synth, 0, self->last_keyswitch, 1.0f);
|
||||||
|
sfizz_send_hd_note_off(self->synth, 1, self->last_keyswitch, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
spin_mutex_unlock(self->synth_mutex);
|
spin_mutex_unlock(self->synth_mutex);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|
@ -1456,8 +1496,17 @@ save(LV2_Handle instance,
|
||||||
absl::string_view((const char*)self->sfz_blob_data, self->sfz_blob_size));
|
absl::string_view((const char*)self->sfz_blob_data, self->sfz_blob_size));
|
||||||
self->sfz_blob_mutex->unlock();
|
self->sfz_blob_mutex->unlock();
|
||||||
|
|
||||||
|
if (self->last_keyswitch >= 0 && self->last_keyswitch <= 127) {
|
||||||
|
store(handle,
|
||||||
|
self->sfizz_last_keyswitch_uri,
|
||||||
|
&self->last_keyswitch,
|
||||||
|
sizeof(int),
|
||||||
|
self->atom_int_uri,
|
||||||
|
LV2_STATE_IS_POD);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||||
if (desc.ccUsed.test(cc)) {
|
if (desc.ccUsed.test(cc) && !desc.sustainOrSostenuto.test(cc)) {
|
||||||
LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc));
|
LV2_URID urid = sfizz_lv2_ccmap_map(self->ccmap, int(cc));
|
||||||
store(handle,
|
store(handle,
|
||||||
urid,
|
urid,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#define SFIZZ__numVoices SFIZZ_URI ":" "numvoices"
|
#define SFIZZ__numVoices SFIZZ_URI ":" "numvoices"
|
||||||
#define SFIZZ__preloadSize SFIZZ_URI ":" "preload_size"
|
#define SFIZZ__preloadSize SFIZZ_URI ":" "preload_size"
|
||||||
#define SFIZZ__oversampling SFIZZ_URI ":" "oversampling"
|
#define SFIZZ__oversampling SFIZZ_URI ":" "oversampling"
|
||||||
|
#define SFIZZ__lastKeyswitch SFIZZ_URI ":" "last_keyswitch"
|
||||||
// These ones are just for the worker
|
// These ones are just for the worker
|
||||||
#define SFIZZ__logStatus SFIZZ_URI ":" "log_status"
|
#define SFIZZ__logStatus SFIZZ_URI ":" "log_status"
|
||||||
#define SFIZZ__checkModification SFIZZ_URI ":" "check_modification"
|
#define SFIZZ__checkModification SFIZZ_URI ":" "check_modification"
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ struct sfizz_plugin_t
|
||||||
LV2_URID sfizz_num_voices_uri {};
|
LV2_URID sfizz_num_voices_uri {};
|
||||||
LV2_URID sfizz_preload_size_uri {};
|
LV2_URID sfizz_preload_size_uri {};
|
||||||
LV2_URID sfizz_oversampling_uri {};
|
LV2_URID sfizz_oversampling_uri {};
|
||||||
|
LV2_URID sfizz_last_keyswitch_uri {};
|
||||||
LV2_URID sfizz_log_status_uri {};
|
LV2_URID sfizz_log_status_uri {};
|
||||||
LV2_URID sfizz_check_modification_uri {};
|
LV2_URID sfizz_check_modification_uri {};
|
||||||
LV2_URID sfizz_active_voices_uri {};
|
LV2_URID sfizz_active_voices_uri {};
|
||||||
|
|
@ -120,6 +121,7 @@ struct sfizz_plugin_t
|
||||||
float sample_rate {};
|
float sample_rate {};
|
||||||
std::atomic<int> must_update_midnam {};
|
std::atomic<int> must_update_midnam {};
|
||||||
volatile bool must_automate_cc {};
|
volatile bool must_automate_cc {};
|
||||||
|
int last_keyswitch { -1 };
|
||||||
|
|
||||||
// Current instrument description
|
// Current instrument description
|
||||||
std::mutex *sfz_blob_mutex {};
|
std::mutex *sfz_blob_mutex {};
|
||||||
|
|
@ -127,6 +129,9 @@ struct sfizz_plugin_t
|
||||||
const uint8_t *volatile sfz_blob_data {};
|
const uint8_t *volatile sfz_blob_data {};
|
||||||
volatile uint32_t sfz_blob_size {};
|
volatile uint32_t sfz_blob_size {};
|
||||||
|
|
||||||
|
// Sostenuto or sustain
|
||||||
|
char sustain_or_sostenuto[16] {};
|
||||||
|
|
||||||
// Current CC values in the synth (synchronized by `synth_mutex`)
|
// Current CC values in the synth (synchronized by `synth_mutex`)
|
||||||
// updated by hdcc or file load
|
// updated by hdcc or file load
|
||||||
float *cc_current {};
|
float *cc_current {};
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,7 @@ sfizz_ui_update_description(sfizz_ui_t *self, const InstrumentDescription& desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||||
bool ccUsed = desc.ccUsed.test(cc);
|
bool ccUsed = desc.ccUsed.test(cc) && !desc.sustainOrSostenuto.test(cc);
|
||||||
self->uiReceiveValue(editIdForCCUsed(cc), float(ccUsed));
|
self->uiReceiveValue(editIdForCCUsed(cc), float(ccUsed));
|
||||||
if (ccUsed) {
|
if (ccUsed) {
|
||||||
self->uiReceiveValue(editIdForCCDefault(cc), desc.ccDefault[cc]);
|
self->uiReceiveValue(editIdForCCDefault(cc), desc.ccDefault[cc]);
|
||||||
|
|
|
||||||
|
|
@ -364,8 +364,7 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Vst::IComponentHandler* componentHandler = getComponentHandler())
|
if (Vst::IComponentHandler* componentHandler = getComponentHandler())
|
||||||
// NOTE(jpc) I think that's the right one, but it needs confirmation
|
componentHandler->restartComponent(Vst::kKeyswitchChanged);
|
||||||
componentHandler->restartComponent(Vst::kNoteExpressionChanged);
|
|
||||||
|
|
||||||
// update the parameter titles and notify
|
// update the parameter titles and notify
|
||||||
for (uint32 cc = 0; cc < sfz::config::numCCs; ++cc) {
|
for (uint32 cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||||
|
|
|
||||||
|
|
@ -59,11 +59,8 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p
|
||||||
config = &x11config;
|
config = &x11config;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Editor* editor = editor_.get();
|
Editor* editor = new Editor(*this);
|
||||||
if (!editor) {
|
editor_.reset(editor);
|
||||||
editor = new Editor(*this);
|
|
||||||
editor_.reset(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!frame->open(parent, platformType, config)) {
|
if (!frame->open(parent, platformType, config)) {
|
||||||
fprintf(stderr, "[sfizz] error opening frame\n");
|
fprintf(stderr, "[sfizz] error opening frame\n");
|
||||||
|
|
@ -122,12 +119,21 @@ void PLUGIN_API SfizzVstEditor::close()
|
||||||
for (FObject* update : updates_)
|
for (FObject* update : updates_)
|
||||||
update->removeDependent(this);
|
update->removeDependent(this);
|
||||||
|
|
||||||
if (editor_)
|
if (editor_) {
|
||||||
editor_->close();
|
editor_->close();
|
||||||
|
editor_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (frame->getNbReference() != 1)
|
if (frame->getNbReference() != 1)
|
||||||
frame->forget();
|
frame->forget();
|
||||||
else
|
else {
|
||||||
frame->close();
|
frame->close();
|
||||||
|
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||||
|
// if vstgui is done using the runloop, destroy it
|
||||||
|
if (!RunLoop::get())
|
||||||
|
_runLoop = nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
this->frame = nullptr;
|
this->frame = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,8 +164,6 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message)
|
||||||
// notifier of X11 events is working. If there is, remove this and
|
// notifier of X11 events is working. If there is, remove this and
|
||||||
// avoid polluting Linux hosts which implement the loop correctly.
|
// avoid polluting Linux hosts which implement the loop correctly.
|
||||||
runLoop->processSomeEvents();
|
runLoop->processSomeEvents();
|
||||||
|
|
||||||
runLoop->cleanupDeadHandlers();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -246,7 +250,7 @@ bool SfizzVstEditor::processUpdate(FUnknown* changedUnknown, int32 message)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
for (unsigned cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||||
bool ccUsed = desc.ccUsed.test(cc);
|
bool ccUsed = desc.ccUsed.test(cc) && !desc.sustainOrSostenuto.test(cc);
|
||||||
uiReceiveValue(editIdForCCUsed(int(cc)), float(ccUsed));
|
uiReceiveValue(editIdForCCUsed(int(cc)), float(ccUsed));
|
||||||
if (ccUsed) {
|
if (ccUsed) {
|
||||||
uiReceiveValue(editIdForCCDefault(int(cc)), desc.ccDefault[cc]);
|
uiReceiveValue(editIdForCCDefault(int(cc)), desc.ccDefault[cc]);
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,10 @@ void SfizzVstProcessor::syncStateToSynth()
|
||||||
synth->setScalaRootKey(_state.scalaRootKey);
|
synth->setScalaRootKey(_state.scalaRootKey);
|
||||||
synth->setTuningFrequency(_state.tuningFrequency);
|
synth->setTuningFrequency(_state.tuningFrequency);
|
||||||
synth->loadStretchTuningByRatio(_state.stretchedTuning);
|
synth->loadStretchTuningByRatio(_state.stretchedTuning);
|
||||||
|
if (_state.lastKeyswitch >= 0 && _state.lastKeyswitch <= 127) {
|
||||||
|
synth->hdNoteOn(0, _state.lastKeyswitch, 1.0f);
|
||||||
|
synth->hdNoteOff(1, _state.lastKeyswitch, 0.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize)
|
tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize)
|
||||||
|
|
@ -669,6 +673,14 @@ bool SfizzVstProcessor::processUpdate(FUnknown* changedUnknown, int32 message)
|
||||||
|
|
||||||
void SfizzVstProcessor::receiveOSC(int delay, const char* path, const char* sig, const sfizz_arg_t* args)
|
void SfizzVstProcessor::receiveOSC(int delay, const char* path, const char* sig, const sfizz_arg_t* args)
|
||||||
{
|
{
|
||||||
|
if (!strcmp(path, "/sw/last/current") && sig)
|
||||||
|
{
|
||||||
|
if (sig[0] == 'i')
|
||||||
|
_state.lastKeyswitch = args[0].i;
|
||||||
|
else if (sig[0] == 'N')
|
||||||
|
_state.lastKeyswitch = -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t* oscTemp = _oscTemp.get();
|
uint8_t* oscTemp = _oscTemp.get();
|
||||||
uint32 oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args);
|
uint32 oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args);
|
||||||
if (oscSize <= kOscTempSize) {
|
if (oscSize <= kOscTempSize) {
|
||||||
|
|
@ -740,8 +752,13 @@ void SfizzVstProcessor::doBackgroundWork()
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool isNotified = _semaToWorker.timed_wait(kBackgroundIdleInterval.count());
|
bool isNotified = _semaToWorker.timed_wait(kBackgroundIdleInterval.count());
|
||||||
|
|
||||||
if (!_workRunning)
|
if (!_workRunning) {
|
||||||
|
// if the quit signal is sent, the semaphore is also signaled
|
||||||
|
// make sure the count is kept consistent
|
||||||
|
if (!isNotified)
|
||||||
|
_semaToWorker.wait();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const char* id = nullptr;
|
const char* id = nullptr;
|
||||||
RTMessagePtr msg;
|
RTMessagePtr msg;
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,14 @@ tresult SfizzVstState::load(IBStream* state)
|
||||||
oscillatorQuality = defaults.oscillatorQuality;
|
oscillatorQuality = defaults.oscillatorQuality;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version >= 4) {
|
||||||
|
if (!s.readInt32(lastKeyswitch))
|
||||||
|
return kResultFalse;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastKeyswitch = -1;
|
||||||
|
}
|
||||||
|
|
||||||
controllers.clear();
|
controllers.clear();
|
||||||
if (version >= 2) {
|
if (version >= 2) {
|
||||||
uint32 count;
|
uint32 count;
|
||||||
|
|
@ -135,6 +143,9 @@ tresult SfizzVstState::store(IBStream* state) const
|
||||||
if (!s.writeInt32(oscillatorQuality))
|
if (!s.writeInt32(oscillatorQuality))
|
||||||
return kResultFalse;
|
return kResultFalse;
|
||||||
|
|
||||||
|
if (!s.writeInt32(lastKeyswitch))
|
||||||
|
return kResultFalse;
|
||||||
|
|
||||||
{
|
{
|
||||||
uint32 ccCount = 0;
|
uint32 ccCount = 0;
|
||||||
uint32 ccLimit = uint32(std::min(controllers.size(), size_t(0x10000)));
|
uint32 ccLimit = uint32(std::min(controllers.size(), size_t(0x10000)));
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,10 @@ public:
|
||||||
float stretchedTuning = 0.0;
|
float stretchedTuning = 0.0;
|
||||||
int32 sampleQuality = 2;
|
int32 sampleQuality = 2;
|
||||||
int32 oscillatorQuality = 1;
|
int32 oscillatorQuality = 1;
|
||||||
|
int32 lastKeyswitch = -1;
|
||||||
std::vector<absl::optional<float>> controllers;
|
std::vector<absl::optional<float>> controllers;
|
||||||
|
|
||||||
static constexpr uint64 currentStateVersion = 3;
|
static constexpr uint64 currentStateVersion = 4;
|
||||||
|
|
||||||
tresult load(IBStream* state);
|
tresult load(IBStream* state);
|
||||||
tresult store(IBStream* state) const;
|
tresult store(IBStream* state) const;
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,38 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||||
#include "X11RunLoop.h"
|
#include "X11RunLoop.h"
|
||||||
#include "vstgui/lib/platform/linux/x11platform.h"
|
#include "vstgui/lib/platform/linux/x11platform.h"
|
||||||
#include "base/source/fobject.h"
|
#include "base/source/fobject.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace VSTGUI {
|
namespace VSTGUI {
|
||||||
|
|
||||||
RunLoop::RunLoop(Steinberg::FUnknown* runLoop)
|
struct RunLoop::Impl {
|
||||||
: runLoop(runLoop)
|
struct EventHandler;
|
||||||
{
|
struct TimerHandler;
|
||||||
}
|
|
||||||
|
|
||||||
RunLoop::~RunLoop() {}
|
using EventHandlers = std::vector<Steinberg::IPtr<EventHandler>>;
|
||||||
|
using TimerHandlers = std::vector<Steinberg::IPtr<TimerHandler>>;
|
||||||
|
|
||||||
SharedPointer<RunLoop> RunLoop::get()
|
EventHandlers eventHandlers;
|
||||||
{
|
TimerHandlers timerHandlers;
|
||||||
return X11::RunLoop::get().cast<VSTGUI::RunLoop>();
|
Steinberg::FUnknownPtr<Steinberg::Linux::IRunLoop> runLoop;
|
||||||
}
|
};
|
||||||
|
|
||||||
struct RunLoop::EventHandler final : Steinberg::Linux::IEventHandler, public Steinberg::FObject {
|
//------------------------------------------------------------------------------
|
||||||
|
struct RunLoop::Impl::EventHandler final : Steinberg::Linux::IEventHandler, public Steinberg::FObject {
|
||||||
X11::IEventHandler* handler { nullptr };
|
X11::IEventHandler* handler { nullptr };
|
||||||
bool alive { false };
|
bool alive { false };
|
||||||
|
|
||||||
void PLUGIN_API onFDIsSet(Steinberg::Linux::FileDescriptor) override
|
void PLUGIN_API onFDIsSet(Steinberg::Linux::FileDescriptor) override;
|
||||||
{
|
|
||||||
if (alive && handler)
|
|
||||||
handler->onEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
DELEGATE_REFCOUNT(Steinberg::FObject)
|
DELEGATE_REFCOUNT(Steinberg::FObject)
|
||||||
DEFINE_INTERFACES
|
DEFINE_INTERFACES
|
||||||
|
|
@ -35,15 +40,11 @@ struct RunLoop::EventHandler final : Steinberg::Linux::IEventHandler, public Ste
|
||||||
END_DEFINE_INTERFACES(Steinberg::FObject)
|
END_DEFINE_INTERFACES(Steinberg::FObject)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RunLoop::TimerHandler final : Steinberg::Linux::ITimerHandler, public Steinberg::FObject {
|
struct RunLoop::Impl::TimerHandler final : Steinberg::Linux::ITimerHandler, public Steinberg::FObject {
|
||||||
X11::ITimerHandler* handler { nullptr };
|
X11::ITimerHandler* handler { nullptr };
|
||||||
bool alive { false };
|
bool alive { false };
|
||||||
|
|
||||||
void PLUGIN_API onTimer() override
|
void PLUGIN_API onTimer() override;
|
||||||
{
|
|
||||||
if (alive && handler)
|
|
||||||
handler->onTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
DELEGATE_REFCOUNT(Steinberg::FObject)
|
DELEGATE_REFCOUNT(Steinberg::FObject)
|
||||||
DEFINE_INTERFACES
|
DEFINE_INTERFACES
|
||||||
|
|
@ -51,45 +52,126 @@ struct RunLoop::TimerHandler final : Steinberg::Linux::ITimerHandler, public Ste
|
||||||
END_DEFINE_INTERFACES(Steinberg::FObject)
|
END_DEFINE_INTERFACES(Steinberg::FObject)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
void PLUGIN_API RunLoop::Impl::EventHandler::onFDIsSet(Steinberg::Linux::FileDescriptor)
|
||||||
|
{
|
||||||
|
SharedPointer<RunLoop> runLoop = RunLoop::get();
|
||||||
|
if (!runLoop) {
|
||||||
|
fprintf(stderr, "[x11] event has fired without active runloop\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alive && handler)
|
||||||
|
handler->onEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PLUGIN_API RunLoop::Impl::TimerHandler::onTimer()
|
||||||
|
{
|
||||||
|
SharedPointer<RunLoop> runLoop = RunLoop::get();
|
||||||
|
if (!runLoop) {
|
||||||
|
fprintf(stderr, "[x11] timer has fired without active runloop\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alive && handler)
|
||||||
|
handler->onTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
RunLoop::RunLoop(Steinberg::FUnknown* runLoop)
|
||||||
|
: impl(new Impl)
|
||||||
|
{
|
||||||
|
impl->runLoop = runLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunLoop::~RunLoop()
|
||||||
|
{
|
||||||
|
//dumpCurrentState();
|
||||||
|
|
||||||
|
if (0) {
|
||||||
|
// remove any leftover handlers
|
||||||
|
for (size_t i = 0; i < impl->eventHandlers.size(); ++i) {
|
||||||
|
const auto& eh = impl->eventHandlers[i];
|
||||||
|
if (eh->alive && eh->handler) {
|
||||||
|
impl->runLoop->unregisterEventHandler(eh.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < impl->timerHandlers.size(); ++i) {
|
||||||
|
const auto& th = impl->timerHandlers[i];
|
||||||
|
if (th->alive && th->handler) {
|
||||||
|
impl->runLoop->unregisterTimer(th.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedPointer<RunLoop> RunLoop::get()
|
||||||
|
{
|
||||||
|
return X11::RunLoop::get().cast<VSTGUI::RunLoop>();
|
||||||
|
}
|
||||||
|
|
||||||
void RunLoop::processSomeEvents()
|
void RunLoop::processSomeEvents()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < eventHandlers.size(); ++i) {
|
for (size_t i = 0; i < impl->eventHandlers.size(); ++i) {
|
||||||
const auto& eh = eventHandlers[i];
|
const auto& eh = impl->eventHandlers[i];
|
||||||
if (eh->alive && eh->handler) {
|
if (eh->alive && eh->handler) {
|
||||||
eh->handler->onEvent();
|
eh->handler->onEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunLoop::cleanupDeadHandlers()
|
void RunLoop::dumpCurrentState()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < eventHandlers.size(); ++i) {
|
fprintf(stderr, "=== X11 runloop ===\n");
|
||||||
const auto& eh = eventHandlers[i];
|
|
||||||
if (!eh->alive) {
|
fprintf(stderr, "\t" "Event slots:\n");
|
||||||
runLoop->unregisterEventHandler(eh);
|
for (size_t i = 0, n = impl->eventHandlers.size(); i < n; ++i) {
|
||||||
eventHandlers.erase(eventHandlers.begin() + i--);
|
Impl::EventHandler *eh = impl->eventHandlers[i].get();
|
||||||
}
|
fprintf(stderr, "\t\t" "(%lu) alive=%d handler=%p type=%s\n", i, eh->alive, eh->handler, (eh->alive && eh->handler) ? typeid(*eh->handler).name() : "");
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < timerHandlers.size(); ++i) {
|
|
||||||
const auto& th = timerHandlers[i];
|
fprintf(stderr, "\t" "Timer slots:\n");
|
||||||
if (!th->alive) {
|
for (size_t i = 0, n = impl->timerHandlers.size(); i < n; ++i) {
|
||||||
runLoop->unregisterTimer(th);
|
Impl::TimerHandler *th = impl->timerHandlers[i].get();
|
||||||
timerHandlers.erase(timerHandlers.begin() + i--);
|
fprintf(stderr, "\t\t" "(%lu) alive=%d handler=%p type=%s\n", i, th->alive, th->handler, (th->alive && th->handler) ? typeid(*th->handler).name() : "");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "===/X11 runloop ===\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static void insertHandler(std::vector<Steinberg::IPtr<T>>& list, Steinberg::IPtr<T> handler)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
size_t n = list.size();
|
||||||
|
while (i < n && list[i]->alive)
|
||||||
|
++i;
|
||||||
|
if (i < n)
|
||||||
|
list[i] = handler;
|
||||||
|
else
|
||||||
|
list.emplace_back(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
static size_t findHandler(const std::vector<Steinberg::IPtr<T>>& list, U* handler)
|
||||||
|
{
|
||||||
|
for (size_t i = 0, n = list.size(); i < n; ++i) {
|
||||||
|
if (list[i]->alive && list[i]->handler == handler)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return ~size_t(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunLoop::registerEventHandler(int fd, X11::IEventHandler* handler)
|
bool RunLoop::registerEventHandler(int fd, X11::IEventHandler* handler)
|
||||||
{
|
{
|
||||||
if (!runLoop)
|
if (!impl->runLoop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto smtgHandler = Steinberg::owned(new EventHandler());
|
auto smtgHandler = Steinberg::owned(new Impl::EventHandler);
|
||||||
smtgHandler->handler = handler;
|
smtgHandler->handler = handler;
|
||||||
smtgHandler->alive = true;
|
smtgHandler->alive = true;
|
||||||
if (runLoop->registerEventHandler(smtgHandler, fd) == Steinberg::kResultTrue) {
|
if (impl->runLoop->registerEventHandler(smtgHandler, fd) == Steinberg::kResultTrue) {
|
||||||
eventHandlers.push_back(smtgHandler);
|
insertHandler(impl->eventHandlers, smtgHandler);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -97,29 +179,31 @@ bool RunLoop::registerEventHandler(int fd, X11::IEventHandler* handler)
|
||||||
|
|
||||||
bool RunLoop::unregisterEventHandler(X11::IEventHandler* handler)
|
bool RunLoop::unregisterEventHandler(X11::IEventHandler* handler)
|
||||||
{
|
{
|
||||||
if (!runLoop)
|
if (!impl->runLoop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (size_t i = 0; i < eventHandlers.size(); ++i) {
|
size_t index = findHandler(impl->eventHandlers, handler);
|
||||||
const auto& eh = eventHandlers[i];
|
if (index == ~size_t(0))
|
||||||
if (eh->alive && eh->handler == handler) {
|
return false;
|
||||||
eh->alive = false;
|
|
||||||
return true;
|
Impl::EventHandler *eh = impl->eventHandlers[index].get();
|
||||||
}
|
if (!impl->runLoop->unregisterEventHandler(eh))
|
||||||
}
|
return false;
|
||||||
return false;
|
|
||||||
|
eh->alive = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RunLoop::registerTimer(uint64_t interval, X11::ITimerHandler* handler)
|
bool RunLoop::registerTimer(uint64_t interval, X11::ITimerHandler* handler)
|
||||||
{
|
{
|
||||||
if (!runLoop)
|
if (!impl->runLoop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto smtgHandler = Steinberg::owned(new TimerHandler());
|
auto smtgHandler = Steinberg::owned(new Impl::TimerHandler);
|
||||||
smtgHandler->handler = handler;
|
smtgHandler->handler = handler;
|
||||||
smtgHandler->alive = true;
|
smtgHandler->alive = true;
|
||||||
if (runLoop->registerTimer(smtgHandler, interval) == Steinberg::kResultTrue) {
|
if (impl->runLoop->registerTimer(smtgHandler, interval) == Steinberg::kResultTrue) {
|
||||||
timerHandlers.push_back(smtgHandler);
|
insertHandler(impl->timerHandlers, smtgHandler);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -127,17 +211,19 @@ bool RunLoop::registerTimer(uint64_t interval, X11::ITimerHandler* handler)
|
||||||
|
|
||||||
bool RunLoop::unregisterTimer(X11::ITimerHandler* handler)
|
bool RunLoop::unregisterTimer(X11::ITimerHandler* handler)
|
||||||
{
|
{
|
||||||
if (!runLoop)
|
if (!impl->runLoop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (size_t i = 0; i < timerHandlers.size(); ++i) {
|
size_t index = findHandler(impl->timerHandlers, handler);
|
||||||
const auto& th = timerHandlers[i];
|
if (index == ~size_t(0))
|
||||||
if (th->alive && th->handler == handler) {
|
return false;
|
||||||
th->alive = false;
|
|
||||||
return true;
|
Impl::TimerHandler *th = impl->timerHandlers[index].get();
|
||||||
}
|
if (!impl->runLoop->unregisterTimer(th))
|
||||||
}
|
return false;
|
||||||
return false;
|
|
||||||
|
th->alive = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VSTGUI
|
} // namespace VSTGUI
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,28 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
/*
|
|
||||||
This is a modified version the X11 run loop from vst3editor.cpp.
|
|
||||||
|
|
||||||
This version is edited to add more safeguards to protect against host bugs.
|
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||||
It also permits to call event processing externally in case the host has a
|
// license. You should have receive a LICENSE.md file along with the code.
|
||||||
defective X11 event loop notifier.
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
|
/*
|
||||||
|
This runloop connects to X11 VSTGUI, it connects VST3 and VSTGUI together.
|
||||||
|
The Windows and macOS runloops do not need this, the OS-provided
|
||||||
|
functionality is used instead.
|
||||||
|
|
||||||
|
Previously, this was based on VSTGUI code provided by Steinberg.
|
||||||
|
This is replaced with a rewrite, because the original code has too many
|
||||||
|
issues. For example, it has no robustness in case handlers get added or
|
||||||
|
removed within the execution of the handler.
|
||||||
|
|
||||||
|
This version allows to call event processing externally, in case the host
|
||||||
|
has a defective X11 event loop notifier. (some versions of Bitwig do)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||||
#include "vstgui/lib/platform/linux/x11frame.h"
|
#include "vstgui/lib/platform/linux/x11frame.h"
|
||||||
#include "pluginterfaces/gui/iplugview.h"
|
#include "pluginterfaces/gui/iplugview.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace VSTGUI {
|
namespace VSTGUI {
|
||||||
|
|
||||||
|
|
@ -22,24 +34,16 @@ public:
|
||||||
static SharedPointer<RunLoop> get();
|
static SharedPointer<RunLoop> get();
|
||||||
|
|
||||||
void processSomeEvents();
|
void processSomeEvents();
|
||||||
void cleanupDeadHandlers();
|
void dumpCurrentState();
|
||||||
|
|
||||||
// X11::IRunLoop
|
// X11::IRunLoop
|
||||||
bool registerEventHandler(int fd, X11::IEventHandler* handler);
|
bool registerEventHandler(int fd, X11::IEventHandler* handler) override;
|
||||||
bool unregisterEventHandler(X11::IEventHandler* handler);
|
bool unregisterEventHandler(X11::IEventHandler* handler) override;
|
||||||
bool registerTimer(uint64_t interval, X11::ITimerHandler* handler);
|
bool registerTimer(uint64_t interval, X11::ITimerHandler* handler) override;
|
||||||
bool unregisterTimer(X11::ITimerHandler* handler);
|
bool unregisterTimer(X11::ITimerHandler* handler) override;
|
||||||
|
|
||||||
private:
|
struct Impl;
|
||||||
struct EventHandler;
|
std::unique_ptr<Impl> impl;
|
||||||
struct TimerHandler;
|
|
||||||
|
|
||||||
private:
|
|
||||||
using EventHandlers = std::vector<Steinberg::IPtr<EventHandler>>;
|
|
||||||
using TimerHandlers = std::vector<Steinberg::IPtr<TimerHandler>>;
|
|
||||||
EventHandlers eventHandlers;
|
|
||||||
TimerHandlers timerHandlers;
|
|
||||||
Steinberg::FUnknownPtr<Steinberg::Linux::IRunLoop> runLoop;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VSTGUI
|
} // namespace VSTGUI
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@ add_library(vst3sdk STATIC EXCLUDE_FROM_ALL
|
||||||
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstnoteexpressiontypes.cpp"
|
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstnoteexpressiontypes.cpp"
|
||||||
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstparameters.cpp"
|
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstparameters.cpp"
|
||||||
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstpresetfile.cpp"
|
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstpresetfile.cpp"
|
||||||
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstrepresentation.cpp")
|
"${VST3SDK_BASEDIR}/public.sdk/source/vst/vstrepresentation.cpp"
|
||||||
|
"${VST3SDK_BASEDIR}/public.sdk/source/vst/utility/stringconvert.cpp")
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(vst3sdk PRIVATE
|
target_sources(vst3sdk PRIVATE
|
||||||
"${VST3SDK_BASEDIR}/public.sdk/source/common/threadchecker_win32.cpp")
|
"${VST3SDK_BASEDIR}/public.sdk/source/common/threadchecker_win32.cpp")
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit b8566ef3b2a0cba60a96e3ef2001224c865c8b36
|
Subproject commit 93cef1afb7061e488625045ba5a82abaa83d27fe
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit d69d011fa08c3977928f7da0010f8938f93fd370
|
Subproject commit 9589800ed94573354bc29de45eec5744523fbfcb
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include <simde/x86/sse.h>
|
#include <simde/x86/sse.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __cplusplus >= 201703L
|
#if __cplusplus >= 201703L && defined(__cpp_lib_math_special_functions)
|
||||||
static double i0(double x) { return std::cyl_bessel_i(0.0, x); }
|
static double i0(double x) { return std::cyl_bessel_i(0.0, x); }
|
||||||
#else
|
#else
|
||||||
// external Bessel function from cephes
|
// external Bessel function from cephes
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,7 @@ void Synth::Impl::clear()
|
||||||
filePool.setRamLoading(config::loadInRam);
|
filePool.setRamLoading(config::loadInRam);
|
||||||
clearCCLabels();
|
clearCCLabels();
|
||||||
currentUsedCCs_.clear();
|
currentUsedCCs_.clear();
|
||||||
|
sustainOrSostenuto_.clear();
|
||||||
changedCCsThisCycle_.clear();
|
changedCCsThisCycle_.clear();
|
||||||
changedCCsLastCycle_.clear();
|
changedCCsLastCycle_.clear();
|
||||||
clearKeyLabels();
|
clearKeyLabels();
|
||||||
|
|
@ -2111,8 +2112,11 @@ void Synth::Impl::collectUsedCCsFromModulations(BitArray<config::numCCs>& usedCC
|
||||||
BitArray<config::numCCs> Synth::Impl::collectAllUsedCCs()
|
BitArray<config::numCCs> Synth::Impl::collectAllUsedCCs()
|
||||||
{
|
{
|
||||||
BitArray<config::numCCs> used;
|
BitArray<config::numCCs> used;
|
||||||
for (const LayerPtr& layerPtr : layers_)
|
for (const LayerPtr& layerPtr : layers_) {
|
||||||
collectUsedCCsFromRegion(used, layerPtr->getRegion());
|
collectUsedCCsFromRegion(used, layerPtr->getRegion());
|
||||||
|
sustainOrSostenuto_.set(layerPtr->region_.sustainCC);
|
||||||
|
sustainOrSostenuto_.set(layerPtr->region_.sostenutoCC);
|
||||||
|
}
|
||||||
collectUsedCCsFromModulations(used, resources_.getModMatrix());
|
collectUsedCCsFromModulations(used, resources_.getModMatrix());
|
||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
|
||||||
client.receive<'b'>(delay, path, &blob);
|
client.receive<'b'>(delay, path, &blob);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
MATCH("/sustain_or_sostenuto/slots", "") {
|
||||||
|
const BitArray<128>& sustainOrSostenuto = impl.sustainOrSostenuto_;
|
||||||
|
sfizz_blob_t blob { sustainOrSostenuto.data(),
|
||||||
|
static_cast<uint32_t>(sustainOrSostenuto.byte_size()) };
|
||||||
|
client.receive<'b'>(delay, path, &blob);
|
||||||
|
} break;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
MATCH("/mem/buffers", "") {
|
MATCH("/mem/buffers", "") {
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,7 @@ struct Synth::Impl final: public Parser::Listener {
|
||||||
std::map<int, size_t> keyLabelsMap_;
|
std::map<int, size_t> keyLabelsMap_;
|
||||||
BitArray<128> keySlots_;
|
BitArray<128> keySlots_;
|
||||||
BitArray<128> swLastSlots_;
|
BitArray<128> swLastSlots_;
|
||||||
|
BitArray<128> sustainOrSostenuto_;
|
||||||
std::vector<NoteNamePair> keyswitchLabels_;
|
std::vector<NoteNamePair> keyswitchLabels_;
|
||||||
std::map<int, size_t> keyswitchLabelsMap_;
|
std::map<int, size_t> keyswitchLabelsMap_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ void DecentSamplerInstrumentImporter::emitRegionalOpcodes(std::ostream& os, pugi
|
||||||
break;
|
break;
|
||||||
case hash("loopEnabled"):
|
case hash("loopEnabled"):
|
||||||
os << "loop_mode="
|
os << "loop_mode="
|
||||||
<< ((xmlOpcode.value == "true") ? "loop_continuous" : "one_shot") << "\n";
|
<< ((xmlOpcode.value == "true") ? "loop_continuous" : "no_loop") << "\n";
|
||||||
break;
|
break;
|
||||||
case hash("attack"):
|
case hash("attack"):
|
||||||
convertToReal("ampeg_attack");
|
convertToReal("ampeg_attack");
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue