コード例 #1
0
ファイル: Effect.c プロジェクト: cyberixae/kunquat
static void Effect_process(
        const Device* device,
        Device_states* states,
        uint32_t start,
        uint32_t until,
        uint32_t freq,
        double tempo)
{
    assert(device != NULL);
    assert(states != NULL);
    assert(freq > 0);
    assert(isfinite(tempo));

    Effect_state* eff_state = (Effect_state*)Device_states_get_state(
            states,
            Device_get_id(device));

    const Effect* eff = (const Effect*)device;

    if (eff_state->bypass)
    {
        Device_state* ds = Device_states_get_state(
                states, Device_get_id((const Device*)device));

        mix_interface_connection(ds, ds, start, until);
    }
    else if (eff->connections != NULL)
    {
#ifndef NDEBUG
        static bool in_effect = false;
        assert(!in_effect);
        in_effect = true;
#endif
        Connections_clear_buffers(eff->connections, states, start, until);

        // Fill input interface buffers
        Device_state* ds = Device_states_get_state(
                states, Device_get_id((const Device*)device));
        Device_state* in_iface_ds = Device_states_get_state(
                states, Device_get_id(Effect_get_input_interface(eff)));
        mix_interface_connection(in_iface_ds, ds, start, until);

        // Process effect graph
        Connections_mix(eff->connections, states, start, until, freq, tempo);

        // Fill output interface buffers
        Device_state* out_iface_ds = Device_states_get_state(
                states, Device_get_id(Effect_get_output_interface(eff)));
        mix_interface_connection(ds, out_iface_ds, start, until);
#ifndef NDEBUG
        in_effect = false;
#endif
    }

    return;
}
コード例 #2
0
ファイル: Au_state.c プロジェクト: kagu/kunquat
static void Au_state_fire_event(
        Device_state* dstate, const char* event_name, const Value* arg, Random* rand)
{
    rassert(dstate != NULL);
    rassert(event_name != NULL);
    rassert(arg != NULL);
    rassert(rand != NULL);

    const Audio_unit* au = (const Audio_unit*)dstate->device;

    const Au_event_map* map = Audio_unit_get_event_map(au);
    if (map == NULL)
        return;

    const Proc_table* procs = Audio_unit_get_procs(au);
    Au_event_iter* iter = AU_EVENT_ITER_AUTO;
    Au_event_iter_result* result = Au_event_iter_init(iter, map, event_name, arg, rand);
    while (result != NULL)
    {
        rassert(result->dev_type == AU_EVENT_TARGET_DEV_PROC);
        const Device* device =
            (const Device*)Proc_table_get_proc(procs, result->dev_index);
        if (device != NULL)
        {
            Device_states* dstates = ((Au_state*)dstate)->dstates;
            Device_state* pstate =
                Device_states_get_state(dstates, Device_get_id(device));
            Device_state_fire_event(pstate, result->event_name, &result->arg, rand);
        }

        result = Au_event_iter_get_next(iter);
    }

    return;
}
コード例 #3
0
ファイル: Event_au_streams.c プロジェクト: kagu/kunquat
static Device_state* get_target_dstate(
        const Audio_unit* au, Device_states* dstates, const char* stream_name)
{
    rassert(au != NULL);
    rassert(dstates != NULL);
    rassert(stream_name != NULL);

    const Au_streams* streams = Audio_unit_get_streams(au);
    if (streams == NULL)
        return NULL;

    const int proc_index = Au_streams_get_target_proc_index(streams, stream_name);
    if (proc_index < 0)
        return NULL;

    const Processor* proc = Audio_unit_get_proc(au, proc_index);
    if ((proc == NULL) || !Device_is_existent((const Device*)proc))
        return NULL;

    Device_state* dstate =
        Device_states_get_state(dstates, Device_get_id((const Device*)proc));
    if (Device_impl_get_proc_type(dstate->device->dimpl) != Proc_type_stream)
        return NULL;

    return dstate;
}
コード例 #4
0
ファイル: Device.c プロジェクト: EdwardBetts/kunquat
bool Device_sync_states(const Device* device, Device_states* dstates)
{
    assert(device != NULL);
    assert(dstates != NULL);

    if (device->dimpl != NULL)
    {
        Device_state* dstate = Device_states_get_state(
                dstates, Device_get_id(device));

        Device_params_iter* iter = Device_params_iter_init(
                DEVICE_PARAMS_ITER_AUTO, device->dparams);

        const char* key = Device_params_iter_get_next_key(iter);
        while (key != NULL)
        {
            if (!Device_impl_set_state_key(device->dimpl, dstate, key))
                return false;

            key = Device_params_iter_get_next_key(iter);
        }
    }

    return true;
}
コード例 #5
0
ファイル: Device_states.c プロジェクト: kagu/kunquat
static bool init_effect_buffers(Device_states* dstates, const Device_node* node)
{
    rassert(dstates != NULL);
    rassert(node != NULL);

    const Device* node_device = Device_node_get_device(node);
    if (node_device == NULL)
        return true;

    Device_thread_state* node_ts =
        Device_states_get_thread_state(dstates, 0, Device_get_id(node_device));

    if (Device_thread_state_get_node_state(node_ts) > DEVICE_NODE_STATE_NEW)
    {
        rassert(Device_thread_state_get_node_state(node_ts) != DEVICE_NODE_STATE_REACHED);
        return true;
    }

    Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_REACHED);

    if (Device_node_get_type(node) == DEVICE_NODE_TYPE_AU)
    {
        const Audio_unit* au = Device_node_get_au_mut(node);
        if (au == NULL)
        {
            Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_VISITED);
            return true;
        }

        const Connections* au_conns = Audio_unit_get_connections(au);
        if (au_conns != NULL)
        {
            if (!Device_states_prepare(dstates, au_conns))
                return false;
        }
    }

    for (int port = 0; port < KQT_DEVICE_PORTS_MAX; ++port)
    {
        const Connection* edge = Device_node_get_received(node, port);
        while (edge != NULL)
        {
            if (Device_node_get_device(edge->node) == NULL)
            {
                edge = edge->next;
                continue;
            }

            if (!init_effect_buffers(dstates, edge->node))
                return false;

            edge = edge->next;
        }
    }

    Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_VISITED);
    return true;
}
コード例 #6
0
ファイル: DSP_gc.c プロジェクト: cyberixae/kunquat
static void DSP_gc_process(
        const Device* device,
        Device_states* states,
        uint32_t start,
        uint32_t until,
        uint32_t freq,
        double tempo)
{
    assert(device != NULL);
    assert(states != NULL);
    assert(freq > 0);
    assert(tempo > 0);

    Device_state* ds = Device_states_get_state(states, Device_get_id(device));
    assert(ds != NULL);

    (void)freq;
    (void)tempo;
    DSP_gc* gc = (DSP_gc*)device->dimpl;
    //assert(string_eq(gc->parent.type, "gaincomp"));
    kqt_frame* in_data[] = { NULL, NULL };
    kqt_frame* out_data[] = { NULL, NULL };
    DSP_get_raw_input(ds, 0, in_data);
    DSP_get_raw_output(ds, 0, out_data);

    if (gc->map != NULL)
    {
        for (uint32_t i = start; i < until; ++i)
        {
            kqt_frame val_l = fabs(in_data[0][i]);
            kqt_frame val_r = fabs(in_data[1][i]);
            val_l = Envelope_get_value(gc->map, min(val_l, 1));
            val_r = Envelope_get_value(gc->map, min(val_r, 1));
            if (in_data[0][i] < 0)
                val_l = -val_l;
            if (in_data[1][i] < 0)
                val_r = -val_r;

            out_data[0][i] += val_l;
            out_data[1][i] += val_r;
            assert(!isnan(out_data[0][i]) || isnan(in_data[0][i]));
            assert(!isnan(out_data[0][i]) || isnan(in_data[1][i]));
        }
    }
    else
    {
        for (uint32_t i = start; i < until; ++i)
        {
            out_data[0][i] += in_data[0][i];
            out_data[1][i] += in_data[1][i];
        }
    }

    return;
}
コード例 #7
0
ファイル: DSP_freeverb.c プロジェクト: cyberixae/kunquat
static void DSP_freeverb_process(
        const Device* device,
        Device_states* states,
        uint32_t start,
        uint32_t until,
        uint32_t freq,
        double tempo)
{
    assert(device != NULL);
    assert(states != NULL);
    assert(freq > 0);
    assert(tempo > 0);
    (void)freq;
    (void)tempo;

    Freeverb_state* fstate = (Freeverb_state*)Device_states_get_state(
            states, Device_get_id(device));

    DSP_freeverb* freeverb = (DSP_freeverb*)device->dimpl;
    //assert(string_eq(freeverb->parent.type, "freeverb"));
    kqt_frame* in_data[] = { NULL, NULL };
    kqt_frame* out_data[] = { NULL, NULL };
    DSP_get_raw_input(&fstate->parent.parent, 0, in_data);
    DSP_get_raw_output(&fstate->parent.parent, 0, out_data);

    for (uint32_t i = start; i < until; ++i)
    {
        kqt_frame out_l = 0;
        kqt_frame out_r = 0;
        kqt_frame input = (in_data[0][i] + in_data[1][i]) * freeverb->gain;

        for (int comb = 0; comb < FREEVERB_COMBS; ++comb)
        {
            out_l += Freeverb_comb_process(fstate->comb_left[comb], input);
            out_r += Freeverb_comb_process(fstate->comb_right[comb], input);
        }

        for (int allpass = 0; allpass < FREEVERB_ALLPASSES; ++allpass)
        {
            out_l = Freeverb_allpass_process(
                    fstate->allpass_left[allpass], out_l);
            out_r = Freeverb_allpass_process(
                    fstate->allpass_right[allpass], out_r);
        }

        out_data[0][i] += out_l * freeverb->wet1 + out_r * freeverb->wet2
                                  /* + in_data[0][i] * freeverb->dry */;
        out_data[1][i] += out_r * freeverb->wet1 + out_l * freeverb->wet2
                                  /* + in_data[1][i] * freeverb->dry */;
    }

    return;
}
コード例 #8
0
ファイル: Device.c プロジェクト: EdwardBetts/kunquat
bool Device_set_state_key(
        const Device* device,
        Device_states* dstates,
        const char* key)
{
    assert(device != NULL);
    assert(dstates != NULL);
    assert(key != NULL);
    assert(string_has_prefix(key, "i/") || string_has_prefix(key, "c/"));

    if (device->dimpl != NULL)
    {
        Device_state* dstate = Device_states_get_state(
                dstates, Device_get_id(device));
        return Device_impl_set_state_key(device->dimpl, dstate, key + 2);
    }

    return true;
}
コード例 #9
0
ファイル: Effect.c プロジェクト: cyberixae/kunquat
static void Effect_reset(const Device* device, Device_states* dstates)
{
    assert(device != NULL);
    assert(dstates != NULL);

    // Reset DSPs
    const Effect* eff = (const Effect*)device;
    for (int i = 0; i < KQT_DSPS_MAX; ++i)
    {
        const DSP* dsp = DSP_table_get_dsp(eff->dsps, i);
        if (dsp != NULL)
            Device_reset((const Device*)dsp, dstates);
    }

    // Reset Effect state
    Effect_state* eff_state = (Effect_state*)Device_states_get_state(
            dstates,
            Device_get_id(device));
    Effect_state_reset(eff_state);

    return;
}
コード例 #10
0
ファイル: Device_states.c プロジェクト: kagu/kunquat
static bool init_buffers(Device_states* dstates, const Device_node* node)
{
    rassert(dstates != NULL);
    rassert(node != NULL);

    const Device* node_device = Device_node_get_device(node);
    if (node_device == NULL)
        return true;

    Device_thread_state* node_ts =
        Device_states_get_thread_state(dstates, 0, Device_get_id(node_device));
    rassert(Device_thread_state_get_node_state(node_ts) != DEVICE_NODE_STATE_REACHED);

    if (Device_thread_state_get_node_state(node_ts) == DEVICE_NODE_STATE_VISITED)
        return true;

    Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_REACHED);

    for (int port = 0; port < KQT_DEVICE_PORTS_MAX; ++port)
    {
        const Connection* edge = Device_node_get_received(node, port);
        while (edge != NULL)
        {
            rassert(edge->node != NULL);
            const Device* send_device = Device_node_get_device(edge->node);
            if (send_device == NULL ||
                    !Device_has_complete_type(send_device) ||
                    !Device_get_port_existence(
                        node_device, DEVICE_PORT_TYPE_RECV, port) ||
                    !Device_get_port_existence(
                        send_device, DEVICE_PORT_TYPE_SEND, edge->port))
            {
                edge = edge->next;
                continue;
            }
            /*
            if (!Device_get_port_existence(
                    node_device, DEVICE_PORT_TYPE_RECV, port))
                fprintf(stderr, "Warning: connecting to non-existent port %d of device %s\n",
                        port, node->name);
            if (!Device_get_port_existence(
                    send_device, DEVICE_PORT_TYPE_SEND, edge->port))
                fprintf(stderr, "Warning: connecting from non-existent port %d of device %s\n",
                        edge->port, edge->node->name);
            // */

            // Add receive buffers
            const uint32_t recv_id = Device_get_id(node_device);
            if (!Device_states_add_audio_buffer(
                        dstates, recv_id, DEVICE_PORT_TYPE_RECV, port))
                return false;

            // Add send buffers
            const uint32_t send_id = Device_get_id(send_device);
            if (!Device_states_add_audio_buffer(
                        dstates, send_id, DEVICE_PORT_TYPE_SEND, edge->port))
                return false;

            // Recurse to the sender
            if (!init_buffers(dstates, edge->node))
                return false;

            edge = edge->next;
        }
    }

    Device_thread_state_set_node_state(node_ts, DEVICE_NODE_STATE_VISITED);
    return true;
}
コード例 #11
0
ファイル: Event_channel_note.c プロジェクト: kagu/kunquat
bool Event_channel_hit_process(
        Channel* ch,
        Device_states* dstates,
        const Master_params* master_params,
        const Event_params* params)
{
    rassert(ch != NULL);
    rassert(ch->audio_rate > 0);
    rassert(ch->tempo > 0);
    rassert(dstates != NULL);
    rassert(master_params != NULL);
    rassert(params != NULL);
    rassert(params->arg != NULL);
    rassert(params->arg->type == VALUE_TYPE_INT);

    // Move the old Voices to the background
    Event_channel_note_off_process(ch, dstates, master_params, NULL);

    // Find our audio unit
    Audio_unit* au = Module_get_au_from_input(ch->parent.module, ch->au_input);
    if (au == NULL)
        return true;

    init_force_controls(ch, master_params);

    // Don't attempt to hit effects
    if (Audio_unit_get_type(au) != AU_TYPE_INSTRUMENT)
        return true;

    const int hit_index = (int)params->arg->value.int_type;

    if (!Audio_unit_get_hit_existence(au, hit_index))
        return true;

    const Param_proc_filter* hpf = Audio_unit_get_hit_proc_filter(au, hit_index);

    // Generate our next note random seed here so that random generation
    // is consistent even if we run out of voices
    const uint64_t note_rand_seed = Random_get_uint64(&ch->rand);

    // Find reserved voices
    Voice_group* vgroup = VOICE_GROUP_AUTO;

    if (!Voice_group_reservations_get_clear_entry(
                ch->voice_group_res, ch->num, &ch->fg_group_id) ||
            (Voice_pool_get_group(ch->pool, ch->fg_group_id, vgroup) == NULL))
    {
        reset_channel_voices(ch);
        return true;
    }

    int voice_index = 0;

    for (int i = 0; i < KQT_PROCESSORS_MAX; ++i)
    {
        const Processor* proc = Audio_unit_get_proc(au, i);
        if (proc == NULL ||
                !Device_is_existent((const Device*)proc) ||
                !Processor_get_voice_signals(proc))
            continue;

        // Skip processors that are filtered out for this hit index
        if ((hpf != NULL) && !Param_proc_filter_is_proc_allowed(hpf, i))
            continue;

        const Proc_state* proc_state = (Proc_state*)Device_states_get_state(
                dstates, Device_get_id((const Device*)proc));

        Voice_state_get_size_func* get_vstate_size =
            proc_state->parent.device->dimpl->get_vstate_size;
        if ((get_vstate_size != NULL) && (get_vstate_size() == 0))
            continue;

        char context_str[16] = "";
        snprintf(context_str, 16, "np%hd", (short)i);
        Random* random = Random_init(RANDOM_AUTO, context_str);
        Random_set_seed(random, note_rand_seed);
        const uint64_t voice_rand_seed = Random_get_uint64(random);

        Voice* voice = Voice_group_get_voice(vgroup, voice_index);

        const bool voice_allocated = init_voice(
                ch, voice, au, ch->fg_group_id, proc_state, i, voice_rand_seed);
        if (!voice_allocated)
        {
            // Some of our voices were reallocated
            reset_channel_voices(ch);
            return true;
        }

        ++voice_index;

        Voice_state* vs = voice->state;
        vs->hit_index = hit_index;

        if (vs->proc_type == Proc_type_force)
        {
            Force_controls* fc = Force_vstate_get_force_controls_mut(vs);
            Force_controls_copy(fc, &ch->force_controls);
        }
    }

    Channel_reset_test_output(ch);

    init_streams(ch, au);

    return true;
}
コード例 #12
0
ファイル: Event_channel_note.c プロジェクト: kagu/kunquat
bool Event_channel_note_on_process(
        Channel* ch,
        Device_states* dstates,
        const Master_params* master_params,
        const Event_params* params)
{
    rassert(ch != NULL);
    rassert(ch->audio_rate > 0);
    rassert(ch->tempo > 0);
    rassert(dstates != NULL);
    rassert(master_params != NULL);
    rassert(params != NULL);
    rassert(params->arg != NULL);
    rassert(params->arg->type == VALUE_TYPE_FLOAT);

    // Move the old Voices to the background
    Event_channel_note_off_process(ch, dstates, master_params, NULL);

    // Find our audio unit
    Audio_unit* au = Module_get_au_from_input(ch->parent.module, ch->au_input);
    if (au == NULL)
        return true;

    double pitch_param = params->arg->value.float_type;

    // Retune pitch parameter if a retuner is active
    {
        const int tuning_index = master_params->cur_tuning_state;
        if (0 <= tuning_index && tuning_index < KQT_TUNING_TABLES_MAX)
        {
            Tuning_state* state = master_params->tuning_states[tuning_index];
            const Tuning_table* table =
                Module_get_tuning_table(master_params->parent.module, tuning_index);
            if (state != NULL && table != NULL)
                pitch_param = Tuning_state_get_retuned_pitch(state, table, pitch_param);
        }
    }

    if (ch->carry_pitch)
    {
        if (isnan(ch->pitch_controls.pitch))
            ch->pitch_controls.pitch = pitch_param;
        if (isnan(ch->pitch_controls.orig_carried_pitch))
            ch->pitch_controls.orig_carried_pitch = pitch_param;

        const double pitch_diff = pitch_param - ch->pitch_controls.orig_carried_pitch;
        ch->pitch_controls.pitch_add = pitch_diff;
    }
    else
    {
        Pitch_controls_reset(&ch->pitch_controls);
        ch->pitch_controls.orig_carried_pitch = pitch_param;

        Slider_set_tempo(&ch->pitch_controls.slider, master_params->tempo);
        Slider_set_length(&ch->pitch_controls.slider, &ch->pitch_slide_length);

        LFO_set_tempo(&ch->pitch_controls.vibrato, master_params->tempo);
        LFO_set_speed_slide(&ch->pitch_controls.vibrato, &ch->vibrato_speed_slide);
        LFO_set_depth_slide(&ch->pitch_controls.vibrato, &ch->vibrato_depth_slide);

        ch->pitch_controls.pitch = pitch_param;
        if (isnan(ch->pitch_controls.orig_carried_pitch))
            ch->pitch_controls.orig_carried_pitch = pitch_param;
    }

    init_force_controls(ch, master_params);

    // Don't attempt to play effects
    if (Audio_unit_get_type(au) != AU_TYPE_INSTRUMENT)
        return true;

    // Generate our next note random seed here so that random generation
    // is consistent even if we run out of voices
    const uint64_t note_rand_seed = Random_get_uint64(&ch->rand);

    // Find reserved voices
    Voice_group* vgroup = VOICE_GROUP_AUTO;

    if (!Voice_group_reservations_get_clear_entry(
                ch->voice_group_res, ch->num, &ch->fg_group_id) ||
            (Voice_pool_get_group(ch->pool, ch->fg_group_id, vgroup) == NULL))
    {
        reset_channel_voices(ch);
        return true;
    }

    int voice_index = 0;

    for (int i = 0; i < KQT_PROCESSORS_MAX; ++i)
    {
        const Processor* proc = Audio_unit_get_proc(au, i);
        if (proc == NULL ||
                !Device_is_existent((const Device*)proc) ||
                !Processor_get_voice_signals(proc))
            continue;

        const Proc_state* proc_state = (Proc_state*)Device_states_get_state(
                dstates, Device_get_id((const Device*)proc));

        Voice_state_get_size_func* get_vstate_size =
            proc_state->parent.device->dimpl->get_vstate_size;
        if ((get_vstate_size != NULL) && (get_vstate_size() == 0))
            continue;

        char context_str[16] = "";
        snprintf(context_str, 16, "np%hd", (short)i);
        Random* random = Random_init(RANDOM_AUTO, context_str);
        Random_set_seed(random, note_rand_seed);
        const uint64_t voice_rand_seed = Random_get_uint64(random);

        Voice* voice = Voice_group_get_voice(vgroup, voice_index);

        const bool voice_allocated = init_voice(
                ch, voice, au, ch->fg_group_id, proc_state, i, voice_rand_seed);
        if (!voice_allocated)
        {
            // Some of our voices were reallocated
            reset_channel_voices(ch);
            return true;
        }

        ++voice_index;

        Voice_state* vs = voice->state;

        if (vs->proc_type == Proc_type_pitch)
            Pitch_vstate_set_controls(vs, &ch->pitch_controls);

        if (vs->proc_type == Proc_type_force)
        {
            Force_controls* fc = Force_vstate_get_force_controls_mut(vs);
            Force_controls_copy(fc, &ch->force_controls);
        }
    }

    Channel_reset_test_output(ch);

    init_streams(ch, au);

    return true;
}