Exemple #1
0
END_TEST


START_TEST(Matching_visible_characters_succeed)
{
    static const char* ones[] =
    {
        "1",
        " 1",
        " 1 ",
    };
    for (size_t i = 0; i < arr_size(ones); ++i)
    {
        Streader* sr = init_with_cstr(ones[i]);

        fail_if(!Streader_match_char(sr, '1'),
                "Could not match '1' in \"%s\"", ones[i]);
        fail_if(Streader_is_error_set(sr),
                "Error set after a successful match in \"%s\"", ones[i]);
        fail_if(Streader_match_char(sr, '1'),
                "Streader did not move forwards after a successful match"
                " in \"%s\"",
                ones[i]);
    }

    static const char* exprs[] =
    {
        "1+2",
        " 1+2",
        "1 +2",
        " 1 +2",
        "1+ 2",
        "1 + 2",
        " 1 + 2 ",
    };
    for (size_t i = 0; i < arr_size(exprs); ++i)
    {
        Streader* sr = init_with_cstr(exprs[i]);

        fail_if(!Streader_match_char(sr, '1'),
                "Could not match '1' in \"%s\"", exprs[i]);
        fail_if(Streader_is_error_set(sr),
                "Error set after a successful match in \"%s\"", exprs[i]);
        fail_if(!Streader_match_char(sr, '+'),
                "Could not match '+' in \"%s\"", exprs[i]);
        fail_if(Streader_is_error_set(sr),
                "Error set after a successful match in \"%s\"", exprs[i]);
        fail_if(!Streader_match_char(sr, '2'),
                "Could not match '2' in \"%s\"", exprs[i]);
        fail_if(Streader_is_error_set(sr),
                "Error set after a successful match in \"%s\"", exprs[i]);
    }
}
Exemple #2
0
bool Streader_match_char(Streader* sr, char ch)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "Expected '%c' instead of end of data", ch);
        return false;
    }

    if (CUR_CH != ch)
    {
        if (isprint(CUR_CH))
            Streader_set_error(
                    sr, "Expected '%c' instead of '%c'", ch, CUR_CH);
        else
            Streader_set_error(
                    sr,
                    "Expected '%c' instead of %#04hhx",
                    ch, (unsigned)CUR_CH);

        return false;
    }

    ++sr->pos;

    return true;
}
Exemple #3
0
bool Module_read_force_shift(Module* module, Streader* sr)
{
    rassert(module != NULL);
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    double shift = 0;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_float(sr, &shift))
            return false;

        if (!isfinite(shift) || (shift < -60) || (shift > 0))
        {
            Streader_set_error(sr, "Invalid force shift: %.4f", shift);
            return false;
        }
    }

    module->force_shift = shift;

    return true;
}
Exemple #4
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;
}
Exemple #5
0
bool Module_read_mixing_volume(Module* module, Streader* sr)
{
    rassert(module != NULL);
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    double mix_vol = COMP_DEFAULT_MIX_VOL;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_float(sr, &mix_vol))
            return false;

        if (!isfinite(mix_vol) && mix_vol != -INFINITY)
        {
            Streader_set_error(sr, "Invalid mixing volume: %.4f", mix_vol);
            return false;
        }
    }

    module->mix_vol_dB = mix_vol;
    module->mix_vol = exp2(module->mix_vol_dB / 6);

    return true;
}
Exemple #6
0
bool Streader_read_finite_rt(Streader* sr, Value* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);
    const int64_t start_pos = sr->pos;

    Value* value = VALUE_AUTO;

    if (Streader_read_bool(sr, &value->value.bool_type))
        value->type = VALUE_TYPE_BOOL;
    else if ((recover(sr, start_pos), Streader_read_int(sr, &value->value.int_type)) &&
            (CUR_CH != '.') && (CUR_CH != 'e') && (CUR_CH != 'E'))
        value->type = VALUE_TYPE_INT;
    else if (recover(sr, start_pos),
            (Streader_read_float(sr, &value->value.float_type) &&
             isfinite(value->value.float_type)))
        value->type = VALUE_TYPE_FLOAT;
    else if (recover(sr, start_pos), Streader_read_tstamp(sr, &value->value.Tstamp_type))
        value->type = VALUE_TYPE_TSTAMP;

    if (value->type == VALUE_TYPE_NONE)
        return false;

    if (dest != NULL)
        Value_copy(dest, value);

    return true;
}
Exemple #7
0
bool Module_parse_random_seed(Module* module, Streader* sr)
{
    rassert(module != NULL);
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t seed = 0;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_int(sr, &seed))
            return false;

        if (seed < 0)
        {
            Streader_set_error(sr, "Random seed must be non-negative");
            return false;
        }
    }

    module->random_seed = (uint64_t)seed;

    return true;
}
Exemple #8
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;
}
Exemple #9
0
END_TEST


static bool fill_array_index(Streader* sr, const char* key, void* userdata)
{
    fail_if(sr == NULL, "Callback did not get a Streader");
    fail_if(Streader_is_error_set(sr),
            "Callback was called with Streader error set: %s",
            Streader_get_error_desc(sr));
    fail_if(key == NULL,
            "Callback did not get a key");
    fail_if(strlen(key) != 1 || strchr("0123", key[0]) == NULL,
            "Callback got an unexpected key `%s`",
            key);
    fail_if(userdata == NULL, "Callback did not get userdata");

    int arr_index = key[0] - '0';
    assert(arr_index >= 0);
    assert(arr_index < 4);
    int* array = userdata;

    int64_t num = 0;
    fail_if(!Streader_read_int(sr, &num),
            "Could not read integer from dictionary: %s",
            Streader_get_error_desc(sr));
    fail_if(num != arr_index + 10,
            "Unexpected value %" PRId64 " (expected %d)",
            num, arr_index + 10);

    array[arr_index] = (int)num;

    return true;
}
Exemple #10
0
END_TEST


static bool check_adjusted_tstamp(Streader* sr, int32_t index, void* userdata)
{
    fail_if(sr == NULL, "Callback did not get a Streader");
    fail_if(Streader_is_error_set(sr),
            "Callback was called with Streader error set: %s",
            Streader_get_error_desc(sr));
    fail_if(index < 0,
            "Callback got a negative item index (%" PRId32 ")",
            index);
    fail_if(index >= item_count,
            "Callback got too large an index (%" PRId32 ")",
            index);
    fail_if(userdata != NULL, "Callback got unexpected userdata");

    Tstamp* ts = TSTAMP_AUTO;
    fail_if(!Streader_read_tstamp(sr, ts),
            "Could not read timestamp from list index %" PRId32 ": %s",
            index, Streader_get_error_desc(sr));
    fail_if((Tstamp_get_beats(ts) != index + 10) ||
                (Tstamp_get_rem(ts) != index + 100),
            "Unexpected list item " PRIts " (expected (%d, %d))",
            PRIVALts(*ts), (int)index + 10, (int)index + 100);

    return true;
}
Exemple #11
0
END_TEST


#define item_count 4

static bool inc_doubled_int(Streader* sr, int32_t index, void* userdata)
{
    fail_if(sr == NULL, "Callback did not get a Streader");
    fail_if(Streader_is_error_set(sr),
            "Callback was called with Streader error set: %s",
            Streader_get_error_desc(sr));
    fail_if(index < 0,
            "Callback got a negative item index (%" PRId32 ")",
            index);
    fail_if(index >= item_count,
            "Callback got too large an index (%" PRId32 ")",
            index);
    fail_if(userdata == NULL, "Callback did not get userdata");

    int64_t num = 0;
    fail_if(!Streader_read_int(sr, &num),
            "Could not read integer from list index %" PRId32 ": %s",
            index, Streader_get_error_desc(sr));
    fail_if(num != index * 2,
            "Unexpected list item %" PRId64 " (expected %" PRId32 ")",
            num, index * 2);

    int* nums = userdata;
    nums[index] = (int)num + 1;

    return true;
}
Exemple #12
0
bool Streader_read_bool(Streader* sr, bool* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    bool result = false;

    if (Streader_try_match_char_seq(sr, "true"))
    {
        result = true;
    }
    else
    {
        if (!Streader_match_char_seq(sr, "false"))
        {
            Streader_set_error(sr, "Expected a boolean value");
            return false;
        }
    }

    if (dest != NULL)
        *dest = result;

    return true;
}
Exemple #13
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;
}
Exemple #14
0
Au_expressions* new_Au_expressions(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Au_expressions* ae = memory_alloc_item(Au_expressions);
    if (ae == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for audio unit expressions");
        return NULL;
    }

    memset(ae->default_note_expr, '\0', KQT_VAR_NAME_MAX);
    ae->entries = new_AAtree(
            (AAtree_item_cmp*)strcmp, (AAtree_item_destroy*)del_Entry);
    if (ae->entries == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for audio unit expressions");
        del_Au_expressions(ae);
        return NULL;
    }

    if (!Streader_read_dict(sr, read_expressions_def, ae))
    {
        rassert(Streader_is_error_set(sr));
        del_Au_expressions(ae);
        return NULL;
    }

    if (ae->default_note_expr[0] != '\0' &&
            !Au_expressions_get_proc_filter(ae, ae->default_note_expr))
    {
        Streader_set_error(
                sr,
                "Audio unit expressions do not contain the default expression %s",
                ae->default_note_expr);
        del_Au_expressions(ae);
        return NULL;
    }

    return ae;
}
Exemple #15
0
bool Streader_has_data(Streader* sr)
{
    rassert(sr != NULL);
    rassert(!Streader_is_error_set(sr));

    Streader_skip_whitespace(sr);
    return !Streader_end_reached(sr);
}
Exemple #16
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;
}
Exemple #17
0
END_TEST


START_TEST(Matching_wrong_characters_fails)
{
    Streader* sr = init_with_cstr("1");

    fail_if(Streader_match_char(sr, '2'),
            "Matched '2' successfully in \"1\"");
    fail_if(!Streader_is_error_set(sr),
            "No error set after a failed match");
    fail_if(Streader_match_char(sr, '1'),
            "Match succeeded after an error");

    Streader_clear_error(sr);
    fail_if(Streader_is_error_set(sr),
            "Streader_clear_error did not remove Streader error");
    fail_if(!Streader_match_char(sr, '1'),
            "Correct match did not succeed after a cleared failure");
}
Exemple #18
0
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;
}
Exemple #19
0
bool read_default_manifest(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    if (!Streader_has_data(sr))
        return false;

    return Streader_read_dict(sr, read_manifest_entry, NULL);
}
Exemple #20
0
bool Streader_match_string(Streader* sr, const char* str)
{
    rassert(sr != NULL);
    rassert(str != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (Streader_end_reached(sr))
    {
        Streader_set_error(
                sr, "Expected beginning of a string instead of end of data");
        return false;
    }

    // Match opening double quote
    if (CUR_CH != '\"')
    {
        if (isprint(CUR_CH))
            Streader_set_error(
                    sr,
                    "Expected beginning of a string instead of '%c'",
                    CUR_CH);
        else
            Streader_set_error(
                    sr,
                    "Expected beginning of a string instead of %#2x",
                    (unsigned)CUR_CH);

        return false;
    }

    ++sr->pos;

    // Match the string
    if (!Streader_match_char_seq(sr, str))
        return false;

    // Match closing double quote
    if (Streader_end_reached(sr) || CUR_CH != '\"')
    {
        Streader_set_error(sr, "Unexpected string (expected `%s`)", str);
        return false;
    }

    ++sr->pos;

    return true;
}
Exemple #21
0
bool Streader_read_piref(Streader* sr, Pat_inst_ref* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t pat = 0;
    int64_t inst = 0;

    if (!(Streader_match_char(sr, '[') &&
                Streader_read_int(sr, &pat)  &&
                Streader_match_char(sr, ',') &&
                Streader_read_int(sr, &inst) &&
                Streader_match_char(sr, ']')))
    {
        Streader_set_error(sr, "Expected a valid pattern instance");
        return false;
    }

    if (pat < 0 || pat >= KQT_PATTERNS_MAX)
    {
        Streader_set_error(
                sr,
                "Pattern number %" PRId64 " out of range [0..%ld)"
                    " in pattern instance",
                pat,
                KQT_PATTERNS_MAX);
        return false;
    }

    if (inst < 0 || inst >= KQT_PAT_INSTANCES_MAX)
    {
        Streader_set_error(
                sr,
                "Pattern instance number %" PRId64 " out of range [0..%ld)"
                    " in pattern instance",
                inst,
                KQT_PAT_INSTANCES_MAX);
        return false;
    }

    if (dest != NULL)
    {
        dest->pat = (int16_t)pat;
        dest->inst = (int16_t)inst;
    }

    return true;
}
Exemple #22
0
bool Streader_try_match_char(Streader* sr, char ch)
{
    rassert(sr != NULL);
    rassert(!Streader_is_error_set(sr));

    const int64_t start_pos = sr->pos;
    const bool success = Streader_match_char(sr, ch);
    if (!success)
    {
        Streader_clear_error(sr);
        sr->pos = start_pos;
    }

    return success;
}
Exemple #23
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;
}
Exemple #24
0
static bool Streader_try_match_char_seq(Streader* sr, const char* seq)
{
    assert(sr != NULL);
    assert(!Streader_is_error_set(sr));
    assert(seq != NULL);

    const size_t start_pos = sr->pos;
    const bool success = Streader_match_char_seq(sr, seq);
    if (!success)
    {
        Streader_clear_error(sr);
        sr->pos = start_pos;
    }

    return success;
}
Exemple #25
0
bool Streader_read_null(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    if (!Streader_match_char_seq(sr, "null"))
    {
        Streader_set_error(sr, "Expected null");
        return false;
    }

    return true;
}
Exemple #26
0
bool Streader_read_dict(Streader* sr, Dict_item_reader ir, void* userdata)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    // Check opening brace
    if (!(Streader_skip_whitespace(sr) && Streader_match_char(sr, '{')))
    {
        Streader_set_error(sr, "Expected a dictionary opening brace");
        return false;
    }

    // Check empty dictionary
    if (Streader_try_match_char(sr, '}'))
        return true;

    if (ir == NULL)
    {
        Streader_set_error(sr, "Expected an empty dictionary");
        return false;
    }

    // Read key/value pairs
    do
    {
        char key[STREADER_DICT_KEY_LENGTH_MAX + 1] = "";
        if (!(Streader_read_string(sr, STREADER_DICT_KEY_LENGTH_MAX + 1, key) &&
                    Streader_match_char(sr, ':') &&
                    ir(sr, key, userdata)))
            return false;
    } while (Streader_try_match_char(sr, ','));

    // Check closing brace
    if (!Streader_match_char(sr, '}'))
    {
        Streader_set_error(sr, "Expected a dictionary closing brace");
        return false;
    }

    return true;
}
Exemple #27
0
bool Streader_skip_whitespace(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    while (!Streader_end_reached(sr) && isspace(CUR_CH))
    {
        if (CUR_CH == '\n')
            ++sr->line;

        ++sr->pos;
    }

    rassert(sr->pos <= sr->len);

    return true;
}
Exemple #28
0
static bool Streader_match_char_seq(Streader* sr, const char* seq)
{
    rassert(sr != NULL);
    rassert(seq != NULL);

    rassert(!Streader_is_error_set(sr));
    rassert(!Streader_end_reached(sr));

    // Check that we have enough data
    const int64_t expected_len = (int64_t)strlen(seq);
    if (sr->len - sr->pos < expected_len)
    {
        Streader_set_error(
                sr,
                "Too few bytes left to contain expected string `%s`",
                seq);
        return false;
    }

    // Match the string
    if (strncmp(&sr->str[sr->pos], seq, (size_t)expected_len) != 0)
    {
        Streader_set_error(sr, "Unexpected string (expected `%s`)", seq);
        return false;
    }

    // Update position
    for (int64_t i = 0; i < expected_len; ++i)
    {
        if (CUR_CH == '\n')
            ++sr->line;
        ++sr->pos;
    }

    if (!Streader_end_reached(sr) && isalnum(CUR_CH))
    {
        Streader_set_error(
                sr, "Unexpected character after expected string `%s`", seq);
        return false;
    }

    return true;
}
Exemple #29
0
Tuning_table* new_Tuning_table_from_string(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    Tuning_table* tt = new_Tuning_table(
            TUNING_TABLE_DEFAULT_REF_PITCH, TUNING_TABLE_DEFAULT_OCTAVE_WIDTH);
    if (tt == NULL)
    {
        Streader_set_memory_error(
                sr, "Couldn't allocate memory for tuning table");
        return NULL;
    }

    if (Streader_has_data(sr))
    {
        if (!Streader_read_dict(sr, read_tuning_table_item, tt))
        {
            del_Tuning_table(tt);
            return NULL;
        }

        if (tt->ref_note >= tt->note_count)
        {
            Streader_set_error(sr,
                     "Reference note doesn't exist: %d", tt->ref_note);
            del_Tuning_table(tt);
            return NULL;
        }
    }

    if (!Tuning_table_build_pitch_map(tt))
    {
        Streader_set_memory_error(sr, "Couldn't allocate memory for tuning table");
        del_Tuning_table(tt);
        return NULL;
    }

    return tt;
}
Exemple #30
0
static bool Streader_read_tuning(Streader* sr, double* cents)
{
    rassert(sr != NULL);
    rassert(cents != NULL);

    if (Streader_is_error_set(sr))
        return false;

    if (Streader_try_match_char(sr, '['))
    {
        int64_t num = 0;
        int64_t den = 0;
        if (!Streader_readf(sr, "%i,%i]", &num, &den))
            return false;

        if (num <= 0)
        {
            Streader_set_error(sr, "Numerator must be positive");
            return false;
        }
        if (den <= 0)
        {
            Streader_set_error(sr, "Denominator must be positive");
            return false;
        }

        *cents = log2((double)num / (double)den) * 1200;
    }
    else
    {
        if (!Streader_read_float(sr, cents))
            return false;

        if (!isfinite(*cents))
        {
            Streader_set_error(sr, "Cents value must be finite");
            return false;
        }
    }

    return true;
}