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 #ifndef __AUDIO_EXT_PORT_H__
21 #define __AUDIO_EXT_PORT_H__
22 
23 /**
24  * \file
25  *
26  * External ports.
27  */
28 
29 #include "zrythm-config.h"
30 
31 #include "audio/fader.h"
32 #include "plugins/plugin.h"
33 #include "utils/audio.h"
34 #include "utils/types.h"
35 #include "utils/yaml.h"
36 
37 #include <gdk/gdk.h>
38 
39 #ifdef HAVE_JACK
40 #include "weak_libjack.h"
41 #endif
42 
43 #ifdef HAVE_RTMIDI
44 #include <rtmidi/rtmidi_c.h>
45 #endif
46 
47 typedef struct WindowsMmeDevice WindowsMmeDevice;
48 typedef struct HardwareProcessor HardwareProcessor;
49 
50 /**
51  * @addtogroup audio
52  *
53  * @{
54  */
55 
56 #define EXT_PORT_SCHEMA_VERSION 1
57 
58 /**
59  * Maximum external ports.
60  *
61  * Used for fixed-size arrays.
62  */
63 #define EXT_PORTS_MAX 1024
64 
65 #define ext_port_is_in_active_project(self) \
66   (self->hw_processor \
67    && \
68    hw_processor_is_in_active_project ( \
69      (self)->hw_processor))
70 
71 /**
72  * External port type.
73  */
74 typedef enum ExtPortType
75 {
76   EXT_PORT_TYPE_JACK,
77   EXT_PORT_TYPE_ALSA,
78   EXT_PORT_TYPE_WINDOWS_MME,
79   EXT_PORT_TYPE_RTMIDI,
80   EXT_PORT_TYPE_RTAUDIO,
81 } ExtPortType;
82 
83 static const cyaml_strval_t
84 ext_port_type_strings[] =
85 {
86   { "JACK",   EXT_PORT_TYPE_JACK    },
87   { "ALSA",   EXT_PORT_TYPE_ALSA   },
88   { "Windows MME",   EXT_PORT_TYPE_WINDOWS_MME   },
89   { "RtMidi",   EXT_PORT_TYPE_RTMIDI   },
90   { "RtAudio",   EXT_PORT_TYPE_RTAUDIO   },
91 };
92 
93 /**
94  * External port.
95  */
96 typedef struct ExtPort
97 {
98   int              schema_version;
99 
100   /** JACK port. */
101 #ifdef HAVE_JACK
102   jack_port_t *    jport;
103 #else
104   void *           jport;
105 #endif
106 
107   /** Full port name, used also as ID. */
108   char *           full_name;
109 
110   /** Short port name. */
111   char *           short_name;
112 
113   /** Alias #1 if any. */
114   char *           alias1;
115 
116   /** Alias #2 if any. */
117   char *           alias2;
118 
119   int              num_aliases;
120 
121 #ifdef _WOE32
122   /**
123    * Pointer to a WindowsMmeDevice.
124    *
125    * This must be one of the devices in AudioEngine.
126    * It must NOT be allocated or free'd.
127    */
128   WindowsMmeDevice * mme_dev;
129 #else
130   void *             mme_dev;
131 #endif
132 
133   /** RtAudio channel index. */
134   unsigned int     rtaudio_channel_idx;
135 
136   /** RtAudio device name. */
137   char *           rtaudio_dev_name;
138 
139   /** RtAudio device index. */
140   unsigned int     rtaudio_id;
141 
142   /** Whether the channel is input. */
143   bool             rtaudio_is_input;
144   bool             rtaudio_is_duplex;
145 
146 #ifdef HAVE_RTAUDIO
147   RtAudioDevice *  rtaudio_dev;
148 #else
149   void *           rtaudio_dev;
150 #endif
151 
152   /** RtMidi port index. */
153   unsigned int     rtmidi_id;
154 
155 #ifdef HAVE_RTMIDI
156   RtMidiDevice *   rtmidi_dev;
157 #else
158   void *           rtmidi_dev;
159 #endif
160 
161   ExtPortType      type;
162 
163   /** True if MIDI, false if audio. */
164   bool             is_midi;
165 
166   /** Index in the HW processor (cache for real-time
167    * use) */
168   int              hw_processor_index;
169 
170   /** Pointer to owner hardware processor, if any. */
171   HardwareProcessor * hw_processor;
172 
173   /** Whether the port is active and receiving
174    * events (for use by hw processor). */
175   bool             active;
176 
177   /**
178    * Temporary port to receive data.
179    */
180   Port *           port;
181 } ExtPort;
182 
183 static const cyaml_schema_field_t
184 ext_port_fields_schema[] =
185 {
186   YAML_FIELD_INT (
187     ExtPort, schema_version),
188   YAML_FIELD_STRING_PTR (
189     ExtPort, full_name),
190   YAML_FIELD_STRING_PTR_OPTIONAL (
191     ExtPort, short_name),
192   YAML_FIELD_STRING_PTR_OPTIONAL (
193     ExtPort, alias1),
194   YAML_FIELD_STRING_PTR_OPTIONAL (
195     ExtPort, alias2),
196   YAML_FIELD_STRING_PTR_OPTIONAL (
197     ExtPort, rtaudio_dev_name),
198   YAML_FIELD_INT (
199     ExtPort, num_aliases),
200   YAML_FIELD_INT (
201     ExtPort, is_midi),
202   YAML_FIELD_ENUM (
203     ExtPort, type, ext_port_type_strings),
204   YAML_FIELD_UINT (
205     ExtPort, rtaudio_channel_idx),
206 
207   CYAML_FIELD_END
208 };
209 
210 static const cyaml_schema_value_t
211 ext_port_schema =
212 {
213   YAML_VALUE_PTR (
214     ExtPort, ext_port_fields_schema),
215 };
216 
217 /**
218  * Inits the ExtPort after loading a project.
219  */
220 COLD
221 NONNULL_ARGS (1)
222 void
223 ext_port_init_loaded (
224   ExtPort *           self,
225   HardwareProcessor * hw_processor);
226 
227 /**
228  * Prints the port info.
229  */
230 void
231 ext_port_print (
232   ExtPort * self);
233 
234 /**
235  * Returns if the ext port matches the current
236  * backend.
237  */
238 bool
239 ext_port_matches_backend (
240   ExtPort * self);
241 
242 /**
243  * Returns a unique identifier (full name prefixed
244  * with backend type).
245  */
246 char *
247 ext_port_get_id (
248   ExtPort * ext_port);
249 
250 /**
251  * Returns the buffer of the external port.
252  */
253 float *
254 ext_port_get_buffer (
255   ExtPort * ext_port,
256   nframes_t nframes);
257 
258 /**
259  * Clears the buffer of the external port.
260  */
261 void
262 ext_port_clear_buffer (
263   ExtPort * ext_port,
264   nframes_t nframes);
265 
266 /**
267  * Exposes the given Port if not exposed and makes
268  * the connection from the Port to the ExtPort (eg in
269  * JACK) or backwards.
270  *
271  * @param src 1 if the ext_port is the source, 0 if it
272  *   is the destination.
273  */
274 void
275 ext_port_connect (
276   ExtPort * ext_port,
277   Port *    port,
278   int       src);
279 
280 /**
281  * Disconnects the Port from the ExtPort.
282  *
283  * @param src 1 if the ext_port is the source, 0 if it
284  *   is the destination.
285  */
286 void
287 ext_port_disconnect (
288   ExtPort * ext_port,
289   Port *    port,
290   int       src);
291 
292 /**
293  * Activates the port (starts receiving data) or
294  * deactivates it.
295  *
296  * @param port Port to send the output to.
297  */
298 void
299 ext_port_activate (
300   ExtPort * self,
301   Port *    port,
302   bool      activate);
303 
304 /**
305  * Checks in the GSettings whether this port is
306  * marked as enabled by the user.
307  *
308  * @note Not realtime safe.
309  *
310  * @return Whether the port is enabled.
311  */
312 bool
313 ext_port_get_enabled (
314   ExtPort * self);
315 
316 /**
317  * Collects external ports of the given type.
318  *
319  * @param flow The signal flow. Note that this is
320  *   inverse to what Zrythm sees. E.g., to get
321  *   MIDI inputs like MIDI keyboards, pass
322  *   \ref FLOW_OUTPUT here.
323  * @param hw Hardware or not.
324  */
325 void
326 ext_ports_get (
327   PortType    type,
328   PortFlow    flow,
329   bool        hw,
330   GPtrArray * ports);
331 
332 /**
333  * Creates a shallow clone of the port.
334  */
335 ExtPort *
336 ext_port_clone (
337   ExtPort * ext_port);
338 
339 /**
340  * Frees an array of ExtPort pointers.
341  */
342 void
343 ext_ports_free (
344   ExtPort ** ext_port,
345   int        size);
346 
347 /**
348  * Frees the ext_port.
349  */
350 void
351 ext_port_free (
352   ExtPort * ext_port);
353 
354 /**
355  * @}
356  */
357 
358 #endif
359