Nils 3 anni fa
parent
commit
98a1312fd1
  1. 2
      template/calfbox/py/cbox.py
  2. 38
      template/calfbox/sampler_layer.c
  3. 14
      template/calfbox/sfzloader.c
  4. 15
      template/calfbox/sfzparser.c
  5. 2
      template/calfbox/tarfile.h
  6. 72
      template/calfbox/wavebank.c
  7. 3
      template/engine/api.py

2
template/calfbox/py/cbox.py

@ -1041,6 +1041,8 @@ class DocScene(DocObj):
def move_layer(self, old_pos, new_pos):
self.cmd("/move_layer", None, int(old_pos + 1), int(new_pos + 1))
#Layer positions are 0 for "append" and other positions are 1...n which need to be unique
def add_layer(self, aux, pos = None):
if pos is None:
return self.cmd_makeobj("/add_layer", 0, aux)

38
template/calfbox/sampler_layer.c

@ -1034,8 +1034,8 @@ static gboolean sampler_layer_process_cmd(struct cbox_command_target *ct, struct
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
if (!((!layer->parent_program || cbox_execute_on(fb, NULL, "/parent_program", "o", error, layer->parent_program)) &&
(!layer->parent || cbox_execute_on(fb, NULL, "/parent", "o", error, layer->parent)) &&
if (!((!layer->parent_program || cbox_execute_on(fb, NULL, "/parent_program", "o", error, layer->parent_program)) &&
(!layer->parent || cbox_execute_on(fb, NULL, "/parent", "o", error, layer->parent)) &&
CBOX_OBJECT_DEFAULT_STATUS(layer, fb, error)))
return FALSE;
return TRUE;
@ -1148,7 +1148,7 @@ struct sampler_layer *sampler_layer_new(struct sampler_module *m, struct sampler
memset(l, 0, sizeof(struct sampler_layer));
CBOX_OBJECT_HEADER_INIT(l, sampler_layer, doc);
cbox_command_target_init(&l->cmd_target, sampler_layer_process_cmd, l);
l->module = m;
l->child_layers = g_hash_table_new(NULL, NULL);
if (parent)
@ -1205,7 +1205,7 @@ struct sampler_layer *sampler_layer_new(struct sampler_module *m, struct sampler
#define PROC_FIELDS_CLONE_dahdsr(name, parname, index) \
DAHDSR_FIELDS(PROC_SUBSTRUCT_CLONE, name, dst, src) \
if (!copy_hasattr) \
DAHDSR_FIELDS(PROC_SUBSTRUCT_RESET_HAS_FIELD, name, dst)
DAHDSR_FIELDS(PROC_SUBSTRUCT_RESET_HAS_FIELD, name, dst)
#define PROC_FIELDS_CLONE_lfo(name, parname, index) \
LFO_FIELDS(PROC_SUBSTRUCT_CLONE, name, dst, src) \
if (!copy_hasattr) \
@ -1291,11 +1291,11 @@ static inline int sampler_filter_num_stages(float cutoff, enum sampler_filter_ty
#define END_VALUE_amp_velcurve (l->amp_veltrack < 0 ? dB2gain(l->amp_veltrack * 84.0 / 100.0) : 1)
#define IS_QUADRATIC_amp_velcurve l->velcurve_quadratic
#define PROC_FIELDS_FINALISER(type, name, def_value)
#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->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_enum(type, name, def_value)
#define PROC_FIELDS_FINALISER_dBamp(type, name, def_value) \
l->name##_linearized = dB2gain(l->name);
#define PROC_FIELDS_FINALISER_dahdsr(name, parname, index) \
@ -1319,7 +1319,7 @@ void sampler_layer_data_finalize(struct sampler_layer_data *l, struct sampler_la
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_warning("Cannot load waveform \"%s\" in sample_dir \"%s\" : \"%s\"", l->sample, p->sample_dir, error ? error->message : "unknown error");
g_error_free(error);
}
}
@ -1330,7 +1330,7 @@ void sampler_layer_data_finalize(struct sampler_layer_data *l, struct sampler_la
l->computed.eff_is_silent = !l->sample || !strcmp(l->sample, "*silence");
l->sample_changed = FALSE;
}
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) &&
@ -1457,7 +1457,7 @@ void sampler_layer_load_overrides(struct sampler_layer *l, const char *cfg_secti
char *imp = cbox_config_get_string(cfg_section, "import");
if (imp)
sampler_layer_load_overrides(l, imp);
struct layer_foreach_struct lfs = {
.layer = l,
.cfg_section = cfg_section
@ -1478,7 +1478,7 @@ static void sampler_layer_apply_unknown(struct sampler_layer *l, const char *key
{
if (!l->unknown_keys)
l->unknown_keys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_insert(l->unknown_keys, g_strdup(key), g_strdup(value));
}
@ -1628,16 +1628,16 @@ gchar *sampler_layer_to_string(struct sampler_layer *lr, gboolean show_inherited
char floatbuf[G_ASCII_DTOSTR_BUF_SIZE];
int floatbufsize = G_ASCII_DTOSTR_BUF_SIZE;
SAMPLER_FIXED_FIELDS(PROC_FIELDS_TO_FILEPTR)
for(struct sampler_noteinitfunc *nd = l->voice_nifs; nd; nd = nd->next)
{
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,
#define PROC_ENVSTAGE_NAME(name, index, def_value) #name,
static const char *env_stages[] = { DAHDSR_FIELDS(PROC_ENVSTAGE_NAME) "start" };
uint32_t v = nd->key.variant;
g_ascii_dtostr(floatbuf, floatbufsize, nd->value.value);
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)
@ -1825,7 +1825,7 @@ gchar *sampler_layer_to_string(struct sampler_layer *lr, gboolean show_inherited
while(g_hash_table_iter_next(&hti, (gpointer *)&key, (gpointer *)&value))
g_string_append_printf(outstr, " %s=%s", key, value);
}
gchar *res = outstr->str;
g_string_free(outstr, FALSE);
return res;
@ -1935,7 +1935,7 @@ static int sampler_layer_update_cmd_prepare(void *data)
struct sampler_layer_update_cmd *cmd = data;
cmd->old_data = cmd->layer->runtime;
cmd->new_data = calloc(1, sizeof(struct sampler_layer_data));
sampler_layer_data_clone(cmd->new_data, &cmd->layer->data, TRUE);
sampler_layer_data_finalize(cmd->new_data, cmd->layer->parent ? &cmd->layer->parent->data : NULL, cmd->layer->parent_program);
if (cmd->layer->runtime == NULL)
@ -1952,7 +1952,7 @@ static int sampler_layer_update_cmd_prepare(void *data)
static int sampler_layer_update_cmd_execute(void *data)
{
struct sampler_layer_update_cmd *cmd = data;
for (int i = 0; i < 16; i++)
{
FOREACH_VOICE(cmd->module->channels[i].voices_running, v)
@ -1983,7 +1983,7 @@ static int sampler_layer_update_cmd_execute(void *data)
static void sampler_layer_update_cmd_cleanup(void *data)
{
struct sampler_layer_update_cmd *cmd = data;
sampler_layer_data_destroy(cmd->old_data);
free(cmd);
}
@ -2008,13 +2008,13 @@ void sampler_layer_update(struct sampler_layer *l)
.execute = sampler_layer_update_cmd_execute,
.cleanup = sampler_layer_update_cmd_cleanup,
};
struct sampler_layer_update_cmd *lcmd = malloc(sizeof(struct sampler_layer_update_cmd));
lcmd->module = l->module;
lcmd->layer = l;
lcmd->new_data = NULL;
lcmd->old_data = NULL;
cbox_rt_execute_cmd_async(l->module->module.rt, &rtcmd, lcmd);
}

14
template/calfbox/sfzloader.c

@ -128,7 +128,7 @@ static gboolean load_sfz_group(struct sfz_parser_client *client)
static gboolean load_sfz_region(struct sfz_parser_client *client)
{
struct sfz_load_state *ls = client->user_data;
ls->target = ls->region = sampler_layer_new(ls->m, ls->program, ls->group);
// g_warning("-- start region");
return TRUE;
@ -154,7 +154,7 @@ static gboolean load_sfz_curve(struct sfz_parser_client *client)
static gboolean load_sfz_key_value(struct sfz_parser_client *client, const char *key, const char *value)
{
struct sfz_load_state *ls = client->user_data;
if (ls->section_type == slst_curve)
{
if (key[0] == 'v' && isdigit(key[1]))
@ -218,14 +218,14 @@ static gboolean load_sfz_key_value(struct sfz_parser_client *client, const char
g_warning("Unrecognized SFZ key in control section: %s", key);
return TRUE;
}
struct sampler_layer *l = ls->target;
if (!ls->target)
{
g_warning("Parameter '%s' entered outside of global, master, region or group", key);
return TRUE;
}
if (!sampler_layer_apply_param(l, key, value, ls->error))
return FALSE;
@ -275,7 +275,9 @@ gboolean sampler_module_load_program_sfz(struct sampler_module *m, struct sample
if (is_from_string)
status = load_sfz_from_string(sfz, strlen(sfz), &c, error);
else
status = load_sfz(sfz, prg->tarfile, &c, error);
{
status = load_sfz(sfz, prg->tarfile, &c, error); //Loads the audio files but also sets fields, like prg->sample_dir. After this we cannot modify any values anymore.
}
if (!status)
{
if (ls.region)
@ -284,7 +286,7 @@ gboolean sampler_module_load_program_sfz(struct sampler_module *m, struct sample
}
end_token(&c);
prg->all_layers = g_slist_reverse(prg->all_layers);
sampler_program_update_layers(prg);
return TRUE;

15
template/calfbox/sfzparser.c

@ -434,6 +434,11 @@ restore:
return ok;
}
/*
* This is not only called when literally constructing a sfz string
* but also when loading a null instrument e.g. to first create the jack ports and only later
* actually load the sfz and samples, which can be costly.
*/
gboolean load_sfz_from_string(const char *buf, int len, struct sfz_parser_client *c, GError **error)
{
struct sfz_parser_state s;
@ -449,13 +454,17 @@ gboolean load_sfz_from_string(const char *buf, int len, struct sfz_parser_client
return result;
}
/*
* Called once per sfz.
* Does not load samples, but only the sfz file.
*/
gboolean load_sfz_into_state(struct sfz_parser_state *s, const char *name)
{
g_clear_error(s->error);
FILE *f;
int len = -1;
if (s->tarfile)
{
{ //This only extracts the .sfz file itself and will not attempt to load any sample waveforms, eventhough cbox_tarfile_get_item_by_name will later be used to extract the sample as well.
struct cbox_taritem *item = cbox_tarfile_get_item_by_name(s->tarfile, name, TRUE);
if (!item)
{
@ -479,14 +488,14 @@ gboolean load_sfz_into_state(struct sfz_parser_state *s, const char *name)
g_set_error(s->error, G_FILE_ERROR, g_file_error_from_errno (errno), "Cannot open '%s'", name);
return FALSE;
}
if (len == -1)
{
fseek(f, 0, SEEK_END);
len = ftell(f);
fseek(f, 0, SEEK_SET);
}
unsigned char *buf = malloc(len + 1);
buf[len] = '\0';
if (fread(buf, 1, len, f) != (size_t)len)

2
template/calfbox/tarfile.h

@ -38,7 +38,7 @@ struct cbox_tarfile
int refs;
GHashTable *items_byname;
GHashTable *items_byname_nc;
char *file_pathname;
char *file_pathname; //full path to the .tar file with filename.ext
};
struct cbox_tarpool

72
template/calfbox/wavebank.c

@ -70,7 +70,7 @@ static void my_fft_main(complex float output[STD_WAVEFORM_FRAMES])
int invi = STD_WAVEFORM_BITS - i - 1;
int disp = 1 << i;
int mask = disp - 1;
for (int j = 0; j < STD_WAVEFORM_FRAMES / 2; j++)
{
int jj1 = (j & mask) + ((j & ~mask) << 1); // insert 0 at i'th bit to get the left arm of the butterfly
@ -93,9 +93,9 @@ static void my_fft_r2c(complex float output[STD_WAVEFORM_FRAMES], int16_t input[
// Copy + bit reversal addressing
for (int i = 0; i < STD_WAVEFORM_FRAMES; i++)
output[i] = input[map_table[i]] * (1.0 / STD_WAVEFORM_FRAMES);
my_fft_main(output);
}
static void my_ifft_c2r(int16_t output[STD_WAVEFORM_FRAMES], complex float input[STD_WAVEFORM_FRAMES])
@ -116,7 +116,7 @@ static void my_ifft_c2r(int16_t output[STD_WAVEFORM_FRAMES], complex float input
if (fabs(value) > maxv)
maxv = fabs(value);
output[i] = (int16_t)value;
}
}
}
struct wave_bank
@ -168,7 +168,7 @@ void cbox_waveform_generate_levels(struct cbox_waveform *waveform, int levels, d
complex float output[STD_WAVEFORM_FRAMES], bandlimited[STD_WAVEFORM_FRAMES];
my_fft_r2c(output, waveform->data);
int N = STD_WAVEFORM_FRAMES;
waveform->levels = calloc(levels, sizeof(struct cbox_waveform_level));
double rate = 65536.0 * 65536.0; // / waveform->info.frames;
double orig_rate = 65536.0 * 65536.0; // / waveform->info.frames;
@ -176,7 +176,7 @@ void cbox_waveform_generate_levels(struct cbox_waveform *waveform, int levels, d
{
int harmonics = N / 2 / (rate / orig_rate);
bandlimited[0] = 0;
if (harmonics > 0)
{
for (int j = 1; j <= harmonics; j++)
@ -187,7 +187,7 @@ void cbox_waveform_generate_levels(struct cbox_waveform *waveform, int levels, d
for (int j = harmonics; j <= N / 2; j++)
bandlimited[j] = bandlimited [N - j] = 0;
}
waveform->levels[i].data = calloc(N + MAX_INTERPOLATION_ORDER, sizeof(int16_t));
my_ifft_c2r(waveform->levels[i].data, bandlimited);
memcpy(waveform->levels[i].data + N, waveform->levels[i].data, MAX_INTERPOLATION_ORDER * sizeof(int16_t));
@ -204,11 +204,11 @@ void cbox_wavebank_add_std_waveform(const char *name, float (*getfunc)(float v,
for (int i = 0; i < nsize; i++)
{
float v = getfunc(i * 1.0 / nsize, user_data);
if (fabs(v) > 1)
if (fabs(v) > 1)
v = (v < 0) ? -1 : 1;
// cannot use full scale here, because bandlimiting will introduce
// some degree of overshoot
wave[i] = (int16_t)(25000 * v);
wave[i] = (int16_t)(25000 * v);
}
struct cbox_waveform *waveform = calloc(1, sizeof(struct cbox_waveform));
waveform->data = wave;
@ -225,10 +225,10 @@ void cbox_wavebank_add_std_waveform(const char *name, float (*getfunc)(float v,
waveform->loop_end = nsize;
waveform->levels = NULL;
waveform->level_count = 0;
if (levels)
cbox_waveform_generate_levels(waveform, levels, 2);
g_hash_table_insert(bank.waveforms_by_name, waveform->canonical_name, waveform);
g_hash_table_insert(bank.waveforms_by_id, &waveform->id, waveform);
bank.std_waveforms = g_slist_prepend(bank.std_waveforms, waveform);
@ -247,7 +247,7 @@ void cbox_wavebank_init()
bank.waveforms_by_id = g_hash_table_new(g_int_hash, g_int_equal);
bank.std_waveforms = NULL;
bank.streaming_prefetch_size = cbox_config_get_int("streaming", "prefetch_size", 65536);
cbox_wavebank_add_std_waveform("*sine", func_sine, NULL, 0);
// XXXKF this should not be a real waveform
cbox_wavebank_add_std_waveform("*silence", func_silence, NULL, 0);
@ -263,7 +263,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
g_set_error(error, CBOX_WAVEFORM_ERROR, CBOX_WAVEFORM_ERROR_FAILED, "%s: no filename specified", context_name);
return NULL;
}
// Built in waveforms don't go through path canonicalization
if (filename[0] == '*')
{
@ -275,7 +275,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
return waveform;
}
}
gchar *value_copy = g_strdup(filename);
for (int i = 0; value_copy[i]; i++)
{
@ -309,17 +309,35 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
{
g_free(pathname);
g_free(canonical);
struct cbox_waveform *waveform = value;
cbox_waveform_ref(waveform);
return waveform;
}
struct cbox_waveform *waveform = calloc(1, sizeof(struct cbox_waveform));
SNDFILE *sndfile = NULL;
struct cbox_taritem *taritem = NULL;
if (tarfile)
{
if (strcmp(sample_dir, ".") == 0)
{
//Potential path lookup problem:
//This is a sample without sfz default_path opcode inside a tar.
//We need to set the sample dir to the position of the .sfz file within the .tar
//because we also assume that the sample paths in regions are relative to the .sfz path.
//If the sfz is in the tar root this is a redundant action, but if the sfz is itself
//in a subdirectoy we need to adjust the path now.
// XXXNH sample_dir will not be updated in the struct itself and thus reported as "." in python etc.
//context_name is the sfz file, filename the sample file without leading ./ and sample_dir just a dot.
gchar *sfz_dir = g_path_get_dirname(context_name); //take the path of the sfz file...
pathname = g_build_filename(sfz_dir, filename, NULL); //... and prefix the sample filename with it.
g_free(sfz_dir);
}
taritem = cbox_tarfile_get_item_by_name(tarfile, pathname, TRUE);
if (taritem)
sndfile = cbox_tarfile_opensndfile(tarfile, taritem, &waveform->sndstream, &waveform->info);
@ -339,7 +357,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
uint32_t nshorts;
if (waveform->info.channels != 1 && waveform->info.channels != 2)
{
g_set_error(error, CBOX_WAVEFORM_ERROR, CBOX_WAVEFORM_ERROR_FAILED,
g_set_error(error, CBOX_WAVEFORM_ERROR, CBOX_WAVEFORM_ERROR_FAILED,
"%s: cannot open file '%s': unsupported channel count %d", context_name, pathname, (int)waveform->info.channels);
sf_close(sndfile);
free(canonical);
@ -364,7 +382,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
waveform->preloaded_frames = preloaded_frames;
waveform->tarfile = tarfile;
waveform->taritem = taritem;
if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(SF_INSTRUMENT)))
{
for (int i = 0; i < instrument.loop_count; i++)
@ -389,7 +407,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
bank.maxbytes = bank.bytes;
g_hash_table_insert(bank.waveforms_by_name, waveform->canonical_name, waveform);
g_hash_table_insert(bank.waveforms_by_id, &waveform->id, waveform);
return waveform;
}
@ -419,10 +437,10 @@ void cbox_wavebank_foreach(void (*cb)(void *, struct cbox_waveform *), void *use
gpointer key, value;
g_hash_table_iter_init (&iter, bank.waveforms_by_id);
while (g_hash_table_iter_next (&iter, &key, &value))
while (g_hash_table_iter_next (&iter, &key, &value))
{
(*cb)(user_data, value);
}
}
}
void cbox_wavebank_close()
@ -451,7 +469,7 @@ void cbox_waveform_unref(struct cbox_waveform *waveform)
{
if (--waveform->refcount > 0)
return;
g_hash_table_remove(bank.waveforms_by_name, waveform->canonical_name);
g_hash_table_remove(bank.waveforms_by_id, &waveform->id);
bank.bytes -= waveform->bytes;
@ -463,7 +481,7 @@ void cbox_waveform_unref(struct cbox_waveform *waveform)
free(waveform->levels);
free(waveform->data);
free(waveform);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -478,7 +496,7 @@ struct waves_foreach_data
void wave_list_cb(void *user_data, struct cbox_waveform *waveform)
{
struct waves_foreach_data *wfd = user_data;
wfd->success = wfd->success && cbox_execute_on(wfd->fb, NULL, "/waveform", "i", wfd->error, (int)waveform->id);
}
@ -488,7 +506,7 @@ static gboolean waves_process_cmd(struct cbox_command_target *ct, struct cbox_co
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
// XXXKF this only supports 4GB - not a big deal for now yet?
return cbox_execute_on(fb, NULL, "/bytes", "i", error, (int)cbox_wavebank_get_bytes()) &&
cbox_execute_on(fb, NULL, "/max_bytes", "i", error, (int)cbox_wavebank_get_maxbytes()) &&
@ -499,7 +517,7 @@ static gboolean waves_process_cmd(struct cbox_command_target *ct, struct cbox_co
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
struct waves_foreach_data wfd = { fb, error, TRUE };
cbox_wavebank_foreach(wave_list_cb, &wfd);
return wfd.success;
@ -508,7 +526,7 @@ static gboolean waves_process_cmd(struct cbox_command_target *ct, struct cbox_co
{
if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE;
int id = CBOX_ARG_I(cmd, 0);
struct cbox_waveform *waveform = cbox_wavebank_peek_waveform_by_id(id);
if (waveform == NULL)

3
template/engine/api.py

@ -308,6 +308,9 @@ def startEngine(nsmClient):
logger.info("Template api engine started")
def isStandaloneMode():
return session.standaloneMode
def _deprecated_updatePlayback():
"""The only place in the program to update the cbox playback besides startEngine.
We only need to update it after a user action, which always goes through the api.

Caricamento…
Annulla
Salva