#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"

//////////////////////////////////////////////////////////////////////////
// Note initialisation functions

void sampler_nif_cc2delay(struct sampler_noteinitfunc *nif, struct sampler_prevoice *pv)
{
    float cc = sampler_channel_getcc_prevoice(pv->channel, pv, nif->key.variant, nif->value.curve_id, nif->value.step);
    pv->delay_computed += nif->value.value * cc;
}

void sampler_nif_addrandomdelay(struct sampler_noteinitfunc *nif, struct sampler_prevoice *pv)
{
    pv->delay_computed += nif->value.value * rand() * (1.0 / RAND_MAX);
}

void sampler_nif_syncbeats(struct sampler_noteinitfunc *nif, struct sampler_prevoice *pv)
{
    if (nif->value.value > 0)
    {
        pv->sync_beats = nif->value.value;
        double cur_beat = sampler_get_current_beat(pv->channel->module);
        pv->sync_initial_time = cur_beat;
        double cur_rel_beat = fmod(cur_beat, pv->sync_beats);
        double bar_start = cur_beat - cur_rel_beat;
        if (pv->layer_data->sync_offset <= cur_rel_beat) // trigger in next bar
            pv->sync_trigger_time = bar_start + pv->sync_beats + pv->layer_data->sync_offset;
        else // trigger in the same bar
            pv->sync_trigger_time = bar_start + pv->layer_data->sync_offset;
        // printf("cur_beat %f trigger %f offset %f\n", cur_beat, pv->sync_trigger_time, pv->layer_data->sync_offset);
    }
}

void sampler_nif_vel2pitch(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    v->pitch_shift += nif->value.value * v->vel * (1.0 / 127.0);
}

void sampler_nif_vel2offset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    v->offset += nif->value.value * v->vel * (1.0 / 127.0);
}

void sampler_nif_cc2offset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    v->offset += nif->value.value * sampler_channel_getcc_mod(v->channel, v, nif->key.variant, nif->value.curve_id, nif->value.step);
}

void sampler_nif_vel2reloffset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    v->reloffset += nif->value.value * v->vel * (1.0 / 127.0);
}

void sampler_nif_cc2reloffset(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    v->reloffset += nif->value.value * sampler_channel_getcc_mod(v->channel, v, nif->key.variant, nif->value.curve_id, nif->value.step);
}

void sampler_nif_addrandom(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    float rnd = rand() * 1.0 / RAND_MAX;
    switch(nif->key.variant)
    {
        case 0:
            v->gain_shift += rnd * nif->value.value;
            break;
        case 1:
            v->cutoff_shift += rnd * nif->value.value;
            break;
        case 2:
            v->pitch_shift += rnd * nif->value.value; // this is in cents
            break;
    }
}

static void modify_env_stage_by_nif(struct sampler_noteinitfunc *nif, struct sampler_voice *v, uint32_t variant, float value)
{
    int env_type = variant >> 4;
    struct cbox_envelope *env = NULL;
    switch(env_type)
    {
        case 0:
            env = &v->amp_env;
            break;
        case 1:
            env = &v->filter_env;
            break;
        case 2:
            env = &v->pitch_env;
            break;
        default:
            assert(0);
    }
    if (env->shape != &v->vel_envs[env_type])
    {
        memcpy(&v->vel_envs[env_type], env->shape, sizeof(struct cbox_envelope_shape));
        env->shape = &v->vel_envs[env_type];
    }
    float param = nif->value.value * value;
    if ((variant & 15) == snif_env_sustain || (variant & 15) == snif_env_start)
        param *= 0.01;
    cbox_envelope_modify_dahdsr(env->shape, variant & 15, param, v->channel->module->module.srate * (1.0 / CBOX_BLOCK_SIZE));
}

void sampler_nif_vel2env(struct sampler_noteinitfunc *nif, struct sampler_voice *v)
{
    modify_env_stage_by_nif(nif, v, nif->key.variant, v->vel * (1.0 / 127.0));
}
