/*
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/>.
*/
# 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 <assert.h>
# include <errno.h>
# include <glib.h>
# include <math.h>
# include <memory.h>
# include <sndfile.h>
# include <stdio.h>
# include <stdlib.h>
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 <arm_neon.h>
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 ) ;
}