1 /*
2  * Copyright (C) 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/modulator_macro_processor.h"
21 #include "audio/port.h"
22 #include "utils/dsp.h"
23 #include "utils/debug.h"
24 #include "utils/objects.h"
25 
26 #include <glib/gi18n.h>
27 
28 void
modulator_macro_processor_init_loaded(ModulatorMacroProcessor * self,Track * track)29 modulator_macro_processor_init_loaded (
30   ModulatorMacroProcessor * self,
31   Track *                   track)
32 {
33   self->track = track;
34 
35   port_init_loaded (self->macro, self);
36   port_init_loaded (self->cv_in, self);
37   port_init_loaded (self->cv_out, self);
38 }
39 
40 Track *
modulator_macro_processor_get_track(ModulatorMacroProcessor * self)41 modulator_macro_processor_get_track (
42   ModulatorMacroProcessor * self)
43 {
44   return port_get_track (self->cv_in, true);
45 }
46 
47 void
modulator_macro_processor_set_name(ModulatorMacroProcessor * self,const char * name)48 modulator_macro_processor_set_name (
49   ModulatorMacroProcessor * self,
50   const char *              name)
51 {
52   self->name = g_strdup (name);
53 }
54 
55 /**
56  * Process.
57  *
58  * @param g_start_frames Global frames.
59  * @param start_frame The local offset in this
60  *   cycle.
61  * @param nframes The number of frames to process.
62  */
63 void
modulator_macro_processor_process(ModulatorMacroProcessor * self,long g_start_frames,nframes_t start_frame,const nframes_t nframes)64 modulator_macro_processor_process (
65   ModulatorMacroProcessor * self,
66   long                      g_start_frames,
67   nframes_t                 start_frame,
68   const nframes_t           nframes)
69 {
70   z_return_if_fail_cmp (
71     start_frame + nframes, <=,
72     self->cv_out->last_buf_sz);
73 
74   /* if there are inputs, multiply by the knov
75    * value */
76   if (self->cv_in->num_srcs > 0)
77     {
78       dsp_mix2 (
79         &self->cv_out->buf[start_frame],
80         &self->cv_in->buf[start_frame],
81         0.f, self->macro->control, nframes);
82     }
83   /* else if there are no inputs, set the knob value
84    * as the output */
85   else
86     {
87       Port * cv_out = self->cv_out;
88       g_return_if_fail (IS_PORT (cv_out));
89       dsp_fill (
90         &cv_out->buf[start_frame],
91         self->macro->control *
92           (cv_out->maxf - cv_out->minf) +
93           cv_out->minf,
94         nframes);
95     }
96 }
97 
98 ModulatorMacroProcessor *
modulator_macro_processor_new(Track * track,int idx)99 modulator_macro_processor_new (
100   Track * track,
101   int     idx)
102 {
103   ModulatorMacroProcessor * self =
104     object_new (ModulatorMacroProcessor);
105   self->schema_version =
106     MODULATOR_MACRO_PROCESSOR_SCHEMA_VERSION;
107   self->track = track;
108 
109   char str[600];
110   sprintf (str, _("Macro %d"), idx + 1);
111   self->name = g_strdup (str);
112   self->macro =
113     port_new_with_type_and_owner (
114       TYPE_CONTROL, FLOW_INPUT, str,
115       PORT_OWNER_TYPE_MODULATOR_MACRO_PROCESSOR,
116       self);
117   Port * port = self->macro;
118   port->minf = 0.f;
119   port->maxf = 1.f;
120   port->deff = 0.f;
121   port_set_control_value (
122     port, 0.75f, false, false);
123   port->id.flags |=
124     PORT_FLAG_AUTOMATABLE;
125   port->id.flags |=
126     PORT_FLAG_MODULATOR_MACRO;
127   port->id.port_index = idx;
128 
129   sprintf (str, _("Macro CV In %d"), idx + 1);
130   self->cv_in =
131     port_new_with_type_and_owner (
132       TYPE_CV, FLOW_INPUT, str,
133       PORT_OWNER_TYPE_MODULATOR_MACRO_PROCESSOR,
134       self);
135   port = self->cv_in;
136   port->id.flags |=
137     PORT_FLAG_MODULATOR_MACRO;
138   port->id.port_index = idx;
139 
140   sprintf (str, _("Macro CV Out %d"), idx + 1);
141   self->cv_out =
142     port_new_with_type_and_owner (
143       TYPE_CV, FLOW_OUTPUT, str,
144       PORT_OWNER_TYPE_MODULATOR_MACRO_PROCESSOR,
145       self);
146   port = self->cv_out;
147   port->id.flags |=
148     PORT_FLAG_MODULATOR_MACRO;
149   port->id.port_index = idx;
150 
151   return self;
152 }
153 
154 void
modulator_macro_processor_free(ModulatorMacroProcessor * self)155 modulator_macro_processor_free (
156   ModulatorMacroProcessor * self)
157 {
158   object_free_w_func_and_null (
159     port_free, self->macro);
160   object_free_w_func_and_null (
161     port_free, self->cv_in);
162   object_free_w_func_and_null (
163     port_free, self->cv_out);
164 
165   object_zero_and_free (self);
166 }
167