From f95ffebea8bcc3f9dbb8ddffdd79e808b4edfa5f Mon Sep 17 00:00:00 2001 From: Alexandros Theodotou Date: Sun, 24 Jul 2022 23:48:38 +0900 Subject: [PATCH] fix loading undo history under different sample rate Also fix sanity checking of audio regions. --- inc/actions/undoable_action.h | 10 ++++ inc/audio/audio_region.h | 29 ++++------ inc/audio/engine.h | 7 +++ inc/audio/position.h | 5 +- inc/audio/region.h | 29 ++++------ src/actions/undoable_action.c | 5 ++ src/audio/audio_region.c | 44 +++++++++++---- src/audio/engine.c | 4 ++ src/audio/position.c | 16 ++++-- src/audio/region.c | 13 +++-- src/audio/router.c | 25 +++------ src/audio/track.c | 9 ++-- src/audio/track_lane.c | 12 +++++ src/audio/tracklist.c | 20 +------ src/gui/backend/arranger_object.c | 56 ++++++++++++++++++- src/gui/backend/arranger_selections.c | 9 +++- src/project.c | 20 +++---- tests/actions/arranger_selections.c | 77 +++++++++++++++++++++++++-- 18 files changed, 280 insertions(+), 110 deletions(-) diff --git a/inc/actions/undoable_action.h b/inc/actions/undoable_action.h index 5a790d2f1..074efe7a4 100644 --- a/inc/actions/undoable_action.h +++ b/inc/actions/undoable_action.h @@ -12,6 +12,7 @@ #include +#include "utils/types.h" #include "utils/yaml.h" typedef struct AudioClip AudioClip; @@ -88,6 +89,14 @@ typedef struct UndoableAction * action is executed. */ double frames_per_tick; + /** + * Sample rate of this action. + * + * Used to recalculate UndoableAction.frames_per_tick when + * the project is loaded under a new samplerate. + */ + sample_rate_t sample_rate; + /** * Index in the stack. * @@ -114,6 +123,7 @@ static const cyaml_schema_field_t undoable_action_fields_schema[] = { type, undoable_action_type_strings), YAML_FIELD_FLOAT (UndoableAction, frames_per_tick), + YAML_FIELD_INT (UndoableAction, sample_rate), YAML_FIELD_INT (UndoableAction, stack_idx), YAML_FIELD_INT (UndoableAction, num_actions), diff --git a/inc/audio/audio_region.h b/inc/audio/audio_region.h index e38ba162f..f42bf532c 100644 --- a/inc/audio/audio_region.h +++ b/inc/audio/audio_region.h @@ -1,21 +1,5 @@ -/* - * Copyright (C) 2019-2022 Alexandros Theodotou - * - * This file is part of Zrythm - * - * Zrythm is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Zrythm is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Zrythm. If not, see . - */ +// SPDX-FileCopyrightText: © 2019-2022 Alexandros Theodotou +// SPDX-License-Identifier: LicenseRef-ZrythmLicense /** * \file @@ -159,8 +143,15 @@ audio_region_fill_stereo_ports ( float audio_region_detect_bpm (ZRegion * self, GArray * candidates); +/** + * Sanity checking. + * + * @param frames_per_tick Frames per tick used when + * validating audio regions. Passing 0 will use the value + * from the current engine. + */ bool -audio_region_validate (ZRegion * self); +audio_region_validate (ZRegion * self, double frames_per_tick); /** * Frees members only but not the audio region itself. diff --git a/inc/audio/engine.h b/inc/audio/engine.h index d37474431..765681468 100644 --- a/inc/audio/engine.h +++ b/inc/audio/engine.h @@ -774,6 +774,13 @@ typedef struct AudioEngine /** Pointer to owner project, if any. */ Project * project; + + /** + * True while updating frames per tick. + * + * See engine_update_frames_per_tick(). + */ + bool updating_frames_per_tick; } AudioEngine; static const cyaml_schema_field_t engine_fields_schema[] = { diff --git a/inc/audio/position.h b/inc/audio/position.h index f726a2397..341f5cbbf 100644 --- a/inc/audio/position.h +++ b/inc/audio/position.h @@ -151,8 +151,11 @@ typedef struct Position * * To be used where more precision than Position.frames is * needed. + * + * @note Does not seem needed, keep comment around for + * reference in the future. */ - double precise_frames; + //double precise_frames; } Position; static const cyaml_schema_field_t position_fields_schema[] = { diff --git a/inc/audio/region.h b/inc/audio/region.h index 2518ad9ee..54db92eb1 100644 --- a/inc/audio/region.h +++ b/inc/audio/region.h @@ -1,21 +1,5 @@ -/* - * Copyright (C) 2018-2022 Alexandros Theodotou - * - * This file is part of Zrythm - * - * Zrythm is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Zrythm is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Zrythm. If not, see . - */ +// SPDX-FileCopyrightText: © 2018-2022 Alexandros Theodotou +// SPDX-License-Identifier: LicenseRef-ZrythmLicense /** * \file @@ -705,9 +689,16 @@ region_get_arranger_selections (ZRegion * self); /** * Sanity checking. + * + * @param frames_per_tick Frames per tick used when + * validating audio regions. Passing 0 will use the value + * from the current engine. */ bool -region_validate (ZRegion * self, bool is_project); +region_validate ( + ZRegion * self, + bool is_project, + double frames_per_tick); /** * Disconnects the region and anything using it. diff --git a/src/actions/undoable_action.c b/src/actions/undoable_action.c index b958c34f4..42b6beea1 100644 --- a/src/actions/undoable_action.c +++ b/src/actions/undoable_action.c @@ -18,6 +18,10 @@ void undoable_action_init_loaded (UndoableAction * self) { + double sample_rate_ratio = + (double) AUDIO_ENGINE->sample_rate / (double) self->sample_rate; + self->frames_per_tick = self->frames_per_tick * sample_rate_ratio; + /* uppercase, camel case, snake case */ #define INIT_LOADED(uc, sc, cc) \ case UA_##uc: \ @@ -62,6 +66,7 @@ undoable_action_init ( self->num_actions = 1; self->frames_per_tick = AUDIO_ENGINE->frames_per_tick; + self->sample_rate = AUDIO_ENGINE->sample_rate; } /** diff --git a/src/audio/audio_region.c b/src/audio/audio_region.c index 400d86937..d3fee1cb5 100644 --- a/src/audio/audio_region.c +++ b/src/audio/audio_region.c @@ -600,23 +600,49 @@ audio_region_detect_bpm (ZRegion * self, GArray * candidates) (unsigned int) AUDIO_ENGINE->sample_rate, candidates); } +/** + * Sanity checking. + * + * @param frames_per_tick Frames per tick used when + * validating audio regions. Passing 0 will use the value + * from the current engine. + */ bool -audio_region_validate (ZRegion * self) +audio_region_validate (ZRegion * self, double frames_per_tick) { - if (PROJECT->loaded) + if (PROJECT->loaded && !AUDIO_ENGINE->updating_frames_per_tick) { AudioClip * clip = audio_region_get_clip (self); g_return_val_if_fail (clip, false); - signed_frame_t loop_len = - arranger_object_get_loop_length_in_frames ( - (ArrangerObject *) self); - /* verify that the loop does not contain more * frames than available in the clip */ - z_return_val_if_fail_cmp ( - loop_len, <=, (signed_frame_t) clip->num_frames, - false); + /* use global positions because sometimes the loop + * appears to have 1 more frame due to rounding to + * nearest frame*/ + ArrangerObject * obj = (ArrangerObject *) self; + signed_frame_t loop_start_global = + position_get_frames_from_ticks ( + obj->pos.ticks + obj->loop_start_pos.ticks, + frames_per_tick); + signed_frame_t loop_end_global = + position_get_frames_from_ticks ( + obj->pos.ticks + obj->loop_end_pos.ticks, + frames_per_tick); + signed_frame_t loop_len = + loop_end_global - loop_start_global; + /*g_debug ("loop len: %" SIGNED_FRAME_FORMAT, loop_len);*/ + + if (loop_len > (signed_frame_t) clip->num_frames) + { + g_critical ( + "Audio region loop length in frames (%" SIGNED_FRAME_FORMAT + ") is " + "greater than the number of frames in the " + "clip (%" UNSIGNED_FRAME_FORMAT "). ", + loop_len, clip->num_frames); + return false; + } } return true; diff --git a/src/audio/engine.c b/src/audio/engine.c index 525fb744e..5f966641e 100644 --- a/src/audio/engine.c +++ b/src/audio/engine.c @@ -160,6 +160,8 @@ engine_update_frames_per_tick ( return; } + self->updating_frames_per_tick = true; + /* process all recording events */ recording_manager_process_events (RECORDING_MANAGER); @@ -191,6 +193,8 @@ engine_update_frames_per_tick ( track_update_positions ( TRACKLIST->tracks[i], update_from_ticks, bpm_change); } + + self->updating_frames_per_tick = false; } /** diff --git a/src/audio/position.c b/src/audio/position.c index 486be7413..908bd2713 100644 --- a/src/audio/position.c +++ b/src/audio/position.c @@ -679,9 +679,19 @@ position_to_string_full ( int sixteenths = position_get_sixteenths (pos, true); double ticks = position_get_ticks (pos); g_return_if_fail (bars > -80000); - sprintf ( - buf, "%d.%d.%d.%.*f", bars, abs (beats), abs (sixteenths), - decimal_places, fabs (ticks)); + if (ZRYTHM_TESTING) + { + sprintf ( + buf, "%d.%d.%d.%.*f (%" SIGNED_FRAME_FORMAT ")", bars, + abs (beats), abs (sixteenths), decimal_places, + fabs (ticks), pos->frames); + } + else + { + sprintf ( + buf, "%d.%d.%d.%.*f", bars, abs (beats), + abs (sixteenths), decimal_places, fabs (ticks)); + } } /** diff --git a/src/audio/region.c b/src/audio/region.c index 52fb7e206..085f0f39e 100644 --- a/src/audio/region.c +++ b/src/audio/region.c @@ -88,7 +88,7 @@ region_init ( self->magic = REGION_MAGIC; - region_validate (self, false); + region_validate (self, false, 0); } /** @@ -476,9 +476,16 @@ region_get_type_as_string (RegionType type, char * buf) /** * Sanity checking. + * + * @param frames_per_tick Frames per tick used when + * validating audio regions. Passing 0 will use the value + * from the current engine. */ bool -region_validate (ZRegion * self, bool is_project) +region_validate ( + ZRegion * self, + bool is_project, + double frames_per_tick) { g_return_val_if_fail (IS_REGION (self), false); @@ -511,7 +518,7 @@ region_validate (ZRegion * self, bool is_project) automation_region_validate (self); break; case REGION_TYPE_AUDIO: - audio_region_validate (self); + audio_region_validate (self, frames_per_tick); break; default: break; diff --git a/src/audio/router.c b/src/audio/router.c index 5c38367ac..57fd24e51 100644 --- a/src/audio/router.c +++ b/src/audio/router.c @@ -1,24 +1,11 @@ +// SPDX-FileCopyrightText: © 2019-2022 Alexandros Theodotou +// SPDX-License-Identifier: LicenseRef-ZrythmLicense /* - * Copyright (C) 2019-2022 Alexandros Theodotou - * - * This file is part of Zrythm - * - * Zrythm is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Zrythm is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Zrythm. If not, see . - * * This file incorporates work covered by the following copyright and * permission notice: * + * --- + * * Copyright (C) 2017, 2019 Robin Gareus * * This program is free software: you can redistribute it and/or modify @@ -33,6 +20,10 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * --- */ #include "zrythm-config.h" diff --git a/src/audio/track.c b/src/audio/track.c index 74a51ef4f..e1d58765a 100644 --- a/src/audio/track.c +++ b/src/audio/track.c @@ -1123,15 +1123,16 @@ track_validate (Track * self) for (int j = 0; j < lane->num_regions; j++) { ZRegion * region = lane->regions[j]; - region_validate ( - region, track_is_in_active_project (self)); + bool is_project = track_is_in_active_project (self); + region_validate (region, is_project, 0); } } for (int i = 0; i < self->num_chord_regions; i++) { ZRegion * r = self->chord_regions[i]; - region_validate (r, track_is_in_active_project (self)); + region_validate ( + r, track_is_in_active_project (self), 0); } g_debug ("done validating track '%s'", self->name); @@ -1801,7 +1802,7 @@ track_insert_region ( track = automation_track_get_track (at); } g_return_if_fail (IS_TRACK (track)); - g_return_if_fail (region_validate (region, false)); + g_return_if_fail (region_validate (region, false, 0)); g_return_if_fail (track_type_can_have_region_type ( track->type, region->id.type)); diff --git a/src/audio/track_lane.c b/src/audio/track_lane.c index 91d803aed..96b7ca307 100644 --- a/src/audio/track_lane.c +++ b/src/audio/track_lane.c @@ -240,8 +240,20 @@ track_lane_update_positions ( continue; g_return_if_fail (IS_REGION_AND_NONNULL (r_obj)); + if (ZRYTHM_TESTING) + { + region_validate ( + (ZRegion *) r_obj, + track_lane_is_in_active_project (self), 0); + } arranger_object_update_positions ( r_obj, from_ticks, bpm_change, NULL); + if (ZRYTHM_TESTING) + { + region_validate ( + (ZRegion *) r_obj, + track_lane_is_in_active_project (self), 0); + } } } diff --git a/src/audio/tracklist.c b/src/audio/tracklist.c index 4e9af5afb..69bfccdfd 100644 --- a/src/audio/tracklist.c +++ b/src/audio/tracklist.c @@ -1,21 +1,5 @@ -/* - * Copyright (C) 2018-2022 Alexandros Theodotou - * - * This file is part of Zrythm - * - * Zrythm is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Zrythm is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Zrythm. If not, see . - */ +// SPDX-FileCopyrightText: © 2018-2022 Alexandros Theodotou +// SPDX-License-Identifier: LicenseRef-ZrythmLicense #include "actions/tracklist_selections.h" #include "audio/audio_region.h" diff --git a/src/gui/backend/arranger_object.c b/src/gui/backend/arranger_object.c index 5781ae1dc..9d72b816c 100644 --- a/src/gui/backend/arranger_object.c +++ b/src/gui/backend/arranger_object.c @@ -1070,7 +1070,8 @@ init_loaded_region (ZRegion * self) arranger_object_gen_escaped_name ((ArrangerObject *) self); - region_validate (self, false); + /* TODO reenable */ + /*region_validate (self, false);*/ } /** @@ -1125,6 +1126,15 @@ arranger_object_update_positions ( bool bpm_change, UndoableAction * action) { +#if 0 + g_debug ("\n\n\nobject before"); + arranger_object_print (self); + if (self->type == ARRANGER_OBJECT_TYPE_REGION) + { + region_print ((ZRegion *) self); + } +#endif + long frames_len_before = 0; if (bpm_change && arranger_object_type_has_length (self->type)) { @@ -1172,6 +1182,15 @@ arranger_object_update_positions ( position_update (&self->fade_out_pos, from_ticks, ratio); } +#if 0 + g_debug ("\n\n\nobject after just position updates"); + arranger_object_print (self); + if (self->type == ARRANGER_OBJECT_TYPE_REGION) + { + region_print ((ZRegion *) self); + } +#endif + ZRegion * r; switch (self->type) { @@ -1205,11 +1224,21 @@ arranger_object_update_positions ( clip = audio_region_get_clip (r); g_return_if_fail (clip); +#if 0 + g_debug ( + "\n\n\nobject after audio region main logic"); + arranger_object_print (self); +#endif + /* sometimes due to rounding errors, * the region frames are 1 frame more * than the clip frames. this works * around it by resizing the region * by -1 frame*/ +#if 0 + signed_frame_t loop_len_frames = + arranger_object_get_loop_length_in_frames (self); +#endif while ( local_frames == (signed_frame_t) clip->num_frames) { @@ -1222,12 +1251,37 @@ arranger_object_update_positions ( ticks, false); local_frames = region_timeline_frames_to_local ( r, tl_frames, F_NORMALIZE); +#if 0 + loop_len_frames = + arranger_object_get_loop_length_in_frames ( + self); + g_return_if_fail ( + loop_len_frames + <= (signed_frame_t) clip->num_frames); +#endif } +#if 0 + arranger_object_print (self); region_print (r); + double loop_len_ticks = + arranger_object_get_loop_length_in_ticks (self); + g_message ( + "\t\t\tassert local frames %" SIGNED_FRAME_FORMAT + " < clip frames %" UNSIGNED_FRAME_FORMAT + ", loop len %f ticks %" SIGNED_FRAME_FORMAT + " frames", + local_frames, clip->num_frames, loop_len_ticks, + loop_len_frames); +#endif z_return_if_fail_cmp ( local_frames, <, (signed_frame_t) clip->num_frames); +#if 0 + z_return_if_fail_cmp ( + loop_len_frames, <=, + (signed_frame_t) clip->num_frames); +#endif } for (int i = 0; i < r->num_midi_notes; i++) diff --git a/src/gui/backend/arranger_selections.c b/src/gui/backend/arranger_selections.c index 5ead3ad4a..4669d6943 100644 --- a/src/gui/backend/arranger_selections.c +++ b/src/gui/backend/arranger_selections.c @@ -45,7 +45,6 @@ * @param action To be passed when this is called from an * undoable action. */ -NONNULL void arranger_selections_init_loaded ( ArrangerSelections * self, @@ -85,12 +84,18 @@ arranger_selections_init_loaded ( obj, true, false, NULL); \ sel->sc##s[i] = (cc *) arranger_object_find (obj); \ } \ - else \ + else /* else if not project */ \ { \ arranger_object_init_loaded ( \ (ArrangerObject *) sel->sc##s[i]); \ arranger_object_update_positions ( \ obj, true, false, action); \ + if (obj->type == ARRANGER_OBJECT_TYPE_REGION) \ + { \ + region_validate ( \ + (ZRegion *) obj, project, \ + action ? action->frames_per_tick : 0); \ + } \ } \ } diff --git a/src/project.c b/src/project.c index d1bfcef6c..92d0ff219 100644 --- a/src/project.c +++ b/src/project.c @@ -1029,15 +1029,6 @@ load (const char * filename, const int is_template) * during engine pre setup */ audio_pool_init_loaded (self->audio_engine->pool); - if (self->undo_manager) - { - undo_manager_init_loaded (self->undo_manager); - } - else - { - self->undo_manager = undo_manager_new (); - } - clip_editor_init_loaded (self->clip_editor); timeline_init_loaded (self->timeline); tracklist_init_loaded (self->tracklist, self, NULL); @@ -1049,6 +1040,17 @@ load (const char * filename, const int is_template) tempo_track_get_current_bpm (P_TEMPO_TRACK), AUDIO_ENGINE->sample_rate, true, true, false); + /* undo manager must be loaded after updating engine + * frames per tick */ + if (self->undo_manager) + { + undo_manager_init_loaded (self->undo_manager); + } + else + { + self->undo_manager = undo_manager_new (); + } + midi_mappings_init_loaded (self->midi_mappings); arranger_selections_init_loaded ( diff --git a/tests/actions/arranger_selections.c b/tests/actions/arranger_selections.c index 50485c300..0f49654d2 100644 --- a/tests/actions/arranger_selections.c +++ b/tests/actions/arranger_selections.c @@ -284,7 +284,7 @@ test_delete_chords (void) rebootstrap_timeline (); ZRegion * r = P_CHORD_TRACK->chord_regions[0]; - g_assert_true (region_validate (r, F_PROJECT)); + g_assert_true (region_validate (r, F_PROJECT, 0)); /* add another chord */ ChordObject * c = chord_object_new (&r->id, 2, 2); @@ -304,7 +304,7 @@ test_delete_chords (void) (ArrangerObject *) r->chord_objects[0]); arranger_selections_action_perform_delete ( CHORD_SELECTIONS, NULL); - g_assert_true (region_validate (r, F_PROJECT)); + g_assert_true (region_validate (r, F_PROJECT, 0)); undo_manager_undo (UNDO_MANAGER, NULL); undo_manager_redo (UNDO_MANAGER, NULL); @@ -478,7 +478,6 @@ check_after_move_timeline (int new_tracks) static void test_move_audio_region_and_lower_bpm (void) { - return; test_helper_zrythm_init (); char audio_file_path[2000]; @@ -510,9 +509,29 @@ test_move_audio_region_and_lower_bpm (void) /* lower BPM and attempt to save */ bpm_t bpm_before = tempo_track_get_current_bpm (P_TEMPO_TRACK); + ZRegion * r = TRACKLIST->tracks[5]->lanes[0]->regions[0]; + long frames_len = arranger_object_get_length_in_frames ( + (ArrangerObject *) r); + double ticks_len = arranger_object_get_length_in_ticks ( + (ArrangerObject *) r); + AudioClip * clip = AUDIO_ENGINE->pool->clips[r->pool_id]; + g_message ( + "before | r size: %ld (ticks %f), clip size %ld", + frames_len, ticks_len, clip->num_frames); + region_print (r); + region_validate (r, true, 0); tempo_track_set_bpm ( P_TEMPO_TRACK, bpm_before - bpm_diff, bpm_before, Z_F_NOT_TEMPORARY, F_NO_PUBLISH_EVENTS); + frames_len = arranger_object_get_length_in_frames ( + (ArrangerObject *) r); + ticks_len = arranger_object_get_length_in_ticks ( + (ArrangerObject *) r); + g_message ( + "after | r size: %ld (ticks %f), clip size %ld", + frames_len, ticks_len, clip->num_frames); + region_print (r); + region_validate (r, true, 0); test_project_save_and_reload (); /* undo lowering BPM */ @@ -522,6 +541,51 @@ test_move_audio_region_and_lower_bpm (void) test_helper_zrythm_cleanup (); } +static void +test_move_audio_region_and_lower_samplerate (void) +{ + test_helper_zrythm_init (); + + char audio_file_path[2000]; + sprintf ( + audio_file_path, "%s%s%s", TESTS_SRCDIR, + G_DIR_SEPARATOR_S, "test.wav"); + + /* create audio track with region */ + Position pos; + position_init (&pos); + int track_pos = TRACKLIST->num_tracks; + SupportedFile * file = + supported_file_new_from_path (audio_file_path); + Track * track = track_create_with_action ( + TRACK_TYPE_AUDIO, NULL, file, &pos, track_pos, 1, NULL); + + /* move the region */ + arranger_object_select ( + (ArrangerObject *) track->lanes[0]->regions[0], F_SELECT, + F_NO_APPEND, F_NO_PUBLISH_EVENTS); + arranger_selections_action_perform_move_timeline ( + TL_SELECTIONS, MOVE_TICKS, 0, 0, F_NOT_ALREADY_MOVED, + NULL); + + /* save the project */ + int ret = + project_save (PROJECT, PROJECT->dir, 0, 0, F_NO_ASYNC); + g_assert_cmpint (ret, ==, 0); + char * prj_file = + g_build_filename (PROJECT->dir, PROJECT_FILE, NULL); + + /* adjust the samplerate to be given at startup */ + zrythm_app->samplerate = (int) AUDIO_ENGINE->sample_rate / 2; + + object_free_w_func_and_null (project_free, PROJECT); + + /* reload */ + ret = project_load (prj_file, 0); + + test_helper_zrythm_cleanup (); +} + /** * Tests the move action. * @@ -1432,7 +1496,7 @@ test_split (void) g_assert_cmpint (lane2->num_regions, ==, 1); ZRegion * region2 = lane2->regions[0]; - region_validate (region2, false); + region_validate (region2, false, 0); undo_manager_undo (UNDO_MANAGER, NULL); undo_manager_redo (UNDO_MANAGER, NULL); @@ -1447,7 +1511,7 @@ test_split (void) g_assert_cmpint (lane->num_regions, ==, 1); ZRegion * region = lane->regions[0]; - region_validate (region, false); + region_validate (region, false, 0); r_obj = (ArrangerObject *) region; arranger_object_select ( r_obj, F_SELECT, F_NO_APPEND, F_NO_PUBLISH_EVENTS); @@ -3066,6 +3130,9 @@ main (int argc, char * argv[]) #define TEST_PREFIX "/actions/arranger_selections/" + g_test_add_func ( + TEST_PREFIX "test move audio_region_and lower samplerate", + (GTestFunc) test_move_audio_region_and_lower_samplerate); g_test_add_func ( TEST_PREFIX "test move audio_region_and lower bpm", (GTestFunc) test_move_audio_region_and_lower_bpm);