Added the LV2 parameters related to the preloaded size and the oversampling

This commit is contained in:
Paul Ferrand 2019-12-02 00:10:21 +01:00
parent 30bf269359
commit 6713640b22
5 changed files with 228 additions and 14 deletions

View file

@ -51,6 +51,8 @@
#define SFIZZ_PREFIX SFIZZ_URI "#"
#define SFIZZ__sfzFile "http://sfztools.github.io/sfizz:sfzfile"
#define SFIZZ__numVoices "http://sfztools.github.io/sfizz:numvoices"
#define SFIZZ__preloadSize "http://sfztools.github.io/sfizz:preload_size"
#define SFIZZ__oversampling "http://sfztools.github.io/sfizz:oversampling"
#define CHANNEL_MASK 0x0F
#define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK)
@ -59,6 +61,8 @@
#define MAX_PATH_SIZE 1024
#define MAX_VOICES 256
#define DEFAULT_VOICES 64
#define DEFAULT_OVERSAMPLING SFIZZ_OVERSAMPLING_X1
#define DEFAULT_PRELOAD 8192
#define UNUSED(x) (void)(x)
typedef struct
@ -75,6 +79,8 @@ typedef struct
float *output_buffers[2];
const float *volume_port;
const float *polyphony_port;
const float *oversampling_port;
const float *preload_port;
// Atom forge
LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread
@ -103,13 +109,17 @@ typedef struct
LV2_URID state_changed_uri;
LV2_URID sfizz_sfz_file_uri;
LV2_URID sfizz_num_voices_uri;
LV2_URID sfizz_preload_size_uri;
LV2_URID sfizz_oversampling_uri;
// Sfizz related data
sfizz_synth_t *synth;
bool expect_nominal_block_length;
char sfz_file_path[MAX_PATH_SIZE];
int num_voices;
bool changing_voices;
unsigned int preload_size;
sfizz_oversampling_factor_t oversampling;
bool changing_state;
int max_block_size;
float sample_rate;
} sfizz_plugin_t;
@ -121,7 +131,9 @@ enum
SFIZZ_LEFT = 2,
SFIZZ_RIGHT = 3,
SFIZZ_VOLUME = 4,
SFIZZ_POLYPHONY = 5
SFIZZ_POLYPHONY = 5,
SFIZZ_OVERSAMPLING = 6,
SFIZZ_PRELOAD = 7
};
static void
@ -146,6 +158,8 @@ sfizz_lv2_map_required_uris(sfizz_plugin_t *self)
self->state_changed_uri = map->map(map->handle, LV2_STATE__StateChanged);
self->sfizz_sfz_file_uri = map->map(map->handle, SFIZZ__sfzFile);
self->sfizz_num_voices_uri = map->map(map->handle, SFIZZ__numVoices);
self->sfizz_preload_size_uri = map->map(map->handle, SFIZZ__preloadSize);
self->sfizz_oversampling_uri = map->map(map->handle, SFIZZ__oversampling);
}
static void
@ -174,6 +188,12 @@ connect_port(LV2_Handle instance,
case SFIZZ_POLYPHONY:
self->polyphony_port = (const float *)data;
break;
case SFIZZ_OVERSAMPLING:
self->oversampling_port = (const float *)data;
break;
case SFIZZ_PRELOAD:
self->preload_port = (const float *)data;
break;
default:
break;
}
@ -203,7 +223,9 @@ instantiate(const LV2_Descriptor *descriptor,
self->expect_nominal_block_length = false;
self->sfz_file_path[0] = '\0';
self->num_voices = DEFAULT_VOICES;
self->changing_voices = false;
self->oversampling = DEFAULT_OVERSAMPLING;
self->preload_size = DEFAULT_PRELOAD;
self->changing_state = false;
// Get the features from the host and populate the structure
for (const LV2_Feature *const *f = features; *f; f++)
@ -509,8 +531,7 @@ run(LV2_Handle instance, uint32_t sample_count)
sfizz_set_volume(self->synth, volume);
int num_voices = (int)*self->polyphony_port;
if (num_voices != self->num_voices && !self->changing_voices)
{
if (num_voices != self->num_voices && !self->changing_state) {
lv2_log_note(&self->logger, "[run] Number of voices changed to %d\n", num_voices);
LV2_Atom_Int num_voices_atom;
num_voices_atom.atom.type = self->sfizz_num_voices_uri;
@ -520,7 +541,37 @@ run(LV2_Handle instance, uint32_t sample_count)
lv2_atom_total_size((LV2_Atom*)&num_voices_atom),
&num_voices_atom) == LV2_WORKER_SUCCESS)
{
self->changing_voices = true;
self->changing_state = true;
}
}
unsigned int preload_size = (int)*self->preload_port;
if (preload_size != self->preload_size && !self->changing_state) {
lv2_log_note(&self->logger, "[run] Preload size changed to %d\n", preload_size);
LV2_Atom_Int atom;
atom.atom.type = self->sfizz_preload_size_uri;
atom.atom.size = sizeof(int);
atom.body = preload_size;
if (self->worker->schedule_work(self->worker->handle,
lv2_atom_total_size((LV2_Atom*)&atom),
&atom) == LV2_WORKER_SUCCESS)
{
self->changing_state = true;
}
}
sfizz_oversampling_factor_t oversampling = (sfizz_oversampling_factor_t)*self->oversampling_port;
if (oversampling != self->oversampling && !self->changing_state) {
lv2_log_note(&self->logger, "[run] Oversampling size changed to %d\n", oversampling);
LV2_Atom_Int atom;
atom.atom.type = self->sfizz_oversampling_uri;
atom.atom.size = sizeof(int);
atom.body = oversampling;
if (self->worker->schedule_work(self->worker->handle,
lv2_atom_total_size((LV2_Atom*)&atom),
&atom) == LV2_WORKER_SUCCESS)
{
self->changing_state = true;
}
}
@ -614,6 +665,30 @@ restore(LV2_Handle instance,
self->num_voices = num_voices;
}
}
value = retrieve(handle, self->sfizz_preload_size_uri, &size, &type, &val_flags);
if (value)
{
unsigned int preload_size = *(const unsigned int *)value;
if (preload_size != self->preload_size)
{
lv2_log_note(&self->logger, "Restoring the preload size to %d\n", preload_size);
sfizz_set_preload_size(self->synth, preload_size);
self->preload_size = preload_size;
}
}
value = retrieve(handle, self->sfizz_oversampling_uri, &size, &type, &val_flags);
if (value)
{
sfizz_oversampling_factor_t oversampling = *(const sfizz_oversampling_factor_t *)value;
if (oversampling != self->oversampling)
{
lv2_log_note(&self->logger, "Restoring the oversampling to %d\n", oversampling);
sfizz_set_oversampling_factor(self->synth, oversampling);
self->oversampling = oversampling;
}
}
return LV2_STATE_SUCCESS;
}
@ -643,6 +718,22 @@ save(LV2_Handle instance,
self->atom_int_uri,
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
// Save the preload size
store(handle,
self->sfizz_preload_size_uri,
&self->preload_size,
sizeof(unsigned int),
self->atom_int_uri,
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
// Save the preload size
store(handle,
self->sfizz_oversampling_uri,
&self->oversampling,
sizeof(int),
self->atom_int_uri,
LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
return LV2_STATE_SUCCESS;
}
@ -674,6 +765,19 @@ work(LV2_Handle instance,
lv2_log_note(&self->logger, "[work] Changing number of voices to: %d\n", num_voices);
sfizz_set_num_voices(self->synth, num_voices);
}
else if (atom->type == self->sfizz_preload_size_uri)
{
const unsigned int preload_size = *(const unsigned int *)LV2_ATOM_BODY_CONST(atom);
lv2_log_note(&self->logger, "[work] Changing preload size to: %d\n", preload_size);
sfizz_set_preload_size(self->synth, preload_size);
}
else if (atom->type == self->sfizz_oversampling_uri)
{
const sfizz_oversampling_factor_t oversampling =
*(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom);
lv2_log_note(&self->logger, "[work] Changing oversampling to: %d\n", oversampling);
sfizz_set_oversampling_factor(self->synth, oversampling);
}
else
{
lv2_log_error(&self->logger, "[worker] Got an unknown atom.\n");
@ -702,18 +806,33 @@ work_response(LV2_Handle instance,
const LV2_Atom *atom = (const LV2_Atom *)data;
if (atom->type == self->sfizz_sfz_file_uri)
{
{ // TODO: could check that everything is indeed changed here
const char *sfz_file_path = LV2_ATOM_BODY_CONST(atom);
strcpy(self->sfz_file_path, sfz_file_path);
lv2_log_note(&self->logger, "[work_response] File changed to: %s\n", self->sfz_file_path);
}
else if (atom->type == self->sfizz_num_voices_uri)
{
{ // TODO: could check that everything is indeed changed here
const int num_voices = *(const int *)LV2_ATOM_BODY_CONST(atom);
self->num_voices = num_voices;
self->changing_voices = false;
self->changing_state = false;
lv2_log_note(&self->logger, "[work_response] Number of voices changed to: %d\n", self->num_voices);
}
else if (atom->type == self->sfizz_preload_size_uri)
{ // TODO: could check that everything is indeed changed here
const unsigned int preload_size = *(const unsigned int *)LV2_ATOM_BODY_CONST(atom);
self->preload_size = preload_size;
self->changing_state = false;
lv2_log_note(&self->logger, "[work_response] Preload size changed to: %d\n", self->preload_size);
}
else if (atom->type == self->sfizz_oversampling_uri)
{ // TODO: could check that everything is indeed changed here
const sfizz_oversampling_factor_t oversampling =
*(const sfizz_oversampling_factor_t *)LV2_ATOM_BODY_CONST(atom);
self->oversampling = oversampling;
self->changing_state = false;
lv2_log_note(&self->logger, "[work_response] Oversampling changed to: %d\n", self->oversampling);
}
else
{
lv2_log_error(&self->logger, "[work_response] Got an unknown atom.\n");

View file

@ -30,6 +30,16 @@
rdfs:label "Polyphony" ;
rdfs:range atom:Int .
<@LV2PLUGIN_URI@:preload_size>
a lv2:Parameter ;
rdfs:label "Preload size" ;
rdfs:range atom:Int .
<@LV2PLUGIN_URI@:oversampling>
a lv2:Parameter ;
rdfs:label "Oversampling" ;
rdfs:range atom:Int .
<@LV2PLUGIN_URI@>
a doap:Project, lv2:Plugin, lv2:InstrumentPlugin ;
@ -105,4 +115,39 @@
lv2:scalePoint [ rdfs:label "64 voices"; rdf:value 64 ] ;
lv2:scalePoint [ rdfs:label "128 voices"; rdf:value 128 ] ;
lv2:scalePoint [ rdfs:label "256 voices"; rdf:value 256 ] ;
] .
] , [
a lv2:InputPort, lv2:ControlPort ;
lv2:index 6 ;
lv2:symbol "oversampling" ;
lv2:name "Internal oversampling factor" ;
pg:group <#config> ;
lv2:portProperty pprop:notAutomatic ;
lv2:portProperty pprop:expensive ;
lv2:portProperty lv2:integer ;
lv2:portProperty lv2:enumeration ;
lv2:default 1 ;
lv2:minimum 1 ;
lv2:maximum 8 ;
lv2:scalePoint [ rdfs:label "x1 oversampling"; rdf:value 1 ] ;
lv2:scalePoint [ rdfs:label "x2 oversampling"; rdf:value 2 ] ;
lv2:scalePoint [ rdfs:label "x4 oversampling"; rdf:value 4 ] ;
lv2:scalePoint [ rdfs:label "x8 oversampling"; rdf:value 8 ] ;
], [
a lv2:InputPort, lv2:ControlPort ;
lv2:index 7 ;
lv2:symbol "preload_size" ;
lv2:name "Preload size" ;
pg:group <#config> ;
lv2:portProperty pprop:notAutomatic ;
lv2:portProperty pprop:expensive ;
lv2:portProperty lv2:integer ;
lv2:portProperty lv2:enumeration ;
lv2:default 8192 ;
lv2:minimum 1024 ;
lv2:maximum 16384 ;
lv2:scalePoint [ rdfs:label "4 Ko"; rdf:value 1024 ] ;
lv2:scalePoint [ rdfs:label "8 Ko"; rdf:value 2048 ] ;
lv2:scalePoint [ rdfs:label "16 Ko"; rdf:value 4096 ] ;
lv2:scalePoint [ rdfs:label "32 Ko"; rdf:value 8192 ] ;
lv2:scalePoint [ rdfs:label "64 Ko"; rdf:value 16384 ] ;
].

View file

@ -39,6 +39,7 @@ typedef enum {
SFIZZ_OVERSAMPLING_X4 = 4,
SFIZZ_OVERSAMPLING_X8 = 8
} sfizz_oversampling_factor_t;
/**
* @brief Creates a sfizz synth. This object has to be freed by the caller
* using sfizz_free().
@ -268,9 +269,9 @@ sfizz_oversampling_factor_t sfizz_get_oversampling_factor(sfizz_synth_t* synth);
* @param synth The synth
* @param[in] preload_size The preload size
*
* @return The internal sample rate of the engine
* @return True if the oversampling factor was correct
*/
void sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_factor_t preload_size);
bool sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_factor_t oversampling);
/**
* @brief Set the global instrument volume.

View file

@ -144,10 +144,28 @@ sfizz_oversampling_factor_t sfizz_get_oversampling_factor(sfizz_synth_t* synth)
auto self = reinterpret_cast<sfz::Synth*>(synth);
return static_cast<sfizz_oversampling_factor_t>(self->getOversamplingFactor());
}
void sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_factor_t preload_size)
bool sfizz_set_oversampling_factor(sfizz_synth_t* synth, sfizz_oversampling_factor_t oversampling)
{
auto self = reinterpret_cast<sfz::Synth*>(synth);
self->setOversamplingFactor(static_cast<sfz::Oversampling>(preload_size));
using sfz::Oversampling;
switch(oversampling)
{
case SFIZZ_OVERSAMPLING_X1:
self->setOversamplingFactor(sfz::Oversampling::x1);
return true;
case SFIZZ_OVERSAMPLING_X2:
self->setOversamplingFactor(sfz::Oversampling::x2);
return true;
case SFIZZ_OVERSAMPLING_X4:
self->setOversamplingFactor(sfz::Oversampling::x4);
return true;
case SFIZZ_OVERSAMPLING_X8:
self->setOversamplingFactor(sfz::Oversampling::x8);
return true;
default:
return false;
}
}
void sfizz_set_volume(sfizz_synth_t* synth, float volume)

View file

@ -21,6 +21,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Config.h"
#include "sfizz.hpp"
#include "catch2/catch.hpp"
using namespace Catch::literals;
@ -89,3 +90,33 @@ TEST_CASE("[Synth] Check that the sample per block and sample rate are actually
REQUIRE( synth.getVoiceView(i)->getSampleRate() == 48000.0f );
}
}
TEST_CASE("[Synth] Check that we can change the size of the preload before and after loading")
{
sfz::Synth synth;
synth.setPreloadSize(512);
sfz::AudioBuffer<float> buffer { 2, blockSize };
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz");
synth.setPreloadSize(1024);
synth.noteOn(0, 1, 36, 24);
synth.noteOn(0, 1, 36, 89);
synth.renderBlock(buffer);
synth.setPreloadSize(2048);
synth.renderBlock(buffer);
}
TEST_CASE("[Synth] Check that we can change the oversampling factor before and after loading")
{
sfz::Synth synth;
synth.setOversamplingFactor(sfz::x2);
sfz::AudioBuffer<float> buffer { 2, blockSize };
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz");
synth.setOversamplingFactor(sfz::x4);
synth.noteOn(0, 1, 36, 24);
synth.noteOn(0, 1, 36, 89);
synth.renderBlock(buffer);
synth.setOversamplingFactor(sfz::x2);
synth.renderBlock(buffer);
}