Example #1
0
bool Cgiter_get_local_bp_dist(const Cgiter* cgiter, Tstamp* dist)
{
    rassert(cgiter != NULL);
    rassert(dist != NULL);
    rassert(Tstamp_cmp(dist, TSTAMP_AUTO) >= 0);

    if (Cgiter_has_finished(cgiter))
        return false;

    const Pattern* pattern = find_pattern(cgiter);
    if (pattern == NULL)
        return false;

    // Check pattern end
    const Tstamp* pat_length = Pattern_get_length(pattern);
    const Tstamp* dist_to_end =
        Tstamp_sub(TSTAMP_AUTO, pat_length, &cgiter->pos.pat_pos);

    if (Tstamp_cmp(dist_to_end, TSTAMP_AUTO) <= 0)
    {
        // We cannot move forwards in playback time
        Tstamp_set(dist, 0, 0);
        return true;
    }

    // Check next trigger row
    Column* column = Pattern_get_column(pattern, cgiter->col_index);
    rassert(column != NULL);
    Column_iter* citer = Column_iter_init(COLUMN_ITER_AUTO);
    Column_iter_change_col(citer, column);

    const Tstamp* epsilon = Tstamp_set(TSTAMP_AUTO, 0, 1);
    Tstamp* next_pos_min = Tstamp_add(TSTAMP_AUTO, &cgiter->pos.pat_pos, epsilon);
    const Trigger_list* row = Column_iter_get_row(citer, next_pos_min);

    if (row != NULL)
    {
        rassert(row->next != NULL);
        rassert(row->next->trigger != NULL);
        if (Tstamp_cmp(&row->next->trigger->pos, pat_length) <= 0)
        {
            // Trigger row found inside this pattern
            const Tstamp* dist_to_row = Tstamp_sub(
                    TSTAMP_AUTO,
                    &row->next->trigger->pos,
                    &cgiter->pos.pat_pos);
            Tstamp_mina(dist, dist_to_row);
            return true;
        }
    }

    // No trigger row found
    Tstamp_mina(dist, dist_to_end);
    return true;
}
bool Event_channel_set_arpeggio_speed_process(
        Channel* ch,
        Device_states* dstates,
        const Value* value)
{
    assert(ch != NULL);
    assert(dstates != NULL);
    (void)dstates;
    assert(value != NULL);
    assert(value->type == VALUE_TYPE_FLOAT);

    ch->arpeggio_speed = value->value.float_type;
    const double unit_len = Tstamp_toframes(
            Tstamp_set(TSTAMP_AUTO, 1, 0),
            *ch->tempo,
            *ch->freq);

    for (int i = 0; i < KQT_GENERATORS_MAX; ++i)
    {
        Event_check_voice(ch, i);
        Voice_state* vs = ch->fg[i]->state;
        vs->arpeggio_length = unit_len / value->value.float_type;
    }

    return true;
}
Example #3
0
bool Streader_read_tstamp(Streader* sr, Tstamp* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t beats = 0;
    int64_t rem = 0;

    if (!(Streader_match_char(sr, '[')  &&
                Streader_read_int(sr, &beats) &&
                Streader_match_char(sr, ',')  &&
                Streader_read_int(sr, &rem)   &&
                Streader_match_char(sr, ']')))
    {
        Streader_set_error(sr, "Expected a valid timestamp");
        return false;
    }

    if (rem < 0 || rem >= KQT_TSTAMP_BEAT)
    {
        Streader_set_error(
                sr,
                "Timestamp remainder %" PRId64 " out of range [0..%ld)",
                rem,
                KQT_TSTAMP_BEAT);
        return false;
    }

    if (dest != NULL)
        Tstamp_set(dest, beats, (int32_t)rem);

    return true;
}
Example #4
0
Jump_context* new_Jump_context(void)
{
    Jump_context* jc = memory_alloc_item(Jump_context);
    if (jc == NULL)
        return NULL;

    jc->piref.pat = -1;
    jc->piref.inst = -1;
    Tstamp_set(&jc->row, 0, 0);
    jc->ch_num = 0;
    jc->order = 0;

    jc->counter = 0;

    jc->target_piref.pat = -1;
    jc->target_piref.inst = -1;
    Tstamp_set(&jc->target_row, 0, 0);

    return jc;
}
Example #5
0
bool Event_control_play_pattern_process(
        General_state* global_state, Channel* channel, const Value* value)
{
    rassert(global_state != NULL);
    rassert(channel != NULL);
    rassert(value != NULL);
    rassert(value->type == VALUE_TYPE_PAT_INST_REF);

    Master_params* master_params = (Master_params*)global_state;
    master_params->playback_state = PLAYBACK_PATTERN;
    master_params->pattern_playback_flag = true;

    master_params->cur_pos.track = -1;
    master_params->cur_pos.system = -1;
    Tstamp_set(&master_params->cur_pos.pat_pos, 0, 0);
    master_params->cur_pos.piref = value->value.Pat_inst_ref_type;

    // Reset parameters to make sure we start at the new location immediately
    master_params->parent.pause = false;
    Tstamp_set(&master_params->delay_left, 0, 0);

    return true;
}
Example #6
0
END_TEST


START_TEST(Read_valid_tstamp)
{
    static const struct
    {
        const char* data;
        const Tstamp expected;
    }
    tstamps[] =
    {
        { "[0, 0]", { 0, 0 } },
        { "[2,5]",  { 2, 5 } },
        { " [2,5]", { 2, 5 } },
        { "[ 2,5]", { 2, 5 } },
        { "[2 ,5]", { 2, 5 } },
        { "[2, 5]", { 2, 5 } },
        { "[2,5 ]", { 2, 5 } },
        { "[-1, 3]", { -1, 3 } },
        { "[0, 882161279]", { 0, KQT_TSTAMP_BEAT - 1 } },
    };

    for (size_t i = 0; i < arr_size(tstamps); ++i)
    {
        char data[128] = "";
        sprintf(data, "%s x", tstamps[i].data);

        Streader* sr = init_with_cstr(data);
        Tstamp* result = Tstamp_set(TSTAMP_AUTO, 99, 99);

        fail_if(!Streader_read_tstamp(sr, result),
                "Could not read timestamp " PRIts " from `%s`: %s",
                PRIVALts(tstamps[i].expected),
                data,
                Streader_get_error_desc(sr));
        fail_if(Tstamp_cmp(result, &tstamps[i].expected) != 0,
                "Streader stored " PRIts " instead of " PRIts
                    " when reading `%s`",
                PRIVALts(*result),
                PRIVALts(tstamps[i].expected),
                data);
        fail_if(!Streader_match_char(sr, 'x'),
                "Streader did not consume timestamp from `%s` correctly", data);
    }
}
Example #7
0
void Cgiter_move(Cgiter* cgiter, const Tstamp* dist)
{
    rassert(cgiter != NULL);
    rassert(dist != NULL);
    rassert(Tstamp_cmp(dist, TSTAMP_AUTO) >= 0);

    if (cgiter->pos.piref.pat < 0)
        return;

    // Find current pattern
    const Pattern* pattern = Module_get_pattern(cgiter->module, &cgiter->pos.piref);
    if (pattern == NULL)
    {
        cgiter->has_finished = true;
        return;
    }

    // Check if we are at the end of a pattern
    const Tstamp* pat_length = Pattern_get_length(pattern);
    if (Tstamp_cmp(&cgiter->pos.pat_pos, pat_length) >= 0)
    {
        // dist must be 0 or the pattern length changed
        if (cgiter->is_pattern_playback_state)
        {
            Tstamp_set(&cgiter->pos.pat_pos, 0, 0);

            // Play zero-length pattern only once to avoid infinite loop
            if (Tstamp_cmp(pat_length, TSTAMP_AUTO) == 0)
                cgiter->has_finished = true;
        }
        else
        {
            Cgiter_go_to_next_system(cgiter);
        }

        cgiter->row_returned = false;
        return;
    }

    // Move forwards
    Tstamp_adda(&cgiter->pos.pat_pos, dist);
    if (Tstamp_cmp(dist, TSTAMP_AUTO) > 0)
        cgiter->row_returned = false;

    return;
}
Example #8
0
static void Cgiter_go_to_next_system(Cgiter* cgiter)
{
    rassert(cgiter != NULL);
    rassert(!cgiter->is_pattern_playback_state);

    Tstamp_set(&cgiter->pos.pat_pos, 0, 0);

    ++cgiter->pos.system;
    cgiter->pos.piref.pat = -1;
    const Pat_inst_ref* piref =
        find_pat_inst_ref(cgiter->module, cgiter->pos.track, cgiter->pos.system);
    if (piref != NULL)
        cgiter->pos.piref = *piref;
    else
        cgiter->has_finished = true;

    return;
}
bool Event_channel_arpeggio_on_process(
        Channel* ch,
        Device_states* dstates,
        const Value* value)
{
    assert(ch != NULL);
    assert(dstates != NULL);
    (void)dstates;
    (void)value;

    for (int i = 0; i < KQT_GENERATORS_MAX; ++i)
    {
        Event_check_voice(ch, i);
        Voice* voice = ch->fg[i];
        Voice_state* vs = voice->state;
        //pitch_t orig_pitch = -1;
        if (vs->arpeggio || voice->gen->ins_params->pitch_locks[i].enabled)
            continue;

#if 0
        if (voice->gen->ins_params->scale != NULL &&
                *voice->gen->ins_params->scale != NULL &&
                **voice->gen->ins_params->scale != NULL)
        {
            orig_pitch = Scale_get_pitch_from_cents(
                         **voice->gen->ins_params->scale, vs->orig_cents);
        }
        else
        {
            orig_pitch = exp2(vs->orig_cents / 1200) * 440;
        }
        if (orig_pitch <= 0)
        {
            vs->arpeggio = false;
            continue;
        }
#endif
        if (isnan(ch->arpeggio_ref))
            ch->arpeggio_ref = vs->orig_cents;

        if (isnan(ch->arpeggio_tones[0]))
            ch->arpeggio_tones[0] = ch->arpeggio_ref;

        vs->arpeggio_ref = ch->arpeggio_ref;
        memcpy(vs->arpeggio_tones, ch->arpeggio_tones,
                KQT_ARPEGGIO_NOTES_MAX * sizeof(double));
#if 0
        int last_nonzero = -1;
        for (int k = 0; k < KQT_ARPEGGIO_NOTES_MAX; ++k)
        {
            if (data[k + 1].field.double_type != 0)
            {
                last_nonzero = k;
            }
            pitch_t new_pitch = -1;
            if (voice->gen->ins_params->scale != NULL &&
                    *voice->gen->ins_params->scale != NULL &&
                    **voice->gen->ins_params->scale != NULL)
            {
                Scale* scale = **voice->gen->ins_params->scale;
                new_pitch = Scale_get_pitch_from_cents(scale,
                            vs->orig_cents + data[k + 1].field.double_type);
            }
            else
            {
                new_pitch = vs->orig_cents + data[k + 1].field.double_type;
            }
            if (new_pitch <= 0)
            {
                last_nonzero = -1;
                break;
            }
            else
            {
                vs->arpeggio_factors[k] = new_pitch / orig_pitch;
            }
        }
        if (last_nonzero == -1)
        {
            vs->arpeggio = false;
            continue;
        }
        else if (last_nonzero < KQT_ARPEGGIO_NOTES_MAX - 1)
        {
            vs->arpeggio_factors[last_nonzero + 1] = -1;
        }
#endif
        const double unit_len = Tstamp_toframes(
                Tstamp_set(TSTAMP_AUTO, 1, 0),
                *ch->tempo,
                *ch->freq);
        vs->arpeggio_length = unit_len / ch->arpeggio_speed;
        vs->arpeggio_frames = 0;
        vs->arpeggio_note = 0;
        vs->arpeggio = true;
    }

    return true;
}