/* metro.c: Copyright (C) 2000 Gabriel Maldonado, (C) 2019 Gleb Rogozinsky This file is part of Csound. The Csound Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Csound is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Csound; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "stdopcod.h" #include typedef struct { OPDS h; MYFLT *sr, *xcps, *iphs; double curphs; int32_t flag; } METRO; // METRO2 ADDED BY GLEB ROGOZINSKY Oct 2019 typedef struct { OPDS h; MYFLT *sr, *xcps, *kswng, *iamp, *iphs; double amp2, curphs, curphs2, swng_init; int32_t flag, flag2; } METRO2; // typedef struct { OPDS h; MYFLT *trig, *ndx, *maxtics, *ifn, *outargs[VARGMAX]; int32_t numouts, currtic, old_ndx; MYFLT *table; } SPLIT_TRIG; typedef struct { OPDS h; MYFLT *ktrig, *kphs, *ifn, *args[VARGMAX]; MYFLT endSeq, *table, oldPhs; int32_t numParm, endIndex, prevIndex, nextIndex ; MYFLT prevActime, nextActime; int32_t initFlag; } TIMEDSEQ; static int32_t metro_set(CSOUND *csound, METRO *p) { double phs = *p->iphs; int32 longphs; if (phs >= 0.0) { if (UNLIKELY((longphs = (int32)phs))) csound->Warning(csound, Str("metro:init phase truncation")); p->curphs = (MYFLT)phs - (MYFLT)longphs; } p->flag=1; return OK; } static int32_t metro(CSOUND *csound, METRO *p) { double phs= p->curphs; IGN(csound); if (phs == 0.0 && p->flag) { *p->sr = FL(1.0); p->flag = 0; } else if ((phs += *p->xcps * CS_ONEDKR) >= 1.0) { *p->sr = FL(1.0); phs -= 1.0; p->flag = 0; } else *p->sr = FL(0.0); p->curphs = phs; return OK; } /* GLEB ROGOZINSKY Oct 2019 Opcode metro2 in addition to 'classic' metro opcode, allows swinging with possibiliy of setting its own amplitude value */ static int32_t metro2_set(CSOUND *csound, METRO2 *p) { double phs = *p->iphs; double swng = *p->kswng; int32 longphs; p->amp2 = *p->iamp; if (phs >= 0.0) { if (UNLIKELY((longphs = (int32)phs))) csound->Warning(csound, Str("metro2:init phase truncation")); p->curphs = (MYFLT)phs - (MYFLT)longphs; p->curphs2 = (MYFLT)phs - (MYFLT)longphs + 1.0 - (MYFLT)swng; } p->flag = 1; p->flag2 = 1; p->swng_init = (MYFLT)swng; return OK; } static int32_t metro2(CSOUND *csound, METRO2 *p) { double phs= p->curphs; double phs2= p->curphs2; double phs2_init = p->swng_init; double amp2= p->amp2; double swng= *p->kswng; IGN(csound); // MAIN TICK if (phs == 0.0 && p->flag) { *p->sr = FL(1.0); p->flag = 0; } else if ((phs += *p->xcps * CS_ONEDKR * 0.5) >= 1.0 ) { *p->sr = FL(1.0); phs -= 1.0; p->flag = 0; } else *p->sr = FL(0.0); p->curphs = phs; // SWINGING TICK if (phs2 == 0.0 && p->flag2) { *p->sr = FL(amp2); p->flag2 = 0; } else if ((phs2 += *p->xcps * CS_ONEDKR * 0.5) >= (1.0 + swng - phs2_init) ) { *p->sr = FL(amp2); phs2 -= 1.0; p->flag2 = 0; } p->curphs2 = phs2; return OK; } // static int32_t split_trig_set(CSOUND *csound, SPLIT_TRIG *p) { /* syntax of each table element: numtics_elem1, tic1_out1, tic1_out2, ... , tic1_outN, tic2_out1, tic2_out2, ... , tic2_outN, tic3_out1, tic3_out2, ... , tic3_outN, ..... ticN_out1, ticN_out2, ... , ticN_outN, numtics_elem2, tic1_out1, tic1_out2, ... , tic1_outN, tic2_out1, tic2_out2, ... , tic2_outN, tic3_out1, tic3_out2, ... , tic3_outN, ..... ticN_out1, ticN_out2, ... , ticN_outN, */ FUNC *ftp; if (UNLIKELY((ftp = csound->FTnp2Find(csound, p->ifn)) == NULL)) { return csound->InitError(csound, Str("splitrig: incorrect table number")); } p->table = ftp->ftable; p->numouts = p->INOCOUNT-4; p->currtic = 0; return OK; } static int32_t split_trig(CSOUND *csound, SPLIT_TRIG *p) { IGN(csound); int32_t j; int32_t numouts = p->numouts; MYFLT **outargs = p->outargs; if (*p->trig) { int32_t ndx = (int32_t) *p->ndx * (numouts * (int32_t) *p->maxtics + 1); int32_t numtics = (int32_t) p->table[ndx]; MYFLT *table = &(p->table[ndx+1]); int32_t kndx = (int32_t) *p->ndx; int32_t currtic; if (kndx != p->old_ndx) { p->currtic = 0; p->old_ndx = kndx; } currtic = p->currtic; for (j = 0; j < numouts; j++) *outargs[j] = table[j + currtic * numouts ]; p->currtic = (currtic +1) % numtics; } else { // Maybe a memset? for(j =0; j< numouts; j++) *outargs[j] = FL(0.0); } return OK; } static int32_t timeseq_set(CSOUND *csound, TIMEDSEQ *p) { FUNC *ftp; MYFLT *table; uint32_t j; if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn)) == NULL)) return NOTOK; table = p->table = ftp->ftable; p->numParm = p->INOCOUNT-2; /* ? */ for (j = 0; j < ftp->flen; j+= p->numParm) { if (table[j] < 0) { p->endSeq = table[j+1]; p->endIndex = j/p->numParm; break; } } p->initFlag = 1; return OK; } static int32_t timeseq(CSOUND *csound, TIMEDSEQ *p) { IGN(csound); MYFLT *table = p->table, minDist = CS_ONEDKR; MYFLT phs = *p->kphs, endseq = p->endSeq; int32_t j,k, numParm = p->numParm, endIndex = p->endIndex; while (phs > endseq) phs -=endseq; while (phs < 0 ) phs +=endseq; if (p->initFlag) { prev: for (j=0,k=endIndex; j < endIndex; j++, k--) { if (table[j*numParm + 1] > phs ) { p->nextActime = table[j*numParm + 1]; p->nextIndex = j; p->prevActime = table[(j-1)*numParm + 1]; p->prevIndex = j-1; break; } if (table[k*numParm + 1] < phs ) { p->nextActime = table[(k+1)*numParm + 1]; p->nextIndex = k+1; p->prevActime = table[k*numParm + 1]; p->prevIndex = k; break; } } if (phs == p->prevActime&& p->prevIndex != -1 ) { *p->ktrig = 1; for (j=0; j < numParm; j++) { *p->args[j]=table[p->prevIndex*numParm + j]; } } else if (phs == p->nextActime && p->nextIndex != -1 ) { *p->ktrig = 1; for (j=0; j < numParm; j++) { *p->args[j]=table[p->nextIndex*numParm + j]; } } /*p->oldPhs = phs; */ p->initFlag=0; } else { if (phs > p->nextActime || phs < p->prevActime) { for (j=0; j < numParm; j++) { *p->args[j]=table[p->nextIndex*numParm + j]; } if (table[p->nextIndex*numParm] != -1) /* if it is not end locator */ /**p->ktrig = 1; */ *p->ktrig = table[p->nextIndex*numParm + 3]; if (phs > p->nextActime) { if (p->prevIndex > p->nextIndex && p->oldPhs < phs) { /* there is a phase jump */ *p->ktrig = 0; goto fine; } if (fabs(phs-p->nextActime) > minDist) goto prev; p->prevActime = table[p->nextIndex*numParm + 1]; p->prevIndex = p->nextIndex; p->nextIndex = (p->nextIndex + 1) % endIndex; p->nextActime = table[p->nextIndex*numParm + 1]; } else { if (fabs(phs-p->nextActime) > minDist) goto prev; p->nextActime = table[p->prevIndex*numParm + 1]; /*p->nextActime+1; */ p->nextIndex = p->prevIndex; p->prevIndex = (p->prevIndex - 1); if (p->prevIndex < 0) { p->prevIndex += p->endIndex; } p->prevActime = table[p->prevIndex*numParm + 1]; /*p->nextActime+1; */ } } else *p->ktrig = 0; fine: p->oldPhs = phs; } return OK; } #define S(x) sizeof(x) static OENTRY localops[] = { { "metro", S(METRO), 0, 3, "k", "ko", (SUBR)metro_set, (SUBR)metro }, { "metro2", S(METRO2), 0, 3, "k", "kkpo", (SUBR)metro2_set, (SUBR)metro2 }, { "splitrig", S(SPLIT_TRIG), 0, 3, "", "kkiiz", (SUBR)split_trig_set, (SUBR)split_trig }, { "timedseq",S(TIMEDSEQ), TR, 3, "k", "kiz", (SUBR)timeseq_set, (SUBR)timeseq } }; int32_t metro_init_(CSOUND *csound) { return csound->AppendOpcodes(csound, &(localops[0]), (int32_t ) (sizeof(localops) / sizeof(OENTRY))); }