/* Calf Box, an open source musical instrument. Copyright (C) 2010-2013 Krzysztof Foltman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "app.h" #include "blob.h" #include "engine.h" #include "instr.h" #include "rt.h" #include "sampler.h" #include "sampler_prg.h" #include "sfzloader.h" #include "tarfile.h" #include CBOX_CLASS_DEFINITION_ROOT(sampler_program) // GSList *sampler_channel_get_next_layer(struct sampler_channel *c, GSList *next_layer, int note, int vel, float random, gboolean is_first, gboolean is_release) struct sampler_layer *sampler_rll_iterator_next(struct sampler_rll_iterator *iter) { retry: while(iter->next_layer) { 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->computed.eff_waveform) continue; 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) return lr; else continue; } if ((l->trigger == stm_first && !iter->is_first) || (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; struct sampler_channel *c = iter->channel; struct sampler_module *m = c->module; if (iter->note >= l->lokey && iter->note <= l->hikey && iter->vel >= l->lovel && iter->vel <= l->hivel && c >= &m->channels[l->lochan - 1] && c <= &m->channels[l->hichan - 1] && iter->random >= l->lorand && iter->random < l->hirand && c->pitchwheel >= l->lobend && c->pitchwheel < l->hibend && 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 && sampler_cc_range_is_in(l->cc, c)) { 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))) { gboolean play = lr->current_seq_position == 1; lr->current_seq_position--; if (lr->current_seq_position > l->seq_length) lr->current_seq_position = 1; else if (lr->current_seq_position < 1) lr->current_seq_position = l->seq_length; if (play) return lr; } } } while(iter->next_keyswitch_index < iter->rll->keyswitch_group_count && iter->next_keyswitch_index < MAX_KEYSWITCH_GROUPS) { struct sampler_rll *rll = iter->rll; uint32_t ks_group = iter->next_keyswitch_index++; uint8_t ks_state = iter->channel->keyswitch_state[ks_group]; if (ks_state == 255) // nothing defined for this switch state continue; uint8_t key_range = rll->ranges_by_key[iter->note]; if (key_range != 255) { GSList **layers_by_range = iter->is_release ? rll->release_layers_by_range : rll->layers_by_range; layers_by_range += (rll->keyswitch_groups[ks_group]->group_offset + ks_state) * rll->layers_by_range_count; iter->next_layer = layers_by_range[key_range]; if (iter->next_layer) goto retry; } } return NULL; } void sampler_rll_iterator_init(struct sampler_rll_iterator *iter, struct sampler_rll *rll, struct sampler_channel *c, int note, int vel, float random, gboolean is_first, gboolean is_release) { iter->channel = c; iter->note = note; iter->vel = vel; iter->random = random; iter->is_first = is_first; iter->is_release = is_release; iter->rll = rll; iter->next_keyswitch_index = 0; if (note >= rll->lokey && note <= rll->hikey) { assert(note >= 0 && note <= 127); GSList **layers_by_range = is_release ? rll->release_layers_by_range : rll->layers_by_range; if (layers_by_range) { uint8_t key_range = rll->ranges_by_key[note]; if (key_range != 255) iter->next_layer = layers_by_range[key_range]; } else iter->next_layer = NULL; } else iter->next_layer = NULL; } static gboolean return_layers(GSList *layers, const char *keyword, struct cbox_command_target *fb, GError **error) { for (GSList *p = layers; p; p = g_slist_next(p)) { if (!cbox_execute_on(fb, NULL, keyword, "o", error, p->data)) return FALSE; } return TRUE; } static gboolean sampler_program_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct sampler_program *program = ct->user_data; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; if (!((!program->name || cbox_execute_on(fb, NULL, "/name", "s", error, program->name)) && cbox_execute_on(fb, NULL, "/sample_dir", "s", error, program->sample_dir) && cbox_execute_on(fb, NULL, "/source_file", "s", error, program->source_file) && cbox_execute_on(fb, NULL, "/program_no", "i", error, program->prog_no) && cbox_execute_on(fb, NULL, "/in_use", "i", error, program->in_use) && CBOX_OBJECT_DEFAULT_STATUS(program, fb, error))) return FALSE; return TRUE; } if (!strcmp(cmd->command, "/regions") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return return_layers(program->all_layers, "/region", fb, error); } if (!strcmp(cmd->command, "/global") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return cbox_execute_on(fb, NULL, "/uuid", "o", error, program->global); } if (!strcmp(cmd->command, "/control_inits") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for (GSList *p = program->ctrl_init_list; p; p = p->next) { const struct sampler_ctrlinit *cin = (const struct sampler_ctrlinit *)&p->data; if (!cbox_execute_on(fb, NULL, "/control_init", "ii", error, (int)cin->controller, (int)cin->value)) return FALSE; } return TRUE; } if (!strcmp(cmd->command, "/control_labels") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for (GSList *p = program->ctrl_label_list; p; p = p->next) { const struct sampler_ctrllabel *cin = (const struct sampler_ctrllabel *)&p->data; if (!cbox_execute_on(fb, NULL, "/control_label", "is", error, (int)cin->controller, cin->label)) return FALSE; } return TRUE; } if (!strcmp(cmd->command, "/add_control_init") && !strcmp(cmd->arg_types, "ii")) { sampler_program_add_controller_init(program, CBOX_ARG_I(cmd, 0), CBOX_ARG_I(cmd, 1)); return TRUE; } if (!strcmp(cmd->command, "/delete_control_init") && !strcmp(cmd->arg_types, "ii")) { sampler_program_remove_controller_init(program, CBOX_ARG_I(cmd, 0), CBOX_ARG_I(cmd, 1)); return TRUE; } if (!strcmp(cmd->command, "/new_group") && !strcmp(cmd->arg_types, "")) { struct sampler_layer *l = sampler_layer_new(program->module, program, program->global->default_child); return cbox_execute_on(fb, NULL, "/uuid", "o", error, l); } if (!strcmp(cmd->command, "/clone_to") && !strcmp(cmd->arg_types, "si")) { struct cbox_instrument *instrument = (struct cbox_instrument *)CBOX_ARG_O(cmd, 0, program, cbox_instrument, error); if (!instrument) return FALSE; struct cbox_module *module = instrument->module; if (strcmp(module->engine_name, "sampler")) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot copy sampler program to module '%s' of type '%s'", module->instance_name, module->engine_name); return FALSE; } struct sampler_program *prg = sampler_program_clone(program, (struct sampler_module *)module, CBOX_ARG_I(cmd, 1), error); if (!prg) return FALSE; sampler_register_program((struct sampler_module *)module, prg); return cbox_execute_on(fb, NULL, "/uuid", "o", error, prg); } if (!strcmp(cmd->command, "/load_file") && !strcmp(cmd->arg_types, "si")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; struct cbox_blob *blob = cbox_blob_new_from_file(program->name, program->tarfile, program->sample_dir, CBOX_ARG_S(cmd, 0), CBOX_ARG_I(cmd, 1), error); if (!blob) return FALSE; return cbox_execute_on(fb, NULL, "/data", "b", error, blob); } if (!strcmp(cmd->command, "/keyswitch_groups") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for (uint32_t i = 0; i < program->rll->keyswitch_group_count; ++i) { struct sampler_keyswitch_group *ksg = program->rll->keyswitch_groups[i]; if (!cbox_execute_on(fb, NULL, "/key_range", "ii", error, ksg->lo, ksg->hi)) return FALSE; } return TRUE; } return cbox_object_default_process_cmd(ct, fb, cmd, error); } struct sampler_program *sampler_program_new(struct sampler_module *m, int prog_no, const char *name, struct cbox_tarfile *tarfile, const char *sample_dir, GError **error) { gchar *perm_sample_dir = g_strdup(sample_dir); if (sample_dir && !perm_sample_dir) return NULL; struct cbox_document *doc = CBOX_GET_DOCUMENT(&m->module); struct sampler_program *prg = malloc(sizeof(struct sampler_program)); if (!prg) { g_free(perm_sample_dir); return NULL; } memset(prg, 0, sizeof(*prg)); CBOX_OBJECT_HEADER_INIT(prg, sampler_program, doc); cbox_command_target_init(&prg->cmd_target, sampler_program_process_cmd, prg); prg->module = m; prg->prog_no = prog_no; prg->name = g_strdup(name); prg->tarfile = tarfile; prg->source_file = NULL; prg->sample_dir = perm_sample_dir; prg->all_layers = NULL; prg->rll = NULL; prg->ctrl_init_list = NULL; prg->ctrl_label_list = NULL; prg->global = sampler_layer_new(m, prg, NULL); prg->global->default_child = sampler_layer_new(m, prg, prg->global); prg->global->default_child->default_child = sampler_layer_new(m, prg, prg->global->default_child); prg->deleting = FALSE; prg->in_use = 0; for (int i = 0; i < MAX_MIDI_CURVES; ++i) { prg->curves[i] = NULL; prg->interpolated_curves[i] = NULL; } CBOX_OBJECT_REGISTER(prg); return prg; } struct sampler_program *sampler_program_new_from_cfg(struct sampler_module *m, const char *cfg_section, const char *name, int pgm_id, GError **error) { int i; char *name2 = NULL, *sfz_path = NULL, *spath = NULL, *tar_name = NULL; const char *sfz = NULL; struct cbox_tarfile *tarfile = NULL; g_clear_error(error); tar_name = cbox_config_get_string(cfg_section, "tar"); if (!strncmp(cfg_section, "spgm:!", 6)) { sfz = cfg_section + 6; if (!strncmp(sfz, "sbtar:", 6)) { sfz_path = "."; gchar *p = strchr(sfz + 6, ';'); if (p) { char *tmp = g_strndup(sfz + 6, p - sfz - 6); tarfile = cbox_tarpool_get_tarfile(app.tarpool, tmp, error); g_free(tmp); if (!tarfile) return NULL; sfz = p + 1; name2 = p + 1; } else { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot load sampler program '%s' from section '%s': missing name of a file inside a tar archive", name, cfg_section); return NULL; } } else { name2 = strrchr(name, '/'); if (name2) name2++; } } else { if (tar_name) { tarfile = cbox_tarpool_get_tarfile(app.tarpool, tar_name, error); if (!tarfile) return NULL; } if (!sfz && !cbox_config_has_section(cfg_section)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot load sampler program '%s' from section '%s': section not found", name, cfg_section); return FALSE; } name2 = cbox_config_get_string(cfg_section, "name"); sfz_path = cbox_config_get_string(cfg_section, "sfz_path"); spath = cbox_config_get_string(cfg_section, "sample_path"); sfz = cbox_config_get_string(cfg_section, "sfz"); if (tarfile && !sfz_path) sfz_path = "."; } if (sfz && !sfz_path && !spath && !tarfile) { char *lastslash = strrchr(sfz, '/'); if (lastslash && !sfz_path && !spath) { char *tmp = g_strndup(sfz, lastslash - sfz); sfz_path = cbox_config_permify(tmp); g_free(tmp); sfz = lastslash + 1; } } struct sampler_program *prg = sampler_program_new( m, pgm_id != -1 ? pgm_id : cbox_config_get_int(cfg_section, "program", 0), name2 ? name2 : name, tarfile, spath ? spath : (sfz_path ? sfz_path : ""), error ); if (!prg) return NULL; if (sfz) { if (sfz_path) prg->source_file = g_build_filename(sfz_path, sfz, NULL); else { prg->source_file = g_strdup(sfz); } if (sampler_module_load_program_sfz(m, prg, prg->source_file, FALSE, error)) return prg; CBOX_DELETE(prg); return NULL; } else { prg->source_file = g_strdup_printf("config:%s", cfg_section); } for (i = 0; ; i++) { gchar *s = g_strdup_printf("group%d", 1 + i); const char *group_section = cbox_config_get_string(cfg_section, s); g_free(s); if (!group_section) break; gchar *swhere = g_strdup_printf("sgroup:%s", group_section); struct sampler_layer *g = sampler_layer_new_from_section(m, prg, prg->global->default_child, swhere); if (!g) g_warning("Sample layer '%s' cannot be created - skipping", group_section); else { // XXXKF // sampler_program_add_group(prg, g); for (int j = 0; ; j++) { char *where = NULL; gchar *s = g_strdup_printf("layer%d", 1 + j); const char *layer_section = cbox_config_get_string(swhere, s); g_free(s); if (!layer_section) break; where = g_strdup_printf("slayer:%s", layer_section); struct sampler_layer *l = sampler_layer_new_from_section(m, prg, g, where); if (!l) g_warning("Sample layer '%s' cannot be created - skipping", layer_section); else { sampler_layer_update(l); 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); } else sampler_program_add_layer(prg, l); } g_free(where); } } g_free(swhere); } for (i = 0; ; i++) { char *where = NULL; gchar *s = g_strdup_printf("layer%d", 1 + i); const char *layer_section = cbox_config_get_string(cfg_section, s); g_free(s); if (!layer_section) break; where = g_strdup_printf("slayer:%s", layer_section); struct sampler_layer *l = sampler_layer_new_from_section(m, prg, NULL, where); if (!l) g_warning("Sample layer '%s' cannot be created - skipping", layer_section); else { sampler_layer_update(l); 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); } else sampler_program_add_layer(prg, l); } g_free(where); } prg->all_layers = g_slist_reverse(prg->all_layers); sampler_program_update_layers(prg); return prg; } void sampler_program_add_layer(struct sampler_program *prg, struct sampler_layer *l) { // Always call sampler_update_layer before sampler_program_add_layer. assert(l->runtime); assert(l->parent); assert(l->parent->parent); assert(l->parent->parent->parent); assert(l->parent->parent->parent == prg->global); prg->all_layers = g_slist_prepend(prg->all_layers, l); } void sampler_program_delete_layer(struct sampler_program *prg, struct sampler_layer *l) { prg->all_layers = g_slist_remove(prg->all_layers, l); } void sampler_program_add_controller_init(struct sampler_program *prg, uint16_t controller, uint8_t value) { union sampler_ctrlinit_union u; u.ptr = NULL; u.cinit.controller = controller; u.cinit.value = value; prg->ctrl_init_list = g_slist_append(prg->ctrl_init_list, u.ptr); } static void sampler_ctrl_label_destroy(gpointer value) { struct sampler_ctrllabel *label = value; free(label->label); free(label); } void sampler_program_add_controller_label(struct sampler_program *prg, uint16_t controller, gchar *text) { struct sampler_ctrllabel *label = calloc(1, sizeof(struct sampler_ctrllabel)); label->controller = controller; label->label = text; prg->ctrl_label_list = g_slist_append(prg->ctrl_label_list, label); } void sampler_program_remove_controller_init(struct sampler_program *prg, uint16_t controller, int which) { for (GSList **p = &prg->ctrl_init_list; *p; ) { const struct sampler_ctrlinit *cin = (const struct sampler_ctrlinit *)&(*p)->data; if (cin->controller != controller) { p = &((*p)->next); continue; } if (which > 0) which--; GSList *q = (GSList *)cbox_rt_swap_pointers(prg->module->module.rt, (void **)p, (*p)->next); g_slist_free1(q); if (which == 0) break; } } static void delete_layers_recursively(struct sampler_layer *layer) { GHashTableIter iter; g_hash_table_iter_init(&iter, layer->child_layers); GSList *dellist = NULL; gpointer key, value; while(g_hash_table_iter_next(&iter, &key, &value)) dellist = g_slist_prepend(dellist, key); GSList *liter = dellist; while(liter) { struct sampler_layer *chl = liter->data; delete_layers_recursively(chl); liter = liter->next; } g_slist_free(dellist); CBOX_DELETE(layer); } void sampler_program_destroyfunc(struct cbox_objhdr *hdr_ptr) { struct sampler_program *prg = CBOX_H2O(hdr_ptr); sampler_unselect_program(prg->module, prg); if (prg->rll) { sampler_rll_destroy(prg->rll); prg->rll = NULL; } for (GSList *p = prg->all_layers; p; p = g_slist_next(p)) CBOX_DELETE((struct sampler_layer *)p->data); delete_layers_recursively(prg->global); for (int i = 0; i < MAX_MIDI_CURVES; ++i) { g_free(prg->curves[i]); g_free(prg->interpolated_curves[i]); } g_free(prg->name); g_free(prg->sample_dir); g_free(prg->source_file); g_slist_free(prg->all_layers); g_slist_free(prg->ctrl_init_list); g_slist_free_full(prg->ctrl_label_list, sampler_ctrl_label_destroy); if (prg->tarfile) cbox_tarpool_release_tarfile(app.tarpool, prg->tarfile); free(prg); } void sampler_program_update_layers(struct sampler_program *prg) { struct sampler_module *m = prg->module; struct sampler_rll *new_rll = sampler_rll_new_from_program(prg); struct sampler_rll *old_rll = cbox_rt_swap_pointers(m->module.rt, (void **)&prg->rll, new_rll); if (old_rll) sampler_rll_destroy(old_rll); } struct sampler_program *sampler_program_clone(struct sampler_program *prg, struct sampler_module *m, int prog_no, GError **error) { struct sampler_program *newprg = sampler_program_new(m, prog_no, prg->name, prg->tarfile, prg->sample_dir, error); if (!newprg) return NULL; if (prg->source_file) newprg->source_file = g_strdup(prg->source_file); // The values are stored as a union aliased with the data pointer, so no need to deep-copy newprg->ctrl_init_list = g_slist_copy(prg->ctrl_init_list); // XXXKF ctrl_label_list newprg->rll = NULL; newprg->global = sampler_layer_new_clone(prg->global, m, newprg, NULL); sampler_program_update_layers(newprg); if (newprg->tarfile) newprg->tarfile->refs++; return newprg; }