/*
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.h"
#include "config-api.h"
#include "dspmath.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
static void lfo_update_freq(struct sampler_lfo *lfo, struct sampler_lfo_params *lfop, int srate, double srate_inv)
{
lfo->delta = (uint32_t)(lfop->freq * 65536.0 * 65536.0 * CBOX_BLOCK_SIZE * srate_inv);
lfo->delay = (uint32_t)(lfop->delay * srate);
lfo->fade = (uint32_t)(lfop->fade * srate);
lfo->wave = (int32_t)(lfop->wave);
}
static void lfo_init(struct sampler_lfo *lfo, struct sampler_lfo_params *lfop, int srate, double srate_inv)
{
lfo->phase = 0;
lfo->xdelta = 0;
lfo->age = 0;
lfo->random_value = 0; // safe, less CPU intensive value
lfo_update_freq(lfo, lfop, srate, srate_inv);
}
static inline float lfo_run(struct sampler_lfo *lfo)
{
if (lfo->age < lfo->delay)
{
lfo->age += CBOX_BLOCK_SIZE;
return 0.f;
}
uint32_t delta = lfo->delta + lfo->xdelta;
const int FRAC_BITS = 32 - 11;
float v = 0;
switch(lfo->wave) {
case 0: // triangle
{
uint32_t ph = lfo->phase + 0x40000000;
uint32_t tri = (ph & 0x7FFFFFFF) ^ (((ph >> 31) - 1) & 0x7FFFFFFF);
v = -1.0 + tri * (2.0 / (1U << 31));
break;
}
case 1: // sine (default)
default:
{
uint32_t iphase = lfo->phase >> FRAC_BITS;
float frac = (lfo->phase & ((1 << FRAC_BITS) - 1)) * (1.0 / (1 << FRAC_BITS));
v = sampler_sine_wave[iphase] + (sampler_sine_wave[iphase + 1] - sampler_sine_wave[iphase]) * frac;
break;
}
case 2:
v = lfo->phase < 0xC0000000 ? 1 : -1;
break;
case 3:
v = lfo->phase < 0x80000000 ? 1 : -1;
break;
case 4:
v = lfo->phase < 0x40000000 ? 1 : -1;
break;
case 5:
v = lfo->phase < 0x20000000 ? 1 : -1;
break;
case 6:
v = -1 + lfo->phase * (1.0 / (1U << 31));
break;
case 7:
v = 1 - lfo->phase * (1.0 / (1U << 31));
break;
case 12:
if ((lfo->phase & 0x80000000) != ((lfo->phase + delta) & 0x80000000))
lfo->random_value = -1 + 2 * rand() / (1.0 * RAND_MAX);
v = lfo->random_value;
break;
}
lfo->phase += delta;
if (lfo->fade && lfo->age < lfo->delay + lfo->fade)
{
v *= (lfo->age - lfo->delay) * 1.0 / lfo->fade;
lfo->age += CBOX_BLOCK_SIZE;
}
return v;
}
static gboolean is_tail_finished(struct sampler_voice *v)
{
if (!v->layer->computed.eff_num_stages)
return TRUE;
double eps = 1.0 / 65536.0;
if (cbox_biquadf_is_audible(&v->filter.filter_left[0], eps))
return FALSE;
if (cbox_biquadf_is_audible(&v->filter.filter_right[0], eps))
return FALSE;
int num_stages = v->layer->computed.eff_num_stages;
if (num_stages > 1)
{
if (cbox_biquadf_is_audible(&v->filter.filter_left[num_stages - 1], eps))
return FALSE;
if (cbox_biquadf_is_audible(&v->filter.filter_right[num_stages - 1], eps))
return FALSE;
}
return TRUE;
}
#if USE_NEON
#include
static inline void mix_block_into_with_gain(cbox_sample_t **outputs, int oofs, float *src_leftright, float gain)
{
float *dst_left = outputs[oofs];
float *dst_right = outputs[oofs + 1];
float32x2_t gain2 = {gain, gain};
for (size_t i = 0; i < CBOX_BLOCK_SIZE; i += 2)
{
float32x2_t lr1 = vld1_f32(&src_leftright[2 * i]);
float32x2_t lr2 = vld1_f32(&src_leftright[2 * i + 2]);
float32x2x2_t lr12 = vtrn_f32(lr1, lr2);
float32x2_t dl1 = vld1_f32(&dst_left[i]);
float32x2_t dr1 = vld1_f32(&dst_right[i]);
float32x2_t l1 = vmla_f32(dl1, lr12.val[0], gain2);
vst1_f32(&dst_left[i], l1);
float32x2_t r1 = vmla_f32(dr1, lr12.val[1], gain2);
vst1_f32(&dst_right[i], r1);
}
}
static inline void mix_block_into(cbox_sample_t **outputs, int oofs, float *src_leftright)
{
float *dst_left = outputs[oofs];
float *dst_right = outputs[oofs + 1];
for (size_t i = 0; i < CBOX_BLOCK_SIZE; i += 2)
{
float32x2_t lr1 = vld1_f32(&src_leftright[2 * i]);
float32x2_t lr2 = vld1_f32(&src_leftright[2 * i + 2]);
float32x2x2_t lr12 = vtrn_f32(lr1, lr2);
float32x2_t dl1 = vld1_f32(&dst_left[i]);
float32x2_t dr1 = vld1_f32(&dst_right[i]);
float32x2_t l1 = vadd_f32(dl1, lr12.val[0]);
vst1_f32(&dst_left[i], l1);
float32x2_t r1 = vadd_f32(dr1, lr12.val[1]);
vst1_f32(&dst_right[i], r1);
}
}
#else
static inline void mix_block_into_with_gain(cbox_sample_t **outputs, int oofs, float *src_leftright, float gain)
{
cbox_sample_t *dst_left = outputs[oofs];
cbox_sample_t *dst_right = outputs[oofs + 1];
for (size_t i = 0; i < CBOX_BLOCK_SIZE; i++)
{
dst_left[i] += gain * src_leftright[2 * i];
dst_right[i] += gain * src_leftright[2 * i + 1];
}
}
static inline void mix_block_into(cbox_sample_t **outputs, int oofs, float *src_leftright)
{
cbox_sample_t *dst_left = outputs[oofs];
cbox_sample_t *dst_right = outputs[oofs + 1];
for (size_t i = 0; i < CBOX_BLOCK_SIZE; i++)
{
dst_left[i] += src_leftright[2 * i];
dst_right[i] += src_leftright[2 * i + 1];
}
}
#endif
////////////////////////////////////////////////////////////////////////////////
static float sfz_crossfade(float param, float xfin_lo, float xfin_hi, float xfout_lo, float xfout_hi, enum sampler_xf_curve xfc)
{
if (param >= xfin_hi && param <= xfout_lo)
return 1.f;
if (param < xfin_lo || param > xfout_hi)
return 0.f;
float for0 = (param < xfout_lo) ? xfin_lo : xfout_hi;
float for1 = (param < xfout_lo) ? xfin_hi : xfout_lo;
if (for0 == for1)
return 1.f;
if (xfc == stxc_gain)
return (param - for0) / (for1 - for0);
else
{
float v = (param - for0) / (for1 - for0);
return sqrtf(v);
}
}
// One-half version for CC-based crossfades
static inline float sfz_crossfade2(float param, float xflo, float xfhi, float left, float right, enum sampler_xf_curve xfc)
{
if (xflo > xfhi)
return sfz_crossfade2(param, xfhi, xflo, right, left, xfc);
if (param <= xflo)
return left;
if (param >= xfhi)
return right;
float res;
if (xflo == xfhi)
res = 0.5f * (left + right);
else
res = left + (right - left) * (param - xflo) / (xfhi - xflo);
if (xfc == stxc_gain)
return res;
else
return sqrtf(res);
}
////////////////////////////////////////////////////////////////////////////////
void sampler_voice_activate(struct sampler_voice *v, enum sampler_player_type mode)
{
assert(v->gen.mode == spt_inactive);
sampler_voice_unlink(&v->program->module->voices_free, v);
assert(mode != spt_inactive);
assert(v->channel);
v->gen.mode = mode;
sampler_voice_link(&v->channel->voices_running, v);
}
void sampler_voice_start_silent(struct sampler_layer_data *l, struct sampler_released_groups *exgroupdata)
{
if (l->group >= 1)
sampler_released_groups_add(exgroupdata, l->group);
}
void sampler_voice_start(struct sampler_voice *v, struct sampler_channel *c, struct sampler_layer_data *l, int note, int vel, struct sampler_released_groups *exgroupdata)
{
struct sampler_module *m = c->module;
sampler_gen_reset(&v->gen);
v->age = 0;
if (l->trigger == stm_release)
{
// time since last 'note on' for that note
v->age = m->current_time - c->prev_note_start_time[note];
double age = v->age * m->module.srate_inv;
// if attenuation is more than 84dB, ignore the release trigger
if (age * l->rt_decay > 84)
return;
}
uint32_t end = l->computed.eff_waveform->info.frames;
if (l->end != 0)
end = (l->end == SAMPLER_NO_LOOP) ? 0 : l->end;
v->last_waveform = l->computed.eff_waveform;
v->gen.cur_sample_end = end;
if (end > l->computed.eff_waveform->info.frames)
end = l->computed.eff_waveform->info.frames;
assert(!v->current_pipe);
if (end > l->computed.eff_waveform->preloaded_frames)
{
if (l->computed.eff_loop_mode == slm_loop_continuous && l->computed.eff_loop_end < l->computed.eff_waveform->preloaded_frames)
{
// Everything fits in prefetch, because loop ends in prefetch and post-loop part is not being played
}
else
{
uint32_t loop_start = -1, loop_end = end;
// If in loop mode, set the loop over the looped part... unless we're doing sustain-only loop on prefetch area only. Then
// streaming will only cover the release part, and it shouldn't be looped.
if (l->computed.eff_loop_mode == slm_loop_continuous || (l->computed.eff_loop_mode == slm_loop_sustain && l->computed.eff_loop_end >= l->computed.eff_waveform->preloaded_frames))
{
loop_start = l->computed.eff_loop_start;
loop_end = l->computed.eff_loop_end;
}
// Those are initial values only, they will be adjusted in process function
v->current_pipe = cbox_prefetch_stack_pop(m->pipe_stack, l->computed.eff_waveform, loop_start, loop_end, l->count);
if (!v->current_pipe)
{
g_warning("Prefetch pipe pool exhausted, no streaming playback will be possible");
end = l->computed.eff_waveform->preloaded_frames;
v->gen.cur_sample_end = end;
}
}
}
v->output_pair_no = (l->output + c->output_shift) % m->output_pairs;
v->serial_no = m->serial_no;
v->gen.loop_overlap = l->loop_overlap;
v->gen.loop_overlap_step = l->loop_overlap > 0 ? 1.0 / l->loop_overlap : 0;
v->gain_fromvel = l->computed.eff_amp_velcurve[vel];
v->gain_shift = (note - l->amp_keycenter) * l->amp_keytrack;
v->gain_fromvel *= sfz_crossfade(note, l->xfin_lokey, l->xfin_hikey, l->xfout_lokey, l->xfout_hikey, l->xf_keycurve);
v->gain_fromvel *= sfz_crossfade(vel, l->xfin_lovel, l->xfin_hivel, l->xfout_lovel, l->xfout_hivel, l->xf_velcurve);
v->note = note;
v->vel = vel;
v->off_vel = 0;
v->pitch_shift = 0;
v->released = 0;
v->released_with_sustain = 0;
v->released_with_sostenuto = 0;
v->captured_sostenuto = 0;
v->channel = c;
v->layer = l;
v->program = c->program;
v->amp_env.shape = &l->amp_env_shape;
v->filter_env.shape = &l->filter_env_shape;
v->pitch_env.shape = &l->pitch_env_shape;
v->cutoff_shift = vel * l->fil_veltrack / 127.0 + (note - l->fil_keycenter) * l->fil_keytrack;
v->cutoff2_shift = vel * l->fil2_veltrack / 127.0 + (note - l->fil2_keycenter) * l->fil2_keytrack;
v->loop_mode = l->computed.eff_loop_mode;
v->off_by = l->off_by;
v->reloffset = l->reloffset;
int auxes = (m->module.outputs - m->module.aux_offset) / 2;
if (l->effect1bus >= 1 && l->effect1bus < 1 + auxes)
v->send1bus = l->effect1bus;
else
v->send1bus = 0;
if (l->effect2bus >= 1 && l->effect2bus < 1 + auxes)
v->send2bus = l->effect2bus;
else
v->send2bus = 0;
v->send1gain = l->effect1 * 0.01;
v->send2gain = l->effect2 * 0.01;
if (l->group >= 1)
{
sampler_released_groups_add(exgroupdata, l->group);
}
lfo_init(&v->amp_lfo, &l->amp_lfo, m->module.srate, m->module.srate_inv);
lfo_init(&v->filter_lfo, &l->filter_lfo, m->module.srate, m->module.srate_inv);
lfo_init(&v->pitch_lfo, &l->pitch_lfo, m->module.srate, m->module.srate_inv);
for (int i = 0; i < 3; ++i)
{
cbox_biquadf_reset(&v->filter.filter_left[i]);
cbox_biquadf_reset(&v->filter.filter_right[i]);
cbox_biquadf_reset(&v->filter2.filter_left[i]);
cbox_biquadf_reset(&v->filter2.filter_right[i]);
}
cbox_onepolef_reset(&v->onepole_left);
cbox_onepolef_reset(&v->onepole_right);
// set gain later (it's a less expensive operation)
if (l->tonectl_freq != 0)
cbox_onepolef_set_highshelf_tonectl(&v->onepole_coeffs, l->tonectl_freq * M_PI * m->module.srate_inv, 1.0);
v->offset = l->offset;
for(struct sampler_noteinitfunc *nif = v->layer->voice_nifs; nif; nif = nif->next)
nif->key.notefunc_voice(nif, v);
if (v->gain_shift)
v->gain_fromvel *= dB2gain(v->gain_shift);
if (v->offset + v->reloffset != 0)
{
// For streamed samples, allow only half the preload period worth of offset to avoid gaps
// (maybe we can allow up to preload period minus one buffer size here?)
uint32_t maxend = v->current_pipe ? (l->computed.eff_waveform->preloaded_frames >> 1) : l->computed.eff_waveform->preloaded_frames;
int32_t pos = v->offset + v->reloffset * maxend * 0.01;
if (pos < 0)
pos = 0;
if ((uint32_t)pos > maxend)
pos = (int32_t)maxend;
v->offset = pos;
}
cbox_envelope_reset(&v->amp_env);
cbox_envelope_reset(&v->filter_env);
cbox_envelope_reset(&v->pitch_env);
v->last_eq_bitmask = 0;
sampler_voice_activate(v, l->computed.eff_waveform->info.channels == 2 ? spt_stereo16 : spt_mono16);
uint32_t pos = v->offset;
if (l->offset_random)
pos += ((uint32_t)(rand() + (rand() << 16))) % l->offset_random;
if (pos >= end)
pos = end;
v->gen.bigpos = ((uint64_t)pos) << 32;
v->gen.virtpos = ((uint64_t)pos) << 32;
if (v->current_pipe && v->gen.bigpos)
cbox_prefetch_pipe_consumed(v->current_pipe, v->gen.bigpos >> 32);
v->layer_changed = TRUE;
}
void sampler_voice_link(struct sampler_voice **pv, struct sampler_voice *v)
{
v->prev = NULL;
v->next = *pv;
if (*pv)
(*pv)->prev = v;
*pv = v;
}
void sampler_voice_unlink(struct sampler_voice **pv, struct sampler_voice *v)
{
if (*pv == v)
*pv = v->next;
if (v->prev)
v->prev->next = v->next;
if (v->next)
v->next->prev = v->prev;
v->prev = NULL;
v->next = NULL;
}
void sampler_voice_inactivate(struct sampler_voice *v, gboolean expect_active)
{
assert((v->gen.mode != spt_inactive) == expect_active);
sampler_voice_unlink(&v->channel->voices_running, v);
v->gen.mode = spt_inactive;
if (v->current_pipe)
{
cbox_prefetch_stack_push(v->program->module->pipe_stack, v->current_pipe);
v->current_pipe = NULL;
}
v->channel = NULL;
sampler_voice_link(&v->program->module->voices_free, v);
}
void sampler_voice_release(struct sampler_voice *v, gboolean is_polyaft)
{
if ((v->loop_mode == slm_one_shot_chokeable) != is_polyaft)
return;
if (v->loop_mode != slm_one_shot && !v->layer->count)
{
v->released = 1;
if (v->loop_mode == slm_loop_sustain && v->current_pipe)
{
// Break the loop
v->current_pipe->file_loop_end = v->gen.cur_sample_end;
v->current_pipe->file_loop_start = -1;
}
}
}
void sampler_voice_update_params_from_layer(struct sampler_voice *v)
{
struct sampler_layer_data *l = v->layer;
struct sampler_module *m = v->program->module;
lfo_update_freq(&v->amp_lfo, &l->amp_lfo, m->module.srate, m->module.srate_inv);
lfo_update_freq(&v->filter_lfo, &l->filter_lfo, m->module.srate, m->module.srate_inv);
lfo_update_freq(&v->pitch_lfo, &l->pitch_lfo, m->module.srate, m->module.srate_inv);
cbox_envelope_update_shape(&v->amp_env, &l->amp_env_shape);
cbox_envelope_update_shape(&v->filter_env, &l->filter_env_shape);
cbox_envelope_update_shape(&v->pitch_env, &l->pitch_env_shape);
}
static inline void lfo_update_xdelta(struct sampler_module *m, struct sampler_lfo *lfo, uint32_t modmask, uint32_t dest, const float *moddests)
{
if (!(modmask & (1 << dest)))
lfo->xdelta = 0;
else
lfo->xdelta = (uint32_t)(moddests[dest] * 65536.0 * 65536.0 * CBOX_BLOCK_SIZE * m->module.srate_inv);
}
static inline void sampler_filter_process_control(struct sampler_filter *f, enum sampler_filter_type fil_type, float logcutoff, float resonance_linearized, const struct cbox_sincos *sincos_base)
{
f->second_filter = &f->filter_coeffs;
if (logcutoff < 0)
logcutoff = 0;
if (logcutoff > 12798)
logcutoff = 12798;
//float resonance = v->resonance*pow(32.0,c->cc[71]/maxv);
float resonance = resonance_linearized;
if (resonance < 0.7f)
resonance = 0.7f;
if (resonance > 32.f)
resonance = 32.f;
const struct cbox_sincos *sincos = &sincos_base[(int)logcutoff];
switch(fil_type)
{
case sft_lp24hybrid:
cbox_biquadf_set_lp_rbj_lookup(&f->filter_coeffs, sincos, resonance * resonance);
cbox_biquadf_set_1plp_lookup(&f->filter_coeffs_extra, sincos, 1);
f->second_filter = &f->filter_coeffs_extra;
break;
case sft_lp12:
case sft_lp24:
case sft_lp36:
cbox_biquadf_set_lp_rbj_lookup(&f->filter_coeffs, sincos, resonance);
break;
case sft_hp12:
case sft_hp24:
cbox_biquadf_set_hp_rbj_lookup(&f->filter_coeffs, sincos, resonance);
break;
case sft_bp6:
case sft_bp12:
cbox_biquadf_set_bp_rbj_lookup(&f->filter_coeffs, sincos, resonance);
break;
case sft_lp6:
case sft_lp12nr:
case sft_lp24nr:
cbox_biquadf_set_1plp_lookup(&f->filter_coeffs, sincos, fil_type != sft_lp6);
break;
case sft_hp6:
case sft_hp12nr:
case sft_hp24nr:
cbox_biquadf_set_1php_lookup(&f->filter_coeffs, sincos, fil_type != sft_hp6);
break;
default:
assert(0);
}
}
static inline void sampler_filter_process_audio(struct sampler_filter *f, int num_stages, float *leftright)
{
for (int i = 0; i < num_stages; ++i)
cbox_biquadf_process_stereo(&f->filter_left[i], &f->filter_right[i], i ? f->second_filter : &f->filter_coeffs, leftright);
}
static inline void do_channel_mixing(float *leftright, uint32_t numsamples, float position, float width)
{
float crossmix = (100.0 - width) * 0.005f;
float amtleft = position > 0 ? 1 - 0.01 * position : 1;
float amtright = position < 0 ? 1 - 0.01 * -position : 1;
if (amtleft < 0)
amtleft = 0;
if (amtright < 0)
amtright = 0;
for (uint32_t i = 0; i < 2 * numsamples; i += 2) {
float left = leftright[i], right = leftright[i + 1];
float newleft = left + crossmix * (right - left);
float newright = right + crossmix * (left - right);
leftright[i] = newleft * amtleft;
leftright[i + 1] = newright * amtright;
}
}
static inline uint32_t sampler_gen_sample_playback_with_pipe(struct sampler_gen *gen, float *leftright, struct cbox_prefetch_pipe *current_pipe)
{
if (!current_pipe)
return sampler_gen_sample_playback(gen, leftright, (uint32_t)-1);
uint32_t limit = cbox_prefetch_pipe_get_remaining(current_pipe);
if (limit <= 4)
{
gen->mode = spt_inactive;
return 0;
}
uint32_t samples = sampler_gen_sample_playback(gen, leftright, limit - 4);
cbox_prefetch_pipe_consumed(current_pipe, gen->consumed);
gen->consumed = 0;
return samples;
}
static const float gain_for_num_stages[] = { 1, 1, 0.5, 0.33f };
void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cbox_sample_t **outputs)
{
struct sampler_layer_data *l = v->layer;
assert(v->gen.mode != spt_inactive);
struct sampler_channel *c = v->channel;
v->age += CBOX_BLOCK_SIZE;
const float velscl = v->vel * (1.f / 127.f);
struct cbox_envelope_shape *pitcheg_shape = v->pitch_env.shape, *fileg_shape = v->filter_env.shape, *ampeg_shape = v->amp_env.shape;
if (__builtin_expect(l->computed.mod_bitmask, 0))
{
#define COPY_ORIG_SHAPE(envtype, envtype2, index) \
if (l->computed.mod_bitmask & slmb_##envtype2##eg_cc) { \
memcpy(&v->cc_envs[index], envtype2##eg_shape, sizeof(struct cbox_envelope_shape)); \
envtype2##eg_shape = &v->cc_envs[index]; \
}
COPY_ORIG_SHAPE(amp, amp, 0)
COPY_ORIG_SHAPE(filter, fil, 1)
COPY_ORIG_SHAPE(pitch, pitch, 2)
for(struct sampler_modulation *sm = l->modulations; sm; sm = sm->next)
{
// Simplified modulations for EG stages (CCs only)
if (sm->key.dest >= smdest_eg_stage_start && sm->key.dest <= smdest_eg_stage_end)
{
float value = 0.f;
if (sm->key.src < smsrc_pernote_offset)
value = sampler_channel_getcc_mod(c, v, sm->key.src, sm->value.curve_id, sm->value.step);
uint32_t param = sm->key.dest - smdest_eg_stage_start;
if (value * sm->value.amount != 0)
cbox_envelope_modify_dahdsr(&v->cc_envs[(param >> 4)], param & 0x0F, value * sm->value.amount, m->module.srate * 1.0 / CBOX_BLOCK_SIZE);
}
}
#define UPDATE_ENV_POSITION(envtype, envtype2) \
if (l->computed.mod_bitmask & slmb_##envtype##eg_cc) \
cbox_envelope_update_shape_after_modify(&v->envtype2##_env, envtype##eg_shape, m->module.srate * 1.0 / CBOX_BLOCK_SIZE);
UPDATE_ENV_POSITION(amp, amp)
UPDATE_ENV_POSITION(fil, filter)
UPDATE_ENV_POSITION(pitch, pitch)
}
// if it's a DAHD envelope without sustain, consider the note finished
if (__builtin_expect(v->amp_env.cur_stage == 4 && ampeg_shape->stages[3].end_value <= 0.f, 0))
cbox_envelope_go_to(&v->amp_env, 15);
#define RECALC_EQ_MASK_EQ1 (7 << smdest_eq1_freq)
#define RECALC_EQ_MASK_EQ2 (7 << smdest_eq2_freq)
#define RECALC_EQ_MASK_EQ3 (7 << smdest_eq3_freq)
#define RECALC_EQ_MASK_ALL (RECALC_EQ_MASK_EQ1 | RECALC_EQ_MASK_EQ2 | RECALC_EQ_MASK_EQ3)
uint32_t recalc_eq_mask = 0;
if (__builtin_expect(v->layer_changed, 0))
{
v->last_level = -1;
if (v->last_waveform != v->layer->computed.eff_waveform)
{
v->last_waveform = v->layer->computed.eff_waveform;
if (v->layer->computed.eff_waveform)
{
v->gen.mode = v->layer->computed.eff_waveform->info.channels == 2 ? spt_stereo16 : spt_mono16;
v->gen.cur_sample_end = v->layer->computed.eff_waveform->info.frames;
}
else
{
sampler_voice_inactivate(v, TRUE);
return;
}
}
if (l->computed.eq_bitmask & (1 << 0)) recalc_eq_mask |= RECALC_EQ_MASK_EQ1;
if (l->computed.eq_bitmask & (1 << 1)) recalc_eq_mask |= RECALC_EQ_MASK_EQ2;
if (l->computed.eq_bitmask & (1 << 2)) recalc_eq_mask |= RECALC_EQ_MASK_EQ3;
v->last_eq_bitmask = l->computed.eq_bitmask;
v->layer_changed = FALSE;
}
float pitch = (v->note - l->pitch_keycenter) * l->pitch_keytrack + l->tune + l->transpose * 100 + v->pitch_shift;
float modsrcs[smsrc_pernote_count];
modsrcs[smsrc_vel - smsrc_pernote_offset] = v->vel * velscl;
modsrcs[smsrc_pitch - smsrc_pernote_offset] = pitch * (1.f / 100.f);
modsrcs[smsrc_chanaft - smsrc_pernote_offset] = c->last_chanaft * (1.f / 127.f);
modsrcs[smsrc_polyaft - smsrc_pernote_offset] = sampler_channel_get_poly_pressure(c, v->note);
modsrcs[smsrc_pitchenv - smsrc_pernote_offset] = cbox_envelope_get_value(&v->pitch_env, pitcheg_shape) * 0.01f;
modsrcs[smsrc_filenv - smsrc_pernote_offset] = l->computed.eff_use_filter_mods ? cbox_envelope_get_value(&v->filter_env, fileg_shape) * 0.01f : 0;
modsrcs[smsrc_ampenv - smsrc_pernote_offset] = cbox_envelope_get_value(&v->amp_env, ampeg_shape) * 0.01f;
modsrcs[smsrc_amplfo - smsrc_pernote_offset] = lfo_run(&v->amp_lfo);
modsrcs[smsrc_fillfo - smsrc_pernote_offset] = l->computed.eff_use_filter_mods ? lfo_run(&v->filter_lfo) : 0;
modsrcs[smsrc_pitchlfo - smsrc_pernote_offset] = lfo_run(&v->pitch_lfo);
float moddests[smdestcount];
moddests[smdest_pitch] = pitch;
moddests[smdest_cutoff] = v->cutoff_shift;
moddests[smdest_cutoff2] = v->cutoff2_shift;
// These are always set
uint32_t modmask = (1 << smdest_pitch) | (1 << smdest_cutoff) | (1 << smdest_cutoff2);
#if 0
// Those are lazy-initialized using modmask.
moddests[smdest_gain] = 0;
moddests[smdest_resonance] = 0;
moddests[smdest_tonectl] = 0;
moddests[smdest_pitchlfo_freq] = 0;
moddests[smdest_fillfo_freq] = 0;
moddests[smdest_amplfo_freq] = 0;
#endif
if (__builtin_expect(l->trigger == stm_release, 0))
{
moddests[smdest_gain] = -v->age * l->rt_decay * m->module.srate_inv;
modmask |= (1 << smdest_gain);
}
if (c->pitchwheel)
{
int pw = c->pitchwheel * (c->pitchwheel > 0 ? l->bend_up : -l->bend_down);
// approximate dividing by 8191
if (pw < 0)
pw >>= 13;
else
pw = (pw + 4096) >> 13;
if (l->bend_step > 1)
pw = (pw / l->bend_step) * l->bend_step;
moddests[smdest_pitch] += pw;
}
for (struct sampler_modulation *sm = l->modulations; sm; sm = sm->next)
{
enum sampler_modsrc src = sm->key.src;
enum sampler_modsrc src2 = sm->key.src2;
enum sampler_moddest dest = sm->key.dest;
float value = 0.f, value2 = 1.f;
if (src < smsrc_pernote_offset)
value = sampler_channel_getcc_mod(c, v, src, sm->value.curve_id, sm->value.step);
else
value = modsrcs[src - smsrc_pernote_offset];
if (src2 != smsrc_none)
{
if (src2 < smsrc_pernote_offset)
value2 = sampler_channel_getcc_mod(c, v, src2, sm->value.curve_id, sm->value.step);
else
value2 = modsrcs[src2 - smsrc_pernote_offset];
value *= value2;
}
if (dest < 32)
{
if (dest == smdest_amplitude)
{
if (!(modmask & (1 << dest))) // first value
{
moddests[dest] = value * sm->value.amount;
modmask |= (1 << dest);
}
else
moddests[dest] *= value * sm->value.amount;
}
else if (!(modmask & (1 << dest))) // first value
{
moddests[dest] = value * sm->value.amount;
modmask |= (1 << dest);
}
else
moddests[dest] += value * sm->value.amount;
}
}
lfo_update_xdelta(m, &v->pitch_lfo, modmask, smdest_pitchlfo_freq, moddests);
if (l->computed.eff_use_filter_mods)
lfo_update_xdelta(m, &v->filter_lfo, modmask, smdest_fillfo_freq, moddests);
lfo_update_xdelta(m, &v->amp_lfo, modmask, smdest_amplfo_freq, moddests);
recalc_eq_mask |= modmask;
#define RECALC_EQ_IF(index) \
if (recalc_eq_mask & RECALC_EQ_MASK_EQ##index) \
{ \
float dfreq = velscl * l->eq##index.vel2freq + ((modmask & (1 << smdest_eq##index##_freq)) ? moddests[smdest_eq##index##_freq] : 0);\
float fbw = (modmask & (1 << smdest_eq##index##_bw)) ? pow(0.5, moddests[smdest_eq##index##_bw]) : 1;\
float dgain = velscl * l->eq##index.vel2gain + ((modmask & (1 << smdest_eq##index##_gain)) ? moddests[smdest_eq##index##_gain] : 0);\
cbox_biquadf_set_peakeq_rbj_scaled(&v->eq_coeffs[index - 1], l->eq##index.effective_freq + dfreq, fbw / l->eq##index.bw, dB2gain(0.5 * (l->eq##index.gain + dgain)), m->module.srate); \
if (!(v->last_eq_bitmask & (1 << (index - 1)))) \
{ \
cbox_biquadf_reset(&v->eq_left[index-1]); \
cbox_biquadf_reset(&v->eq_right[index-1]); \
} \
}
if (__builtin_expect(recalc_eq_mask, 0))
{
RECALC_EQ_IF(1)
RECALC_EQ_IF(2)
RECALC_EQ_IF(3)
}
cbox_envelope_advance(&v->pitch_env, v->released, pitcheg_shape);
if (l->computed.eff_use_filter_mods)
cbox_envelope_advance(&v->filter_env, v->released, fileg_shape);
cbox_envelope_advance(&v->amp_env, v->released, ampeg_shape);
if (__builtin_expect(v->amp_env.cur_stage < 0, 0))
{
if (__builtin_expect(is_tail_finished(v), 0))
{
sampler_voice_inactivate(v, TRUE);
return;
}
}
double maxv = 127 << 7;
double freq = l->computed.eff_freq * cent2factor(moddests[smdest_pitch]) ;
uint64_t freq64 = (uint64_t)(freq * 65536.0 * 65536.0 * m->module.srate_inv);
gboolean playing_sustain_loop = !v->released && v->loop_mode == slm_loop_sustain;
uint32_t loop_start, loop_end;
gboolean bandlimited = FALSE;
if (!v->current_pipe)
{
v->gen.sample_data = v->last_waveform->data;
if (v->last_waveform->levels)
{
gboolean use_cached = v->last_level > 0 && v->last_level < v->last_waveform->level_count
&& freq64 > v->last_level_min_rate && freq64 <= v->last_waveform->levels[v->last_level].max_rate;
if (__builtin_expect(use_cached, 1))
{
v->gen.sample_data = v->last_waveform->levels[v->last_level].data;
bandlimited = TRUE;
}
else
{
for (int i = 0; i < v->last_waveform->level_count; i++)
{
if (freq64 <= v->last_waveform->levels[i].max_rate)
{
v->last_level = i;
v->gen.sample_data = v->last_waveform->levels[i].data;
bandlimited = TRUE;
break;
}
v->last_level_min_rate = v->last_waveform->levels[i].max_rate;
}
}
}
}
// XXXKF or maybe check for on-cc being in the on-cc range instead?
gboolean play_loop = v->layer->computed.eff_loop_end && (v->loop_mode == slm_loop_continuous || playing_sustain_loop) && !v->layer->on_cc;
loop_start = play_loop ? v->layer->computed.eff_loop_start : (v->layer->count ? 0 : (uint32_t)-1);
loop_end = play_loop ? v->layer->computed.eff_loop_end : v->gen.cur_sample_end;
if (v->current_pipe)
{
v->gen.sample_data = v->gen.loop_count ? v->current_pipe->data : v->last_waveform->data;
v->gen.streaming_buffer = v->current_pipe->data;
v->gen.prefetch_only_loop = (loop_end < v->last_waveform->preloaded_frames);
v->gen.loop_overlap = 0;
if (v->gen.prefetch_only_loop)
{
assert(!v->gen.in_streaming_buffer); // XXXKF this won't hold true when loops are edited while sound is being played (but that's not supported yet anyway)
v->gen.loop_start = loop_start;
v->gen.loop_end = loop_end;
v->gen.streaming_buffer_frames = 0;
}
else
{
v->gen.loop_start = 0;
v->gen.loop_end = v->last_waveform->preloaded_frames;
v->gen.streaming_buffer_frames = v->current_pipe->buffer_loop_end;
}
}
else
{
v->gen.loop_count = v->layer->count;
v->gen.loop_start = loop_start;
v->gen.loop_end = loop_end;
if (!bandlimited)
{
// Use pre-calculated join
v->gen.scratch = loop_start == (uint32_t)-1 ? v->layer->computed.scratch_end : v->layer->computed.scratch_loop;
}
else
{
// The standard waveforms have extra MAX_INTERPOLATION_ORDER of samples from the loop start added past loop_end,
// to avoid wasting time generating the joins in all the practical cases. The slow path covers custom loops
// (i.e. partial loop or no loop) over bandlimited versions of the standard waveforms, and those are probably
// not very useful anyway, as changing the loop removes the guarantee of the waveform being bandlimited and
// may cause looping artifacts or introduce DC offset (e.g. if only a positive part of a sine wave is looped).
if (loop_start == 0 && loop_end == l->computed.eff_waveform->info.frames)
v->gen.scratch = v->gen.sample_data + l->computed.eff_waveform->info.frames - MAX_INTERPOLATION_ORDER;
else
{
// Generate the join for the current wave level
// XXXKF this could be optimised further, by checking if waveform and loops are the same as the last
// time. However, this code is not likely to be used... ever, so optimising it is not the priority.
int shift = l->computed.eff_waveform->info.channels == 2 ? 1 : 0;
uint32_t halfscratch = MAX_INTERPOLATION_ORDER << shift;
v->gen.scratch = v->gen.scratch_bandlimited;
memcpy(&v->gen.scratch_bandlimited[0], &v->gen.sample_data[(loop_end - MAX_INTERPOLATION_ORDER) << shift], halfscratch * sizeof(int16_t) );
if (loop_start != (uint32_t)-1)
memcpy(v->gen.scratch_bandlimited + halfscratch, &v->gen.sample_data[loop_start << shift], halfscratch * sizeof(int16_t));
else
memset(v->gen.scratch_bandlimited + halfscratch, 0, halfscratch * sizeof(int16_t));
}
}
}
if (l->timestretch)
{
v->gen.bigdelta = freq64;
v->gen.virtdelta = (uint64_t)(l->computed.eff_freq * 65536.0 * 65536.0 * m->module.srate_inv);
v->gen.stretching_jump = l->timestretch_jump;
v->gen.stretching_crossfade = l->timestretch_crossfade;
}
else
{
v->gen.bigdelta = freq64;
v->gen.virtdelta = freq64;
}
float gain = modsrcs[smsrc_ampenv - smsrc_pernote_offset] * l->volume_linearized * v->gain_fromvel * c->channel_volume_cc * sampler_channel_addcc(c, 11) / (maxv * maxv);
if (l->computed.eff_use_xfcc) {
for(struct sampler_cc_range *p = l->xfin_cc; p; p = p->next)
gain *= sfz_crossfade2(c->intcc[p->key.cc_number], p->value.locc, p->value.hicc, 0, 1, l->xf_cccurve);
for(struct sampler_cc_range *p = l->xfout_cc; p; p = p->next)
gain *= sfz_crossfade2(c->intcc[p->key.cc_number], p->value.locc, p->value.hicc, 1, 0, l->xf_cccurve);
}
if ((modmask & (1 << smdest_gain)) && moddests[smdest_gain] != 0.f)
gain *= dB2gain(moddests[smdest_gain]);
float amplitude = l->amplitude;
if ((modmask & (1 << smdest_amplitude)))
amplitude *= moddests[smdest_amplitude];
gain *= amplitude * (1.0 / 100.0);
// http://drealm.info/sfz/plj-sfz.xhtml#amp "The overall gain must remain in the range -144 to 6 decibels."
if (gain > 2.f)
gain = 2.f;
float pan = (l->pan + ((modmask & (1 << smdest_pan) ? moddests[smdest_pan] : 0)) + 100.f) * (1.f / 200.f) + (c->channel_pan_cc * 1.f / maxv - 0.5f) * 2.f;
if (pan < 0.f)
pan = 0.f;
if (pan > 1.f)
pan = 1.f;
v->gen.lgain = gain * (1.f - pan) / 32768.f;
v->gen.rgain = gain * pan / 32768.f;
if (l->cutoff != -1)
{
float mod_resonance = (modmask & (1 << smdest_resonance)) ? dB2gain(gain_for_num_stages[l->computed.eff_num_stages] * moddests[smdest_resonance]) : 1;
sampler_filter_process_control(&v->filter, l->fil_type, l->computed.logcutoff + moddests[smdest_cutoff], l->computed.resonance_scaled * mod_resonance, m->sincos);
}
if (l->cutoff2 != -1)
{
float mod_resonance = (modmask & (1 << smdest_resonance2)) ? dB2gain(gain_for_num_stages[l->computed.eff_num_stages2] * moddests[smdest_resonance2]) : 1;
sampler_filter_process_control(&v->filter2, l->fil2_type, l->computed.logcutoff2 + moddests[smdest_cutoff2], l->computed.resonance2_scaled * mod_resonance, m->sincos);
}
if (__builtin_expect(l->tonectl_freq != 0, 0))
{
float ctl = l->tonectl + (modmask & (1 << smdest_tonectl) ? moddests[smdest_tonectl] : 0);
if (fabs(ctl) > 0.0001f)
cbox_onepolef_set_highshelf_setgain(&v->onepole_coeffs, dB2gain(ctl));
else
cbox_onepolef_set_highshelf_setgain(&v->onepole_coeffs, 1.0);
}
// Audio processing starts here
float leftright[2 * CBOX_BLOCK_SIZE];
uint32_t samples = sampler_gen_sample_playback_with_pipe(&v->gen, leftright, v->current_pipe);
if (l->computed.eff_use_channel_mixer)
do_channel_mixing(leftright, samples, l->position, l->width);
for (int i = 2 * samples; i < 2 * CBOX_BLOCK_SIZE; i++)
leftright[i] = 0.f;
if (l->cutoff != -1)
sampler_filter_process_audio(&v->filter, l->computed.eff_num_stages, leftright);
if (l->cutoff2 != -1)
sampler_filter_process_audio(&v->filter2, l->computed.eff_num_stages2, leftright);
if (__builtin_expect(l->tonectl_freq != 0, 0))
cbox_onepolef_process_stereo(&v->onepole_left, &v->onepole_right, &v->onepole_coeffs, leftright);
if (__builtin_expect(l->computed.eq_bitmask, 0))
{
for (int eq = 0; eq < 3; eq++)
{
if (l->computed.eq_bitmask & (1 << eq))
{
cbox_biquadf_process_stereo(&v->eq_left[eq], &v->eq_right[eq], &v->eq_coeffs[eq], leftright);
}
}
}
mix_block_into(outputs, v->output_pair_no * 2, leftright);
if (__builtin_expect((v->send1bus > 0 && v->send1gain != 0) || (v->send2bus > 0 && v->send2gain != 0), 0))
{
if (v->send1bus > 0 && v->send1gain != 0)
{
int oofs = m->module.aux_offset + (v->send1bus - 1) * 2;
mix_block_into_with_gain(outputs, oofs, leftright, v->send1gain);
}
if (v->send2bus > 0 && v->send2gain != 0)
{
int oofs = m->module.aux_offset + (v->send2bus - 1) * 2;
mix_block_into_with_gain(outputs, oofs, leftright, v->send2gain);
}
}
if (v->gen.mode == spt_inactive)
sampler_voice_inactivate(v, FALSE);
}