1 // ----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2008-2019 Fons Adriaensen <fons@linuxaudio.org>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // ----------------------------------------------------------------------------
19
20
21 #include <math.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include "jmatrix.h"
25
26
Jmatrix(const char * client_name,const char * server_name,int ninp,int nout,float maxdel)27 Jmatrix::Jmatrix (const char *client_name, const char *server_name,
28 int ninp, int nout, float maxdel) :
29 _ginp (0),
30 _gout (0),
31 _gmatr (0),
32 _gcurr (0),
33 _dinp (0),
34 _dout (0),
35 _dmatr (0),
36 _dcurr (0),
37 _dproc (0)
38 {
39 if (ninp > MAXINP) ninp = MAXINP;
40 else if (ninp < 0) ninp = 0;
41 if (nout > MAXOUT) nout = MAXOUT;
42 else if (nout < 0) nout = 0;
43 if (maxdel < 0.0f) maxdel = 0.0f;
44 if (maxdel > 3.0f) maxdel = 3.0f;
45 if ( open_jack (client_name, server_name, ninp, nout)
46 || create_inp_ports ("in_%d")
47 || create_out_ports ("out_%d"))
48 {
49 _state = FAILED;
50 return;
51 }
52 init (maxdel);
53 }
54
55
~Jmatrix(void)56 Jmatrix::~Jmatrix (void)
57 {
58 fini ();
59 }
60
61
init(float maxdel)62 void Jmatrix::init (float maxdel)
63 {
64 int i;
65
66 _ginp = new float [_ninp];
67 _gout = new float [_nout];
68 _gmatr = new float [_ninp * _nout];
69 _gcurr = new float [_ninp * _nout];
70 for (i = 0; i < _ninp; i++) _ginp [i] = 1.0f;
71 for (i = 0; i < _nout; i++) _gout [i] = 1.0f;
72 memset (_gmatr, 0, _ninp * _nout * sizeof (float));
73 memset (_gcurr, 0, _ninp * _nout * sizeof (float));
74
75 _maxdel = (int)(maxdel * jack_rate () + 0.5f);
76 if (_maxdel)
77 {
78 _dinp = new int32_t [_ninp];
79 _dout = new int32_t [_nout];
80 _dmatr = new int32_t [_ninp * _nout];
81 _dcurr = new int32_t [_ninp * _nout];
82 _dproc = new Delay [_ninp];
83 memset (_dinp, 0, _ninp * sizeof (int32_t));
84 memset (_dout, 0, _nout * sizeof (int32_t));
85 memset (_dmatr, 0, _ninp * _nout * sizeof (int32_t));
86 memset (_dcurr, 0, _ninp * _nout * sizeof (int32_t));
87 for (i = 0; i < _ninp; i++) _dproc [i].init (_maxdel, jack_size ());
88 }
89
90 _state = PROCESS;
91 }
92
93
fini(void)94 void Jmatrix::fini (void)
95 {
96 _state = INITIAL;
97 close_jack ();
98 delete[] _ginp;
99 delete[] _gout;
100 delete[] _gmatr;
101 delete[] _gcurr;
102 delete[] _dinp;
103 delete[] _dout;
104 delete[] _dmatr;
105 delete[] _dcurr;
106 delete[] _dproc;
107 }
108
109
set_gain(int inp,int out,float gain)110 void Jmatrix::set_gain (int inp, int out, float gain)
111 {
112 if (inp >= _ninp) return;
113 if (out >= _nout) return;
114 if (inp < 0)
115 {
116 if (out >= 0) _gout [out] = gain;
117 return;
118 }
119 if (out < 0)
120 {
121 if (inp >= 0) _ginp [inp] = gain;
122 return;
123 }
124 _gmatr [_ninp * out + inp] = gain;
125 }
126
127
set_delay(int inp,int out,float delay)128 void Jmatrix::set_delay (int inp, int out, float delay)
129 {
130 int32_t d;
131
132 if (inp >= _ninp) return;
133 if (out >= _nout) return;
134 d = (int)(delay * jack_rate () + 0.5f);
135 if (inp < 0)
136 {
137 if (out >= 0) _dout [out] = d;
138 return;
139 }
140 if (out < 0)
141 {
142 if (inp >= 0) _dinp [inp] = d;
143 return;
144 }
145 _dmatr [_ninp * out + inp] = d;
146 }
147
148
jack_process(int nframes)149 int Jmatrix::jack_process (int nframes)
150 {
151 const float *p, *inp [MAXINP];
152 float *out;
153 float g0, g1, g, s;
154 int d0, d1;
155 int i, j, k, m;
156
157 if (_state < PROCESS) return 0;
158
159 for (i = 0; i < _ninp; i++)
160 {
161 p = (float *) jack_port_get_buffer (_inp_ports [i], nframes);
162 if (_maxdel) _dproc [i].write (p);
163 else inp [i] = p;
164 }
165
166 for (j = m = 0; j < _nout; j++, m += _ninp)
167 {
168 out = (float *) jack_port_get_buffer (_out_ports [j], nframes);
169 memset (out, 0, nframes * sizeof (float));
170 for (i = 0; i < _ninp; i++)
171 {
172 g0 = _gcurr [m + i];
173 g1 = _gmatr [m + i] * _ginp [i] * _gout [j];
174 _gcurr [m + i] = g1;
175 if (_maxdel)
176 {
177 d0 = _dcurr [m + i];
178 d1 = _dmatr [m + i] + _dinp [i] + _dout [j];;
179 if (d1 < 0) d1 = 0;
180 if (d1 > _maxdel) d1 = _maxdel;
181 _dcurr [m + i] = d1;
182 }
183 if (_maxdel && (d1 != d0))
184 {
185 p = _dproc [i].readp (d0);
186 g = g0;
187 s = g0 / nframes;
188 for (k = 0; k < nframes; k++)
189 {
190 g -= s;
191 out [k] += g * p [k];
192 }
193 p = _dproc [i].readp (d1);
194 g = 0.0f;
195 s = g1 / nframes;
196 for (k = 0; k < nframes; k++)
197 {
198 g += s;
199 out [k] += g * p [k];
200 }
201 }
202 else
203 {
204 p = _maxdel ? _dproc [i].readp (d0) : inp [i];
205 s = g1 - g0;
206 if (fabsf (s) < 1e-3f * (fabsf (g0) + fabsf (g1)))
207 {
208 if (fabsf (g1) >= 1e-15f)
209 {
210 for (k = 0; k < nframes; k++)
211 {
212 out [k] += g1 * p [k];
213 }
214 }
215 }
216 else
217 {
218 g = g0;
219 s /= nframes;
220 for (k = 0; k < nframes; k++)
221 {
222 g += s;
223 out [k] += g * p [k];
224 }
225 }
226 }
227 }
228 }
229
230 return 0;
231 }
232
233