const Pattern* Module_get_pattern( const Module* module, const Pat_inst_ref* piref) { rassert(module != NULL); rassert(piref != NULL); rassert(piref->pat >= 0); rassert(piref->pat < KQT_PATTERNS_MAX); if (!Pat_table_get_existent(module->pats, piref->pat)) return NULL; const Pattern* pat = Pat_table_get(module->pats, piref->pat); if (pat != NULL && !Pattern_get_inst_existent(pat, piref->inst)) return NULL; return pat; }
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; }
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 (size_t 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 (size_t 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; assert(tl != NULL); for (size_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; assert(tl != NULL); for (size_t 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]; assert(ol != NULL); for (size_t 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->ins_map != NULL) { set_invalid_if( !Input_map_is_valid(h->module->ins_map, h->module->ins_controls), "Control map uses nonexistent controls"); } h->data_is_validated = true; return 1; }