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