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; }
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; }
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]); } }
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; }
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; }
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"); }
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; }
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); }
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; }
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; }
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; }
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, ¢s)) 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, ¢s)) 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; }
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))
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],", ¢s, &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, ']'); }
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, ']'); }