示例#1
0
Channel_defaults_list* new_Channel_defaults_list(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Channel_defaults_list* cdl = memory_alloc_item(Channel_defaults_list);
    if (cdl == NULL)
    {
        Streader_set_memory_error(sr, "Could not allocate memory for channel defaults");
        return NULL;
    }

    for (int ch = 0; ch < KQT_CHANNELS_MAX; ++ch)
        Channel_defaults_init(&cdl->ch_defaults[ch]);

    if (!Streader_has_data(sr))
        return cdl;

    if (!Streader_read_list(sr, read_ch_defaults_item, cdl))
    {
        del_Channel_defaults_list(cdl);
        return NULL;
    }

    return cdl;
}
示例#2
0
Hit_map* new_Hit_map_from_string(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Hit_map* map = memory_alloc_item(Hit_map);
    if (map == NULL)
    {
        Streader_set_memory_error(sr, "Could not allocate memory for hit map");
        return NULL;
    }

    for (int i = 0; i < KQT_HITS_MAX; ++i)
        map->hits[i] = NULL;

    if (!Streader_has_data(sr))
        return map;

    if (!Streader_read_list(sr, read_mapping, map))
    {
        del_Hit_map(map);
        return NULL;
    }

    return map;
}
示例#3
0
文件: streader.c 项目: kagu/kunquat
END_TEST

#undef make_str


START_TEST(Read_empty_list)
{
    static const char* lists[] =
    {
        "[] x",
        "[ ]x",
        "[ ] x",
    };

    for (size_t i = 0; i < arr_size(lists); ++i)
    {
        Streader* sr = init_with_cstr(lists[i]);
        fail_if(!Streader_read_list(sr, NULL, NULL),
                "Could not read empty list from `%s`: %s",
                lists[i],
                Streader_get_error_desc(sr));
        fail_if(!Streader_match_char(sr, 'x'),
                "Streader did not consume empty list from `%s` correctly",
                lists[i]);
    }
}
示例#4
0
文件: Input_map.c 项目: kagu/kunquat
Input_map* new_Input_map(Streader* sr, int32_t num_inputs, int32_t num_outputs)
{
    rassert(sr != NULL);
    rassert(num_inputs > 0);
    rassert(num_outputs > 0);

    Input_map* im = memory_alloc_item(Input_map);
    if (im == NULL)
        return NULL;

    im->map = NULL;
    im->num_inputs = num_inputs;
    im->num_outputs = num_outputs;

    im->map = new_AAtree(
            (AAtree_item_cmp*)Entry_cmp, (AAtree_item_destroy*)memory_free);
    if (im->map == NULL)
    {
        del_Input_map(im);
        return NULL;
    }

    if (!Streader_read_list(sr, read_entry, im))
    {
        del_Input_map(im);
        return NULL;
    }

    return im;
}
示例#5
0
Connections* new_Connections_from_string(
        Streader* sr, Connection_level level, Au_table* au_table, Device* master)
{
    rassert(sr != NULL);
    rassert(au_table != NULL);
    rassert(master != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Connections* graph = memory_alloc_item(Connections);
    if (graph == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for connections");
        return NULL;
    }

    graph->nodes = NULL;
    graph->nodes = new_AAtree(
            (int (*)(const void*, const void*))Device_node_cmp,
            (void (*)(void*))del_Device_node);
    mem_error_if(graph->nodes == NULL, graph, NULL, sr);

    Device_node* master_node = NULL;
    if (level == CONNECTION_LEVEL_AU)
    {
        const Device* iface = Audio_unit_get_output_interface((Audio_unit*)master);
        master_node = new_Device_node("", au_table, iface);
    }
    else
    {
        master_node = new_Device_node("", au_table, master);
    }
    mem_error_if(master_node == NULL, graph, NULL, sr);
    mem_error_if(!AAtree_ins(graph->nodes, master_node), graph, master_node, sr);

    if (!Streader_has_data(sr))
        return graph;

    read_conn_data rcdata = { graph, level, au_table, master };
    if (!Streader_read_list(sr, read_connection, &rcdata))
    {
        del_Connections(graph);
        return NULL;
    }

    if (Connections_is_cyclic(graph))
    {
        Streader_set_error(sr, "The connection graph contains a cycle");
        del_Connections(graph);
        return NULL;
    }

    return graph;
}
示例#6
0
文件: streader.c 项目: kagu/kunquat
END_TEST

#undef max_index


START_TEST(Callback_must_be_specified_for_nonempty_lists)
{
    Streader* sr = init_with_cstr("[[]]");
    int dummy = 0;
    fail_if(Streader_read_list(sr, NULL, &dummy),
            "Reading of non-empty list succeeded without callback");
}
示例#7
0
文件: Order_list.c 项目: kagu/kunquat
Order_list* new_Order_list(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    // Create the base structure
    Order_list* ol = memory_alloc_item(Order_list);
    if (ol == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for order list");
        return NULL;
    }

    ol->pat_insts = NULL;
    ol->index_map = NULL;

    // Create Pattern instance reference vector
    ol->pat_insts = new_Vector(sizeof(Pat_inst_ref));
    if (ol->pat_insts == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for order list");
        del_Order_list(ol);
        return NULL;
    }

    // Create reverse index of ol->pat_insts
    ol->index_map = new_AAtree(
            (AAtree_item_cmp*)Pat_inst_ref_cmp, (AAtree_item_destroy*)memory_free);
    if (ol->index_map == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for order list");
        del_Order_list(ol);
        return NULL;
    }

    // List is empty by default
    if (!Streader_has_data(sr))
        return ol;

    // Read the list of Pattern instance references
    if (!Streader_read_list(sr, read_piref, ol))
    {
        del_Order_list(ol);
        return NULL;
    }

    return ol;
}
示例#8
0
END_TEST


START_TEST(Fire_with_complex_bind_can_be_processed_with_multiple_receives)
{
    set_mix_volume(0);
    setup_debug_instrument();
    setup_debug_single_pulse();

    const int event_count = 2048;
    setup_complex_bind(event_count);

    pause();
    kqt_Handle_fire_event(handle, 0, "[\"#\", \"\"]");
    check_unexpected_error();

    // Receive and make sure all events are found
    const char* events = kqt_Handle_receive_events(handle);
    int32_t expected = 0;
    int loop_count = 0;
    while (strcmp("[]", events) != 0)
    {
        Streader* sr = Streader_init(STREADER_AUTO, events, (int64_t)strlen(events));
        fail_if(!Streader_read_list(sr, read_received_events_bind, &expected),
                "Event list reading failed: %s",
                Streader_get_error_desc(sr));

        events = kqt_Handle_receive_events(handle);
        ++loop_count;
    }

    fail_if(loop_count <= 1,
            "Test did not fill the event buffer, increase event count!");

    fail_if(expected != event_count,
            "Read %" PRId32 " instead of %d events",
            expected, event_count);

    // Continue playing
    kqt_Handle_play(handle, 10);
    fail_if(kqt_Handle_get_frames_available(handle) != 10,
            "Kunquat handle rendered %ld instead of 10 frames",
            kqt_Handle_get_frames_available(handle));

    // FIXME: We can only check for 512 notes as we run out of voices :-P
    const float expected_buf[10] = { min((float)event_count, 512) };
    const float* actual_buf = kqt_Handle_get_audio(handle, 0);
    check_buffers_equal(expected_buf, actual_buf, 10, 0.0f);
}
示例#9
0
Note_map* new_Note_map_from_string(Streader* sr)
{
    assert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Note_map* map = memory_alloc_item(Note_map);
    if (map == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for note map");
        return NULL;
    }

    map->map = NULL;
    map->iter = NULL;
    map->map = new_AAtree(
            (int (*)(const void*, const void*))Random_list_cmp,
            (void (*)(void*))del_Random_list);
    if (map->map == NULL)
    {
        del_Note_map(map);
        Streader_set_memory_error(
                sr, "Could not allocate memory for note map");
        return NULL;
    }

    map->iter = new_AAiter(map->map);
    if (map->iter == NULL)
    {
        del_Note_map(map);
        Streader_set_memory_error(
                sr, "Could not allocate memory for note map");
        return NULL;
    }

    if (!Streader_has_data(sr))
        return map;

    if (!Streader_read_list(sr, read_mapping, map))
    {
        del_Note_map(map);
        return NULL;
    }

    return map;
}
示例#10
0
文件: Num_list.c 项目: kagu/kunquat
Num_list* new_Num_list_from_string(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    if (!Streader_has_data(sr))
        return NULL;

    Num_list* nl = memory_alloc_item(Num_list);
    if (nl == NULL)
    {
        Streader_set_memory_error(
            sr, "Could not allocate memory for number list");
        return NULL;
    }

    nl->len = 0;
    nl->res = 8;
    nl->nums = NULL;

    nl->nums = memory_alloc_items(double, nl->res);
    if (nl->nums == NULL)
    {
        del_Num_list(nl);
        Streader_set_memory_error(
            sr, "Could not allocate memory for number list");
        return NULL;
    }

    if (!Streader_read_list(sr, read_num, nl))
    {
        del_Num_list(nl);
        return NULL;
    }

    return nl;
}
示例#11
0
bool Environment_parse(Environment* env, Streader* sr)
{
    assert(env != NULL);
    assert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    if (!Streader_has_data(sr))
    {
        AAtree_clear(env->vars);
        AAiter_change_tree(env->iter, env->vars);
        return true;
    }

    AAtree* new_vars = new_AAtree(
            (int (*)(const void*, const void*))strcmp,
            (void (*)(void*))del_Env_var);
    if (new_vars == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for environment");
        return false;
    }

    if (!Streader_read_list(sr, read_env_var, new_vars))
    {
        del_AAtree(new_vars);
        return false;
    }

    AAiter_change_tree(env->iter, new_vars);
    AAtree* old_vars = env->vars;
    env->vars = new_vars;
    del_AAtree(old_vars);

    return true;
}
示例#12
0
static bool read_tuning_table_item(Streader* sr, const char* key, void* userdata)
{
    rassert(sr != NULL);
    rassert(key != NULL);
    rassert(userdata != NULL);

    Tuning_table* tt = userdata;

    if (string_eq(key, "ref_note"))
    {
        int64_t num = 0;
        if (!Streader_read_int(sr, &num))
            return false;

        if (num < 0 || num >= KQT_TUNING_TABLE_NOTES_MAX)
        {
            Streader_set_error(
                     sr, "Invalid reference note number: %" PRId64, num);
            return false;
        }

        tt->ref_note = (int)num;
    }
    else if (string_eq(key, "ref_pitch"))
    {
        double num = NAN;
        if (!Streader_read_float(sr, &num))
            return false;

        if (!isfinite(num))
        {
            Streader_set_error(sr, "Invalid reference pitch: %f", num);
            return false;
        }

        tt->ref_pitch = num;
    }
    else if (string_eq(key, "pitch_offset"))
    {
        double cents = NAN;
        if (!Streader_read_float(sr, &cents))
            return false;

        if (!isfinite(cents))
        {
            Streader_set_error(sr, "Pitch offset is not finite");
            return false;
        }

        tt->global_offset = cents;
    }
    else if (string_eq(key, "octave_width"))
    {
        double cents = NAN;
        if (!Streader_read_tuning(sr, &cents))
            return false;

        if (cents <= 0)
        {
            Streader_set_error(sr, "Octave width must be positive");
            return false;
        }

        Tuning_table_set_octave_width(tt, cents);
    }
    else if (string_eq(key, "centre_octave"))
    {
        int64_t octave = -1;
        if (!Streader_read_int(sr, &octave))
            return false;

        if (octave < 0 || octave >= KQT_TUNING_TABLE_OCTAVES)
        {
            Streader_set_error(sr, "Invalid centre octave: %" PRId64, octave);
            return false;
        }

        tt->centre_octave = (int)octave;
        Tuning_table_set_octave_width(tt, tt->octave_width);
    }
    else if (string_eq(key, "notes"))
    {
        for (int i = 0; i < KQT_TUNING_TABLE_NOTES_MAX; ++i)
            tt->note_offsets[i] = NAN;

        if (!Streader_read_list(sr, read_note, tt))
            return false;
    }
    else
    {
        Streader_set_error(sr, "Unrecognised key in tuning table: %s", key);
        return false;
    }

    return true;
}
示例#13
0
bool Streader_readf(Streader* sr, const char* format, ...)
{
    rassert(sr != NULL);
    rassert(format != NULL);

    va_list args;
    va_start(args, format);

    while (!Streader_is_error_set(sr) && *format != '\0')
    {
        if (*format == '%')
        {
            // Conversion characters
            ++format;

            switch (*format)
            {
                case 'n':
                {
                    Streader_read_null(sr);
                }
                break;

                case 'b':
                {
                    bool* dest = va_arg(args, bool*);
                    Streader_read_bool(sr, dest);
                }
                break;

                case 'i':
                {
                    int64_t* dest = va_arg(args, int64_t*);
                    Streader_read_int(sr, dest);
                }
                break;

                case 'f':
                {
                    double* dest = va_arg(args, double*);
                    Streader_read_float(sr, dest);
                }
                break;

                case 's':
                {
                    Streader_readf_str_info info =
                        va_arg(args, Streader_readf_str_info);
                    rassert(info.guard == Streader_readf_str_guard);

                    const int64_t max_bytes = info.max_bytes;
                    char* dest = info.dest;
                    Streader_read_string(sr, max_bytes, dest);
                }
                break;

                case 't':
                {
                    Tstamp* dest = va_arg(args, Tstamp*);
                    Streader_read_tstamp(sr, dest);
                }
                break;

                case 'p':
                {
                    Pat_inst_ref* dest = va_arg(args, Pat_inst_ref*);
                    Streader_read_piref(sr, dest);
                }
                break;

                case 'l':
                {
                    List_item_reader* ir = va_arg(args, List_item_reader*);
                    void* userdata = va_arg(args, void*);
                    Streader_read_list(sr, ir, userdata);
                }
                break;

                case 'd':
                {
                    Dict_item_reader* ir = va_arg(args, Dict_item_reader*);
                    void* userdata = va_arg(args, void*);
                    Streader_read_dict(sr, ir, userdata);
                }
                break;

                case '%':
                {
                    Streader_match_char(sr, '%');
                }
                break;

                default:
                    rassert(false);
            }
        }
        else
        {
            // Characters to be matched
            if (!isspace(*format))
示例#14
0
static bool read_mapping(Streader* sr, int32_t index, void* userdata)
{
    assert(sr != NULL);
    (void)index;
    assert(userdata != NULL);

    Note_map* map = userdata;

    Random_list* list = memory_alloc_item(Random_list);
    if (list == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for note map entry");
        return false;
    }

    double cents = NAN;
    double force = NAN;

    if (!Streader_readf(sr, "[[%f,%f],", &cents, &force))
    {
        memory_free(list);
        return false;
    }

    if (!isfinite(cents))
    {
        Streader_set_error(sr, "Mapping cents is not finite");
        memory_free(list);
        return false;
    }

    if (!isfinite(force))
    {
        Streader_set_error(sr, "Mapping force is not finite");
        memory_free(list);
        return false;
    }

    list->freq = exp2(cents / 1200) * 440;
    list->cents = cents;
    list->force = force;
    list->entry_count = 0;
    if (!AAtree_ins(map->map, list))
    {
        Streader_set_memory_error(
                sr, "Couldn't allocate memory for note map entry");
        memory_free(list);
        return false;
    }

    if (!Streader_read_list(sr, read_random_list_entry, list))
        return false;

    if (list->entry_count == 0)
    {
        Streader_set_error(sr, "Empty note mapping random list");
        return false;
    }

    return Streader_match_char(sr, ']');
}
示例#15
0
static bool read_mapping(Streader* sr, int32_t index, void* userdata)
{
    rassert(sr != NULL);
    ignore(index);
    rassert(userdata != NULL);

    Hit_map* map = userdata;

    Random_list* list = memory_alloc_item(Random_list);
    if (list == NULL)
    {
        del_Hit_map(map);
        Streader_set_memory_error(
                sr, "Could not allocate memory for hit map random list");
        return false;
    }

    int64_t hit_index = -1;
    double force = NAN;

    if (!Streader_readf(sr, "[[%i,%f],", &hit_index, &force))
    {
        memory_free(list);
        return false;
    }

    if (hit_index < 0 || hit_index >= KQT_HITS_MAX)
    {
        Streader_set_error(
                sr,
                "Mapping hit index is outside range [0, %d)",
                KQT_HITS_MAX);
        memory_free(list);
        return false;
    }

    if (!isfinite(force))
    {
        Streader_set_error(
                sr,
                "Mapping force is not finite",
                KQT_HITS_MAX);
        memory_free(list);
        return false;
    }

    if (map->hits[hit_index] == NULL)
    {
        map->hits[hit_index] = new_AAtree(
                (AAtree_item_cmp*)Random_list_cmp, (AAtree_item_destroy*)memory_free);
        if (map->hits[hit_index] == NULL)
        {
            Streader_set_memory_error(
                    sr, "Could not allocate memory for hit map");
            memory_free(list);
            return false;
        }
    }

    list->force = force;
    list->entry_count = 0;
    if (AAtree_contains(map->hits[hit_index], list))
    {
        Streader_set_error(
                sr,
                "Duplicate hit map entry with hit index %" PRId64 ", force %.2f",
                hit_index,
                force);
        memory_free(list);
        return false;
    }
    if (!AAtree_ins(map->hits[hit_index], list))
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for hit map random list");
        memory_free(list);
        return false;
    }

    if (!Streader_read_list(sr, read_random_list_entry, list))
        return false;

    return Streader_match_char(sr, ']');
}