1 /*
2   musmon.c:
3 
4   Copyright (C) 1991,2002 Barry Vercoe, John ffitch,
5   Istvan Varga, rasmus ekman
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"         /*                         MUSMON.C     */
26 #include "midiops.h"
27 #include "soundio.h"
28 #include "namedins.h"
29 #include "oload.h"
30 #include "remote.h"
31 #include <math.h>
32 #include "corfile.h"
33 
34 #include "csdebug.h"
35 
36 #define SEGAMPS AMPLMSG
37 #define SORMSG  RNGEMSG
38 
39 int     MIDIinsert(CSOUND *, int, MCHNBLK*, MEVENT*);
40   int     insert(CSOUND *, int, EVTBLK*);
41   void    MidiOpen(CSOUND *);
42   void    m_chn_init_all(CSOUND *);
43 //  char *  scsortstr(CSOUND *, CORFIL *);
44   void    infoff(CSOUND*, MYFLT), orcompact(CSOUND*);
45   void    beatexpire(CSOUND *, double), timexpire(CSOUND *, double);
46   void    sfopenin(CSOUND *), sfopenout(CSOUND*), sfnopenout(CSOUND*);
47   void    iotranset(CSOUND *), sfclosein(CSOUND*), sfcloseout(CSOUND*);
48   void    MidiClose(CSOUND *);
49   void    RTclose(CSOUND *);
50   void    remote_Cleanup(CSOUND *);
51   char    **csoundGetSearchPathFromEnv(CSOUND *, const char *);
52 void    openMIDIout(CSOUND *);
53 void print_csound_version(CSOUND*);
54 
55 #ifdef HAVE_PTHREAD_SPIN_LOCK
56 #define RT_SPIN_TRYLOCK { int trylock = CSOUND_SUCCESS; \
57   if(csound->oparms->realtime)             \
58   trylock = csoundSpinTryLock(&csound->alloc_spinlock);      \
59   if(trylock == CSOUND_SUCCESS) {
60 #else
61 #define RT_SPIN_TRYLOCK csoundSpinLock(&csound->alloc_spinlock);
62 #endif
63 
64 #ifdef HAVE_PTHREAD_SPIN_LOCK
65 #define RT_SPIN_UNLOCK \
66 if(csound->oparms->realtime) \
67   csoundSpinUnLock(&csound->alloc_spinlock); \
68   trylock = CSOUND_SUCCESS; } }
69 #else
70 #define RT_SPIN_UNLOCK csoundSpinUnLock(&csound->alloc_spinlock);
71 #endif
72 
73 /* extern  void    initialize_instrument0(CSOUND *); */
74 
75 typedef struct evt_cb_func {
76   void    (*func)(CSOUND *, void *);
77   void    *userData;
78   struct evt_cb_func  *nxt;
79 } EVT_CB_FUNC;
80 
81 #define STA(x)   (csound->musmonStatics.x)
82 
83 /**
84   Open and Initialises the input/output
85   returns the HW sampling rate if it has been
86   set, -1.0 otherwise.
87 */
csoundInitialiseIO(CSOUND * csound)88 MYFLT csoundInitialiseIO(CSOUND *csound) {
89     OPARMS *O = csound->oparms;
90     if (csound->enableHostImplementedAudioIO &&
91         csound->hostRequestedBufferSize) {
92       int bufsize    = (int) csound->hostRequestedBufferSize;
93       int ksmps      = (int) csound->ksmps;
94       bufsize        = (bufsize + (ksmps >> 1)) / ksmps;
95       bufsize        = (bufsize ? bufsize * ksmps : ksmps);
96       O->outbufsamps = O->inbufsamps = bufsize;
97     }
98     else {
99       if (!O->oMaxLag)
100         O->oMaxLag = IODACSAMPS;
101       if (!O->outbufsamps)
102         O->outbufsamps = IOBUFSAMPS;
103       else if (UNLIKELY(O->outbufsamps < 0)) { /* if k-aligned iobufs requested  */
104         /* set from absolute value */
105         O->outbufsamps *= -((int64_t)csound->ksmps);
106         csound->Message(csound, Str("k-period aligned audio buffering\n"));
107         if (O->oMaxLag <= O->outbufsamps)
108           O->oMaxLag = O->outbufsamps << 1;
109       }
110       /* else keep the user values */
111       /* IV - Feb 04 2005: make sure that buffer sizes for real time audio */
112       /* are usable */
113       if (check_rtaudio_name(O->infilename, NULL, 0) >= 0 ||
114           check_rtaudio_name(O->outfilename, NULL, 1) >= 0) {
115         O->oMaxLag = ((O->oMaxLag + O->outbufsamps - 1) / O->outbufsamps)
116           * O->outbufsamps;
117         if (O->oMaxLag <= O->outbufsamps && O->outbufsamps > 1)
118           O->outbufsamps >>= 1;
119       }
120       O->inbufsamps = O->outbufsamps;
121     }
122     csound->Message(csound, Str("audio buffered in %d sample-frame blocks\n"),
123                     (int) O->outbufsamps);
124     O->inbufsamps  *= csound->inchnls;    /* now adjusted for n channels  */
125     O->outbufsamps *= csound->nchnls;
126     iotranset(csound);          /* point recv & tran to audio formatter */
127     /* open audio file or device for input first, and then for output */
128     if (!csound->enableHostImplementedAudioIO) {
129       if (O->sfread)
130         sfopenin(csound);
131       if (O->sfwrite && !csound->initonly)
132         sfopenout(csound);
133       else
134        sfnopenout(csound);
135     }
136     csound->io_initialised = 1;
137     return csound->system_sr(csound, 0);
138  }
139 
140 
141 
142 /* IV - Jan 28 2005 */
print_benchmark_info(CSOUND * csound,const char * s)143 void print_benchmark_info(CSOUND *csound, const char *s)
144 {
145   double  rt, ct;
146 
147   if ((csound->oparms->msglevel & TIMEMSG) == 0 || csound->csRtClock == NULL)
148     return;
149   rt = csoundGetRealTime(csound->csRtClock);
150   ct = csoundGetCPUTime(csound->csRtClock);
151   csound->Message(csound,
152                   Str("Elapsed time at %s: real: %.3fs, CPU: %.3fs\n"),
153                   (char*) s, rt, ct);
154 }
155 
settempo(CSOUND * csound,double tempo)156 static void settempo(CSOUND *csound, double tempo)
157 {
158     if (tempo <= 0.0) return;
159     if (csound->oparms->Beatmode==1)
160       csound->ibeatTime = (int64_t)(csound->esr*60.0 / tempo);
161     csound->curBeat_inc = tempo / (60.0 * (double) csound->ekr);
162 }
163 
gettempo(CSOUND * csound,GTEMPO * p)164 int gettempo(CSOUND *csound, GTEMPO *p)
165 {
166     if (LIKELY(csound->oparms->Beatmode)) {
167       *p->ans = FL(60.0) * csound->esr / (MYFLT)csound->ibeatTime;
168     }
169     else
170       *p->ans = FL(60.0);
171     return OK;
172 }
173 
tempset(CSOUND * csound,TEMPO * p)174 int tempset(CSOUND *csound, TEMPO *p)
175 {
176     double tempo;
177 
178     if (UNLIKELY((tempo = (double)*p->istartempo) <= FL(0.0))) {
179       return csound->InitError(csound, Str("illegal istartempo value"));
180     }
181     if (UNLIKELY(csound->oparms->Beatmode==0))
182       return csound->InitError(csound, Str("Beat mode not in force"));
183     settempo(csound, tempo);
184     p->prvtempo = (MYFLT)tempo;
185     return OK;
186 }
187 
tempo(CSOUND * csound,TEMPO * p)188 int tempo(CSOUND *csound, TEMPO *p)
189 {
190     if (*p->ktempo != p->prvtempo) {
191       settempo(csound, (double)*p->ktempo);
192       p->prvtempo = *p->ktempo;
193     }
194     return OK;
195 }
196 
print_maxamp(CSOUND * csound,MYFLT x)197 static void print_maxamp(CSOUND *csound, MYFLT x)
198 {
199     int   attr = 0;
200     if (!(csound->oparms->msglevel & 0x60)) {   /* 0x00: raw amplitudes */
201       if (csound->oparms->msglevel & 0x100) {
202         MYFLT y = x / csound->e0dbfs;     /* relative level */
203         if (UNLIKELY(y >= FL(1.0)))                    /* >= 0 dB: red */
204           attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_RED;
205         else if (csound->oparms->msglevel & 0x200) {
206           if (y >= FL(0.5))                            /* -6..0 dB: yellow */
207             attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_CYAN; /* was yellow but... */
208           else if (y >= FL(0.125))                      /* -24..-6 dB: green */
209             attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_GREEN;
210           else                                          /* -200..-24 dB: blue */
211             attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_BLUE;
212         }
213       }
214       if (csound->e0dbfs > FL(3000.0))
215         csound->MessageS(csound, attr, "%9.1f", x);
216       else if (csound->e0dbfs < FL(3.0))
217         csound->MessageS(csound, attr, "%9.5f", x);
218       else if (csound->e0dbfs > FL(300.0))
219         csound->MessageS(csound, attr, "%9.2f", x);
220       else if (csound->e0dbfs > FL(30.0))
221         csound->MessageS(csound, attr, "%9.3f", x);
222       else
223         csound->MessageS(csound, attr, "%9.4f", x);
224     }
225     else {                              /* dB values */
226       MYFLT y = x / csound->e0dbfs;     /* relative level */
227       if (UNLIKELY(y < FL(1.0e-10))) {
228         /* less than -200 dB: print zero */
229         csound->Message(csound, "      0  ");
230         return;
231       }
232       y = FL(20.0) * (MYFLT) log10((double) y);
233       if (csound->oparms->msglevel & 0x40) {
234         if (UNLIKELY(y >= FL(0.0)))                     /* >= 0 dB: red */
235           attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_RED;
236         else if (csound->oparms->msglevel & 0x20) {
237           if (y >= FL(-6.0))                            /* -6..0 dB: yellow */
238             attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_YELLOW;
239           else if (y >= FL(-24.0))                      /* -24..-6 dB: green */
240             attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_GREEN;
241           else                                          /* -200..-24 dB: blue */
242             attr = CSOUNDMSG_FG_BOLD | CSOUNDMSG_FG_BLUE;
243         }
244       }
245       csound->MessageS(csound, attr, "%+9.2f", y);
246     }
247 }
248 
musmon(CSOUND * csound)249 int musmon(CSOUND *csound)
250 {
251     OPARMS  *O = csound->oparms;
252     /* VL - 20-10-16 this is already printed in csound.c */
253     /*
254       #ifdef USE_DOUBLE
255       #ifdef BETA
256       csound->Message(csound,
257       Str("--Csound version %s beta (double samples) %s\n[%s]\n"),
258       CS_PACKAGE_VERSION, CS_PACKAGE_DATE, GIT_HASH_VALUE_ST);
259       #else
260       csound->Message(csound,
261                       Str("--Csound version %s (double samples) %s\n[%s]\n"),
262       CS_PACKAGE_VERSION, CS_PACKAGE_DATE, GIT_HASH_VALUE_ST);
263       #endif
264       #else
265       #ifdef BETA
266       csound->Message(csound,
267       Str("--Csound version %s beta (float samples) %s\n[%s]\n"),
268       CS_PACKAGE_VERSION, CS_PACKAGE_DATE, GIT_HASH_VALUE_ST);
269       #else
270       csound->Message(csound, Str("--Csound version %s (float samples) %s\n[%s]\n"),
271       CS_PACKAGE_VERSION, CS_PACKAGE_DATE, GIT_HASH_VALUE_ST);
272       #endif
273       #endif
274     */
275     /* initialise search path cache */
276     csoundGetSearchPathFromEnv(csound, "SNAPDIR");
277     csoundGetSearchPathFromEnv(csound, "SFDIR;SSDIR;INCDIR");
278     csoundGetSearchPathFromEnv(csound, "SFDIR");
279     csoundGetSearchPathFromEnv(csound, "SADIR");
280     csoundGetSearchPathFromEnv(csound, "SFDIR;SSDIR");
281 
282     m_chn_init_all(csound);     /* allocate MIDI channels */
283     dispinit(csound);           /* initialise graphics or character display */
284 
285     reverbinit(csound);
286     dbfs_init(csound, csound->e0dbfs);
287     csound->nspout = csound->ksmps * csound->nchnls;  /* alloc spin & spout */
288     csound->nspin = csound->ksmps * csound->inchnls; /* JPff: in preparation */
289     csound->spin  = (MYFLT *) csound->Calloc(csound, csound->nspin*sizeof(MYFLT));
290     csound->spraw = (MYFLT *) csound->Calloc(csound, csound->nspout*sizeof(MYFLT));
291     csound->spout = (MYFLT *) csound->Calloc(csound, csound->nspout*sizeof(MYFLT));
292     csound->auxspin = (MYFLT *) csound->Calloc(csound, csound->nspin*sizeof(MYFLT));
293     /* memset(csound->maxamp, '\0', sizeof(MYFLT)*MAXCHNLS); */
294     /* memset(csound->smaxamp, '\0', sizeof(MYFLT)*MAXCHNLS); */
295     /* memset(csound->omaxamp, '\0', sizeof(MYFLT)*MAXCHNLS); */
296 
297     /* initialise sensevents state */
298     csound->prvbt = csound->curbt = csound->nxtbt = 0.0;
299     csound->curp2 = csound->nxtim = csound->timeOffs = csound->beatOffs = 0.0;
300     csound->icurTime = 0L;
301     if (O->Beatmode && O->cmdTempo > 0.0) {
302       /* if performing from beats, set the initial tempo */
303       csound->curBeat_inc = O->cmdTempo / (60.0 * (double) csound->ekr);
304       csound->ibeatTime = (int64_t)(csound->esr*60.0 / O->cmdTempo);
305     }
306     else {
307       csound->curBeat_inc = 1.0 / (double) csound->ekr;
308       csound->ibeatTime = 1;
309     }
310     csound->cyclesRemaining = 0;
311     memset(&(csound->evt), 0, sizeof(EVTBLK));
312 
313     /* run instr 0 inits */
314     if (UNLIKELY(init0(csound) != 0))
315       csoundDie(csound, Str("header init errors"));
316 
317     /* kperf() will not call csoundYield() more than 250 times per second */
318     csound->evt_poll_cnt    = 0;
319     csound->evt_poll_maxcnt =
320       (int)(250.0 /(double) csound->ekr); /* VL this was wrong: kr/250 originally */
321     /* Enable musmon to handle external MIDI input, if it has been enabled. */
322     if (O->Midiin || O->FMidiin || O->RMidiin) {
323       O->RTevents = 1;
324       MidiOpen(csound);                 /*   alloc bufs & open files    */
325     }
326     /* open MIDI output (moved here from argdecode) */
327     if (O->Midioutname != NULL && O->Midioutname[0] == (char) '\0')
328       O->Midioutname = NULL;
329     if (O->FMidioutname != NULL && O->FMidioutname[0] == (char) '\0')
330       O->FMidioutname = NULL;
331     if (O->Midioutname != NULL || O->FMidioutname != NULL)
332       openMIDIout(csound);
333     csound->Message(csound, Str("orch now loaded\n"));
334 
335     csound->multichan = (csound->nchnls > 1 ? 1 : 0);
336     STA(segamps) = O->msglevel & SEGAMPS;
337     STA(sormsg)  = O->msglevel & SORMSG;
338 
339     if (O->Linein)
340       RTLineset(csound);                /* if realtime input expected   */
341 
342     // VL 01-05-2019
343     // if --use-system-sr, this gets called earlier to override
344     // the sampling rate. Otherwise it gets called here.
345     if(!csound->io_initialised)
346          csoundInitialiseIO(csound);
347 
348     if (O->playscore!=NULL) corfile_flush(csound, O->playscore);
349     //csound->scfp
350     if (UNLIKELY(O->usingcscore)) {
351       if (STA(lsect) == NULL) {
352         STA(lsect) = (EVENT*) csound->Malloc(csound, sizeof(EVENT));
353         STA(lsect)->op = 'l';
354       }
355       csound->Message(csound, Str("using Cscore processing\n"));
356       /* override stdout in */
357       if (UNLIKELY(!(csound->oscfp = fopen("cscore.out", "w"))))
358         csoundDie(csound, Str("cannot create cscore.out"));
359       csoundNotifyFileOpened(csound, "cscore.out", CSFTYPE_SCORE_OUT, 1, 0);
360       /* rdscor for cscorefns */
361       csoundInitializeCscore(csound, csound->scfp, csound->oscfp);
362       /* call cscore, optionally re-enter via lplay() */
363       csound->cscoreCallback_(csound);
364       fclose(csound->oscfp); csound->oscfp = NULL;
365       if (csound->scfp != NULL) {
366         fclose(csound->scfp);
367         csound->scfp = NULL;
368       }
369       if (STA(lplayed))
370         return 0;
371 
372       /*  read from cscore.out */
373       if (UNLIKELY(!(csound->scfp = fopen("cscore.out", "r")))) {
374         csoundDie(csound, Str("cannot reopen cscore.out"));
375       }
376       else {
377         CORFIL *inf = corfile_create_w(csound);
378         int c;
379         while ((c=getc(csound->scfp))!=EOF) corfile_putc(csound, c, inf);
380         corfile_rewind(inf);
381         csound->scorestr = inf;
382         corfile_rm(csound, &csound->scstr);
383       }
384       csoundNotifyFileOpened(csound, "cscore.out", CSFTYPE_SCORE_OUT, 0, 0);
385       /* write to cscore.srt */
386       if (UNLIKELY(!(csound->oscfp = fopen("cscore.srt", "w"))))
387         csoundDie(csound, Str("cannot reopen cscore.srt"));
388       csoundNotifyFileOpened(csound, "cscore.srt", CSFTYPE_SCORE_OUT, 1, 0);
389       csound->Message(csound, Str("sorting cscore.out ..\n"));
390       /* csound->scorestr = copy_to_corefile(csound, "cscore.srt", NULL, 1); */
391       scsortstr(csound, csound->scorestr);  /* call the sorter again */
392       fclose(csound->scfp); csound->scfp = NULL;
393       fputs(corfile_body(csound->scstr), csound->oscfp);
394       fclose(csound->oscfp); csound->oscfp = NULL;
395       csound->Message(csound, Str("\t... done\n"));
396       csound->Message(csound, Str("playing from cscore.srt\n"));
397       O->usingcscore = 0;
398     }
399 
400     csound->Message(csound, Str("SECTION %d:\n"), ++STA(sectno));
401     /* apply score offset if non-zero */
402     if (csound->csoundScoreOffsetSeconds_ > FL(0.0))
403       csoundSetScoreOffsetSeconds(csound, csound->csoundScoreOffsetSeconds_);
404 
405 #ifndef __EMSCRIPTEN__
406     if (csound->oparms->realtime && csound->event_insert_loop == 0){
407       extern uintptr_t event_insert_thread(void *);
408       csound->init_pass_threadlock = csoundCreateMutex(0);
409       csound->Message(csound, "Initialising spinlock...\n");
410       csoundSpinLockInit(&csound->alloc_spinlock);
411       csound->event_insert_loop = 1;
412       csound->alloc_queue = (ALLOC_DATA *)
413         csound->Calloc(csound, sizeof(ALLOC_DATA)*MAX_ALLOC_QUEUE);
414       csound->event_insert_thread =
415         csound->CreateThread(event_insert_thread,
416                              (void*)csound);
417       csound->Message(csound, "Starting realtime mode queue: %p thread: %p\n",
418                       csound->alloc_queue, csound->event_insert_thread );
419     }
420 #endif
421 
422     /* since we are running in components, we exit here to playevents later */
423     return 0;
424 }
425 
deactivate_all_notes(CSOUND * csound)426 static void deactivate_all_notes(CSOUND *csound)
427 {
428     INSDS *ip = csound->actanchor.nxtact;
429 
430     while (ip != NULL) {
431       INSDS *nxt = ip->nxtact;
432 #ifdef BETA
433       printf("deativate: ip, nxt = %p , %p\n", ip, nxt);
434 #endif
435       xturnoff_now(csound, ip);
436       // should not be needed -- if (ip == nxt) break;
437       ip = nxt;
438     }
439 }
440 
delete_pending_rt_events(CSOUND * csound)441 static void delete_pending_rt_events(CSOUND *csound)
442 {
443   EVTNODE *ep = csound->OrcTrigEvts;
444 
445   while (ep != NULL) {
446     EVTNODE *nxt = ep->nxt;
447     if (ep->evt.strarg != NULL) {
448       csound->Free(csound,ep->evt.strarg);
449       ep->evt.strarg = NULL;
450     }
451     /* push to stack of free event nodes */
452     ep->nxt = csound->freeEvtNodes;
453     csound->freeEvtNodes = ep;
454     ep = nxt;
455   }
456   csound->OrcTrigEvts = NULL;
457 }
458 
cs_beep(CSOUND * csound)459 static inline void cs_beep(CSOUND *csound)
460 {
461     csound->Message(csound, Str("%c\tbeep!\n"), '\a');
462 }
463 
csoundCleanup(CSOUND * csound)464 PUBLIC int csoundCleanup(CSOUND *csound)
465 {
466     void    *p;
467     MYFLT   *maxp;
468     int32   *rngp;
469     uint32_t n;
470 
471     csoundLockMutex(csound->API_lock);
472     if (csound->QueryGlobalVariable(csound,"::UDPCOM")
473         != NULL) csoundUDPServerClose(csound);
474 
475 
476 
477     while (csound->evtFuncChain != NULL) {
478       p = (void*) csound->evtFuncChain;
479       csound->evtFuncChain = ((EVT_CB_FUNC*) p)->nxt;
480       csound->Free(csound,p);
481     }
482 
483     /* check if we have already cleaned up */
484     if (!(csound->engineStatus & CS_STATE_CLN)){
485       csoundUnlockMutex(csound->API_lock);
486       return 0;
487     }
488     /* will not clean up more than once */
489     csound->engineStatus &= ~(CS_STATE_CLN);
490 
491     deactivate_all_notes(csound);
492 
493     if (csound->engineState.instrtxtp &&
494         csound->engineState.instrtxtp[0] &&
495         csound->engineState.instrtxtp[0]->instance &&
496         csound->engineState.instrtxtp[0]->instance->actflg)
497       xturnoff_now(csound, csound->engineState.instrtxtp[0]->instance);
498     delete_pending_rt_events(csound);
499 
500 #ifndef __EMSCRIPTEN__
501     if (csound->event_insert_loop == 1) {
502       csound->event_insert_loop = 0;
503       csound->JoinThread(csound->event_insert_thread);
504       csoundDestroyMutex(csound->init_pass_threadlock);
505       csound->event_insert_thread = 0;
506     }
507 #endif
508 
509     while (csound->freeEvtNodes != NULL) {
510       p = (void*) csound->freeEvtNodes;
511       csound->freeEvtNodes = ((EVTNODE*) p)->nxt;
512       csound->Free(csound,p);
513     }
514 
515     orcompact(csound);
516 
517     corfile_rm(csound, &csound->scstr);
518 
519     /* print stats only if musmon was actually run */
520     /* NOT SURE HOW   ************************** */
521     {
522       csound->Message(csound, Str("end of score.\t\t   overall amps:"));
523       corfile_rm(csound, &csound->expanded_sco);
524       for (n = 0; n < csound->nchnls; n++) {
525         if (csound->smaxamp[n] > csound->omaxamp[n])
526           csound->omaxamp[n] = csound->smaxamp[n];
527         if (csound->maxamp[n] > csound->omaxamp[n])
528           csound->omaxamp[n] = csound->maxamp[n];
529         STA(orngcnt)[n] += (STA(srngcnt)[n] + csound->rngcnt[n]);
530       }
531       for (maxp = csound->omaxamp, n = csound->nchnls; n--; )
532         print_maxamp(csound, *maxp++);
533       if (csound->oparms->outformat != AE_FLOAT) {
534         csound->Message(csound, Str("\n\t   overall samples out of range:"));
535         for (rngp = STA(orngcnt), n = csound->nchnls; n--; )
536           csound->Message(csound, "%9d", *rngp++);
537       }
538       csound->Message(csound, Str("\n%d errors in performance\n"),
539                       csound->perferrcnt);
540       print_benchmark_info(csound, Str("end of performance"));
541       if (csound->print_version) print_csound_version(csound);
542     }
543     /* close line input (-L) */
544     RTclose(csound);
545     /* close MIDI input */
546     MidiClose(csound);
547 
548     /* IV - Feb 03 2005: do not need to call rtclose from here, */
549     /* as sfclosein/sfcloseout will do that. */
550     if (!csound->enableHostImplementedAudioIO) {
551       sfclosein(csound);
552       sfcloseout(csound);
553       if (UNLIKELY(!csound->oparms->sfwrite))
554         csound->Message(csound, Str("no sound written to disk\n"));
555     }
556     /* close any remote.c sockets */
557     if (csound->remoteGlobals) remote_Cleanup(csound);
558     if (UNLIKELY(csound->oparms->ringbell))
559       cs_beep(csound);
560 
561     csoundUnlockMutex(csound->API_lock);
562     return dispexit(csound);    /* hold or terminate the display output     */
563 }
564 
lplay(CSOUND * csound,EVLIST * a)565 int lplay(CSOUND *csound, EVLIST *a)    /* cscore re-entry into musmon */
566 {
567   /* if (csound->musmonGlobals == NULL) */
568   /*  csound->musmonGlobals = csound->Calloc(csound, sizeof(MUSMON_GLOBALS)); */
569   STA(lplayed) = 1;
570   if (!STA(sectno))
571     csound->Message(csound, Str("SECTION %d:\n"), ++STA(sectno));
572   STA(ep) = &a->e[1];                  /* from 1st evlist member */
573   STA(epend) = STA(ep) + a->nevents;    /*   to last              */
574   while (csoundPerform(csound) == 0)  /* play list members      */
575     ;                                 /* NB: empoty loop */
576   return OK;
577 }
578 
579 /* make list to turn on instrs for indef */
580 /* perf called from i0 for execution in playevents */
581 
turnon(CSOUND * csound,TURNON * p)582 int turnon(CSOUND *csound, TURNON *p)
583 {
584   EVTBLK  evt;
585   int insno;
586   memset(&evt, 0, sizeof(EVTBLK));
587   evt.strarg = NULL; evt.scnt = 0;
588   evt.opcod = 'i';
589   evt.pcnt = 3;
590 
591   if (csound->ISSTRCOD(*p->insno)) {
592     char *ss = get_arg_string(csound,*p->insno);
593     insno = csound->strarg2insno(csound,ss,1);
594     if (insno == NOT_AN_INSTRUMENT)
595       return NOTOK;
596   } else insno = *p->insno;
597   evt.p[1] = (MYFLT) insno;
598   evt.p[2] = *p->itime;
599   evt.p[3] = FL(-1.0);
600   evt.c.extra = NULL;
601   return insert_score_event_at_sample(csound, &evt, csound->icurTime);
602 }
603 
604 /* make list to turn on instrs for indef */
605 /* perf called from i0 for execution in playevents */
606 
turnon_S(CSOUND * csound,TURNON * p)607 int turnon_S(CSOUND *csound, TURNON *p)
608 {
609   EVTBLK  evt;
610   int     insno;
611   memset(&evt, 0, sizeof(EVTBLK));
612   evt.strarg = NULL; evt.scnt = 0;
613   evt.opcod = 'i';
614   evt.pcnt = 3;
615   insno = csound->strarg2insno(csound, ((STRINGDAT *)p->insno)->data, 1);
616   if (UNLIKELY(insno == NOT_AN_INSTRUMENT))
617     return NOTOK;
618   evt.p[1] = (MYFLT) insno;
619   evt.p[2] = *p->itime;
620   evt.p[3] = FL(-1.0);
621   evt.c.extra = NULL;
622   return insert_score_event_at_sample(csound, &evt, csound->icurTime);
623 }
624 
625 /* Print current amplitude values, and update section amps. */
626 
print_amp_values(CSOUND * csound,int score_evt)627 static void print_amp_values(CSOUND *csound, int score_evt)
628 {
629   CSOUND        *p = csound;
630   MYFLT         *maxp, *smaxp;
631   uint32        *maxps, *smaxps;
632   int32         *rngp, *srngp;
633   int           n;
634 
635   if (UNLIKELY(STA(segamps) || (p->rngflg && STA(sormsg)))) {
636     if (score_evt > 0)
637       p->Message(p, "B%7.3f ..%7.3f T%7.3f TT%7.3f M:",
638                  p->prvbt - p->beatOffs,  p->curbt - p->beatOffs,
639                  p->curp2 - p->timeOffs,  p->curp2);
640     else
641       p->Message(p, "  rtevent:\t   T%7.3f TT%7.3f M:",
642                  p->curp2 - p->timeOffs,  p->curp2);
643 
644     for (n = p->nchnls, maxp = p->maxamp; n--; )
645       print_maxamp(p, *maxp++);               /* IV - Jul 9 2002 */
646     p->Message(p, "\n");
647     if (UNLIKELY(p->rngflg)) {
648       p->Message(p, Str("\t number of samples out of range:"));
649       for (n = p->nchnls, rngp = p->rngcnt; n--; )
650         p->Message(p, "%9d", *rngp++);
651       p->Message(p, "\n");
652     }
653   }
654   if (p->rngflg) {
655     p->rngflg = 0;
656     STA(srngflg)++;
657   }
658   for (n = p->nchnls,
659          maxp = p->maxamp - 1, smaxp = p->smaxamp - 1,
660          maxps = p->maxpos - 1, smaxps = p->smaxpos - 1,
661          rngp = p->rngcnt, srngp = STA(srngcnt); n--; ) {
662     ++maxps; ++smaxps;
663     if (*++maxp > *++smaxp) {
664       *smaxp = *maxp;
665       *smaxps = *maxps;
666     }
667     *maxp = FL(0.0);
668     *maxps = 0;
669     *srngp++ += *rngp;
670     *rngp++ = 0;
671   }
672 }
673 
674 /* Update overall amplitudes from section values, */
675 /* and optionally print message (1: section end, 2: lplay end). */
676 
section_amps(CSOUND * csound,int enable_msgs)677 static void section_amps(CSOUND *csound, int enable_msgs)
678 {
679   CSOUND        *p = csound;
680   MYFLT         *maxp, *smaxp;
681   uint32        *maxps, *smaxps;
682   int32         *rngp, *srngp;
683   int           n;
684 
685   if (enable_msgs) {
686     if (enable_msgs == 1)
687       p->Message(p, Str("end of section %d\t sect peak amps:"), STA(sectno));
688     else if (enable_msgs == 2)
689       p->Message(p, Str("end of lplay event list\t      peak amps:"));
690     for (n = p->nchnls, maxp = p->smaxamp; n--; )
691       print_maxamp(p, *maxp++);               /* IV - Jul 9 2002 */
692     p->Message(p, "\n");
693     if (UNLIKELY(STA(srngflg))) {
694       p->Message(p, Str("\t number of samples out of range:"));
695       for (n = p->nchnls, srngp = STA(srngcnt); n--; )
696         p->Message(p, "%9d", *srngp++);
697       p->Message(p, "\n");
698     }
699   }
700   STA(srngflg) = 0;
701   for (n = p->nchnls,
702          smaxp = p->smaxamp - 1, maxp = p->omaxamp - 1,
703          smaxps = p->smaxpos - 1, maxps = p->omaxpos - 1,
704          srngp = STA(srngcnt), rngp = STA(orngcnt); n--; ) {
705     ++maxps; ++smaxps;
706     if (UNLIKELY(*++smaxp > *++maxp)) {
707       *maxp = *smaxp;                 /* keep ovrl maxamps */
708       *maxps = *smaxps;               /* And where */
709     }
710     *smaxp = FL(0.0);
711     *smaxps = 0;
712     *rngp++ += *srngp;                /*   and orng counts */
713     *srngp++ = 0;
714   }
715 }
716 
printScoreError(CSOUND * p,int rtEvt,const char * fmt,...)717 static CS_NOINLINE void printScoreError(CSOUND *p, int rtEvt,
718                                         const char *fmt, ...)
719 {
720   va_list args;
721 
722   if (rtEvt)
723     p->Message(p, "\t\t   T%7.3f", p->curp2 - p->timeOffs);
724   else
725     p->Message(p, "\t  B%7.3f", p->curbt - p->beatOffs);
726   va_start(args, fmt);
727   p->ErrMsgV(p, NULL, fmt, args);
728   va_end(args);
729   p->perferrcnt++;
730 }
731 
process_score_event(CSOUND * csound,EVTBLK * evt,int rtEvt)732 static int process_score_event(CSOUND *csound, EVTBLK *evt, int rtEvt)
733 {
734   EVTBLK  *saved_currevent;
735   int     insno, rfd, n;
736 
737   saved_currevent = csound->currevent;
738   csound->currevent = evt;
739   switch (evt->opcod) {                       /* scorevt or Linevt:     */
740   case 'e':           /* quit realtime */
741     csound->event_insert_loop = 0;
742     /* fall through */
743   case 'l':
744   case 's':
745     while (csound->frstoff != NULL) {
746       INSDS *nxt = csound->frstoff->nxtoff;
747       xturnoff_now(csound, csound->frstoff);
748       csound->frstoff = nxt;
749     }
750     csound->currevent = saved_currevent;
751     return (evt->opcod == 'l' ? 3 : (evt->opcod == 's' ? 1 : 2));
752   case 'q':
753     if (csound->ISSTRCOD(evt->p[1]) && evt->strarg) {    /* IV - Oct 31 2002 */
754       if (UNLIKELY((insno = (int) named_instr_find(csound, evt->strarg)) == 0)) {
755         printScoreError(csound, rtEvt,
756                         Str(" - note deleted. instr %s undefined"),
757                         evt->strarg);
758         break;
759       }
760       csound->Message(csound, Str("Setting instrument %s %s\n"),
761                       evt->strarg, (evt->p[3] == 0 ? Str("off") : Str("on")));
762       csound->engineState.instrtxtp[insno]->muted = (int16) evt->p[3];
763     }
764     else {                                        /* IV - Oct 31 2002 */
765       insno = abs((int) evt->p[1]);
766       if (UNLIKELY((unsigned int)(insno-1) >=
767                    (unsigned int) csound->engineState.maxinsno ||
768                    csound->engineState.instrtxtp[insno] == NULL)) {
769         printScoreError(csound, rtEvt,
770                         Str(" - note deleted. instr %d(%d) undefined"),
771                         insno, csound->engineState.maxinsno);
772         break;
773       }
774       csound->Message(csound, Str("Setting instrument %d %s\n"),
775                       insno, (evt->p[3] == 0 ? Str("off") : (Str("on"))));
776       csound->engineState.instrtxtp[insno]->muted = (int16) evt->p[3];
777     }
778     break;
779   case 'i':
780   case 'd':
781     if (csound->ISSTRCOD(evt->p[1]) && evt->strarg) {    /* IV - Oct 31 2002 */
782       if (UNLIKELY((insno = (int) named_instr_find(csound, evt->strarg)) == 0)) {
783         printScoreError(csound, rtEvt,
784                         Str(" - note deleted. instr %s undefined"),
785                         evt->strarg);
786         break;
787       }
788       if (insno<0) {
789         evt->p[1] = insno; insno = -insno;
790       }
791       else if (evt->opcod=='d') evt->p[1]=-insno;
792       if ((rfd = getRemoteInsRfd(csound, insno))) {
793         /* RM: if this note labeled as remote */
794         if (rfd == GLOBAL_REMOT)
795           insGlobevt(csound, evt);  /* RM: do a global send and allow local */
796         else {
797           insSendevt(csound, evt, rfd);/* RM: or send to single remote Csound */
798           break;                       /* RM: and quit */
799         }
800       }
801       evt->p[1] = (MYFLT) insno;
802       if (csound->oparms->Beatmode && !rtEvt && evt->p3orig > FL(0.0))
803         evt->p[3] = evt->p3orig * (MYFLT) csound->ibeatTime/csound->esr;
804       /* else alloc, init, activate */
805       if (UNLIKELY((n = insert(csound, insno, evt)))) {
806         printScoreError(csound, rtEvt,
807                         Str(" - note deleted.  i%d (%s) had %d init errors"),
808                         insno, evt->strarg, n);
809       }
810     }
811     else {                                        /* IV - Oct 31 2002 */
812       insno = abs((int) evt->p[1]);
813       if (UNLIKELY((unsigned int)(insno-1) >=
814                    (unsigned int)csound->engineState.maxinsno ||
815                    csound->engineState.instrtxtp[insno] == NULL)) {
816         printScoreError(csound, rtEvt,
817                         Str(" - note deleted. instr %d(%d) undefined"),
818                         insno, csound->engineState.maxinsno);
819         break;
820       }
821       if ((rfd = getRemoteInsRfd(csound, insno))) {
822         /* RM: if this note labeled as remote  */
823         if (rfd == GLOBAL_REMOT)
824           insGlobevt(csound, evt);    /* RM: do a global send and allow local */
825         else {
826           insSendevt(csound, evt, rfd);/* RM: or send to single remote Csound */
827           break;                      /* RM: and quit              */
828         }
829       }
830       if (evt->p[1] < FL(0.0))         /* if p1 neg,             */
831         infoff(csound, -evt->p[1]);    /*  turnoff any infin cpy */
832       else {
833         if (csound->oparms->Beatmode && !rtEvt && evt->p3orig > FL(0.0))
834           evt->p[3] = evt->p3orig * (MYFLT) csound->ibeatTime/csound->esr;
835         if (UNLIKELY((n = insert(csound, insno, evt)))) {
836           /* else alloc, init, activate */
837           printScoreError(csound, rtEvt,
838                           Str(" - note deleted.  i%d had %d init errors"),
839                           insno, n);
840         }
841       }
842     }
843     break;
844   case 'f':                   /* f event: */
845     {
846       FUNC  *dummyftp;
847       csound->hfgens(csound, &dummyftp, evt, 0); /* construct locally */
848       if (getRemoteInsRfdCount(csound))
849         insGlobevt(csound, evt); /* RM: & optionally send to all remotes      */
850     }
851     break;
852   case 'a':
853     {
854       int64_t kCnt;
855       kCnt = (int64_t) ((double) csound->ekr * (double) evt->p[3] + 0.5);
856       if (kCnt > csound->advanceCnt) {
857         csound->advanceCnt = kCnt;
858         csound->Message(csound,
859                         Str("time advanced %5.3f beats by score request\n"),
860                         evt->p3orig);
861       }
862     }
863     break;
864   }
865   csound->currevent = saved_currevent;
866   return 0;
867 }
868 
869 /* RM: this now broken out for access from process_rt_event & sensevents -- bv  */
process_midi_event(CSOUND * csound,MEVENT * mep,MCHNBLK * chn)870 static void process_midi_event(CSOUND *csound, MEVENT *mep, MCHNBLK *chn)
871 {
872   int n, insno = chn->insno;
873   if (mep->type == NOTEON_TYPE && mep->dat2) {      /* midi note ON: */
874     if (UNLIKELY((n = MIDIinsert(csound, insno, chn, mep)))) {
875       /* alloc,init,activ */
876       csound->Message(csound,
877                       Str("\t\t   T%7.3f - note deleted. "), csound->curp2);
878       {
879         char *name = csound->engineState.instrtxtp[insno]->insname;
880         if (name)
881           csound->Message(csound, Str("instr %s had %d init errors\n"),
882                           name, n);
883         else
884           csound->Message(csound, Str("instr %d had %d init errors\n"),
885                           insno, n);
886       }
887       csound->perferrcnt++;
888     }
889   }
890   else {                                          /* else midi note OFF:    */
891 
892     INSDS *ip = chn->kinsptr[mep->dat1];
893     if (ip == NULL)                               /*  if already off, done  */
894       csound->Mxtroffs++;
895     else if (chn->sustaining) {                   /*  if sustain pedal on   */
896       while (ip != NULL && ip->m_sust)
897         ip = ip->nxtolap;
898       if (ip != NULL) {
899         ip->m_sust = 1;                           /*    let the note ring   */
900         chn->ksuscnt++;
901       } else csound->Mxtroffs++;
902     }
903     else xturnoff(csound, ip);                    /*  else some kind of off */
904   }
905 }
906 
process_rt_event(CSOUND * csound,int sensType)907 static int process_rt_event(CSOUND *csound, int sensType)
908 {
909   EVTBLK  *evt;
910   int     retval, insno, rfd;
911 
912   retval = 0;
913   if (csound->curp2 * csound->esr < (double)csound->icurTime) {
914     csound->curp2 = (double)csound->icurTime/csound->esr;
915     //if(sensType != 2)
916       print_amp_values(csound, 0);
917   }
918   if (sensType == 4) {                  /* RM: Realtime orc event   */
919     EVTNODE *e = csound->OrcTrigEvts;
920     /* RM: Events are sorted on insertion, so just check the first */
921     evt = &(e->evt);
922     insno = MYFLT2LONG(evt->p[1]);
923     if ((rfd = getRemoteInsRfd(csound, insno))) {
924       if (rfd == GLOBAL_REMOT)
925         insGlobevt(csound, evt);       /* RM: do a global send and allow local */
926       else
927         insSendevt(csound, evt, rfd);  /* RM: or send to single remote Csound */
928       return 0;
929     }
930     /* pop from the list */
931     csound->OrcTrigEvts = e->nxt;
932     retval = process_score_event(csound, evt, 1);
933     if (evt->strarg != NULL) {
934       csound->Free(csound, evt->strarg);
935       evt->strarg = NULL;
936     }
937     /* push back to free alloc stack so it can be reused later */
938     e->nxt = csound->freeEvtNodes;
939     csound->freeEvtNodes = e;
940   }
941   else if (sensType == 2) {                      /* Midievent:    */
942     MEVENT *mep;
943     MCHNBLK *chn;
944     /* realtime or Midifile  */
945     mep = csound->midiGlobals->Midevtblk;
946     chn = csound->m_chnbp[mep->chan];
947     if ((rfd = getRemoteChnRfd(csound, mep->chan+1))) { /* RM: USE CHAN + 1 */
948       if (rfd == GLOBAL_REMOT)
949         MIDIGlobevt(csound, mep);
950       else MIDIsendevt(csound, mep, rfd);
951       return 0;
952     }
953     else  /* RM: this part is broken out  -- bv  */
954       process_midi_event(csound, mep, chn);
955   }
956   return retval;
957 }
958 
959 #define RNDINT64(x) ((int64_t) ((double) (x) + ((double) (x) < 0.0 ? -0.5 : 0.5)))
960 
961 extern  int     sensMidi(CSOUND *);
962 
963 /* sense events for one k-period            */
964 /* return value is one of the following:    */
965 /*   0: continue performance                */
966 /*   1: terminate (e.g. end of MIDI file)   */
967 /*   2: normal end of score                 */
sensevents(CSOUND * csound)968 int sensevents(CSOUND *csound)
969 {
970   EVTBLK  *e;
971   OPARMS  *O = csound->oparms;
972   int     retval =  0, sensType;
973   int     conn, *sinp, end_check=1;
974 
975   csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
976   if (UNLIKELY(data && data->status == CSDEBUG_STATUS_STOPPED)) {
977     return 0; /* don't process events if we're in debug mode and stopped */
978   }
979   if (UNLIKELY(csound->MTrkend && O->termifend)) {   /* end of MIDI file:  */
980     deactivate_all_notes(csound);
981     csound->Message(csound, Str("terminating.\n"));
982     return 1;                         /* abort with perf incomplete */
983   }
984   /* if turnoffs pending, remove any expired instrs */
985   RT_SPIN_TRYLOCK
986   if (UNLIKELY(csound->frstoff != NULL)) {
987     double  tval;
988     /* the following comparisons must match those in schedofftim() */
989     if (O->Beatmode) {
990       tval = csound->curBeat + (0.505 * csound->curBeat_inc);
991       if (csound->frstoff->offbet <= tval) beatexpire(csound, tval);
992     }
993     else {
994       tval = ((double)csound->icurTime + csound->ksmps * 0.505)/csound->esr;
995       if (csound->frstoff->offtim <= tval)
996         timexpire(csound, tval);
997     }
998   }
999   RT_SPIN_UNLOCK
1000 
1001   e = &(csound->evt);
1002   if (--(csound->cyclesRemaining) <= 0) { /* if done performing score segment: */
1003     if (!csound->cyclesRemaining) {
1004       csound->prvbt = csound->curbt;      /* update beats and times */
1005       csound->curbt = csound->nxtbt;
1006       csound->curp2 = csound->nxtim;
1007       print_amp_values(csound, 1);        /* print amplitudes for this segment */
1008     }
1009     else                                  /* this should only happen at */
1010       csound->cyclesRemaining = 0;        /* beginning of performance   */
1011   }
1012 
1013  retest:
1014   /* in daemon mode, we will ignore the end of
1015      the score, but allow for a realtime event
1016      to stop Csound */
1017     while (csound->cyclesRemaining <= 0 &&
1018            (e->opcod != 'e' || !csound->oparms->daemon)){
1019       /* read each score event:     */
1020     if (e->opcod != '\0') {
1021       /* if there is a pending score event, handle it now */
1022       switch (e->opcod) {
1023       case 'e':                     /* end of score, */
1024       case 'l':                     /* lplay list,   */
1025       case 's':                     /* or section:   */
1026         if (csound->frstoff != NULL) {    /* if still have notes
1027                                              with finite length, wait
1028                                              until all are turned off */
1029           RT_SPIN_TRYLOCK
1030           csound->nxtim = csound->frstoff->offtim;
1031           csound->nxtbt = csound->frstoff->offbet;
1032           RT_SPIN_UNLOCK
1033           break;
1034         }
1035         /* end of: 1: section, 2: score, 3: lplay list */
1036         retval = (e->opcod == 'l' ? 3 : (e->opcod == 's' ? 1 : 2));
1037         if(csound->oparms->realtime && end_check == 1) {
1038           csoundSleep(5); // wait for 5ms for any first events to go through
1039           end_check = 0;  // reset first time check
1040           goto retest;    // loop back
1041         }
1042         goto scode;
1043       default:                            /* q, i, f, a:              */
1044         process_score_event(csound, e, 0);/*   handle event now       */
1045         e->opcod = '\0';                  /*   and get next one       */
1046         continue;
1047       }
1048     }
1049     else {
1050       /* else read next score event */
1051       if (UNLIKELY(O->usingcscore)) {       /*    get next lplay event  */
1052         /* FIXME: this may be non-portable */
1053         if (STA(ep) < STA(epend))           /* nxt event    */
1054           memcpy((void*) e, (void*) &((*STA(ep)++)->strarg), sizeof(EVTBLK));
1055         else                                /* else lcode   */
1056           memcpy((void*) e, (void*) &(STA(lsect)->strarg), sizeof(EVTBLK));
1057       } else
1058         if (!(rdscor(csound, e))){
1059           /* or rd nxt evt from scstr */
1060           e->opcod = 'e';
1061         }
1062       csound->currevent = e;
1063 
1064       switch (e->opcod) {
1065       case 'w':
1066         if (!O->Beatmode)                   /* Not beatmode: read 'w' */
1067           settempo(csound, (double)e->p2orig); /* to init the tempo   */
1068         continue;                           /*   for this section     */
1069       case 'q':
1070       case 'i':
1071       case 'd':
1072       case 'f':
1073       case 'a':
1074         csound->nxtim = (double) e->p[2] + csound->timeOffs;
1075         csound->nxtbt = (double) e->p2orig + csound->beatOffs;
1076         if (e->opcod=='i'||e->opcod=='d')
1077           if (UNLIKELY(csound->oparms->odebug))
1078             csound->Message(csound, "new event: %16.13lf %16.13lf\n",
1079                             csound->nxtim, csound->nxtbt);
1080         break;
1081       case 'e':
1082       case 'l':
1083       case 's':
1084         continue;
1085       default:
1086         csound->Message(csound,
1087                         Str("error in score.  illegal opcode %c (ASCII %d)\n"),
1088                         e->opcod, e->opcod);
1089         csound->perferrcnt++;
1090         continue;
1091       }
1092     }
1093     /* calculate the number of k-periods remaining until next event */
1094     if (!O->sampleAccurate) {
1095       if (O->Beatmode)
1096         csound->cyclesRemaining =
1097           RNDINT64((csound->nxtbt - csound->curBeat) / csound->curBeat_inc);
1098       else {
1099         csound->cyclesRemaining =
1100           RNDINT64((csound->nxtim*csound->esr - csound->icurTime)/csound->ksmps);
1101         csound->nxtim =
1102           (csound->cyclesRemaining*csound->ksmps+csound->icurTime)/csound->esr;
1103       }
1104     }
1105     else {
1106       /* VL 30-11-2012
1107          new code for sample-accurate timing needs to truncate cyclesRemaining
1108       */
1109       if (O->Beatmode)
1110         csound->cyclesRemaining = (int64_t)
1111           ((csound->nxtbt - csound->curBeat) / csound->curBeat_inc);
1112       else {
1113         csound->cyclesRemaining = (int64_t)
1114           FLOOR((csound->nxtim*csound->esr -
1115                  csound->icurTime+csound->onedsr*0.5) / csound->ksmps);
1116         csound->nxtim =
1117           (csound->cyclesRemaining*csound->ksmps+csound->icurTime)/csound->esr;
1118       }
1119     }
1120   }
1121 
1122   /* handle any real time events now: */
1123   /* FIXME: the initialisation pass of real time */
1124   /*   events is not sorted by instrument number */
1125   /*   (although it never was sorted anyway...)  */
1126   if (UNLIKELY(O->RTevents || getRemoteSocksIn(csound))) {
1127     int nrecvd;
1128     /* run all registered callback functions */
1129     if (csound->evtFuncChain != NULL && !csound->advanceCnt) {
1130       EVT_CB_FUNC *fp = (EVT_CB_FUNC*) csound->evtFuncChain;
1131       do {
1132         fp->func(csound, fp->userData);
1133         fp = fp->nxt;
1134       } while (fp != NULL);
1135     }
1136 
1137     /* check for pending real time events */
1138     while (csound->OrcTrigEvts != NULL &&
1139            csound->OrcTrigEvts->start_kcnt <=
1140            (uint32) csound->global_kcounter) {
1141 
1142       if ((retval = process_rt_event(csound, 4)) != 0){
1143         goto scode;
1144       }
1145     }
1146     /* RM */
1147     if ((sinp = getRemoteSocksIn(csound))) {
1148       while ((conn = *sinp++)) {
1149         while ((nrecvd = SVrecv(csound, conn,
1150                                 (void*)&(csound->SVrecvbuf),
1151                                 sizeof(REMOT_BUF) )) > 0) {
1152           int lentot = 0;
1153           do {
1154             REMOT_BUF *bp = (REMOT_BUF*)((char*)(&(csound->SVrecvbuf))+lentot);
1155 
1156             if (bp->type == SCOR_EVT) {
1157               EVTBLK *evt = (EVTBLK*)bp->data;
1158               evt->p[2] = (double)csound->icurTime/csound->esr;
1159               if ((retval = process_score_event(csound, evt, 1)) != 0) {
1160                 e->opcod = evt->opcod;        /* pass any s, e, or l */
1161 
1162                 goto scode;
1163               }
1164             }
1165             else if (bp->type == MIDI_EVT) {
1166               MEVENT *mep = (MEVENT *)bp->data;
1167               MCHNBLK *chn = csound->m_chnbp[mep->chan];
1168               process_midi_event(csound, mep, chn);
1169             }
1170             else if (bp->type == MIDI_MSG) {
1171               MEVENT *mep = (MEVENT *)bp->data;
1172               if (UNLIKELY(mep->type == 0xFF && mep->dat1 == 0x2F)) {
1173                 csound->MTrkend = 1;                     /* catch a Trkend    */
1174                 csound->Message(csound, "SERVER%c: ", remoteID(csound));
1175                 csound->Message(csound, "caught a Trkend\n");
1176                 /*csoundCleanup(csound);
1177                   exit(0);*/
1178                 return 2;  /* end of performance */
1179               }
1180               else m_chanmsg(csound, mep);               /* or a chan msg     */
1181             }
1182             lentot+=bp->len;
1183           } while (lentot < nrecvd);
1184         }
1185       }
1186     }
1187 
1188     /* MIDI note messages */
1189     if (O->Midiin || O->FMidiin)
1190       while ((sensType = sensMidi(csound)) != 0)
1191         if ((retval = process_rt_event(csound, sensType)) != 0) {
1192           goto scode;
1193         }
1194   }
1195   /* no score event at this time, return to continue performance */
1196 
1197   return 0;
1198  scode:
1199   /* end of section (retval == 1), score (retval == 2), */
1200   /* or lplay list (retval == 3) */
1201   if (getRemoteInsRfdCount(csound))
1202     insGlobevt(csound, e);/* RM: send s,e, or l to any remotes */
1203   e->opcod = '\0';
1204   if (retval == 3) {
1205     section_amps(csound, 2);
1206     return 1;
1207   }
1208   /* for s, or e after s */
1209   if (retval == 1 || (retval == 2 && STA(sectno) > 1)) {
1210     delete_pending_rt_events(csound);
1211     if (O->Beatmode)
1212       csound->curbt = csound->curBeat;
1213     csound->curp2 = csound->nxtim =
1214       csound->timeOffs = csound->icurTime/csound->esr;
1215     csound->prvbt = csound->nxtbt = csound->beatOffs = csound->curbt;
1216     section_amps(csound, 1);
1217   }
1218   else{
1219     section_amps(csound, 0);
1220   }
1221   if (retval == 1) {                        /* if s code,        */
1222     RT_SPIN_TRYLOCK
1223     orcompact(csound);                      /*   rtn inactiv spc */
1224     if (csound->actanchor.nxtact == NULL)   /*   if no indef ins */
1225       rlsmemfiles(csound);                  /*    purge memfiles */
1226     csound->Message(csound, Str("SECTION %d:\n"), ++STA(sectno));
1227     RT_SPIN_UNLOCK
1228     goto retest;                            /*   & back for more */
1229   }
1230 
1231   return retval;                   /* done with entire score */
1232 }
1233 
time2kcnt(CSOUND * csound,double tval)1234 static inline uint64_t time2kcnt(CSOUND *csound, double tval)
1235 {
1236   if (tval > 0.0) {
1237     tval *= (double) csound->ekr;
1238 #ifdef HAVE_C99
1239     return (uint64_t) llrint(tval);
1240 #else
1241     return (uint64_t) (tval + 0.5);
1242 #endif
1243   }
1244   return 0UL;
1245 }
1246 
1247 
1248 /* Schedule new score event to be played. 'time_ofs' is the amount of */
1249 /* time in seconds to add to evt->p[2] to get the actual start time   */
1250 /* of the event (measured from the beginning of performance, and not  */
1251 /* section) in seconds.                                               */
1252 /* Required parameters in 'evt':                                      */
1253 /*   char   *strarg   string argument of event (NULL if none)         */
1254 /*   char   opcod     event opcode (a, e, f, i, l, q, s)              */
1255 /*   int16  pcnt      number of p-fields (>=3 for q, i, a; >=4 for f) */
1256 /*   MYFLT  p[]       array of p-fields, p[1]..p[pcnt] should be set  */
1257 /*  p2orig and p3orig are calculated from p[2] and p[3].              */
1258 /* The contents of 'evt', including the string argument, need not be  */
1259 /* preserved after calling this function, as a copy of the event is   */
1260 /* made.                                                              */
1261 /* Return value is zero on success.                                   */
1262 
insert_score_event_at_sample(CSOUND * csound,EVTBLK * evt,int64_t time_ofs)1263 int insert_score_event_at_sample(CSOUND *csound, EVTBLK *evt, int64_t time_ofs)
1264 {
1265   double        start_time;
1266   EVTNODE       *e, *prv;
1267   CSOUND        *st = csound;
1268   MYFLT         *p;
1269   uint32        start_kcnt;
1270   int           i, retval;
1271 
1272   retval = -1;
1273   /* make a copy of the event... */
1274   if (csound->freeEvtNodes != NULL) {             /* pop alloc from stack */
1275     e = csound->freeEvtNodes;                     /*   if available       */
1276     csound->freeEvtNodes = e->nxt;
1277   }
1278   else {
1279     e = (EVTNODE*) csound->Calloc(csound, sizeof(EVTNODE)); /* or alloc new one */
1280     if (UNLIKELY(e == NULL))
1281       return CSOUND_MEMORY;
1282   }
1283   if (evt->strarg != NULL) {  /* copy string argument if present */
1284     /* NEED TO COPY WHOLE STRING STRUCTURE */
1285     int n = evt->scnt;
1286     char *p = evt->strarg;
1287     while (n--) { p += strlen(p)+1; };
1288     e->evt.strarg = (char*) csound->Malloc(csound, (size_t) (p-evt->strarg)+1);
1289     if (UNLIKELY(e->evt.strarg == NULL)) {
1290       csound->Free(csound, e);
1291       return CSOUND_MEMORY;
1292     }
1293     memcpy(e->evt.strarg, evt->strarg, p-evt->strarg+1 );
1294     e->evt.scnt = evt->scnt;
1295   }
1296   e->evt.pinstance = evt->pinstance;
1297   e->evt.opcod = evt->opcod;
1298   e->evt.pcnt = evt->pcnt;
1299   p = &(e->evt.p[0]);
1300   i = 0;
1301   while (++i <= evt->pcnt)    /* copy p-field list */
1302     p[i] = evt->p[i];
1303   /* ...and use the copy from now on */
1304   evt = &(e->evt);
1305 
1306   /* check for required p-fields */
1307   switch (evt->opcod) {
1308   case 'f':
1309     if (UNLIKELY((evt->pcnt < 4) && (p[1]>0)))
1310       goto pfld_err;
1311     goto cont;
1312   case 'i':
1313   case 'q':
1314   case 'a':
1315     if (UNLIKELY(evt->pcnt < 3))
1316       goto pfld_err;
1317     /* fall through */
1318   case 'd':
1319   cont:
1320     /* calculate actual start time in seconds and k-periods */
1321     start_time = (double) p[2] + (double)time_ofs/csound->esr;
1322     start_kcnt = time2kcnt(csound, start_time);
1323     /* correct p2 value for section offset */
1324     p[2] = (MYFLT) (start_time - st->timeOffs);
1325     if (p[2] < FL(0.0))
1326       p[2] = FL(0.0);
1327     /* start beat: this is possibly wrong */
1328     evt->p2orig = (MYFLT) (((start_time - st->icurTime/st->esr) /
1329                             st->ibeatTime)
1330                            + (st->curBeat - st->beatOffs));
1331     if (evt->p2orig < FL(0.0))
1332       evt->p2orig = FL(0.0);
1333     evt->p3orig = p[3];
1334     break;
1335   default:
1336     start_kcnt = 0UL;   /* compiler only */
1337   }
1338 
1339   switch (evt->opcod) {
1340   case 'i':                         /* note event */
1341   case 'd':
1342     /* calculate the length in beats */
1343     if (evt->p3orig > FL(0.0))
1344       evt->p3orig = (MYFLT) ((double) evt->p3orig / st->ibeatTime);
1345     /* fall through */
1346   case 'q':                         /* mute instrument */
1347     /* check for a valid instrument number or name */
1348     if (evt->opcod=='d') {
1349       if (evt->strarg != NULL && csound->ISSTRCOD(p[1])) {
1350         i = (int) named_instr_find(csound, evt->strarg);
1351         //printf("d opcode %s -> %d\n", evt->strarg, i);
1352         p[1] = -i;
1353       }
1354       else {
1355         i = (int) fabs((double) p[1]);
1356         p[1] = -i;
1357       }
1358     }
1359     else if (evt->strarg != NULL && csound->ISSTRCOD(p[1])) {
1360       i = (int) named_instr_find(csound, evt->strarg);
1361       if (i<0) {p[1]=i; i= -i;}
1362     }
1363     else
1364       i = (int) fabs((double) p[1]);
1365     if (UNLIKELY((unsigned int) (i - 1) >=
1366                  (unsigned int) csound->engineState.maxinsno ||
1367                  csound->engineState.instrtxtp[i] == NULL)) {
1368       if (i > INT32_MAX-10)
1369         csoundMessage(csound, "%s",
1370                       Str("insert_score_event(): invalid named instrument\n"));
1371       else
1372         csoundMessage(csound, Str("insert_score_event(): invalid instrument "
1373                                   "number or name %d\n" ), i);
1374       goto err_return;
1375     }
1376     break;
1377   case 'a':                         /* advance score time */
1378     /* calculate the length in beats */
1379     evt->p3orig = (MYFLT) ((double) evt->p3orig *csound->esr/ st->ibeatTime);
1380     /* fall through */
1381   case 'f':                         /* function table */
1382     break;
1383   case 'e':                         /* end of score, */
1384   case 'l':                         /*   lplay list, */
1385   case 's':                         /*   section:    */
1386     start_time = (double)time_ofs/csound->esr;
1387     if (evt->pcnt >= 2)
1388       start_time += (double) p[2];
1389     evt->pcnt = 0;
1390     start_kcnt = time2kcnt(csound, start_time);
1391     break;
1392   default:
1393     csoundMessage(csound, Str("insert_score_event(): unknown opcode: %c\n"),
1394                   evt->opcod);
1395     goto err_return;
1396   }
1397   /* queue new event */
1398   e->start_kcnt = start_kcnt;
1399   prv = csound->OrcTrigEvts;
1400   /* if list is empty, or at beginning of list: */
1401   if (prv == NULL || start_kcnt < prv->start_kcnt) {
1402     e->nxt = prv;
1403     csound->OrcTrigEvts = e;
1404   }
1405   else {                                      /* otherwise sort by time */
1406     while (prv->nxt != NULL && start_kcnt >= prv->nxt->start_kcnt)
1407       prv = prv->nxt;
1408     e->nxt = prv->nxt;
1409     prv->nxt = e;
1410   }
1411   /* Make sure sensevents() looks for RT events */
1412   csound->oparms->RTevents = 1;
1413   return 0;
1414 
1415  pfld_err:
1416   csoundMessage(csound, Str("insert_score_event(): insufficient p-fields\n"));
1417  err_return:
1418   /* clean up */
1419   if (e->evt.strarg != NULL)
1420     csound->Free(csound, e->evt.strarg);
1421   e->evt.strarg = NULL;
1422   e->nxt = csound->freeEvtNodes;
1423   csound->freeEvtNodes = e;
1424   return retval;
1425 }
1426 
insert_score_event(CSOUND * csound,EVTBLK * evt,double time_ofs)1427 int insert_score_event(CSOUND *csound, EVTBLK *evt, double time_ofs)
1428 {
1429   return insert_score_event_at_sample(csound, evt, time_ofs*csound->esr);
1430 }
1431 
1432 /* called by csoundRewindScore() to reset performance to time zero */
1433 
musmon_rewind_score(CSOUND * csound)1434 void musmon_rewind_score(CSOUND *csound)
1435 {
1436   /* deactivate all currently playing notes */
1437   deactivate_all_notes(csound);
1438   /* flush any pending real time events */
1439   delete_pending_rt_events(csound);
1440 
1441   if (csound->global_kcounter != 0L) {
1442     /* reset score time */
1443     csound->global_kcounter = csound->kcounter = 0L;
1444     csound->nxtbt = csound->curbt = csound->prvbt = 0.0;
1445     csound->nxtim = csound->curp2 = 0.0;
1446     csound->beatOffs = csound->timeOffs = 0.0;
1447     csound->curBeat  = 0.0;
1448     csound->icurTime = 0L;
1449     csound->cyclesRemaining = 0;
1450     csound->evt.strarg = NULL;
1451     csound->evt.scnt = 0;
1452     csound->evt.opcod  = '\0';
1453     /* reset tempo */
1454     if (csound->oparms->Beatmode)
1455       settempo(csound, csound->oparms->cmdTempo);
1456     else
1457       settempo(csound, 60.0);
1458     /* update section/overall amplitudes, reset to section 1 */
1459     section_amps(csound, 1);
1460     STA(sectno) = 1;
1461     csound->Message(csound, Str("SECTION %d:\n"), STA(sectno));
1462   }
1463 
1464   /* apply score offset if non-zero */
1465   csound->advanceCnt = 0;
1466   if (csound->csoundScoreOffsetSeconds_ > FL(0.0))
1467     csoundSetScoreOffsetSeconds(csound, csound->csoundScoreOffsetSeconds_);
1468   if (csound->scstr)
1469     corfile_rewind(csound->scstr);
1470   else csound->Warning(csound, Str("cannot rewind score: no score in memory\n"));
1471 }
1472 
1473 /**
1474  * Register a function to be called once in every control period
1475  * by sensevents(). Any number of functions may be registered,
1476  * and will be called in the order of registration.
1477  * The callback function takes two arguments: the Csound instance
1478  * pointer, and the userData pointer as passed to this function.
1479  * Returns zero on success.
1480  */
csoundRegisterSenseEventCallback(CSOUND * csound,void (* func)(CSOUND *,void *),void * userData)1481 PUBLIC int csoundRegisterSenseEventCallback(CSOUND *csound,
1482                                             void (*func)(CSOUND *, void *),
1483                                             void *userData)
1484 {
1485   EVT_CB_FUNC *fp = (EVT_CB_FUNC*) csound->evtFuncChain;
1486 
1487   if (fp == NULL) {
1488     fp = (EVT_CB_FUNC*) csound->Calloc(csound, sizeof(EVT_CB_FUNC));
1489     csound->evtFuncChain = (void*) fp;
1490   }
1491   else {
1492     while (fp->nxt != NULL)
1493       fp = fp->nxt;
1494     fp->nxt = (EVT_CB_FUNC*) csound->Calloc(csound, sizeof(EVT_CB_FUNC));
1495     fp = fp->nxt;
1496   }
1497   if (UNLIKELY(fp == NULL))
1498     return CSOUND_MEMORY;
1499   fp->func = func;
1500   fp->userData = userData;
1501   fp->nxt = NULL;
1502   csound->oparms->RTevents = 1;
1503 
1504   return 0;
1505 }
1506