#include #include #include #include "ini.h" #include "parse.h" #include "init.h" static int sound_index(Sampler *s, const char *name) { for(int i = 0; i < s->num_sounds; ++i) { if(strncmp(s->index[i], name, MAX_NAME) == 0) { return i; } } return -1; } static int sound_index_add(Sampler *s, const char *name) { if(s->num_sounds >= MAX_SOUNDS) { printf("Maximum number of sounds exceeded: %s\n", name); exit(1); } strncpy(s->index[s->num_sounds], name, MAX_NAME); s->num_sounds += 1; return s->num_sounds - 1; } static int sampler_handler(void *user, const char *section, const char *name, const char *value) { Sampler *s = (Sampler*)user; if(strcmp(section, "SAMPLER") != 0) { return 1; } printf("%s: %s = %s\n", section, name, value); if(strcmp(name, "base_dir") == 0) { strncpy(s->base_dir, value, PATH_MAX); } else if(strcmp(name, "midi_min") == 0) { s->midi_min_vel = parse_int(value); } else if(strcmp(name, "midi_max") == 0) { s->midi_max_vel = parse_int(value); } else { printf("Unknown setting.\n"); exit(1); } return 1; } static int trigger_handler(void *user, const char *section, const char *name, const char *value) { Sampler *s = (Sampler*)user; if(strcmp(section, "TRIGGERS") != 0) { return 1; } printf("%s: %s = %s\n", section, name, value); int from = parse_int(name); if(from < 0 || from > 127) { printf("Illegal trigger: %i\n", from); exit(1); } int to = sound_index(s, value); if(to == -1) { to = sound_index_add(s, value); } s->trigger_map[from][s->num_triggers[from]] = to; s->num_triggers[from]++; return 1; } static int cut_handler(void *user, const char *section, const char *name, const char *value) { Sampler *s = (Sampler*)user; if(strcmp(section, "CUTS") != 0) { return 1; } printf("%s: %s = %s\n", section, name, value); int from = sound_index(s, name); if(from == -1) { printf("Sound is not triggered: %s\n", name); return 1; } int to = sound_index(s, value); if(to == -1) { printf("Sound is not triggered: %s\n", value); return 1; } s->cut_map[from][s->num_cuts[from]] = to; s->num_cuts[from]++; return 1; } static void value_handler(SoundConfig *conf, const char *name, const char *value) { if(strcmp(name, "path") == 0) { strncpy((char*)&conf->path, value, PATH_MAX); } else if(strcmp(name, "gamma_amp") == 0) { conf->gamma_amp = parse_double(value); if(conf->gamma_amp <= 0) { printf("Illegal gamma_amp value: %s\n", value); exit(1); } } else if(strcmp(name, "gamma_layer") == 0) { conf->gamma_layer = parse_double(value); if(conf->gamma_layer <= 0) { printf("Illegal gamma_layer value: %s\n", value); exit(1); } } else if(strcmp(name, "tau_off") == 0) { conf->tau_off = parse_double(value); conf->tau_off = proc_raw_tau_value(conf->tau_off); } else if(strcmp(name, "tau_cut") == 0) { conf->tau_cut = parse_double(value); conf->tau_cut = proc_raw_tau_value(conf->tau_cut); } else if(strcmp(name, "fx_pre") == 0 || strcmp(name, "fx") == 0) { soundconfig_proc_fx(conf, value, true); } else if(strcmp(name, "fx_post") == 0) { soundconfig_proc_fx(conf, value, false); } else { printf("Unknown value.\n"); exit(1); } } static int sound_handler(void *user, const char *section, const char *name, const char *value) { Sampler *s = (Sampler*)user; // Is this a new section? If so, record the name. bool new_section = strcmp(s->section, section) != 0; if(new_section) { strncpy(s->section, section, MAX_NAME); } // Skip non-sound sections. if(strcmp(section, "TRIGGERS") == 0 || strcmp(section, "CUTS") == 0 || strcmp(section, "SAMPLER") == 0) { return 1; } printf("%s: %s = %s\n", section, name, value); // Process a global section. if(strcmp(section, "GLOBAL") == 0) { if(new_section) { soundconfig_load_defaults(&s->global_conf); } value_handler(&s->global_conf, name, value); return 1; } // Otherwise this is a sound. int i = sound_index(s, section); if(i == -1) { printf("Sound is not triggered: %s\n", section); return 1; } Sound *sound = &s->sounds[i]; // If it's a new sound, apply the globals. if(new_section) { soundconfig_copy_globals(&sound->conf, &s->global_conf); } value_handler(&s->sounds[i].conf, name, value); return 1; } void sampler_init(Sampler *sampler, char *conf_path) { sampler->section[0] = '\0'; sampler->num_sounds = 0; sampler->midi_min_vel = 0; sampler->midi_max_vel = 127; sampler->midi_free = jlrb_new(MAX_PLAYING); sampler->midi_new = jlrb_new(MAX_PLAYING); sampler->sustainControl = 64; for(int i = 0; i < MAX_PLAYING; ++i) { jlrb_put(sampler->midi_free, jl_malloc_exit(sizeof(MidiEvt))); } for(int i = 0; i < MAX_SOUNDS; ++i) { sampler->index[i][0] = '\0'; sound_init(&sampler->sounds[i]); sampler->num_triggers[i] = 0; sampler->num_cuts[i] = 0; } // 1) Load sampler settings. if(ini_parse(conf_path, sampler_handler, sampler) < 0) { printf("Failed to parse config file %s (sampler).\n", conf_path); exit(1); } // 2) Load the triggers. if(ini_parse(conf_path, trigger_handler, sampler) < 0) { printf("Failed to parse config file %s (triggers).\n", conf_path); exit(1); } // 3) Load cuts. if(ini_parse(conf_path, cut_handler, sampler) < 0) { printf("Failed to parse config file %s (cuts).\n", conf_path); exit(1); } // 4) Load configuration defaults before parsing sound section. We do this // in case the user hasn't provided a GLOBAL section. soundconfig_load_defaults(&sampler->global_conf); // 5) Load sounds from the config file. if(ini_parse(conf_path, sound_handler, sampler) < 0) { printf("Failed to parse config file %s (sounds).\n", conf_path); exit(1); } // Change into base directory. if(chdir(sampler->base_dir) != 0) { printf("Failed to change directory: %s\n", sampler->base_dir); exit(1); } printf("Loaded %i sounds.\n", sampler->num_sounds); }