1 /*
2 metro.c:
3
4 Copyright (C) 2000 Gabriel Maldonado, (C) 2019 Gleb Rogozinsky
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include "stdopcod.h"
25 #include <math.h>
26
27 typedef struct {
28 OPDS h;
29 MYFLT *sr, *xcps, *iphs;
30 double curphs;
31 int32_t flag;
32 } METRO;
33
34 // METRO2 ADDED BY GLEB ROGOZINSKY Oct 2019
35 typedef struct {
36 OPDS h;
37 MYFLT *sr, *xcps, *kswng, *iamp, *iphs;
38 double amp2, curphs, curphs2, swng_init;
39 int32_t flag, flag2;
40 } METRO2;
41 //
42
43 typedef struct {
44 OPDS h;
45 MYFLT *trig, *ndx, *maxtics, *ifn, *outargs[VARGMAX];
46 int32_t numouts, currtic, old_ndx;
47 MYFLT *table;
48 } SPLIT_TRIG;
49
50 typedef struct {
51 OPDS h;
52 MYFLT *ktrig, *kphs, *ifn, *args[VARGMAX];
53 MYFLT endSeq, *table, oldPhs;
54 int32_t numParm, endIndex, prevIndex, nextIndex ;
55 MYFLT prevActime, nextActime;
56 int32_t initFlag;
57
58 } TIMEDSEQ;
59
metro_set(CSOUND * csound,METRO * p)60 static int32_t metro_set(CSOUND *csound, METRO *p)
61 {
62 double phs = *p->iphs;
63 int32 longphs;
64
65 if (phs >= 0.0) {
66 if (UNLIKELY((longphs = (int32)phs)))
67 csound->Warning(csound, Str("metro:init phase truncation"));
68 p->curphs = (MYFLT)phs - (MYFLT)longphs;
69 }
70 p->flag=1;
71 return OK;
72 }
73
metro(CSOUND * csound,METRO * p)74 static int32_t metro(CSOUND *csound, METRO *p)
75 {
76 double phs= p->curphs;
77 IGN(csound);
78 if (phs == 0.0 && p->flag) {
79 *p->sr = FL(1.0);
80 p->flag = 0;
81 }
82 else if ((phs += *p->xcps * CS_ONEDKR) >= 1.0) {
83 *p->sr = FL(1.0);
84 phs -= 1.0;
85 p->flag = 0;
86 }
87 else
88 *p->sr = FL(0.0);
89 p->curphs = phs;
90 return OK;
91 }
92
93 /* GLEB ROGOZINSKY Oct 2019
94 Opcode metro2 in addition to 'classic' metro opcode,
95 allows swinging with possibiliy of setting its own amplitude value
96 */
metro2_set(CSOUND * csound,METRO2 * p)97 static int32_t metro2_set(CSOUND *csound, METRO2 *p)
98 {
99 double phs = *p->iphs;
100 double swng = *p->kswng;
101 int32 longphs;
102 p->amp2 = *p->iamp;
103
104 if (phs >= 0.0) {
105 if (UNLIKELY((longphs = (int32)phs)))
106 csound->Warning(csound, Str("metro2:init phase truncation"));
107 p->curphs = (MYFLT)phs - (MYFLT)longphs;
108 p->curphs2 = (MYFLT)phs - (MYFLT)longphs + 1.0 - (MYFLT)swng;
109 }
110 p->flag = 1;
111 p->flag2 = 1;
112 p->swng_init = (MYFLT)swng;
113 return OK;
114 }
115
metro2(CSOUND * csound,METRO2 * p)116 static int32_t metro2(CSOUND *csound, METRO2 *p)
117 {
118 double phs= p->curphs;
119 double phs2= p->curphs2;
120 double phs2_init = p->swng_init;
121 double amp2= p->amp2;
122 double swng= *p->kswng;
123 IGN(csound);
124 // MAIN TICK
125 if (phs == 0.0 && p->flag) {
126 *p->sr = FL(1.0);
127 p->flag = 0;
128 }
129 else if ((phs += *p->xcps * CS_ONEDKR * 0.5) >= 1.0 ) {
130 *p->sr = FL(1.0);
131 phs -= 1.0;
132 p->flag = 0;
133 }
134 else
135 *p->sr = FL(0.0);
136 p->curphs = phs;
137
138 // SWINGING TICK
139 if (phs2 == 0.0 && p->flag2) {
140 *p->sr = FL(amp2);
141 p->flag2 = 0;
142 }
143 else if ((phs2 += *p->xcps * CS_ONEDKR * 0.5) >= (1.0 + swng - phs2_init) ) {
144 *p->sr = FL(amp2);
145 phs2 -= 1.0;
146 p->flag2 = 0;
147 }
148 p->curphs2 = phs2;
149
150 return OK;
151 }
152 //
153
split_trig_set(CSOUND * csound,SPLIT_TRIG * p)154 static int32_t split_trig_set(CSOUND *csound, SPLIT_TRIG *p)
155 {
156
157 /* syntax of each table element:
158 numtics_elem1,
159 tic1_out1, tic1_out2, ... , tic1_outN,
160 tic2_out1, tic2_out2, ... , tic2_outN,
161 tic3_out1, tic3_out2, ... , tic3_outN,
162 .....
163 ticN_out1, ticN_out2, ... , ticN_outN,
164
165 numtics_elem2,
166 tic1_out1, tic1_out2, ... , tic1_outN,
167 tic2_out1, tic2_out2, ... , tic2_outN,
168 tic3_out1, tic3_out2, ... , tic3_outN,
169 .....
170 ticN_out1, ticN_out2, ... , ticN_outN,
171
172 */
173
174 FUNC *ftp;
175 if (UNLIKELY((ftp = csound->FTnp2Find(csound, p->ifn)) == NULL)) {
176 return csound->InitError(csound, Str("splitrig: incorrect table number"));
177 }
178 p->table = ftp->ftable;
179 p->numouts = p->INOCOUNT-4;
180 p->currtic = 0;
181 return OK;
182 }
183
split_trig(CSOUND * csound,SPLIT_TRIG * p)184 static int32_t split_trig(CSOUND *csound, SPLIT_TRIG *p)
185 {
186 IGN(csound);
187 int32_t j;
188 int32_t numouts = p->numouts;
189 MYFLT **outargs = p->outargs;
190
191 if (*p->trig) {
192 int32_t ndx = (int32_t) *p->ndx * (numouts * (int32_t) *p->maxtics + 1);
193 int32_t numtics = (int32_t) p->table[ndx];
194 MYFLT *table = &(p->table[ndx+1]);
195 int32_t kndx = (int32_t) *p->ndx;
196 int32_t currtic;
197
198 if (kndx != p->old_ndx) {
199 p->currtic = 0;
200 p->old_ndx = kndx;
201 }
202 currtic = p->currtic;
203
204 for (j = 0; j < numouts; j++)
205 *outargs[j] = table[j + currtic * numouts ];
206
207 p->currtic = (currtic +1) % numtics;
208
209 }
210
211 else { // Maybe a memset?
212 for(j =0; j< numouts; j++)
213 *outargs[j] = FL(0.0);
214 }
215 return OK;
216 }
217
timeseq_set(CSOUND * csound,TIMEDSEQ * p)218 static int32_t timeseq_set(CSOUND *csound, TIMEDSEQ *p)
219 {
220 FUNC *ftp;
221 MYFLT *table;
222 uint32_t j;
223 if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn)) == NULL)) return NOTOK;
224 table = p->table = ftp->ftable;
225 p->numParm = p->INOCOUNT-2; /* ? */
226 for (j = 0; j < ftp->flen; j+= p->numParm) {
227 if (table[j] < 0) {
228 p->endSeq = table[j+1];
229 p->endIndex = j/p->numParm;
230 break;
231 }
232 }
233 p->initFlag = 1;
234 return OK;
235 }
236
timeseq(CSOUND * csound,TIMEDSEQ * p)237 static int32_t timeseq(CSOUND *csound, TIMEDSEQ *p)
238 {
239 IGN(csound);
240 MYFLT *table = p->table, minDist = CS_ONEDKR;
241 MYFLT phs = *p->kphs, endseq = p->endSeq;
242 int32_t j,k, numParm = p->numParm, endIndex = p->endIndex;
243 while (phs > endseq)
244 phs -=endseq;
245 while (phs < 0 )
246 phs +=endseq;
247
248 if (p->initFlag) {
249 prev:
250 for (j=0,k=endIndex; j < endIndex; j++, k--) {
251 if (table[j*numParm + 1] > phs ) {
252 p->nextActime = table[j*numParm + 1];
253 p->nextIndex = j;
254 p->prevActime = table[(j-1)*numParm + 1];
255 p->prevIndex = j-1;
256 break;
257 }
258 if (table[k*numParm + 1] < phs ) {
259 p->nextActime = table[(k+1)*numParm + 1];
260 p->nextIndex = k+1;
261 p->prevActime = table[k*numParm + 1];
262 p->prevIndex = k;
263 break;
264 }
265 }
266 if (phs == p->prevActime&& p->prevIndex != -1 ) {
267 *p->ktrig = 1;
268 for (j=0; j < numParm; j++) {
269 *p->args[j]=table[p->prevIndex*numParm + j];
270 }
271 }
272 else if (phs == p->nextActime && p->nextIndex != -1 ) {
273 *p->ktrig = 1;
274 for (j=0; j < numParm; j++) {
275 *p->args[j]=table[p->nextIndex*numParm + j];
276 }
277 }
278 /*p->oldPhs = phs; */
279 p->initFlag=0;
280 }
281 else {
282 if (phs > p->nextActime || phs < p->prevActime) {
283 for (j=0; j < numParm; j++) {
284 *p->args[j]=table[p->nextIndex*numParm + j];
285 }
286 if (table[p->nextIndex*numParm] != -1) /* if it is not end locator */
287 /**p->ktrig = 1; */
288 *p->ktrig = table[p->nextIndex*numParm + 3];
289 if (phs > p->nextActime) {
290 if (p->prevIndex > p->nextIndex && p->oldPhs < phs) {
291 /* there is a phase jump */
292 *p->ktrig = 0;
293 goto fine;
294 }
295 if (fabs(phs-p->nextActime) > minDist)
296 goto prev;
297
298 p->prevActime = table[p->nextIndex*numParm + 1];
299 p->prevIndex = p->nextIndex;
300 p->nextIndex = (p->nextIndex + 1) % endIndex;
301 p->nextActime = table[p->nextIndex*numParm + 1];
302 }
303 else {
304 if (fabs(phs-p->nextActime) > minDist)
305 goto prev;
306
307 p->nextActime = table[p->prevIndex*numParm + 1]; /*p->nextActime+1; */
308 p->nextIndex = p->prevIndex;
309 p->prevIndex = (p->prevIndex - 1);
310 if (p->prevIndex < 0) {
311 p->prevIndex += p->endIndex;
312 }
313 p->prevActime = table[p->prevIndex*numParm + 1]; /*p->nextActime+1; */
314 }
315 }
316 else
317 *p->ktrig = 0;
318 fine:
319 p->oldPhs = phs;
320 }
321 return OK;
322 }
323
324 #define S(x) sizeof(x)
325
326 static OENTRY localops[] = {
327 { "metro", S(METRO), 0, 3, "k", "ko", (SUBR)metro_set, (SUBR)metro },
328 { "metro2", S(METRO2), 0, 3, "k", "kkpo", (SUBR)metro2_set, (SUBR)metro2 },
329 { "splitrig", S(SPLIT_TRIG), 0, 3, "", "kkiiz",
330 (SUBR)split_trig_set, (SUBR)split_trig },
331 { "timedseq",S(TIMEDSEQ), TR, 3, "k", "kiz", (SUBR)timeseq_set, (SUBR)timeseq }
332 };
333
metro_init_(CSOUND * csound)334 int32_t metro_init_(CSOUND *csound)
335 {
336 return csound->AppendOpcodes(csound, &(localops[0]),
337 (int32_t
338 ) (sizeof(localops) / sizeof(OENTRY)));
339 }
340