|
|
|
/*
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef CBOX_SAMPLER_H
|
|
|
|
#define CBOX_SAMPLER_H
|
|
|
|
|
|
|
|
#include "biquad-float.h"
|
|
|
|
#include "envelope.h"
|
|
|
|
#include "module.h"
|
|
|
|
#include "onepole-float.h"
|
|
|
|
#include "prefetch_pipe.h"
|
|
|
|
#include "sampler_layer.h"
|
|
|
|
#include "sampler_prg.h"
|
|
|
|
#include "wavebank.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#define MAX_SAMPLER_VOICES 128
|
|
|
|
#define MAX_SAMPLER_PREVOICES 128
|
|
|
|
#define SAMPLER_NO_LOOP ((uint32_t)-1)
|
|
|
|
|
|
|
|
#define CBOX_SAMPLER_ERROR cbox_sampler_error_quark()
|
|
|
|
|
|
|
|
enum CboxSamplerError
|
|
|
|
{
|
|
|
|
CBOX_SAMPLER_ERROR_FAILED,
|
|
|
|
CBOX_SAMPLER_ERROR_INVALID_LAYER,
|
|
|
|
CBOX_SAMPLER_ERROR_INVALID_WAVEFORM,
|
|
|
|
CBOX_SAMPLER_ERROR_NO_PROGRAMS
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_noteinitfunc;
|
|
|
|
struct sampler_voice;
|
|
|
|
struct sampler_prevoice;
|
|
|
|
|
|
|
|
#define GET_RT_FROM_sampler_channel(channel) ((channel)->module->module.rt)
|
|
|
|
|
|
|
|
#define MAX_KEYSWITCH_GROUPS 16
|
|
|
|
|
|
|
|
struct sampler_channel
|
|
|
|
{
|
|
|
|
struct sampler_module *module;
|
|
|
|
int pitchwheel;
|
|
|
|
uint32_t switchmask[4];
|
|
|
|
uint32_t sustainmask[4];
|
|
|
|
uint32_t sostenutomask[4];
|
|
|
|
int previous_note, first_note_vel;
|
|
|
|
struct sampler_program *program;
|
|
|
|
struct sampler_voice *voices_running;
|
|
|
|
int active_voices, active_prevoices;
|
|
|
|
uint8_t prev_note_velocity[128];
|
|
|
|
uint8_t poly_pressure[128];
|
|
|
|
uint32_t prev_note_start_time[128];
|
|
|
|
int channel_volume_cc, channel_pan_cc;
|
|
|
|
int output_shift;
|
|
|
|
uint32_t poly_pressure_mask;
|
|
|
|
uint8_t intcc[smsrc_perchan_count];
|
|
|
|
float floatcc[smsrc_perchan_count];
|
|
|
|
uint8_t last_polyaft, last_chanaft;
|
|
|
|
uint8_t keyswitch_state[MAX_KEYSWITCH_GROUPS];
|
|
|
|
uint8_t keyswitch_lastkey[MAX_KEYSWITCH_GROUPS];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_lfo
|
|
|
|
{
|
|
|
|
uint32_t phase, delta, xdelta;
|
|
|
|
uint32_t age, delay, fade;
|
|
|
|
int32_t wave;
|
|
|
|
float random_value;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_gen
|
|
|
|
{
|
|
|
|
enum sampler_player_type mode;
|
|
|
|
int16_t *sample_data;
|
|
|
|
int16_t *scratch;
|
|
|
|
|
|
|
|
uint64_t bigpos, bigdelta;
|
|
|
|
uint64_t virtpos, virtdelta;
|
|
|
|
uint32_t loop_start, loop_end;
|
|
|
|
uint32_t cur_sample_end;
|
|
|
|
float lgain, rgain;
|
|
|
|
float last_lgain, last_rgain;
|
|
|
|
float fadein_counter;
|
|
|
|
uint64_t fadein_pos;
|
|
|
|
|
|
|
|
// In-memory mode only
|
|
|
|
uint32_t loop_overlap;
|
|
|
|
float loop_overlap_step;
|
|
|
|
float stretching_jump;
|
|
|
|
float stretching_crossfade;
|
|
|
|
uint32_t play_count, loop_count;
|
|
|
|
int16_t scratch_bandlimited[2 * MAX_INTERPOLATION_ORDER * 2];
|
|
|
|
|
|
|
|
// Streaming mode only
|
|
|
|
int16_t *streaming_buffer;
|
|
|
|
uint32_t consumed, consumed_credit, streaming_buffer_frames;
|
|
|
|
gboolean prefetch_only_loop, in_streaming_buffer;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_prevoice
|
|
|
|
{
|
|
|
|
struct sampler_prevoice *prev, *next;
|
|
|
|
struct sampler_layer_data *layer_data;
|
|
|
|
struct sampler_channel *channel;
|
|
|
|
int note, vel;
|
|
|
|
int age;
|
|
|
|
double sync_trigger_time, sync_initial_time, sync_beats;
|
|
|
|
float delay_computed;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_filter
|
|
|
|
{
|
|
|
|
struct cbox_biquadf_coeffs filter_coeffs, filter_coeffs_extra;
|
|
|
|
struct cbox_biquadf_coeffs *second_filter;
|
|
|
|
struct cbox_biquadf_state filter_left[3], filter_right[3];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_voice
|
|
|
|
{
|
|
|
|
struct sampler_voice *prev, *next;
|
|
|
|
struct sampler_layer_data *layer;
|
|
|
|
// Note: may be NULL when program is being deleted
|
|
|
|
struct sampler_program *program;
|
|
|
|
struct cbox_waveform *last_waveform;
|
|
|
|
struct sampler_gen gen;
|
|
|
|
struct cbox_prefetch_pipe *current_pipe;
|
|
|
|
int note;
|
|
|
|
int vel;
|
|
|
|
int released, released_with_sustain, released_with_sostenuto, captured_sostenuto;
|
|
|
|
int off_by;
|
|
|
|
int age;
|
|
|
|
float pitch_shift;
|
|
|
|
float cutoff_shift, cutoff2_shift;
|
|
|
|
float gain_shift, gain_fromvel;
|
|
|
|
struct sampler_filter filter, filter2;
|
|
|
|
struct cbox_onepolef_state onepole_left, onepole_right;
|
|
|
|
struct cbox_onepolef_coeffs onepole_coeffs;
|
|
|
|
struct sampler_channel *channel;
|
|
|
|
struct cbox_envelope amp_env, filter_env, pitch_env;
|
|
|
|
struct sampler_lfo amp_lfo, filter_lfo, pitch_lfo;
|
|
|
|
enum sampler_loop_mode loop_mode;
|
|
|
|
int output_pair_no;
|
|
|
|
int send1bus, send2bus;
|
|
|
|
float send1gain, send2gain;
|
|
|
|
int serial_no;
|
|
|
|
struct cbox_envelope_shape vel_envs[3], cc_envs[3]; // amp, filter, pitch
|
|
|
|
struct cbox_biquadf_state eq_left[3], eq_right[3];
|
|
|
|
struct cbox_biquadf_coeffs eq_coeffs[3];
|
|
|
|
gboolean layer_changed;
|
|
|
|
int last_level;
|
|
|
|
uint64_t last_level_min_rate;
|
|
|
|
uint32_t last_eq_bitmask;
|
|
|
|
float reloffset;
|
|
|
|
uint32_t offset;
|
|
|
|
int off_vel;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sampler_module
|
|
|
|
{
|
|
|
|
struct cbox_module module;
|
|
|
|
|
|
|
|
struct sampler_voice *voices_free, voices_all[MAX_SAMPLER_VOICES];
|
|
|
|
struct sampler_prevoice *prevoices_free, prevoices_all[MAX_SAMPLER_PREVOICES], *prevoices_running;
|
|
|
|
struct sampler_channel channels[16];
|
|
|
|
struct sampler_program **programs;
|
|
|
|
uint32_t program_count;
|
|
|
|
int active_voices, max_voices;
|
|
|
|
int active_prevoices;
|
|
|
|
int serial_no;
|
|
|
|
int output_pairs, aux_pairs;
|
|
|
|
uint32_t current_time;
|
|
|
|
gboolean deleting;
|
|
|
|
int disable_mixer_controls;
|
|
|
|
struct cbox_prefetch_stack *pipe_stack;
|
|
|
|
struct cbox_sincos sincos[12800];
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_RELEASED_GROUPS 16
|
|
|
|
|
|
|
|
struct sampler_released_groups
|
|
|
|
{
|
|
|
|
// Groups 1-32 use a bitmask
|
|
|
|
uint32_t low_groups;
|
|
|
|
int group_count;
|
|
|
|
int groups[MAX_RELEASED_GROUPS];
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void sampler_released_groups_init(struct sampler_released_groups *groups)
|
|
|
|
{
|
|
|
|
groups->low_groups = 0;
|
|
|
|
groups->group_count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean sampler_released_groups_check(struct sampler_released_groups *groups, int group)
|
|
|
|
{
|
|
|
|
if (group <= 32)
|
|
|
|
return (groups->low_groups >> (group - 1)) & 1;
|
|
|
|
for (int j = 0; j < groups->group_count; j++)
|
|
|
|
{
|
|
|
|
if (groups->groups[j] == group)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void sampler_released_groups_add(struct sampler_released_groups *groups, int group)
|
|
|
|
{
|
|
|
|
if (group <= 32)
|
|
|
|
{
|
|
|
|
groups->low_groups |= (1 << (group - 1));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (groups->group_count >= MAX_RELEASED_GROUPS)
|
|
|
|
return;
|
|
|
|
if (!sampler_released_groups_check(groups, group))
|
|
|
|
groups->groups[groups->group_count++] = group;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern GQuark cbox_sampler_error_quark(void);
|
|
|
|
|
|
|
|
extern void sampler_register_program(struct sampler_module *m, struct sampler_program *pgm);
|
|
|
|
extern gboolean sampler_select_program(struct sampler_module *m, int channel, const gchar *preset, GError **error);
|
|
|
|
extern void sampler_unselect_program(struct sampler_module *m, struct sampler_program *prg);
|
|
|
|
extern double sampler_get_current_beat(struct sampler_module *m);
|
|
|
|
|
|
|
|
extern void sampler_channel_init(struct sampler_channel *c, struct sampler_module *m);
|
|
|
|
// This function may only be called from RT thread!
|
|
|
|
extern void sampler_channel_set_program_RT(struct sampler_channel *c, struct sampler_program *prg);
|
|
|
|
// ... and this one is RT-safe
|
|
|
|
extern void sampler_channel_set_program(struct sampler_channel *c, struct sampler_program *prg);
|
|
|
|
extern void sampler_channel_start_note(struct sampler_channel *c, int note, int vel, gboolean is_release_trigger);
|
|
|
|
extern void sampler_channel_stop_note(struct sampler_channel *c, int note, int vel, gboolean is_polyaft);
|
|
|
|
extern void sampler_channel_program_change(struct sampler_channel *c, int program);
|
|
|
|
extern void sampler_channel_stop_sustained(struct sampler_channel *c);
|
|
|
|
extern void sampler_channel_stop_sostenuto(struct sampler_channel *c);
|
|
|
|
extern void sampler_channel_capture_sostenuto(struct sampler_channel *c);
|
|
|
|
extern void sampler_channel_release_groups(struct sampler_channel *c, int note, struct sampler_released_groups *exgroups);
|
|
|
|
extern void sampler_channel_stop_all(struct sampler_channel *c);
|
|
|
|
extern void sampler_channel_process_cc(struct sampler_channel *c, int cc, int val);
|
|
|
|
extern void sampler_channel_reset_keyswitches(struct sampler_channel *c);
|
|
|
|
|
|
|
|
extern 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 *exgroups);
|
|
|
|
extern void sampler_voice_start_silent(struct sampler_layer_data *l, struct sampler_released_groups *exgroups);
|
|
|
|
extern void sampler_voice_release(struct sampler_voice *v, gboolean is_polyaft);
|
|
|
|
extern void sampler_voice_process(struct sampler_voice *v, struct sampler_module *m, cbox_sample_t **outputs);
|
|
|
|
extern void sampler_voice_link(struct sampler_voice **pv, struct sampler_voice *v);
|
|
|
|
extern void sampler_voice_unlink(struct sampler_voice **pv, struct sampler_voice *v);
|
|
|
|
extern void sampler_voice_inactivate(struct sampler_voice *v, gboolean expect_active);
|
|
|
|
extern void sampler_voice_update_params_from_layer(struct sampler_voice *v);
|
|
|
|
extern float sampler_channel_get_expensive_cc(struct sampler_channel *c, struct sampler_voice *v, struct sampler_prevoice *pv, int cc_no);
|
|
|
|
|
|
|
|
extern void sampler_prevoice_start(struct sampler_prevoice *pv, struct sampler_channel *c, struct sampler_layer_data *l, int note, int vel);
|
|
|
|
extern int sampler_prevoice_process(struct sampler_prevoice *pv, struct sampler_module *m);
|
|
|
|
extern void sampler_prevoice_link(struct sampler_prevoice **pv, struct sampler_prevoice *v);
|
|
|
|
extern void sampler_prevoice_unlink(struct sampler_prevoice **pv, struct sampler_prevoice *v);
|
|
|
|
|
|
|
|
extern float sampler_sine_wave[2049];
|
|
|
|
|
|
|
|
static inline int sampler_channel_addcc(struct sampler_channel *c, int cc_no)
|
|
|
|
{
|
|
|
|
return (((int)c->intcc[cc_no]) << 7) + c->intcc[cc_no + 32];
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float sampler_channel_getcc(struct sampler_channel *c, struct sampler_voice *v, int cc_no)
|
|
|
|
{
|
|
|
|
if (cc_no < 128)
|
|
|
|
return c->floatcc[cc_no];
|
|
|
|
return sampler_channel_get_expensive_cc(c, v, NULL, cc_no);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float sampler_program_get_curve_value(struct sampler_program *program, uint32_t curve_id, float val)
|
|
|
|
{
|
|
|
|
if (val < 0)
|
|
|
|
val = 0;
|
|
|
|
if (val > 1)
|
|
|
|
val = 1;
|
|
|
|
if (curve_id < MAX_MIDI_CURVES && program->interpolated_curves[curve_id])
|
|
|
|
{
|
|
|
|
float *curve = program->interpolated_curves[curve_id];
|
|
|
|
int vint = floorf(val * 127);
|
|
|
|
// Linear interpolation if within bounds
|
|
|
|
if (vint < 127)
|
|
|
|
{
|
|
|
|
float vfrac = val * 127 - vint;
|
|
|
|
val = curve[vint] + (curve[vint + 1] - curve[vint]) * vfrac;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
val = curve[vint];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// possibly wrong implementation of built in curves
|
|
|
|
switch(curve_id)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 3:
|
|
|
|
// slightly fake bipolar, so that both 63 and 64 are 'neutral' (needs to be somewhat symmetric)
|
|
|
|
if (val < 63.f/127.f)
|
|
|
|
val = (curve_id == 3 ? -1 : 1) * -(63.f - 127 * val) / 63.f;
|
|
|
|
else if (val <= 64.f/127.f)
|
|
|
|
val = 0;
|
|
|
|
else
|
|
|
|
val = (curve_id == 3 ? -1 : 1) * (127 * val - 64) / 63.f;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
val = 1 - val; break;
|
|
|
|
case 4:
|
|
|
|
val = val * val;
|
|
|
|
break; // maybe, or maybe it's inverted?
|
|
|
|
case 5: val = sqrtf(val);
|
|
|
|
break; // maybe
|
|
|
|
case 6: val = sqrtf(1-val);
|
|
|
|
break; // maybe
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float sampler_channel_getcc_mod(struct sampler_channel *c, struct sampler_voice *v, int cc_no, int curve_id, float step)
|
|
|
|
{
|
|
|
|
float val = (cc_no < 128) ? c->floatcc[cc_no] : sampler_channel_get_expensive_cc(c, v, NULL, cc_no);
|
|
|
|
if (step)
|
|
|
|
val = floorf(0.9999f * val * (step + 1)) / step;
|
|
|
|
if (curve_id || c->program->interpolated_curves[0])
|
|
|
|
val = sampler_program_get_curve_value(c->program, curve_id, val);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int sampler_channel_getintcc(struct sampler_channel *c, struct sampler_voice *v, int cc_no)
|
|
|
|
{
|
|
|
|
if (cc_no < 128)
|
|
|
|
return c->intcc[cc_no];
|
|
|
|
return (int)127 * (sampler_channel_get_expensive_cc(c, v, NULL, cc_no));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float sampler_channel_getcc_prevoice(struct sampler_channel *c, struct sampler_prevoice *pv, int cc_no, int curve_id, float step)
|
|
|
|
{
|
|
|
|
float val = (cc_no < 128) ? c->floatcc[cc_no] : sampler_channel_get_expensive_cc(c, NULL, pv, cc_no);
|
|
|
|
if (step)
|
|
|
|
val = floorf(0.9999f * val * (step + 1)) / step;
|
|
|
|
if (curve_id || c->program->interpolated_curves[0])
|
|
|
|
val = sampler_program_get_curve_value(c->program, curve_id, val);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline float sampler_channel_get_poly_pressure(struct sampler_channel *c, uint8_t note)
|
|
|
|
{
|
|
|
|
note &= 0x7F;
|
|
|
|
return (c->poly_pressure_mask & (1 << (note >> 2))) ? c->poly_pressure[note] * (1.f / 127.f) : 0;;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline gboolean sampler_cc_range_is_in(const struct sampler_cc_range *range, struct sampler_channel *c)
|
|
|
|
{
|
|
|
|
while(range)
|
|
|
|
{
|
|
|
|
int ccval = sampler_channel_getintcc(c, NULL, range->key.cc_number);
|
|
|
|
if (ccval < range->value.locc || ccval > range->value.hicc)
|
|
|
|
return FALSE;
|
|
|
|
range = range->next;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FOREACH_VOICE(var, p) \
|
|
|
|
for (struct sampler_voice *p = (var), *p##_next = NULL; p && (p##_next = p->next, TRUE); p = p##_next)
|
|
|
|
#define FOREACH_PREVOICE(var, p) \
|
|
|
|
for (struct sampler_prevoice *p = (var), *p##_next = NULL; p && (p##_next = p->next, TRUE); p = p##_next)
|
|
|
|
#define CANCEL_PREVOICE(var, p) \
|
|
|
|
{\
|
|
|
|
struct sampler_prevoice *_tmp = (p); \
|
|
|
|
if (_tmp->prev) \
|
|
|
|
_tmp->prev->next = _tmp->next; \
|
|
|
|
else \
|
|
|
|
var = _tmp->next; \
|
|
|
|
_tmp->prev = _tmp->next = NULL; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|