Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
int kqt_Handle_validate(kqt_Handle handle)
{
    check_handle(handle, 0);
    Handle* h = get_handle(handle);

    check_data_is_valid(h, 0);

    // Check error from set_data
    if (Error_is_set(&h->validation_error))
    {
        Error_copy(&h->error, &h->validation_error);
        Error_copy(&null_error, &h->validation_error);
        h->data_is_valid = false;
        return 0;
    }

    // Check album
    if (h->module->album_is_existent)
    {
        const Track_list* tl = h->module->track_list;
        set_invalid_if(
                tl == NULL,
                "Album does not contain a track list");
        set_invalid_if(
                Track_list_get_len(tl) == 0,
                "Album has no tracks");
    }

    // Check songs
    for (int i = 0; i < KQT_SONGS_MAX; ++i)
    {
        if (!Song_table_get_existent(h->module->songs, i))
            continue;

        // Check for orphans
        const Track_list* tl = h->module->track_list;
        set_invalid_if(
                !h->module->album_is_existent || tl == NULL,
                "Module contains song %d but no album", i);

        bool found = false;
        for (int k = 0; k < Track_list_get_len(tl); ++k)
        {
            if (Track_list_get_song_index(tl, k) == i)
            {
                found = true;
                break;
            }
        }
        set_invalid_if(!found, "Song %d is not included in the album", i);

        // Check for empty songs
        const Order_list* ol = h->module->order_lists[i];
        set_invalid_if(
                ol == NULL || Order_list_get_len(ol) == 0,
                "Song %d does not contain systems", i);

        // Check for missing pattern instances
        for (int system = 0; system < Order_list_get_len(ol); ++system)
        {
            const Pat_inst_ref* piref = Order_list_get_pat_inst_ref(ol, system);
            Pattern* pat = Pat_table_get(h->module->pats, piref->pat);

            set_invalid_if(
                    !Pat_table_get_existent(h->module->pats, piref->pat) ||
                    pat == NULL ||
                    !Pattern_get_inst_existent(pat, piref->inst),
                    "Missing pattern instance [%" PRId16 ", %" PRId16 "]",
                    piref->pat, piref->inst);
        }
    }

    // Check for nonexistent songs in the track list
    if (h->module->album_is_existent)
    {
        const Track_list* tl = h->module->track_list;
        rassert(tl != NULL);

        for (uint16_t i = 0; i < Track_list_get_len(tl); ++i)
        {
            set_invalid_if(
                    !Song_table_get_existent(h->module->songs,
                        Track_list_get_song_index(tl, i)),
                    "Album includes nonexistent song %d", i);
        }
    }

    // Check existing patterns
    for (int i = 0; i < KQT_PATTERNS_MAX; ++i)
    {
        if (!Pat_table_get_existent(h->module->pats, i))
            continue;

        Pattern* pat = Pat_table_get(h->module->pats, i);
        set_invalid_if(
                pat == NULL,
                "Pattern %d exists but contains no data", i);

        bool pattern_has_instance = false;
        for (int k = 0; k < KQT_PAT_INSTANCES_MAX; ++k)
        {
            if (Pattern_get_inst_existent(pat, k))
            {
                // Mark found instance
                pattern_has_instance = true;

                // Check that the instance is used in the album
                set_invalid_if(
                        !h->module->album_is_existent,
                        "Pattern instance [%d, %d] exists but no album"
                        " is present", i, k);

                bool instance_found = false;

                const Track_list* tl = h->module->track_list;
                rassert(tl != NULL);

                for (int track = 0; track < Track_list_get_len(tl); ++track)
                {
                    const int song_index = Track_list_get_song_index(tl, track);

                    if (!Song_table_get_existent(h->module->songs, song_index))
                        continue;

                    const Order_list* ol = h->module->order_lists[song_index];
                    rassert(ol != NULL);

                    for (int system = 0; system < Order_list_get_len(ol); ++system)
                    {
                        const Pat_inst_ref* piref =
                            Order_list_get_pat_inst_ref(ol, system);
                        if (piref->pat == i && piref->inst == k)
                        {
                            set_invalid_if(
                                    instance_found,
                                    "Duplicate occurrence of pattern instance"
                                    " [%d, %d]", i, k);
                            instance_found = true;
                        }
                    }
                }

                set_invalid_if(
                        !instance_found,
                        "Pattern instance [%d, %d] exists but is not used",
                        i, k);
            }
        }

        set_invalid_if(
                !pattern_has_instance,
                "Pattern %d exists but has no instances", i);
    }

    // Check controls
    if (h->module->au_map != NULL)
    {
        set_invalid_if(
                !Input_map_is_valid(h->module->au_map, h->module->au_controls),
                "Control map uses nonexistent controls");
    }

    // Check that all connections are between existing ports
    {
        char err_msg[DEVICE_CONNECTION_ERROR_LENGTH_MAX] = "";

        // Audio units
        Au_table* au_table = Module_get_au_table(h->module);
        for (int au_index = 0; au_index < KQT_AUDIO_UNITS_MAX; ++au_index)
        {
            const Audio_unit* au = Au_table_get(au_table, au_index);
            if ((au != NULL) && Device_is_existent((const Device*)au))
            {
                const Connections* au_conns = Audio_unit_get_connections(au);
                if (au_conns != NULL)
                {
                    set_invalid_if(
                            !Connections_check_connections(au_conns, err_msg),
                            "Error in connections of device au_%02x: %s",
                            au_index, err_msg);
                }

                // Audio unit effects
                for (int sub_au_index = 0; sub_au_index < KQT_AUDIO_UNITS_MAX; ++sub_au_index)
                {
                    const Audio_unit* sub_au = Audio_unit_get_au(au, sub_au_index);
                    if ((sub_au != NULL) && Device_is_existent((const Device*)sub_au))
                    {
                        const Connections* conns = Audio_unit_get_connections(sub_au);
                        if (conns != NULL)
                        {
                            set_invalid_if(
                                    !Connections_check_connections(conns, err_msg),
                                    "Error in connections of device"
                                        " au_%02x/au_%02x: %s",
                                    au_index, sub_au_index, err_msg);
                        }
                    }
                }
            }
        }

        // Top-level connections
        if (h->module->connections != NULL)
        {
            set_invalid_if(
                    !Connections_check_connections(
                        Module_get_connections(h->module), err_msg),
                    "Error in top-level connections: %s",
                    err_msg);
        }
    }

    // Check that audio unit types are allowed in their contexts
    {
        Au_table* au_table = Module_get_au_table(h->module);
        for (int au_index = 0; au_index < KQT_AUDIO_UNITS_MAX; ++au_index)
        {
            const Audio_unit* au = Au_table_get(au_table, au_index);
            if ((au != NULL) && Device_is_existent((const Device*)au))
            {
                const Au_type au_type = Audio_unit_get_type(au);

                for (int sub_au_index = 0;
                        sub_au_index < KQT_AUDIO_UNITS_MAX;
                        ++sub_au_index)
                {
                    const Audio_unit* sub_au = Audio_unit_get_au(au, sub_au_index);
                    if ((sub_au != NULL) && Device_is_existent((const Device*)sub_au))
                    {
                        if (au_type == AU_TYPE_INSTRUMENT)
                        {
                            const Au_type sub_au_type = Audio_unit_get_type(sub_au);
                            set_invalid_if(
                                    sub_au_type == AU_TYPE_INSTRUMENT,
                                    "Audio unit au_%02x is an instrument but contains"
                                        " another instrument",
                                    au_index);
                        }

                        set_invalid_if(
                                au_type == AU_TYPE_EFFECT,
                                "Audio unit au_%02x is an effect but contains"
                                    " another audio unit",
                                au_index);
                    }
                }
            }
        }
    }

    // Data is OK
    h->data_is_validated = true;

    // Update connections if needed
    if (h->update_connections)
    {
        if (!Handle_update_connections(h))
            return 0;

        h->update_connections = false;
    }

    return 1;
}
Beispiel #4
0
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;
}