From 39cf08ee4750e3ea47dc39cb6a0fc0b1408341ea Mon Sep 17 00:00:00 2001
From: Nils <>
Date: Tue, 7 Apr 2020 16:20:02 +0200
Subject: [PATCH] update template
---
template/calfbox/appmenu.c | 4 +-
template/calfbox/envelope.h | 2 +
template/calfbox/experiments/interactive.py | 2 +-
template/calfbox/experiments/meta.py | 2 +-
.../experiments/playPatternsAsMeasures.py | 2 +-
.../calfbox/experiments/printAllMidiEvents.py | 2 +-
.../printAllMidiEventsSpecificPort.py | 2 +-
.../calfbox/experiments/simplePlayback.py | 2 +-
.../calfbox/experiments/simplerPlayback.py | 2 +-
template/calfbox/experiments/testmetadata.py | 2 +-
template/calfbox/fluid.c | 8 -
template/calfbox/menu.c | 4 +-
template/calfbox/sampler.c | 13 +-
template/calfbox/sampler.h | 79 +-
template/calfbox/sampler_api_test.py | 81 +-
template/calfbox/sampler_channel.c | 66 +-
template/calfbox/sampler_impl.h | 13 +-
template/calfbox/sampler_layer.c | 1587 +++++++++--------
template/calfbox/sampler_layer.h | 181 +-
template/calfbox/sampler_nif.c | 31 +-
template/calfbox/sampler_prevoice.c | 9 +-
template/calfbox/sampler_prg.c | 13 +-
template/calfbox/sampler_rll.c | 11 +-
template/calfbox/sampler_voice.c | 300 ++--
template/calfbox/sfzloader.c | 2 +-
template/calfbox/tests.c | 66 +
template/documentation/index.adoc.template | 1 +
27 files changed, 1415 insertions(+), 1072 deletions(-)
diff --git a/template/calfbox/appmenu.c b/template/calfbox/appmenu.c
index aa2053a..7fb7cce 100644
--- a/template/calfbox/appmenu.c
+++ b/template/calfbox/appmenu.c
@@ -35,6 +35,8 @@ along with this program. If not, see .
#include "ui.h"
#include "wavebank.h"
+#if USE_NCURSES
+
#include
#include
#include
@@ -46,8 +48,6 @@ along with this program. If not, see .
#include
#include
-#if USE_NCURSES
-
int cmd_quit(struct cbox_menu_item_command *item, void *context)
{
return 1;
diff --git a/template/calfbox/envelope.h b/template/calfbox/envelope.h
index 58522ff..af26dae 100644
--- a/template/calfbox/envelope.h
+++ b/template/calfbox/envelope.h
@@ -117,6 +117,8 @@ static inline float cbox_envelope_get_value(struct cbox_envelope *env, const str
static inline void cbox_envelope_update_shape_after_modify(struct cbox_envelope *env, struct cbox_envelope_shape *shape, double sr)
{
+ if (env->cur_stage < 0)
+ return;
struct cbox_envstage *es = &shape->stages[env->cur_stage];
if (es->time != env->orig_time)
{
diff --git a/template/calfbox/experiments/interactive.py b/template/calfbox/experiments/interactive.py
index 88d3ed7..e2d23cc 100755
--- a/template/calfbox/experiments/interactive.py
+++ b/template/calfbox/experiments/interactive.py
@@ -4,7 +4,7 @@
This is a minimal calfbox python example. It is meant as a starting
point to find bugs and test performance.
-Copyright 2019, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/meta.py b/template/calfbox/experiments/meta.py
index cd98241..3651b53 100644
--- a/template/calfbox/experiments/meta.py
+++ b/template/calfbox/experiments/meta.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-Copyright 2017, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/playPatternsAsMeasures.py b/template/calfbox/experiments/playPatternsAsMeasures.py
index 6a2368a..8f3657f 100755
--- a/template/calfbox/experiments/playPatternsAsMeasures.py
+++ b/template/calfbox/experiments/playPatternsAsMeasures.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-Copyright 2017, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/printAllMidiEvents.py b/template/calfbox/experiments/printAllMidiEvents.py
index 408f795..394663d 100755
--- a/template/calfbox/experiments/printAllMidiEvents.py
+++ b/template/calfbox/experiments/printAllMidiEvents.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-Copyright 2017, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/printAllMidiEventsSpecificPort.py b/template/calfbox/experiments/printAllMidiEventsSpecificPort.py
index 8638c3d..0f9c218 100755
--- a/template/calfbox/experiments/printAllMidiEventsSpecificPort.py
+++ b/template/calfbox/experiments/printAllMidiEventsSpecificPort.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-Copyright 2017, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/simplePlayback.py b/template/calfbox/experiments/simplePlayback.py
index d36ef77..6312894 100755
--- a/template/calfbox/experiments/simplePlayback.py
+++ b/template/calfbox/experiments/simplePlayback.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-Copyright 2017, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/simplerPlayback.py b/template/calfbox/experiments/simplerPlayback.py
index 1bf8d14..43e8c7d 100755
--- a/template/calfbox/experiments/simplerPlayback.py
+++ b/template/calfbox/experiments/simplerPlayback.py
@@ -1,7 +1,7 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-Copyright 2017, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/experiments/testmetadata.py b/template/calfbox/experiments/testmetadata.py
index 5954144..7f50180 100755
--- a/template/calfbox/experiments/testmetadata.py
+++ b/template/calfbox/experiments/testmetadata.py
@@ -4,7 +4,7 @@
This is a minimal calfbox python example. It is meant as a starting
point to find bugs and test performance.
-Copyright 2018, Nils Hilbricht, Germany ( https://www.hilbricht.net )
+Copyright, Nils Hilbricht, Germany ( https://www.hilbricht.net )
This code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/template/calfbox/fluid.c b/template/calfbox/fluid.c
index 7ac37d8..20580e4 100644
--- a/template/calfbox/fluid.c
+++ b/template/calfbox/fluid.c
@@ -150,14 +150,6 @@ MODULE_CREATE_FUNCTION(fluidsynth)
m->synth = new_fluid_synth(m->settings);
fluid_synth_set_reverb_on(m->synth, cbox_config_get_int(cfg_section, "reverb", 1));
fluid_synth_set_chorus_on(m->synth, cbox_config_get_int(cfg_section, "chorus", 1));
-
- //Log levels in Fluidsynth are handled as settable functions
- fluid_set_log_function(FLUID_PANIC, NULL, NULL);
- fluid_set_log_function(FLUID_ERR, NULL, NULL);
- fluid_set_log_function(FLUID_WARN, NULL, NULL);
- fluid_set_log_function(FLUID_DBG, NULL, NULL);
- fluid_set_log_function(FLUID_INFO, NULL, NULL);
-
m->bank_name = NULL;
m->sfid = -1;
diff --git a/template/calfbox/menu.c b/template/calfbox/menu.c
index 90860f9..e80ca0c 100644
--- a/template/calfbox/menu.c
+++ b/template/calfbox/menu.c
@@ -20,14 +20,14 @@ along with this program. If not, see .
#include "menuitem.h"
#include "ui.h"
+#if USE_NCURSES
+
#include
#include
#include
#include
#include
-#if USE_NCURSES
-
struct cbox_menu
{
GPtrArray *items;
diff --git a/template/calfbox/sampler.c b/template/calfbox/sampler.c
index f17950f..b3bdf92 100644
--- a/template/calfbox/sampler.c
+++ b/template/calfbox/sampler.c
@@ -90,10 +90,11 @@ void sampler_create_voice_from_prevoice(struct sampler_module *m, struct sampler
{
if (!m->voices_free)
return;
- int exgroups[MAX_RELEASED_GROUPS], exgroupcount = 0;
- sampler_voice_start(m->voices_free, pv->channel, pv->layer_data, pv->note, pv->vel, exgroups, &exgroupcount);
- if (exgroupcount)
- sampler_channel_release_groups(pv->channel, pv->note, exgroups, exgroupcount);
+ struct sampler_released_groups exgroups;
+ sampler_released_groups_init(&exgroups);
+ sampler_voice_start(m->voices_free, pv->channel, pv->layer_data, pv->note, pv->vel, &exgroups);
+ if (exgroups.low_groups || exgroups.group_count)
+ sampler_channel_release_groups(pv->channel, pv->note, &exgroups);
}
void sampler_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs)
@@ -142,7 +143,9 @@ void sampler_process_block(struct cbox_module *module, cbox_sample_t **inputs, c
}
m->active_voices = vcount;
m->active_prevoices = pvcount;
- if (vcount - vrel > m->max_voices)
+ if(vcount - vrel > m->max_voices + 1)
+ sampler_steal_voice(m);
+ if(vcount - vrel > m->max_voices)
sampler_steal_voice(m);
m->serial_no++;
m->current_time += CBOX_BLOCK_SIZE;
diff --git a/template/calfbox/sampler.h b/template/calfbox/sampler.h
index 9181093..6dba6e9 100644
--- a/template/calfbox/sampler.h
+++ b/template/calfbox/sampler.h
@@ -189,7 +189,46 @@ struct sampler_module
struct cbox_sincos sincos[12800];
};
-#define MAX_RELEASED_GROUPS 4
+#define MAX_RELEASED_GROUPS 16
+
+struct sampler_released_groups
+{
+ // Groups 1-32 use a bitmask
+ uint32_t low_groups;
+ int group_count;
+ int groups[MAX_RELEASED_GROUPS];
+};
+
+static inline void sampler_released_groups_init(struct sampler_released_groups *groups)
+{
+ groups->low_groups = 0;
+ groups->group_count = 0;
+}
+
+static inline gboolean sampler_released_groups_check(struct sampler_released_groups *groups, int group)
+{
+ if (group <= 32)
+ return (groups->low_groups >> (group - 1)) & 1;
+ for (int j = 0; j < groups->group_count; j++)
+ {
+ if (groups->groups[j] == group)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static inline void sampler_released_groups_add(struct sampler_released_groups *groups, int group)
+{
+ if (group <= 32)
+ {
+ groups->low_groups |= (1 << (group - 1));
+ return;
+ }
+ if (groups->group_count >= MAX_RELEASED_GROUPS)
+ return;
+ if (!sampler_released_groups_check(groups, group))
+ groups->groups[groups->group_count++] = group;
+}
extern GQuark cbox_sampler_error_quark(void);
@@ -209,12 +248,13 @@ extern void sampler_channel_program_change(struct sampler_channel *c, int progra
extern void sampler_channel_stop_sustained(struct sampler_channel *c);
extern void sampler_channel_stop_sostenuto(struct sampler_channel *c);
extern void sampler_channel_capture_sostenuto(struct sampler_channel *c);
-extern void sampler_channel_release_groups(struct sampler_channel *c, int note, int exgroups[MAX_RELEASED_GROUPS], int exgroupcount);
+extern void sampler_channel_release_groups(struct sampler_channel *c, int note, struct sampler_released_groups *exgroups);
extern void sampler_channel_stop_all(struct sampler_channel *c);
extern void sampler_channel_process_cc(struct sampler_channel *c, int cc, int val);
extern void sampler_channel_reset_keyswitches(struct sampler_channel *c);
-extern void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, struct sampler_layer_data *l, int note, int vel, int *exgroups, int *pexgroupcount);
+extern void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, struct sampler_layer_data *l, int note, int vel, struct sampler_released_groups *exgroups);
+extern void sampler_voice_start_silent(struct sampler_layer_data *l, struct sampler_released_groups *exgroups);
extern void sampler_voice_release(struct sampler_voice *v, gboolean is_polyaft);
extern void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cbox_sample_t **outputs);
extern void sampler_voice_link(struct sampler_voice **pv, struct sampler_voice *v);
@@ -292,13 +332,13 @@ static inline float sampler_program_get_curve_value(struct sampler_program *prog
return val;
}
-static inline float sampler_channel_getcc_mod(struct sampler_channel *c, struct sampler_voice *v, int cc_no, struct sampler_modulation *sm)
+static inline float sampler_channel_getcc_mod(struct sampler_channel *c, struct sampler_voice *v, int cc_no, int curve_id, float step)
{
float val = (cc_no < 128) ? c->floatcc[cc_no] : sampler_channel_get_expensive_cc(c, v, NULL, cc_no);
- if (sm->step)
- val = floorf(0.9999f * val * (sm->step + 1)) / sm->step;
- if (sm->curve_id || c->program->interpolated_curves[0])
- val = sampler_program_get_curve_value(c->program, sm->curve_id, val);
+ if (step)
+ val = floorf(0.9999f * val * (step + 1)) / step;
+ if (curve_id || c->program->interpolated_curves[0])
+ val = sampler_program_get_curve_value(c->program, curve_id, val);
return val;
}
@@ -309,11 +349,14 @@ static inline int sampler_channel_getintcc(struct sampler_channel *c, struct sam
return (int)127 * (sampler_channel_get_expensive_cc(c, v, NULL, cc_no));
}
-static inline float sampler_channel_getcc_prevoice(struct sampler_channel *c, struct sampler_prevoice *pv, int cc_no)
+static inline float sampler_channel_getcc_prevoice(struct sampler_channel *c, struct sampler_prevoice *pv, int cc_no, int curve_id, float step)
{
- if (cc_no < 128)
- return c->floatcc[cc_no];
- return sampler_channel_get_expensive_cc(c, NULL, pv, cc_no);
+ float val = (cc_no < 128) ? c->floatcc[cc_no] : sampler_channel_get_expensive_cc(c, NULL, pv, cc_no);
+ if (step)
+ val = floorf(0.9999f * val * (step + 1)) / step;
+ if (curve_id || c->program->interpolated_curves[0])
+ val = sampler_program_get_curve_value(c->program, curve_id, val);
+ return val;
}
static inline float sampler_channel_get_poly_pressure(struct sampler_channel *c, uint8_t note)
@@ -322,6 +365,18 @@ static inline float sampler_channel_get_poly_pressure(struct sampler_channel *c,
return (c->poly_pressure_mask & (1 << (note >> 2))) ? c->poly_pressure[note] * (1.f / 127.f) : 0;;
}
+static inline gboolean sampler_cc_range_is_in(const struct sampler_cc_range *range, struct sampler_channel *c)
+{
+ while(range)
+ {
+ int ccval = sampler_channel_getintcc(c, NULL, range->key.cc_number);
+ if (ccval < range->value.locc || ccval > range->value.hicc)
+ return FALSE;
+ range = range->next;
+ }
+ return TRUE;
+}
+
#define FOREACH_VOICE(var, p) \
for (struct sampler_voice *p = (var), *p##_next = NULL; p && (p##_next = p->next, TRUE); p = p##_next)
#define FOREACH_PREVOICE(var, p) \
diff --git a/template/calfbox/sampler_api_test.py b/template/calfbox/sampler_api_test.py
index aa22bae..8beca0c 100644
--- a/template/calfbox/sampler_api_test.py
+++ b/template/calfbox/sampler_api_test.py
@@ -61,11 +61,13 @@ g1.set_param("volume", "-12")
g1.set_param("fileg_depthcc14", "-5400")
def check_exception(param, value, substr):
+ error = False
try:
g1.set_param(param, value)
- assert False, "Exception with substring %s expected when setting %s to %s, none caught" % (substr, param, value)
except Exception as e:
- assert substr in str(e), "Exception with substring %s expected when setting %s to %s, caught another one: %s" % (substr, param, value, str(e))
+ error = True
+ assert substr in str(e), "Exception with substring '%s' expected when setting %s to %s, caught another one: %s" % (substr, param, value, str(e))
+ assert error, "Exception with substring '%s' expected when setting %s to %s, none caught" % (substr, param, value)
check_exception("cutoff", "bla", "correct numeric value")
check_exception("key", "bla", "valid note name")
@@ -74,9 +76,11 @@ check_exception("lochan", "10.5", "correct integer value")
check_exception("offset", "bla", "correct unsigned integer value")
check_exception("offset", "10.5", "correct unsigned integer value")
check_exception("offset", "-1000", "correct unsigned integer value")
+
+# Make sure that multiple CC assignments work
g1.set_param("locc5", "100")
-check_exception("locc8", "110", "Conflicting controller")
-check_exception("hicc8", "110", "Conflicting controller")
+g1.set_param("locc8", "100")
+g1.set_param("hicc8", "110")
#g1.set_param("cutoff", "1000")
#g1.set_param("fillfo_freq", "4")
@@ -89,6 +93,16 @@ r1.set_param("transpose", "0")
r1.set_param("tune", "5")
r1.set_param("gain_cc17", "12")
+verify_region(g1, ["locc5=100", "locc8=100", "hicc8=110"], ['hicc5'])
+verify_region(r1, ["locc5=100", "locc8=100", "hicc8=110"], [], full=True)
+
+r1.set_param("hicc5", "120")
+r1.set_param("hicc8", "124")
+
+verify_region(g1, ["locc5=100", "locc8=100", "hicc8=110"], ['hicc5'])
+verify_region(g1, ["locc5=100", "hicc5=127", "locc8=100", "hicc8=110"], [], full=True)
+verify_region(r1, ["locc5=100", "hicc5=120", "locc8=100", "hicc8=124"], [], full=True)
+
r2 = g1.new_child()
r2.set_param("sample", "*sqr")
r2.set_param("transpose", "12")
@@ -103,12 +117,29 @@ verify_region(r2, ["sample=*sqr"], ["transpose"])
r2.unset_param("sample")
verify_region(r2, [], ["transpose", "sample"])
+g1.unset_param("cutoff")
+g1.unset_param("resonance")
+g1.unset_param("fil_type")
+g1.unset_param("fileg_sustain")
+g1.unset_param("fileg_decay")
+g1.unset_param("fileg_depth")
+g1.unset_param("fileg_release")
+g1.unset_param("ampeg_release")
+g1.unset_param("amp_veltrack")
+g1.unset_param("volume")
+g1.unset_param("fileg_depthcc14")
+g1.unset_param("locc5")
+g1.unset_param("locc8")
+g1.unset_param("hicc8")
+
params_to_test = [
'lokey', 'hikey', 'lovel', 'hivel', 'key',
'cutoff', 'pan', 'offset', 'tune', 'position', 'width',
'amp_random', 'fil_random', 'pitch_random', 'delay_random',
'pitch_veltrack', 'reloffset_veltrack', 'offset_veltrack',
'delay_cc5', 'delay_cc10', 'reloffset_cc5', 'reloffset_cc10', 'offset_cc5', 'offset_cc10',
+ 'delay_curvecc8', 'reloffset_curvecc5', 'offset_curvecc10',
+ 'delay_stepcc8', 'reloffset_stepcc5', 'offset_stepcc10',
'cutoff_cc1', "resonance_cc1", 'pitch_cc1', 'tonectl_cc1', 'gain_cc1', 'amplitude_cc1',
'cutoff_oncc2', "resonance_oncc2", 'pitch_oncc2', 'tonectl_oncc2', 'gain_oncc2', 'amplitude_oncc2',
'cutoff_curvecc1', 'resonance_curvecc5', 'pitch_curvecc10', 'amplitude_curvecc10',
@@ -141,6 +172,7 @@ params_to_test = [
'amp_velcurve_5', 'amp_velcurve_127',
'locc5', 'hicc5',
'on_locc8', 'on_hicc8',
+ 'lfo5_freq', 'lfo1_wave', 'lfo3_fade', 'lfo4_delay',
]
for i in range(len(params_to_test)):
param = params_to_test[0]
@@ -149,24 +181,57 @@ for i in range(len(params_to_test)):
value1, value2 = "100", "80"
if 'key' in param:
value1, value2 = "e1", "g1"
+ # Verify that a setting is reported back
+ r2.set_param(param, value1)
+ verify_region(r2, ["%s=%s" % (param, value1)], rest)
+
+ # Verify that setting the same value in parent doesn't change the local 'has' flag
+ g1.set_param(param, value1)
+ verify_region(r2, ["%s=%s" % (param, value1)], rest)
+
+ # Verify that setting a different local value doesn't get overridden by parent
+ r2.set_param(param, value2)
+ verify_region(r2, ["%s=%s" % (param, value2)], rest)
+ # Write the original value
r2.set_param(param, value1)
verify_region(r2, ["%s=%s" % (param, value1)], rest)
+
+ # Delete the parent value, confirm the deletion doesn't propagate to child
+ g1.unset_param(param)
+ verify_region(r2, ["%s=%s" % (param, value1)], rest)
+ # Set a different value in the parent, confirm it doesn't affect the child
g1.set_param(param, value2)
- verify_region(g1, ["%s=%s" % (param, value2)], [])
+ verify_region(g1, ["%s=%s" % (param, value2)], rest)
+ verify_region(r2, ["%s=%s" % (param, value1)], rest)
+ # Check that the newly created child inherits the setting from the parent
r3 = g1.new_child()
verify_region(r3, [], [param])
verify_region(r3, ["%s=%s" % (param, value2)], [], full=True)
r3.delete()
- verify_region(r2, ["%s=%s" % (param, value1)], rest)
+ # Verify that the original child still has the original value
verify_region(r2, ["%s=%s" % (param, value1)], [], full=True)
+ # Delete the child value, make sure it disappears but the inherited
+ # value is still reported in the full listing
r2.unset_param(param)
verify_region(r2, [], params_to_test)
-
verify_region(r2, ["%s=%s" % (param, value2)], [], full=True)
+ # Delete the setting in the parent, make sure the inherited value in the
+ # child disappears too
g1.unset_param(param)
verify_region(r2, [], ["%s=%s" % (param, value2)], full=True)
+
+ master.set_param(param, value1)
+ verify_region(master, ["%s=%s" % (param, value1)], [])
+ verify_region(g1, [], params_to_test)
+ verify_region(g1, ["%s=%s" % (param, value1)], [], full=True)
+ verify_region(r2, [], params_to_test)
+ verify_region(r2, ["%s=%s" % (param, value1)], [], full=True)
+ master.unset_param(param)
+ verify_region(master, [], params_to_test)
+ verify_region(g1, [], params_to_test)
+ verify_region(r2, [], params_to_test)
params_to_test = params_to_test[1:] + params_to_test[0:1]
@@ -187,7 +252,7 @@ for t in old_names:
v1, v2 = "10", "20"
else:
old, new, v1, v2 = t
- print ("Trying %s" % old)
+ print ("Trying alias: %s" % old)
r1.set_param(old, v1)
verify_region(r1, ["%s=%s" % (new, v1)], [old])
r1.set_param(old, v2)
diff --git a/template/calfbox/sampler_channel.c b/template/calfbox/sampler_channel.c
index e211a59..4af9396 100644
--- a/template/calfbox/sampler_channel.c
+++ b/template/calfbox/sampler_channel.c
@@ -126,16 +126,28 @@ void sampler_channel_process_cc(struct sampler_channel *c, int cc, int val)
// transition between in-range and out-of-range.
gboolean compatible_oncc_behaviour = TRUE;
- if (layer->runtime->on_cc.cc_number == cc &&
- (val >= layer->runtime->on_cc.locc && val <= layer->runtime->on_cc.hicc) &&
- (compatible_oncc_behaviour || !(old_value >= layer->runtime->on_cc.locc && old_value <= layer->runtime->on_cc.hicc)))
+ struct sampler_cc_range *on_cc = layer->runtime->on_cc;
+ gboolean trigger = FALSE;
+ while(on_cc)
+ {
+ if (on_cc->key.cc_number == cc &&
+ (val >= on_cc->value.locc && val <= on_cc->value.hicc) &&
+ (compatible_oncc_behaviour || !(old_value >= on_cc->value.locc && old_value <= on_cc->value.hicc)))
+ {
+ trigger = TRUE;
+ break;
+ }
+ on_cc = on_cc->next;
+ }
+ if(trigger)
{
struct sampler_voice *v = m->voices_free;
if (!v)
break;
- int exgroups[MAX_RELEASED_GROUPS], exgroupcount = 0;
- sampler_voice_start(v, c, layer->runtime, layer->runtime->pitch_keycenter, 127, exgroups, &exgroupcount);
- sampler_channel_release_groups(c, -1, exgroups, exgroupcount);
+ struct sampler_released_groups exgroups;
+ sampler_released_groups_init(&exgroups);
+ sampler_voice_start(v, c, layer->runtime, layer->runtime->pitch_keycenter, 127, &exgroups);
+ sampler_channel_release_groups(c, -1, &exgroups);
}
}
}
@@ -192,26 +204,19 @@ void sampler_channel_process_cc(struct sampler_channel *c, int cc, int val)
set_cc_int(c, cc, val);
}
-void sampler_channel_release_groups(struct sampler_channel *c, int note, int exgroups[MAX_RELEASED_GROUPS], int exgroupcount)
+void sampler_channel_release_groups(struct sampler_channel *c, int note, struct sampler_released_groups *exgroups)
{
- if (exgroupcount)
+ if (exgroups->group_count || exgroups->low_groups)
{
FOREACH_VOICE(c->voices_running, v)
{
- for (int j = 0; j < exgroupcount; j++)
+ if (v->off_by && v->note != note)
{
- if (v->off_by == exgroups[j] && v->note != note)
+ if (sampler_released_groups_check(exgroups, v->off_by))
{
+ v->released = 1;
if (v->layer->off_mode == som_fast)
- {
- v->released = 1;
cbox_envelope_go_to(&v->amp_env, 15);
- }
- else
- {
- v->released = 1;
- }
- break;
}
}
}
@@ -268,7 +273,7 @@ void sampler_channel_start_note(struct sampler_channel *c, int note, int vel, gb
}
struct sampler_layer_data *layers[MAX_SAMPLER_VOICES];
struct sampler_layer_data *delayed_layers[MAX_SAMPLER_PREVOICES];
- int lcount = 0, dlcount = 0;
+ int lcount = 0, dlcount = 0, slcount = 0;
struct sampler_voice *free_voice = m->voices_free;
struct sampler_prevoice *free_prevoice = m->prevoices_free;
int fvcount = 0, fpcount = 0;
@@ -286,16 +291,22 @@ void sampler_channel_start_note(struct sampler_channel *c, int note, int vel, gb
fpcount++;
}
assert(layer->runtime);
- if (layer->runtime->use_prevoice)
+ if (layer->runtime->computed.eff_use_prevoice)
delayed_layers[dlcount++] = layer->runtime;
else
+ {
layers[lcount++] = layer->runtime;
+ if (layer->runtime->computed.eff_is_silent)
+ slcount++;
+ }
layer = sampler_rll_iterator_next(&iter);
}
- int exgroups[MAX_RELEASED_GROUPS], exgroupcount = 0;
+ struct sampler_released_groups exgroups;
+ sampler_released_groups_init(&exgroups);
// If running out of polyphony, do not start the note if all the regions cannot be played
- if (lcount <= fvcount && dlcount <= fpcount)
+ // (silent notes don't count into polyphony)
+ if (lcount <= slcount + fvcount && dlcount <= fpcount)
{
// this might perhaps be optimized by mapping the group identifiers to flat-array indexes
// but I'm not going to do that until someone gives me an SFZ worth doing that work ;)
@@ -303,8 +314,13 @@ void sampler_channel_start_note(struct sampler_channel *c, int note, int vel, gb
for (int i = 0; i < lcount; ++i)
{
struct sampler_layer_data *l = layers[i];
- int velc = (!is_first && l->vel_mode == svm_previous) ? c->first_note_vel : vel;
- sampler_voice_start(m->voices_free, c, l, note, velc, exgroups, &exgroupcount);
+ if (l->computed.eff_is_silent)
+ sampler_voice_start_silent(l, &exgroups);
+ else
+ {
+ int velc = (!is_first && l->vel_mode == svm_previous) ? c->first_note_vel : vel;
+ sampler_voice_start(m->voices_free, c, l, note, velc, &exgroups);
+ }
}
for (int i = 0; i < dlcount; ++i)
{
@@ -317,7 +333,7 @@ void sampler_channel_start_note(struct sampler_channel *c, int note, int vel, gb
c->previous_note = note;
if (is_first)
c->first_note_vel = vel;
- sampler_channel_release_groups(c, note, exgroups, exgroupcount);
+ sampler_channel_release_groups(c, note, &exgroups);
}
void sampler_channel_start_release_triggered_voices(struct sampler_channel *c, int note)
diff --git a/template/calfbox/sampler_impl.h b/template/calfbox/sampler_impl.h
index aeab6d3..4e28748 100644
--- a/template/calfbox/sampler_impl.h
+++ b/template/calfbox/sampler_impl.h
@@ -30,10 +30,15 @@ static inline int sfz_note_from_string(const char *note)
int pos;
int nn = tolower(note[0]);
int nv;
- if (nn >= '0' && nn <= '9')
- return atoi(note);
+ if ((nn >= '0' && nn <= '9') || nn == '-')
+ {
+ int nv = atoi(note);
+ if (nv >= -1 && nv <= 127)
+ return nv;
+ return -2;
+ }
if (nn < 'a' || nn > 'g')
- return -1;
+ return -2;
nv = semis[nn - 'a'];
for (pos = 1; tolower(note[pos]) == 'b' || note[pos] == '#'; pos++)
@@ -44,7 +49,7 @@ static inline int sfz_note_from_string(const char *note)
return nv + 12 * (1 + atoi(note + pos));
}
- return -1;
+ return -2;
}
static inline gboolean atof_C_verify(const char *key, const char *value, double *result, GError **error)
diff --git a/template/calfbox/sampler_layer.c b/template/calfbox/sampler_layer.c
index 5f6f8d7..4637d3d 100644
--- a/template/calfbox/sampler_layer.c
+++ b/template/calfbox/sampler_layer.c
@@ -35,282 +35,221 @@ along with this program. If not, see .
#include
#include
-void sampler_layer_data_dump_modulations(struct sampler_layer_data *l)
+static inline gboolean sampler_modulation_key_equal(const struct sampler_modulation_key *k1, const struct sampler_modulation_key *k2)
{
- GSList *p = l->modulations;
- while(p)
- {
- struct sampler_modulation *sm = p->data;
- printf("%d x %d -> %d : %f : %d\n", sm->src, sm->src2, sm->dest, sm->amount, sm->curve_id);
- p = g_slist_next(p);
- }
+ return (k1->src == k2->src && k1->src2 == k2->src2 && k1->dest == k2->dest);
}
-static struct sampler_modulation *sampler_layer_data_find_modulation(struct sampler_layer_data *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, GSList **link_ptr)
+static inline void sampler_modulation_dump_one(const struct sampler_modulation *sm)
{
- GSList *p = l->modulations;
- while(p)
- {
- struct sampler_modulation *sm = p->data;
- if (sm->src == src && sm->src2 == src2 && sm->dest == dest)
- {
- if (link_ptr)
- *link_ptr = p;
- return sm;
- }
- p = g_slist_next(p);
- }
- return NULL;
+ printf("%d x %d -> %d : %f : %d\n", sm->key.src, sm->key.src2, sm->key.dest, sm->value.amount, sm->value.curve_id);
}
-static struct sampler_modulation *sampler_layer_data_add_modulation(struct sampler_layer_data *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest)
-{
- struct sampler_modulation *sm = sampler_layer_data_find_modulation(l, src, src2, dest, NULL);
- if (sm)
- return sm;
- sm = g_malloc0(sizeof(struct sampler_modulation));
- sm->src = src;
- sm->src2 = src2;
- sm->dest = dest;
- sm->amount = 0;
- sm->curve_id = 0;
- sm->smooth = 0;
- sm->step = 0;
- sm->has_amount = FALSE;
- sm->has_curve = FALSE;
- sm->has_smooth = FALSE;
- sm->has_step = FALSE;
- l->modulations = g_slist_prepend(l->modulations, sm);
- return sm;
-}
+//////////////////////////////////////////////////////////////////////////////////////////////////
-static inline gboolean is_null_modulation(const struct sampler_modulation *sm)
+static inline gboolean sampler_noteinitfunc_key_equal(const struct sampler_noteinitfunc_key *k1, const struct sampler_noteinitfunc_key *k2)
{
- return !sm->amount && !sm->curve_id && !sm->smooth && !sm->step &&
- !sm->has_amount && !sm->has_curve && !sm->has_smooth && !sm->has_step;
+ return (k1->notefunc_voice == k2->notefunc_voice && k1->variant == k2->variant);
}
-static inline gboolean is_null_values_modulation(const struct sampler_modulation *sm)
+static inline void sampler_noteinitfunc_dump_one(const struct sampler_noteinitfunc *nif)
{
- return !sm->amount && !sm->curve_id && !sm->smooth && !sm->step;
+ printf("%p(%d) = %f\n", nif->key.notefunc_voice, nif->key.variant, nif->value.value);
}
-void sampler_layer_propagate_modulation(struct sampler_layer *l, const struct sampler_modulation *srcm, gboolean starting)
-{
- if (!starting)
- {
- struct sampler_modulation *dstm = sampler_layer_data_add_modulation(&l->data, srcm->src, srcm->src2, srcm->dest);
- if (!dstm->has_amount)
- dstm->amount = srcm->amount;
- if (!dstm->has_curve)
- dstm->curve_id = srcm->curve_id;
- if (!dstm->has_smooth)
- dstm->smooth = srcm->smooth;
- if (!dstm->has_step)
- dstm->step = srcm->step;
- }
-
- if (l->child_layers) {
- GHashTableIter iter;
- g_hash_table_iter_init(&iter, l->child_layers);
- gpointer key, value;
- while(g_hash_table_iter_next(&iter, &key, &value))
- {
- struct sampler_layer *child = value;
- sampler_layer_propagate_modulation(child, srcm, FALSE);
- }
- }
-}
+//////////////////////////////////////////////////////////////////////////////////////////////////
-void sampler_layer_set_modulation_amount(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, float amount)
+static inline gboolean sampler_cc_range_key_equal(const struct sampler_cc_range_key *k1, const struct sampler_cc_range_key *k2)
{
- struct sampler_modulation *dstm = sampler_layer_data_add_modulation(&l->data, src, src2, dest);
- dstm->has_amount = TRUE;
- dstm->amount = amount;
- sampler_layer_propagate_modulation(l, dstm, TRUE);
+ return k1->cc_number == k2->cc_number;
}
-void sampler_layer_set_modulation_curve(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, int curve)
+static inline void sampler_cc_range_dump_one(const struct sampler_cc_range *ccrange)
{
- struct sampler_modulation *dstm = sampler_layer_data_add_modulation(&l->data, src, src2, dest);
- dstm->has_curve = TRUE;
- dstm->curve_id = curve;
- sampler_layer_propagate_modulation(l, dstm, TRUE);
+ printf("CC%d in [%c%d, %c%d]\n", (int)ccrange->key.cc_number, ccrange->value.has_locc ? '!' : '.', (int)ccrange->value.locc, ccrange->value.has_hicc ? '!' : '.', (int)ccrange->value.hicc);
}
-void sampler_layer_set_modulation_smooth(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, float amount)
-{
- struct sampler_modulation *dstm = sampler_layer_data_add_modulation(&l->data, src, src2, dest);
- dstm->has_smooth = TRUE;
- dstm->smooth = amount;
- sampler_layer_propagate_modulation(l, dstm, TRUE);
-}
+//////////////////////////////////////////////////////////////////////////////////////////////////
-void sampler_layer_set_modulation_step(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, float amount)
+static inline gboolean sampler_flex_lfo_key_equal(const struct sampler_flex_lfo_key *k1, const struct sampler_flex_lfo_key *k2)
{
- struct sampler_modulation *dstm = sampler_layer_data_add_modulation(&l->data, src, src2, dest);
- dstm->has_step = TRUE;
- dstm->step = amount;
- sampler_layer_propagate_modulation(l, dstm, TRUE);
+ return k1->id == k2->id;
}
-static gboolean sampler_layer_data_unset_modulation(struct sampler_layer_data *l, struct sampler_layer_data *parent_data, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, gboolean remove_local, gboolean unset_amount, gboolean unset_curve, gboolean unset_smooth, gboolean unset_step)
+static inline void sampler_flex_lfo_dump_one(const struct sampler_flex_lfo *lfo)
{
- GSList *link = NULL;
- struct sampler_modulation *sm = sampler_layer_data_find_modulation(l, src, src2, dest, &link);
- if (!sm)
- return FALSE;
- struct sampler_modulation *psm = remove_local && parent_data != NULL ? sampler_layer_data_find_modulation(parent_data, src, src2, dest, NULL) : NULL;
- if (unset_amount && sm->has_amount == remove_local)
- {
- sm->amount = psm ? psm->amount : 0;
- if (remove_local)
- sm->has_amount = FALSE;
- }
- if (unset_curve && sm->has_curve == remove_local)
- {
- sm->curve_id = psm ? psm->curve_id : 0;
- if (remove_local)
- sm->has_curve = FALSE;
- }
- if (unset_smooth && sm->has_smooth == remove_local)
- {
- sm->smooth = psm ? psm->smooth : 0;
- if (remove_local)
- sm->has_smooth = FALSE;
- }
- if (unset_step && sm->has_step == remove_local)
- {
- sm->step = psm ? psm->step : 0;
- if (remove_local)
- sm->has_step = FALSE;
- }
- // Delete if it's all default values and it's not overriding anything
- if (is_null_modulation(sm))
- l->modulations = g_slist_delete_link(l->modulations, link);
-
- return TRUE;
+ printf("LFO%d (freq %s %f, delay %s %f, fade %s %f, wave %s %d)\n",
+ (int)lfo->key.id,
+ lfo->value.has_freq ? "(local)" : "(inherited)", lfo->value.freq,
+ lfo->value.has_delay ? "(local)" : "(inherited)", lfo->value.delay,
+ lfo->value.has_fade ? "(local)" : "(inherited)", lfo->value.fade,
+ lfo->value.has_wave ? "(local)" : "(inherited)", lfo->value.wave
+ );
}
-static void sampler_layer_unset_modulation(struct sampler_layer*l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, gboolean remove_local, gboolean unset_amount, gboolean unset_curve, gboolean unset_smooth, gboolean unset_step)
-{
- if (!sampler_layer_data_unset_modulation(&l->data, l->parent ? &l->parent->data : NULL, src, src2, dest, remove_local, unset_amount, unset_curve, unset_smooth, unset_step))
- return;
+//////////////////////////////////////////////////////////////////////////////////////////////////
- if (l->child_layers) {
- // Also recursively remove propagated copies from child layers, if any
- GHashTableIter iter;
- g_hash_table_iter_init(&iter, l->child_layers);
- gpointer key, value;
- while(g_hash_table_iter_next(&iter, &key, &value))
- {
- struct sampler_layer *child = value;
- sampler_layer_unset_modulation(child, src, src2, dest, FALSE, unset_amount, unset_curve, unset_smooth, unset_step);
- }
+#define SAMPLER_COLL_FUNC_DUMP(sname) \
+ void sname##_dump(const struct sname *p) \
+ { \
+ for(; p; p = p->next) \
+ sname##_dump_one(p); \
}
-}
-void sampler_layer_unset_modulation_amount(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, gboolean remove_local)
-{
- sampler_layer_unset_modulation(l, src, src2, dest, remove_local, TRUE, FALSE, FALSE, FALSE);
-}
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_DUMP)
+
+#define SAMPLER_COLL_FUNC_FIND(sname) \
+ static struct sname *sname##_find(struct sname *list, const struct sname##_key *key) \
+ { \
+ for(struct sname *p = list; p; p = p->next) \
+ { \
+ struct sname##_key *dkey = &p->key; \
+ if (sname##_key_equal(dkey, key)) \
+ return p; \
+ } \
+ return NULL; \
+ } \
+ static struct sname *sname##_find2(struct sname **list_ptr, const struct sname##_key *key, struct sname ***link_ptr) \
+ { \
+ for(struct sname **pp = list_ptr; *pp; pp = &(*pp)->next) \
+ { \
+ struct sname##_key *dkey = &(*pp)->key; \
+ if (sname##_key_equal(dkey, key)) \
+ { \
+ if (link_ptr) \
+ *link_ptr = pp; \
+ return *pp; \
+ } \
+ } \
+ return NULL; \
+ }
-void sampler_layer_unset_modulation_curve(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, gboolean remove_local)
-{
- sampler_layer_unset_modulation(l, src, src2, dest, remove_local, FALSE, TRUE, FALSE, FALSE);
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_FIND)
+
+#define SAMPLER_COLL_FIELD_INIT(name, has_name, type, init_value) \
+ d->value.name = init_value; \
+ d->value.has_name = FALSE;
+
+#define SAMPLER_COLL_FUNC_ADD(sname) \
+static struct sname *sname##_add(struct sname **list_ptr, const struct sname##_key *key) \
+{ \
+ struct sname *d = sname##_find(*list_ptr, key); \
+ if (d) \
+ return d; \
+ d = g_malloc0(sizeof(struct sname)); \
+ d->key = *key; \
+ SAMPLER_COLL_FIELD_LIST_##sname(SAMPLER_COLL_FIELD_INIT)\
+ d->next = *list_ptr; \
+ *list_ptr = d; \
+ return d; \
}
-void sampler_layer_unset_modulation_smooth(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, gboolean remove_local)
-{
- sampler_layer_unset_modulation(l, src, src2, dest, remove_local, FALSE, FALSE, TRUE, FALSE);
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_ADD)
+
+#define SAMPLER_COLL_FUNC_DESTROY(sname) \
+static void sname##s_destroy(struct sname *list_ptr) \
+{ \
+ while(list_ptr) \
+ { \
+ struct sname *p = list_ptr->next; \
+ g_free(list_ptr); \
+ list_ptr = p; \
+ } \
}
-void sampler_layer_unset_modulation_step(struct sampler_layer *l, enum sampler_modsrc src, enum sampler_modsrc src2, enum sampler_moddest dest, gboolean remove_local)
-{
- sampler_layer_unset_modulation(l, src, src2, dest, remove_local, FALSE, FALSE, FALSE, TRUE);
-}
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_DESTROY)
-void sampler_layer_data_add_nif(struct sampler_layer_data *l, SamplerNoteInitFunc notefunc_voice, SamplerNoteInitFunc2 notefunc_prevoice, int variant, float param, gboolean propagating_defaults)
-{
- assert(!(notefunc_voice && notefunc_prevoice));
- GSList **list = notefunc_voice ? &l->voice_nifs : &l->prevoice_nifs;
- GSList *p = *list;
- while(p)
- {
- struct sampler_noteinitfunc *nif = p->data;
- if (nif->notefunc_voice == notefunc_voice && nif->notefunc_prevoice == notefunc_prevoice && nif->variant == variant)
- {
- // do not overwrite locally set value with defaults
- if (propagating_defaults && nif->has_value)
- return;
- nif->param = param;
- nif->has_value = !propagating_defaults;
- return;
- }
- p = g_slist_next(p);
- }
- struct sampler_noteinitfunc *nif = malloc(sizeof(struct sampler_noteinitfunc));
- nif->notefunc_voice = notefunc_voice;
- nif->notefunc_prevoice = notefunc_prevoice;
- nif->variant = variant;
- nif->param = param;
- nif->has_value = !propagating_defaults;
- *list = g_slist_prepend(*list, nif);
-}
+#define SAMPLER_COLL_FIELD_ISNULL(name, has_name, type, init_value) \
+ if (d->name != init_value || d->has_name) \
+ return FALSE;
-void sampler_layer_data_remove_nif(struct sampler_layer_data *l, struct sampler_layer_data *parent_data, SamplerNoteInitFunc notefunc_voice, SamplerNoteInitFunc2 notefunc_prevoice, int variant, gboolean remove_propagated)
-{
- assert(!(notefunc_voice && notefunc_prevoice));
- GSList **list = notefunc_voice ? &l->voice_nifs : &l->prevoice_nifs;
- GSList *p = *list;
- while(p)
- {
- struct sampler_noteinitfunc *nif = p->data;
- if (nif->notefunc_voice == notefunc_voice && nif->notefunc_prevoice == notefunc_prevoice && nif->variant == variant && nif->has_value == !remove_propagated)
- {
- if (!remove_propagated && parent_data) {
- // Try to copy over from parent
- GSList *q = notefunc_voice ? parent_data->voice_nifs : parent_data->prevoice_nifs;
- while(q)
- {
- struct sampler_noteinitfunc *pnif = q->data;
- if (pnif->notefunc_voice == notefunc_voice && pnif->notefunc_prevoice == notefunc_prevoice && pnif->variant == variant && pnif->has_value)
- {
- memcpy(nif, pnif, sizeof(*pnif));
- nif->has_value = FALSE;
- return;
- }
- q = g_slist_next(q);
- }
- }
- *list = g_slist_delete_link(*list, p);
- return;
- }
- p = g_slist_next(p);
+#define SAMPLER_COLL_FUNC_ISNULL(sname) \
+ static inline gboolean sname##_is_null(const struct sname##_value *d) \
+ { \
+ SAMPLER_COLL_FIELD_LIST_##sname(SAMPLER_COLL_FIELD_ISNULL) \
+ return TRUE; \
}
-}
-void sampler_layer_add_nif(struct sampler_layer *l, SamplerNoteInitFunc notefunc_voice, SamplerNoteInitFunc2 notefunc_prevoice, int variant, float param)
-{
- sampler_layer_data_add_nif(&l->data, notefunc_voice, notefunc_prevoice, variant, param, FALSE);
-}
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_ISNULL)
+
+// sampler_modulation_set_amount etc.
+#define SAMPLER_COLL_FIELD_SETTER(name, has_name, type, init_value, sname) \
+ struct sname *sname##_set_##name##_by_offset(struct sampler_layer *l, uint32_t offset, const struct sname##_key *key, gboolean set_local_value, type value) \
+ { \
+ void *vl = &l->data; \
+ struct sname **list_ptr = vl + offset; \
+ struct sname *dstm = sname##_add(list_ptr, key); \
+ if (!set_local_value && dstm->value.has_name) \
+ return dstm; \
+ dstm->value.has_name = set_local_value; \
+ dstm->value.name = value; \
+ return dstm; \
+ }
-void sampler_layer_remove_nif(struct sampler_layer *l, SamplerNoteInitFunc notefunc_voice, SamplerNoteInitFunc2 notefunc_prevoice, int variant, gboolean remove_propagated)
-{
- sampler_layer_data_remove_nif(&l->data, !remove_propagated && l->parent ? &l->parent->data : NULL, notefunc_voice, notefunc_prevoice, variant, remove_propagated);
+#define SAMPLER_COLL_FUNC_SETTERS(sname) \
+ SAMPLER_COLL_FIELD_LIST_##sname(SAMPLER_COLL_FIELD_SETTER, sname)
+
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_SETTERS)
+
+#define SAMPLER_COLL_FIELD_UNSET(name, has_name, type, init_value, sname) \
+ if ((unset_mask & (1 << sname##_value_field_##name)) && d->value.has_name == remove_local) \
+ { \
+ d->value.name = parent ? parent->value.name : init_value; \
+ d->value.has_name = FALSE; \
+ } \
+
+#define SAMPLER_COLL_FIELD_KEY_ENUM_VALUE(name, has_name, type, init_value, sname) \
+ sname##_value_field_##name,
+
+#define SAMPLER_COLL_FUNC_UNSET(sname) \
+ enum { \
+ SAMPLER_COLL_FIELD_LIST_##sname(SAMPLER_COLL_FIELD_KEY_ENUM_VALUE, sname) \
+ }; \
+ static gboolean sname##_unset_by_offset(struct sampler_layer *l, uint32_t offset, const struct sname##_key *key, gboolean remove_local, uint32_t unset_mask) \
+ { \
+ void *vl = &l->data, *vp = l->parent ? &l->parent->data : NULL; \
+ struct sname **list_ptr = vl + offset; \
+ struct sname **parent_list_ptr = vp ? vp + offset : NULL; \
+ struct sname **link_ptr = NULL; \
+ struct sname *d = sname##_find2(list_ptr, key, &link_ptr); \
+ if (!d) \
+ return FALSE; \
+ struct sname *parent = remove_local && *parent_list_ptr != NULL ? sname##_find(*parent_list_ptr, key) : NULL; \
+ SAMPLER_COLL_FIELD_LIST_##sname(SAMPLER_COLL_FIELD_UNSET, sname) \
+ /* Delete if it's all default values and it's not overriding anything */ \
+ if (sname##_is_null(&d->value)) {\
+ *link_ptr = d->next; \
+ g_free(d); \
+ } \
+ return TRUE; \
+ }
- if (l->child_layers) {
- // Also recursively remove propagated copies from child layers, if any
- GHashTableIter iter;
- g_hash_table_iter_init(&iter, l->child_layers);
- gpointer key, value;
- while(g_hash_table_iter_next(&iter, &key, &value))
- {
- struct sampler_layer *child = value;
- sampler_layer_remove_nif(child, notefunc_voice, notefunc_prevoice, variant, TRUE);
- }
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_UNSET)
+
+#define SAMPLER_COLL_FIELD_ZEROHASATTR(name, has_name, type, init_value) \
+ dstv->value.has_name = FALSE;
+#define SAMPLER_COLL_FUNC_CLONE(sname) \
+ static struct sname *sname##_clone(struct sname *src, gboolean copy_hasattr) \
+ { \
+ struct sname *dst = NULL, **last = &dst;\
+ for(const struct sname *srcv = src; srcv; srcv = srcv->next) \
+ { \
+ struct sname *dstv = g_malloc(sizeof(struct sname)); \
+ memcpy(dstv, srcv, sizeof(struct sname)); \
+ if (!copy_hasattr) \
+ { \
+ SAMPLER_COLL_FIELD_LIST_##sname(SAMPLER_COLL_FIELD_ZEROHASATTR) \
+ } \
+ *last = dstv; \
+ dstv->next = NULL; \
+ last = &dstv->next; \
+ } \
+ return dst; \
}
-}
+
+SAMPLER_COLL_LIST(SAMPLER_COLL_FUNC_CLONE)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
enum sampler_layer_param_type
{
@@ -326,22 +265,15 @@ enum sampler_layer_param_type
slpt_midicurve,
slpt_ccrange,
// modulation matrix
- slpt_depthcc, // src * CC -> dest
- slpt_amountcc, // CC -> dest
- slpt_amount, // src -> dest
- slpt_modulation, // src1 * src2 -> dest
+ slpt_mod_amount, // src (or CC) * src2 (or CC) -> dest
+ slpt_mod_curveid,
+ slpt_mod_smooth,
+ slpt_mod_step,
slpt_generic_modulation,
- slpt_curvecc,
- slpt_smoothcc,
- slpt_stepcc,
- slpt_depth_curvecc,
- slpt_depth_smoothcc,
- slpt_depth_stepcc,
// note init functions
slpt_voice_nif,
slpt_prevoice_nif,
- slpt_voice_cc_nif,
- slpt_prevoice_cc_nif,
+ slpt_flex_lfo,
slpt_reserved,
};
@@ -351,103 +283,113 @@ struct sampler_layer_param_entry
size_t offset;
enum sampler_layer_param_type type;
double def_value;
- uint32_t extra_int;
+ uint64_t extra_int;
void *extra_ptr;
void (*set_has_value)(struct sampler_layer_data *, gboolean);
+ gboolean (*get_has_value)(struct sampler_layer_data *);
};
+#define MODSRC_CC 0xFFF
+#define smsrc_CC MODSRC_CC
+
+#define ENCODE_MOD(src, src2, dst) ((((uint32_t)(src) & 0xFFFU) | (((uint32_t)(src2) & 0xFFFU) << 12U) | ((uint32_t)(dst) << 24U)))
+
#define PROC_SUBSTRUCT_FIELD_SETHASFUNC(name, index, def_value, parent) \
- static void sampler_layer_data_##parent##_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##parent.name = value; }
+ static void sampler_layer_data_##parent##_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##parent.name = value; } \
+ static gboolean sampler_layer_data_##parent##_get_has_##name(struct sampler_layer_data *l) { return l->has_##parent.name; }
#define PROC_FIELD_SETHASFUNC(type, name, default_value) \
- static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##name = value; }
+ static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##name = value; } \
+ static gboolean sampler_layer_data_get_has_##name(struct sampler_layer_data *l) { return l->has_##name; }
#define PROC_FIELD_SETHASFUNC_string(name) \
- static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##name = value; }
+ static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##name = value; } \
+ static gboolean sampler_layer_data_get_has_##name(struct sampler_layer_data *l) { return l->has_##name; }
#define PROC_FIELD_SETHASFUNC_dBamp(type, name, default_value) \
- static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##name = value; }
+ PROC_FIELD_SETHASFUNC(type, name, default_value)
#define PROC_FIELD_SETHASFUNC_enum(type, name, default_value) \
- static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, gboolean value) { l->has_##name = value; }
+ PROC_FIELD_SETHASFUNC(type, name, default_value)
#define PROC_FIELD_SETHASFUNC_dahdsr(field, name, default_value) \
DAHDSR_FIELDS(PROC_SUBSTRUCT_FIELD_SETHASFUNC, field)
#define PROC_FIELD_SETHASFUNC_lfo(field, name, default_value) \
LFO_FIELDS(PROC_SUBSTRUCT_FIELD_SETHASFUNC, field)
#define PROC_FIELD_SETHASFUNC_eq(field, name, default_value) \
EQ_FIELDS(PROC_SUBSTRUCT_FIELD_SETHASFUNC, field)
-#define PROC_FIELD_SETHASFUNC_ccrange(name, parname) \
- static void sampler_layer_data_set_has_##name##_lo(struct sampler_layer_data *l, gboolean value) { l->name.has_locc = value; } \
- static void sampler_layer_data_set_has_##name##_hi(struct sampler_layer_data *l, gboolean value) { l->name.has_hicc = value; }
+#define PROC_FIELD_SETHASFUNC_ccrange(name, parname)
#define PROC_FIELD_SETHASFUNC_midicurve(name) \
- static void sampler_layer_data_set_has_##name(struct sampler_layer_data *l, uint32_t index, gboolean value) { l->name.has_values[index] = value; }
+ static gboolean sampler_layer_data_set_get_has_##name(struct sampler_layer_data *l, uint32_t index, int value) \
+ { \
+ if (value != -1) \
+ l->name.has_values[index] = value; \
+ return l->name.has_values[index]; \
+ }
SAMPLER_FIXED_FIELDS(PROC_FIELD_SETHASFUNC)
+#define LOFS(field) offsetof(struct sampler_layer_data, field)
+
+#define FIELD_MOD(name, param, src, src2, dest) \
+ { name, LOFS(modulations), slpt_mod_##param, 0, ENCODE_MOD(smsrc_##src, smsrc_##src2, smdest_##dest), NULL, NULL, NULL },
#define FIELD_AMOUNT(name, src, dest) \
- { name, -1, slpt_amount, 0, (smsrc_##src << 16) | smdest_##dest, NULL, NULL },
+ FIELD_MOD(name, amount, src, none, dest)
#define FIELD_AMOUNT_CC(name, dest) \
- { name "cc#", -1, slpt_amountcc, 0, smdest_##dest, NULL, NULL }, \
- { name "_oncc#", -1, slpt_amountcc, 0, smdest_##dest, NULL, NULL }, \
- { name "_curvecc#", -1, slpt_curvecc, 0, smdest_##dest, NULL, NULL }, \
- { name "_smoothcc#", -1, slpt_smoothcc, 0, smdest_##dest, NULL, NULL }, \
- { name "_stepcc#", -1, slpt_stepcc, 0, smdest_##dest, NULL, NULL },
+ FIELD_ALIAS(name "cc#", name "_oncc#") \
+ FIELD_MOD(name "_oncc#", amount, CC, none, dest) \
+ FIELD_MOD(name "_curvecc#", curveid, CC, none, dest) \
+ FIELD_MOD(name "_smoothcc#", smooth, CC, none, dest) \
+ FIELD_MOD(name "_stepcc#", step, CC, none, dest)
#define FIELD_AMOUNT_CC_(name, dest) \
- { name "_cc#", -1, slpt_amountcc, 0, smdest_##dest, NULL, NULL }, \
- { name "_oncc#", -1, slpt_amountcc, 0, smdest_##dest, NULL, NULL }, \
- { name "_curvecc#", -1, slpt_curvecc, 0, smdest_##dest, NULL, NULL }, \
- { name "_smoothcc#", -1, slpt_smoothcc, 0, smdest_##dest, NULL, NULL }, \
- { name "_stepcc#", -1, slpt_stepcc, 0, smdest_##dest, NULL, NULL },
+ FIELD_ALIAS(name "_cc#", name "_oncc#") \
+ FIELD_MOD(name "_oncc#", amount, CC, none, dest) \
+ FIELD_MOD(name "_curvecc#", curveid, CC, none, dest) \
+ FIELD_MOD(name "_smoothcc#", smooth, CC, none, dest) \
+ FIELD_MOD(name "_stepcc#", step, CC, none, dest)
#define FIELD_VOICE_NIF(name, nif, variant) \
- { name, -1, slpt_voice_nif, 0, variant, nif, NULL },
+ { name, LOFS(voice_nifs), slpt_voice_nif, 0, variant, nif, NULL, NULL },
#define FIELD_PREVOICE_NIF(name, nif, variant) \
- { name, -1, slpt_prevoice_nif, 0, variant, nif, NULL },
-#define FIELD_VOICE_CC_NIF(name, nif, variant) \
- { name, -1, slpt_voice_cc_nif, 0, variant, nif, NULL },
-#define FIELD_PREVOICE_CC_NIF(name, nif, variant) \
- { name, -1, slpt_prevoice_cc_nif, 0, variant, nif, NULL },
+ { name, LOFS(prevoice_nifs), slpt_prevoice_nif, 0, variant, nif, NULL, NULL },
#define FIELD_ALIAS(alias, name) \
- { alias, -1, slpt_alias, 0, 0, name, NULL },
+ { alias, -1, slpt_alias, 0, 0, name, NULL, NULL },
-#define LOFS(field) offsetof(struct sampler_layer_data, field)
#define PROC_SUBSTRUCT_FIELD_DESCRIPTOR(name, index, def_value, parent, parent_name, parent_index, parent_struct) \
- { #parent_name "_" #name, offsetof(struct sampler_layer_data, parent) + offsetof(struct parent_struct, name), slpt_float, def_value, parent_index * 100 + index, NULL, sampler_layer_data_##parent##_set_has_##name }, \
+ { #parent_name "_" #name, offsetof(struct sampler_layer_data, parent) + offsetof(struct parent_struct, name), slpt_float, def_value, parent_index * 100 + index, NULL, sampler_layer_data_##parent##_set_has_##name, sampler_layer_data_##parent##_get_has_##name }, \
#define PROC_SUBSTRUCT_FIELD_DESCRIPTOR_DAHDSR(name, index, def_value, parent, parent_name, parent_index, parent_struct) \
- { #parent_name "_" #name, offsetof(struct sampler_layer_data, parent) + offsetof(struct parent_struct, name), slpt_float, def_value, parent_index * 100 + index, NULL, sampler_layer_data_##parent##_set_has_##name }, \
+ { #parent_name "_" #name, offsetof(struct sampler_layer_data, parent) + offsetof(struct parent_struct, name), slpt_float, def_value, parent_index * 100 + index, NULL, sampler_layer_data_##parent##_set_has_##name, sampler_layer_data_##parent##_get_has_##name }, \
FIELD_VOICE_NIF(#parent_name "_vel2" #name, sampler_nif_vel2env, (parent_index << 4) + snif_env_##name) \
FIELD_AMOUNT_CC(#parent_name "_" #name, ampeg_stage + (parent_index << 4) + snif_env_##name) \
#define PROC_FIELD_DESCRIPTOR(type, name, default_value) \
- { #name, LOFS(name), slpt_##type, default_value, 0, NULL, sampler_layer_data_set_has_##name },
+ { #name, LOFS(name), slpt_##type, default_value, 0, NULL, sampler_layer_data_set_has_##name, sampler_layer_data_get_has_##name },
#define PROC_FIELD_DESCRIPTOR_dBamp(type, name, default_value) \
- { #name, LOFS(name), slpt_##type, default_value, 0, NULL, sampler_layer_data_set_has_##name },
+ { #name, LOFS(name), slpt_##type, default_value, 0, NULL, sampler_layer_data_set_has_##name, sampler_layer_data_get_has_##name },
#define PROC_FIELD_DESCRIPTOR_string(name) \
- { #name, LOFS(name), slpt_string, 0, LOFS(name##_changed), NULL, sampler_layer_data_set_has_##name },
+ { #name, LOFS(name), slpt_string, 0, LOFS(name##_changed), NULL, sampler_layer_data_set_has_##name, sampler_layer_data_get_has_##name },
#define PROC_FIELD_DESCRIPTOR_enum(enumtype, name, default_value) \
- { #name, LOFS(name), slpt_enum, (double)(enum enumtype)default_value, 0, enumtype##_from_string, sampler_layer_data_set_has_##name },
+ { #name, LOFS(name), slpt_enum, (double)(enum enumtype)default_value, 0, enumtype##_from_string, sampler_layer_data_set_has_##name, sampler_layer_data_get_has_##name },
#define PROC_FIELD_DESCRIPTOR_midicurve(name) \
- { #name "_#", LOFS(name), slpt_midicurve, 0, 0, (void *)sampler_layer_data_set_has_##name, NULL },
-
-#define FIELD_DEPTHCC_SET(name, dest, attrib) \
- { #name attrib "cc#", -1, slpt_depthcc, 0, (smsrc_##name << 16) | (dest), NULL, NULL }, \
- { #name attrib "_oncc#", -1, slpt_depthcc, 0, (smsrc_##name << 16) | (dest), NULL, NULL }, \
- { #name attrib "_curvecc#", -1, slpt_depth_curvecc, 0, (smsrc_##name << 16) | (dest), NULL, NULL }, \
- { #name attrib "_smoothcc#", -1, slpt_depth_smoothcc, 0, (smsrc_##name << 16) | (dest), NULL, NULL }, \
- { #name attrib "_stepcc#", -1, slpt_depth_stepcc, 0, (smsrc_##name << 16) | (dest), NULL, NULL },
+ { #name "_#", LOFS(name), slpt_midicurve, 0, 0, (void *)sampler_layer_data_set_get_has_##name, NULL, NULL },
+
+#define FIELD_DEPTH_SET(name, dest, attrib) \
+ FIELD_ALIAS(#name attrib "cc#", #name attrib "_oncc#") \
+ FIELD_MOD(#name attrib "_oncc#", amount, name, CC, dest) \
+ FIELD_MOD(#name attrib "_curvecc#", curveid, name, CC, dest) \
+ FIELD_MOD(#name attrib "_smoothcc#", smooth, name, CC, dest) \
+ FIELD_MOD(#name attrib "_stepcc#", step, name, CC, dest) \
+ FIELD_MOD(#name attrib "polyaft", amount, name, polyaft, dest) \
+ FIELD_MOD(#name attrib "chanaft", amount, name, chanaft, dest) \
+ FIELD_MOD(#name attrib, amount, name, none, dest) \
#define PROC_FIELD_DESCRIPTOR_dahdsr(field, name, index) \
DAHDSR_FIELDS(PROC_SUBSTRUCT_FIELD_DESCRIPTOR_DAHDSR, field, name, index, cbox_dahdsr) \
- FIELD_AMOUNT(#name "_depth", name, from_##name) \
- FIELD_DEPTHCC_SET(name, smdest_from_##name, "_depth") \
- { #name "_vel2depth", -1, slpt_modulation, 0, (smsrc_##name << 8) | (smsrc_vel << 20) | (smdest_from_##name), NULL, NULL },
+ FIELD_DEPTH_SET(name, from_##name, "_depth") \
+ FIELD_MOD(#name "_vel2depth", amount, name, vel, from_##name)
#define PROC_FIELD_DESCRIPTOR_lfo(field, name, index) \
LFO_FIELDS(PROC_SUBSTRUCT_FIELD_DESCRIPTOR, field, name, index, sampler_lfo_params) \
- FIELD_AMOUNT(#name "_depth", name, from_##name) \
FIELD_AMOUNT(#name "_freqpolyaft", polyaft, name##_freq) \
FIELD_AMOUNT(#name "_freqchanaft", chanaft, name##_freq) \
FIELD_AMOUNT_CC(#name "_freq", name##_freq) \
- { #name "_depthpolyaft", -1, slpt_modulation, 0, (smsrc_##name << 8) | (smsrc_polyaft << 20) | (smdest_from_##name), NULL, NULL }, \
- { #name "_depthchanaft", -1, slpt_modulation, 0, (smsrc_##name << 8) | (smsrc_chanaft << 20) | (smdest_from_##name), NULL, NULL }, \
- FIELD_DEPTHCC_SET(name, smdest_from_##name, "_depth")
+ FIELD_DEPTH_SET(name, from_##name, "_depth")
#define PROC_FIELD_DESCRIPTOR_eq(field, name, index) \
EQ_FIELDS(PROC_SUBSTRUCT_FIELD_DESCRIPTOR, field, name, index, sampler_eq_params) \
@@ -456,8 +398,16 @@ SAMPLER_FIXED_FIELDS(PROC_FIELD_SETHASFUNC)
FIELD_AMOUNT_CC(#name "_gain", name##_gain)
#define PROC_FIELD_DESCRIPTOR_ccrange(field, parname) \
- { #parname "locc#", LOFS(field), slpt_ccrange, 0, 0, NULL, sampler_layer_data_set_has_##field##_lo }, \
- { #parname "hicc#", LOFS(field), slpt_ccrange, 127, 1, NULL, sampler_layer_data_set_has_##field##_hi },
+ { #parname "locc#", LOFS(field), slpt_ccrange, 0, 0, NULL, NULL, NULL }, \
+ { #parname "hicc#", LOFS(field), slpt_ccrange, 127, 1, NULL, NULL, NULL },
+
+#define FIELD_FLEX_LFO(name, field) \
+ { name, LOFS(flex_lfos), slpt_flex_lfo, 0, sampler_flex_lfo_value_field_##field, NULL, NULL, NULL },
+
+#define NIF_VARIANT_CC 0x01000000
+#define NIF_VARIANT_CURVECC 0x02000000
+#define NIF_VARIANT_STEPCC 0x03000000
+#define NIF_VARIANT_MASK 0xFF000000
struct sampler_layer_param_entry sampler_layer_params[] = {
SAMPLER_FIXED_FIELDS(PROC_FIELD_DESCRIPTOR)
@@ -467,13 +417,10 @@ struct sampler_layer_param_entry sampler_layer_params[] = {
FIELD_AMOUNT("cutoff_polyaft", polyaft, cutoff)
FIELD_AMOUNT("resonance_polyaft", polyaft, resonance)
- FIELD_AMOUNT("fileg_depth2", fileg, cutoff2)
- FIELD_DEPTHCC_SET(fileg, smdest_cutoff2, "_depth2")
- { "fileg_vel2depth2", -1, slpt_modulation, 0, (smsrc_fileg << 8) | (smsrc_vel << 20) | (smdest_cutoff2), NULL, NULL },
- FIELD_AMOUNT("fillfo_depth2", fillfo, cutoff2)
- { "fillfo_depthpolyaft", -1, slpt_modulation, 0, (smsrc_fillfo << 8) | (smsrc_polyaft << 20) | (smdest_cutoff2), NULL, NULL }, \
- { "fillfo_depthchanaft", -1, slpt_modulation, 0, (smsrc_fillfo << 8) | (smsrc_chanaft << 20) | (smdest_cutoff2), NULL, NULL }, \
- FIELD_DEPTHCC_SET(fillfo, smdest_cutoff2, "_depth2")
+ FIELD_DEPTH_SET(fileg, cutoff2, "_depth2")
+ FIELD_MOD("fileg_vel2depth2", amount, fileg, vel, cutoff2)
+
+ FIELD_DEPTH_SET(fillfo, cutoff2, "_depth2")
FIELD_AMOUNT("cutoff2_chanaft", chanaft, cutoff2)
FIELD_AMOUNT("resonance2_chanaft", chanaft, resonance2)
@@ -499,9 +446,20 @@ struct sampler_layer_param_entry sampler_layer_params[] = {
FIELD_VOICE_NIF("reloffset_veltrack", sampler_nif_vel2reloffset, 0)
FIELD_PREVOICE_NIF("delay_random", sampler_nif_addrandomdelay, 0)
FIELD_PREVOICE_NIF("sync_beats", sampler_nif_syncbeats, 0)
- FIELD_PREVOICE_CC_NIF("delay_cc#", sampler_nif_cc2delay, 0)
- FIELD_VOICE_CC_NIF("reloffset_cc#", sampler_nif_cc2reloffset, 0)
- FIELD_VOICE_CC_NIF("offset_cc#", sampler_nif_cc2offset, 0)
+ FIELD_PREVOICE_NIF("delay_cc#", sampler_nif_cc2delay, NIF_VARIANT_CC)
+ FIELD_PREVOICE_NIF("delay_curvecc#", sampler_nif_cc2delay, NIF_VARIANT_CURVECC)
+ FIELD_PREVOICE_NIF("delay_stepcc#", sampler_nif_cc2delay, NIF_VARIANT_STEPCC)
+ FIELD_VOICE_NIF("reloffset_cc#", sampler_nif_cc2reloffset, NIF_VARIANT_CC)
+ FIELD_VOICE_NIF("reloffset_curvecc#", sampler_nif_cc2reloffset, NIF_VARIANT_CURVECC)
+ FIELD_VOICE_NIF("reloffset_stepcc#", sampler_nif_cc2reloffset, NIF_VARIANT_STEPCC)
+ FIELD_VOICE_NIF("offset_cc#", sampler_nif_cc2offset, NIF_VARIANT_CC)
+ FIELD_VOICE_NIF("offset_curvecc#", sampler_nif_cc2offset, NIF_VARIANT_CURVECC)
+ FIELD_VOICE_NIF("offset_stepcc#", sampler_nif_cc2offset, NIF_VARIANT_STEPCC)
+
+ FIELD_FLEX_LFO("lfo#_freq", freq)
+ FIELD_FLEX_LFO("lfo#_delay", delay)
+ FIELD_FLEX_LFO("lfo#_fade", fade)
+ FIELD_FLEX_LFO("lfo#_wave", wave)
FIELD_ALIAS("hilev", "hivel")
FIELD_ALIAS("lolev", "lovel")
@@ -515,7 +473,7 @@ struct sampler_layer_param_entry sampler_layer_params[] = {
FIELD_ALIAS("reloffset_oncc#", "reloffset_cc#")
FIELD_ALIAS("delay_oncc#", "delay_cc#")
- { "genericmod_#_#_#_#", -1, slpt_generic_modulation, 0, 0, NULL, NULL },
+ { "genericmod_#_#_#_#", -1, slpt_generic_modulation, 0, 0, NULL, NULL, NULL },
};
#define NPARAMS (sizeof(sampler_layer_params) / sizeof(sampler_layer_params[0]))
@@ -541,17 +499,233 @@ void sampler_layer_prepare_params(void)
assert(found);
e->extra_ptr = found;
}
+ if (i)
+ {
+ struct sampler_layer_param_entry *prev_e = &sampler_layer_params[i - 1];
+ if (!strcmp(e->name, prev_e->name))
+ {
+ printf("Duplicate parameter %s\n", e->name);
+ assert(FALSE);
+ }
+ }
}
}
-#define VERIFY_FLOAT_VALUE do { if (!atof_C_verify(e->name, value, &fvalue, error)) return FALSE; } while(0)
+// This only works for setting. Unsetting is slightly different.
+static gboolean override_logic(gboolean is_equal, gboolean has_value, gboolean set_local_value)
+{
+ if (!set_local_value && has_value) // Do not override locally set values
+ return FALSE;
+ // Override if a value or a inherited value is replaced with a local setting.
+ return (!is_equal) || (set_local_value != has_value);
+}
+
+static inline void mod_key_decode(uint64_t extra_int, const uint32_t *args, struct sampler_modulation_key *mod_key)
+{
+ uint32_t modsrc = (extra_int & 0xFFF);
+ uint32_t modsrc2 = ((extra_int >> 12) & 0xFFF);
+ if (modsrc == MODSRC_CC)
+ modsrc = args[0];
+ if (modsrc2 == MODSRC_CC)
+ modsrc2 = args[0];
+ mod_key->src = modsrc;
+ mod_key->src2 = modsrc2;
+ mod_key->dest = ((extra_int >> 24) & 0xFF);
+}
-gboolean sampler_layer_param_entry_set_from_string(const struct sampler_layer_param_entry *e, struct sampler_layer *l, const char *value, const uint32_t *args, GError **error)
+static inline void nif_key_decode(uint64_t extra_int, void *extra_ptr, const uint32_t *args, struct sampler_noteinitfunc_key *nif_key)
+{
+ uint32_t variant = extra_int &~ NIF_VARIANT_MASK;
+ nif_key->notefunc_voice = extra_ptr;
+ if (extra_int & NIF_VARIANT_MASK)
+ {
+ int cc = args[0] & 255;
+ variant = cc + (variant << 8);
+ }
+ nif_key->variant = variant;
+}
+
+static inline void flex_lfo_key_decode(const uint32_t *args, struct sampler_flex_lfo_key *flex_lfo_key)
+{
+ flex_lfo_key->id = args[0];
+}
+
+#define OVERRIDE_LOGIC(type) override_logic(!memcmp(p, data_ptr, sizeof(type)), e->get_has_value(&l->data), set_local_value)
+
+#define CAST_FLOAT_VALUE fvalue = *(double *)data_ptr
+
+gboolean sampler_layer_param_entry_set_from_ptr(const struct sampler_layer_param_entry *e, struct sampler_layer *l, gboolean set_local_value, const void *data_ptr, const uint32_t *args, GError **error)
{
void *p = ((uint8_t *)&l->data) + e->offset;
- uint32_t cc;
- double fvalue;
+ uint32_t cc = 0;
+ double fvalue = 0;
+ struct sampler_modulation_key mod_key = {0, 0, 0};
+ struct sampler_noteinitfunc_key nif_key = {{NULL}, 0};
+ struct sampler_flex_lfo_key flex_lfo_key = {0};
+ switch(e->type)
+ {
+ case slpt_midi_note_t:
+ if (!OVERRIDE_LOGIC(midi_note_t))
+ return TRUE;
+ memcpy(p, data_ptr, sizeof(midi_note_t));
+ break;
+ case slpt_int:
+ if (!OVERRIDE_LOGIC(int))
+ return TRUE;
+ memcpy(p, data_ptr, sizeof(int));
+ break;
+ case slpt_enum:
+ case slpt_uint32_t:
+ if (!OVERRIDE_LOGIC(uint32_t))
+ return TRUE;
+ memcpy(p, data_ptr, sizeof(uint32_t));
+ break;
+ case slpt_string:
+ {
+ char **pc = p;
+ gboolean str_differs = (!*pc != !data_ptr) || strcmp(*pc, data_ptr);
+ if (!override_logic(!str_differs, e->get_has_value(&l->data), set_local_value))
+ return TRUE;
+ if (str_differs)
+ {
+ free(*pc);
+ *pc = g_strdup(data_ptr);
+ gboolean *changed_ptr = (gboolean *)(((uint8_t *)&l->data) + e->extra_int);
+ *changed_ptr = 1;
+ }
+ }
+ break;
+ case slpt_float:
+ case slpt_dBamp:
+ fvalue = *(double *)data_ptr;
+ if (!override_logic((float)fvalue == *(float *)p, e->get_has_value(&l->data), set_local_value))
+ return TRUE;
+ *(float *)p = fvalue;
+ break;
+ case slpt_midicurve:
+ CAST_FLOAT_VALUE;
+ if (args[0] >= 0 && args[0] <= 127)
+ {
+ gboolean (*setgethasfunc)(struct sampler_layer_data *, uint32_t, int) = e->extra_ptr;
+ float *dst = &((struct sampler_midi_curve *)p)->values[args[0]];
+ if (!override_logic(*dst == fvalue, setgethasfunc(&l->data, args[0], -1), set_local_value))
+ return TRUE;
+ *dst = fvalue;
+ setgethasfunc(&l->data, args[0], set_local_value);
+ }
+ else
+ {
+ g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Curve entry index (%u) is out of range for %s", (unsigned)args[0], e->name);
+ return FALSE;
+ }
+ break;
+ case slpt_ccrange:
+ {
+ int number = *(int *)data_ptr;
+ cc = args[0];
+ switch(e->extra_int) {
+ case 0:
+ sampler_cc_range_set_locc_by_offset(l, e->offset, &(struct sampler_cc_range_key){cc}, set_local_value, number);
+ break;
+ case 1:
+ sampler_cc_range_set_hicc_by_offset(l, e->offset, &(struct sampler_cc_range_key){cc}, set_local_value, number);
+ break;
+ default: assert(0);
+ }
+ break;
+ }
+ case slpt_mod_amount:
+ CAST_FLOAT_VALUE;
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_set_amount_by_offset(l, e->offset, &mod_key, set_local_value, fvalue);
+ break;
+ case slpt_mod_curveid:
+ CAST_FLOAT_VALUE;
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_set_curve_id_by_offset(l, e->offset, &mod_key, set_local_value, (int)fvalue);
+ break;
+ case slpt_mod_smooth:
+ CAST_FLOAT_VALUE;
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_set_smooth_by_offset(l, e->offset, &mod_key, set_local_value, fvalue);
+ break;
+ case slpt_mod_step:
+ CAST_FLOAT_VALUE;
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_set_step_by_offset(l, e->offset, &mod_key, set_local_value, fvalue);
+ break;
+ case slpt_generic_modulation:
+ CAST_FLOAT_VALUE;
+ sampler_modulation_set_amount_by_offset(l, e->offset, &(struct sampler_modulation_key){args[0], args[1], args[2]}, set_local_value, fvalue);
+ sampler_modulation_set_curve_id_by_offset(l, e->offset, &(struct sampler_modulation_key){args[0], args[1], args[2]}, set_local_value, (int)args[3]);
+ break;
+ case slpt_voice_nif:
+ case slpt_prevoice_nif:
+ CAST_FLOAT_VALUE;
+ nif_key_decode(e->extra_int, e->extra_ptr, args, &nif_key);
+ switch(e->extra_int & NIF_VARIANT_MASK)
+ {
+ case 0:
+ case NIF_VARIANT_CC:
+ sampler_noteinitfunc_set_value_by_offset(l, e->offset, &nif_key, set_local_value, fvalue);
+ break;
+ case NIF_VARIANT_CURVECC:
+ sampler_noteinitfunc_set_curve_id_by_offset(l, e->offset, &nif_key, set_local_value, (int)fvalue);
+ break;
+ case NIF_VARIANT_STEPCC:
+ sampler_noteinitfunc_set_step_by_offset(l, e->offset, &nif_key, set_local_value, fvalue);
+ break;
+ }
+ break;
+ case slpt_flex_lfo:
+ CAST_FLOAT_VALUE;
+ flex_lfo_key_decode(args, &flex_lfo_key);
+ switch(e->extra_int)
+ {
+ case sampler_flex_lfo_value_field_freq:
+ sampler_flex_lfo_set_freq_by_offset(l, e->offset, &flex_lfo_key, set_local_value, fvalue);
+ break;
+ case sampler_flex_lfo_value_field_delay:
+ sampler_flex_lfo_set_delay_by_offset(l, e->offset, &flex_lfo_key, set_local_value, fvalue);
+ break;
+ case sampler_flex_lfo_value_field_fade:
+ sampler_flex_lfo_set_fade_by_offset(l, e->offset, &flex_lfo_key, set_local_value, fvalue);
+ break;
+ case sampler_flex_lfo_value_field_wave:
+ sampler_flex_lfo_set_wave_by_offset(l, e->offset, &flex_lfo_key, set_local_value, (int)fvalue);
+ break;
+ }
+ break;
+ case slpt_reserved:
+ case slpt_invalid:
+ case slpt_alias:
+ printf("Unhandled parameter type of parameter %s\n", e->name);
+ assert(0);
+ return FALSE;
+ }
+ if (e->set_has_value)
+ e->set_has_value(&l->data, set_local_value);
+ if (l->child_layers) {
+ /* Propagate to children */
+ GHashTableIter iter;
+ g_hash_table_iter_init(&iter, l->child_layers);
+ gpointer key, value;
+ while(g_hash_table_iter_next(&iter, &key, &value))
+ {
+ struct sampler_layer *child = value;
+ if (!sampler_layer_param_entry_set_from_ptr(e, child, FALSE, data_ptr, args, error))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+#define VERIFY_FLOAT_VALUE do { if (!atof_C_verify(e->name, value, &fvalue, error)) return FALSE; } while(0)
+
+gboolean sampler_layer_param_entry_set_from_string(const struct sampler_layer_param_entry *e, struct sampler_layer *l, gboolean set_local_value, const char *value, const uint32_t *args, GError **error)
+{
+ double fvalue;
switch(e->type)
{
case slpt_midi_note_t:
@@ -562,9 +736,7 @@ gboolean sampler_layer_param_entry_set_from_string(const struct sampler_layer_pa
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "'%s' is not a valid note name for %s", value, e->name);
return FALSE;
}
- *((midi_note_t *)p) = note;
- e->set_has_value(&l->data, 1);
- return TRUE;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, ¬e, args, error);
}
case slpt_int:
{
@@ -576,21 +748,19 @@ gboolean sampler_layer_param_entry_set_from_string(const struct sampler_layer_pa
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "'%s' is not a correct integer value for %s", value, e->name);
return FALSE;
}
- *(int *)p = number;
- e->set_has_value(&l->data, 1);
- return TRUE;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, &number, args, error);
}
case slpt_enum:
{
gboolean (*func)(const char *, uint32_t *value);
func = e->extra_ptr;
- if (!func(value, (uint32_t *)p))
+ uint32_t data = 0;
+ if (!func(value, &data))
{
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "'%s' is not a correct value for %s", value, e->name);
return FALSE;
}
- e->set_has_value(&l->data, 1);
- return TRUE;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, &data, args, error);
}
case slpt_uint32_t:
{
@@ -602,45 +772,12 @@ gboolean sampler_layer_param_entry_set_from_string(const struct sampler_layer_pa
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "'%s' is not a correct unsigned integer value for %s", value, e->name);
return FALSE;
}
- *(uint32_t *)p = number;
- e->set_has_value(&l->data, 1);
- return TRUE;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, &number, args, error);
}
- case slpt_float:
- case slpt_dBamp:
- VERIFY_FLOAT_VALUE;
- *((float *)p) = fvalue;
- e->set_has_value(&l->data, 1);
- return TRUE;
case slpt_string:
- {
- char **pc = p;
- if (*pc && !strcmp(*pc, value))
- return TRUE; // no change
- free(*pc);
- *pc = g_strdup(value);
- e->set_has_value(&l->data, 1);
- gboolean *changed_ptr = (gboolean *)(((uint8_t *)&l->data) + e->extra_int);
- *changed_ptr = 1;
- }
- return TRUE;
- case slpt_midicurve:
- VERIFY_FLOAT_VALUE;
- if (args[0] >= 0 && args[0] <= 127)
- {
- ((struct sampler_midi_curve *)p)->values[args[0]] = fvalue;
- void (*sethasfunc)(struct sampler_layer_data *, uint32_t, gboolean value) = e->extra_ptr;
- sethasfunc(&l->data, args[0], 1);
- }
- else
- {
- g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Curve entry index (%u) is out of range for %s", (unsigned)args[0], e->name);
- return FALSE;
- }
- return TRUE;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, value, args, error);
case slpt_ccrange:
{
- cc = args[0];
char *endptr;
errno = 0;
int number = strtol(value, &endptr, 10);
@@ -649,113 +786,31 @@ gboolean sampler_layer_param_entry_set_from_string(const struct sampler_layer_pa
g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "'%s' is not a correct control change value for %s", value, e->name);
return FALSE;
}
- struct sampler_cc_range *range = p;
- if (!range->has_locc && !range->has_hicc)
- range->cc_number = cc;
- else if (range->cc_number != cc)
- {
- //g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Conflicting controller number for %s (%d vs previously used %d)", e->name, cc, (int)range->cc_number);
- //return FALSE;
- }
- switch(e->extra_int) {
- case 0: range->locc = number; range->is_active = 1; break;
- case 1: range->hicc = number; range->is_active = 1; break;
- default: assert(0);
- }
- e->set_has_value(&l->data, 1);
- return TRUE;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, &number, args, error);
}
- case slpt_depthcc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_amount(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_depth_curvecc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_curve(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), (int)fvalue);
- return TRUE;
- case slpt_depth_smoothcc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_smooth(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_depth_stepcc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_step(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_amountcc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_amount(l, cc, smsrc_none, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_curvecc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_curve(l, cc, smsrc_none, (e->extra_int & 0xFFFF), (int)fvalue);
- return TRUE;
- case slpt_smoothcc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_smooth(l, cc, smsrc_none, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_stepcc:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_set_modulation_step(l, cc, smsrc_none, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_amount:
- VERIFY_FLOAT_VALUE;
- sampler_layer_set_modulation_amount(l, (e->extra_int >> 16), smsrc_none, (e->extra_int & 0xFFFF), fvalue);
- return TRUE;
- case slpt_modulation:
- VERIFY_FLOAT_VALUE;
- sampler_layer_set_modulation_amount(l, (e->extra_int >> 8) & 0xFFF, (e->extra_int >> 20), (e->extra_int & 0xFF), fvalue);
- return TRUE;
- case slpt_generic_modulation:
- VERIFY_FLOAT_VALUE;
- sampler_layer_set_modulation_amount(l, args[0], args[1], args[2], fvalue);
- sampler_layer_set_modulation_curve(l, args[0], args[1], args[2], args[3]);
- return TRUE;
- case slpt_voice_nif:
- VERIFY_FLOAT_VALUE;
- sampler_layer_add_nif(l, e->extra_ptr, NULL, e->extra_int, fvalue);
- return TRUE;
- case slpt_prevoice_nif:
- VERIFY_FLOAT_VALUE;
- sampler_layer_add_nif(l, NULL, e->extra_ptr, e->extra_int, fvalue);
- return TRUE;
- case slpt_voice_cc_nif:
- VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_add_nif(l, e->extra_ptr, NULL, cc + (e->extra_int << 8), fvalue);
- return TRUE;
- case slpt_prevoice_cc_nif:
+ case slpt_float:
+ case slpt_dBamp:
+ default:
VERIFY_FLOAT_VALUE;
- cc = args[0];
- sampler_layer_add_nif(l, NULL, e->extra_ptr, cc + (e->extra_int << 8), fvalue);
- return TRUE;
- case slpt_reserved:
- case slpt_invalid:
- case slpt_alias:
- break;
+ return sampler_layer_param_entry_set_from_ptr(e, l, set_local_value, &fvalue, args, error);
}
- printf("Unhandled parameter type of parameter %s\n", e->name);
- assert(0);
- return FALSE;
}
#define COPY_NUM_FROM_PARENT(case_value, type) \
case case_value: \
+ if (!unset_local_value && e->get_has_value(&l->data)) \
+ return TRUE; \
*(type *)p = pp ? *(type *)pp : (type)e->def_value; \
e->set_has_value(&l->data, 0); \
- return TRUE;
-gboolean sampler_layer_param_entry_unset(const struct sampler_layer_param_entry *e, struct sampler_layer *l, const uint32_t *args, GError **error)
+ break;
+gboolean sampler_layer_param_entry_unset(const struct sampler_layer_param_entry *e, struct sampler_layer *l, gboolean unset_local_value, const uint32_t *args, GError **error)
{
void *p = ((uint8_t *)&l->data) + e->offset;
void *pp = l->parent ? ((uint8_t *)&l->parent->data) + e->offset : NULL;
uint32_t cc;
+ struct sampler_modulation_key mod_key = {0, 0, 0};
+ struct sampler_noteinitfunc_key nif_key = {{NULL}, 0};
+ struct sampler_flex_lfo_key flex_lfo_key = {0};
switch(e->type)
{
@@ -767,6 +822,8 @@ gboolean sampler_layer_param_entry_unset(const struct sampler_layer_param_entry
COPY_NUM_FROM_PARENT(slpt_dBamp, float)
case slpt_string:
{
+ if (!unset_local_value && e->get_has_value(&l->data))
+ return TRUE;
char **pc = p;
free(*pc);
*pc = pp ? g_strdup(*(const char **)pp) : NULL;
@@ -779,10 +836,12 @@ gboolean sampler_layer_param_entry_unset(const struct sampler_layer_param_entry
if (args[0] >= 0 && args[0] <= 127)
{
struct sampler_midi_curve *curve = p, *parent_curve = pp;
- curve->values[args[0]] = parent_curve ? parent_curve->values[args[0]] : -1;
- void (*sethasfunc)(struct sampler_layer_data *, uint32_t, gboolean value) = e->extra_ptr;
- sethasfunc(&l->data, args[0], 0);
- return TRUE;
+ gboolean (*setgethasfunc)(struct sampler_layer_data *, uint32_t, gboolean value) = e->extra_ptr;
+ if (setgethasfunc(&l->data, args[0], -1) && !unset_local_value)
+ return TRUE;
+ curve->values[args[0]] = parent_curve ? parent_curve->values[args[0]] : SAMPLER_CURVE_GAP;
+ setgethasfunc(&l->data, args[0], 0);
+ break;
}
else
{
@@ -790,86 +849,94 @@ gboolean sampler_layer_param_entry_unset(const struct sampler_layer_param_entry
return FALSE;
}
case slpt_ccrange:
- {
- struct sampler_cc_range *range = p, *prange = pp;
cc = args[0];
- if ((range->has_locc || range->has_hicc) && range->cc_number != cc)
+ if (!sampler_cc_range_unset_by_offset(l, e->offset, &(struct sampler_cc_range_key){cc}, unset_local_value, 1 << e->extra_int))
{
- g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Conflicting controller number for %s (%d vs previously used %d)", e->name, cc, (int)range->cc_number);
+ if (!unset_local_value)
+ return TRUE;
+ g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Controller number %d not used for %s", cc, e->name);
return FALSE;
}
-
- switch(e->extra_int) {
- case 0: range->locc = prange ? prange->locc : (uint8_t)e->def_value; range->is_active = range->has_hicc || (prange ? prange->is_active : 0); break;
- case 1: range->hicc = prange ? prange->hicc : (uint8_t)e->def_value; range->is_active = range->has_locc || (prange ? prange->is_active : 0); break;
- default: assert(0);
- }
- e->set_has_value(&l->data, 0);
- return TRUE;
- }
- case slpt_depthcc:
- cc = args[0];
- sampler_layer_unset_modulation_amount(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_depth_curvecc:
- cc = args[0];
- sampler_layer_unset_modulation_curve(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_depth_smoothcc:
- cc = args[0];
- sampler_layer_unset_modulation_smooth(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_depth_stepcc:
- cc = args[0];
- sampler_layer_unset_modulation_step(l, (e->extra_int >> 16), cc, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_amountcc:
- cc = args[0];
- sampler_layer_unset_modulation_amount(l, cc, smsrc_none, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_curvecc:
- cc = args[0];
- sampler_layer_unset_modulation_curve(l, cc, smsrc_none, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_smoothcc:
- cc = args[0];
- sampler_layer_unset_modulation_smooth(l, cc, smsrc_none, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_stepcc:
- cc = args[0];
- sampler_layer_unset_modulation_step(l, cc, smsrc_none, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_amount:
- sampler_layer_unset_modulation_amount(l, (e->extra_int >> 16), smsrc_none, (e->extra_int & 0xFFFF), TRUE);
- return TRUE;
- case slpt_modulation:
- sampler_layer_unset_modulation_amount(l, (e->extra_int >> 8) & 0xFFF, (e->extra_int >> 20), (e->extra_int & 0xFF), TRUE);
- return TRUE;
+ break;
+ case slpt_mod_amount:
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_unset_by_offset(l, e->offset, &mod_key, unset_local_value, 1 << sampler_modulation_value_field_amount);
+ break;
+ case slpt_mod_curveid:
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_unset_by_offset(l, e->offset, &mod_key, unset_local_value, 1 << sampler_modulation_value_field_curve_id);
+ break;
+ case slpt_mod_smooth:
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_unset_by_offset(l, e->offset, &mod_key, unset_local_value, 1 << sampler_modulation_value_field_smooth);
+ break;
+ case slpt_mod_step:
+ mod_key_decode(e->extra_int, args, &mod_key);
+ sampler_modulation_unset_by_offset(l, e->offset, &mod_key, unset_local_value, 1 << sampler_modulation_value_field_step);
+ break;
+ case slpt_generic_modulation:
+ mod_key = (struct sampler_modulation_key){args[0], args[1], args[2]};
+ sampler_modulation_unset_by_offset(l, e->offset, &mod_key, unset_local_value, (1 << sampler_modulation_value_field_amount) | (1 << sampler_modulation_value_field_curve_id));
+ break;
case slpt_voice_nif:
- sampler_layer_remove_nif(l, e->extra_ptr, NULL, e->extra_int, FALSE);
- return TRUE;
case slpt_prevoice_nif:
- sampler_layer_remove_nif(l, NULL, e->extra_ptr, e->extra_int, FALSE);
- return TRUE;
- case slpt_voice_cc_nif:
- cc = args[0];
- sampler_layer_remove_nif(l, e->extra_ptr, NULL, cc + (e->extra_int << 8), FALSE);
- return TRUE;
- case slpt_prevoice_cc_nif:
- cc = args[0];
- sampler_layer_remove_nif(l, NULL, e->extra_ptr, cc + (e->extra_int << 8), FALSE);
- return TRUE;
- case slpt_generic_modulation:
- sampler_layer_unset_modulation_amount(l, args[0], args[1], args[2], TRUE);
- return TRUE;
+ {
+ nif_key_decode(e->extra_int, e->extra_ptr, args, &nif_key);
+ static const uint32_t value_fields[] = {
+ sampler_noteinitfunc_value_field_value, sampler_noteinitfunc_value_field_value,
+ sampler_noteinitfunc_value_field_curve_id, sampler_noteinitfunc_value_field_step,
+ };
+ if (!sampler_noteinitfunc_unset_by_offset(l, e->offset, &nif_key, unset_local_value, 1 << value_fields[e->extra_int >> 24]))
+ {
+ if (!unset_local_value)
+ return TRUE;
+ if (e->extra_int & NIF_VARIANT_MASK)
+ g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Controller number %d not used for %s", args[0], e->name);
+ else
+ g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "%s not set", e->name);
+ return FALSE;
+ }
+ break;
+ }
+ case slpt_flex_lfo:
+ flex_lfo_key_decode(args, &flex_lfo_key);
+ switch(e->extra_int)
+ {
+ case sampler_flex_lfo_value_field_freq:
+ sampler_flex_lfo_unset_by_offset(l, e->offset, &flex_lfo_key, unset_local_value, 1 << sampler_flex_lfo_value_field_freq);
+ break;
+ case sampler_flex_lfo_value_field_delay:
+ sampler_flex_lfo_unset_by_offset(l, e->offset, &flex_lfo_key, unset_local_value, 1 << sampler_flex_lfo_value_field_delay);
+ break;
+ case sampler_flex_lfo_value_field_fade:
+ sampler_flex_lfo_unset_by_offset(l, e->offset, &flex_lfo_key, unset_local_value, 1 << sampler_flex_lfo_value_field_fade);
+ break;
+ case sampler_flex_lfo_value_field_wave:
+ sampler_flex_lfo_unset_by_offset(l, e->offset, &flex_lfo_key, unset_local_value, 1 << sampler_flex_lfo_value_field_wave);
+ break;
+ }
+ break;
case slpt_invalid:
case slpt_reserved:
case slpt_alias:
- break;
+ default:
+ printf("Unhandled parameter type of parameter %s\n", e->name);
+ assert(0);
+ return FALSE;
}
- printf("Unhandled parameter type of parameter %s\n", e->name);
- assert(0);
- return FALSE;
+ if (l->child_layers) {
+ /* Propagate to children */
+ GHashTableIter iter;
+ g_hash_table_iter_init(&iter, l->child_layers);
+ gpointer key, value;
+ while(g_hash_table_iter_next(&iter, &key, &value))
+ {
+ struct sampler_layer *child = value;
+ if (!sampler_layer_param_entry_unset(e, child, FALSE, args, error))
+ return FALSE;
+ }
+ }
+ return TRUE;
}
#undef COPY_NUM_FROM_PARENT
@@ -944,7 +1011,7 @@ int sampler_layer_apply_fixed_param(struct sampler_layer *l, const char *key, co
uint32_t args[10];
const struct sampler_layer_param_entry *e = sampler_layer_param_find(key, args);
if (e)
- return sampler_layer_param_entry_set_from_string(e, l, value, args, error);
+ return sampler_layer_param_entry_set_from_string(e, l, TRUE, value, args, error);
else
return -1;
}
@@ -954,7 +1021,7 @@ int sampler_layer_unapply_fixed_param(struct sampler_layer *l, const char *key,
uint32_t args[10];
const struct sampler_layer_param_entry *e = sampler_layer_param_find(key, args);
if (e)
- return sampler_layer_param_entry_unset(e, l, args, error);
+ return sampler_layer_param_entry_unset(e, l, TRUE, args, error);
else
return -1;
}
@@ -1070,12 +1137,7 @@ static gboolean sampler_layer_process_cmd(struct cbox_command_target *ct, struct
EQ_FIELDS(PROC_SUBSTRUCT_RESET_FIELD, name, ld); \
EQ_FIELDS(PROC_SUBSTRUCT_RESET_HAS_FIELD, name, ld)
#define PROC_FIELDS_INITIALISER_ccrange(name, parname) \
- ld->name.locc = 0; \
- ld->name.hicc = 127; \
- ld->name.cc_number = 0; \
- ld->name.has_locc = 0; \
- ld->name.has_hicc = 0; \
- ld->name.is_active = 0;
+ ld->name = NULL;
CBOX_CLASS_DEFINITION_ROOT(sampler_layer)
@@ -1104,21 +1166,22 @@ struct sampler_layer *sampler_layer_new(struct sampler_module *m, struct sampler
struct sampler_layer_data *ld = &l->data;
SAMPLER_FIXED_FIELDS(PROC_FIELDS_INITIALISER)
- ld->eff_waveform = NULL;
- ld->eff_freq = 44100;
+ ld->computed.eff_waveform = NULL;
+ ld->computed.eff_freq = 44100;
ld->modulations = NULL;
ld->voice_nifs = NULL;
ld->prevoice_nifs = NULL;
- ld->eff_use_keyswitch = 0;
+ ld->computed.eff_use_keyswitch = 0;
if (!parent)
{
// Systemwide default instead?
- sampler_layer_set_modulation_amount(l, 74, smsrc_none, smdest_cutoff, 9600);
- sampler_layer_set_modulation_curve(l, 74, smsrc_none, smdest_cutoff, 1);
- sampler_layer_set_modulation_amount(l, 71, smsrc_none, smdest_resonance, 12);
- sampler_layer_set_modulation_curve(l, 71, smsrc_none, smdest_resonance, 1);
- sampler_layer_set_modulation_amount(l, smsrc_pitchlfo, 1, smdest_pitch, 100);
+ uint32_t mod_offset = LOFS(modulations);
+ sampler_modulation_set_amount_by_offset(l, mod_offset, &(struct sampler_modulation_key){74, smsrc_none, smdest_cutoff}, TRUE, 9600);
+ sampler_modulation_set_curve_id_by_offset(l, mod_offset, &(struct sampler_modulation_key){74, smsrc_none, smdest_cutoff}, TRUE, 1);
+ sampler_modulation_set_amount_by_offset(l, mod_offset, &(struct sampler_modulation_key){71, smsrc_none, smdest_resonance}, TRUE, 12);
+ sampler_modulation_set_curve_id_by_offset(l, mod_offset, &(struct sampler_modulation_key){71, smsrc_none, smdest_resonance}, TRUE, 1);
+ sampler_modulation_set_amount_by_offset(l, mod_offset, &(struct sampler_modulation_key){smsrc_pitchlfo, 1, smdest_pitch}, TRUE, 100);
}
l->runtime = NULL;
l->unknown_keys = NULL;
@@ -1152,99 +1215,18 @@ struct sampler_layer *sampler_layer_new(struct sampler_module *m, struct sampler
if (!copy_hasattr) \
EQ_FIELDS(PROC_SUBSTRUCT_RESET_HAS_FIELD, name, dst)
#define PROC_FIELDS_CLONE_ccrange(name, parname) \
- dst->name.locc = src->name.locc; \
- dst->name.hicc = src->name.hicc; \
- dst->name.cc_number = src->name.cc_number; \
- dst->name.is_active = src->name.is_active; \
- dst->name.has_locc = copy_hasattr ? src->name.has_locc : FALSE; \
- dst->name.has_hicc = copy_hasattr ? src->name.has_hicc : FALSE;
-
-static GSList *clone_nifs(GSList *nifs, gboolean copy_hasattr)
-{
- nifs = g_slist_copy(nifs);
- for(GSList *nif = nifs; nif; nif = nif->next)
- {
- struct sampler_noteinitfunc *dstn = g_malloc(sizeof(struct sampler_noteinitfunc));
- struct sampler_noteinitfunc *srcn = nif->data;
- memcpy(dstn, srcn, sizeof(struct sampler_noteinitfunc));
- dstn->has_value = copy_hasattr ? srcn->has_value : FALSE;
- nif->data = dstn;
- }
- return nifs;
-}
+ dst->name = sampler_cc_range_clone(src->name, copy_hasattr);
void sampler_layer_data_clone(struct sampler_layer_data *dst, const struct sampler_layer_data *src, gboolean copy_hasattr)
{
SAMPLER_FIXED_FIELDS(PROC_FIELDS_CLONE)
- dst->modulations = g_slist_copy(src->modulations);
- for(GSList *mod = dst->modulations; mod; mod = mod->next)
- {
- struct sampler_modulation *srcm = mod->data;
- struct sampler_modulation *dstm = g_malloc(sizeof(struct sampler_modulation));
- memcpy(dstm, srcm, sizeof(struct sampler_modulation));
- dstm->has_amount = copy_hasattr ? srcm->has_amount : FALSE;
- dstm->has_curve = copy_hasattr ? srcm->has_curve : FALSE;
- dstm->has_smooth = copy_hasattr ? srcm->has_smooth : FALSE;
- dstm->has_step = copy_hasattr ? srcm->has_step : FALSE;
- mod->data = dstm;
- }
- dst->voice_nifs = clone_nifs(src->voice_nifs, copy_hasattr);
- dst->prevoice_nifs = clone_nifs(src->prevoice_nifs, copy_hasattr);
- dst->eff_waveform = src->eff_waveform;
- if (dst->eff_waveform)
- cbox_waveform_ref(dst->eff_waveform);
-}
-
-#define PROC_FIELDS_CLONEPARENT(type, name, def_value) \
- if (!l->has_##name) \
- l->name = parent ? parent->name : def_value;
-#define PROC_FIELDS_CLONEPARENT_string(name) \
- if (!l->has_##name && (!l->name || !parent->name || strcmp(l->name, parent->name))) { \
- g_free(l->name); \
- l->name = parent && parent->name ? g_strdup(parent->name) : NULL; \
- l->name##_changed = parent && parent->name##_changed; \
- }
-// XXXKF use a better default
-#define PROC_FIELDS_CLONEPARENT_midicurve(name) \
- for (uint32_t i = 0; i < 128; ++i) \
- if (!l->name.has_values[i]) \
- l->name.values[i] = parent ? parent->name.values[i] : SAMPLER_CURVE_GAP;
-#define PROC_FIELDS_CLONEPARENT_dBamp PROC_FIELDS_CLONEPARENT
-#define PROC_FIELDS_CLONEPARENT_enum PROC_FIELDS_CLONEPARENT
-#define PROC_FIELDS_CLONEPARENT_dahdsr(name, parname, index) \
- DAHDSR_FIELDS(PROC_SUBSTRUCT_CLONEPARENT, name, l)
-#define PROC_FIELDS_CLONEPARENT_lfo(name, parname, index) \
- LFO_FIELDS(PROC_SUBSTRUCT_CLONEPARENT, name, l)
-#define PROC_FIELDS_CLONEPARENT_eq(name, parname, index) \
- EQ_FIELDS(PROC_SUBSTRUCT_CLONEPARENT, name, l)
-#define PROC_FIELDS_CLONEPARENT_ccrange(name, parname) \
- if (!l->name.has_locc) \
- l->name.locc = parent ? parent->name.locc : 0; \
- if (!l->name.has_hicc) \
- l->name.hicc = parent ? parent->name.hicc : 127; \
- if (!l->name.has_locc && !l->name.has_hicc) {\
- l->name.is_active = parent ? parent->name.is_active : 0; \
- l->name.cc_number = parent ? parent->name.cc_number : -1; \
- }
-
-static void sampler_layer_data_getdefaults(struct sampler_layer_data *l, struct sampler_layer_data *parent)
-{
- SAMPLER_FIXED_FIELDS(PROC_FIELDS_CLONEPARENT)
- // XXXKF: add handling for velcurve
- if (parent)
- {
- // set NIFs used by parent
- for(GSList *mod = parent->voice_nifs; mod; mod = mod->next)
- {
- struct sampler_noteinitfunc *nif = mod->data;
- sampler_layer_data_add_nif(l, nif->notefunc_voice, nif->notefunc_prevoice, nif->variant, nif->param, TRUE);
- }
- for(GSList *mod = parent->prevoice_nifs; mod; mod = mod->next)
- {
- struct sampler_noteinitfunc *nif = mod->data;
- sampler_layer_data_add_nif(l, nif->notefunc_voice, nif->notefunc_prevoice, nif->variant, nif->param, TRUE);
- }
- }
+ dst->modulations = sampler_modulation_clone(src->modulations, copy_hasattr);
+ dst->voice_nifs = sampler_noteinitfunc_clone(src->voice_nifs, copy_hasattr);
+ dst->prevoice_nifs = sampler_noteinitfunc_clone(src->prevoice_nifs, copy_hasattr);
+ dst->flex_lfos = sampler_flex_lfo_clone(src->flex_lfos, copy_hasattr);
+ dst->computed.eff_waveform = src->computed.eff_waveform;
+ if (dst->computed.eff_waveform)
+ cbox_waveform_ref(dst->computed.eff_waveform);
}
void sampler_midi_curve_init(struct sampler_midi_curve *curve)
@@ -1312,7 +1294,7 @@ static inline int sampler_filter_num_stages(float cutoff, enum sampler_filter_ty
#define PROC_FIELDS_FINALISER(type, name, def_value)
#define PROC_FIELDS_FINALISER_string(name)
#define PROC_FIELDS_FINALISER_midicurve(name) \
- sampler_midi_curve_interpolate(&l->name, l->eff_##name, START_VALUE_##name, END_VALUE_##name, IS_QUADRATIC_##name);
+ sampler_midi_curve_interpolate(&l->name, l->computed.eff_##name, START_VALUE_##name, END_VALUE_##name, IS_QUADRATIC_##name);
#define PROC_FIELDS_FINALISER_enum(type, name, def_value)
#define PROC_FIELDS_FINALISER_dBamp(type, name, def_value) \
l->name##_linearized = dB2gain(l->name);
@@ -1327,31 +1309,30 @@ void sampler_layer_data_finalize(struct sampler_layer_data *l, struct sampler_la
struct sampler_module *m = p->module;
SAMPLER_FIXED_FIELDS(PROC_FIELDS_FINALISER)
- sampler_layer_data_getdefaults(l, parent);
-
// Handle change of sample in the parent group without override on region level
if (parent && (l->sample_changed || parent->sample_changed))
{
- struct cbox_waveform *oldwf = l->eff_waveform;
+ struct cbox_waveform *oldwf = l->computed.eff_waveform;
if (l->sample && *l->sample)
{
GError *error = NULL;
- l->eff_waveform = cbox_wavebank_get_waveform(p->name, p->tarfile, p->sample_dir, l->sample, &error);
- if (!l->eff_waveform)
+ l->computed.eff_waveform = cbox_wavebank_get_waveform(p->name, p->tarfile, p->sample_dir, l->sample, &error);
+ if (!l->computed.eff_waveform)
{
g_warning("Cannot load waveform %s: %s", l->sample, error ? error->message : "unknown error");
g_error_free(error);
}
}
else
- l->eff_waveform = NULL;
+ l->computed.eff_waveform = NULL;
if (oldwf)
cbox_waveform_unref(oldwf);
+ l->computed.eff_is_silent = !l->sample || !strcmp(l->sample, "*silence");
l->sample_changed = FALSE;
}
- l->eff_use_keyswitch = ((l->sw_down != -1) || (l->sw_up != -1) || (l->sw_last != -1) || (l->sw_previous != -1));
- l->eff_use_simple_trigger_logic =
+ l->computed.eff_use_keyswitch = ((l->sw_down != -1) || (l->sw_up != -1) || (l->sw_last != -1) || (l->sw_previous != -1));
+ l->computed.eff_use_simple_trigger_logic =
(l->seq_length == 1 && l->seq_position == 1) &&
(l->trigger != stm_first && l->trigger != stm_legato) &&
(l->lochan == 1 && l->hichan == 16) &&
@@ -1360,28 +1341,31 @@ void sampler_layer_data_finalize(struct sampler_layer_data *l, struct sampler_la
(l->lochanaft == 0 && l->hichanaft == 127) &&
(l->lopolyaft == 0 && l->hipolyaft == 127) &&
(l->lobpm == 0 && l->hibpm == NO_HI_BPM_VALUE) &&
- !l->cc.is_active && !l->eff_use_keyswitch;
- l->eff_use_xfcc = l->xfin_cc.is_active || l->xfout_cc.is_active;
- l->eff_freq = (l->eff_waveform && l->eff_waveform->info.samplerate) ? l->eff_waveform->info.samplerate : 44100;
- l->eff_loop_mode = l->loop_mode;
+ !l->cc && !l->computed.eff_use_keyswitch;
+ l->computed.eff_use_xfcc = l->xfin_cc || l->xfout_cc;
+ l->computed.eff_use_channel_mixer = l->position != 0 || l->width != 100;
+ l->computed.eff_freq = (l->computed.eff_waveform && l->computed.eff_waveform->info.samplerate) ? l->computed.eff_waveform->info.samplerate : 44100;
+ l->computed.eff_loop_mode = l->loop_mode;
+ l->computed.eff_use_filter_mods = l->cutoff != -1 || l->cutoff2 != -1;
if (l->loop_mode == slm_unknown)
{
- if (l->eff_waveform && l->eff_waveform->has_loop)
- l->eff_loop_mode = slm_loop_continuous;
+ if (l->computed.eff_waveform && l->computed.eff_waveform->has_loop)
+ l->computed.eff_loop_mode = slm_loop_continuous;
else
- if (l->eff_waveform)
- l->eff_loop_mode = l->loop_end == 0 ? slm_no_loop : slm_loop_continuous;
+ if (l->computed.eff_waveform)
+ l->computed.eff_loop_mode = l->loop_end == 0 ? slm_no_loop : slm_loop_continuous;
}
-
- if (l->eff_loop_mode == slm_one_shot || l->eff_loop_mode == slm_no_loop || l->eff_loop_mode == slm_one_shot_chokeable)
- l->loop_start = SAMPLER_NO_LOOP;
- if ((l->eff_loop_mode == slm_loop_continuous || l->eff_loop_mode == slm_loop_sustain) && l->loop_start == SAMPLER_NO_LOOP)
- l->loop_start = 0;
- if ((l->eff_loop_mode == slm_loop_continuous || l->eff_loop_mode == slm_loop_sustain) && l->loop_start == 0 && l->eff_waveform && l->eff_waveform->has_loop)
- l->loop_start = l->eff_waveform->loop_start;
- if (l->loop_end == 0 && l->eff_waveform != NULL)
- l->loop_end = l->eff_waveform->has_loop ? l->eff_waveform->loop_end : l->eff_waveform->info.frames;
+ l->computed.eff_loop_start = l->loop_start;
+ l->computed.eff_loop_end = l->loop_end;
+ if (l->computed.eff_loop_mode == slm_one_shot || l->computed.eff_loop_mode == slm_no_loop || l->computed.eff_loop_mode == slm_one_shot_chokeable)
+ l->computed.eff_loop_start = SAMPLER_NO_LOOP;
+ if ((l->computed.eff_loop_mode == slm_loop_continuous || l->computed.eff_loop_mode == slm_loop_sustain) && l->computed.eff_loop_start == SAMPLER_NO_LOOP)
+ l->computed.eff_loop_start = 0;
+ if ((l->computed.eff_loop_mode == slm_loop_continuous || l->computed.eff_loop_mode == slm_loop_sustain) && l->computed.eff_loop_start == 0 && l->computed.eff_waveform && l->computed.eff_waveform->has_loop)
+ l->computed.eff_loop_start = l->computed.eff_waveform->loop_start;
+ if (l->loop_end == 0 && l->computed.eff_waveform != NULL)
+ l->computed.eff_loop_end = l->computed.eff_waveform->has_loop ? l->computed.eff_waveform->loop_end : l->computed.eff_waveform->info.frames;
if (l->off_mode == som_unknown)
l->off_mode = l->off_by != 0 ? som_fast : som_normal;
@@ -1394,45 +1378,45 @@ void sampler_layer_data_finalize(struct sampler_layer_data *l, struct sampler_la
// and 3 (N) frames at the start of the loop, and play it; in rare cases this will need to be
// repeated twice if output write pointer is close to CBOX_BLOCK_SIZE or playback rate is very low,
// but that's OK.
- if (l->eff_waveform && l->eff_waveform->preloaded_frames == (size_t)l->eff_waveform->info.frames)
+ if (l->computed.eff_waveform && l->computed.eff_waveform->preloaded_frames == (size_t)l->computed.eff_waveform->info.frames)
{
- int shift = l->eff_waveform->info.channels == 2 ? 1 : 0;
+ int shift = l->computed.eff_waveform->info.channels == 2 ? 1 : 0;
uint32_t halfscratch = MAX_INTERPOLATION_ORDER << shift;
- memcpy(&l->scratch_loop[0], &l->eff_waveform->data[(l->loop_end - MAX_INTERPOLATION_ORDER) << shift], halfscratch * sizeof(int16_t) );
- memcpy(&l->scratch_end[0], &l->eff_waveform->data[(l->loop_end - MAX_INTERPOLATION_ORDER) << shift], halfscratch * sizeof(int16_t) );
- memset(l->scratch_end + halfscratch, 0, halfscratch * sizeof(int16_t));
- if (l->loop_start != (uint32_t)-1)
- memcpy(l->scratch_loop + halfscratch, &l->eff_waveform->data[l->loop_start << shift], halfscratch * sizeof(int16_t));
+ memcpy(&l->computed.scratch_loop[0], &l->computed.eff_waveform->data[(l->computed.eff_loop_end - MAX_INTERPOLATION_ORDER) << shift], halfscratch * sizeof(int16_t) );
+ memcpy(&l->computed.scratch_end[0], &l->computed.eff_waveform->data[(l->computed.eff_loop_end - MAX_INTERPOLATION_ORDER) << shift], halfscratch * sizeof(int16_t) );
+ memset(l->computed.scratch_end + halfscratch, 0, halfscratch * sizeof(int16_t));
+ if (l->computed.eff_loop_start != (uint32_t)-1)
+ memcpy(l->computed.scratch_loop + halfscratch, &l->computed.eff_waveform->data[l->computed.eff_loop_start << shift], halfscratch * sizeof(int16_t));
else
- memset(l->scratch_loop + halfscratch, 0, halfscratch * sizeof(int16_t));
+ memset(l->computed.scratch_loop + halfscratch, 0, halfscratch * sizeof(int16_t));
}
if (l->cutoff < 20)
- l->logcutoff = -1;
+ l->computed.logcutoff = -1;
else
- l->logcutoff = 1200.0 * log(l->cutoff / 440.0) / log(2) + 5700.0;
+ l->computed.logcutoff = 1200.0 * log(l->cutoff / 440.0) / log(2) + 5700.0;
if (l->cutoff2 < 20)
- l->logcutoff2 = -1;
+ l->computed.logcutoff2 = -1;
else
- l->logcutoff2 = 1200.0 * log(l->cutoff2 / 440.0) / log(2) + 5700.0;
+ l->computed.logcutoff2 = 1200.0 * log(l->cutoff2 / 440.0) / log(2) + 5700.0;
- l->eq_bitmask = ((l->eq1.gain != 0 || l->eq1.vel2gain != 0) ? 1 : 0)
+ l->computed.eq_bitmask = ((l->eq1.gain != 0 || l->eq1.vel2gain != 0) ? 1 : 0)
| ((l->eq2.gain != 0 || l->eq2.vel2gain != 0) ? 2 : 0)
| ((l->eq3.gain != 0 || l->eq3.vel2gain != 0) ? 4 : 0);
- l->mod_bitmask = 0;
- for(GSList *mod = l->modulations; mod; mod = g_slist_next(mod))
+ l->computed.mod_bitmask = 0;
+ for(struct sampler_modulation *mod = l->modulations; mod; mod = mod->next)
{
- const struct sampler_modulation *mval = (const struct sampler_modulation *)mod->data;
- if (mval->dest >= smdest_eg_stage_start && mval->dest <= smdest_eg_stage_end)
- l->mod_bitmask |= slmb_ampeg_cc << ((mval->dest >> 4) & 3);
+ const struct sampler_modulation_key *mk = &mod->key;
+ if (mk->dest >= smdest_eg_stage_start && mk->dest <= smdest_eg_stage_end)
+ l->computed.mod_bitmask |= slmb_ampeg_cc << ((mk->dest >> 4) & 3);
}
- l->use_prevoice = (l->delay || l->prevoice_nifs);
- l->eff_num_stages = sampler_filter_num_stages(l->cutoff, l->fil_type);
- l->eff_num_stages2 = sampler_filter_num_stages(l->cutoff2, l->fil2_type);
+ l->computed.eff_use_prevoice = (l->delay || l->prevoice_nifs);
+ l->computed.eff_num_stages = sampler_filter_num_stages(l->cutoff, l->fil_type);
+ l->computed.eff_num_stages2 = sampler_filter_num_stages(l->cutoff2, l->fil2_type);
- l->resonance_scaled = pow(l->resonance_linearized, 1.f / l->eff_num_stages);
- l->resonance2_scaled = pow(l->resonance2_linearized, 1.f / l->eff_num_stages2);
+ l->computed.resonance_scaled = pow(l->resonance_linearized, 1.f / l->computed.eff_num_stages);
+ l->computed.resonance2_scaled = pow(l->resonance2_linearized, 1.f / l->computed.eff_num_stages2);
}
void sampler_layer_reset_switches(struct sampler_layer *l, struct sampler_module *m)
@@ -1565,10 +1549,16 @@ gboolean sampler_layer_unapply_param(struct sampler_layer *layer, const char *ke
#define PROC_FIELDS_TO_FILEPTR_eq(name, parname, index) \
EQ_FIELDS(ENV_PARAM_OUTPUT, l->name, name, parname)
#define PROC_FIELDS_TO_FILEPTR_ccrange(name, parname) \
- if (show_inherited || l->name.has_locc) \
- g_string_append_printf(outstr, " " #parname "locc%d=%d", l->name.cc_number, l->name.locc); \
- if (show_inherited || l->name.has_hicc) \
- g_string_append_printf(outstr, " " #parname "hicc%d=%d", l->name.cc_number, l->name.hicc);
+ { \
+ struct sampler_cc_range *range = l->name; \
+ while (range) { \
+ if (show_inherited || range->value.has_locc) \
+ g_string_append_printf(outstr, " " #parname "locc%d=%d", range->key.cc_number, range->value.locc); \
+ if (show_inherited || range->value.has_hicc) \
+ g_string_append_printf(outstr, " " #parname "hicc%d=%d", range->key.cc_number, range->value.hicc); \
+ range = range->next; \
+ } \
+ }
static const char *addrandom_variants[] = { "amp", "fil", "pitch" };
static const char *env_stages[] = { "delay", "attack", "hold", "decay", "sustain", "release", "start" };
@@ -1579,7 +1569,7 @@ static const char *moddest_names[] = { "gain", "pitch", "cutoff", "resonance", "
"eq3_freq", "eq3_bw", "eq3_gain",
};
-static void mod_cc_attrib_to_string(GString *outstr, const char *attrib, const struct sampler_modulation *md, const char *floatbuf)
+static void mod_cc_attrib_to_string(GString *outstr, const char *attrib, const struct sampler_modulation_key *md, const char *floatbuf)
{
if (md->dest >= smdest_eg_stage_start && md->dest <= smdest_eg_stage_end)
{
@@ -1594,24 +1584,40 @@ static void mod_cc_attrib_to_string(GString *outstr, const char *attrib, const s
(md->src == smsrc_fillfo && md->dest == smdest_cutoff) ||
(md->src == smsrc_pitchlfo && md->dest == smdest_pitch))
{
- if (md->src2 < 120)
+ if (md->src2 < EXT_CC_COUNT)
g_string_append_printf(outstr, " %s_depth%s%d=%s", modsrc_names[md->src - smsrc_perchan_count], attrib, md->src2, floatbuf);
}
else if ((md->src == smsrc_ampenv && md->dest == smdest_gain) ||
(md->src == smsrc_filenv && md->dest == smdest_cutoff) ||
(md->src == smsrc_pitchenv && md->dest == smdest_pitch))
{
- if (md->src2 < 120)
+ if (md->src2 < EXT_CC_COUNT)
g_string_append_printf(outstr, " %s_depth%s%d=%s", modsrc_names[md->src - smsrc_perchan_count], attrib, md->src2, floatbuf);
}
else if ((md->src == smsrc_filenv && md->dest == smdest_cutoff2) ||
(md->src == smsrc_fillfo && md->dest == smdest_cutoff2))
{
- if (md->src2 < 120)
+ if (md->src2 < EXT_CC_COUNT)
g_string_append_printf(outstr, " %s_depth2%s%d=%s", modsrc_names[md->src - smsrc_perchan_count], attrib, md->src2, floatbuf);
}
else
- assert(md->src2 >= 120);
+ assert(md->src2 >= EXT_CC_COUNT);
+}
+
+static void nif_attrib_to_string(GString *outstr, const char *attrib, const struct sampler_noteinitfunc *nd, const char *floatbuf)
+{
+ int v = nd->key.variant;
+ if (nd->value.value)
+ g_string_append_printf(outstr, " %s_cc%d=%s", attrib, v, floatbuf);
+ if (nd->value.curve_id)
+ g_string_append_printf(outstr, " %s_curvecc%d=%d", attrib, v, nd->value.curve_id);
+ if (nd->value.step)
+ {
+ char floatbuf2[G_ASCII_DTOSTR_BUF_SIZE];
+ int floatbufsize = G_ASCII_DTOSTR_BUF_SIZE;
+ g_ascii_dtostr(floatbuf2, floatbufsize, nd->value.step);
+ g_string_append_printf(outstr, " %s_stepcc%d=%s", attrib, v, floatbuf2);
+ }
}
gchar *sampler_layer_to_string(struct sampler_layer *lr, gboolean show_inherited)
@@ -1623,173 +1629,191 @@ gchar *sampler_layer_to_string(struct sampler_layer *lr, gboolean show_inherited
int floatbufsize = G_ASCII_DTOSTR_BUF_SIZE;
SAMPLER_FIXED_FIELDS(PROC_FIELDS_TO_FILEPTR)
- for(GSList *nif = l->voice_nifs; nif; nif = nif->next)
+ for(struct sampler_noteinitfunc *nd = l->voice_nifs; nd; nd = nd->next)
{
- struct sampler_noteinitfunc *nd = nif->data;
- if (!nd->has_value && !show_inherited)
+ if (!nd->value.has_value && !nd->value.has_curve && !nd->value.has_step && !show_inherited)
continue;
#define PROC_ENVSTAGE_NAME(name, index, def_value) #name,
static const char *env_stages[] = { DAHDSR_FIELDS(PROC_ENVSTAGE_NAME) "start" };
- int v = nd->variant;
- g_ascii_dtostr(floatbuf, floatbufsize, nd->param);
+ uint32_t v = nd->key.variant;
+ g_ascii_dtostr(floatbuf, floatbufsize, nd->value.value);
- if (nd->notefunc_voice == sampler_nif_addrandom && v >= 0 && v <= 2)
- g_string_append_printf(outstr, " %s_random=%s", addrandom_variants[nd->variant], floatbuf);
- else if (nd->notefunc_voice == sampler_nif_vel2pitch)
+ if (nd->key.notefunc_voice == sampler_nif_addrandom && v >= 0 && v <= 2)
+ g_string_append_printf(outstr, " %s_random=%s", addrandom_variants[v], floatbuf);
+ else if (nd->key.notefunc_voice == sampler_nif_vel2pitch)
g_string_append_printf(outstr, " pitch_veltrack=%s", floatbuf);
- else if (nd->notefunc_voice == sampler_nif_vel2reloffset)
+ else if (nd->key.notefunc_voice == sampler_nif_vel2reloffset)
g_string_append_printf(outstr, " reloffset_veltrack=%s", floatbuf);
- else if (nd->notefunc_voice == sampler_nif_cc2reloffset)
- g_string_append_printf(outstr, " reloffset_cc%d=%s", nd->variant, floatbuf);
- else if (nd->notefunc_voice == sampler_nif_vel2offset)
+ else if (nd->key.notefunc_voice == sampler_nif_cc2reloffset)
+ nif_attrib_to_string(outstr, "reloffset", nd, floatbuf);
+ else if (nd->key.notefunc_voice == sampler_nif_vel2offset)
g_string_append_printf(outstr, " offset_veltrack=%s", floatbuf);
- else if (nd->notefunc_voice == sampler_nif_cc2offset)
- g_string_append_printf(outstr, " offset_cc%d=%s", nd->variant, floatbuf);
- else if (nd->notefunc_voice == sampler_nif_vel2env && (v & 15) >= snif_env_delay && (v & 15) <= snif_env_start && ((v >> 4) & 3) < 3)
- g_string_append_printf(outstr, " %seg_vel2%s=%s", addrandom_variants[nd->variant >> 4], env_stages[1 + (v & 15)], floatbuf);
+ else if (nd->key.notefunc_voice == sampler_nif_cc2offset)
+ nif_attrib_to_string(outstr, "offset", nd, floatbuf);
+ else if (nd->key.notefunc_voice == sampler_nif_vel2env && (v & 15) >= snif_env_delay && (v & 15) <= snif_env_start && ((v >> 4) & 3) < 3)
+ g_string_append_printf(outstr, " %seg_vel2%s=%s", addrandom_variants[v >> 4], env_stages[1 + (v & 15)], floatbuf);
else
assert(0); // unknown NIF
}
- for(GSList *nif = l->prevoice_nifs; nif; nif = nif->next)
+ for(struct sampler_noteinitfunc *nd = l->prevoice_nifs; nd; nd = nd->next)
{
- struct sampler_noteinitfunc *nd = nif->data;
- if (!nd->has_value && !show_inherited)
+ if (!nd->value.has_value && !nd->value.has_curve && !nd->value.has_step && !show_inherited)
continue;
- int v = nd->variant;
- g_ascii_dtostr(floatbuf, floatbufsize, nd->param);
+ g_ascii_dtostr(floatbuf, floatbufsize, nd->value.value);
- if (nd->notefunc_prevoice == sampler_nif_cc2delay)
- g_string_append_printf(outstr, " delay_cc%d=%s", v, floatbuf);
- else if (nd->notefunc_prevoice == sampler_nif_addrandomdelay)
+ if (nd->key.notefunc_prevoice == sampler_nif_cc2delay)
+ nif_attrib_to_string(outstr, "delay", nd, floatbuf);
+ else if (nd->key.notefunc_prevoice == sampler_nif_addrandomdelay)
g_string_append_printf(outstr, " delay_random=%s", floatbuf);
else
assert(0); // unknown NIF
}
- for(GSList *mod = l->modulations; mod; mod = mod->next)
+ for(struct sampler_flex_lfo *flfo = l->flex_lfos; flfo; flfo = flfo->next)
+ {
+ if (flfo->value.has_freq || show_inherited)
+ {
+ g_ascii_dtostr(floatbuf, floatbufsize, flfo->value.freq);
+ g_string_append_printf(outstr, " lfo%d_freq=%s", (int)flfo->key.id, floatbuf);
+ }
+ if (flfo->value.has_delay || show_inherited)
+ {
+ g_ascii_dtostr(floatbuf, floatbufsize, flfo->value.delay);
+ g_string_append_printf(outstr, " lfo%d_delay=%s", (int)flfo->key.id, floatbuf);
+ }
+ if (flfo->value.has_fade || show_inherited)
+ {
+ g_ascii_dtostr(floatbuf, floatbufsize, flfo->value.fade);
+ g_string_append_printf(outstr, " lfo%d_fade=%s", (int)flfo->key.id, floatbuf);
+ }
+ if (flfo->value.has_wave || show_inherited)
+ g_string_append_printf(outstr, " lfo%d_wave=%d", (int)flfo->key.id, flfo->value.wave);
+ }
+ for(struct sampler_modulation *md = l->modulations; md; md = md->next)
{
- struct sampler_modulation *md = mod->data;
- if (md->has_curve || show_inherited)
+ const struct sampler_modulation_key *mk = &md->key;
+ const struct sampler_modulation_value *mv = &md->value;
+ if (mv->has_curve || show_inherited)
{
- g_ascii_dtostr(floatbuf, floatbufsize, md->curve_id);
- mod_cc_attrib_to_string(outstr, "_curvecc", md, floatbuf);
+ g_ascii_dtostr(floatbuf, floatbufsize, mv->curve_id);
+ mod_cc_attrib_to_string(outstr, "_curvecc", mk, floatbuf);
}
- if (md->has_smooth || show_inherited)
+ if (mv->has_smooth || show_inherited)
{
- g_ascii_dtostr(floatbuf, floatbufsize, md->smooth);
- mod_cc_attrib_to_string(outstr, "_smoothcc", md, floatbuf);
+ g_ascii_dtostr(floatbuf, floatbufsize, mv->smooth);
+ mod_cc_attrib_to_string(outstr, "_smoothcc", mk, floatbuf);
}
- if (md->has_step || show_inherited)
+ if (mv->has_step || show_inherited)
{
- g_ascii_dtostr(floatbuf, floatbufsize, md->step);
- mod_cc_attrib_to_string(outstr, "_stepcc", md, floatbuf);
+ g_ascii_dtostr(floatbuf, floatbufsize, mv->step);
+ mod_cc_attrib_to_string(outstr, "_stepcc", mk, floatbuf);
}
- if (md->has_amount || show_inherited)
+ if (mv->has_amount || show_inherited)
{
- gboolean is_egcc = md->dest >= smdest_eg_stage_start && md->dest <= smdest_eg_stage_end;
- gboolean is_lfofreq = md->dest >= smdest_pitchlfo_freq && md->dest <= smdest_eq3_gain;
- g_ascii_dtostr(floatbuf, floatbufsize, md->amount);
+ gboolean is_egcc = mk->dest >= smdest_eg_stage_start && mk->dest <= smdest_eg_stage_end;
+ gboolean is_lfofreq = mk->dest >= smdest_pitchlfo_freq && mk->dest <= smdest_eq3_gain;
+ g_ascii_dtostr(floatbuf, floatbufsize, mv->amount);
- if (md->src2 == smsrc_none)
+ if (mk->src2 == smsrc_none)
{
if (is_egcc)
{
- uint32_t param = md->dest - smdest_eg_stage_start;
- g_string_append_printf(outstr, " %seg_%scc%d=%s", addrandom_variants[(param >> 4) & 3], env_stages[param & 15], md->src, floatbuf);
+ uint32_t param = mk->dest - smdest_eg_stage_start;
+ g_string_append_printf(outstr, " %seg_%scc%d=%s", addrandom_variants[(param >> 4) & 3], env_stages[param & 15], mk->src, floatbuf);
continue;
}
- if (md->src < smsrc_perchan_count)
+ if (mk->src < smsrc_perchan_count)
{
// Inconsistency: cutoff_cc5 but amplfo_freqcc5
if (is_lfofreq)
- g_string_append_printf(outstr, " %scc%d=%s", moddest_names[md->dest], md->src, floatbuf);
+ g_string_append_printf(outstr, " %scc%d=%s", moddest_names[mk->dest], mk->src, floatbuf);
else
- g_string_append_printf(outstr, " %s_cc%d=%s", moddest_names[md->dest], md->src, floatbuf);
+ g_string_append_printf(outstr, " %s_cc%d=%s", moddest_names[mk->dest], mk->src, floatbuf);
continue;
}
- if (md->src < smsrc_perchan_count + sizeof(modsrc_names) / sizeof(modsrc_names[0]))
+ if (mk->src < smsrc_perchan_count + sizeof(modsrc_names) / sizeof(modsrc_names[0]))
{
- if ((md->src == smsrc_filenv && md->dest == smdest_cutoff) ||
- (md->src == smsrc_pitchenv && md->dest == smdest_pitch) ||
- (md->src == smsrc_amplfo && md->dest == smdest_gain) ||
- (md->src == smsrc_fillfo && md->dest == smdest_cutoff) ||
- (md->src == smsrc_pitchlfo && md->dest == smdest_pitch))
- g_string_append_printf(outstr, " %s_depth=%s", modsrc_names[md->src - smsrc_perchan_count], floatbuf);
- else if ((md->src == smsrc_filenv && md->dest == smdest_cutoff2) ||
- (md->src == smsrc_fillfo && md->dest == smdest_cutoff2))
- g_string_append_printf(outstr, " %s_depth2=%s", modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ if ((mk->src == smsrc_filenv && mk->dest == smdest_cutoff) ||
+ (mk->src == smsrc_pitchenv && mk->dest == smdest_pitch) ||
+ (mk->src == smsrc_amplfo && mk->dest == smdest_gain) ||
+ (mk->src == smsrc_fillfo && mk->dest == smdest_cutoff) ||
+ (mk->src == smsrc_pitchlfo && mk->dest == smdest_pitch))
+ g_string_append_printf(outstr, " %s_depth=%s", modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
+ else if ((mk->src == smsrc_filenv && mk->dest == smdest_cutoff2) ||
+ (mk->src == smsrc_fillfo && mk->dest == smdest_cutoff2))
+ g_string_append_printf(outstr, " %s_depth2=%s", modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
else if (is_lfofreq)
- g_string_append_printf(outstr, " %s%s=%s", moddest_names[md->dest], modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s%s=%s", moddest_names[mk->dest], modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
else
- g_string_append_printf(outstr, " %s_%s=%s", moddest_names[md->dest], modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s_%s=%s", moddest_names[mk->dest], modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
continue;
}
}
- if ((md->src == smsrc_amplfo && md->dest == smdest_gain) ||
- (md->src == smsrc_fillfo && md->dest == smdest_cutoff) ||
- (md->src == smsrc_pitchlfo && md->dest == smdest_pitch))
+ if ((mk->src == smsrc_amplfo && mk->dest == smdest_gain) ||
+ (mk->src == smsrc_fillfo && mk->dest == smdest_cutoff) ||
+ (mk->src == smsrc_pitchlfo && mk->dest == smdest_pitch))
{
- switch(md->src2)
+ switch(mk->src2)
{
case smsrc_chanaft:
case smsrc_polyaft:
- g_string_append_printf(outstr, " %s_depth%s=%s", modsrc_names[md->src - smsrc_perchan_count], modsrc_names[md->src2 - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s_depth%s=%s", modsrc_names[mk->src - smsrc_perchan_count], modsrc_names[mk->src2 - smsrc_perchan_count], floatbuf);
continue;
case smsrc_none:
- g_string_append_printf(outstr, " %s_depth=%s", modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s_depth=%s", modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
continue;
default:
- if (md->src2 < 120)
+ if (mk->src2 < EXT_CC_COUNT)
{
- g_string_append_printf(outstr, " %s_depthcc%d=%s", modsrc_names[md->src - smsrc_perchan_count], md->src2, floatbuf);
+ g_string_append_printf(outstr, " %s_depthcc%d=%s", modsrc_names[mk->src - smsrc_perchan_count], mk->src2, floatbuf);
continue;
}
break;
}
}
- if ((md->src == smsrc_ampenv && md->dest == smdest_gain) ||
- (md->src == smsrc_filenv && md->dest == smdest_cutoff) ||
- (md->src == smsrc_pitchenv && md->dest == smdest_pitch))
+ if ((mk->src == smsrc_ampenv && mk->dest == smdest_gain) ||
+ (mk->src == smsrc_filenv && mk->dest == smdest_cutoff) ||
+ (mk->src == smsrc_pitchenv && mk->dest == smdest_pitch))
{
- if (md->src2 == smsrc_vel)
+ if (mk->src2 == smsrc_vel)
{
- g_string_append_printf(outstr, " %s_vel2depth=%s", modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s_vel2depth=%s", modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
continue;
}
- if (md->src2 == smsrc_none)
+ if (mk->src2 == smsrc_none)
{
- g_string_append_printf(outstr, " %s_depth=%s", modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s_depth=%s", modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
continue;
}
- if (md->src2 < 120)
+ if (mk->src2 < EXT_CC_COUNT)
{
- g_string_append_printf(outstr, " %s_depthcc%d=%s", modsrc_names[md->src - smsrc_perchan_count], md->src2, floatbuf);
+ g_string_append_printf(outstr, " %s_depthcc%d=%s", modsrc_names[mk->src - smsrc_perchan_count], mk->src2, floatbuf);
continue;
}
}
- if (md->src == smsrc_filenv && md->dest == smdest_cutoff2)
+ if (mk->src == smsrc_filenv && mk->dest == smdest_cutoff2)
{
- if (md->src2 == smsrc_vel)
+ if (mk->src2 == smsrc_vel)
{
- g_string_append_printf(outstr, " %s_vel2depth2=%s", modsrc_names[md->src - smsrc_perchan_count], floatbuf);
+ g_string_append_printf(outstr, " %s_vel2depth2=%s", modsrc_names[mk->src - smsrc_perchan_count], floatbuf);
continue;
}
- assert(md->src2 != smsrc_none);
- if (md->src2 < 120)
+ assert(mk->src2 != smsrc_none);
+ if (mk->src2 < EXT_CC_COUNT)
{
- g_string_append_printf(outstr, " %s_depth2cc%d=%s", modsrc_names[md->src - smsrc_perchan_count], md->src2, floatbuf);
+ g_string_append_printf(outstr, " %s_depth2cc%d=%s", modsrc_names[mk->src - smsrc_perchan_count], mk->src2, floatbuf);
continue;
}
}
- if (md->src == smsrc_fillfo && md->dest == smdest_cutoff2)
+ if (mk->src == smsrc_fillfo && mk->dest == smdest_cutoff2)
{
- assert(md->src2 != smsrc_none);
- if (md->src2 < 120)
+ assert(mk->src2 != smsrc_none);
+ if (mk->src2 < EXT_CC_COUNT)
{
- g_string_append_printf(outstr, " %s_depth2cc%d=%s", modsrc_names[md->src - smsrc_perchan_count], md->src2, floatbuf);
+ g_string_append_printf(outstr, " %s_depth2cc%d=%s", modsrc_names[mk->src - smsrc_perchan_count], mk->src2, floatbuf);
continue;
}
}
- g_string_append_printf(outstr, " genericmod_%d_%d_%d_%d=%s", md->src, md->src2, md->dest, md->curve_id, floatbuf);
+ g_string_append_printf(outstr, " genericmod_%d_%d_%d_%d=%s", mk->src, mk->src2, mk->dest, mv->curve_id, floatbuf);
}
}
@@ -1815,13 +1839,18 @@ void sampler_layer_dump(struct sampler_layer *l, FILE *f)
void sampler_layer_data_close(struct sampler_layer_data *l)
{
- g_slist_free_full(l->voice_nifs, g_free);
- g_slist_free_full(l->prevoice_nifs, g_free);
- g_slist_free_full(l->modulations, g_free);
- if (l->eff_waveform)
+ sampler_flex_lfos_destroy(l->flex_lfos);
+ sampler_cc_ranges_destroy(l->cc);
+ sampler_cc_ranges_destroy(l->on_cc);
+ sampler_cc_ranges_destroy(l->xfin_cc);
+ sampler_cc_ranges_destroy(l->xfout_cc);
+ sampler_noteinitfuncs_destroy(l->voice_nifs);
+ sampler_noteinitfuncs_destroy(l->prevoice_nifs);
+ sampler_modulations_destroy(l->modulations);
+ if (l->computed.eff_waveform)
{
- cbox_waveform_unref(l->eff_waveform);
- l->eff_waveform = NULL;
+ cbox_waveform_unref(l->computed.eff_waveform);
+ l->computed.eff_waveform = NULL;
}
g_free(l->sample);
}
diff --git a/template/calfbox/sampler_layer.h b/template/calfbox/sampler_layer.h
index 19e7278..0a1b5bc 100644
--- a/template/calfbox/sampler_layer.h
+++ b/template/calfbox/sampler_layer.h
@@ -27,6 +27,8 @@ along with this program. If not, see .
// arbitrary value that doesn't collide with a useful range
#define SAMPLER_CURVE_GAP -100000
#define NO_HI_BPM_VALUE 10000
+#define CC_COUNT 128
+#define EXT_CC_COUNT 143
struct sampler_program;
struct sampler_voice;
@@ -239,11 +241,15 @@ enum sampler_moddest
smdest_eg_stage_end = 0xAF,
};
-struct sampler_modulation
+struct sampler_modulation_key
{
enum sampler_modsrc src;
enum sampler_modsrc src2;
enum sampler_moddest dest;
+};
+
+struct sampler_modulation_value
+{
float amount;
float smooth;
float step;
@@ -254,17 +260,37 @@ struct sampler_modulation
unsigned int has_step:1;
};
+#define SAMPLER_COLL_FIELD_LIST_sampler_modulation(MACRO, ...) \
+ MACRO(amount, has_amount, float, 0, ## __VA_ARGS__) \
+ MACRO(curve_id, has_curve, uint32_t, 0, ## __VA_ARGS__) \
+ MACRO(smooth, has_smooth, float, 0, ## __VA_ARGS__) \
+ MACRO(step, has_step, float, 0, ## __VA_ARGS__)
+
+#define SAMPLER_COLL_CHAIN_LIST_sampler_modulation(MACRO, ...) \
+ MACRO(modulations, modulation, ## __VA_ARGS__)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
typedef void (*SamplerNoteInitFunc)(struct sampler_noteinitfunc *nif, struct sampler_voice *voice);
typedef void (*SamplerNoteInitFunc2)(struct sampler_noteinitfunc *nif, struct sampler_prevoice *prevoice);
-struct sampler_noteinitfunc
+struct sampler_noteinitfunc_key
+{
+ union {
+ SamplerNoteInitFunc notefunc_voice;
+ SamplerNoteInitFunc2 notefunc_prevoice;
+ };
+ int variant;
+};
+
+struct sampler_noteinitfunc_value
{
- SamplerNoteInitFunc notefunc_voice;
- SamplerNoteInitFunc2 notefunc_prevoice;
- int variant:31;
+ float value;
+ uint32_t curve_id;
+ float step;
unsigned int has_value:1;
- float param;
- // XXXKF no destructor for now - might not be necessary
+ unsigned int has_curve:1;
+ unsigned int has_step:1;
};
enum sampler_noteinitfunc_envelope_variant
@@ -278,6 +304,90 @@ enum sampler_noteinitfunc_envelope_variant
snif_env_start = 6,
};
+#define SAMPLER_COLL_FIELD_LIST_sampler_noteinitfunc(MACRO, ...) \
+ MACRO(value, has_value, float, 0, ## __VA_ARGS__) \
+ MACRO(curve_id, has_curve, int, 0, ## __VA_ARGS__) \
+ MACRO(step, has_step, float, 0, ## __VA_ARGS__)
+
+#define SAMPLER_COLL_CHAIN_LIST_sampler_noteinitfunc(MACRO, ...) \
+ MACRO(voice_nifs, voice_nif, ## __VA_ARGS__) \
+ MACRO(prevoice_nifs, prevoice_nif, ## __VA_ARGS__)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct sampler_cc_range_key
+{
+ uint8_t cc_number;
+};
+
+struct sampler_cc_range_value
+{
+ uint8_t locc;
+ uint8_t hicc;
+ uint8_t has_locc:1;
+ uint8_t has_hicc:1;
+};
+
+#define SAMPLER_COLL_FIELD_LIST_sampler_cc_range(MACRO, ...) \
+ MACRO(locc, has_locc, uint8_t, 0, ## __VA_ARGS__) \
+ MACRO(hicc, has_hicc, uint8_t, 127, ## __VA_ARGS__)
+
+#define SAMPLER_COLL_CHAIN_LIST_sampler_cc_range(MACRO, ...) \
+ MACRO(on_cc, on_cc, ## __VA_ARGS__) \
+ MACRO(cc, cc, ## __VA_ARGS__) \
+ MACRO(xfin_cc, xfin_cc, ## __VA_ARGS__) \
+ MACRO(xfout_cc, xfout_cc, ## __VA_ARGS__)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct sampler_flex_lfo_key
+{
+ uint32_t id;
+};
+
+struct sampler_flex_lfo_value
+{
+ // Note: layout/order must be identical to sampler_lfo_params
+ float freq;
+ float delay;
+ float fade;
+ int wave;
+
+ uint8_t has_freq:1;
+ uint8_t has_delay:1;
+ uint8_t has_fade:1;
+ uint8_t has_wave:1;
+};
+
+#define SAMPLER_COLL_FIELD_LIST_sampler_flex_lfo(MACRO, ...) \
+ MACRO(freq, has_freq, float, 0, ## __VA_ARGS__) \
+ MACRO(delay, has_delay, float, 0, ## __VA_ARGS__) \
+ MACRO(fade, has_fade, float, 0, ## __VA_ARGS__) \
+ MACRO(wave, has_wave, int, 0, ## __VA_ARGS__)
+
+#define SAMPLER_COLL_CHAIN_LIST_sampler_flex_lfo(MACRO, ...) \
+ MACRO(flex_lfos, flex_lfos, ## __VA_ARGS__)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define SAMPLER_COLL_LIST(MACRO) \
+ MACRO(sampler_modulation) \
+ MACRO(sampler_noteinitfunc) \
+ MACRO(sampler_cc_range) \
+ MACRO(sampler_flex_lfo)
+
+#define SAMPLER_COLL_DEFINITION(sname) \
+ struct sname \
+ { \
+ struct sname##_key key; \
+ struct sname##_value value; \
+ struct sname *next; \
+ };
+
+SAMPLER_COLL_LIST(SAMPLER_COLL_DEFINITION)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
struct sampler_lfo_params
{
float freq;
@@ -339,7 +449,6 @@ typedef int midi_note_t;
MACRO(int, fil_veltrack, 0) \
MACRO(int, fil2_veltrack, 0) \
MACRO(int, amp_veltrack, 100) \
- MACRO(int, pitch_veltrack, 0) \
MACRO(int, lovel, 0) \
MACRO(int, hivel, 127) \
MACRO(int, lobend, -8192) \
@@ -448,9 +557,6 @@ typedef int midi_note_t;
#define PROC_SUBSTRUCT_CLONE(name, index, def_value, param, dst, src) \
dst->param.name = src->param.name; \
dst->has_##param.name = src->has_##param.name;
-#define PROC_SUBSTRUCT_CLONEPARENT(name, index, def_value, param, l) \
- if (!l->has_##param.name) \
- l->param.name = parent ? parent->param.name : def_value;
struct sampler_dahdsr_has_fields
{
@@ -467,16 +573,6 @@ struct sampler_eq_has_fields
EQ_FIELDS(PROC_SUBSTRUCT_HAS_FIELD, name)
};
-struct sampler_cc_range
-{
- uint8_t locc;
- uint8_t hicc;
- uint8_t cc_number;
- uint8_t has_locc:1;
- uint8_t has_hicc:1;
- uint8_t is_active:1;
-};
-
struct sampler_midi_curve
{
float values[128];
@@ -501,10 +597,9 @@ struct sampler_midi_curve
#define PROC_FIELDS_TO_STRUCT_eq(name, parname, index) \
struct sampler_eq_params name;
#define PROC_FIELDS_TO_STRUCT_ccrange(name, parname) \
- struct sampler_cc_range name;
+ struct sampler_cc_range *name;
#define PROC_FIELDS_TO_STRUCT_midicurve(name) \
- struct sampler_midi_curve name; \
- float eff_##name[128];
+ struct sampler_midi_curve name;
#define PROC_HAS_FIELD(type, name, def_value) \
unsigned int has_##name:1;
@@ -533,28 +628,40 @@ enum sampler_layer_mod_bitmasks
slmb_pitcheg_cc = 0x04,
};
-struct sampler_layer_data
+struct sampler_layer_computed
{
- SAMPLER_FIXED_FIELDS(PROC_FIELDS_TO_STRUCT)
- SAMPLER_FIXED_FIELDS(PROC_HAS_FIELD)
-
- GSList *modulations;
- GSList *voice_nifs, *prevoice_nifs;
-
// computed values:
- float eff_freq;
- gboolean eff_use_keyswitch;
- gboolean eff_use_simple_trigger_logic;
- enum sampler_loop_mode eff_loop_mode;
struct cbox_waveform *eff_waveform;
+ enum sampler_loop_mode eff_loop_mode;
+ uint32_t eff_loop_start, eff_loop_end;
+ float eff_freq;
+ gboolean eff_use_keyswitch:1;
+ gboolean eff_use_simple_trigger_logic:1;
+ gboolean eff_use_xfcc:1;
+ gboolean eff_use_prevoice:1;
+ gboolean eff_use_channel_mixer:1;
+ gboolean eff_use_filter_mods:1;
+ gboolean eff_is_silent:1;
int16_t scratch_loop[2 * MAX_INTERPOLATION_ORDER * 2];
int16_t scratch_end[2 * MAX_INTERPOLATION_ORDER * 2];
float resonance_scaled, resonance2_scaled;
float logcutoff, logcutoff2;
uint32_t eq_bitmask, mod_bitmask;
- gboolean eff_use_xfcc;
- gboolean use_prevoice;
int eff_num_stages, eff_num_stages2;
+
+ float eff_amp_velcurve[128];
+};
+
+struct sampler_layer_data
+{
+ SAMPLER_FIXED_FIELDS(PROC_FIELDS_TO_STRUCT)
+ SAMPLER_FIXED_FIELDS(PROC_HAS_FIELD)
+
+ struct sampler_modulation *modulations;
+ struct sampler_noteinitfunc *voice_nifs, *prevoice_nifs;
+ struct sampler_flex_lfo *flex_lfos;
+
+ struct sampler_layer_computed computed;
};
struct sampler_layer
diff --git a/template/calfbox/sampler_nif.c b/template/calfbox/sampler_nif.c
index 87821e8..b8c06c2 100644
--- a/template/calfbox/sampler_nif.c
+++ b/template/calfbox/sampler_nif.c
@@ -12,19 +12,20 @@
void sampler_nif_cc2delay(struct sampler_noteinitfunc *nif, struct sampler_prevoice *pv)
{
- pv->delay_computed += nif->param * sampler_channel_getcc_prevoice(pv->channel, pv, nif->variant);
+ float cc = sampler_channel_getcc_prevoice(pv->channel, pv, nif->key.variant, nif->value.curve_id, nif->value.step);
+ pv->delay_computed += nif->value.value * cc;
}
void sampler_nif_addrandomdelay(struct sampler_noteinitfunc *nif, struct sampler_prevoice *pv)
{
- pv->delay_computed += nif->param * rand() * (1.0 / RAND_MAX);
+ pv->delay_computed += nif->value.value * rand() * (1.0 / RAND_MAX);
}
void sampler_nif_syncbeats(struct sampler_noteinitfunc *nif, struct sampler_prevoice *pv)
{
- if (nif->param > 0)
+ if (nif->value.value > 0)
{
- pv->sync_beats = nif->param;
+ pv->sync_beats = nif->value.value;
double cur_beat = sampler_get_current_beat(pv->channel->module);
pv->sync_initial_time = cur_beat;
double cur_rel_beat = fmod(cur_beat, pv->sync_beats);
@@ -39,42 +40,42 @@ void sampler_nif_syncbeats(struct sampler_noteinitfunc *nif, struct sampler_prev
void sampler_nif_vel2pitch(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
- v->pitch_shift += nif->param * v->vel * (1.0 / 127.0);
+ v->pitch_shift += nif->value.value * v->vel * (1.0 / 127.0);
}
void sampler_nif_vel2offset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
- v->offset += nif->param * v->vel * (1.0 / 127.0);
+ v->offset += nif->value.value * v->vel * (1.0 / 127.0);
}
void sampler_nif_cc2offset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
- v->offset += nif->param * sampler_channel_getcc(v->channel, v, nif->variant);
+ v->offset += nif->value.value * sampler_channel_getcc_mod(v->channel, v, nif->key.variant, nif->value.curve_id, nif->value.step);
}
void sampler_nif_vel2reloffset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
- v->reloffset += nif->param * v->vel * (1.0 / 127.0);
+ v->reloffset += nif->value.value * v->vel * (1.0 / 127.0);
}
void sampler_nif_cc2reloffset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
- v->reloffset += nif->param * sampler_channel_getcc(v->channel, v, nif->variant);
+ v->reloffset += nif->value.value * sampler_channel_getcc_mod(v->channel, v, nif->key.variant, nif->value.curve_id, nif->value.step);
}
void sampler_nif_addrandom(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
float rnd = rand() * 1.0 / RAND_MAX;
- switch(nif->variant)
+ switch(nif->key.variant)
{
case 0:
- v->gain_shift += rnd * nif->param;
+ v->gain_shift += rnd * nif->value.value;
break;
case 1:
- v->cutoff_shift += rnd * nif->param;
+ v->cutoff_shift += rnd * nif->value.value;
break;
case 2:
- v->pitch_shift += rnd * nif->param; // this is in cents
+ v->pitch_shift += rnd * nif->value.value; // this is in cents
break;
}
}
@@ -102,7 +103,7 @@ static void modify_env_stage_by_nif(struct sampler_noteinitfunc *nif, struct sam
memcpy(&v->vel_envs[env_type], env->shape, sizeof(struct cbox_envelope_shape));
env->shape = &v->vel_envs[env_type];
}
- float param = nif->param * value;
+ float param = nif->value.value * value;
if ((variant & 15) == snif_env_sustain || (variant & 15) == snif_env_start)
param *= 0.01;
cbox_envelope_modify_dahdsr(env->shape, variant & 15, param, v->channel->module->module.srate * (1.0 / CBOX_BLOCK_SIZE));
@@ -110,5 +111,5 @@ static void modify_env_stage_by_nif(struct sampler_noteinitfunc *nif, struct sam
void sampler_nif_vel2env(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
- modify_env_stage_by_nif(nif, v, nif->variant, v->vel * (1.0 / 127.0));
+ modify_env_stage_by_nif(nif, v, nif->key.variant, v->vel * (1.0 / 127.0));
}
diff --git a/template/calfbox/sampler_prevoice.c b/template/calfbox/sampler_prevoice.c
index 30b52d2..7089550 100644
--- a/template/calfbox/sampler_prevoice.c
+++ b/template/calfbox/sampler_prevoice.c
@@ -20,13 +20,8 @@ void sampler_prevoice_start(struct sampler_prevoice *pv, struct sampler_channel
pv->sync_initial_time = -1;
pv->sync_trigger_time = -1;
- GSList *nif = pv->layer_data->prevoice_nifs;
- while(nif)
- {
- struct sampler_noteinitfunc *p = nif->data;
- p->notefunc_prevoice(p, pv);
- nif = nif->next;
- }
+ for(struct sampler_noteinitfunc *nif = pv->layer_data->prevoice_nifs; nif; nif = nif->next)
+ nif->key.notefunc_prevoice(nif, pv);
sampler_prevoice_unlink(&channel->module->prevoices_free, pv);
sampler_prevoice_link(&channel->module->prevoices_running, pv);
}
diff --git a/template/calfbox/sampler_prg.c b/template/calfbox/sampler_prg.c
index 1220e99..c8cc81c 100644
--- a/template/calfbox/sampler_prg.c
+++ b/template/calfbox/sampler_prg.c
@@ -40,10 +40,10 @@ retry:
struct sampler_layer *lr = iter->next_layer->data;
struct sampler_layer_data *l = lr->runtime;
iter->next_layer = g_slist_next(iter->next_layer);
- if (!l->eff_waveform)
+ if (!l->computed.eff_waveform)
continue;
- if (l->eff_use_simple_trigger_logic)
+ if (l->computed.eff_use_simple_trigger_logic)
{
if (iter->note >= l->lokey && iter->note <= l->hikey &&
iter->vel >= l->lovel && iter->vel <= l->hivel)
@@ -56,7 +56,6 @@ retry:
(l->trigger == stm_legato && iter->is_first) ||
(l->trigger == stm_release && !iter->is_release)) // sw_last keyswitches are still added to the note-on list in RLL
continue;
- int ccval = -1;
struct sampler_channel *c = iter->channel;
struct sampler_module *m = c->module;
if (iter->note >= l->lokey && iter->note <= l->hikey &&
@@ -67,9 +66,9 @@ retry:
c->last_chanaft >= l->lochanaft && c->last_chanaft <= l->hichanaft &&
c->last_polyaft >= l->lopolyaft && c->last_polyaft <= l->hipolyaft &&
c->module->module.engine->master->tempo >= l->lobpm && c->module->module.engine->master->tempo < l->hibpm &&
- (!l->cc.is_active || (ccval = sampler_channel_getintcc(c, NULL, l->cc.cc_number), ccval >= l->cc.locc && ccval <= l->cc.hicc)))
+ sampler_cc_range_is_in(l->cc, c))
{
- if (!l->eff_use_keyswitch ||
+ if (!l->computed.eff_use_keyswitch ||
((l->sw_down == -1 || (c->switchmask[l->sw_down >> 5] & (1 << (l->sw_down & 31)))) &&
(l->sw_up == -1 || !(c->switchmask[l->sw_up >> 5] & (1 << (l->sw_up & 31)))) &&
(l->sw_previous == -1 || l->sw_previous == c->previous_note)))
@@ -414,7 +413,7 @@ struct sampler_program *sampler_program_new_from_cfg(struct sampler_module *m, c
else
{
sampler_layer_update(l);
- if (!l->data.eff_waveform)
+ if (!l->data.computed.eff_waveform)
{
g_warning("Sample layer '%s' does not have a waveform - skipping", layer_section);
CBOX_DELETE((struct sampler_layer *)l);
@@ -443,7 +442,7 @@ struct sampler_program *sampler_program_new_from_cfg(struct sampler_module *m, c
else
{
sampler_layer_update(l);
- if (!l->data.eff_waveform)
+ if (!l->data.computed.eff_waveform)
{
g_warning("Sample layer '%s' does not have a waveform - skipping", layer_section);
CBOX_DELETE((struct sampler_layer *)l);
diff --git a/template/calfbox/sampler_rll.c b/template/calfbox/sampler_rll.c
index 6f392bc..7e8198f 100644
--- a/template/calfbox/sampler_rll.c
+++ b/template/calfbox/sampler_rll.c
@@ -132,11 +132,16 @@ struct sampler_rll *sampler_rll_new_from_program(struct sampler_program *prg)
ks_offset = ks->group_offset + rel_offset;
}
- if (l->data.on_cc.is_active)
+ struct sampler_cc_range *oncc = l->data.on_cc;
+ if (oncc)
{
- int cc = l->data.on_cc.cc_number;
rll->layers_oncc = g_slist_prepend(rll->layers_oncc, l);
- rll->cc_trigger_bitmask[cc >> 5] |= 1 << (cc & 31);
+ while(oncc)
+ {
+ int cc = oncc->key.cc_number;
+ rll->cc_trigger_bitmask[cc >> 5] |= 1 << (cc & 31);
+ oncc = oncc->next;
+ }
}
if (l->data.trigger == stm_release)
add_layers(rll, rll->release_layers_by_range + ks_offset * range_count, l, l->data.lokey, l->data.hikey);
diff --git a/template/calfbox/sampler_voice.c b/template/calfbox/sampler_voice.c
index 66f37ef..b31f8a5 100644
--- a/template/calfbox/sampler_voice.c
+++ b/template/calfbox/sampler_voice.c
@@ -118,14 +118,14 @@ static inline float lfo_run(struct sampler_lfo *lfo)
static gboolean is_tail_finished(struct sampler_voice *v)
{
- if (!v->layer->eff_num_stages)
+ if (!v->layer->computed.eff_num_stages)
return TRUE;
double eps = 1.0 / 65536.0;
if (cbox_biquadf_is_audible(&v->filter.filter_left[0], eps))
return FALSE;
if (cbox_biquadf_is_audible(&v->filter.filter_right[0], eps))
return FALSE;
- int num_stages = v->layer->eff_num_stages;
+ int num_stages = v->layer->computed.eff_num_stages;
if (num_stages > 1)
{
if (cbox_biquadf_is_audible(&v->filter.filter_left[num_stages - 1], eps))
@@ -259,7 +259,13 @@ void sampler_voice_activate(struct sampler_voice *v, enum sampler_player_type mo
sampler_voice_link(&v->channel->voices_running, v);
}
-void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, struct sampler_layer_data *l, int note, int vel, int *exgroups, int *pexgroupcount)
+void sampler_voice_start_silent(struct sampler_layer_data *l, struct sampler_released_groups *exgroupdata)
+{
+ if (l->group >= 1)
+ sampler_released_groups_add(exgroupdata, l->group);
+}
+
+void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, struct sampler_layer_data *l, int note, int vel, struct sampler_released_groups *exgroupdata)
{
struct sampler_module *m = c->module;
sampler_gen_reset(&v->gen);
@@ -274,18 +280,18 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
if (age * l->rt_decay > 84)
return;
}
- uint32_t end = l->eff_waveform->info.frames;
+ uint32_t end = l->computed.eff_waveform->info.frames;
if (l->end != 0)
end = (l->end == SAMPLER_NO_LOOP) ? 0 : l->end;
- v->last_waveform = l->eff_waveform;
+ v->last_waveform = l->computed.eff_waveform;
v->gen.cur_sample_end = end;
- if (end > l->eff_waveform->info.frames)
- end = l->eff_waveform->info.frames;
+ if (end > l->computed.eff_waveform->info.frames)
+ end = l->computed.eff_waveform->info.frames;
assert(!v->current_pipe);
- if (end > l->eff_waveform->preloaded_frames)
+ if (end > l->computed.eff_waveform->preloaded_frames)
{
- if (l->eff_loop_mode == slm_loop_continuous && l->loop_end < l->eff_waveform->preloaded_frames)
+ if (l->computed.eff_loop_mode == slm_loop_continuous && l->computed.eff_loop_end < l->computed.eff_waveform->preloaded_frames)
{
// Everything fits in prefetch, because loop ends in prefetch and post-loop part is not being played
}
@@ -294,17 +300,17 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
uint32_t loop_start = -1, loop_end = end;
// If in loop mode, set the loop over the looped part... unless we're doing sustain-only loop on prefetch area only. Then
// streaming will only cover the release part, and it shouldn't be looped.
- if (l->eff_loop_mode == slm_loop_continuous || (l->eff_loop_mode == slm_loop_sustain && l->loop_end >= l->eff_waveform->preloaded_frames))
+ if (l->computed.eff_loop_mode == slm_loop_continuous || (l->computed.eff_loop_mode == slm_loop_sustain && l->computed.eff_loop_end >= l->computed.eff_waveform->preloaded_frames))
{
- loop_start = l->loop_start;
- loop_end = l->loop_end;
+ loop_start = l->computed.eff_loop_start;
+ loop_end = l->computed.eff_loop_end;
}
// Those are initial values only, they will be adjusted in process function
- v->current_pipe = cbox_prefetch_stack_pop(m->pipe_stack, l->eff_waveform, loop_start, loop_end, l->count);
+ v->current_pipe = cbox_prefetch_stack_pop(m->pipe_stack, l->computed.eff_waveform, loop_start, loop_end, l->count);
if (!v->current_pipe)
{
g_warning("Prefetch pipe pool exhausted, no streaming playback will be possible");
- end = l->eff_waveform->preloaded_frames;
+ end = l->computed.eff_waveform->preloaded_frames;
v->gen.cur_sample_end = end;
}
}
@@ -315,7 +321,7 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
v->gen.loop_overlap = l->loop_overlap;
v->gen.loop_overlap_step = l->loop_overlap > 0 ? 1.0 / l->loop_overlap : 0;
- v->gain_fromvel = l->eff_amp_velcurve[vel];
+ v->gain_fromvel = l->computed.eff_amp_velcurve[vel];
v->gain_shift = (note - l->amp_keycenter) * l->amp_keytrack;
v->gain_fromvel *= sfz_crossfade(note, l->xfin_lokey, l->xfin_hikey, l->xfout_lokey, l->xfout_hikey, l->xf_keycurve);
@@ -338,7 +344,7 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
v->cutoff_shift = vel * l->fil_veltrack / 127.0 + (note - l->fil_keycenter) * l->fil_keytrack;
v->cutoff2_shift = vel * l->fil2_veltrack / 127.0 + (note - l->fil2_keycenter) * l->fil2_keytrack;
- v->loop_mode = l->eff_loop_mode;
+ v->loop_mode = l->computed.eff_loop_mode;
v->off_by = l->off_by;
v->reloffset = l->reloffset;
int auxes = (m->module.outputs - m->module.aux_offset) / 2;
@@ -352,21 +358,9 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
v->send2bus = 0;
v->send1gain = l->effect1 * 0.01;
v->send2gain = l->effect2 * 0.01;
- if (l->group >= 1 && *pexgroupcount < MAX_RELEASED_GROUPS)
+ if (l->group >= 1)
{
- gboolean found = FALSE;
- for (int j = 0; j < *pexgroupcount; j++)
- {
- if (exgroups[j] == l->group)
- {
- found = TRUE;
- break;
- }
- }
- if (!found)
- {
- exgroups[(*pexgroupcount)++] = l->group;
- }
+ sampler_released_groups_add(exgroupdata, l->group);
}
lfo_init(&v->amp_lfo, &l->amp_lfo, m->module.srate, m->module.srate_inv);
lfo_init(&v->filter_lfo, &l->filter_lfo, m->module.srate, m->module.srate_inv);
@@ -386,13 +380,8 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
cbox_onepolef_set_highshelf_tonectl(&v->onepole_coeffs, l->tonectl_freq * M_PI * m->module.srate_inv, 1.0);
v->offset = l->offset;
- GSList *nif = v->layer->voice_nifs;
- while(nif)
- {
- struct sampler_noteinitfunc *p = nif->data;
- p->notefunc_voice(p, v);
- nif = nif->next;
- }
+ for(struct sampler_noteinitfunc *nif = v->layer->voice_nifs; nif; nif = nif->next)
+ nif->key.notefunc_voice(nif, v);
if (v->gain_shift)
v->gain_fromvel *= dB2gain(v->gain_shift);
@@ -400,7 +389,7 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
{
// For streamed samples, allow only half the preload period worth of offset to avoid gaps
// (maybe we can allow up to preload period minus one buffer size here?)
- uint32_t maxend = v->current_pipe ? (l->eff_waveform->preloaded_frames >> 1) : l->eff_waveform->preloaded_frames;
+ uint32_t maxend = v->current_pipe ? (l->computed.eff_waveform->preloaded_frames >> 1) : l->computed.eff_waveform->preloaded_frames;
int32_t pos = v->offset + v->reloffset * maxend * 0.01;
if (pos < 0)
pos = 0;
@@ -415,7 +404,7 @@ void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, str
v->last_eq_bitmask = 0;
- sampler_voice_activate(v, l->eff_waveform->info.channels == 2 ? spt_stereo16 : spt_mono16);
+ sampler_voice_activate(v, l->computed.eff_waveform->info.channels == 2 ? spt_stereo16 : spt_mono16);
uint32_t pos = v->offset;
if (l->offset_random)
@@ -557,6 +546,41 @@ static inline void sampler_filter_process_audio(struct sampler_filter *f, int nu
cbox_biquadf_process_stereo(&f->filter_left[i], &f->filter_right[i], i ? f->second_filter : &f->filter_coeffs, leftright);
}
+static inline void do_channel_mixing(float *leftright, uint32_t numsamples, float position, float width)
+{
+ float crossmix = (100.0 - width) * 0.005f;
+ float amtleft = position > 0 ? 1 - 0.01 * position : 1;
+ float amtright = position < 0 ? 1 - 0.01 * -position : 1;
+ if (amtleft < 0)
+ amtleft = 0;
+ if (amtright < 0)
+ amtright = 0;
+ for (uint32_t i = 0; i < 2 * numsamples; i += 2) {
+ float left = leftright[i], right = leftright[i + 1];
+ float newleft = left + crossmix * (right - left);
+ float newright = right + crossmix * (left - right);
+ leftright[i] = newleft * amtleft;
+ leftright[i + 1] = newright * amtright;
+ }
+}
+
+static inline uint32_t sampler_gen_sample_playback_with_pipe(struct sampler_gen *gen, float *leftright, struct cbox_prefetch_pipe *current_pipe)
+{
+ if (!current_pipe)
+ return sampler_gen_sample_playback(gen, leftright, (uint32_t)-1);
+
+ uint32_t limit = cbox_prefetch_pipe_get_remaining(current_pipe);
+ if (limit <= 4)
+ {
+ gen->mode = spt_inactive;
+ return 0;
+ }
+ uint32_t samples = sampler_gen_sample_playback(gen, leftright, limit - 4);
+ cbox_prefetch_pipe_consumed(current_pipe, gen->consumed);
+ gen->consumed = 0;
+ return samples;
+}
+
static const float gain_for_num_stages[] = { 1, 1, 0.5, 0.33f };
void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cbox_sample_t **outputs)
@@ -570,10 +594,10 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
const float velscl = v->vel * (1.f / 127.f);
struct cbox_envelope_shape *pitcheg_shape = v->pitch_env.shape, *fileg_shape = v->filter_env.shape, *ampeg_shape = v->amp_env.shape;
- if (__builtin_expect(l->mod_bitmask, 0))
+ if (__builtin_expect(l->computed.mod_bitmask, 0))
{
#define COPY_ORIG_SHAPE(envtype, envtype2, index) \
- if (l->mod_bitmask & slmb_##envtype2##eg_cc) { \
+ if (l->computed.mod_bitmask & slmb_##envtype2##eg_cc) { \
memcpy(&v->cc_envs[index], envtype2##eg_shape, sizeof(struct cbox_envelope_shape)); \
envtype2##eg_shape = &v->cc_envs[index]; \
}
@@ -581,24 +605,21 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
COPY_ORIG_SHAPE(filter, fil, 1)
COPY_ORIG_SHAPE(pitch, pitch, 2)
- GSList *mod = l->modulations;
- while(mod)
+ for(struct sampler_modulation *sm = l->modulations; sm; sm = sm->next)
{
// Simplified modulations for EG stages (CCs only)
- struct sampler_modulation *sm = mod->data;
- if (sm->dest >= smdest_eg_stage_start && sm->dest <= smdest_eg_stage_end)
+ if (sm->key.dest >= smdest_eg_stage_start && sm->key.dest <= smdest_eg_stage_end)
{
float value = 0.f;
- if (sm->src < smsrc_pernote_offset)
- value = sampler_channel_getcc_mod(c, v, sm->src, sm);
- uint32_t param = sm->dest - smdest_eg_stage_start;
- if (value * sm->amount != 0)
- cbox_envelope_modify_dahdsr(&v->cc_envs[(param >> 4)], param & 0x0F, value * sm->amount, m->module.srate * 1.0 / CBOX_BLOCK_SIZE);
+ if (sm->key.src < smsrc_pernote_offset)
+ value = sampler_channel_getcc_mod(c, v, sm->key.src, sm->value.curve_id, sm->value.step);
+ uint32_t param = sm->key.dest - smdest_eg_stage_start;
+ if (value * sm->value.amount != 0)
+ cbox_envelope_modify_dahdsr(&v->cc_envs[(param >> 4)], param & 0x0F, value * sm->value.amount, m->module.srate * 1.0 / CBOX_BLOCK_SIZE);
}
- mod = g_slist_next(mod);
}
#define UPDATE_ENV_POSITION(envtype, envtype2) \
- if (l->mod_bitmask & slmb_##envtype##eg_cc) \
+ if (l->computed.mod_bitmask & slmb_##envtype##eg_cc) \
cbox_envelope_update_shape_after_modify(&v->envtype2##_env, envtype##eg_shape, m->module.srate * 1.0 / CBOX_BLOCK_SIZE);
UPDATE_ENV_POSITION(amp, amp)
UPDATE_ENV_POSITION(fil, filter)
@@ -618,13 +639,13 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
if (__builtin_expect(v->layer_changed, 0))
{
v->last_level = -1;
- if (v->last_waveform != v->layer->eff_waveform)
+ if (v->last_waveform != v->layer->computed.eff_waveform)
{
- v->last_waveform = v->layer->eff_waveform;
- if (v->layer->eff_waveform)
+ v->last_waveform = v->layer->computed.eff_waveform;
+ if (v->layer->computed.eff_waveform)
{
- v->gen.mode = v->layer->eff_waveform->info.channels == 2 ? spt_stereo16 : spt_mono16;
- v->gen.cur_sample_end = v->layer->eff_waveform->info.frames;
+ v->gen.mode = v->layer->computed.eff_waveform->info.channels == 2 ? spt_stereo16 : spt_mono16;
+ v->gen.cur_sample_end = v->layer->computed.eff_waveform->info.frames;
}
else
{
@@ -632,36 +653,27 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
return;
}
}
- if (l->eq_bitmask & (1 << 0)) recalc_eq_mask |= RECALC_EQ_MASK_EQ1;
- if (l->eq_bitmask & (1 << 1)) recalc_eq_mask |= RECALC_EQ_MASK_EQ2;
- if (l->eq_bitmask & (1 << 2)) recalc_eq_mask |= RECALC_EQ_MASK_EQ3;
- v->last_eq_bitmask = l->eq_bitmask;
+ if (l->computed.eq_bitmask & (1 << 0)) recalc_eq_mask |= RECALC_EQ_MASK_EQ1;
+ if (l->computed.eq_bitmask & (1 << 1)) recalc_eq_mask |= RECALC_EQ_MASK_EQ2;
+ if (l->computed.eq_bitmask & (1 << 2)) recalc_eq_mask |= RECALC_EQ_MASK_EQ3;
+ v->last_eq_bitmask = l->computed.eq_bitmask;
v->layer_changed = FALSE;
}
- float pitch = (v->note - l->pitch_keycenter) * l->pitch_keytrack + velscl * l->pitch_veltrack + l->tune + l->transpose * 100 + v->pitch_shift;
+ float pitch = (v->note - l->pitch_keycenter) * l->pitch_keytrack + l->tune + l->transpose * 100 + v->pitch_shift;
float modsrcs[smsrc_pernote_count];
modsrcs[smsrc_vel - smsrc_pernote_offset] = v->vel * velscl;
modsrcs[smsrc_pitch - smsrc_pernote_offset] = pitch * (1.f / 100.f);
modsrcs[smsrc_chanaft - smsrc_pernote_offset] = c->last_chanaft * (1.f / 127.f);
modsrcs[smsrc_polyaft - smsrc_pernote_offset] = sampler_channel_get_poly_pressure(c, v->note);
modsrcs[smsrc_pitchenv - smsrc_pernote_offset] = cbox_envelope_get_value(&v->pitch_env, pitcheg_shape) * 0.01f;
- modsrcs[smsrc_filenv - smsrc_pernote_offset] = cbox_envelope_get_value(&v->filter_env, fileg_shape) * 0.01f;
+ modsrcs[smsrc_filenv - smsrc_pernote_offset] = l->computed.eff_use_filter_mods ? cbox_envelope_get_value(&v->filter_env, fileg_shape) * 0.01f : 0;
modsrcs[smsrc_ampenv - smsrc_pernote_offset] = cbox_envelope_get_value(&v->amp_env, ampeg_shape) * 0.01f;
modsrcs[smsrc_amplfo - smsrc_pernote_offset] = lfo_run(&v->amp_lfo);
- modsrcs[smsrc_fillfo - smsrc_pernote_offset] = lfo_run(&v->filter_lfo);
+ modsrcs[smsrc_fillfo - smsrc_pernote_offset] = l->computed.eff_use_filter_mods ? lfo_run(&v->filter_lfo) : 0;
modsrcs[smsrc_pitchlfo - smsrc_pernote_offset] = lfo_run(&v->pitch_lfo);
- if (__builtin_expect(v->amp_env.cur_stage < 0, 0))
- {
- if (__builtin_expect(is_tail_finished(v), 0))
- {
- sampler_voice_inactivate(v, TRUE);
- return;
- }
- }
-
float moddests[smdestcount];
moddests[smdest_pitch] = pitch;
moddests[smdest_cutoff] = v->cutoff_shift;
@@ -677,7 +689,6 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
moddests[smdest_fillfo_freq] = 0;
moddests[smdest_amplfo_freq] = 0;
#endif
- GSList *mod = l->modulations;
if (__builtin_expect(l->trigger == stm_release, 0))
{
moddests[smdest_gain] = -v->age * l->rt_decay * m->module.srate_inv;
@@ -697,38 +708,50 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
moddests[smdest_pitch] += pw;
}
- while(mod)
+ for (struct sampler_modulation *sm = l->modulations; sm; sm = sm->next)
{
- struct sampler_modulation *sm = mod->data;
+ enum sampler_modsrc src = sm->key.src;
+ enum sampler_modsrc src2 = sm->key.src2;
+ enum sampler_moddest dest = sm->key.dest;
float value = 0.f, value2 = 1.f;
- if (sm->src < smsrc_pernote_offset)
- value = sampler_channel_getcc_mod(c, v, sm->src, sm);
+ if (src < smsrc_pernote_offset)
+ value = sampler_channel_getcc_mod(c, v, src, sm->value.curve_id, sm->value.step);
else
- value = modsrcs[sm->src - smsrc_pernote_offset];
+ value = modsrcs[src - smsrc_pernote_offset];
- if (sm->src2 != smsrc_none)
+ if (src2 != smsrc_none)
{
- if (sm->src2 < smsrc_pernote_offset)
- value2 = sampler_channel_getcc_mod(c, v, sm->src2, sm);
+ if (src2 < smsrc_pernote_offset)
+ value2 = sampler_channel_getcc_mod(c, v, src2, sm->value.curve_id, sm->value.step);
else
- value2 = modsrcs[sm->src2 - smsrc_pernote_offset];
+ value2 = modsrcs[src2 - smsrc_pernote_offset];
value *= value2;
}
- if (sm->dest < 32)
+ if (dest < 32)
{
- if (!(modmask & (1 << sm->dest))) // first value
+ if (dest == smdest_amplitude)
+ {
+ if (!(modmask & (1 << dest))) // first value
+ {
+ moddests[dest] = value * sm->value.amount;
+ modmask |= (1 << dest);
+ }
+ else
+ moddests[dest] *= value * sm->value.amount;
+ }
+ else if (!(modmask & (1 << dest))) // first value
{
- moddests[sm->dest] = value * sm->amount;
- modmask |= (1 << sm->dest);
+ moddests[dest] = value * sm->value.amount;
+ modmask |= (1 << dest);
}
else
- moddests[sm->dest] += value * sm->amount;
+ moddests[dest] += value * sm->value.amount;
}
- mod = g_slist_next(mod);
}
lfo_update_xdelta(m, &v->pitch_lfo, modmask, smdest_pitchlfo_freq, moddests);
- lfo_update_xdelta(m, &v->filter_lfo, modmask, smdest_fillfo_freq, moddests);
+ if (l->computed.eff_use_filter_mods)
+ lfo_update_xdelta(m, &v->filter_lfo, modmask, smdest_fillfo_freq, moddests);
lfo_update_xdelta(m, &v->amp_lfo, modmask, smdest_amplfo_freq, moddests);
recalc_eq_mask |= modmask;
@@ -752,11 +775,20 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
RECALC_EQ_IF(3)
}
cbox_envelope_advance(&v->pitch_env, v->released, pitcheg_shape);
- cbox_envelope_advance(&v->filter_env, v->released, fileg_shape);
+ if (l->computed.eff_use_filter_mods)
+ cbox_envelope_advance(&v->filter_env, v->released, fileg_shape);
cbox_envelope_advance(&v->amp_env, v->released, ampeg_shape);
+ if (__builtin_expect(v->amp_env.cur_stage < 0, 0))
+ {
+ if (__builtin_expect(is_tail_finished(v), 0))
+ {
+ sampler_voice_inactivate(v, TRUE);
+ return;
+ }
+ }
double maxv = 127 << 7;
- double freq = l->eff_freq * cent2factor(moddests[smdest_pitch]) ;
+ double freq = l->computed.eff_freq * cent2factor(moddests[smdest_pitch]) ;
uint64_t freq64 = (uint64_t)(freq * 65536.0 * 65536.0 * m->module.srate_inv);
gboolean playing_sustain_loop = !v->released && v->loop_mode == slm_loop_sustain;
@@ -794,9 +826,9 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
}
// XXXKF or maybe check for on-cc being in the on-cc range instead?
- gboolean play_loop = v->layer->loop_end && (v->loop_mode == slm_loop_continuous || playing_sustain_loop) && !v->layer->on_cc.is_active;
- loop_start = play_loop ? v->layer->loop_start : (v->layer->count ? 0 : (uint32_t)-1);
- loop_end = play_loop ? v->layer->loop_end : v->gen.cur_sample_end;
+ gboolean play_loop = v->layer->computed.eff_loop_end && (v->loop_mode == slm_loop_continuous || playing_sustain_loop) && !v->layer->on_cc;
+ loop_start = play_loop ? v->layer->computed.eff_loop_start : (v->layer->count ? 0 : (uint32_t)-1);
+ loop_end = play_loop ? v->layer->computed.eff_loop_end : v->gen.cur_sample_end;
if (v->current_pipe)
{
@@ -828,7 +860,7 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
if (!bandlimited)
{
// Use pre-calculated join
- v->gen.scratch = loop_start == (uint32_t)-1 ? v->layer->scratch_end : v->layer->scratch_loop;
+ v->gen.scratch = loop_start == (uint32_t)-1 ? v->layer->computed.scratch_end : v->layer->computed.scratch_loop;
}
else
{
@@ -837,14 +869,14 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
// (i.e. partial loop or no loop) over bandlimited versions of the standard waveforms, and those are probably
// not very useful anyway, as changing the loop removes the guarantee of the waveform being bandlimited and
// may cause looping artifacts or introduce DC offset (e.g. if only a positive part of a sine wave is looped).
- if (loop_start == 0 && loop_end == l->eff_waveform->info.frames)
- v->gen.scratch = v->gen.sample_data + l->eff_waveform->info.frames - MAX_INTERPOLATION_ORDER;
+ if (loop_start == 0 && loop_end == l->computed.eff_waveform->info.frames)
+ v->gen.scratch = v->gen.sample_data + l->computed.eff_waveform->info.frames - MAX_INTERPOLATION_ORDER;
else
{
// Generate the join for the current wave level
// XXXKF this could be optimised further, by checking if waveform and loops are the same as the last
// time. However, this code is not likely to be used... ever, so optimising it is not the priority.
- int shift = l->eff_waveform->info.channels == 2 ? 1 : 0;
+ int shift = l->computed.eff_waveform->info.channels == 2 ? 1 : 0;
uint32_t halfscratch = MAX_INTERPOLATION_ORDER << shift;
v->gen.scratch = v->gen.scratch_bandlimited;
@@ -860,7 +892,7 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
if (l->timestretch)
{
v->gen.bigdelta = freq64;
- v->gen.virtdelta = (uint64_t)(l->eff_freq * 65536.0 * 65536.0 * m->module.srate_inv);
+ v->gen.virtdelta = (uint64_t)(l->computed.eff_freq * 65536.0 * 65536.0 * m->module.srate_inv);
v->gen.stretching_jump = l->timestretch_jump;
v->gen.stretching_crossfade = l->timestretch_crossfade;
}
@@ -870,17 +902,18 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
v->gen.virtdelta = freq64;
}
float gain = modsrcs[smsrc_ampenv - smsrc_pernote_offset] * l->volume_linearized * v->gain_fromvel * c->channel_volume_cc * sampler_channel_addcc(c, 11) / (maxv * maxv);
- if (l->eff_use_xfcc) {
- gain *=
- (l->xfin_cc.is_active ? sfz_crossfade2(c->intcc[l->xfin_cc.cc_number], l->xfin_cc.locc, l->xfin_cc.hicc, 0, 1, l->xf_cccurve) : 1.f) *
- (l->xfout_cc.is_active ? sfz_crossfade2(c->intcc[l->xfout_cc.cc_number], l->xfout_cc.locc, l->xfout_cc.hicc, 1, 0, l->xf_cccurve) : 1.f);
+ if (l->computed.eff_use_xfcc) {
+ for(struct sampler_cc_range *p = l->xfin_cc; p; p = p->next)
+ gain *= sfz_crossfade2(c->intcc[p->key.cc_number], p->value.locc, p->value.hicc, 0, 1, l->xf_cccurve);
+ for(struct sampler_cc_range *p = l->xfout_cc; p; p = p->next)
+ gain *= sfz_crossfade2(c->intcc[p->key.cc_number], p->value.locc, p->value.hicc, 1, 0, l->xf_cccurve);
}
if ((modmask & (1 << smdest_gain)) && moddests[smdest_gain] != 0.f)
gain *= dB2gain(moddests[smdest_gain]);
float amplitude = l->amplitude;
if ((modmask & (1 << smdest_amplitude)))
- amplitude += moddests[smdest_amplitude];
+ amplitude *= moddests[smdest_amplitude];
gain *= amplitude * (1.0 / 100.0);
// http://drealm.info/sfz/plj-sfz.xhtml#amp "The overall gain must remain in the range -144 to 6 decibels."
@@ -896,13 +929,13 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
if (l->cutoff != -1)
{
- float mod_resonance = (modmask & (1 << smdest_resonance)) ? dB2gain(gain_for_num_stages[l->eff_num_stages] * moddests[smdest_resonance]) : 1;
- sampler_filter_process_control(&v->filter, l->fil_type, l->logcutoff + moddests[smdest_cutoff], l->resonance_scaled * mod_resonance, m->sincos);
+ float mod_resonance = (modmask & (1 << smdest_resonance)) ? dB2gain(gain_for_num_stages[l->computed.eff_num_stages] * moddests[smdest_resonance]) : 1;
+ sampler_filter_process_control(&v->filter, l->fil_type, l->computed.logcutoff + moddests[smdest_cutoff], l->computed.resonance_scaled * mod_resonance, m->sincos);
}
if (l->cutoff2 != -1)
{
- float mod_resonance = (modmask & (1 << smdest_resonance2)) ? dB2gain(gain_for_num_stages[l->eff_num_stages2] * moddests[smdest_resonance2]) : 1;
- sampler_filter_process_control(&v->filter2, l->fil2_type, l->logcutoff2 + moddests[smdest_cutoff2], l->resonance2_scaled * mod_resonance, m->sincos);
+ float mod_resonance = (modmask & (1 << smdest_resonance2)) ? dB2gain(gain_for_num_stages[l->computed.eff_num_stages2] * moddests[smdest_resonance2]) : 1;
+ sampler_filter_process_control(&v->filter2, l->fil2_type, l->computed.logcutoff2 + moddests[smdest_cutoff2], l->computed.resonance2_scaled * mod_resonance, m->sincos);
}
if (__builtin_expect(l->tonectl_freq != 0, 0))
@@ -913,60 +946,29 @@ void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cb
else
cbox_onepolef_set_highshelf_setgain(&v->onepole_coeffs, 1.0);
}
-
+
+ // Audio processing starts here
float leftright[2 * CBOX_BLOCK_SIZE];
- uint32_t samples = 0;
-
- if (v->current_pipe)
- {
- uint32_t limit = cbox_prefetch_pipe_get_remaining(v->current_pipe);
- if (limit <= 4)
- v->gen.mode = spt_inactive;
- else
- {
- samples = sampler_gen_sample_playback(&v->gen, leftright, limit - 4);
- cbox_prefetch_pipe_consumed(v->current_pipe, v->gen.consumed);
- v->gen.consumed = 0;
- }
- }
- else
- {
- samples = sampler_gen_sample_playback(&v->gen, leftright, (uint32_t)-1);
- }
-
- if (l->position != 0 || l->width != 100) {
- float crossmix = (100.0 - l->width) * 0.005f;
- float amtleft = l->position > 0 ? 1 - 0.01 * l->position : 1;
- float amtright = l->position < 0 ? 1 - 0.01 * -l->position : 1;
- if (amtleft < 0)
- amtleft = 0;
- if (amtright < 0)
- amtright = 0;
- for (uint32_t i = 0; i < 2 * samples; i += 2) {
- float left = leftright[i], right = leftright[i + 1];
- float newleft = left + crossmix * (right - left);
- float newright = right + crossmix * (left - right);
- leftright[i] = newleft * amtleft;
- leftright[i + 1] = newright * amtright;
- }
- }
+ uint32_t samples = sampler_gen_sample_playback_with_pipe(&v->gen, leftright, v->current_pipe);
+ if (l->computed.eff_use_channel_mixer)
+ do_channel_mixing(leftright, samples, l->position, l->width);
for (int i = 2 * samples; i < 2 * CBOX_BLOCK_SIZE; i++)
leftright[i] = 0.f;
if (l->cutoff != -1)
- sampler_filter_process_audio(&v->filter, l->eff_num_stages, leftright);
+ sampler_filter_process_audio(&v->filter, l->computed.eff_num_stages, leftright);
if (l->cutoff2 != -1)
- sampler_filter_process_audio(&v->filter2, l->eff_num_stages2, leftright);
+ sampler_filter_process_audio(&v->filter2, l->computed.eff_num_stages2, leftright);
if (__builtin_expect(l->tonectl_freq != 0, 0))
cbox_onepolef_process_stereo(&v->onepole_left, &v->onepole_right, &v->onepole_coeffs, leftright);
- if (__builtin_expect(l->eq_bitmask, 0))
+ if (__builtin_expect(l->computed.eq_bitmask, 0))
{
for (int eq = 0; eq < 3; eq++)
{
- if (l->eq_bitmask & (1 << eq))
+ if (l->computed.eq_bitmask & (1 << eq))
{
cbox_biquadf_process_stereo(&v->eq_left[eq], &v->eq_right[eq], &v->eq_coeffs[eq], leftright);
}
diff --git a/template/calfbox/sfzloader.c b/template/calfbox/sfzloader.c
index c062dc9..8b64bbc 100644
--- a/template/calfbox/sfzloader.c
+++ b/template/calfbox/sfzloader.c
@@ -196,7 +196,7 @@ static gboolean load_sfz_key_value(struct sfz_parser_client *client, const char
{
int ctrl = atoi(key + 6);
int val = atoi(value);
- if (ctrl >= 0 && ctrl <= 119 && val >=0 && val <= 127)
+ if (ctrl >= 0 && ctrl < CC_COUNT && val >=0 && val <= 127)
sampler_program_add_controller_init(ls->program, ctrl, val);
else
g_warning("Invalid CC initialisation: %s=%s", key, value);
diff --git a/template/calfbox/tests.c b/template/calfbox/tests.c
index 249e6f5..a2cba95 100644
--- a/template/calfbox/tests.c
+++ b/template/calfbox/tests.c
@@ -412,6 +412,70 @@ REGION_LOGIC_TEST_SETUP(cc,
"locc16=32 hicc16=33 sample=*saw"
);
+struct region_logic_test_setup_step steps_cc2[] = {
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x1F", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x20", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x11\x41", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x10\x21", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x10\x22", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x21", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x11\x42", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x11\x41", 0),
+ MIDI_DATA_STEP("\xB0\x10\x22", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x11\x3F", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x22", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_END,
+};
+
+REGION_LOGIC_TEST_SETUP(cc2,
+ "locc16=32 hicc16=33 locc17=64 hicc17=65 sample=*saw"
+);
+
+struct region_logic_test_setup_step steps_cc3[] = { // CC16 <= 33, CC17 >= 64
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x1F", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x20", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x11\x41", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x11\x71", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x10\x21", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x10\x22", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x21", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x10\x1F", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x11\x42", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 1),
+ MIDI_DATA_STEP("\xB0\x11\x41", 0),
+ MIDI_DATA_STEP("\xB0\x10\x22", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x11\x3F", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_STEP("\xB0\x10\x22", 0),
+ MIDI_DATA_STEP("\x90\x20\x20", 0),
+ MIDI_DATA_END,
+};
+
+REGION_LOGIC_TEST_SETUP(cc3,
+ "hicc16=33 locc17=64 sample=*saw"
+);
+
struct region_logic_test_setup_step steps_oncc[] = {
MIDI_DATA_STEP("\xB0\x10\x1F", 0),
MIDI_DATA_STEP("\xB0\x10\x20", 1),
@@ -625,6 +689,8 @@ struct test_info {
{ "test_sampler_note_region_logic/chanaft", test_sampler_note_region_logic, &setup_chanaft },
{ "test_sampler_note_region_logic/polyaft", test_sampler_note_region_logic, &setup_polyaft },
{ "test_sampler_note_region_logic/cc", test_sampler_note_region_logic, &setup_cc },
+ { "test_sampler_note_region_logic/cc2", test_sampler_note_region_logic, &setup_cc2 },
+ { "test_sampler_note_region_logic/cc3", test_sampler_note_region_logic, &setup_cc3 },
{ "test_sampler_note_region_logic/oncc", test_sampler_note_region_logic, &setup_oncc },
{ "test_sampler_note_region_logic/release", test_sampler_note_region_logic, &setup_release },
{ "test_sampler_note_region_logic/firstlegato", test_sampler_note_region_logic, &setup_firstlegato },
diff --git a/template/documentation/index.adoc.template b/template/documentation/index.adoc.template
index e1035ac..7bfa18b 100644
--- a/template/documentation/index.adoc.template
+++ b/template/documentation/index.adoc.template
@@ -22,6 +22,7 @@ https://asciidoctor.org/docs/user-manual/
image::logo.png["logo", 320, 180]
For program version
+
This site is part of the https://www.laborejo.org[Laborejo Software Suite]