Browse Source

update cbox

master
Nils 3 years ago
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): def move_layer(self, old_pos, new_pos):
self.cmd("/move_layer", None, int(old_pos + 1), int(new_pos + 1)) 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): def add_layer(self, aux, pos = None):
if pos is None: if pos is None:
return self.cmd_makeobj("/add_layer", 0, aux) 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)) if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE; return FALSE;
if (!((!layer->parent_program || cbox_execute_on(fb, NULL, "/parent_program", "o", error, layer->parent_program)) && 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)) && (!layer->parent || cbox_execute_on(fb, NULL, "/parent", "o", error, layer->parent)) &&
CBOX_OBJECT_DEFAULT_STATUS(layer, fb, error))) CBOX_OBJECT_DEFAULT_STATUS(layer, fb, error)))
return FALSE; return FALSE;
return TRUE; 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)); memset(l, 0, sizeof(struct sampler_layer));
CBOX_OBJECT_HEADER_INIT(l, sampler_layer, doc); CBOX_OBJECT_HEADER_INIT(l, sampler_layer, doc);
cbox_command_target_init(&l->cmd_target, sampler_layer_process_cmd, l); cbox_command_target_init(&l->cmd_target, sampler_layer_process_cmd, l);
l->module = m; l->module = m;
l->child_layers = g_hash_table_new(NULL, NULL); l->child_layers = g_hash_table_new(NULL, NULL);
if (parent) 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) \ #define PROC_FIELDS_CLONE_dahdsr(name, parname, index) \
DAHDSR_FIELDS(PROC_SUBSTRUCT_CLONE, name, dst, src) \ DAHDSR_FIELDS(PROC_SUBSTRUCT_CLONE, name, dst, src) \
if (!copy_hasattr) \ 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) \ #define PROC_FIELDS_CLONE_lfo(name, parname, index) \
LFO_FIELDS(PROC_SUBSTRUCT_CLONE, name, dst, src) \ LFO_FIELDS(PROC_SUBSTRUCT_CLONE, name, dst, src) \
if (!copy_hasattr) \ 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 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 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_string(name)
#define PROC_FIELDS_FINALISER_midicurve(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); 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) \ #define PROC_FIELDS_FINALISER_dBamp(type, name, def_value) \
l->name##_linearized = dB2gain(l->name); l->name##_linearized = dB2gain(l->name);
#define PROC_FIELDS_FINALISER_dahdsr(name, parname, index) \ #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); l->computed.eff_waveform = cbox_wavebank_get_waveform(p->name, p->tarfile, p->sample_dir, l->sample, &error);
if (!l->computed.eff_waveform) 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); 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->computed.eff_is_silent = !l->sample || !strcmp(l->sample, "*silence");
l->sample_changed = FALSE; 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_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->computed.eff_use_simple_trigger_logic =
(l->seq_length == 1 && l->seq_position == 1) && (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"); char *imp = cbox_config_get_string(cfg_section, "import");
if (imp) if (imp)
sampler_layer_load_overrides(l, imp); sampler_layer_load_overrides(l, imp);
struct layer_foreach_struct lfs = { struct layer_foreach_struct lfs = {
.layer = l, .layer = l,
.cfg_section = cfg_section .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) if (!l->unknown_keys)
l->unknown_keys = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 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)); 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]; char floatbuf[G_ASCII_DTOSTR_BUF_SIZE];
int floatbufsize = G_ASCII_DTOSTR_BUF_SIZE; int floatbufsize = G_ASCII_DTOSTR_BUF_SIZE;
SAMPLER_FIXED_FIELDS(PROC_FIELDS_TO_FILEPTR) SAMPLER_FIXED_FIELDS(PROC_FIELDS_TO_FILEPTR)
for(struct sampler_noteinitfunc *nd = l->voice_nifs; nd; nd = nd->next) 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) if (!nd->value.has_value && !nd->value.has_curve && !nd->value.has_step && !show_inherited)
continue; 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" }; static const char *env_stages[] = { DAHDSR_FIELDS(PROC_ENVSTAGE_NAME) "start" };
uint32_t v = nd->key.variant; uint32_t v = nd->key.variant;
g_ascii_dtostr(floatbuf, floatbufsize, nd->value.value); g_ascii_dtostr(floatbuf, floatbufsize, nd->value.value);
if (nd->key.notefunc_voice == sampler_nif_addrandom && v >= 0 && v <= 2) if (nd->key.notefunc_voice == sampler_nif_addrandom && v >= 0 && v <= 2)
g_string_append_printf(outstr, " %s_random=%s", addrandom_variants[v], floatbuf); g_string_append_printf(outstr, " %s_random=%s", addrandom_variants[v], floatbuf);
else if (nd->key.notefunc_voice == sampler_nif_vel2pitch) 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)) while(g_hash_table_iter_next(&hti, (gpointer *)&key, (gpointer *)&value))
g_string_append_printf(outstr, " %s=%s", key, value); g_string_append_printf(outstr, " %s=%s", key, value);
} }
gchar *res = outstr->str; gchar *res = outstr->str;
g_string_free(outstr, FALSE); g_string_free(outstr, FALSE);
return res; return res;
@ -1935,7 +1935,7 @@ static int sampler_layer_update_cmd_prepare(void *data)
struct sampler_layer_update_cmd *cmd = data; struct sampler_layer_update_cmd *cmd = data;
cmd->old_data = cmd->layer->runtime; cmd->old_data = cmd->layer->runtime;
cmd->new_data = calloc(1, sizeof(struct sampler_layer_data)); cmd->new_data = calloc(1, sizeof(struct sampler_layer_data));
sampler_layer_data_clone(cmd->new_data, &cmd->layer->data, TRUE); 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); sampler_layer_data_finalize(cmd->new_data, cmd->layer->parent ? &cmd->layer->parent->data : NULL, cmd->layer->parent_program);
if (cmd->layer->runtime == NULL) 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) static int sampler_layer_update_cmd_execute(void *data)
{ {
struct sampler_layer_update_cmd *cmd = data; struct sampler_layer_update_cmd *cmd = data;
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
FOREACH_VOICE(cmd->module->channels[i].voices_running, v) 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) static void sampler_layer_update_cmd_cleanup(void *data)
{ {
struct sampler_layer_update_cmd *cmd = data; struct sampler_layer_update_cmd *cmd = data;
sampler_layer_data_destroy(cmd->old_data); sampler_layer_data_destroy(cmd->old_data);
free(cmd); free(cmd);
} }
@ -2008,13 +2008,13 @@ void sampler_layer_update(struct sampler_layer *l)
.execute = sampler_layer_update_cmd_execute, .execute = sampler_layer_update_cmd_execute,
.cleanup = sampler_layer_update_cmd_cleanup, .cleanup = sampler_layer_update_cmd_cleanup,
}; };
struct sampler_layer_update_cmd *lcmd = malloc(sizeof(struct sampler_layer_update_cmd)); struct sampler_layer_update_cmd *lcmd = malloc(sizeof(struct sampler_layer_update_cmd));
lcmd->module = l->module; lcmd->module = l->module;
lcmd->layer = l; lcmd->layer = l;
lcmd->new_data = NULL; lcmd->new_data = NULL;
lcmd->old_data = NULL; lcmd->old_data = NULL;
cbox_rt_execute_cmd_async(l->module->module.rt, &rtcmd, lcmd); 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) static gboolean load_sfz_region(struct sfz_parser_client *client)
{ {
struct sfz_load_state *ls = client->user_data; struct sfz_load_state *ls = client->user_data;
ls->target = ls->region = sampler_layer_new(ls->m, ls->program, ls->group); ls->target = ls->region = sampler_layer_new(ls->m, ls->program, ls->group);
// g_warning("-- start region"); // g_warning("-- start region");
return TRUE; 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) 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; struct sfz_load_state *ls = client->user_data;
if (ls->section_type == slst_curve) if (ls->section_type == slst_curve)
{ {
if (key[0] == 'v' && isdigit(key[1])) 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); g_warning("Unrecognized SFZ key in control section: %s", key);
return TRUE; return TRUE;
} }
struct sampler_layer *l = ls->target; struct sampler_layer *l = ls->target;
if (!ls->target) if (!ls->target)
{ {
g_warning("Parameter '%s' entered outside of global, master, region or group", key); g_warning("Parameter '%s' entered outside of global, master, region or group", key);
return TRUE; return TRUE;
} }
if (!sampler_layer_apply_param(l, key, value, ls->error)) if (!sampler_layer_apply_param(l, key, value, ls->error))
return FALSE; return FALSE;
@ -275,7 +275,9 @@ gboolean sampler_module_load_program_sfz(struct sampler_module *m, struct sample
if (is_from_string) if (is_from_string)
status = load_sfz_from_string(sfz, strlen(sfz), &c, error); status = load_sfz_from_string(sfz, strlen(sfz), &c, error);
else 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 (!status)
{ {
if (ls.region) if (ls.region)
@ -284,7 +286,7 @@ gboolean sampler_module_load_program_sfz(struct sampler_module *m, struct sample
} }
end_token(&c); end_token(&c);
prg->all_layers = g_slist_reverse(prg->all_layers); prg->all_layers = g_slist_reverse(prg->all_layers);
sampler_program_update_layers(prg); sampler_program_update_layers(prg);
return TRUE; return TRUE;

15
template/calfbox/sfzparser.c

@ -434,6 +434,11 @@ restore:
return ok; 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) gboolean load_sfz_from_string(const char *buf, int len, struct sfz_parser_client *c, GError **error)
{ {
struct sfz_parser_state s; 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; 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) gboolean load_sfz_into_state(struct sfz_parser_state *s, const char *name)
{ {
g_clear_error(s->error); g_clear_error(s->error);
FILE *f; FILE *f;
int len = -1; int len = -1;
if (s->tarfile) 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); struct cbox_taritem *item = cbox_tarfile_get_item_by_name(s->tarfile, name, TRUE);
if (!item) 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); g_set_error(s->error, G_FILE_ERROR, g_file_error_from_errno (errno), "Cannot open '%s'", name);
return FALSE; return FALSE;
} }
if (len == -1) if (len == -1)
{ {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
len = ftell(f); len = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
} }
unsigned char *buf = malloc(len + 1); unsigned char *buf = malloc(len + 1);
buf[len] = '\0'; buf[len] = '\0';
if (fread(buf, 1, len, f) != (size_t)len) if (fread(buf, 1, len, f) != (size_t)len)

2
template/calfbox/tarfile.h

@ -38,7 +38,7 @@ struct cbox_tarfile
int refs; int refs;
GHashTable *items_byname; GHashTable *items_byname;
GHashTable *items_byname_nc; GHashTable *items_byname_nc;
char *file_pathname; char *file_pathname; //full path to the .tar file with filename.ext
}; };
struct cbox_tarpool 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 invi = STD_WAVEFORM_BITS - i - 1;
int disp = 1 << i; int disp = 1 << i;
int mask = disp - 1; int mask = disp - 1;
for (int j = 0; j < STD_WAVEFORM_FRAMES / 2; j++) 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 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 // Copy + bit reversal addressing
for (int i = 0; i < STD_WAVEFORM_FRAMES; i++) for (int i = 0; i < STD_WAVEFORM_FRAMES; i++)
output[i] = input[map_table[i]] * (1.0 / STD_WAVEFORM_FRAMES); output[i] = input[map_table[i]] * (1.0 / STD_WAVEFORM_FRAMES);
my_fft_main(output); my_fft_main(output);
} }
static void my_ifft_c2r(int16_t output[STD_WAVEFORM_FRAMES], complex float input[STD_WAVEFORM_FRAMES]) 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) if (fabs(value) > maxv)
maxv = fabs(value); maxv = fabs(value);
output[i] = (int16_t)value; output[i] = (int16_t)value;
} }
} }
struct wave_bank 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]; complex float output[STD_WAVEFORM_FRAMES], bandlimited[STD_WAVEFORM_FRAMES];
my_fft_r2c(output, waveform->data); my_fft_r2c(output, waveform->data);
int N = STD_WAVEFORM_FRAMES; int N = STD_WAVEFORM_FRAMES;
waveform->levels = calloc(levels, sizeof(struct cbox_waveform_level)); waveform->levels = calloc(levels, sizeof(struct cbox_waveform_level));
double rate = 65536.0 * 65536.0; // / waveform->info.frames; double rate = 65536.0 * 65536.0; // / waveform->info.frames;
double orig_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); int harmonics = N / 2 / (rate / orig_rate);
bandlimited[0] = 0; bandlimited[0] = 0;
if (harmonics > 0) if (harmonics > 0)
{ {
for (int j = 1; j <= harmonics; j++) 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++) for (int j = harmonics; j <= N / 2; j++)
bandlimited[j] = bandlimited [N - j] = 0; bandlimited[j] = bandlimited [N - j] = 0;
} }
waveform->levels[i].data = calloc(N + MAX_INTERPOLATION_ORDER, sizeof(int16_t)); waveform->levels[i].data = calloc(N + MAX_INTERPOLATION_ORDER, sizeof(int16_t));
my_ifft_c2r(waveform->levels[i].data, bandlimited); my_ifft_c2r(waveform->levels[i].data, bandlimited);
memcpy(waveform->levels[i].data + N, waveform->levels[i].data, MAX_INTERPOLATION_ORDER * sizeof(int16_t)); 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++) for (int i = 0; i < nsize; i++)
{ {
float v = getfunc(i * 1.0 / nsize, user_data); float v = getfunc(i * 1.0 / nsize, user_data);
if (fabs(v) > 1) if (fabs(v) > 1)
v = (v < 0) ? -1 : 1; v = (v < 0) ? -1 : 1;
// cannot use full scale here, because bandlimiting will introduce // cannot use full scale here, because bandlimiting will introduce
// some degree of overshoot // 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)); struct cbox_waveform *waveform = calloc(1, sizeof(struct cbox_waveform));
waveform->data = wave; 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->loop_end = nsize;
waveform->levels = NULL; waveform->levels = NULL;
waveform->level_count = 0; waveform->level_count = 0;
if (levels) if (levels)
cbox_waveform_generate_levels(waveform, levels, 2); 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_name, waveform->canonical_name, waveform);
g_hash_table_insert(bank.waveforms_by_id, &waveform->id, waveform); g_hash_table_insert(bank.waveforms_by_id, &waveform->id, waveform);
bank.std_waveforms = g_slist_prepend(bank.std_waveforms, 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.waveforms_by_id = g_hash_table_new(g_int_hash, g_int_equal);
bank.std_waveforms = NULL; bank.std_waveforms = NULL;
bank.streaming_prefetch_size = cbox_config_get_int("streaming", "prefetch_size", 65536); bank.streaming_prefetch_size = cbox_config_get_int("streaming", "prefetch_size", 65536);
cbox_wavebank_add_std_waveform("*sine", func_sine, NULL, 0); cbox_wavebank_add_std_waveform("*sine", func_sine, NULL, 0);
// XXXKF this should not be a real waveform // XXXKF this should not be a real waveform
cbox_wavebank_add_std_waveform("*silence", func_silence, NULL, 0); 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); g_set_error(error, CBOX_WAVEFORM_ERROR, CBOX_WAVEFORM_ERROR_FAILED, "%s: no filename specified", context_name);
return NULL; return NULL;
} }
// Built in waveforms don't go through path canonicalization // Built in waveforms don't go through path canonicalization
if (filename[0] == '*') if (filename[0] == '*')
{ {
@ -275,7 +275,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
return waveform; return waveform;
} }
} }
gchar *value_copy = g_strdup(filename); gchar *value_copy = g_strdup(filename);
for (int i = 0; value_copy[i]; i++) 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(pathname);
g_free(canonical); g_free(canonical);
struct cbox_waveform *waveform = value; struct cbox_waveform *waveform = value;
cbox_waveform_ref(waveform); cbox_waveform_ref(waveform);
return waveform; return waveform;
} }
struct cbox_waveform *waveform = calloc(1, sizeof(struct cbox_waveform)); struct cbox_waveform *waveform = calloc(1, sizeof(struct cbox_waveform));
SNDFILE *sndfile = NULL; SNDFILE *sndfile = NULL;
struct cbox_taritem *taritem = NULL; struct cbox_taritem *taritem = NULL;
if (tarfile) 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); taritem = cbox_tarfile_get_item_by_name(tarfile, pathname, TRUE);
if (taritem) if (taritem)
sndfile = cbox_tarfile_opensndfile(tarfile, taritem, &waveform->sndstream, &waveform->info); 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; uint32_t nshorts;
if (waveform->info.channels != 1 && waveform->info.channels != 2) 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); "%s: cannot open file '%s': unsupported channel count %d", context_name, pathname, (int)waveform->info.channels);
sf_close(sndfile); sf_close(sndfile);
free(canonical); free(canonical);
@ -364,7 +382,7 @@ struct cbox_waveform *cbox_wavebank_get_waveform(const char *context_name, struc
waveform->preloaded_frames = preloaded_frames; waveform->preloaded_frames = preloaded_frames;
waveform->tarfile = tarfile; waveform->tarfile = tarfile;
waveform->taritem = taritem; waveform->taritem = taritem;
if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(SF_INSTRUMENT))) if (sf_command(sndfile, SFC_GET_INSTRUMENT, &instrument, sizeof(SF_INSTRUMENT)))
{ {
for (int i = 0; i < instrument.loop_count; i++) 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; bank.maxbytes = bank.bytes;
g_hash_table_insert(bank.waveforms_by_name, waveform->canonical_name, waveform); g_hash_table_insert(bank.waveforms_by_name, waveform->canonical_name, waveform);
g_hash_table_insert(bank.waveforms_by_id, &waveform->id, waveform); g_hash_table_insert(bank.waveforms_by_id, &waveform->id, waveform);
return waveform; return waveform;
} }
@ -419,10 +437,10 @@ void cbox_wavebank_foreach(void (*cb)(void *, struct cbox_waveform *), void *use
gpointer key, value; gpointer key, value;
g_hash_table_iter_init (&iter, bank.waveforms_by_id); 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); (*cb)(user_data, value);
} }
} }
void cbox_wavebank_close() void cbox_wavebank_close()
@ -451,7 +469,7 @@ void cbox_waveform_unref(struct cbox_waveform *waveform)
{ {
if (--waveform->refcount > 0) if (--waveform->refcount > 0)
return; return;
g_hash_table_remove(bank.waveforms_by_name, waveform->canonical_name); g_hash_table_remove(bank.waveforms_by_name, waveform->canonical_name);
g_hash_table_remove(bank.waveforms_by_id, &waveform->id); g_hash_table_remove(bank.waveforms_by_id, &waveform->id);
bank.bytes -= waveform->bytes; bank.bytes -= waveform->bytes;
@ -463,7 +481,7 @@ void cbox_waveform_unref(struct cbox_waveform *waveform)
free(waveform->levels); free(waveform->levels);
free(waveform->data); free(waveform->data);
free(waveform); free(waveform);
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -478,7 +496,7 @@ struct waves_foreach_data
void wave_list_cb(void *user_data, struct cbox_waveform *waveform) void wave_list_cb(void *user_data, struct cbox_waveform *waveform)
{ {
struct waves_foreach_data *wfd = user_data; struct waves_foreach_data *wfd = user_data;
wfd->success = wfd->success && cbox_execute_on(wfd->fb, NULL, "/waveform", "i", wfd->error, (int)waveform->id); 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)) if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE; return FALSE;
// XXXKF this only supports 4GB - not a big deal for now yet? // 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()) && 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()) && 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)) if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE; return FALSE;
struct waves_foreach_data wfd = { fb, error, TRUE }; struct waves_foreach_data wfd = { fb, error, TRUE };
cbox_wavebank_foreach(wave_list_cb, &wfd); cbox_wavebank_foreach(wave_list_cb, &wfd);
return wfd.success; 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)) if (!cbox_check_fb_channel(fb, cmd->command, error))
return FALSE; return FALSE;
int id = CBOX_ARG_I(cmd, 0); int id = CBOX_ARG_I(cmd, 0);
struct cbox_waveform *waveform = cbox_wavebank_peek_waveform_by_id(id); struct cbox_waveform *waveform = cbox_wavebank_peek_waveform_by_id(id);
if (waveform == NULL) if (waveform == NULL)

3
template/engine/api.py

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

Loading…
Cancel
Save