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