/* Calf Box, an open source musical instrument. Copyright (C) 2010-2011 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 "sampler.h" #include "sfzparser.h" #include "sampler_impl.h" #define DUMP_LAYER_ATTRIBS 0 enum sfz_load_section_type { slst_normal, slst_control, slst_effect, slst_curve, }; struct sfz_load_state { struct sampler_module *m; const char *filename, *default_path; struct sampler_program *program; struct sampler_layer *global, *master, *group, *region, *target; struct sampler_midi_curve *curve; enum sfz_load_section_type section_type; uint32_t curve_index; GError **error; }; static void load_sfz_end_region(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; // printf("-- copy current region to the list of layers\n"); struct sampler_layer *l = ls->region; sampler_layer_data_finalize(&l->data, l->parent ? &l->parent->data : NULL, ls->program); sampler_layer_reset_switches(l, ls->m); sampler_layer_update(l); sampler_program_add_layer(ls->program, ls->region); ls->region = NULL; } static void end_token(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; #if DUMP_LAYER_ATTRIBS if (ls->group) { fprintf(stdout, ""); sampler_layer_dump(&ls->group, stdout); } if (ls->region) { fprintf(stdout, ""); sampler_layer_dump(&ls->region, stdout); } #endif if (ls->section_type == slst_curve) { uint32_t i = ls->curve_index; if (i < MAX_MIDI_CURVES) { if (ls->program->curves[i]) g_free(ls->program->curves[i]); else ls->program->interpolated_curves[i] = g_new(float, 128); sampler_midi_curve_interpolate(ls->curve, ls->program->interpolated_curves[i], 0, 1, FALSE); ls->program->curves[i] = ls->curve; } else { if (i == (uint32_t)-1) g_warning("Curve index not specified"); else g_warning("Curve number %u is greater than the maximum of %u", (unsigned)i, (unsigned)MAX_MIDI_CURVES); g_free(ls->curve); } ls->curve = NULL; } if (ls->region) load_sfz_end_region(client); ls->region = NULL; ls->section_type = slst_normal; } static gboolean load_sfz_global(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; // printf("-- start global\n"); ls->target = ls->global = ls->program->global; ls->master = ls->global->default_child; ls->group = ls->master->default_child; return TRUE; } static gboolean load_sfz_master(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; // printf("-- start master\n"); ls->target = ls->master = sampler_layer_new(ls->m, ls->program, ls->program->global); ls->group = ls->master->default_child = sampler_layer_new(ls->m, ls->program, ls->master); return TRUE; } static gboolean load_sfz_group(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; // printf("-- start group\n"); ls->target = ls->group = sampler_layer_new(ls->m, ls->program, ls->master); return TRUE; } 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; } static gboolean load_sfz_control(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; ls->section_type = slst_control; return TRUE; } static gboolean load_sfz_curve(struct sfz_parser_client *client) { struct sfz_load_state *ls = client->user_data; ls->section_type = slst_curve; ls->curve = g_new0(struct sampler_midi_curve, 1); ls->curve_index = -1; sampler_midi_curve_init(ls->curve); return TRUE; } 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])) { int pos = atoi(key + 1); if (pos >= 0 && pos < 128) { double fvalue = -1; if (!atof_C_verify(key, value, &fvalue, ls->error)) return FALSE; ls->curve->values[pos] = fvalue; return TRUE; } else g_warning("Out of range curve point: %s", key); } else if (!strcmp(key, "curve_index")) { ls->curve_index = atoi(value); return TRUE; } else g_warning("Unknown parameter in curve section: %s=%s", key, value); return TRUE; } if (ls->section_type == slst_effect) { g_warning("Parameter found in unsupported effect section: %s=%s", key, value); return TRUE; } if (ls->section_type == slst_control) { if (!strncmp(key, "label_cc", 8)) { int ctrl = atoi(key + 8); sampler_program_add_controller_label(ls->program, ctrl, g_strdup(value)); } else if (!strncmp(key, "set_cc", 6)) { int ctrl = atoi(key + 6); int val = atoi(value); 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); } else if (!strcmp(key, "default_path")) { g_free(ls->program->sample_dir); gchar *dir = g_path_get_dirname(ls->filename); char value2[strlen(value) + 1]; int i; for (i = 0; value[i]; ++i) value2[i] = value[i] == '\\' ? '/' : value[i]; value2[i] = '\0'; gchar *combined = g_build_filename(dir, value2, NULL); ls->program->sample_dir = combined; g_free(dir); } else 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; return TRUE; } static gboolean handle_token(struct sfz_parser_client *client, const char *token, GError **error) { struct sfz_load_state *ls = client->user_data; end_token(client); if (!strcmp(token, "region")) return load_sfz_region(client); if (!strcmp(token, "group")) return load_sfz_group(client); if (!strcmp(token, "master")) return load_sfz_master(client); if (!strcmp(token, "global")) return load_sfz_global(client); if (!strcmp(token, "control")) return load_sfz_control(client); if (!strcmp(token, "curve")) return load_sfz_curve(client); if (!strcmp(token, "effect")) { ls->section_type = slst_effect; return TRUE; } g_set_error(error, CBOX_SFZPARSER_ERROR, CBOX_SFZ_PARSER_ERROR_INVALID_HEADER, "Unexpected header <%s>", token); return FALSE; } gboolean sampler_module_load_program_sfz(struct sampler_module *m, struct sampler_program *prg, const char *sfz, int is_from_string, GError **error) { struct sfz_load_state ls = { .global = prg->global, .master = prg->global->default_child, .group = prg->global->default_child->default_child, .target = NULL, .m = m, .filename = sfz, .region = NULL, .error = error, .program = prg, .section_type = slst_normal, .default_path = NULL }; struct sfz_parser_client c = { .user_data = &ls, .token = handle_token, .key_value = load_sfz_key_value }; g_clear_error(error); gboolean status; if (is_from_string) status = load_sfz_from_string(sfz, strlen(sfz), &c, error); else { 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) CBOX_DELETE(ls.region); return FALSE; } end_token(&c); prg->all_layers = g_slist_reverse(prg->all_layers); sampler_program_update_layers(prg); return TRUE; }