1 /*
2   midiops.c:
3 
4   Copyright (C) 1995 Barry Vercoe, Gabriel Maldonado,
5   Istvan Varga, John ffitch
6 
7   This file is part of Csound.
8 
9   The Csound Library is free software; you can redistribute it
10   and/or modify it under the terms of the GNU Lesser General Public
11   License as published by the Free Software Foundation; either
12   version 2.1 of the License, or (at your option) any later version.
13 
14   Csound is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU Lesser General Public License for more details.
18 
19   You should have received a copy of the GNU Lesser General Public
20   License along with Csound; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   02110-1301 USA
23 */
24 
25 #include "csoundCore.h"                                 /*      MIDIOPS.C   */
26 #include "midiops.h"
27 #include <math.h>
28 #include <time.h>
29 #include "namedins.h"           /* IV - Oct 31 2002 */
30 
31 #define dv127   (FL(1.0)/FL(127.0))
32 
33 extern int32_t m_chinsno(CSOUND *csound, int32_t chan,
34                          int32_t insno, int32_t reset_ctls);
35 
36 #define MIDI_VALUE(m,field) ((m != (MCHNBLK *) NULL) ? m->field : FL(0.0))
37 
38 /*
39  * m (=m_chnbp) can easily be NULL (the only place it gets set, as
40  * of 3.484, is in MIDIinsert) so we should check for validity
41  *                                  [added by nicb@axnet.it]
42  */
43 
44 /* This line has reverted to checking the null pointer as the code in oload
45  * does leaves it null if there is no chanel.  The correct fix is to fix that
46  * code so the test is not dynamic, but until I understand it.... */
47 #define pitchbend_value(m) MIDI_VALUE(m,pchbend)
48 
49 #define MGLOB(x) (((CSOUND*)csound)->midiGlobals->x)
50 
51 int32_t midibset(CSOUND*, MIDIKMB*);
52 
53 /* IV - Oct 31 2002: modified to allow named instruments */
54 
massign_p(CSOUND * csound,MASSIGN * p)55 int32_t massign_p(CSOUND *csound, MASSIGN *p)
56 {
57     int32_t   chnl = (int32_t)(*p->chnl + FL(0.5));
58     int32_t   resetCtls;
59     int32_t   retval = OK;
60 
61     resetCtls = (*p->iresetctls == FL(0.0) ? 0 : 1);
62     if (--chnl >= 0)
63       retval = m_chinsno(csound, chnl, (int32_t) *p->insno, resetCtls);
64     else {
65       for (chnl = 0; chnl < 16; chnl++) {
66         if (m_chinsno(csound, chnl, (int32_t) *p->insno, resetCtls) != OK)
67           retval = NOTOK;
68       }
69     }
70     return retval;
71 }
72 
massign_S(CSOUND * csound,MASSIGNS * p)73 int32_t massign_S(CSOUND *csound, MASSIGNS *p)
74 {
75     int32_t   chnl = (int32_t)(*p->chnl + FL(0.5));
76     int32_t   instno = 0L;
77     int32_t   resetCtls;
78     int32_t   retval = OK;
79 
80     if (UNLIKELY((instno = strarg2insno(csound, p->insno->data, 1)) <= 0L))
81       return NOTOK;
82 
83     resetCtls = (*p->iresetctls == FL(0.0) ? 0 : 1);
84     if (--chnl >= 0)
85       retval = m_chinsno(csound, chnl, (int32_t) instno, resetCtls);
86     else {
87       for (chnl = 0; chnl < 16; chnl++) {
88         if (m_chinsno(csound, chnl, (int32_t) instno, resetCtls) != OK)
89           retval = NOTOK;
90       }
91     }
92     return retval;
93 }
94 
95 
ctrlinit(CSOUND * csound,CTLINIT * p)96 int32_t ctrlinit(CSOUND *csound, CTLINIT *p)
97 {
98     int16 chnl = (int16)(*p->chnl - FL(0.5));
99     int16 nargs = p->INOCOUNT;
100     if (UNLIKELY((nargs & 0x1) == 0)) {
101       return csound->InitError(csound, Str("uneven ctrl pairs"));
102     }
103     else {
104       MCHNBLK *chn;
105       MYFLT **argp = p->ctrls;
106       int16 ctlno, nctls = nargs >> 1;
107       chn = csound->m_chnbp[chnl];
108       do {
109         MYFLT val;
110         ctlno = (int16)**argp++;
111         if (UNLIKELY(ctlno < 0 || ctlno > 127)) {
112           return csound->InitError(csound, Str("illegal ctrl no"));
113         }
114         val = **argp++;
115         if (val < FL(0.0) || val > FL(127.0))
116           return csound->InitError(csound, Str("Value out of range [0,127]\n"));
117         chn->ctl_val[ctlno] = val;
118       } while (--nctls);
119       return OK;
120     }
121 }
122 
notnum(CSOUND * csound,MIDIKMB * p)123 int32_t notnum(CSOUND *csound, MIDIKMB *p)       /* valid only at I-time */
124 {
125     *p->r = csound->curip->m_pitch;
126     return OK;
127 }
128 
129 /* cpstmid by G.Maldonado */
cpstmid(CSOUND * csound,CPSTABLE * p)130 int32_t cpstmid(CSOUND *csound, CPSTABLE *p)
131 {
132     FUNC  *ftp;
133     MYFLT *func;
134     int32_t notenum = csound->curip->m_pitch;
135     int32_t grade;
136     int32_t numgrades;
137     int32_t basekeymidi;
138     MYFLT basefreq, factor, interval;
139 
140     if (UNLIKELY((ftp = csound->FTnp2Find(csound, p->tablenum)) == NULL)) {
141       return csound->InitError(csound, Str("cpstabm: invalid modulator table"));
142     }
143     func = ftp->ftable;
144     numgrades = (int32_t)*func++;
145     interval = *func++;
146     basefreq = *func++;
147     basekeymidi = (int32_t)*func++;
148 
149     if (notenum < basekeymidi) {
150       notenum = basekeymidi - notenum;
151       grade  = (numgrades-(notenum % numgrades)) % numgrades;
152       factor = - (MYFLT)(int32_t)((notenum+numgrades-1) / numgrades) ;
153     }
154     else {
155       notenum = notenum - basekeymidi;
156       grade  = notenum % numgrades;
157       factor = (MYFLT)(int32_t)(notenum / numgrades);
158     }
159     factor = POWER(interval, factor);
160     *p->r = func[grade] * factor * basefreq;
161     return OK;
162 }
163 
veloc(CSOUND * csound,MIDIMAP * p)164 int32_t veloc(CSOUND *csound, MIDIMAP *p)           /* valid only at I-time */
165 {
166     *p->r = *p->ilo + csound->curip->m_veloc*(*p->ihi - *p->ilo) * dv127;
167     return OK;
168 }
169 
pchmidi(CSOUND * csound,MIDIKMB * p)170 int32_t pchmidi(CSOUND *csound, MIDIKMB *p)
171 {
172     IGN(csound);
173     INSDS *lcurip = p->h.insdshead;
174     double fract, oct, ioct;
175     oct = lcurip->m_pitch / 12.0 + 3.0;
176     fract = modf(oct, &ioct);
177     fract *= 0.12;
178     *p->r = (MYFLT)(ioct + fract);
179     return OK;
180 }
181 
pchmidib(CSOUND * csound,MIDIKMB * p)182 int32_t pchmidib(CSOUND *csound, MIDIKMB *p)
183 {
184     INSDS *lcurip = p->h.insdshead;
185     double fract, oct, ioct;
186     MCHNBLK *xxx = csound->curip->m_chnbp;
187     MYFLT bend = pitchbend_value(xxx);
188     oct = (lcurip->m_pitch + (bend * p->scale)) / FL(12.0) + FL(3.0);
189     fract = modf(oct, &ioct);
190     fract *= 0.12;
191     *p->r = (MYFLT)(ioct + fract);
192     return OK;
193 }
194 
pchmidib_i(CSOUND * csound,MIDIKMB * p)195 int32_t pchmidib_i(CSOUND *csound, MIDIKMB *p)
196 {
197     midibset(csound, p);
198     pchmidib(csound, p);
199     return OK;
200 }
201 
octmidi(CSOUND * csound,MIDIKMB * p)202 int32_t octmidi(CSOUND *csound, MIDIKMB *p)
203 {
204     IGN(csound);
205     INSDS *lcurip = p->h.insdshead;
206     *p->r = lcurip->m_pitch / FL(12.0) + FL(3.0);
207     return OK;
208 }
209 
octmidib(CSOUND * csound,MIDIKMB * p)210 int32_t octmidib(CSOUND *csound, MIDIKMB *p)
211 {
212     IGN(csound);
213     INSDS *lcurip = p->h.insdshead;
214     *p->r = (lcurip->m_pitch + (pitchbend_value(lcurip->m_chnbp) *
215                                 p->scale)) / FL(12.0) + FL(3.0);
216     return OK;
217 }
218 
octmidib_i(CSOUND * csound,MIDIKMB * p)219 int32_t octmidib_i(CSOUND *csound, MIDIKMB *p)
220 {
221     midibset(csound, p);
222     octmidib(csound, p);
223     return OK;
224 }
225 
cpsmidi(CSOUND * csound,MIDIKMB * p)226 int32_t cpsmidi(CSOUND *csound, MIDIKMB *p)
227 {
228     INSDS *lcurip = p->h.insdshead;
229     int32_t  loct;
230     /*    loct = (int64_t)(((lcurip->m_pitch +
231      *       pitchbend_value(lcurip->m_chnbp) * p->iscal)/ 12.0f + 3.0f) * OCTRES);
232      */
233     loct = (int32_t)((lcurip->m_pitch/ FL(12.0) + FL(3.0)) * OCTRES);
234     *p->r = CPSOCTL(loct);
235     return OK;
236 }
237 
icpsmidib(CSOUND * csound,MIDIKMB * p)238 int32_t icpsmidib(CSOUND *csound, MIDIKMB *p)
239 {
240     INSDS *lcurip = p->h.insdshead;
241     int32_t  loct;
242     MYFLT bend = pitchbend_value(lcurip->m_chnbp);
243     p->prvbend = bend;
244     loct = (int32_t)(((lcurip->m_pitch +
245                      bend * p->scale) / FL(12.0) + FL(3.0)) * OCTRES);
246     *p->r = CPSOCTL(loct);
247     return OK;
248 }
249 
icpsmidib_i(CSOUND * csound,MIDIKMB * p)250 int32_t icpsmidib_i(CSOUND *csound, MIDIKMB *p)
251 {
252     midibset(csound, p);
253     icpsmidib(csound, p);
254     return OK;
255 }
256 
kcpsmidib(CSOUND * csound,MIDIKMB * p)257 int32_t kcpsmidib(CSOUND *csound, MIDIKMB *p)
258 {
259     INSDS *lcurip = p->h.insdshead;
260     MYFLT bend = pitchbend_value(lcurip->m_chnbp);
261 
262     if (bend == p->prvbend || lcurip->relesing)
263       *p->r = p->prvout;
264     else {
265       int32_t  loct;
266       p->prvbend = bend;
267       loct = (int32_t)(((lcurip->m_pitch +
268                        bend * p->scale) / FL(12.0) + FL(3.0)) * OCTRES);
269       *p->r = p->prvout = CPSOCTL(loct);
270     }
271     return OK;
272 }
273 
ampmidi(CSOUND * csound,MIDIAMP * p)274 int32_t ampmidi(CSOUND *csound, MIDIAMP *p)   /* convert midi veloc to amplitude */
275 {                                         /*   valid only at I-time          */
276     MYFLT amp;
277     int32_t  fno;
278     FUNC *ftp;
279 
280     amp = csound->curip->m_veloc / FL(128.0);     /* amp = normalised veloc */
281     if ((fno = (int32_t)*p->ifn) > 0) {              /* if valid ftable,       */
282       if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn)) == NULL))
283         return NOTOK;                             /*     use amp as index   */
284       amp = *(ftp->ftable + (int32_t)(amp * ftp->flen));
285     }
286     *p->r = amp * *p->imax;                       /* now scale the output   */
287     return OK;
288 }
289 
290 /*      MWB 2/11/97  New optional field to set pitch bend range
291         I also changed each of the xxxmidib opcodes, adding * p->scale */
midibset(CSOUND * csound,MIDIKMB * p)292 int32_t midibset(CSOUND *csound, MIDIKMB *p)
293 {
294     MCHNBLK *chn;
295     IGN(csound);
296     chn = p->h.insdshead->m_chnbp;
297     if (*p->iscal > FL(0.0))
298       p->scale = *p->iscal;
299     else if (chn != NULL)
300       p->scale = chn->pbensens;
301     else
302       p->scale = FL(2.0);
303     /* Start from sane position */
304     if (chn != NULL)
305       p->prvbend = chn->pchbend;
306     else
307       p->prvbend = FL(0.0);
308     return OK;
309 }
310 
aftset(CSOUND * csound,MIDIKMAP * p)311 int32_t aftset(CSOUND *csound, MIDIKMAP *p)
312 {
313     IGN(csound);
314     p->lo = *p->ilo;
315     p->scale = (*p->ihi - p->lo) * dv127;
316     return OK;
317 }
318 
aftouch(CSOUND * csound,MIDIKMAP * p)319 int32_t aftouch(CSOUND *csound, MIDIKMAP *p)
320 {
321     IGN(csound);
322     INSDS *lcurip = p->h.insdshead;
323     *p->r = p->lo + MIDI_VALUE(lcurip->m_chnbp, aftouch) * p->scale;
324     return OK;
325 }
326 
imidictl(CSOUND * csound,MIDICTL * p)327 int32_t imidictl(CSOUND *csound, MIDICTL *p)
328 {
329     int32_t  ctlno;
330     if (UNLIKELY((ctlno = (int32_t)*p->ictlno) < 0 || ctlno > 127))
331       return csound->InitError(csound, Str("illegal controller number"));
332     else *p->r = MIDI_VALUE(csound->curip->m_chnbp, ctl_val[ctlno])
333            * (*p->ihi - *p->ilo) * dv127 + *p->ilo;
334     return OK;
335 }
336 
mctlset(CSOUND * csound,MIDICTL * p)337 int32_t mctlset(CSOUND *csound, MIDICTL *p)
338 {
339     int32_t  ctlno;
340     if (UNLIKELY((ctlno = (int32_t)*p->ictlno) < 0 || ctlno > 127))
341       return csound->InitError(csound, Str("illegal controller number"));
342     else {
343       p->ctlno = ctlno;
344       p->scale = (*p->ihi - *p->ilo) * dv127;
345       p->lo = *p->ilo;
346     }
347     return OK;
348 }
349 
midictl(CSOUND * csound,MIDICTL * p)350 int32_t midictl(CSOUND *csound, MIDICTL *p)
351 {
352     IGN(csound);
353     INSDS *lcurip = p->h.insdshead;
354     *p->r = MIDI_VALUE(lcurip->m_chnbp, ctl_val[p->ctlno]) * p->scale + p->lo;
355     return OK;
356 }
357 
imidiaft(CSOUND * csound,MIDICTL * p)358 int32_t imidiaft(CSOUND *csound, MIDICTL *p)
359 {
360     int32_t  ctlno;
361     if (UNLIKELY((ctlno = (int32_t)*p->ictlno) < 0 || ctlno > 127))
362       return csound->InitError(csound, Str("illegal controller number"));
363     else *p->r = MIDI_VALUE(csound->curip->m_chnbp, polyaft[ctlno])
364            * (*p->ihi - *p->ilo) * dv127 + *p->ilo;
365     return OK;
366 }
367 
maftset(CSOUND * csound,MIDICTL * p)368 int32_t maftset(CSOUND *csound, MIDICTL *p)
369 {
370     int32_t  ctlno;
371     if (UNLIKELY((ctlno = (int32_t)*p->ictlno) < 0 || ctlno > 127))
372       return csound->InitError(csound, Str("illegal controller number"));
373     else {
374       p->ctlno = ctlno;
375       p->scale = (*p->ihi - *p->ilo) * dv127;
376       p->lo = *p->ilo;
377     }
378     return OK;
379 }
380 
midiaft(CSOUND * csound,MIDICTL * p)381 int32_t midiaft(CSOUND *csound, MIDICTL *p)
382 {
383     IGN(csound);
384     INSDS *lcurip = p->h.insdshead;
385     *p->r = MIDI_VALUE(lcurip->m_chnbp, polyaft[p->ctlno]) * p->scale + p->lo;
386     return OK;
387 }
388 
389 /* midichn opcode - get MIDI channel number or 0 for score notes */
390 /* written by Istvan Varga, May 2002 */
391 
midichn(CSOUND * csound,MIDICHN * p)392 int32_t midichn(CSOUND *csound, MIDICHN *p)
393 {
394     *(p->ichn) = (MYFLT) (csound->GetMidiChannelNumber(p) + 1);
395     return OK;
396 }
397 
398 /* pgmassign - assign MIDI program to instrument */
399 
pgmassign_(CSOUND * csound,PGMASSIGN * p,int32_t instname)400 int32_t pgmassign_(CSOUND *csound, PGMASSIGN *p, int32_t instname)
401 {
402     int32_t pgm, ins, chn;
403 
404     chn = (int32_t)(*p->ichn + 0.5);
405     if (UNLIKELY(chn < 0 || chn > 16))
406       return csound->InitError(csound, Str("illegal channel number"));
407     /* IV - Oct 31 2002: allow named instruments */
408     if (instname || csound->ISSTRCOD(*p->inst)) {
409       MYFLT buf[128];
410       csound->strarg2name(csound, (char*) buf, p->inst, "", 1);
411       ins = (int32_t)strarg2insno(csound, buf, 1);
412     }
413     else
414       ins = (int32_t)(*(p->inst) + FL(0.5));
415     if (*(p->ipgm) < FL(0.5)) {         /* program <= 0: assign all pgms */
416       if (!chn) {                           /* on all channels */
417         for (chn = 0; chn < 16; chn++)
418           for (pgm = 0; pgm < 128; pgm++)
419             csound->m_chnbp[chn]->pgm2ins[pgm] = ins;
420       }
421       else {                                /* or selected channel only */
422         chn--;
423         for (pgm = 0; pgm < 128; pgm++)
424           csound->m_chnbp[chn]->pgm2ins[pgm] = ins;
425       }
426     }
427     else {                              /* program > 0: assign selected pgm */
428       pgm = (int32_t)(*(p->ipgm) - FL(0.5));
429       if (UNLIKELY(pgm < 0 || pgm > 127)) {
430         return csound->InitError(csound, Str("pgmassign: invalid program number"));
431       }
432       if (!chn) {                           /* on all channels */
433         for (chn = 0; chn < 16; chn++)
434           csound->m_chnbp[chn]->pgm2ins[pgm] = ins;
435       }
436       else {                                /* or selected channel only */
437         chn--;
438         csound->m_chnbp[chn]->pgm2ins[pgm] = ins;
439       }
440     }
441     return OK;
442 }
443 
pgmassign_S(CSOUND * csound,PGMASSIGN * p)444 int32_t pgmassign_S(CSOUND *csound, PGMASSIGN *p) {
445     return pgmassign_(csound,p,1);
446 }
447 
pgmassign(CSOUND * csound,PGMASSIGN * p)448 int32_t pgmassign(CSOUND *csound, PGMASSIGN *p) {
449     return pgmassign_(csound,p,0);
450 }
451 
ichanctl(CSOUND * csound,CHANCTL * p)452 int32_t ichanctl(CSOUND *csound, CHANCTL *p)
453 {
454     int32_t  ctlno, chan = (int32_t)(*p->ichano - FL(1.0));
455     if (UNLIKELY(chan < 0 || chan > 15 || csound->m_chnbp[chan] == NULL))
456       return csound->InitError(csound, Str("illegal channel number"));
457     if (UNLIKELY((ctlno = (int32_t)*p->ictlno) < 0 || ctlno > 127))
458       return csound->InitError(csound, Str("illegal controller number"));
459     else *p->r = csound->m_chnbp[chan]->ctl_val[ctlno] * (*p->ihi - *p->ilo)
460            * dv127 + *p->ilo;
461     return OK;
462 }
463 
chctlset(CSOUND * csound,CHANCTL * p)464 int32_t chctlset(CSOUND *csound, CHANCTL *p)
465 {
466     int32_t  ctlno, chan = (int32_t)(*p->ichano - FL(1.0));
467     if (UNLIKELY(chan < 0 || chan > 15 || csound->m_chnbp[chan] == NULL)) {
468       return csound->InitError(csound, Str("illegal channel number"));
469     }
470     p->chano = chan;
471     if (UNLIKELY((ctlno = (int32_t)*p->ictlno) < 0 || ctlno > 127)) {
472       return csound->InitError(csound, Str("illegal controller number"));
473     }
474     else {
475       p->ctlno = ctlno;
476       p->scale = (*p->ihi - *p->ilo) * dv127;
477       p->lo = *p->ilo;
478     }
479     return OK;
480 }
481 
chanctl(CSOUND * csound,CHANCTL * p)482 int32_t chanctl(CSOUND *csound, CHANCTL *p)
483 {
484     *p->r = csound->m_chnbp[p->chano]->ctl_val[p->ctlno] * p->scale + p->lo;
485     return OK;
486 }
487 
ipchbend(CSOUND * csound,MIDIMAP * p)488 int32_t ipchbend(CSOUND *csound, MIDIMAP *p)
489 {
490     IGN(csound);
491     *p->r = *p->ilo + (*p->ihi - *p->ilo) *
492       pitchbend_value(p->h.insdshead->m_chnbp);
493     return OK;
494 }
495 
kbndset(CSOUND * csound,MIDIKMAP * p)496 int32_t kbndset(CSOUND *csound, MIDIKMAP *p)
497 {
498     IGN(csound);
499     p->lo = *p->ilo;
500     p->scale = *p->ihi - *p->ilo;
501     return OK;
502 }
503 
kpchbend(CSOUND * csound,MIDIKMAP * p)504 int32_t kpchbend(CSOUND *csound, MIDIKMAP *p)
505 {
506     IGN(csound);
507     INSDS *lcurip = p->h.insdshead;
508     *p->r = p->lo + pitchbend_value(lcurip->m_chnbp) * p->scale;
509     return OK;
510 }
511 
midiin_set(CSOUND * csound,MIDIIN * p)512 int32_t midiin_set(CSOUND *csound, MIDIIN *p)
513 {
514     p->local_buf_index = MGLOB(MIDIINbufIndex) & MIDIINBUFMSK;
515     return OK;
516 }
517 
midiin(CSOUND * csound,MIDIIN * p)518 int32_t midiin(CSOUND *csound, MIDIIN *p)
519 {
520     unsigned char *temp;                        /* IV - Nov 30 2002 */
521     if (p->local_buf_index != MGLOB(MIDIINbufIndex)) {
522       temp = &(MGLOB(MIDIINbuffer2)[p->local_buf_index++].bData[0]);
523       p->local_buf_index &= MIDIINBUFMSK;
524       *p->status = (MYFLT) *temp; //(*temp & (unsigned char) 0xf0);
525       *p->chan   = (MYFLT) *++temp; //((*temp & 0x0f) + 1);
526       *p->data1  = (MYFLT) *++temp;
527       *p->data2  = (MYFLT) *++temp;
528     }
529     else *p->status = FL(0.0);
530     return OK;
531 }
532 
pgmin_set(CSOUND * csound,PGMIN * p)533 int32_t pgmin_set(CSOUND *csound, PGMIN *p)
534 {
535     p->local_buf_index = MGLOB(MIDIINbufIndex) & MIDIINBUFMSK;
536     p->watch =(int32_t)*p->ochan;
537     return OK;
538 }
539 
pgmin(CSOUND * csound,PGMIN * p)540 int32_t pgmin(CSOUND *csound, PGMIN *p)
541 {
542     unsigned char *temp;
543     if (p->local_buf_index != MGLOB(MIDIINbufIndex)) {
544       int32_t st,ch,d1;
545       temp = &(MGLOB(MIDIINbuffer2)[p->local_buf_index++].bData[0]);
546       st = *temp & (unsigned char) 0xf0;
547       ch = (*temp & 0x0f) + 1;
548       d1 = *++temp;
549       /*       d2 = *++temp; */
550       if (st == 0xC0 && (p->watch==0 || p->watch==ch)) {
551         *p->pgm = (MYFLT)1+d1;
552         *p->chn = (MYFLT)ch;
553       }
554       else {
555         *p->pgm = FL(-1.0);
556         *p->chn = FL(0.0);
557       }
558       p->local_buf_index &= MIDIINBUFMSK;
559     }
560     else {
561       *p->pgm = FL(-1.0);
562       *p->chn = FL(0.0);
563     }
564     return OK;
565 }
566 
ctlin_set(CSOUND * csound,CTLIN * p)567 int32_t ctlin_set(CSOUND *csound, CTLIN *p)
568 {
569     p->local_buf_index = MGLOB(MIDIINbufIndex) & MIDIINBUFMSK;
570     p->watch1 =(int32_t)*p->ochan;
571     p->watch2 =(int32_t)*p->onum;
572     return OK;
573 }
574 
ctlin(CSOUND * csound,CTLIN * p)575 int32_t ctlin(CSOUND *csound, CTLIN *p)
576 {
577     unsigned char *temp;
578     if  (p->local_buf_index != MGLOB(MIDIINbufIndex)) {
579       int32_t st,ch,d1,d2;
580       temp = &(MGLOB(MIDIINbuffer2)[p->local_buf_index++].bData[0]);
581       st = *temp & (unsigned char) 0xf0;
582       ch = (*temp & 0x0f) + 1;
583       d1 = *++temp;
584       d2 = *++temp;
585       if (st == 0xB0 &&
586           (p->watch1==0 || p->watch1==ch) &&
587           (p->watch2==0 || p->watch2==d2)) {
588         *p->data = (MYFLT)d1;
589         *p->numb = (MYFLT)d2;
590         *p->chn = (MYFLT)ch;
591       }
592       else {
593         *p->data = FL(-1.0);
594         *p->numb = FL(-1.0);
595         *p->chn = FL(0.0);
596       }
597       p->local_buf_index &= MIDIINBUFMSK;
598     }
599     else {
600       *p->data = FL(-1.0);
601       *p->numb = FL(-1.0);
602       *p->chn = FL(0.0);
603     }
604     return OK;
605 
606 }
607 
608 
609 /* MIDIARP by Rory Walsh, 2016
610  */
611 
midiarp_set(CSOUND * csound,MIDIARP * p)612 int32_t midiarp_set(CSOUND *csound, MIDIARP *p)
613 /* MIDI Arp - Jan 2017 - RW */
614 {
615     int32_t cnt;
616     srand(time(NULL));
617     p->flag=1, *p->arpMode=0, p->direction=2, p->noteIndex=9;
618     p->maxNumNotes=10, p->noteCnt=0, p->status=0, p->chan=0;
619     p->data1=0, p->data2=0;
620 
621     p->local_buf_index = MGLOB(MIDIINbufIndex) & MIDIINBUFMSK;
622 
623     for (cnt=0;cnt<10;cnt++)
624       p->notes[cnt] = 0;
625 
626     return OK;
627 }
628 
sort_notes(int32_t notes[],int32_t n)629 void sort_notes(int32_t notes[], int32_t n)
630 {
631     int32_t j,i,tmp;
632     for (i = 0; i < n; ++i) {
633       for (j = i + 1; j < n; ++j) {
634         if (notes[i] > notes[j]) {
635           tmp =  notes[i];
636           notes[i] = notes[j];
637           notes[j] = tmp;
638         }
639       }
640     }
641 }
642 
zeroNoteFromArray(int32_t notes[],int32_t noteNumber,int32_t size)643 void zeroNoteFromArray(int32_t notes[], int32_t noteNumber, int32_t size)
644 {
645     int32_t i;
646     for (i=0;i<size;i++) {
647       if (notes[i]==noteNumber)
648         notes[i]=0;
649     }
650 }
651 
metroCounter(MIDIARP * p)652 int32_t metroCounter(MIDIARP *p)
653 {
654     double phs = p->curphs;
655     if (phs == 0.0 && p->flag) {
656       p->metroTick = FL(1.0);
657       p->flag = 0;
658     }
659     else if ((phs += *p->arpRate * CS_ONEDKR) >= 1.0) {
660       p->metroTick = FL(1.0);
661       phs -= 1.0;
662       p->flag = 0;
663     }
664     else
665       p->metroTick = FL(0.0);
666 
667     p->curphs = phs;
668     return p->metroTick;
669 }
670 
671 
midiarp(CSOUND * csound,MIDIARP * p)672 int32_t midiarp(CSOUND *csound, MIDIARP *p)
673 {
674     int32_t i=0;
675     unsigned char *temp;
676     int32_t arpmode = (int32_t)*p->arpMode;
677 
678     if (p->local_buf_index != MGLOB(MIDIINbufIndex))
679       {
680         temp = &(MGLOB(MIDIINbuffer2)[p->local_buf_index++].bData[0]);
681         p->local_buf_index &= MIDIINBUFMSK;
682         p->status = (MYFLT) (*temp & (unsigned char) 0xf0);
683         p->chan   = (MYFLT) ((*temp & 0x0f) + 1);
684         p->data1  = (MYFLT) *++temp;
685         p->data2  = (MYFLT) *++temp;
686 
687         if (p->status==144 && p->data2>0) {
688           p->notes[p->noteCnt] = p->data1;
689 
690           for (i = 0 ; i < p->maxNumNotes ; i++)
691             p->sortedNotes[i] = p->notes[i];
692 
693           p->noteCnt = (p->noteCnt>p->maxNumNotes-1 ?
694                         p->maxNumNotes-1 : p->noteCnt+1);
695           sort_notes(p->sortedNotes, 10);
696 
697         }
698         else if (p->status==128 || (p->status==144 && p->data2==0)) {
699           zeroNoteFromArray(p->notes, p->data1, p->maxNumNotes);
700 
701           for (i = 0 ; i < p->maxNumNotes ; i++)
702             p->sortedNotes[i] = p->notes[i];
703 
704           p->noteCnt = (p->noteCnt<0 ? 0 : p->noteCnt-1);
705           sort_notes(p->sortedNotes, p->maxNumNotes);
706         }
707       }
708     else p->status = FL(0.0);
709 
710     if (p->noteCnt != 0) {
711       // only when some note/s are pressed
712       *p->counter = metroCounter(p);
713       if (*p->counter == 1) {
714 
715         if (p->noteIndex<p->maxNumNotes && p->sortedNotes[p->noteIndex]!=0)
716           *p->noteOut = p->sortedNotes[p->noteIndex];
717 
718         if (arpmode==0) {
719           //up and down pattern
720           if (p->direction>0) {
721             p->noteIndex = (p->noteIndex < p->maxNumNotes-1
722                             ? p->noteIndex+1 : p->maxNumNotes - p->noteCnt);
723             if (p->noteIndex==p->maxNumNotes-1)
724               p->direction = -2;
725           }
726           else {
727             p->noteIndex = (p->noteIndex > p->maxNumNotes - p->noteCnt
728                             ? p->noteIndex-1 : p->maxNumNotes-1);
729             if (p->noteIndex==p->maxNumNotes-p->noteCnt)
730               p->direction = 2;
731 
732           }
733         }
734         else if (arpmode==1) {
735           //up only pattern
736           p->noteIndex = (p->noteIndex < p->maxNumNotes-1
737                           ? p->noteIndex+1 : p->maxNumNotes - p->noteCnt);
738         }
739         else if (arpmode==2) {
740           //down only pattern
741           p->noteIndex = (p->noteIndex > p->maxNumNotes - p->noteCnt
742                           ? p->noteIndex-1 : p->maxNumNotes-1);
743         }
744         else if (arpmode==3) {
745           //random pattern
746           int32_t randIndex = ((rand() % 100)/100.f)*(p->noteCnt);
747           p->noteIndex = p->maxNumNotes-randIndex-1;
748         }
749         else{
750           csound->Message(csound,
751                           Str("Invalid arp mode selected:"
752                               " %d. Valid modes are 0, 1, 2, and 3\n"),
753                           arpmode);
754         }
755       }
756     }
757 
758     return OK;
759 }
760