2017-07-22 09:04:10 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#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);
|
2017-07-22 18:16:41 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-07-22 09:04:10 +00:00
|
|
|
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);
|
|
|
|
}
|