1 /*
2  * Copyright (C) 2020-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 "audio/engine.h"
21 #include "audio/ext_port.h"
22 #include "audio/hardware_processor.h"
23 #include "audio/midi_event.h"
24 #include "audio/port.h"
25 #include "project.h"
26 #include "settings/settings.h"
27 #include "utils/arrays.h"
28 #include "utils/flags.h"
29 #include "utils/mem.h"
30 #include "utils/objects.h"
31 #include "utils/string.h"
32 #include "zrythm.h"
33 #include "zrythm_app.h"
34 
35 void
hardware_processor_init_loaded(HardwareProcessor * self,AudioEngine * engine)36 hardware_processor_init_loaded (
37   HardwareProcessor * self,
38   AudioEngine *       engine)
39 {
40   self->engine = engine;
41   self->ext_audio_ports_size =
42     (size_t) self->num_ext_audio_ports;
43   self->ext_midi_ports_size =
44     (size_t) self->num_ext_midi_ports;
45 }
46 
47 /**
48  * Returns a new empty instance.
49  */
50 HardwareProcessor *
hardware_processor_new(bool input,AudioEngine * engine)51 hardware_processor_new (
52   bool          input,
53   AudioEngine * engine)
54 {
55   HardwareProcessor * self =
56     object_new (HardwareProcessor);
57   self->schema_version =
58     HW_PROCESSOR_SCHEMA_VERSION;
59   self->engine = engine;
60   self->is_input = input;
61 
62   return self;
63 }
64 
65 /**
66  * Finds an ext port from its ID (type + full name).
67  *
68  * @see ext_port_get_id()
69  */
70 ExtPort *
hardware_processor_find_ext_port(HardwareProcessor * self,const char * id)71 hardware_processor_find_ext_port (
72   HardwareProcessor * self,
73   const char *        id)
74 {
75   g_return_val_if_fail (self && id, NULL);
76 
77   for (int i = 0; i < self->num_ext_audio_ports;
78        i++)
79     {
80       ExtPort * port = self->ext_audio_ports[i];
81       char * port_id = ext_port_get_id (port);
82       if (string_is_equal (port_id, id))
83         {
84           g_free (port_id);
85           return port;
86         }
87       g_free (port_id);
88     }
89   for (int i = 0; i < self->num_ext_midi_ports; i++)
90     {
91       ExtPort * port = self->ext_midi_ports[i];
92       char * port_id = ext_port_get_id (port);
93       if (string_is_equal (port_id, id))
94         {
95           g_free (port_id);
96           return port;
97         }
98       g_free (port_id);
99     }
100 
101   return NULL;
102 }
103 
104 /**
105  * Finds a port from its ID (type + full name).
106  *
107  * @see ext_port_get_id()
108  */
109 Port *
hardware_processor_find_port(HardwareProcessor * self,const char * id)110 hardware_processor_find_port (
111   HardwareProcessor * self,
112   const char *        id)
113 {
114   g_return_val_if_fail (self && id, NULL);
115 
116   for (int i = 0; i < self->num_ext_audio_ports;
117        i++)
118     {
119       ExtPort * ext_port = self->ext_audio_ports[i];
120       char * ext_port_id =
121         ext_port_get_id (ext_port);
122       Port * port = self->audio_ports[i];
123       if (!PROJECT || !PROJECT->loaded)
124         {
125           port->magic = PORT_MAGIC;
126         }
127       g_return_val_if_fail (
128         ext_port && IS_PORT (port), NULL);
129       if (string_is_equal (ext_port_id, id))
130         {
131           g_free (ext_port_id);
132           return port;
133         }
134       g_free (ext_port_id);
135     }
136   for (int i = 0; i < self->num_ext_midi_ports; i++)
137     {
138       ExtPort * ext_port = self->ext_midi_ports[i];
139       char * ext_port_id =
140         ext_port_get_id (ext_port);
141       Port * port = self->midi_ports[i];
142       if (!PROJECT || !PROJECT->loaded)
143         {
144           port->magic = PORT_MAGIC;
145         }
146       g_return_val_if_fail (
147         ext_port && IS_PORT (port), NULL);
148       if (string_is_equal (ext_port_id, id))
149         {
150           g_free (ext_port_id);
151           return port;
152         }
153       g_free (ext_port_id);
154     }
155 
156   return NULL;
157 }
158 
159 static Port *
create_port_for_ext_port(ExtPort * ext_port,PortType type,PortFlow flow)160 create_port_for_ext_port (
161   ExtPort * ext_port,
162   PortType  type,
163   PortFlow  flow)
164 {
165   Port * port =
166     port_new_with_type_and_owner (
167       type, flow, ext_port->full_name,
168       PORT_OWNER_TYPE_HW, ext_port);
169   port->id.flags |= PORT_FLAG_HW;
170   port->id.ext_port_id = ext_port_get_id (ext_port);
171 
172   return port;
173 }
174 
175 /**
176  * Rescans the hardware ports and appends any missing
177  * ones.
178  */
179 bool
hardware_processor_rescan_ext_ports(HardwareProcessor * self)180 hardware_processor_rescan_ext_ports (
181   HardwareProcessor * self)
182 {
183   g_debug ("rescanning ports...");
184 
185   /* get correct flow */
186   PortFlow flow =
187   /* these are reversed:
188    * input here -> port that outputs in backend */
189     self->is_input ? FLOW_OUTPUT : FLOW_INPUT;
190 
191   /* collect audio ports */
192   GPtrArray * ports = g_ptr_array_new ();
193   ext_ports_get (
194     TYPE_AUDIO, flow, true, ports);
195 
196   /* add missing ports to the list */
197   for (size_t i = 0; i < ports->len; i++)
198     {
199       ExtPort * ext_port =
200         g_ptr_array_index (ports, i);
201       ExtPort * existing_port =
202         hardware_processor_find_ext_port (
203           self, ext_port_get_id (ext_port));
204 
205       if (!existing_port)
206         {
207           array_double_size_if_full (
208             self->ext_audio_ports,
209             self->num_ext_audio_ports,
210             self->ext_audio_ports_size,
211             ExtPort *);
212           ext_port->hw_processor = self;
213           array_append (
214             self->ext_audio_ports,
215             self->num_ext_audio_ports, ext_port);
216           char * id = ext_port_get_id (ext_port);
217           g_message (
218             "[HW] Added audio port %s", id);
219           g_free (id);
220         }
221       else
222         {
223           ext_port_free (ext_port);
224         }
225     }
226   g_ptr_array_unref (ports);
227 
228   /* collect midi ports */
229   ports = g_ptr_array_new ();
230   ext_ports_get (TYPE_EVENT, flow, true, ports);
231 
232   /* add missing ports to the list */
233   for (size_t i = 0; i < ports->len; i++)
234     {
235       ExtPort * ext_port =
236         g_ptr_array_index (ports, i);
237       ExtPort * existing_port =
238         hardware_processor_find_ext_port (
239           self, ext_port_get_id (ext_port));
240 
241       if (!existing_port)
242         {
243           array_double_size_if_full (
244             self->ext_midi_ports,
245             self->num_ext_midi_ports,
246             self->ext_midi_ports_size,
247             ExtPort *);
248           ext_port->hw_processor = self;
249           array_append (
250             self->ext_midi_ports,
251             self->num_ext_midi_ports, ext_port);
252           char * id = ext_port_get_id (ext_port);
253           g_message (
254             "[HW] Added MIDI port %s", id);
255           g_free (id);
256         }
257       else
258         {
259           ext_port_free (ext_port);
260         }
261     }
262   g_ptr_array_unref (ports);
263 
264   /* create ports for each ext port */
265   self->audio_ports =
266     realloc (
267       self->audio_ports,
268       MAX (1, self->ext_audio_ports_size) *
269         sizeof (Port *));
270   self->midi_ports =
271     realloc (
272       self->midi_ports,
273       MAX (1, self->ext_midi_ports_size) *
274         sizeof (Port *));
275   for (int i = 0; i < self->num_ext_audio_ports; i++)
276     {
277       ExtPort * ext_port = self->ext_audio_ports[i];
278       g_return_val_if_fail (ext_port, G_SOURCE_REMOVE);
279       if (i >= self->num_audio_ports)
280         {
281           self->audio_ports[i] =
282             create_port_for_ext_port (
283               ext_port, TYPE_AUDIO, FLOW_OUTPUT);
284           self->num_audio_ports++;
285         }
286 
287       g_return_val_if_fail (
288         IS_PORT (self->audio_ports[i]),
289         G_SOURCE_REMOVE);
290     }
291   for (int i = 0; i < self->num_ext_midi_ports; i++)
292     {
293       ExtPort * ext_port = self->ext_midi_ports[i];
294       g_return_val_if_fail (ext_port, G_SOURCE_REMOVE);
295       if (i >= self->num_midi_ports)
296         {
297           self->midi_ports[i] =
298             create_port_for_ext_port (
299               ext_port, TYPE_EVENT, FLOW_OUTPUT);
300           self->num_midi_ports++;
301         }
302 
303       g_return_val_if_fail (
304         IS_PORT (self->midi_ports[i]),
305         G_SOURCE_REMOVE);
306     }
307 
308   /* TODO deactivate ports that weren't found
309    * (stop engine temporarily to remove) */
310 
311   g_debug (
312     "[%s] have %d audio and %d MIDI ports",
313     self->is_input ?
314       "HW processor inputs" :
315       "HW processor outputs",
316     self->num_ext_audio_ports,
317     self->num_ext_midi_ports);
318 
319   for (int i = 0; i < self->num_ext_audio_ports;
320        i++)
321     {
322       char * id =
323         ext_port_get_id (self->ext_audio_ports[i]);
324       g_debug (
325         "[%s] audio: %s",
326         self->is_input ?
327           "HW processor input" :
328           "HW processor output",
329         id);
330       g_free (id);
331     }
332   for (int i = 0; i < self->num_ext_midi_ports;
333        i++)
334     {
335       char * id =
336         ext_port_get_id (self->ext_midi_ports[i]);
337       g_debug (
338         "[%s] MIDI: %s",
339         self->is_input ?
340           "HW processor input" :
341           "HW processor output",
342         id);
343       g_free (id);
344     }
345 
346   return G_SOURCE_CONTINUE;
347 }
348 
349 /**
350  * Sets up the ports but does not start them.
351  *
352  * @return Non-zero on fail.
353  */
354 int
hardware_processor_setup(HardwareProcessor * self)355 hardware_processor_setup (
356   HardwareProcessor * self)
357 {
358   if (ZRYTHM_TESTING || ZRYTHM_GENERATING_PROJECT)
359     return 0;
360 
361   g_return_val_if_fail (
362     ZRYTHM_APP_IS_GTK_THREAD && S_P_GENERAL_ENGINE,
363     -1);
364 
365   if (self->is_input)
366     {
367       /* cache selections */
368       self->selected_midi_ports =
369         g_settings_get_strv (
370           S_P_GENERAL_ENGINE, "midi-controllers");
371       self->selected_audio_ports =
372         g_settings_get_strv (
373           S_P_GENERAL_ENGINE, "audio-inputs");
374 
375       /* get counts */
376       self->num_selected_midi_ports = 0;
377       self->num_selected_audio_ports = 0;
378       while ((self->selected_midi_ports[
379                 self->num_selected_midi_ports++]));
380       self->num_selected_midi_ports--;
381       while ((self->selected_audio_ports[
382                 self->num_selected_audio_ports++]));
383       self->num_selected_audio_ports--;
384     }
385 
386   /* ---- scan current ports ---- */
387 
388   hardware_processor_rescan_ext_ports (self);
389 
390   /* ---- end scan ---- */
391 
392   self->setup = true;
393 
394   return 0;
395 }
396 
397 /*void*/
398 /*hardware_processor_find_or_create_rtaudio_dev (*/
399   /*HardwareProcessor * self,*/
400 
401 /**
402  * Starts or stops the ports.
403  *
404  * @param activate True to activate, false to
405  *   deactivate
406  */
407 void
hardware_processor_activate(HardwareProcessor * self,bool activate)408 hardware_processor_activate (
409   HardwareProcessor * self,
410   bool                activate)
411 {
412   g_message ("hw processor activate: %d", activate);
413 
414   /* go through each selected port and activate/
415    * deactivate */
416   for (int i = 0; i < self->num_selected_midi_ports;
417        i++)
418     {
419       char * selected_port =
420         self->selected_midi_ports[i];
421       ExtPort * ext_port =
422         hardware_processor_find_ext_port (
423           self, selected_port);
424       Port * port =
425         hardware_processor_find_port (
426           self, selected_port);
427       if (port && ext_port)
428         {
429           ext_port_activate (
430             ext_port, port, activate);
431         }
432       else
433         {
434           g_message (
435             "could not find port %s", selected_port);
436         }
437     }
438   for (int i = 0; i < self->num_selected_audio_ports;
439        i++)
440     {
441       char * selected_port =
442         self->selected_audio_ports[i];
443       ExtPort * ext_port =
444         hardware_processor_find_ext_port (
445           self, selected_port);
446       Port * port =
447         hardware_processor_find_port (
448           self, selected_port);
449       if (port && ext_port)
450         {
451           ext_port_activate (
452             ext_port, port, activate);
453         }
454       else
455         {
456           g_message (
457             "could not find port %s", selected_port);
458         }
459     }
460 
461   if (activate && !self->rescan_timeout_id)
462     {
463       /* add timer to keep rescanning */
464       self->rescan_timeout_id =
465         g_timeout_add_seconds (
466           7,
467           (GSourceFunc)
468             hardware_processor_rescan_ext_ports,
469           self);
470     }
471   else if (!activate && self->rescan_timeout_id)
472     {
473       /* remove timeout */
474       g_source_remove (self->rescan_timeout_id);
475       self->rescan_timeout_id = 0;
476     }
477 
478   self->activated = activate;
479 }
480 
481 /**
482  * Processes the data.
483  */
484 void
hardware_processor_process(HardwareProcessor * self,nframes_t nframes)485 hardware_processor_process (
486   HardwareProcessor * self,
487   nframes_t           nframes)
488 {
489   /* go through each selected port and fetch data */
490   for (int i = 0; i < self->num_audio_ports; i++)
491     {
492       ExtPort * ext_port = self->ext_audio_ports[i];
493       if (!ext_port->active)
494         continue;
495 
496       Port * port = self->audio_ports[i];
497 
498       /* clear the buffer */
499       port_clear_buffer (port);
500 
501       switch (AUDIO_ENGINE->audio_backend)
502         {
503 #ifdef HAVE_JACK
504         case AUDIO_BACKEND_JACK:
505           port_receive_audio_data_from_jack (
506             port, 0, nframes);
507           break;
508 #endif
509 #ifdef HAVE_RTAUDIO
510         case AUDIO_BACKEND_ALSA_RTAUDIO:
511         case AUDIO_BACKEND_JACK_RTAUDIO:
512         case AUDIO_BACKEND_PULSEAUDIO_RTAUDIO:
513         case AUDIO_BACKEND_COREAUDIO_RTAUDIO:
514         case AUDIO_BACKEND_WASAPI_RTAUDIO:
515         case AUDIO_BACKEND_ASIO_RTAUDIO:
516           /* extract audio data from the RtAudio
517            * device ring buffer into RtAudio
518            * device temp buffer */
519           port_prepare_rtaudio_data (port);
520 
521           /* copy data from RtAudio temp buffer
522            * to normal buffer */
523           port_sum_data_from_rtaudio (
524             port, 0, nframes);
525           break;
526 #endif
527         default:
528           break;
529         }
530     }
531   for (int i = 0; i < self->num_midi_ports; i++)
532     {
533       ExtPort * ext_port = self->ext_midi_ports[i];
534       if (!ext_port->active)
535         continue;
536 
537       Port * port = self->midi_ports[i];
538 
539       /* clear the buffer */
540       midi_events_clear (
541         port->midi_events, F_NOT_QUEUED);
542 
543       switch (AUDIO_ENGINE->midi_backend)
544         {
545 #ifdef HAVE_JACK
546         case MIDI_BACKEND_JACK:
547           port_receive_midi_events_from_jack (
548             port, 0, nframes);
549           break;
550 #endif
551 #ifdef HAVE_RTMIDI
552         case MIDI_BACKEND_ALSA_RTMIDI:
553         case MIDI_BACKEND_JACK_RTMIDI:
554         case MIDI_BACKEND_WINDOWS_MME_RTMIDI:
555         case MIDI_BACKEND_COREMIDI_RTMIDI:
556           /* extract MIDI events from the RtMidi
557            * device ring buffer into RtMidi device */
558           port_prepare_rtmidi_events (port);
559 
560           /* copy data from RtMidi device events
561            * to normal events */
562           port_sum_data_from_rtmidi (
563             port, 0, nframes);
564           break;
565 #endif
566         default:
567           break;
568         }
569     }
570 }
571 
572 /**
573  * To be used during serialization.
574  */
575 HardwareProcessor *
hardware_processor_clone(const HardwareProcessor * src)576 hardware_processor_clone (
577   const HardwareProcessor * src)
578 {
579   HardwareProcessor * self =
580     object_new (HardwareProcessor);
581   self->schema_version =
582     HW_PROCESSOR_SCHEMA_VERSION;
583 
584   self->is_input = src->is_input;
585 
586   self->ext_audio_ports =
587     object_new_n (
588       (size_t) src->num_ext_audio_ports, ExtPort *);
589   for (int i = 0; i < src->num_ext_audio_ports; i++)
590     {
591       self->ext_audio_ports[i] =
592         ext_port_clone (src->ext_audio_ports[i]);
593     }
594   self->num_ext_audio_ports =
595     src->num_ext_audio_ports;
596 
597   self->ext_midi_ports =
598     object_new_n (
599       (size_t) src->num_ext_midi_ports, ExtPort *);
600   for (int i = 0; i < src->num_ext_midi_ports; i++)
601     {
602       self->ext_midi_ports[i] =
603         ext_port_clone (src->ext_midi_ports[i]);
604     }
605   self->num_ext_midi_ports =
606     src->num_ext_midi_ports;
607 
608   self->audio_ports =
609     object_new_n (
610       (size_t) src->num_audio_ports, Port *);
611   for (int i = 0; i < src->num_audio_ports; i++)
612     {
613       self->audio_ports[i] =
614         port_clone (src->audio_ports[i]);
615     }
616   self->num_audio_ports = src->num_audio_ports;
617 
618   self->midi_ports =
619     object_new_n (
620       (size_t) src->num_midi_ports, Port *);
621   for (int i = 0; i < src->num_midi_ports; i++)
622     {
623       self->midi_ports[i] =
624         port_clone (src->midi_ports[i]);
625     }
626   self->num_midi_ports = src->num_midi_ports;
627 
628   return self;
629 }
630 
631 void
hardware_processor_free(HardwareProcessor * self)632 hardware_processor_free (
633   HardwareProcessor * self)
634 {
635   for (int i = 0;
636        i < self->num_selected_midi_ports; i++)
637     {
638       g_free_and_null (
639         self->selected_midi_ports[i]);
640     }
641   object_zero_and_free_if_nonnull (
642     self->selected_midi_ports);
643 
644   for (int i = 0;
645        i < self->num_selected_audio_ports; i++)
646     {
647       g_free_and_null (
648         self->selected_audio_ports[i]);
649     }
650   object_zero_and_free_if_nonnull (
651     self->selected_audio_ports);
652 
653   for (int i = 0; i < self->num_ext_audio_ports;
654        i++)
655     {
656       object_free_w_func_and_null (
657         ext_port_free, self->ext_audio_ports[i]);
658     }
659   object_zero_and_free_if_nonnull (
660     self->ext_audio_ports);
661 
662   for (int i = 0; i < self->num_ext_midi_ports;
663        i++)
664     {
665       object_free_w_func_and_null (
666         ext_port_free, self->ext_midi_ports[i]);
667     }
668   object_zero_and_free_if_nonnull (
669     self->ext_midi_ports);
670 
671   for (int i = 0; i < self->num_audio_ports;
672        i++)
673     {
674       object_free_w_func_and_null (
675         port_free, self->audio_ports[i]);
676     }
677   object_zero_and_free_if_nonnull (
678     self->audio_ports);
679 
680   for (int i = 0; i < self->num_midi_ports;
681        i++)
682     {
683       object_free_w_func_and_null (
684         port_free, self->midi_ports[i]);
685     }
686   object_zero_and_free_if_nonnull (
687     self->midi_ports);
688 
689   object_zero_and_free (self);
690 }
691