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 /**
21  * \file
22  *
23  * API for Region's specific to instrument Track's.
24  */
25 
26 #ifndef __AUDIO_MIDI_REGION_H__
27 #define __AUDIO_MIDI_REGION_H__
28 
29 #include <stddef.h>
30 #include <stdbool.h>
31 #include <stdint.h>
32 
33 #include "utils/types.h"
34 
35 typedef struct Track Track;
36 typedef struct Position Position;
37 typedef struct MidiNote MidiNote;
38 typedef struct ZRegion ZRegion;
39 typedef struct MidiEvents MidiEvents;
40 typedef struct ChordDescriptor ChordDescriptor;
41 typedef struct Velocity Velocity;
42 typedef ZRegion MidiRegion;
43 typedef void MIDI_FILE;
44 
45 /**
46  * @addtogroup audio
47  *
48  * @{
49  */
50 
51 /**
52  * Creates a new ZRegion for MIDI notes.
53  */
54 ZRegion *
55 midi_region_new (
56   const Position * start_pos,
57   const Position * end_pos,
58   unsigned int     track_name_hash,
59   int              lane_pos,
60   int              idx_inside_lane);
61 
62 /**
63  * Creates a MIDI region from the given MIDI
64  * file path, starting at the given Position.
65  *
66  * @param idx The index of this track, starting from
67  *   0. This will be sequential, ie, if idx 1 is
68  *   requested and the MIDI file only has tracks
69  *   5 and 7, it will use track 7.
70  */
71 ZRegion *
72 midi_region_new_from_midi_file (
73   const Position * start_pos,
74   const char *     abs_path,
75   unsigned int     track_name_hash,
76   int              lane_pos,
77   int              idx_inside_lane,
78   int              idx);
79 
80 /**
81  * Create a region from the chord descriptor.
82  *
83  * Default size will be timeline snap and default
84  * notes size will be editor snap.
85  */
86 ZRegion *
87 midi_region_new_from_chord_descr (
88   const Position *  pos,
89   ChordDescriptor * descr,
90   unsigned int      track_name_hash,
91   int               lane_pos,
92   int               idx_inside_lane);
93 
94 /**
95  * Adds the MidiNote to the given ZRegion.
96  *
97  * @param pub_events Publish UI events or not.
98  */
99 #define midi_region_add_midi_note( \
100   region,midi_note,pub_events) \
101   midi_region_insert_midi_note ( \
102     region, midi_note, \
103     ((ZRegion *) (region))->num_midi_notes, \
104     pub_events)
105 
106 /**
107  * Inserts the MidiNote to the given ZRegion.
108  *
109  * @param idx Index to insert at.
110  * @param pub_events Publish UI events or not.
111  */
112 void
113 midi_region_insert_midi_note (
114   ZRegion *  region,
115   MidiNote * midi_note,
116   int        idx,
117   int        pub_events);
118 
119 /**
120  * Starts an unended note with the given pitch and
121  * velocity and adds it to \ref ZRegion.midi_notes.
122  *
123  * @param end_pos If this is NULL, it will be set to
124  *   1 tick after the start_pos.
125  */
126 void
127 midi_region_start_unended_note (
128   ZRegion *  self,
129   Position * start_pos,
130   Position * end_pos,
131   int        pitch,
132   int        vel,
133   int        pub_events);
134 
135 /**
136  * Returns the midi note with the given pitch from
137  * the unended notes.
138  *
139  * Used when recording.
140  *
141  * @param pitch The pitch. If -1, it returns any
142  *   unended note. This is useful when the loop
143  *   point is met and we want to end them all.
144  */
145 MidiNote *
146 midi_region_pop_unended_note (
147   ZRegion * self,
148   int       pitch);
149 
150 /**
151  * Fills MIDI event queue from the region.
152  *
153  * The events are dequeued right after the call to
154  * this function.
155  *
156  * @note The caller already splits calls to this
157  *   function at each sub-loop inside the region,
158  *   so region loop related logic is not needed.
159  *
160  * @param g_start_frames Global start frame.
161  * @param local_start_frame The start frame offset
162  *   from 0 in this cycle.
163  * @param nframes Number of frames at start
164  *   Position.
165  * @param note_off_at_end Whether a note off should
166  *   be added at the end frame (eg, when the caller
167  *   knows there is a region loop or the region
168  *   ends).
169  * @param midi_events MidiEvents to fill (from
170  *   Piano Roll Port for example).
171  */
172 REALTIME
173 void
174 midi_region_fill_midi_events (
175   ZRegion *    self,
176   long         g_start_frames,
177   nframes_t    local_start_frame,
178   nframes_t    nframes,
179   bool         note_off_at_end,
180   MidiEvents * midi_events);
181 
182 /**
183  * Prints the MidiNotes in the Region.
184  *
185  * Used for debugging.
186  */
187 void
188 midi_region_print_midi_notes (
189   ZRegion * self);
190 
191 /**
192  * Gets first midi note
193  */
194 MidiNote *
195 midi_region_get_first_midi_note (
196 	ZRegion * region);
197 
198 /**
199  * Gets last midi note
200  */
201 MidiNote *
202 midi_region_get_last_midi_note (
203 	ZRegion * region);
204 
205 /**
206  * Gets highest midi note
207  */
208 MidiNote *
209 midi_region_get_highest_midi_note (
210 	ZRegion * region);
211 
212 /**
213  * Gets lowest midi note
214  */
215 MidiNote *
216 midi_region_get_lowest_midi_note (
217 	ZRegion * region);
218 
219 /**
220  * Removes the MIDI note from the Region.
221  *
222  * @param free Also free the MidiNote.
223  * @param pub_event Publish an event.
224  */
225 void
226 midi_region_remove_midi_note (
227   ZRegion *  region,
228   MidiNote * midi_note,
229   int        free,
230   int        pub_event);
231 
232 /**
233  * Removes all MIDI ntoes and their components
234  * completely.
235  */
236 void
237 midi_region_remove_all_midi_notes (
238   ZRegion * region);
239 
240 
241 /**
242  * Returns the midi note at given position with the given
243  * pitch.
244  *
245  * Used when recording.
246  */
247 //MidiNote *
248 //midi_region_get_midi_note_at (
249   //ZRegion * self,
250   //Position *   pos,
251   //int          pitch);
252 
253 /**
254  * Exports the ZRegion to an existing MIDI file
255  * instance.
256  *
257  * @param add_region_start Add the region start
258  *   offset to the positions.
259  * @param export_full Traverse loops and export the
260  *   MIDI file as it would be played inside Zrythm.
261  *   If this is 0, only the original region (from
262  *   true start to true end) is exported.
263  * @param use_track_pos Whether to use the track
264  *   position in the MIDI data. The track will be
265  *   set to 1 if false.
266  */
267 void
268 midi_region_write_to_midi_file (
269   ZRegion *   self,
270   MIDI_FILE * mf,
271   const int   add_region_start,
272   bool        export_full,
273   bool        use_track_pos);
274 
275 /**
276  * Exports the ZRegion to a specified MIDI file.
277  *
278  * @param full_path Absolute path to the MIDI file.
279  * @param export_full Traverse loops and export the
280  *   MIDI file as it would be played inside Zrythm.
281  *   If this is 0, only the original region (from
282  *   true start to true end) is exported.
283  */
284 void
285 midi_region_export_to_midi_file (
286   ZRegion * self,
287   const char * full_path,
288   int          midi_version,
289   const int    export_full);
290 
291 /**
292  * Returns the MIDI channel that this region should
293  * be played on, starting from 1.
294  */
295 uint8_t
296 midi_region_get_midi_ch (
297   const ZRegion * self);
298 
299 /**
300  * Returns a newly initialized MidiEvents with
301  * the contents of the region converted into
302  * events.
303  *
304  * Must be free'd with midi_events_free ().
305  *
306  * @param add_region_start Add the region start
307  *   offset to the positions.
308  */
309 MidiEvents *
310 midi_region_get_as_events (
311   const ZRegion * self,
312   const int       add_region_start,
313   const int       full);
314 
315 /**
316  * Fills in the array with all the velocities in
317  * the project that are within or outside the
318  * range given.
319  *
320  * @param inside Whether to find velocities inside
321  *   the range (1) or outside (0).
322  */
323 void
324 midi_region_get_velocities_in_range (
325   const ZRegion *  self,
326   const Position * start_pos,
327   const Position * end_pos,
328   Velocity ***     velocities,
329   int *            num_velocities,
330   size_t *         velocities_size,
331   int              inside);
332 
333 /**
334  * Frees members only but not the midi region itself.
335  *
336  * Regions should be free'd using region_free.
337  */
338 void
339 midi_region_free_members (
340   ZRegion * self);
341 
342 /**
343  * @}
344  */
345 
346 #endif // __AUDIO_MIDI_REGION_H__
347