Instrument description in VST and LV2
This commit is contained in:
parent
b272b1a3e3
commit
9d3e365f2e
17 changed files with 464 additions and 209 deletions
|
|
@ -7,7 +7,7 @@ target_include_directories(plugins-common PUBLIC "common")
|
|||
target_link_libraries(plugins-common
|
||||
PUBLIC sfizz::spin_mutex
|
||||
PUBLIC sfizz::filesystem absl::strings
|
||||
PRIVATE sfizz::internal)
|
||||
PRIVATE sfizz::internal sfizz::sfizz)
|
||||
add_library(sfizz::plugins-common ALIAS plugins-common)
|
||||
|
||||
if((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,11 @@ std::string getDescriptionBlob(sfizz_synth_t* handle)
|
|||
}
|
||||
});
|
||||
|
||||
synth.sendMessage(*client, 0, "/num_regions", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/num_groups", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/num_masters", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/num_curves", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/num_samples", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/key/slots", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/sw/last/slots", "", nullptr);
|
||||
synth.sendMessage(*client, 0, "/cc/slots", "", nullptr);
|
||||
|
|
@ -125,7 +130,17 @@ InstrumentDescription parseDescriptionBlob(absl::string_view blob)
|
|||
};
|
||||
|
||||
//
|
||||
if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b"))
|
||||
if (Messages::matchOSC("/num_regions", path, indices) && !strcmp(sig, "i"))
|
||||
desc.numRegions = uint32_t(args[0].i);
|
||||
else if (Messages::matchOSC("/num_groups", path, indices) && !strcmp(sig, "i"))
|
||||
desc.numGroups = uint32_t(args[0].i);
|
||||
else if (Messages::matchOSC("/num_masters", path, indices) && !strcmp(sig, "i"))
|
||||
desc.numMasters = uint32_t(args[0].i);
|
||||
else if (Messages::matchOSC("/num_curves", path, indices) && !strcmp(sig, "i"))
|
||||
desc.numCurves = uint32_t(args[0].i);
|
||||
else if (Messages::matchOSC("/num_samples", path, indices) && !strcmp(sig, "i"))
|
||||
desc.numSamples = uint32_t(args[0].i);
|
||||
else if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b"))
|
||||
copyArgToBitSpan(args[0], desc.keyUsed.span());
|
||||
else if (Messages::matchOSC("/sw/last/slots", path, indices) && !strcmp(sig, "b"))
|
||||
copyArgToBitSpan(args[0], desc.keyswitchUsed.span());
|
||||
|
|
@ -151,6 +166,12 @@ std::ostream& operator<<(std::ostream& os, const InstrumentDescription& desc)
|
|||
{
|
||||
os << "instrument:\n";
|
||||
|
||||
os << " regions: " << desc.numRegions << "\n";
|
||||
os << " groups: " << desc.numGroups << "\n";
|
||||
os << " masters: " << desc.numMasters << "\n";
|
||||
os << " curves: " << desc.numCurves << "\n";
|
||||
os << " samples: " << desc.numSamples << "\n";
|
||||
|
||||
os << " keys:\n";
|
||||
for (unsigned i = 0; i < 128; ++i) {
|
||||
if (desc.keyUsed.test(i)) {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,15 @@
|
|||
#include <iosfwd>
|
||||
struct sfizz_synth_t;
|
||||
|
||||
/**
|
||||
* @brief Description of user-interactible elements of the SFZ instrument
|
||||
*/
|
||||
struct InstrumentDescription {
|
||||
uint32_t numRegions {};
|
||||
uint32_t numGroups {};
|
||||
uint32_t numMasters {};
|
||||
uint32_t numCurves {};
|
||||
uint32_t numSamples {};
|
||||
BitArray<128> keyUsed {};
|
||||
BitArray<128> keyswitchUsed {};
|
||||
BitArray<sfz::config::numCCs> ccUsed {};
|
||||
|
|
@ -23,7 +31,21 @@ struct InstrumentDescription {
|
|||
std::array<float, sfz::config::numCCs> ccDefault {};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Produce a description of the currently loaded instrument in the synth,
|
||||
* in the form of a concatenation of OSC messages.
|
||||
*
|
||||
* This form is a message transmissible over binary channels.
|
||||
*/
|
||||
std::string getDescriptionBlob(sfizz_synth_t* handle);
|
||||
|
||||
/**
|
||||
* @brief Extract the information from the OSC blob and rearrange it in a
|
||||
* structured form.
|
||||
*/
|
||||
InstrumentDescription parseDescriptionBlob(absl::string_view blob);
|
||||
|
||||
/**
|
||||
* @brief Display the description in human-readable format.
|
||||
*/
|
||||
std::ostream& operator<<(std::ostream& os, const InstrumentDescription& desc);
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@ source_group("Turtle Files" FILES
|
|||
)
|
||||
add_library(${LV2PLUGIN_PRJ_NAME} MODULE
|
||||
${PROJECT_NAME}.cpp
|
||||
${PROJECT_NAME}_lv2_common.cpp
|
||||
${LV2PLUGIN_TTL_SRC_FILES})
|
||||
target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::import sfizz::plugins-common)
|
||||
|
||||
if(SFIZZ_LV2_UI)
|
||||
add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE
|
||||
${PROJECT_NAME}_ui.cpp
|
||||
${PROJECT_NAME}_lv2_common.cpp
|
||||
vstgui_helpers.h
|
||||
vstgui_helpers.cpp)
|
||||
target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui sfizz::plugins-common)
|
||||
|
|
|
|||
|
|
@ -33,38 +33,15 @@
|
|||
*/
|
||||
|
||||
#include "sfizz_lv2.h"
|
||||
#include "sfizz_lv2_plugin.h"
|
||||
|
||||
#include "sfizz/import/ForeignInstrument.h"
|
||||
|
||||
#include <lv2/atom/atom.h>
|
||||
#include <lv2/atom/forge.h>
|
||||
#include <lv2/atom/util.h>
|
||||
#include <lv2/buf-size/buf-size.h>
|
||||
#include <lv2/core/lv2.h>
|
||||
#include <lv2/core/lv2_util.h>
|
||||
#include <lv2/midi/midi.h>
|
||||
#include <lv2/options/options.h>
|
||||
#include <lv2/parameters/parameters.h>
|
||||
#include <lv2/patch/patch.h>
|
||||
#include <lv2/state/state.h>
|
||||
#include <lv2/urid/urid.h>
|
||||
#include <lv2/worker/worker.h>
|
||||
#include <lv2/log/logger.h>
|
||||
#include <lv2/log/log.h>
|
||||
#include <lv2/time/time.h>
|
||||
|
||||
#include <ardour/lv2_extensions.h>
|
||||
|
||||
#include <spin_mutex.h>
|
||||
#include "plugin/InstrumentDescription.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <sfizz.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#define CHANNEL_MASK 0x0F
|
||||
#define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK)
|
||||
#define MIDI_STATUS(byte) (byte & ~CHANNEL_MASK)
|
||||
|
|
@ -77,122 +54,12 @@
|
|||
#define LOG_SAMPLE_COUNT 48000
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#define DEFAULT_SCALA_FILE "Contents/Resources/DefaultScale.scl"
|
||||
#define DEFAULT_SFZ_FILE "Contents/Resources/DefaultInstrument.sfz"
|
||||
// This assumes that the longest path is the default sfz file; if not, change it
|
||||
#define MAX_BUNDLE_PATH_SIZE (MAX_PATH_SIZE - sizeof(DEFAULT_SFZ_FILE))
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define LV2_DEBUG(...) lv2_log_note(&self->logger, "[DEBUG] " __VA_ARGS__)
|
||||
#else
|
||||
#define LV2_DEBUG(...)
|
||||
#endif
|
||||
|
||||
struct sfizz_plugin_t
|
||||
{
|
||||
// Features
|
||||
LV2_URID_Map *map {};
|
||||
LV2_URID_Unmap *unmap {};
|
||||
LV2_Worker_Schedule *worker {};
|
||||
LV2_Log_Log *log {};
|
||||
LV2_Midnam *midnam {};
|
||||
|
||||
// Ports
|
||||
const LV2_Atom_Sequence *control_port {};
|
||||
LV2_Atom_Sequence *notify_port {};
|
||||
float *output_buffers[2] {};
|
||||
const float *volume_port {};
|
||||
const float *polyphony_port {};
|
||||
const float *oversampling_port {};
|
||||
const float *preload_port {};
|
||||
const float *freewheel_port {};
|
||||
const float *scala_root_key_port {};
|
||||
const float *tuning_frequency_port {};
|
||||
const float *stretch_tuning_port {};
|
||||
float *active_voices_port {};
|
||||
float *num_curves_port {};
|
||||
float *num_masters_port {};
|
||||
float *num_groups_port {};
|
||||
float *num_regions_port {};
|
||||
float *num_samples_port {};
|
||||
|
||||
// Atom forge
|
||||
LV2_Atom_Forge forge {}; ///< Forge for writing atoms in run thread
|
||||
LV2_Atom_Forge forge_secondary {}; ///< Forge for writing into other buffers
|
||||
|
||||
// Logger
|
||||
LV2_Log_Logger logger {};
|
||||
|
||||
// URIs
|
||||
LV2_URID midi_event_uri {};
|
||||
LV2_URID options_interface_uri {};
|
||||
LV2_URID max_block_length_uri {};
|
||||
LV2_URID nominal_block_length_uri {};
|
||||
LV2_URID sample_rate_uri {};
|
||||
LV2_URID atom_object_uri {};
|
||||
LV2_URID atom_blank_uri {};
|
||||
LV2_URID atom_float_uri {};
|
||||
LV2_URID atom_double_uri {};
|
||||
LV2_URID atom_int_uri {};
|
||||
LV2_URID atom_long_uri {};
|
||||
LV2_URID atom_urid_uri {};
|
||||
LV2_URID atom_path_uri {};
|
||||
LV2_URID patch_set_uri {};
|
||||
LV2_URID patch_get_uri {};
|
||||
LV2_URID patch_put_uri {};
|
||||
LV2_URID patch_property_uri {};
|
||||
LV2_URID patch_value_uri {};
|
||||
LV2_URID patch_body_uri {};
|
||||
LV2_URID state_changed_uri {};
|
||||
LV2_URID sfizz_sfz_file_uri {};
|
||||
LV2_URID sfizz_scala_file_uri {};
|
||||
LV2_URID sfizz_num_voices_uri {};
|
||||
LV2_URID sfizz_preload_size_uri {};
|
||||
LV2_URID sfizz_oversampling_uri {};
|
||||
LV2_URID sfizz_log_status_uri {};
|
||||
LV2_URID sfizz_check_modification_uri {};
|
||||
LV2_URID sfizz_active_voices_uri {};
|
||||
LV2_URID sfizz_osc_blob_uri {};
|
||||
LV2_URID time_position_uri {};
|
||||
LV2_URID time_bar_uri {};
|
||||
LV2_URID time_bar_beat_uri {};
|
||||
LV2_URID time_beat_unit_uri {};
|
||||
LV2_URID time_beats_per_bar_uri {};
|
||||
LV2_URID time_beats_per_minute_uri {};
|
||||
LV2_URID time_speed_uri {};
|
||||
|
||||
// Sfizz related data
|
||||
sfizz_synth_t *synth {};
|
||||
sfizz_client_t *client {};
|
||||
spin_mutex_t *synth_mutex {};
|
||||
bool expect_nominal_block_length {};
|
||||
char sfz_file_path[MAX_PATH_SIZE] {};
|
||||
char scala_file_path[MAX_PATH_SIZE] {};
|
||||
int num_voices {};
|
||||
unsigned int preload_size {};
|
||||
sfizz_oversampling_factor_t oversampling {};
|
||||
float stretch_tuning {};
|
||||
volatile bool check_modification {};
|
||||
int max_block_size {};
|
||||
int sample_counter {};
|
||||
float sample_rate {};
|
||||
std::atomic<int> must_update_midnam {};
|
||||
|
||||
// Timing data
|
||||
int bar {};
|
||||
double bar_beat {};
|
||||
int beats_per_bar {};
|
||||
int beat_unit {};
|
||||
double bpm_tempo {};
|
||||
double speed {};
|
||||
|
||||
// Paths
|
||||
char bundle_path[MAX_BUNDLE_PATH_SIZE] {};
|
||||
|
||||
// OSC
|
||||
uint8_t osc_temp[OSC_TEMP_SIZE] {};
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SFIZZ_TIMEINFO_POSITION = 1 << 0,
|
||||
|
|
@ -201,6 +68,14 @@ enum
|
|||
SFIZZ_TIMEINFO_SPEED = 1 << 3,
|
||||
};
|
||||
|
||||
///
|
||||
static bool
|
||||
sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path);
|
||||
|
||||
static bool
|
||||
sfizz_lv2_load_scala_file(sfizz_plugin_t *self, const char *file_path);
|
||||
|
||||
///
|
||||
static void
|
||||
sfizz_lv2_state_free_path(LV2_State_Free_Path_Handle handle,
|
||||
char *path)
|
||||
|
|
@ -607,11 +482,10 @@ instantiate(const LV2_Descriptor *descriptor,
|
|||
sfizz_set_broadcast_callback(self->synth, &sfizz_lv2_receive_message, self);
|
||||
sfizz_set_receive_callback(self->client, &sfizz_lv2_receive_message);
|
||||
|
||||
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);
|
||||
self->sfz_blob_mutex = new std::mutex;
|
||||
|
||||
sfizz_load_file(self->synth, self->sfz_file_path);
|
||||
sfizz_load_scala_file(self->synth, self->scala_file_path);
|
||||
sfizz_lv2_load_file(self, self->sfz_file_path);
|
||||
sfizz_lv2_load_scala_file(self, self->scala_file_path);
|
||||
|
||||
sfizz_lv2_update_timeinfo(self, 0, ~0);
|
||||
|
||||
|
|
@ -622,6 +496,8 @@ static void
|
|||
cleanup(LV2_Handle instance)
|
||||
{
|
||||
sfizz_plugin_t *self = (sfizz_plugin_t *)instance;
|
||||
delete[] self->sfz_blob_data;
|
||||
delete self->sfz_blob_mutex;
|
||||
spin_mutex_destroy(self->synth_mutex);
|
||||
sfizz_delete_client(self->client);
|
||||
sfizz_free(self->synth);
|
||||
|
|
@ -1172,6 +1048,25 @@ sfizz_lv2_update_file_info(sfizz_plugin_t* self, const char *file_path)
|
|||
self->must_update_midnam.store(1);
|
||||
}
|
||||
|
||||
static void
|
||||
sfizz_lv2_update_sfz_info(sfizz_plugin_t *self)
|
||||
{
|
||||
const std::string blob = getDescriptionBlob(self->synth);
|
||||
|
||||
uint32_t size = uint32_t(blob.size());
|
||||
uint8_t *data = new uint8_t[size];
|
||||
memcpy(data, blob.data(), size);
|
||||
|
||||
self->sfz_blob_mutex->lock();
|
||||
self->sfz_blob_serial += 1;
|
||||
const uint8_t *old_data = self->sfz_blob_data;
|
||||
self->sfz_blob_data = data;
|
||||
self->sfz_blob_size = size;
|
||||
self->sfz_blob_mutex->unlock();
|
||||
|
||||
delete[] old_data;
|
||||
}
|
||||
|
||||
static bool
|
||||
sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path)
|
||||
{
|
||||
|
|
@ -1197,7 +1092,7 @@ sfizz_lv2_load_file(sfizz_plugin_t *self, const char *file_path)
|
|||
status = sfizz_load_string(self->synth, virtual_path.c_str(), sfz_text.c_str());
|
||||
}
|
||||
|
||||
///
|
||||
sfizz_lv2_update_sfz_info(self);
|
||||
sfizz_lv2_update_file_info(self, file_path);
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,27 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <lv2/atom/atom.h>
|
||||
#include <lv2/atom/forge.h>
|
||||
#include <lv2/atom/util.h>
|
||||
#include <lv2/buf-size/buf-size.h>
|
||||
#include <lv2/core/lv2.h>
|
||||
#include <lv2/core/lv2_util.h>
|
||||
#include <lv2/midi/midi.h>
|
||||
#include <lv2/options/options.h>
|
||||
#include <lv2/parameters/parameters.h>
|
||||
#include <lv2/patch/patch.h>
|
||||
#include <lv2/state/state.h>
|
||||
#include <lv2/urid/urid.h>
|
||||
#include <lv2/worker/worker.h>
|
||||
#include <lv2/log/logger.h>
|
||||
#include <lv2/log/log.h>
|
||||
#include <lv2/time/time.h>
|
||||
|
||||
#include <ardour/lv2_extensions.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_PATH_SIZE 1024
|
||||
#define ATOM_TEMP_SIZE 8192
|
||||
#define OSC_TEMP_SIZE 8192
|
||||
|
|
@ -45,3 +66,22 @@ enum
|
|||
SFIZZ_NUM_REGIONS = 16,
|
||||
SFIZZ_NUM_SAMPLES = 17,
|
||||
};
|
||||
|
||||
// For use with instance-access
|
||||
struct sfizz_plugin_t;
|
||||
|
||||
/**
|
||||
* @brief Fetch a copy of the current description, if more recent than what the
|
||||
* version we already have.
|
||||
*
|
||||
* @param self The LV2 plugin
|
||||
* @param serial The optional serial number to compare against
|
||||
* @param desc The memory zone which receives the copy
|
||||
* @param sizep The memory zone which receives the size
|
||||
* @param serialp The memory zone which receives the new serial
|
||||
* @return if serial is not null and its value isn't older, false
|
||||
* otherwise, true, and the pointer returned in descp must be freed with delete[] after use
|
||||
*/
|
||||
bool sfizz_lv2_fetch_description(
|
||||
sfizz_plugin_t *self, const int *serial,
|
||||
uint8_t **descp, uint32_t *sizep, int *serialp);
|
||||
|
|
|
|||
31
plugins/lv2/sfizz_lv2_common.cpp
Normal file
31
plugins/lv2/sfizz_lv2_common.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// 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
|
||||
|
||||
#include "sfizz_lv2.h"
|
||||
#include "sfizz_lv2_plugin.h"
|
||||
|
||||
bool sfizz_lv2_fetch_description(
|
||||
sfizz_plugin_t *self, const int *serial,
|
||||
uint8_t **descp, uint32_t *sizep, int *serialp)
|
||||
{
|
||||
// must be thread-safe
|
||||
|
||||
if (serial && self->sfz_blob_serial == *serial)
|
||||
return false;
|
||||
|
||||
self->sfz_blob_mutex->lock();
|
||||
uint32_t size = self->sfz_blob_size;
|
||||
uint8_t *data = new uint8_t[size];
|
||||
int new_serial = self->sfz_blob_serial;
|
||||
memcpy(data, self->sfz_blob_data, size);
|
||||
self->sfz_blob_mutex->unlock();
|
||||
|
||||
*descp = data;
|
||||
*sizep = size;
|
||||
*serialp = new_serial;
|
||||
|
||||
return true;
|
||||
}
|
||||
131
plugins/lv2/sfizz_lv2_plugin.h
Normal file
131
plugins/lv2/sfizz_lv2_plugin.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sfizz_lv2.h"
|
||||
#include <spin_mutex.h>
|
||||
#include <sfizz.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#define DEFAULT_SCALA_FILE "Contents/Resources/DefaultScale.scl"
|
||||
#define DEFAULT_SFZ_FILE "Contents/Resources/DefaultInstrument.sfz"
|
||||
// This assumes that the longest path is the default sfz file; if not, change it
|
||||
#define MAX_BUNDLE_PATH_SIZE (MAX_PATH_SIZE - sizeof(DEFAULT_SFZ_FILE))
|
||||
|
||||
struct sfizz_plugin_t
|
||||
{
|
||||
// Features
|
||||
LV2_URID_Map *map {};
|
||||
LV2_URID_Unmap *unmap {};
|
||||
LV2_Worker_Schedule *worker {};
|
||||
LV2_Log_Log *log {};
|
||||
LV2_Midnam *midnam {};
|
||||
|
||||
// Ports
|
||||
const LV2_Atom_Sequence *control_port {};
|
||||
LV2_Atom_Sequence *notify_port {};
|
||||
float *output_buffers[2] {};
|
||||
const float *volume_port {};
|
||||
const float *polyphony_port {};
|
||||
const float *oversampling_port {};
|
||||
const float *preload_port {};
|
||||
const float *freewheel_port {};
|
||||
const float *scala_root_key_port {};
|
||||
const float *tuning_frequency_port {};
|
||||
const float *stretch_tuning_port {};
|
||||
float *active_voices_port {};
|
||||
float *num_curves_port {};
|
||||
float *num_masters_port {};
|
||||
float *num_groups_port {};
|
||||
float *num_regions_port {};
|
||||
float *num_samples_port {};
|
||||
|
||||
// Atom forge
|
||||
LV2_Atom_Forge forge {}; ///< Forge for writing atoms in run thread
|
||||
LV2_Atom_Forge forge_secondary {}; ///< Forge for writing into other buffers
|
||||
|
||||
// Logger
|
||||
LV2_Log_Logger logger {};
|
||||
|
||||
// URIs
|
||||
LV2_URID midi_event_uri {};
|
||||
LV2_URID options_interface_uri {};
|
||||
LV2_URID max_block_length_uri {};
|
||||
LV2_URID nominal_block_length_uri {};
|
||||
LV2_URID sample_rate_uri {};
|
||||
LV2_URID atom_object_uri {};
|
||||
LV2_URID atom_blank_uri {};
|
||||
LV2_URID atom_float_uri {};
|
||||
LV2_URID atom_double_uri {};
|
||||
LV2_URID atom_int_uri {};
|
||||
LV2_URID atom_long_uri {};
|
||||
LV2_URID atom_urid_uri {};
|
||||
LV2_URID atom_path_uri {};
|
||||
LV2_URID patch_set_uri {};
|
||||
LV2_URID patch_get_uri {};
|
||||
LV2_URID patch_put_uri {};
|
||||
LV2_URID patch_property_uri {};
|
||||
LV2_URID patch_value_uri {};
|
||||
LV2_URID patch_body_uri {};
|
||||
LV2_URID state_changed_uri {};
|
||||
LV2_URID sfizz_sfz_file_uri {};
|
||||
LV2_URID sfizz_scala_file_uri {};
|
||||
LV2_URID sfizz_num_voices_uri {};
|
||||
LV2_URID sfizz_preload_size_uri {};
|
||||
LV2_URID sfizz_oversampling_uri {};
|
||||
LV2_URID sfizz_log_status_uri {};
|
||||
LV2_URID sfizz_check_modification_uri {};
|
||||
LV2_URID sfizz_active_voices_uri {};
|
||||
LV2_URID sfizz_osc_blob_uri {};
|
||||
LV2_URID time_position_uri {};
|
||||
LV2_URID time_bar_uri {};
|
||||
LV2_URID time_bar_beat_uri {};
|
||||
LV2_URID time_beat_unit_uri {};
|
||||
LV2_URID time_beats_per_bar_uri {};
|
||||
LV2_URID time_beats_per_minute_uri {};
|
||||
LV2_URID time_speed_uri {};
|
||||
|
||||
// Sfizz related data
|
||||
sfizz_synth_t *synth {};
|
||||
sfizz_client_t *client {};
|
||||
spin_mutex_t *synth_mutex {};
|
||||
bool expect_nominal_block_length {};
|
||||
char sfz_file_path[MAX_PATH_SIZE] {};
|
||||
char scala_file_path[MAX_PATH_SIZE] {};
|
||||
int num_voices {};
|
||||
unsigned int preload_size {};
|
||||
sfizz_oversampling_factor_t oversampling {};
|
||||
float stretch_tuning {};
|
||||
volatile bool check_modification {};
|
||||
int max_block_size {};
|
||||
int sample_counter {};
|
||||
float sample_rate {};
|
||||
std::atomic<int> must_update_midnam {};
|
||||
|
||||
// Current instrument description
|
||||
std::mutex *sfz_blob_mutex {};
|
||||
volatile int sfz_blob_serial {};
|
||||
const uint8_t *volatile sfz_blob_data {};
|
||||
volatile uint32_t sfz_blob_size {};
|
||||
|
||||
// Timing data
|
||||
int bar {};
|
||||
double bar_beat {};
|
||||
int beats_per_bar {};
|
||||
int beat_unit {};
|
||||
double bpm_tempo {};
|
||||
double speed {};
|
||||
|
||||
// Paths
|
||||
char bundle_path[MAX_BUNDLE_PATH_SIZE] {};
|
||||
|
||||
// OSC
|
||||
uint8_t osc_temp[OSC_TEMP_SIZE] {};
|
||||
};
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#include "editor/Editor.h"
|
||||
#include "editor/EditorController.h"
|
||||
#include "editor/EditIds.h"
|
||||
#include "plugin/InstrumentDescription.h"
|
||||
#include <lv2/ui/ui.h>
|
||||
#include <lv2/atom/atom.h>
|
||||
#include <lv2/atom/forge.h>
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
#include <lv2/midi/midi.h>
|
||||
#include <lv2/patch/patch.h>
|
||||
#include <lv2/urid/urid.h>
|
||||
#include <lv2/instance-access/instance-access.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
|
@ -86,6 +88,7 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface {
|
|||
LV2_URID_Unmap *unmap = nullptr;
|
||||
LV2UI_Resize *resize = nullptr;
|
||||
LV2UI_Touch *touch = nullptr;
|
||||
sfizz_plugin_t *plugin = nullptr;
|
||||
FrameHolder uiFrame;
|
||||
std::unique_ptr<Editor> editor;
|
||||
#if LINUX
|
||||
|
|
@ -112,6 +115,9 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface {
|
|||
uint8_t osc_temp[OSC_TEMP_SIZE];
|
||||
alignas(LV2_Atom) uint8_t atom_temp[ATOM_TEMP_SIZE];
|
||||
|
||||
int sfz_serial = 0;
|
||||
bool valid_sfz_serial = false;
|
||||
|
||||
protected:
|
||||
void uiSendValue(EditId id, const EditValue& v) override;
|
||||
void uiBeginSend(EditId id) override;
|
||||
|
|
@ -178,12 +184,18 @@ instantiate(const LV2UI_Descriptor *descriptor,
|
|||
self->touch = (LV2UI_Touch*)(**f).data;
|
||||
else if (!strcmp((**f).URI, LV2_UI__parent))
|
||||
parentWindowId = (**f).data;
|
||||
else if (!strcmp((**f).URI, LV2_INSTANCE_ACCESS_URI))
|
||||
self->plugin = (sfizz_plugin_t *)(**f).data;
|
||||
}
|
||||
|
||||
// The map feature is required
|
||||
if (!map || !unmap)
|
||||
return nullptr;
|
||||
|
||||
// The instance-access feature is required
|
||||
if (!self->plugin)
|
||||
return nullptr;
|
||||
|
||||
LV2_Atom_Forge *forge = &self->atom_forge;
|
||||
lv2_atom_forge_init(forge, map);
|
||||
self->atom_event_transfer_uri = map->map(map->handle, LV2_ATOM__eventTransfer);
|
||||
|
|
@ -358,11 +370,44 @@ port_event(LV2UI_Handle ui,
|
|||
(void)buffer_size;
|
||||
}
|
||||
|
||||
static void
|
||||
sfizz_ui_update_description(const InstrumentDescription& desc)
|
||||
{
|
||||
// TODO(jpc) perform editor updates here
|
||||
|
||||
//std::cerr << desc << std::endl;
|
||||
}
|
||||
|
||||
static void
|
||||
sfizz_ui_check_sfz_update(sfizz_ui_t *self)
|
||||
{
|
||||
uint8_t *data = nullptr;
|
||||
uint32_t size = 0;
|
||||
int new_serial = 0;
|
||||
const int *serial = self->valid_sfz_serial ? &self->sfz_serial : nullptr;
|
||||
|
||||
bool update = sfizz_lv2_fetch_description(
|
||||
self->plugin, serial, &data, &size, &new_serial);
|
||||
|
||||
if (update) {
|
||||
std::unique_ptr<uint8_t[]> cleanup(data);
|
||||
self->sfz_serial = new_serial;
|
||||
self->valid_sfz_serial = true;
|
||||
|
||||
const InstrumentDescription desc = parseDescriptionBlob(
|
||||
absl::string_view(reinterpret_cast<char*>(data), size));
|
||||
sfizz_ui_update_description(desc);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
idle(LV2UI_Handle ui)
|
||||
{
|
||||
sfizz_ui_t *self = (sfizz_ui_t *)ui;
|
||||
|
||||
// check if there are news regarding the current SFZ
|
||||
sfizz_ui_check_sfz_update(self);
|
||||
|
||||
#if LINUX
|
||||
self->runLoop->execIdle();
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -11,4 +11,5 @@
|
|||
lv2:optionalFeature ui:parent ;
|
||||
lv2:optionalFeature ui:touch ;
|
||||
lv2:requiredFeature urid:map ;
|
||||
lv2:requiredFeature urid:unmap .
|
||||
lv2:requiredFeature urid:unmap ;
|
||||
lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
|||
// create update objects
|
||||
oscUpdate_ = Steinberg::owned(new OSCUpdate);
|
||||
noteUpdate_ = Steinberg::owned(new NoteUpdate);
|
||||
sfzPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateSfz));
|
||||
scalaPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateScala));
|
||||
sfzUpdate_ = Steinberg::owned(new SfzUpdate);
|
||||
scalaUpdate_ = Steinberg::owned(new ScalaUpdate);
|
||||
processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate);
|
||||
playStateUpdate_ = Steinberg::owned(new PlayStateUpdate);
|
||||
|
||||
|
|
@ -211,10 +211,8 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
|||
setParam(kPidTuningFrequency, s.tuningFrequency);
|
||||
setParam(kPidStretchedTuning, s.stretchedTuning);
|
||||
|
||||
sfzPathUpdate_->setPath(s.sfzFile);
|
||||
sfzPathUpdate_->deferUpdate();
|
||||
scalaPathUpdate_->setPath(s.scalaFile);
|
||||
scalaPathUpdate_->deferUpdate();
|
||||
scalaUpdate_->setPath(s.scalaFile);
|
||||
scalaUpdate_->deferUpdate();
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
|
@ -230,35 +228,47 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
|||
const char* id = message->getMessageID();
|
||||
Vst::IAttributeList* attr = message->getAttributes();
|
||||
|
||||
if (!strcmp(id, "LoadedSfz")) {
|
||||
///
|
||||
auto stringFromBinaryAttribute = [attr](const char* id, absl::string_view& string) -> tresult {
|
||||
const void* data = nullptr;
|
||||
uint32 size = 0;
|
||||
result = attr->getBinary("File", data, size);
|
||||
tresult result = attr->getBinary(id, data, size);
|
||||
if (result == kResultTrue)
|
||||
string = absl::string_view(reinterpret_cast<const char*>(data), size);
|
||||
return result;
|
||||
};
|
||||
|
||||
///
|
||||
if (!strcmp(id, "LoadedSfz")) {
|
||||
absl::string_view sfzFile;
|
||||
absl::string_view sfzDescriptionBlob;
|
||||
|
||||
result = stringFromBinaryAttribute("File", sfzFile);
|
||||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
std::string sfzFile(static_cast<const char *>(data), size);
|
||||
processorStateUpdate_->access([&sfzFile](SfizzVstState& state) {
|
||||
state.sfzFile = sfzFile;
|
||||
result = stringFromBinaryAttribute("Description", sfzDescriptionBlob);
|
||||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
processorStateUpdate_->access([sfzFile](SfizzVstState& state) {
|
||||
state.sfzFile = std::string(sfzFile);
|
||||
});
|
||||
sfzPathUpdate_->setPath(std::move(sfzFile));
|
||||
sfzPathUpdate_->deferUpdate();
|
||||
sfzUpdate_->setPath(std::string(sfzFile), std::string(sfzDescriptionBlob));
|
||||
sfzUpdate_->deferUpdate();
|
||||
}
|
||||
else if (!strcmp(id, "LoadedScala")) {
|
||||
const void* data = nullptr;
|
||||
uint32 size = 0;
|
||||
result = attr->getBinary("File", data, size);
|
||||
absl::string_view scalaFile;
|
||||
|
||||
result = stringFromBinaryAttribute("File", scalaFile);
|
||||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
std::string scalaFile(static_cast<const char *>(data), size);
|
||||
processorStateUpdate_->access([&scalaFile](SfizzVstState& state) {
|
||||
state.scalaFile = scalaFile;
|
||||
processorStateUpdate_->access([scalaFile](SfizzVstState& state) {
|
||||
state.scalaFile = std::string(scalaFile);
|
||||
});
|
||||
scalaPathUpdate_->setPath(std::move(scalaFile));
|
||||
scalaPathUpdate_->deferUpdate();
|
||||
scalaUpdate_->setPath(std::string(scalaFile));
|
||||
scalaUpdate_->deferUpdate();
|
||||
}
|
||||
else if (!strcmp(id, "NotifiedPlayState")) {
|
||||
const void* data = nullptr;
|
||||
|
|
@ -314,8 +324,8 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name)
|
|||
return nullptr;
|
||||
|
||||
std::vector<FObject*> continuousUpdates;
|
||||
continuousUpdates.push_back(sfzPathUpdate_);
|
||||
continuousUpdates.push_back(scalaPathUpdate_);
|
||||
continuousUpdates.push_back(sfzUpdate_);
|
||||
continuousUpdates.push_back(scalaUpdate_);
|
||||
continuousUpdates.push_back(playStateUpdate_);
|
||||
for (uint32 i = 0, n = parameters.getParameterCount(); i < n; ++i)
|
||||
continuousUpdates.push_back(parameters.getParameterByIndex(i));
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ public:
|
|||
protected:
|
||||
Steinberg::IPtr<OSCUpdate> oscUpdate_;
|
||||
Steinberg::IPtr<NoteUpdate> noteUpdate_;
|
||||
Steinberg::IPtr<FilePathUpdate> sfzPathUpdate_;
|
||||
Steinberg::IPtr<FilePathUpdate> scalaPathUpdate_;
|
||||
Steinberg::IPtr<SfzUpdate> sfzUpdate_;
|
||||
Steinberg::IPtr<ScalaUpdate> scalaUpdate_;
|
||||
Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_;
|
||||
Steinberg::IPtr<PlayStateUpdate> playStateUpdate_;
|
||||
Vst::ParamID midiMapping_[Vst::kCountCtrlNumber] {};
|
||||
|
|
|
|||
|
|
@ -188,17 +188,14 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
|||
}
|
||||
}
|
||||
|
||||
if (FilePathUpdate* update = FCast<FilePathUpdate>(changedUnknown)) {
|
||||
if (SfzUpdate* update = FCast<SfzUpdate>(changedUnknown)) {
|
||||
const std::string path = update->getPath();
|
||||
switch (update->getType()) {
|
||||
case kFilePathUpdateSfz:
|
||||
uiReceiveValue(EditId::SfzFile, path);
|
||||
break;
|
||||
case kFilePathUpdateScala:
|
||||
uiReceiveValue(EditId::ScalaFile, path);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
uiReceiveValue(EditId::SfzFile, path);
|
||||
}
|
||||
|
||||
if (ScalaUpdate* update = FCast<ScalaUpdate>(changedUnknown)) {
|
||||
const std::string path = update->getPath();
|
||||
uiReceiveValue(EditId::ScalaFile, path);
|
||||
}
|
||||
|
||||
if (ProcessorStateUpdate* update = FCast<ProcessorStateUpdate>(changedUnknown)) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "SfizzVstParameters.h"
|
||||
#include "SfizzFileScan.h"
|
||||
#include "sfizz/import/ForeignInstrument.h"
|
||||
#include "plugin/InstrumentDescription.h"
|
||||
#include "base/source/fstreamer.h"
|
||||
#include "pluginterfaces/vst/ivstevents.h"
|
||||
#include "pluginterfaces/vst/ivstparameterchanges.h"
|
||||
|
|
@ -97,7 +98,7 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
|
|||
_synth->setBroadcastCallback(onMessage, this);
|
||||
|
||||
_currentStretchedTuning = 0.0;
|
||||
loadSfzFileOrDefault(*_synth, {});
|
||||
loadSfzFileOrDefault({});
|
||||
|
||||
_synth->tempo(0, 0.5);
|
||||
_timeSigNumerator = 4;
|
||||
|
|
@ -121,6 +122,19 @@ tresult PLUGIN_API SfizzVstProcessor::setBusArrangements(Vst::SpeakerArrangement
|
|||
return AudioEffect::setBusArrangements(inputs, numIns, outputs, numOuts);
|
||||
}
|
||||
|
||||
tresult PLUGIN_API SfizzVstProcessor::connect(IConnectionPoint* other)
|
||||
{
|
||||
tresult result = AudioEffect::connect(other);
|
||||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
// when controller connects, send these messages that we couldn't earlier
|
||||
if (_loadedSfzMessage)
|
||||
sendMessage(_loadedSfzMessage);
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream)
|
||||
{
|
||||
SfizzVstState s;
|
||||
|
|
@ -173,7 +187,7 @@ void SfizzVstProcessor::syncStateToSynth()
|
|||
if (!synth)
|
||||
return;
|
||||
|
||||
loadSfzFileOrDefault(*synth, _state.sfzFile);
|
||||
loadSfzFileOrDefault(_state.sfzFile);
|
||||
synth->setVolume(_state.volume);
|
||||
synth->setNumVoices(_state.numVoices);
|
||||
synth->setOversamplingFactor(1 << _state.oversamplingLog2);
|
||||
|
|
@ -556,13 +570,8 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
|
|||
|
||||
std::unique_lock<SpinMutex> lock(_processMutex);
|
||||
_state.sfzFile.assign(static_cast<const char *>(data), size);
|
||||
loadSfzFileOrDefault(*_synth, _state.sfzFile);
|
||||
loadSfzFileOrDefault(_state.sfzFile);
|
||||
lock.unlock();
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
|
||||
reply->setMessageID("LoadedSfz");
|
||||
reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size());
|
||||
sendMessage(reply);
|
||||
}
|
||||
else if (!std::strcmp(id, "LoadScala")) {
|
||||
const void* data = nullptr;
|
||||
|
|
@ -614,8 +623,10 @@ void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char*
|
|||
}
|
||||
}
|
||||
|
||||
void SfizzVstProcessor::loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath)
|
||||
void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath)
|
||||
{
|
||||
sfz::Sfizz& synth = *_synth;
|
||||
|
||||
if (!filePath.empty()) {
|
||||
const sfz::InstrumentFormatRegistry& formatRegistry = sfz::InstrumentFormatRegistry::getInstance();
|
||||
const sfz::InstrumentFormat* format = formatRegistry.getMatchingFormat(filePath);
|
||||
|
|
@ -628,8 +639,22 @@ void SfizzVstProcessor::loadSfzFileOrDefault(sfz::Sfizz& synth, const std::strin
|
|||
synth.loadSfzString(virtualPath, sfzText);
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
synth.loadSfzString("default.sfz", defaultSfzText);
|
||||
}
|
||||
|
||||
const std::string desc = getDescriptionBlob(synth.handle());
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> message { allocateMessage() };
|
||||
message->setMessageID("LoadedSfz");
|
||||
Vst::IAttributeList* attrs = message->getAttributes();
|
||||
attrs->setBinary("File", filePath.data(), filePath.size());
|
||||
attrs->setBinary("Description", desc.data(), desc.size());
|
||||
|
||||
// sending can fail if controller is not connected yet, so keep it around
|
||||
_loadedSfzMessage = message;
|
||||
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
void SfizzVstProcessor::doBackgroundWork()
|
||||
|
|
@ -706,12 +731,7 @@ void SfizzVstProcessor::doBackgroundIdle()
|
|||
if (_synth->shouldReloadFile()) {
|
||||
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||
loadSfzFileOrDefault(*_synth, _state.sfzFile);
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
|
||||
reply->setMessageID("LoadedSfz");
|
||||
reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size());
|
||||
sendMessage(reply);
|
||||
loadSfzFileOrDefault(_state.sfzFile);
|
||||
}
|
||||
if (_synth->shouldReloadScala()) {
|
||||
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ public:
|
|||
tresult PLUGIN_API initialize(FUnknown* context) override;
|
||||
tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts) override;
|
||||
|
||||
tresult PLUGIN_API connect(IConnectionPoint* other) override;
|
||||
|
||||
tresult PLUGIN_API setState(IBStream* stream) override;
|
||||
tresult PLUGIN_API getState(IBStream* stream) override;
|
||||
void syncStateToSynth();
|
||||
|
|
@ -49,6 +51,7 @@ public:
|
|||
private:
|
||||
// synth state. acquire processMutex before accessing
|
||||
std::unique_ptr<sfz::Sfizz> _synth;
|
||||
Steinberg::IPtr<Vst::IMessage> _loadedSfzMessage;
|
||||
bool _isActive = false;
|
||||
SfizzVstState _state;
|
||||
float _currentStretchedTuning = 0;
|
||||
|
|
@ -59,7 +62,7 @@ private:
|
|||
void receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args);
|
||||
|
||||
// misc
|
||||
static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath);
|
||||
void loadSfzFileOrDefault(const std::string& filePath);
|
||||
|
||||
// note event tracking
|
||||
std::array<float, 128> _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change
|
||||
|
|
|
|||
|
|
@ -67,21 +67,42 @@ private:
|
|||
};
|
||||
|
||||
/**
|
||||
* @brief Update which notifies a change of file path pseudo-parameter
|
||||
* The message ID is used to indicate which path it is.
|
||||
* @brief Update which notifies a change of SFZ file.
|
||||
*/
|
||||
class FilePathUpdate : public Steinberg::FObject {
|
||||
class SfzUpdate : public Steinberg::FObject {
|
||||
public:
|
||||
explicit FilePathUpdate(int32 type)
|
||||
: type_(type)
|
||||
void setPath(std::string newPath, std::string newDescription)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
path_ = std::move(newPath);
|
||||
description_ = std::move(newDescription);
|
||||
}
|
||||
|
||||
int32 getType() const noexcept
|
||||
std::string getPath() const
|
||||
{
|
||||
return type_;
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return path_;
|
||||
}
|
||||
|
||||
std::string getDescription() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return description_;
|
||||
}
|
||||
|
||||
OBJ_METHODS(SfzUpdate, FObject)
|
||||
|
||||
private:
|
||||
std::string path_;
|
||||
std::string description_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Update which notifies a change of scala file.
|
||||
*/
|
||||
class ScalaUpdate : public Steinberg::FObject {
|
||||
public:
|
||||
void setPath(std::string newPath)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
|
@ -94,19 +115,13 @@ public:
|
|||
return path_;
|
||||
}
|
||||
|
||||
OBJ_METHODS(FilePathUpdate, FObject)
|
||||
OBJ_METHODS(ScalaUpdate, FObject)
|
||||
|
||||
private:
|
||||
int32 type_ {};
|
||||
std::string path_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
enum {
|
||||
kFilePathUpdateSfz,
|
||||
kFilePathUpdateScala,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Update which indicates the processor status.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -39,6 +39,28 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
MATCH("/num_regions", "") {
|
||||
client.receive<'i'>(delay, path, int(impl.layers_.size()));
|
||||
} break;
|
||||
|
||||
MATCH("/num_groups", "") {
|
||||
client.receive<'i'>(delay, path, impl.numGroups_);
|
||||
} break;
|
||||
|
||||
MATCH("/num_masters", "") {
|
||||
client.receive<'i'>(delay, path, impl.numMasters_);
|
||||
} break;
|
||||
|
||||
MATCH("/num_curves", "") {
|
||||
client.receive<'i'>(delay, path, int(impl.resources_.curves.getNumCurves()));
|
||||
} break;
|
||||
|
||||
MATCH("/num_samples", "") {
|
||||
client.receive<'i'>(delay, path, int(impl.resources_.filePool.getNumPreloadedSamples()));
|
||||
} break;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
MATCH("/key/slots", "") {
|
||||
const BitArray<128>& keys = impl.keySlots_;
|
||||
sfizz_blob_t blob { keys.data(), static_cast<uint32_t>(keys.byte_size()) };
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue