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  * Mapping MIDI CC to controls.
24  */
25 
26 #ifndef __AUDIO_MIDI_MAPPING_H__
27 #define __AUDIO_MIDI_MAPPING_H__
28 
29 #include "audio/ext_port.h"
30 #include "audio/midi.h"
31 #include "audio/port.h"
32 
33 /**
34  * @addtogroup audio
35  *
36  * @{
37  */
38 
39 #define MIDI_MAPPING_SCHEMA_VERSION 1
40 #define MIDI_MAPPINGS_SCHEMA_VERSION 1
41 
42 #define MIDI_MAPPINGS (PROJECT->midi_mappings)
43 
44 /**
45  * A mapping from a MIDI value to a destination.
46  */
47 typedef struct MidiMapping
48 {
49   int            schema_version;
50 
51   /** Raw MIDI signal. */
52   midi_byte_t    key[3];
53 
54   /** The device that this connection will be mapped
55    * for. */
56   ExtPort *      device_port;
57 
58   /** Destination. */
59   PortIdentifier dest_id;
60 
61   /**
62    * Destination pointer, for convenience.
63    *
64    * @note This pointer is not owned by this
65    *   instance.
66    */
67   Port *         dest;
68 
69   /** Whether this binding is enabled. */
70   volatile int   enabled;
71 } MidiMapping;
72 
73 static const cyaml_schema_field_t
74 midi_mapping_fields_schema[] =
75 {
76   YAML_FIELD_INT (
77     MidiMapping, schema_version),
78   YAML_FIELD_FIXED_SIZE_PTR_ARRAY (
79     MidiMapping, key,
80     uint8_t_schema, 3),
81   YAML_FIELD_MAPPING_PTR_OPTIONAL (
82     MidiMapping, device_port,
83     ext_port_fields_schema),
84   YAML_FIELD_MAPPING_EMBEDDED (
85     MidiMapping, dest_id,
86     port_identifier_fields_schema),
87   YAML_FIELD_INT (
88     MidiMapping, enabled),
89 
90   CYAML_FIELD_END
91 };
92 
93 static const cyaml_schema_value_t
94   midi_mapping_schema =
95 {
96   YAML_VALUE_PTR (
97     MidiMapping, midi_mapping_fields_schema),
98 };
99 
100 #if 0
101 static const cyaml_schema_value_t
102   midi_mapping_schema_default =
103 {
104   YAML_VALUE_DEFAULT (
105     MidiMapping, midi_mapping_fields_schema),
106 };
107 #endif
108 
109 /**
110  * All MIDI mappings in Zrythm.
111  */
112 typedef struct MidiMappings
113 {
114   int             schema_version;
115 
116   MidiMapping **  mappings;
117   size_t          mappings_size;
118   int             num_mappings;
119 } MidiMappings;
120 
121 static const cyaml_schema_field_t
122 midi_mappings_fields_schema[] =
123 {
124   YAML_FIELD_INT (MidiMappings, schema_version),
125   YAML_FIELD_DYN_PTR_ARRAY_VAR_COUNT_OPT (
126     MidiMappings, mappings,
127     midi_mapping_schema),
128 
129   CYAML_FIELD_END
130 };
131 
132 static const cyaml_schema_value_t
133 midi_mappings_schema =
134 {
135   YAML_VALUE_PTR (
136     MidiMappings, midi_mappings_fields_schema),
137 };
138 
139 /**
140  * Initializes the MidiMappings after a Project
141  * is loaded.
142  */
143 void
144 midi_mappings_init_loaded (
145   MidiMappings * self);
146 
147 /**
148  * Returns a newly allocated MidiMappings.
149  */
150 MidiMappings *
151 midi_mappings_new (void);
152 
153 #define midi_mappings_bind_device( \
154   self,buf,dev_port,dest_port,fire_events) \
155   midi_mappings_bind_at ( \
156     self, buf, dev_port, dest_port, \
157     (self)->num_mappings, fire_events)
158 
159 #define midi_mappings_bind_track( \
160   self,buf,dest_port,fire_events) \
161   midi_mappings_bind_at ( \
162     self, buf, NULL, dest_port, \
163     (self)->num_mappings, fire_events)
164 
165 /**
166  * Binds the CC represented by the given raw buffer
167  * (must be size 3) to the given Port.
168  *
169  * @param idx Index to insert at.
170  * @param buf The buffer used for matching at [0] and
171  *   [1].
172  * @param device_port Device port, if custom mapping.
173  */
174 void
175 midi_mappings_bind_at (
176   MidiMappings * self,
177   midi_byte_t *  buf,
178   ExtPort *      device_port,
179   Port *         dest_port,
180   int            idx,
181   bool           fire_events);
182 
183 /**
184  * Unbinds the given binding.
185  *
186  * @note This must be called inside a port operation
187  *   lock, such as inside an undoable action.
188  */
189 void
190 midi_mappings_unbind (
191   MidiMappings * self,
192   int            idx,
193   bool           fire_events);
194 
195 MidiMapping *
196 midi_mapping_new (void);
197 
198 void
199 midi_mapping_set_enabled (
200   MidiMapping * self,
201   bool          enabled);
202 
203 int
204 midi_mapping_get_index (
205   MidiMappings * self,
206   MidiMapping *  mapping);
207 
208 NONNULL
209 MidiMapping *
210 midi_mapping_clone (
211   const MidiMapping * src);
212 
213 void
214 midi_mapping_free (
215   MidiMapping * self);
216 
217 /**
218  * Applies the events to the appropriate mapping.
219  *
220  * This is used only for TrackProcessor.cc_mappings.
221  *
222  * @note Must only be called while transport is
223  *   recording.
224  */
225 void
226 midi_mappings_apply_from_cc_events (
227   MidiMappings * self,
228   MidiEvents *   events,
229   bool           queued);
230 
231 /**
232  * Applies the given buffer to the matching ports.
233  */
234 void
235 midi_mappings_apply (
236   MidiMappings * self,
237   midi_byte_t *  buf);
238 
239 /**
240  * Get MIDI mappings for the given port.
241  *
242  * @param size Size to set.
243  *
244  * @return a newly allocated array that must be
245  * free'd with free().
246  */
247 MidiMapping **
248 midi_mappings_get_for_port (
249   MidiMappings * self,
250   Port *         dest_port,
251   int *          size);
252 
253 MidiMappings *
254 midi_mappings_clone (
255   const MidiMappings * src);
256 
257 void
258 midi_mappings_free (
259   MidiMappings * self);
260 
261 /**
262  * @}
263  */
264 
265 #endif
266