1 /*
2  * Copyright (C) 2018-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 MIDI notes in the PianoRoll.
24  */
25 
26 #ifndef __AUDIO_MIDI_NOTE_H__
27 #define __AUDIO_MIDI_NOTE_H__
28 
29 #include <stdint.h>
30 
31 #include "audio/midi_region.h"
32 #include "audio/position.h"
33 #include "audio/velocity.h"
34 #include "gui/backend/arranger_object.h"
35 
36 typedef struct _MidiNoteWidget MidiNoteWidget;
37 typedef struct Channel Channel;
38 typedef struct Track Track;
39 typedef struct MidiEvents MidiEvents;
40 typedef struct Position Position;
41 typedef struct Velocity Velocity;
42 
43 /**
44  * @addtogroup audio
45  *
46  * @{
47  */
48 
49 #define MIDI_NOTE_SCHEMA_VERSION 1
50 
51 #define MIDI_NOTE_MAGIC 3588791
52 #define IS_MIDI_NOTE(tr) \
53   ((MidiNote *) tr && \
54    ((MidiNote *) tr)->magic == MIDI_NOTE_MAGIC)
55 
56 #define midi_note_is_selected(r) \
57   arranger_object_is_selected ( \
58     (ArrangerObject *) r)
59 
60 /**
61  * A MIDI note inside a ZRegion shown in the
62  * piano roll.
63  */
64 typedef struct MidiNote
65 {
66   /** Base struct. */
67   ArrangerObject  base;
68 
69   int             schema_version;
70 
71   /** Velocity. */
72   Velocity *      vel;
73 
74   /** The note/pitch, (0-127). */
75   uint8_t         val;
76 
77   /** Cached note, for live operations. */
78   uint8_t         cache_val;
79 
80   /** Muted or not */
81   int             muted;
82 
83   /** Whether or not this note is currently
84    * listened to */
85   int             currently_listened;
86 
87   /** The note/pitch that is currently playing,
88    * if \ref MidiNote.currently_listened is true. */
89   uint8_t         last_listened_val;
90 
91   /** Index in the parent region. */
92   int             pos;
93 
94   int             magic;
95 
96   /** Cache layout for drawing the name. */
97   PangoLayout *   layout;
98 } MidiNote;
99 
100 static const cyaml_schema_field_t
101 midi_note_fields_schema[] =
102 {
103   YAML_FIELD_MAPPING_EMBEDDED (
104     MidiNote, base,
105     arranger_object_fields_schema),
106   YAML_FIELD_INT (MidiNote, schema_version),
107   YAML_FIELD_MAPPING_PTR (
108     MidiNote, vel, velocity_fields_schema),
109   YAML_FIELD_UINT (MidiNote, val),
110   YAML_FIELD_INT (MidiNote, muted),
111   YAML_FIELD_INT (MidiNote, pos),
112   CYAML_FIELD_END
113 };
114 
115 static const cyaml_schema_value_t
116   midi_note_schema =
117 {
118   /* allow nullable for mn_r1 in
119    * ArrangerSelectionsAction */
120   CYAML_VALUE_MAPPING (
121     CYAML_FLAG_POINTER_NULL_STR,
122     MidiNote, midi_note_fields_schema),
123 };
124 
125 /**
126  * Gets the global Position of the MidiNote's
127  * start_pos.
128  *
129  * @param pos Position to fill in.
130  */
131 void
132 midi_note_get_global_start_pos (
133   MidiNote * self,
134   Position * pos);
135 
136 /**
137  * Creates a new MidiNote.
138  */
139 MidiNote *
140 midi_note_new (
141   RegionIdentifier * region_id,
142   Position *   start_pos,
143   Position *   end_pos,
144   uint8_t      val,
145   uint8_t      vel);
146 
147 /**
148  * Sets the region the MidiNote belongs to.
149  */
150 void
151 midi_note_set_region_and_index (
152   MidiNote * self,
153   ZRegion *   region,
154   int        idx);
155 
156 void
157 midi_note_set_cache_val (
158   MidiNote *    self,
159   const uint8_t val);
160 
161 /**
162  * Returns 1 if the MidiNotes match, 0 if not.
163  */
164 int
165 midi_note_is_equal (
166   MidiNote * src,
167   MidiNote * dest);
168 
169 /**
170  * Gets the MIDI note's value as a string (eg
171  * "C#4").
172  *
173  * @param use_markup Use markup to show the octave
174  *   as a superscript.
175  */
176 void
177 midi_note_get_val_as_string (
178   MidiNote * self,
179   char *     buf,
180   const int  use_markup);
181 
182 /**
183  * For debugging.
184  */
185 void
186 midi_note_print (
187   MidiNote * mn);
188 
189 /**
190  * Listen to the given MidiNote.
191  *
192  * @param listen Turn note on if 1, or turn it
193  *   off if 0.
194  */
195 void
196 midi_note_listen (
197   MidiNote * mn,
198   bool       listen);
199 
200 /**
201  * Shifts MidiNote's position and/or value.
202  *
203  * @param delta Y (0-127)
204  */
205 void
206 midi_note_shift_pitch (
207   MidiNote * self,
208   const int  delta);
209 
210 /**
211  * Returns if the MIDI note is hit at given pos (in
212  * the timeline).
213  */
214 int
215 midi_note_hit (
216   MidiNote * midi_note,
217   const long       gframes);
218 
219 /**
220  * Converts an array of MIDI notes to MidiEvents.
221  *
222  * @param midi_notes Array of MidiNote's.
223  * @param num_notes Number of notes in array.
224  * @param pos Position to offset time from.
225  * @param events Preallocated struct to fill.
226  */
227 void
228 midi_note_notes_to_events (
229   MidiNote **  midi_notes,
230   int          num_notes,
231   Position *   pos,
232   MidiEvents * events);
233 
234 /**
235  * Sends a note off if currently playing and sets
236  * the pitch of the MidiNote.
237  */
238 void
239 midi_note_set_val (
240   MidiNote *    midi_note,
241   const uint8_t val);
242 
243 ZRegion *
244 midi_note_get_region (
245   MidiNote * self);
246 
247 /**
248  * @}
249  */
250 
251 #endif // __AUDIO_MIDI_NOTE_H__
252