/* 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 "config-api.h" #include "dspmath.h" #include "engine.h" #include "errors.h" #include "midi.h" #include "module.h" #include "rt.h" #include "sampler.h" #include "sampler_impl.h" #include "sfzloader.h" #include "stm.h" #include #include #include #include #include #include #include #include float sampler_sine_wave[2049]; GQuark cbox_sampler_error_quark() { return g_quark_from_string("cbox-sampler-error-quark"); } static void sampler_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs); static void sampler_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len); static void sampler_destroyfunc(struct cbox_module *module); void sampler_steal_voice(struct sampler_module *m) { int max_age = 0; struct sampler_voice *voice_found = NULL; for (int i = 0; i < 16; i++) { FOREACH_VOICE(m->channels[i].voices_running, v) { if (v->amp_env.cur_stage == 15) continue; int age = m->serial_no - v->serial_no; if (v->gen.loop_start == (uint32_t)-1) age += (int)((v->gen.bigpos >> 32) * 100.0 / v->gen.cur_sample_end); else if (v->released) age += 10; if (age > max_age) { max_age = age; voice_found = v; } } } if (voice_found) { voice_found->released = 1; cbox_envelope_go_to(&voice_found->amp_env, 15); } } static inline float clip01(float v) { if (v < 0.f) return 0; if (v > 1.f) return 1; return v; } void sampler_create_voice_from_prevoice(struct sampler_module *m, struct sampler_prevoice *pv) { if (!m->voices_free) return; struct sampler_released_groups exgroups; sampler_released_groups_init(&exgroups); sampler_voice_start(m->voices_free, pv->channel, pv->layer_data, pv->note, pv->vel, &exgroups); if (exgroups.low_groups || exgroups.group_count) sampler_channel_release_groups(pv->channel, pv->note, &exgroups); } void sampler_process_block(struct cbox_module *module, cbox_sample_t **inputs, cbox_sample_t **outputs) { struct sampler_module *m = (struct sampler_module *)module; int active_prevoices[16]; uint32_t active_prevoices_mask = 0; FOREACH_PREVOICE(m->prevoices_running, pv) { uint32_t c = pv->channel - m->channels; active_prevoices[c] = (active_prevoices_mask >> c) & 1 ? 1 + active_prevoices[c] : 1; active_prevoices_mask |= 1 << c; if (sampler_prevoice_process(pv, m)) { sampler_prevoice_unlink(&m->prevoices_running, pv); sampler_create_voice_from_prevoice(m, pv); sampler_prevoice_link(&m->prevoices_free, pv); } } for (int c = 0; c < m->output_pairs + m->aux_pairs; c++) { int oo = 2 * c; for (int i = 0; i < CBOX_BLOCK_SIZE; i++) outputs[oo][i] = outputs[oo + 1][i] = 0.f; } int vcount = 0, vrel = 0, pvcount = 0; for (int i = 0; i < 16; i++) { int cvcount = 0; FOREACH_VOICE(m->channels[i].voices_running, v) { sampler_voice_process(v, m, outputs); if (v->amp_env.cur_stage == 15) vrel++; cvcount++; } int cpvcount = (active_prevoices_mask >> i) & 1 ? active_prevoices[i] : 0; m->channels[i].active_voices = cvcount; m->channels[i].active_prevoices = cpvcount; vcount += cvcount; pvcount += cpvcount; } m->active_voices = vcount; m->active_prevoices = pvcount; if(vcount - vrel > m->max_voices + 1) sampler_steal_voice(m); if(vcount - vrel > m->max_voices) sampler_steal_voice(m); m->serial_no++; m->current_time += CBOX_BLOCK_SIZE; } void sampler_process_event(struct cbox_module *module, const uint8_t *data, uint32_t len) { struct sampler_module *m = (struct sampler_module *)module; if (len > 0) { int cmd = data[0] >> 4; int chn = data[0] & 15; struct sampler_channel *c = &m->channels[chn]; switch(cmd) { case 8: sampler_channel_stop_note(c, data[1], data[2], FALSE); break; case 9: if (data[2] > 0) sampler_channel_start_note(c, data[1], data[2], FALSE); else sampler_channel_stop_note(c, data[1], data[2], FALSE); break; case 10: c->last_polyaft = data[2]; // Lazy clearing if (!(c->poly_pressure_mask & (1 << (data[1] >> 2)))) { // Clear the group of 4 memset(c->poly_pressure + (data[1] & ~3), 0, 4); c->poly_pressure_mask |= 1 << (data[1] >> 2); } c->poly_pressure[data[1]] = data[2]; // XXXKF add a new opcode for cymbal chokes via poly pressure // if (data[2] == 127) // sampler_channel_stop_note(c, data[1], data[2], TRUE); break; case 11: sampler_channel_process_cc(c, data[1], data[2]); break; case 12: sampler_channel_program_change(c, data[1]); break; case 13: c->last_chanaft = data[1]; break; case 14: c->pitchwheel = data[1] + 128 * data[2] - 8192; break; } } } static int get_first_free_program_no(struct sampler_module *m) { int prog_no = -1; gboolean found; // XXXKF this has a N-squared complexity - but I'm not seeing // this being used with more than 10 programs at the same time // in the near future do { prog_no++; found = FALSE; for (uint32_t i = 0; i < m->program_count; i++) { if (m->programs[i]->prog_no == prog_no) { found = TRUE; break; } } } while(found); return prog_no; } static int find_program(struct sampler_module *m, int prog_no) { for (uint32_t i = 0; i < m->program_count; i++) { if (m->programs[i]->prog_no == prog_no) return i; } return -1; } struct release_program_voices_data { struct sampler_module *module; struct sampler_program *old_pgm, *new_pgm; uint16_t channels_to_wait_for; }; static int release_program_voices_execute(void *data) { struct release_program_voices_data *rpv = data; struct sampler_module *m = rpv->module; int finished = 1; FOREACH_PREVOICE(m->prevoices_running, pv) { if (pv->channel->program == rpv->old_pgm) { sampler_prevoice_unlink(&m->prevoices_running, pv); sampler_prevoice_link(&m->prevoices_free, pv); } } for (int i = 0; i < 16; i++) { uint16_t mask = 1 << i; struct sampler_channel *c = &m->channels[i]; if (c->program == rpv->old_pgm || c->program == NULL) { sampler_channel_set_program_RT(c, rpv->new_pgm); rpv->channels_to_wait_for |= mask; } if (rpv->channels_to_wait_for & mask) { FOREACH_VOICE(c->voices_running, v) { if (m->deleting || !m->module.rt) { sampler_voice_inactivate(v, TRUE); continue; } // This is a new voice, started after program change, so it // should not be terminated and waited for. if (v->program == rpv->new_pgm) continue; // The voice is still going, so repeat until it fades out finished = 0; // If not in final fadeout stage, force final fadeout. if (v->amp_env.cur_stage != 15) { v->released = 1; cbox_envelope_go_to(&v->amp_env, 15); } } } } return finished; } static void swap_program(struct sampler_module *m, int index, struct sampler_program *pgm, gboolean delete_old) { static struct cbox_rt_cmd_definition release_program_voices = { NULL, release_program_voices_execute, NULL }; struct sampler_program *old_program = NULL; if (pgm) old_program = cbox_rt_swap_pointers(m->module.rt, (void **)&m->programs[index], pgm); else old_program = cbox_rt_array_remove(m->module.rt, (void ***)&m->programs, &m->program_count, index); struct release_program_voices_data data = {m, old_program, pgm, 0}; cbox_rt_execute_cmd_sync(m->module.rt, &release_program_voices, &data); if (delete_old && old_program) CBOX_DELETE(old_program); } static void select_initial_program(struct sampler_module *m) { static struct cbox_rt_cmd_definition release_program_voices = { NULL, release_program_voices_execute, NULL }; struct release_program_voices_data data = {m, NULL, m->programs[0], 0}; cbox_rt_execute_cmd_sync(m->module.rt, &release_program_voices, &data); } void sampler_register_program(struct sampler_module *m, struct sampler_program *pgm) { struct sampler_program **programs = malloc(sizeof(struct sampler_program *) * (m->program_count + 1)); memcpy(programs, m->programs, sizeof(struct sampler_program *) * m->program_count); programs[m->program_count] = pgm; free(cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->programs, programs, &m->program_count, m->program_count + 1)); if (m->program_count == 1U) select_initial_program(m); } static gboolean load_program_at(struct sampler_module *m, const char *cfg_section, const char *name, int prog_no, struct sampler_program **ppgm, GError **error) { struct sampler_program *pgm = NULL; int index = find_program(m, prog_no); pgm = sampler_program_new_from_cfg(m, cfg_section, name, prog_no, error); if (!pgm) return FALSE; if (index != -1) { swap_program(m, index, pgm, TRUE); return TRUE; } sampler_register_program(m, pgm); if (ppgm) *ppgm = pgm; return TRUE; } void sampler_unselect_program(struct sampler_module *m, struct sampler_program *prg) { // Ensure no new notes are played on that program prg->deleting = TRUE; // Remove from the list of available programs, so that it cannot be selected again for (uint32_t i = 0; i < m->program_count; i++) { if (m->programs[i] == prg) swap_program(m, i, NULL, FALSE); } } static gboolean load_from_string(struct sampler_module *m, const char *sample_dir, const char *sfz_data, const char *name, int prog_no, struct sampler_program **ppgm, GError **error) { int index = find_program(m, prog_no); struct sampler_program *pgm = sampler_program_new(m, prog_no, name, NULL, sample_dir, error); if (!pgm) return FALSE; pgm->source_file = g_strdup("string"); if (!sampler_module_load_program_sfz(m, pgm, sfz_data, TRUE, error)) { free(pgm); return FALSE; } if (index != -1) { swap_program(m, index, pgm, TRUE); if (ppgm) *ppgm = pgm; return TRUE; } struct sampler_program **programs = calloc((m->program_count + 1), sizeof(struct sampler_program *)); memcpy(programs, m->programs, sizeof(struct sampler_program *) * m->program_count); programs[m->program_count] = pgm; if (ppgm) *ppgm = pgm; free(cbox_rt_swap_pointers_and_update_count(m->module.rt, (void **)&m->programs, programs, &m->program_count, m->program_count + 1)); if (m->program_count == 1) select_initial_program(m); return TRUE; } gboolean sampler_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error) { struct sampler_module *m = (struct sampler_module *)ct->user_data; if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for (int i = 0; i < 16; i++) { struct sampler_channel *channel = &m->channels[i]; gboolean result; if (channel->program) result = cbox_execute_on(fb, NULL, "/patch", "iis", error, i + 1, channel->program->prog_no, channel->program->name); else result = cbox_execute_on(fb, NULL, "/patch", "iis", error, i + 1, -1, ""); if (!result) return FALSE; if (!(cbox_execute_on(fb, NULL, "/channel_voices", "ii", error, i + 1, channel->active_voices) && cbox_execute_on(fb, NULL, "/channel_prevoices", "ii", error, i + 1, channel->active_prevoices) && cbox_execute_on(fb, NULL, "/output", "ii", error, i + 1, channel->output_shift) && cbox_execute_on(fb, NULL, "/volume", "ii", error, i + 1, sampler_channel_addcc(channel, 7)) && cbox_execute_on(fb, NULL, "/pan", "ii", error, i + 1, sampler_channel_addcc(channel, 10)))) return FALSE; } return cbox_execute_on(fb, NULL, "/active_voices", "i", error, m->active_voices) && cbox_execute_on(fb, NULL, "/active_prevoices", "i", error, m->active_prevoices) && cbox_execute_on(fb, NULL, "/active_pipes", "i", error, cbox_prefetch_stack_get_active_pipe_count(m->pipe_stack)) && cbox_execute_on(fb, NULL, "/polyphony", "i", error, m->max_voices) && CBOX_OBJECT_DEFAULT_STATUS(&m->module, fb, error); } else if (!strcmp(cmd->command, "/patches") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; for (uint32_t i = 0; i < m->program_count; i++) { struct sampler_program *prog = m->programs[i]; if (!cbox_execute_on(fb, NULL, "/patch", "isoi", error, prog->prog_no, prog->name, prog, prog->in_use)) return FALSE; } return TRUE; } else if (!strcmp(cmd->command, "/polyphony") && !strcmp(cmd->arg_types, "i")) { int polyphony = CBOX_ARG_I(cmd, 0); if (polyphony < 1 || polyphony > MAX_SAMPLER_VOICES) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid polyphony %d (must be between 1 and %d)", polyphony, (int)MAX_SAMPLER_VOICES); return FALSE; } m->max_voices = polyphony; return TRUE; } else if (!strcmp(cmd->command, "/set_patch") && !strcmp(cmd->arg_types, "ii")) { int channel = CBOX_ARG_I(cmd, 0); if (channel < 1 || channel > 16) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid channel %d", channel); return FALSE; } int value = CBOX_ARG_I(cmd, 1); struct sampler_program *pgm = NULL; for (uint32_t i = 0; i < m->program_count; i++) { if (m->programs[i]->prog_no == value) { pgm = m->programs[i]; break; } } sampler_channel_set_program(&m->channels[channel - 1], pgm); return TRUE; } else if (!strcmp(cmd->command, "/set_output") && !strcmp(cmd->arg_types, "ii")) { int channel = CBOX_ARG_I(cmd, 0); int output = CBOX_ARG_I(cmd, 1); if (channel < 1 || channel > 16) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid channel %d", channel); return FALSE; } if (output < 0 || output >= m->output_pairs) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Invalid output %d", output); return FALSE; } m->channels[channel - 1].output_shift = output; return TRUE; } else if (!strcmp(cmd->command, "/load_patch") && !strcmp(cmd->arg_types, "iss")) { struct sampler_program *pgm = NULL; if (!load_program_at(m, CBOX_ARG_S(cmd, 1), CBOX_ARG_S(cmd, 2), CBOX_ARG_I(cmd, 0), &pgm, error)) return FALSE; if (fb) return cbox_execute_on(fb, NULL, "/uuid", "o", error, pgm); return TRUE; } else if (!strcmp(cmd->command, "/load_patch_from_file") && !strcmp(cmd->arg_types, "iss")) { struct sampler_program *pgm = NULL; char *cfg_section = g_strdup_printf("spgm:!%s", CBOX_ARG_S(cmd, 1)); gboolean res = load_program_at(m, cfg_section, CBOX_ARG_S(cmd, 2), CBOX_ARG_I(cmd, 0), &pgm, error); g_free(cfg_section); if (res && pgm && fb) return cbox_execute_on(fb, NULL, "/uuid", "o", error, pgm); return res; } else if (!strcmp(cmd->command, "/load_patch_from_string") && !strcmp(cmd->arg_types, "isss")) { struct sampler_program *pgm = NULL; if (!load_from_string(m, CBOX_ARG_S(cmd, 1), CBOX_ARG_S(cmd, 2), CBOX_ARG_S(cmd, 3), CBOX_ARG_I(cmd, 0), &pgm, error)) return FALSE; if (fb && pgm) return cbox_execute_on(fb, NULL, "/uuid", "o", error, pgm); return TRUE; } else if (!strcmp(cmd->command, "/get_unused_program") && !strcmp(cmd->arg_types, "")) { if (!cbox_check_fb_channel(fb, cmd->command, error)) return FALSE; return cbox_execute_on(fb, NULL, "/program_no", "i", error, get_first_free_program_no(m)); } else return cbox_object_default_process_cmd(ct, fb, cmd, error); return TRUE; } gboolean sampler_select_program(struct sampler_module *m, int channel, const gchar *preset, GError **error) { for (uint32_t i = 0; i < m->program_count; i++) { if (!strcmp(m->programs[i]->name, preset)) { sampler_channel_set_program(&m->channels[channel], m->programs[i]); return TRUE; } } g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Preset not found: %s", preset); return FALSE; } double sampler_get_current_beat(struct sampler_module *m) { uint32_t song_pos_samples = cbox_engine_current_pos_samples(m->module.engine); double tempo_bpm = m->module.engine->master->tempo; double song_pos_sec = song_pos_samples * 1.0 / m->module.srate; return song_pos_sec * tempo_bpm / 60; } MODULE_CREATE_FUNCTION(sampler) { int i; static int inited = 0; if (!inited) { for (int i = 0; i < 2049; i++) sampler_sine_wave[i] = sin(i * M_PI / 1024.0); inited = 1; } int max_voices = cbox_config_get_int(cfg_section, "polyphony", MAX_SAMPLER_VOICES); if (max_voices < 1 || max_voices > MAX_SAMPLER_VOICES) { g_set_error(error, CBOX_SAMPLER_ERROR, CBOX_SAMPLER_ERROR_INVALID_LAYER, "%s: invalid polyphony value", cfg_section); return NULL; } int output_pairs = cbox_config_get_int(cfg_section, "output_pairs", 1); if (output_pairs < 1 || output_pairs > 16) { g_set_error(error, CBOX_SAMPLER_ERROR, CBOX_SAMPLER_ERROR_INVALID_LAYER, "%s: invalid output pairs value", cfg_section); return NULL; } int aux_pairs = cbox_config_get_int(cfg_section, "aux_pairs", 0); if (aux_pairs < 0 || aux_pairs > 4) { g_set_error(error, CBOX_SAMPLER_ERROR, CBOX_SAMPLER_ERROR_INVALID_LAYER, "%s: invalid aux pairs value", cfg_section); return NULL; } struct sampler_module *m = calloc(1, sizeof(struct sampler_module)); CALL_MODULE_INIT(m, 0, (output_pairs + aux_pairs) * 2, sampler); m->output_pairs = output_pairs; m->aux_pairs = aux_pairs; m->module.aux_offset = m->output_pairs * 2; m->module.process_event = sampler_process_event; m->module.process_block = sampler_process_block; m->programs = NULL; m->max_voices = max_voices; m->serial_no = 0; m->deleting = FALSE; // XXXKF read defaults from some better place, like config // XXXKF allow dynamic change of the number of the pipes m->pipe_stack = cbox_prefetch_stack_new(MAX_SAMPLER_VOICES, cbox_config_get_int("streaming", "streambuf_size", 65536), cbox_config_get_int("streaming", "min_buf_frames", PIPE_MIN_PREFETCH_SIZE_FRAMES)); m->disable_mixer_controls = cbox_config_get_int("sampler", "disable_mixer_controls", 0); float srate = m->module.srate; for (i = 0; i < 12800; i++) { float freq = 440 * pow(2, (i - 5700) / 1200.0); if (freq < 20.0) freq = 20.0; if (freq > srate * 0.45) freq = srate * 0.45; float omega=(float)(2*M_PI*freq/srate); m->sincos[i].sine = sinf(omega); m->sincos[i].cosine = cosf(omega); m->sincos[i].prewarp = 2.0 * tan(hz2w(freq, srate) * 0.5f); m->sincos[i].prewarp2 = 1.0 / (1.0 + m->sincos[i].prewarp); } for (i = 0; ; i++) { gchar *s = g_strdup_printf("program%d", i); char *p = cbox_config_get_string(cfg_section, s); g_free(s); if (!p) { m->program_count = i; break; } } m->programs = calloc(m->program_count, sizeof(struct sampler_program *)); int success = 1; for (i = 0; i < (int)m->program_count; i++) { gchar *s = g_strdup_printf("program%d", i); char *pgm_section = NULL; int pgm_id = -1; const char *pgm_name = cbox_config_get_string(cfg_section, s); g_free(s); char *at = strchr(pgm_name, '@'); if (at) { pgm_id = atoi(at + 1); s = g_strndup(pgm_name, at - pgm_name); pgm_section = g_strdup_printf("spgm:%s", s); g_free(s); } else { pgm_id = i; pgm_section = g_strdup_printf("spgm:%s", pgm_name); } m->programs[i] = sampler_program_new_from_cfg(m, pgm_section, pgm_section + 5, pgm_id, error); g_free(pgm_section); if (!m->programs[i]) { success = 0; break; } } if (!success) { // XXXKF free programs/layers, first ensuring that they're fully initialised free(m); return NULL; } m->voices_free = NULL; memset(m->voices_all, 0, sizeof(m->voices_all)); for (i = 0; i < MAX_SAMPLER_VOICES; i++) { struct sampler_voice *v = &m->voices_all[i]; v->gen.mode = spt_inactive; sampler_voice_link(&m->voices_free, v); } m->active_voices = 0; m->active_prevoices = 0; m->prevoices_free = NULL; memset(m->prevoices_all, 0, sizeof(m->prevoices_all)); for (i = 0; i < MAX_SAMPLER_PREVOICES; i++) { struct sampler_prevoice *v = &m->prevoices_all[i]; sampler_prevoice_link(&m->prevoices_free, v); } for (i = 0; i < 16; i++) sampler_channel_init(&m->channels[i], m); for (i = 0; i < 16; i++) { gchar *key = g_strdup_printf("channel%d", i + 1); gchar *preset = cbox_config_get_string(cfg_section, key); if (preset) { if (!sampler_select_program(m, i, preset, error)) { CBOX_DELETE(&m->module); return NULL; } } g_free(key); key = g_strdup_printf("channel%d_output", i + 1); m->channels[i].output_shift = cbox_config_get_int(cfg_section, key, 1) - 1; g_free(key); } return &m->module; } void sampler_destroyfunc(struct cbox_module *module) { struct sampler_module *m = (struct sampler_module *)module; uint32_t i; m->deleting = TRUE; for (i = 0; i < m->program_count;) { if (m->programs[i]) CBOX_DELETE(m->programs[i]); else i++; } for (i = 0; i < 16U; i++) { assert (m->channels[i].voices_running == NULL); } cbox_prefetch_stack_destroy(m->pipe_stack); free(m->programs); } #define MAKE_TO_STRING_CONTENT(name, v) \ case v: return name; #define MAKE_FROM_STRING_CONTENT(n, v) \ if (!strcmp(name, n)) { *value = v; return TRUE; } #define MAKE_FROM_TO_STRING(enumtype) \ const char *enumtype##_to_string(enum enumtype value) \ { \ switch(value) { \ ENUM_VALUES_##enumtype(MAKE_TO_STRING_CONTENT) \ default: return NULL; \ } \ } \ \ gboolean enumtype##_from_string(const char *name, enum enumtype *value) \ { \ ENUM_VALUES_##enumtype(MAKE_FROM_STRING_CONTENT) \ return FALSE; \ } ENUM_LIST(MAKE_FROM_TO_STRING) ////////////////////////////////////////////////////////////////////////// struct cbox_module_livecontroller_metadata sampler_controllers[] = { }; struct cbox_module_keyrange_metadata sampler_keyranges[] = { }; DEFINE_MODULE(sampler, 0, 2)