1 /*
2 * Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Zrythm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21
22 #include "audio/audio_region.h"
23 #include "audio/track.h"
24 #include "audio/track_lane.h"
25 #include "audio/tracklist.h"
26 #include "gui/backend/event.h"
27 #include "gui/backend/event_manager.h"
28 #include "gui/widgets/arranger.h"
29 #include "midilib/src/midifile.h"
30 #include "midilib/src/midiinfo.h"
31 #include "project.h"
32 #include "utils/arrays.h"
33 #include "utils/error.h"
34 #include "utils/flags.h"
35 #include "utils/mem.h"
36 #include "utils/objects.h"
37 #include "zrythm_app.h"
38
39 #include <glib/gi18n.h>
40
41 /**
42 * Inits the TrackLane after a project was loaded.
43 */
44 void
track_lane_init_loaded(TrackLane * self,Track * track)45 track_lane_init_loaded (
46 TrackLane * self,
47 Track * track)
48 {
49 self->track = track;
50 self->regions_size =
51 (size_t) self->num_regions;
52 int i;
53 ZRegion * region;
54 for (i = 0; i < self->num_regions; i++)
55 {
56 region = self->regions[i];
57 region->magic = REGION_MAGIC;
58 ArrangerObject * r_obj =
59 (ArrangerObject *) region;
60 region_set_lane (region, self);
61 arranger_object_init_loaded (r_obj);
62 }
63 }
64
65 /**
66 * Creates a new TrackLane at the given pos in the
67 * given Track.
68 *
69 * @param track The Track to create the TrackLane for.
70 * @param pos The position (index) in the Track that
71 * this lane will be placed in.
72 */
73 TrackLane *
track_lane_new(Track * track,int pos)74 track_lane_new (
75 Track * track,
76 int pos)
77 {
78 TrackLane * self = object_new (TrackLane);
79 self->schema_version = TRACK_LANE_SCHEMA_VERSION;
80 self->pos = pos;
81 self->track = track;
82
83 self->name =
84 g_strdup_printf (_("Lane %d"), pos + 1);
85
86 self->regions_size = 1;
87 self->regions =
88 object_new_n (self->regions_size, ZRegion *);
89
90 self->height = TRACK_DEF_HEIGHT;
91
92 return self;
93 }
94
95 /**
96 * Rename the lane.
97 *
98 * @param with_action Whether to make this an
99 * undoable action.
100 */
101 void
track_lane_rename(TrackLane * self,const char * new_name,bool with_action)102 track_lane_rename (
103 TrackLane * self,
104 const char * new_name,
105 bool with_action)
106 {
107 if (with_action)
108 {
109 GError * err = NULL;
110 bool ret =
111 tracklist_selections_action_perform_edit_rename_lane (
112 self, new_name, &err);
113 if (!ret)
114 {
115 HANDLE_ERROR (
116 err, "%s", _("Failed to rename lane"));
117 }
118 EVENTS_PUSH (
119 ET_TRACK_LANES_VISIBILITY_CHANGED, NULL);
120 }
121 else
122 {
123 char * prev_name = self->name;
124 self->name = g_strdup (new_name);
125 g_free (prev_name);
126 }
127 }
128
129 /**
130 * Wrapper over track_lane_rename().
131 */
132 void
track_lane_rename_with_action(TrackLane * self,const char * new_name)133 track_lane_rename_with_action (
134 TrackLane * self,
135 const char * new_name)
136 {
137 track_lane_rename (self, new_name, true);
138 }
139
140 const char *
track_lane_get_name(TrackLane * self)141 track_lane_get_name (
142 TrackLane * self)
143 {
144 return self->name;
145 }
146
147 /**
148 * Updates the positions in each child recursively.
149 *
150 * @param from_ticks Whether to update the
151 * positions based on ticks (true) or frames
152 * (false).
153 */
154 void
track_lane_update_positions(TrackLane * self,bool from_ticks)155 track_lane_update_positions (
156 TrackLane * self,
157 bool from_ticks)
158 {
159 for (int i = 0; i < self->num_regions; i++)
160 {
161 ArrangerObject * r_obj =
162 (ArrangerObject *) self->regions[i];
163
164 /* project not ready yet */
165 if (!PROJECT || !AUDIO_ENGINE->pre_setup)
166 continue;
167
168 g_return_if_fail (
169 IS_REGION_AND_NONNULL (r_obj));
170 arranger_object_update_positions (
171 r_obj, from_ticks);
172 }
173 }
174
175 /**
176 * Adds a ZRegion to the given TrackLane.
177 */
178 void
track_lane_add_region(TrackLane * self,ZRegion * region)179 track_lane_add_region (
180 TrackLane * self,
181 ZRegion * region)
182 {
183 track_lane_insert_region (
184 self, region, self->num_regions);
185 }
186
187 /**
188 * Inserts a ZRegion to the given TrackLane at the
189 * given index.
190 */
191 void
track_lane_insert_region(TrackLane * self,ZRegion * region,int idx)192 track_lane_insert_region (
193 TrackLane * self,
194 ZRegion * region,
195 int idx)
196 {
197 g_return_if_fail (
198 self && IS_REGION (region) && idx >= 0 &&
199 (region->id.type == REGION_TYPE_AUDIO ||
200 region->id.type == REGION_TYPE_MIDI));
201
202 region_set_lane (region, self);
203
204 array_double_size_if_full (
205 self->regions, self->num_regions,
206 self->regions_size, ZRegion *);
207 for (int i = self->num_regions; i > idx; i--)
208 {
209 self->regions[i] = self->regions[i - 1];
210 self->regions[i]->id.idx = i;
211 region_update_identifier (
212 self->regions[i]);
213 }
214 self->num_regions++;
215 self->regions[idx] = region;
216 region->id.lane_pos = self->pos;
217 region->id.idx = idx;
218 region_update_identifier (region);
219
220 if (region->id.type == REGION_TYPE_AUDIO)
221 {
222 AudioClip * clip =
223 audio_region_get_clip (region);
224 g_return_if_fail (clip);
225 }
226 }
227
228 /**
229 * Sets the new track name hash to all the lane's
230 * objects recursively.
231 */
232 void
track_lane_update_track_name_hash(TrackLane * self)233 track_lane_update_track_name_hash (
234 TrackLane * self)
235 {
236 Track * track = self->track;
237 g_return_if_fail (IS_TRACK_AND_NONNULL (track));
238
239 for (int i = 0; i < self->num_regions; i++)
240 {
241 ZRegion * region = self->regions[i];
242 region->id.track_name_hash =
243 track_get_name_hash (track);
244 region->id.lane_pos = self->pos;
245 region_update_identifier (region);
246 }
247 }
248
249 /**
250 * Clones the TrackLane.
251 *
252 * @param track New owner track, if any.
253 */
254 TrackLane *
track_lane_clone(const TrackLane * src,Track * track)255 track_lane_clone (
256 const TrackLane * src,
257 Track * track)
258 {
259 TrackLane * self = object_new (TrackLane);
260 self->schema_version = TRACK_LANE_SCHEMA_VERSION;
261 self->track = track;
262
263 self->name =
264 g_strdup (src->name);
265 self->regions_size =
266 (size_t) src->num_regions;
267 self->regions =
268 object_new_n (self->regions_size, ZRegion *);
269 self->height =
270 src->height;
271 self->pos = src->pos;
272 self->mute = src->mute;
273 self->solo = src->solo;
274 self->midi_ch = src->midi_ch;
275
276 ZRegion * region, * new_region;
277 self->num_regions = src->num_regions;
278 self->regions =
279 g_realloc (
280 self->regions,
281 sizeof (ZRegion *) *
282 (size_t) src->num_regions);
283 for (int i = 0; i < src->num_regions; i++)
284 {
285 /* clone region */
286 region = src->regions[i];
287 new_region =
288 (ZRegion *)
289 arranger_object_clone (
290 (ArrangerObject *) region);
291
292 self->regions[i] = new_region;
293 region_set_lane (new_region, self);
294
295 region_gen_name (
296 new_region, region->name, NULL, NULL);
297 }
298
299 return self;
300 }
301
302 /**
303 * Unselects all arranger objects.
304 *
305 * TODO replace with "select_all" and boolean param.
306 */
307 void
track_lane_unselect_all(TrackLane * self)308 track_lane_unselect_all (
309 TrackLane * self)
310 {
311 Track * track = track_lane_get_track (self);
312 g_return_if_fail (track);
313 for (int i = 0; i < self->num_regions; i++)
314 {
315 ZRegion * region = self->regions[i];
316 arranger_object_select (
317 (ArrangerObject *) region, false, false,
318 F_NO_PUBLISH_EVENTS);
319 }
320 }
321
322 /**
323 * Removes all objects recursively from the track
324 * lane.
325 */
326 void
track_lane_clear(TrackLane * self)327 track_lane_clear (
328 TrackLane * self)
329 {
330 Track * track = track_lane_get_track (self);
331 g_return_if_fail (IS_TRACK_AND_NONNULL (track));
332
333 g_message (
334 "clearing track lane %d (%p) for track '%s' | "
335 "num regions %d",
336 self->pos, self, track->name, self->num_regions);
337
338 for (int i = self->num_regions - 1; i >= 0; i--)
339 {
340 ZRegion * region = self->regions[i];
341 g_return_if_fail (
342 IS_REGION (region)
343 &&
344 region->id.track_name_hash ==
345 track_get_name_hash (track)
346 && region->id.lane_pos == self->pos);
347 track_remove_region (
348 track, region, 0, 1);
349 }
350
351 g_return_if_fail (self->num_regions == 0);
352 }
353
354 /**
355 * Removes but does not free the region.
356 */
357 void
track_lane_remove_region(TrackLane * self,ZRegion * region)358 track_lane_remove_region (
359 TrackLane * self,
360 ZRegion * region)
361 {
362 g_return_if_fail (IS_REGION (region));
363
364 if (track_lane_is_in_active_project (self)
365 && !track_lane_is_auditioner (self))
366 {
367 /* if clip editor region index is greater
368 * than this index, decrement it */
369 ZRegion * clip_editor_r =
370 clip_editor_get_region (CLIP_EDITOR);
371 if (clip_editor_r
372 &&
373 clip_editor_r->id.track_name_hash ==
374 region->id.track_name_hash
375 &&
376 clip_editor_r->id.lane_pos ==
377 region->id.lane_pos
378 &&
379 clip_editor_r->id.idx > region->id.idx)
380 {
381 CLIP_EDITOR->region_id.idx--;
382 }
383 }
384
385 bool deleted = false;
386 array_delete_confirm (
387 self->regions, self->num_regions, region,
388 deleted);
389 g_return_if_fail (deleted);
390
391 for (int i = region->id.idx; i < self->num_regions;
392 i++)
393 {
394 ZRegion * r = self->regions[i];
395 r->id.idx = i;
396 region_update_identifier (r);
397 }
398 }
399
400 Tracklist *
track_lane_get_tracklist(TrackLane * self)401 track_lane_get_tracklist (
402 TrackLane * self)
403 {
404 if (track_lane_is_auditioner (self))
405 return SAMPLE_PROCESSOR->tracklist;
406 else
407 return TRACKLIST;
408 }
409
410 Track *
track_lane_get_track(TrackLane * self)411 track_lane_get_track (
412 TrackLane * self)
413 {
414 g_return_val_if_fail (self->track, NULL);
415 return self->track;
416 }
417
418 /**
419 * Writes the lane to the given MIDI file.
420 */
421 void
track_lane_write_to_midi_file(TrackLane * self,MIDI_FILE * mf)422 track_lane_write_to_midi_file (
423 TrackLane * self,
424 MIDI_FILE * mf)
425 {
426 /* All data is written out to _tracks_ not
427 * channels. We therefore
428 ** set the current channel before writing
429 data out. Channel assignments
430 ** can change any number of times during the
431 file, and affect all
432 ** tracks messages until it is changed. */
433 midiFileSetTracksDefaultChannel (
434 mf, self->track->pos, MIDI_CHANNEL_1);
435
436 Track * track = track_lane_get_track (self);
437 g_return_if_fail (track);
438
439 /* add track name */
440 midiTrackAddText (
441 mf, self->track->pos, textTrackName,
442 track->name);
443
444 ZRegion * region;
445 for (int i = 0; i < self->num_regions; i++)
446 {
447 region = self->regions[i];
448 midi_region_write_to_midi_file (
449 region, mf, 1, true, true);
450 }
451 }
452
453 /**
454 * Frees the TrackLane.
455 */
456 void
track_lane_free(TrackLane * self)457 track_lane_free (
458 TrackLane * self)
459 {
460 g_free_and_null (self->name);
461
462 for (int i = 0; i < self->num_regions; i++)
463 {
464 arranger_object_free (
465 (ArrangerObject *) self->regions[i]);
466 }
467
468 object_zero_and_free_if_nonnull (self->regions);
469
470 object_zero_and_free (self);
471 }
472