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