1 /*
2 * C S O U N D
3 *
4 * An auto-extensible system for making music on computers
5 * by means of software alone.
6 *
7 * Copyright (C) 2001-2006 Michael Gogins, Matt Ingalls, John D. Ramsdell,
8 * John P. ffitch, Istvan Varga, Victor Lazzarini,
9 * Steven Yi
10 *
11 * L I C E N S E
12 *
13 * This software is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 *
18 * This software is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this software; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 *
27 */
28
29 //#ifdef __cplusplus
30 //extern "C" {
31 //#endif
32
33 #if defined(HAVE_UNISTD_H) || defined (__unix) || defined(__unix__)
34 #include <unistd.h>
35 #endif
36 #include "csoundCore.h"
37 #include "csmodule.h"
38 #include "corfile.h"
39 #include "csGblMtx.h"
40 #include <stdarg.h>
41 #include <signal.h>
42 #include <time.h>
43 #include <ctype.h>
44 #include <limits.h>
45 #ifdef HAVE_SYS_TYPES_H
46 # include <sys/types.h>
47 #endif
48 #if defined(WIN32) && !defined(__CYGWIN__)
49 # include <winsock2.h>
50 # include <windows.h>
51 #endif
52 #include <math.h>
53 #include "oload.h"
54 #include "fgens.h"
55 #include "namedins.h"
56 #include "pvfileio.h"
57 #include "fftlib.h"
58 #include "lpred.h"
59 #include "cs_par_base.h"
60 #include "cs_par_orc_semantics.h"
61 #include "namedins.h"
62 //#include "cs_par_dispatch.h"
63 #include "find_opcode.h"
64
65 #if defined(linux) || defined(__FreeBSD__) || defined(__HAIKU__)|| defined(__EMSCRIPTEN__)||defined(__CYGWIN__)
66 #define PTHREAD_SPINLOCK_INITIALIZER 0
67 #endif
68
69 #if defined(__FreeBSD__)
70 #include <sys/sysctl.h>
71 #endif
72
73 #include "csound_standard_types.h"
74
75 #include "csdebug.h"
76 #include <time.h>
77
78 extern void allocate_message_queue(CSOUND *csound);
79 static void SetInternalYieldCallback(CSOUND *, int (*yieldCallback)(CSOUND *));
80 int playopen_dummy(CSOUND *, const csRtAudioParams *parm);
81 void rtplay_dummy(CSOUND *, const MYFLT *outBuf, int nbytes);
82 int recopen_dummy(CSOUND *, const csRtAudioParams *parm);
83 int rtrecord_dummy(CSOUND *, MYFLT *inBuf, int nbytes);
84 void rtclose_dummy(CSOUND *);
85 int audio_dev_list_dummy(CSOUND *, CS_AUDIODEVICE *, int);
86 int midi_dev_list_dummy(CSOUND *, CS_MIDIDEVICE *, int);
87 static void csoundDefaultMessageCallback(CSOUND *, int, const char *, va_list);
88 static int defaultCsoundYield(CSOUND *);
89 static int csoundDoCallback_(CSOUND *, void *, unsigned int);
90 static void reset(CSOUND *);
91 static int csoundPerformKsmpsInternal(CSOUND *csound);
92 void csoundTableSetInternal(CSOUND *csound, int table, int index,
93 MYFLT value);
94 static INSTRTXT **csoundGetInstrumentList(CSOUND *csound);
95 uint64_t csoundGetKcounter(CSOUND *csound);
96 static void set_util_sr(CSOUND *csound, MYFLT sr);
97 static void set_util_nchnls(CSOUND *csound, int nchnls);
98
99 extern void cscoreRESET(CSOUND *);
100 extern void memRESET(CSOUND *);
101 extern MYFLT csoundPow2(CSOUND *csound, MYFLT a);
102 extern int csoundInitStaticModules(CSOUND *);
103 extern void close_all_files(CSOUND *);
104 extern void csoundInputMessageInternal(CSOUND *csound, const char *message);
105 extern int isstrcod(MYFLT );
106 extern int fterror(const FGDATA *ff, const char *s, ...);
107 PUBLIC int csoundErrCnt(CSOUND *);
108 void (*msgcallback_)(CSOUND *, int, const char *, va_list) = NULL;
109 INSTRTXT *csoundGetInstrument(CSOUND *csound, int insno, const char *name);
110
111 void csoundDebuggerBreakpointReached(CSOUND *csound);
112 void message_dequeue(CSOUND *csound);
113
114 extern OENTRY opcodlst_1[];
115
116 #define STRING_HASH(arg) STRSH(arg)
117 #define STRSH(arg) #arg
118
print_csound_version(CSOUND * csound)119 void print_csound_version(CSOUND* csound)
120 {
121 #ifdef USE_DOUBLE
122 #ifdef BETA
123 csound->Message(csound,
124 Str("--Csound version %s beta (double samples) %s\n"
125 "[commit: %s]\n"),
126 CS_PACKAGE_VERSION, CS_PACKAGE_DATE,
127 STRING_HASH(GIT_HASH_VALUE));
128 #else
129 csound->Message(csound, Str("--Csound version %s (double samples) %s\n"
130 "[commit: %s]\n"),
131 CS_PACKAGE_VERSION, CS_PACKAGE_DATE
132 , STRING_HASH(GIT_HASH_VALUE));
133 #endif
134 #else
135 #ifdef BETA
136 csound->Message(csound, Str("--Csound version %s beta (float samples) %s\n"
137 "[commit: %s]\n"),
138 CS_PACKAGE_VERSION, CS_PACKAGE_DATE,
139 STRING_HASH(GIT_HASH_VALUE));
140 #else
141 csound->Message(csound, Str("--Csound version %s (float samples) %s\n"
142 "[commit: %s]\n"),
143 CS_PACKAGE_VERSION, CS_PACKAGE_DATE,
144 STRING_HASH(GIT_HASH_VALUE));
145 #endif
146 #endif
147 }
148
free_opcode_table(CSOUND * csound)149 static void free_opcode_table(CSOUND* csound) {
150 int i;
151 CS_HASH_TABLE_ITEM* bucket;
152 CONS_CELL* head;
153
154 for (i = 0; i < csound->opcodes->table_size; i++) {
155 bucket = csound->opcodes->buckets[i];
156
157 while (bucket != NULL) {
158 head = bucket->value;
159 cs_cons_free_complete(csound, head);
160 bucket = bucket->next;
161 }
162 }
163
164 cs_hash_table_free(csound, csound->opcodes);
165 }
create_opcode_table(CSOUND * csound)166 static void create_opcode_table(CSOUND *csound)
167 {
168
169 int err;
170
171 if (csound->opcodes != NULL) {
172 free_opcode_table(csound);
173 }
174 csound->opcodes = cs_hash_table_create(csound);
175
176 /* Basic Entry1 stuff */
177 err = csoundAppendOpcodes(csound, &(opcodlst_1[0]), -1);
178
179 if (UNLIKELY(err))
180 csoundDie(csound, Str("Error allocating opcode list"));
181
182 }
183
184 #define MAX_MODULES 64
185
module_list_add(CSOUND * csound,char * drv,char * type)186 static void module_list_add(CSOUND *csound, char *drv, char *type){
187 MODULE_INFO **modules =
188 (MODULE_INFO **) csoundQueryGlobalVariable(csound, "_MODULES");
189 if (modules != NULL){
190 int i = 0;
191 while (modules[i] != NULL && i < MAX_MODULES) {
192 if (!strcmp(modules[i]->module, drv)) return;
193 i++;
194 }
195 modules[i] = (MODULE_INFO *) csound->Malloc(csound, sizeof(MODULE_INFO));
196 strNcpy(modules[i]->module, drv, 11);
197 strNcpy(modules[i]->type, type, 11);
198 }
199 }
200
csoundGetRandSeed(CSOUND * csound,int which)201 static int csoundGetRandSeed(CSOUND *csound, int which){
202 if (which > 1) return csound->randSeed1;
203 else return csound->randSeed2;
204 }
205
csoundGetStrsets(CSOUND * csound,long p)206 static char *csoundGetStrsets(CSOUND *csound, long p){
207 if (csound->strsets == NULL) return NULL;
208 else return csound->strsets[p];
209 }
210
csoundGetStrsmax(CSOUND * csound)211 static int csoundGetStrsmax(CSOUND *csound){
212 return csound->strsmax;
213 }
214
csoundGetOParms(CSOUND * csound,OPARMS * p)215 static void csoundGetOParms(CSOUND *csound, OPARMS *p){
216 memcpy(p, csound->oparms, sizeof(OPARMS));
217 }
218
csoundGetDitherMode(CSOUND * csound)219 static int csoundGetDitherMode(CSOUND *csound){
220 return csound->dither_output;
221 }
222
223 #include "Opcodes/zak.h"
csoundGetZakBounds(CSOUND * csound,MYFLT ** zkstart)224 static int csoundGetZakBounds(CSOUND *csound, MYFLT **zkstart){
225 ZAK_GLOBALS *zz;
226 zz = (ZAK_GLOBALS*) csound->QueryGlobalVariable(csound, "_zak_globals");
227 if (zz==NULL) {
228 *zkstart = NULL;
229 return -1;
230 }
231 *zkstart = zz->zkstart;
232 return zz->zklast;
233 }
234
csoundGetZaBounds(CSOUND * csound,MYFLT ** zastart)235 static int csoundGetZaBounds(CSOUND *csound, MYFLT **zastart){
236 ZAK_GLOBALS *zz;
237 zz = (ZAK_GLOBALS*) csound->QueryGlobalVariable(csound, "_zak_globals");
238 if (zz==NULL) {
239 *zastart = NULL;
240 return -1;
241 }
242 *zastart = zz->zastart;
243 return zz->zalast;
244 }
245
csoundGetReinitFlag(CSOUND * csound)246 static int csoundGetReinitFlag(CSOUND *csound){
247 return csound->reinitflag;
248 }
249
csoundGetTieFlag(CSOUND * csound)250 static int csoundGetTieFlag(CSOUND *csound){
251 return csound->tieflag;
252 }
253
csoundSystemSr(CSOUND * csound,MYFLT val)254 MYFLT csoundSystemSr(CSOUND *csound, MYFLT val) {
255 if (val > 0) csound->_system_sr = val;
256 return csound->_system_sr;
257 }
258
259 static const CSOUND cenviron_ = {
260 /* attributes */
261 csoundGetSr,
262 csoundGetKr,
263 csoundGetKsmps,
264 csoundGetNchnls,
265 csoundGetNchnlsInput,
266 csoundGet0dBFS,
267 csoundGetKcounter,
268 csoundGetCurrentTimeSamples,
269 csoundGetInputBufferSize,
270 csoundGetOutputBufferSize,
271 csoundGetInputBuffer,
272 csoundGetOutputBuffer,
273 csoundSetDebug,
274 csoundGetDebug,
275 csoundGetSizeOfMYFLT,
276 csoundGetOParms,
277 csoundGetEnv,
278 /* message printout */
279 csoundMessage,
280 csoundMessageS,
281 csoundMessageV,
282 csoundGetMessageLevel,
283 csoundSetMessageLevel,
284 csoundSetMessageCallback,
285 /* Event and MIDI functionality for opcodes */
286 csoundSetReleaseLength,
287 csoundSetReleaseLengthSeconds,
288 csoundGetMidiChannelNumber,
289 csoundGetMidiChannel,
290 csoundGetMidiNoteNumber,
291 csoundGetMidiVelocity,
292 csoundGetReleaseFlag,
293 csoundGetOffTime,
294 csoundGetPFields,
295 csoundGetInstrumentNumber,
296 csoundGetZakBounds,
297 csoundGetTieFlag,
298 csoundGetReinitFlag,
299 csoundGetStrsmax,
300 csoundGetStrsets,
301 csoundPow2,
302 intpow,
303 type2string,
304 /* arguments to opcodes */
305 csoundGetTypeForArg,
306 csoundGetInputArgCnt,
307 csoundGetInputArgName,
308 csoundGetOutputArgCnt,
309 csoundGetOutputArgName,
310 get_arg_string,
311 strarg2insno,
312 strarg2name,
313 /* memory allocation */
314 csoundAuxAlloc,
315 mmalloc,
316 mcalloc,
317 mrealloc,
318 cs_strdup,
319 mfree,
320 /* function tables */
321 hfgens,
322 csoundFTAlloc,
323 csoundFTDelete,
324 csoundFTFind,
325 csoundFTFindP,
326 csoundFTnp2Find,
327 csoundGetTable,
328 csoundTableLength,
329 csoundTableGet,
330 csoundTableSetInternal,
331 csoundGetNamedGens,
332 /* global and config variable manipulation */
333 csoundCreateGlobalVariable,
334 csoundQueryGlobalVariable,
335 csoundQueryGlobalVariableNoCheck,
336 csoundDestroyGlobalVariable,
337 csoundCreateConfigurationVariable,
338 csoundSetConfigurationVariable,
339 csoundParseConfigurationVariable,
340 csoundQueryConfigurationVariable,
341 csoundListConfigurationVariables,
342 csoundDeleteConfigurationVariable,
343 csoundCfgErrorCodeToString,
344 /* FFT support */
345 csoundGetInverseComplexFFTScale,
346 csoundGetInverseRealFFTScale,
347 csoundComplexFFT,
348 csoundInverseComplexFFT,
349 csoundRealFFT,
350 csoundInverseRealFFT,
351 csoundRealFFTMult,
352 csoundRealFFTnp2,
353 csoundInverseRealFFTnp2,
354 /* PVOC-EX system */
355 pvoc_createfile,
356 pvoc_openfile,
357 pvoc_closefile,
358 pvoc_putframes,
359 pvoc_getframes,
360 pvoc_framecount,
361 pvoc_fseek,
362 pvoc_errorstr,
363 PVOCEX_LoadFile,
364 /* error messages */
365 csoundDie,
366 csoundInitError,
367 csoundPerfError,
368 csoundWarning,
369 csoundDebugMsg,
370 csoundLongJmp,
371 csoundErrorMsg,
372 csoundErrMsgV,
373 /* random numbers */
374 csoundGetRandomSeedFromTime,
375 csoundSeedRandMT,
376 csoundRandMT,
377 csoundRand31,
378 csoundGetRandSeed,
379 /* threads and locks */
380 csoundCreateThread,
381 csoundJoinThread,
382 csoundCreateThreadLock,
383 csoundDestroyThreadLock,
384 csoundWaitThreadLock,
385 csoundNotifyThreadLock,
386 csoundWaitThreadLockNoTimeout,
387 csoundCreateMutex,
388 csoundLockMutexNoWait,
389 csoundLockMutex,
390 csoundUnlockMutex,
391 csoundDestroyMutex,
392 csoundCreateBarrier,
393 csoundDestroyBarrier,
394 csoundWaitBarrier,
395 csoundGetCurrentThreadId,
396 csoundSleep,
397 csoundInitTimerStruct,
398 csoundGetRealTime,
399 csoundGetCPUTime,
400 /* circular buffer */
401 csoundCreateCircularBuffer,
402 csoundReadCircularBuffer,
403 csoundWriteCircularBuffer,
404 csoundFlushCircularBuffer,
405 csoundDestroyCircularBuffer,
406 /* File access */
407 csoundFindInputFile,
408 csoundFindOutputFile,
409 SAsndgetset,
410 sndgetset,
411 getsndin,
412 rewriteheader,
413 csoundLoadSoundFile,
414 fdrecord,
415 csound_fd_close,
416 csoundCreateFileHandle,
417 csoundGetFileName,
418 csoundFileClose,
419 csoundFileOpenWithType,
420 type2csfiletype,
421 csoundNotifyFileOpened,
422 sftype2csfiletype,
423 ldmemfile2withCB,
424 csoundFileOpenWithType_Async,
425 csoundReadAsync,
426 csoundWriteAsync,
427 csoundFSeekAsync,
428 getstrformat,
429 sfsampsize,
430 /* RT audio IO and callbacks */
431 csoundSetPlayopenCallback,
432 csoundSetRtplayCallback,
433 csoundSetRecopenCallback,
434 csoundSetRtrecordCallback,
435 csoundSetRtcloseCallback,
436 csoundSetAudioDeviceListCallback,
437 csoundGetRtRecordUserData,
438 csoundGetRtPlayUserData,
439 csoundGetDitherMode,
440 /* MIDI and callbacks */
441 csoundSetExternalMidiInOpenCallback,
442 csoundSetExternalMidiReadCallback,
443 csoundSetExternalMidiInCloseCallback,
444 csoundSetExternalMidiOutOpenCallback,
445 csoundSetExternalMidiWriteCallback,
446 csoundSetExternalMidiOutCloseCallback,
447 csoundSetExternalMidiErrorStringCallback,
448 csoundSetMIDIDeviceListCallback,
449 module_list_add,
450 /* displays & graphs */
451 dispset,
452 display,
453 dispexit,
454 dispinit,
455 csoundSetIsGraphable,
456 csoundSetMakeGraphCallback,
457 csoundSetDrawGraphCallback,
458 csoundSetKillGraphCallback,
459 csoundSetExitGraphCallback,
460 /* generic callbacks */
461 csoundSetYieldCallback,
462 csoundRegisterKeyboardCallback,
463 csoundRemoveKeyboardCallback,
464 csoundRegisterSenseEventCallback,
465 csoundRegisterDeinitCallback,
466 csoundRegisterResetCallback,
467 SetInternalYieldCallback,
468 /* opcodes and instruments */
469 csoundAppendOpcode,
470 csoundAppendOpcodes,
471 csoundGetOpcodeName,
472 csoundGetInstrumentList,
473 /* events and performance */
474 csoundYield,
475 insert_score_event,
476 insert_score_event_at_sample,
477 csoundPerformKsmpsInternal,
478 /* utilities */
479 csoundAddUtility,
480 csoundRunUtility,
481 csoundListUtilities,
482 csoundSetUtilityDescription,
483 csoundGetUtilityDescription,
484 set_util_sr,
485 set_util_nchnls,
486 /* miscellaneous */
487 csoundRunCommand,
488 csoundOpenLibrary,
489 csoundCloseLibrary,
490 csoundGetLibrarySymbol,
491 csoundLocalizeString,
492 cs_strtok_r,
493 cs_strtod,
494 cs_sprintf,
495 cs_sscanf,
496 csoundSystemSr,
497 csoundGetScoreOffsetSeconds,
498 csoundSetScoreOffsetSeconds,
499 csoundRewindScore,
500 csoundInputMessageInternal,
501 isstrcod,
502 csoundRealFFT2Setup,
503 csoundRealFFT2,
504 fterror,
505 csoundGetA4,
506 csoundAuxAllocAsync,
507 csoundGetHostData,
508 strNcpy,
509 csoundGetZaBounds,
510 find_opcode_new,
511 find_opcode_exact,
512 csoundGetChannelPtr,
513 csoundListChannels,
514 csoundErrCnt,
515 csoundFTnp2Finde,
516 csoundGetInstrument,
517 csoundAutoCorrelation,
518 csoundLPsetup,
519 csoundLPfree,
520 csoundLPred,
521 csoundLPCeps,
522 csoundCepsLP,
523 csoundLPrms,
524 {
525 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
526 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
527 NULL, NULL, NULL
528 },
529 /* ------- private data (not to be used by hosts or externals) ------- */
530 /* callback function pointers */
531 (SUBR) NULL, /* first_callback_ */
532 (channelCallback_t) NULL,
533 (channelCallback_t) NULL,
534 csoundDefaultMessageCallback,
535 (int (*)(CSOUND *)) NULL,
536 (void (*)(CSOUND *, WINDAT *, const char *)) NULL, /* was: MakeAscii,*/
537 (void (*)(CSOUND *, WINDAT *windat)) NULL, /* was: DrawAscii,*/
538 (void (*)(CSOUND *, WINDAT *windat)) NULL, /* was: KillAscii,*/
539 (int (*)(CSOUND *)) NULL, /* was: defaultCsoundExitGraph, */
540 defaultCsoundYield,
541 cscore_, /* cscoreCallback_ */
542 (void(*)(CSOUND*, const char*, int, int, int)) NULL, /* FileOpenCallback_ */
543 (SUBR) NULL, /* last_callback_ */
544 /* these are not saved on RESET */
545 playopen_dummy,
546 rtplay_dummy,
547 recopen_dummy,
548 rtrecord_dummy,
549 rtclose_dummy,
550 audio_dev_list_dummy,
551 midi_dev_list_dummy,
552 csoundDoCallback_, /* doCsoundCallback */
553 defaultCsoundYield, /* csoundInternalYieldCallback_*/
554 /* end of callbacks */
555 (void (*)(CSOUND *)) NULL, /* spinrecv */
556 (void (*)(CSOUND *)) NULL, /* spoutran */
557 (int (*)(CSOUND *, MYFLT *, int)) NULL, /* audrecv */
558 (void (*)(CSOUND *, const MYFLT *, int)) NULL, /* audtran */
559 NULL, /* hostdata */
560 NULL, NULL, /* orchname, scorename */
561 NULL, NULL, /* orchstr, *scorestr */
562 (OPDS*) NULL, /* ids */
563 { (CS_VAR_POOL*)NULL,
564 (CS_HASH_TABLE *) NULL,
565 (CS_HASH_TABLE *) NULL,
566 -1,
567 (INSTRTXT**)NULL,
568 { NULL,
569 {
570 0,0,
571 NULL, NULL, NULL, NULL,
572 0,0,
573 NULL,
574 0,0,0},
575 0,0,0,
576 //0,
577 NULL,
578 0,
579 0,
580 NULL,
581 NULL,
582 NULL,
583 NULL,
584 NULL,
585 0,
586 0,
587 0,
588 FL(0.0),
589 NULL,
590 NULL,
591 0,
592 0,
593 0
594 },
595 NULL,
596 MAXINSNO, /* engineState */
597 },
598 (INSTRTXT *) NULL, /* instr0 */
599 (INSTRTXT**)NULL, /* dead_instr_pool */
600 0, /* dead_instr_no */
601 (TYPE_POOL*)NULL,
602 DFLT_KSMPS, /* ksmps */
603 DFLT_NCHNLS, /* nchnls */
604 -1, /* inchns */
605 0, /* spoutactive */
606 0L, /* kcounter */
607 0L, /* global_kcounter */
608 DFLT_SR, /* esr */
609 DFLT_KR, /* ekr */
610 0l, /* curTime */
611 0l, /* curTime_inc */
612 0.0, /* timeOffs */
613 0.0, /* beatOffs */
614 0.0, /* curBeat */
615 0.0, /* curBeat_inc */
616 0L, /* beatTime */
617 (EVTBLK*) NULL, /* currevent */
618 (INSDS*) NULL, /* curip */
619 FL(0.0), /* cpu_power_busy */
620 (char*) NULL, /* xfilename */
621 1, /* peakchunks */
622 0, /* keep_tmp */
623 (CS_HASH_TABLE*)NULL, /* Opcode hash table */
624 0, /* nrecs */
625 NULL, /* Linepipe */
626 0, /* Linefd */
627 NULL, /* csoundCallbacks_ */
628 (FILE*)NULL, /* scfp */
629 (CORFIL*)NULL, /* scstr */
630 NULL, /* oscfp */
631 { FL(0.0) }, /* maxamp */
632 { FL(0.0) }, /* smaxamp */
633 { FL(0.0) }, /* omaxamp */
634 {0}, {0}, {0}, /* maxpos, smaxpos, omaxpos */
635 NULL, NULL, /* scorein, scoreout */
636 NULL, /* argoffspace */
637 NULL, /* frstoff */
638 NULL, /* stdOp_Env */
639 2345678, /* holdrand */
640 0, /* randSeed1 */
641 0, /* randSeed2 */
642 NULL, /* csRandState */
643 NULL, /* csRtClock */
644 // 16384, /* strVarMaxLen */
645 0, /* strsmax */
646 (char**) NULL, /* strsets */
647 NULL, /* spin */
648 NULL, /* spout */
649 NULL, /* spraw */
650 0, /* nspin */
651 0, /* nspout */
652 NULL, /* auxspin */
653 (OPARMS*) NULL, /* oparms */
654 { NULL }, /* m_chnbp */
655 0, /* dither_output */
656 FL(0.0), /* onedsr */
657 FL(0.0), /* sicvt */
658 FL(-1.0), /* tpidsr */
659 FL(-1.0), /* pidsr */
660 FL(-1.0), /* mpidsr */
661 FL(-1.0), /* mtpdsr */
662 FL(0.0), /* onedksmps */
663 FL(0.0), /* onedkr */
664 FL(0.0), /* kicvt */
665 0, /* reinitflag */
666 0, /* tieflag */
667 DFLT_DBFS, /* e0dbfs */
668 FL(1.0) / DFLT_DBFS, /* dbfs_to_float ( = 1.0 / e0dbfs) */
669 440.0, /* A4 base frequency */
670 NULL, /* rtRecord_userdata */
671 NULL, /* rtPlay_userdata */
672 #if defined(MSVC) ||defined(__POWERPC__) || defined(MACOSX)
673 {0},
674 #else
675 {{{0}}}, /* exitjmp of type jmp_buf */
676 #endif
677 NULL, /* frstbp */
678 0, /* sectcnt */
679 0, 0, 0, /* inerrcnt, synterrcnt, perferrcnt */
680 /* {NULL}, */ /* instxtanchor in engineState */
681 { /* actanchor */
682 NULL,
683 NULL,
684 NULL,
685 NULL,
686 NULL,
687 NULL,
688 NULL,
689 NULL,
690 NULL,
691 0,
692 NULL,
693 NULL,
694 0,
695 NULL,
696 0,
697 0,
698 0,
699 0,
700 0,
701 0.0,
702 0.0,
703 NULL,
704 NULL,
705 0,
706 0,
707 FL(0.0),
708 FL(0.0), FL(0.0), FL(0.0),
709 NULL,
710 {FL(0.0), FL(0.0), FL(0.0), FL(0.0)},
711 NULL,
712 NULL,NULL,
713 NULL,
714 0,
715 0,
716 0,
717 NULL,
718 NULL,
719 0,
720 0,
721 0,
722 FL(0.0),
723 NULL,
724 NULL,
725 {NULL, FL(0.0)},
726 {NULL, FL(0.0)},
727 {NULL, FL(0.0)},
728 {NULL, FL(0.0)}
729 },
730 {0L }, /* rngcnt */
731 0, 0, /* rngflg, multichan */
732 NULL, /* evtFuncChain */
733 NULL, /* OrcTrigEvts */
734 NULL, /* freeEvtNodes */
735 1, /* csoundIsScorePending_ */
736 0, /* advanceCnt */
737 0, /* initonly */
738 0, /* evt_poll_cnt */
739 0, /* evt_poll_maxcnt */
740 0, 0, 0, /* Mforcdecs, Mxtroffs, MTrkend */
741 NULL, /* opcodeInfo */
742 NULL, /* flist */
743 0, /* maxfnum */
744 NULL, /* gensub */
745 GENMAX+1, /* genmax */
746 NULL, /* namedGlobals */
747 NULL, /* cfgVariableDB */
748 FL(0.0), FL(0.0), FL(0.0), /* prvbt, curbt, nxtbt */
749 FL(0.0), FL(0.0), /* curp2, nxtim */
750 0, /* cyclesRemaining */
751 { 0, NULL, NULL, '\0', 0, FL(0.0),
752 FL(0.0), { FL(0.0) }, {NULL}}, /* evt */
753 NULL, /* memalloc_db */
754 (MGLOBAL*) NULL, /* midiGlobals */
755 NULL, /* envVarDB */
756 (MEMFIL*) NULL, /* memfiles */
757 NULL, /* pvx_memfiles */
758 0, /* FFT_max_size */
759 NULL, /* FFT_table_1 */
760 NULL, /* FFT_table_2 */
761 NULL, NULL, NULL, /* tseg, tpsave, unused */
762 (MYFLT*) NULL, /* gbloffbas */
763 NULL, /* file_io_thread */
764 0, /* file_io_start */
765 NULL, /* file_io_threadlock */
766 0, /* realtime_audio_flag */
767 NULL, /* init pass thread */
768 0, /* init pass loop */
769 NULL, /* init pass threadlock */
770 NULL, /* API_lock */
771 SPINLOCK_INIT, SPINLOCK_INIT, /* spinlocks */
772 SPINLOCK_INIT, SPINLOCK_INIT, /* spinlocks */
773 NULL, NULL, /* Delayed messages */
774 {
775 NULL, NULL, NULL, NULL, /* bp, prvibp, sp, nx */
776 0, 0, 0, 0, /* op warpin linpos lincnt */
777 -FL(1.0), FL(0.0), FL(1.0), /* prvp2 clock_base warp_factor */
778 NULL, /* curmem */
779 NULL, /* memend */
780 NULL, /* macros */
781 -1, /* next_name */
782 NULL, NULL, /* inputs, str */
783 0,0,0, /* input_size, input_cnt, pop */
784 1, /* ingappop */
785 -1, /* linepos */
786 {{NULL, 0, 0}}, /* names */
787 {""}, /* repeat_name_n[RPTDEPTH][NAMELEN] */
788 {0}, /* repeat_cnt_n[RPTDEPTH] */
789 {0}, /* repeat_point_n[RPTDEPTH] */
790 1, {NULL}, 0, /* repeat_inc_n,repeat_mm_n repeat_index */
791 "", /* repeat_name[NAMELEN] */
792 0,0,1, /* repeat_cnt, repeat_point, repeat_inc */
793 NULL, /* repeat_mm */
794 0
795 },
796 {
797 NULL,
798 NULL, NULL, NULL, /* orcname, sconame, midname */
799 0, 0 /* midiSet, csdlinecount */
800 },
801 {
802 NULL, NULL, /* Linep, Linebufend */
803 0, /* stdmode */
804 {
805 0, NULL, NULL, 0, 0, FL(0.0), FL(0.0), { FL(0.0) },
806 {NULL},
807 }, /* EVTBLK prve */
808 NULL, /* Linebuf */
809 0, /* linebufsiz */
810 NULL, NULL,
811 0
812 },
813 {
814 {0,0}, {0,0}, /* srngcnt, orngcnt */
815 0, 0, 0, 0, 0, /* srngflg, sectno, lplayed, segamps, sormsg */
816 NULL, NULL, /* ep, epend */
817 NULL /* lsect */
818 },
819 //NULL, /* musmonGlobals */
820 {
821 NULL, /* outfile */
822 NULL, /* infile */
823 NULL, /* sfoutname; */
824 NULL, /* inbuf */
825 NULL, /* outbuf */
826 NULL, /* outbufp */
827 0, /* inbufrem */
828 0, /* outbufrem */
829 0,0, /* inbufsiz, outbufsiz */
830 0, /* isfopen */
831 0, /* osfopen */
832 0,0, /* pipdevin, pipdevout */
833 1U, /* nframes */
834 NULL, NULL, /* pin, pout */
835 0, /*dither */
836 },
837 0, /* warped */
838 0, /* sstrlen */
839 (char*) NULL, /* sstrbuf */
840 1, /* enableMsgAttr */
841 0, /* sampsNeeded */
842 FL(0.0), /* csoundScoreOffsetSeconds_ */
843 -1, /* inChar_ */
844 0, /* isGraphable_ */
845 0, /* delayr_stack_depth */
846 NULL, /* first_delayr */
847 NULL, /* last_delayr */
848 { 0L, 0L, 0L, 0L, 0L, 0L }, /* revlpsiz */
849 0L, /* revlpsum */
850 0.5, /* rndfrac */
851 NULL, /* logbase2 */
852 NULL, NULL, /* omacros, smacros */
853 NULL, /* namedgen */
854 NULL, /* open_files */
855 NULL, /* searchPathCache */
856 NULL, /* sndmemfiles */
857 NULL, /* reset_list */
858 NULL, /* pvFileTable */
859 0, /* pvNumFiles */
860 0, /* pvErrorCode */
861 // NULL, /* pluginOpcodeFiles */
862 0, /* enableHostImplementedAudioIO */
863 0, /* MIDI IO */
864 0, /* hostRequestedBufferSize */
865 0, /* engineStatus */
866 0, /* stdin_assign_flg */
867 0, /* stdout_assign_flg */
868 0, /* orcname_mode */
869 0, /* use_only_orchfile */
870 NULL, /* csmodule_db */
871 (char*) NULL, /* dl_opcodes_oplibs */
872 (char*) NULL, /* SF_csd_licence */
873 (char*) NULL, /* SF_id_title */
874 (char*) NULL, /* SF_id_copyright */
875 -1, /* SF_id_scopyright */
876 (char*) NULL, /* SF_id_software */
877 (char*) NULL, /* SF_id_artist */
878 (char*) NULL, /* SF_id_comment */
879 (char*) NULL, /* SF_id_date */
880 NULL, /* utility_db */
881 (int16*) NULL, /* isintab */
882 NULL, /* lprdaddr */
883 0, /* currentLPCSlot */
884 0, /* max_lpc_slot */
885 NULL, /* chn_db */
886 1, /* opcodedirWasOK */
887 0, /* disable_csd_options */
888 { 0, { 0U } }, /* randState_ */
889 0, /* performState */
890 1000, /* ugens4_rand_16 */
891 1000, /* ugens4_rand_15 */
892 NULL, /* schedule_kicked */
893 (MYFLT*) NULL, /* disprep_fftcoefs */
894 NULL, /* winEPS_globals */
895 { /* oparms_ */
896 0, /* odebug */
897 0, 1, 1, 0, /* sfread, ... */
898 0, 0, 0, 0, /* inbufsamps, ... */
899 0, /* sfsampsize */
900 1, /* displays */
901 1, 0, 135, /* graphsoff ... */
902 0, 0, /* Beatmode, ... */
903 0, 0, /* usingcscore, ... */
904 0, 0, 0, 0, /* RTevents, ... */
905 0, 0, /* ringbell, ... */
906 0, 0, 0, /* rewrt_hdr, ... */
907 0.0, /* cmdTempo */
908 0.0f, 0.0f, /* sr_override ... */
909 0, 0, /* nchnls_override ... */
910 (char*) NULL, (char*) NULL, NULL,
911 (char*) NULL, (char*) NULL, (char*) NULL,
912 (char*) NULL, (char*) NULL,
913 0, /* midiKey */
914 0, /* midiKeyCps */
915 0, /* midiKeyOct */
916 0, /* midiKeyPch */
917 0, /* midiVelocity */
918 0, /* midiVelocityAmp */
919 0, /* noDefaultPaths */
920 1, /* numThreads */
921 0, /* syntaxCheckOnly */
922 1, /* useCsdLineCounts */
923 0, /* samp acc */
924 0, /* realtime */
925 0.0, /* 0dbfs override */
926 0, /* no exit on compile error */
927 0.4, /* vbr quality */
928 0, /* ksmps_override */
929 0, /* fft_lib */
930 0
931 },
932
933 {0, 0, {0}}, /* REMOT_BUF */
934 NULL, /* remoteGlobals */
935 0, 0, /* nchanof, nchanif */
936 NULL, NULL, /* chanif, chanof */
937 0, /* multiThreadedComplete */
938 NULL, /* multiThreadedThreadInfo */
939 NULL, /* multiThreadedDag */
940 NULL, /* barrier1 */
941 NULL, /* barrier2 */
942 NULL, /* pointer1 was global_var_lock_root */
943 NULL, /* pointer2 was global_var_lock_cache */
944 0, /* int1 was global_var_lock_count */
945 /* statics from cs_par_orc_semantic_analysis */
946 NULL, /* instCurr */
947 NULL, /* instRoot */
948 0, /* inInstr */
949 /* new dag model statics */
950 1, /* dag_changed */
951 0, /* dag_num_active */
952 NULL, /* dag_task_map */
953 NULL, /* dag_task_status */
954 NULL, /* dag_task_watch */
955 NULL, /* dag_wlmm */
956 NULL, /* dag_task_dep */
957 100, /* dag_task_max_size */
958 0, /* tempStatus */
959 1, /* orcLineOffset */
960 0, /* scoLineOffset */
961 NULL, /* csdname */
962 -1, /* parserUdoflag */
963 0, /* parserNamedInstrFlag */
964 0, /* tran_nchnlsi */
965 0, /* Count of score strings */
966 0, /* length of current strings space */
967 NULL, /* sinetable */
968 16384, /* sinesize */
969 NULL, /* unused *** pow2 table */
970 NULL, /* cps conv table */
971 NULL, /* output of preprocessor */
972 NULL, /* output of preprocessor */
973 {NULL}, /* filedir */
974 NULL, /* message buffer struct */
975 0, /* jumpset */
976 0, /* info_message_request */
977 0, /* modules loaded */
978 -1, /* audio system sr */
979 0, /* csdebug_data */
980 kperf_nodebug, /* current kperf function - nodebug by default */
981 0, /* which score parser */
982 NULL, /* symbtab */
983 0, /* print_version */
984 1, /* inZero */
985 NULL, /* msg_queue */
986 0, /* msg_queue_wget */
987 0, /* msg_queue_wput */
988 0, /* msg_queue_rstart */
989 0, /* msg_queue_items */
990 127, /* aftouch */
991 NULL, /* directory for corfiles */
992 NULL, /* alloc_queue */
993 0, /* alloc_queue_items */
994 0, /* alloc_queue_wp */
995 SPINLOCK_INIT, /* alloc_spinlock */
996 NULL, /* init_event */
997 NULL, /* message string callback */
998 NULL, /* message_string */
999 0, /* message_string_queue_items */
1000 0, /* message_string_queue_wp */
1001 NULL, /* message_string_queue */
1002 0, /* io_initialised */
1003 NULL, /* op */
1004 0, /* mode */
1005 NULL, /* opcodedir */
1006 NULL /* score_srt */
1007 };
1008
1009 void csound_aops_init_tables(CSOUND *cs);
1010
1011 typedef struct csInstance_s {
1012 CSOUND *csound;
1013 struct csInstance_s *nxt;
1014 } csInstance_t;
1015
1016 /* initialisation state: */
1017 /* 0: not done yet, 1: complete, 2: in progress, -1: failed */
1018 static volatile int init_done = 0;
1019 /* chain of allocated Csound instances */
1020 static volatile csInstance_t *instance_list = NULL;
1021 /* non-zero if performance should be terminated now */
1022 static volatile int exitNow_ = 0;
1023
1024
1025 #if !defined(WIN32)
destroy_all_instances(void)1026 static void destroy_all_instances(void)
1027 {
1028 volatile csInstance_t *p;
1029
1030 csoundLock();
1031 init_done = -1; /* prevent the creation of any new instances */
1032 if (instance_list == NULL) {
1033 csoundUnLock();
1034 return;
1035 }
1036 csoundUnLock();
1037 csoundSleep(250);
1038 while (1) {
1039 csoundLock();
1040 p = instance_list;
1041 csoundUnLock();
1042 if (p == NULL) {
1043 break;
1044 }
1045 csoundDestroy(p->csound);
1046 }
1047 }
1048 #endif
1049
1050 #if defined(ANDROID) || (!defined(LINUX) && !defined(SGI) && \
1051 !defined(__HAIKU__) && !defined(__BEOS__) && \
1052 !defined(__MACH__) && !defined(__EMSCRIPTEN__))
1053
signal_to_string(int sig)1054 static char *signal_to_string(int sig)
1055 {
1056 switch(sig) {
1057 #ifdef SIGHUP
1058 case SIGHUP:
1059 return "Hangup";
1060 #endif
1061 #ifdef SIGINT
1062 case SIGINT:
1063 return "Interrupt";
1064 #endif
1065 #ifdef SIGQUIT
1066 case SIGQUIT:
1067 return "Quit";
1068 #endif
1069 #ifdef SIGILL
1070 case SIGILL:
1071 return "Illegal instruction";
1072 #endif
1073 #ifdef SIGTRAP
1074 case SIGTRAP:
1075 return "Trace trap";
1076 #endif
1077 #ifdef SIGABRT
1078 case SIGABRT:
1079 return "Abort";
1080 #endif
1081 #ifdef SIGBUS
1082 case SIGBUS:
1083 return "BUS error";
1084 #endif
1085 #ifdef SIGFPE
1086 case SIGFPE:
1087 return "Floating-point exception";
1088 #endif
1089 #ifdef SIGUSR1
1090 case SIGUSR1:
1091 return "User-defined signal 1";
1092 #endif
1093 #ifdef SIGSEGV
1094 case SIGSEGV:
1095 return "Segmentation violation";
1096 #endif
1097 #ifdef SIGUSR2
1098 case SIGUSR2:
1099 return "User-defined signal 2";
1100 #endif
1101 #ifdef SIGPIPE
1102 case SIGPIPE:
1103 return "Broken pipe";
1104 #endif
1105 #ifdef SIGALRM
1106 case SIGALRM:
1107 return "Alarm clock";
1108 #endif
1109 #ifdef SIGTERM
1110 case SIGTERM:
1111 return "Termination";
1112 #endif
1113 #ifdef SIGSTKFLT
1114 case SIGSTKFLT:
1115 return "???";
1116 #endif
1117 #ifdef SIGCHLD
1118 case SIGCHLD:
1119 return "Child status has changed";
1120 #endif
1121 #ifdef SIGCONT
1122 case SIGCONT:
1123 return "Continue";
1124 #endif
1125 #ifdef SIGSTOP
1126 case SIGSTOP:
1127 return "Stop, unblockable";
1128 #endif
1129 #ifdef SIGTSTP
1130 case SIGTSTP:
1131 return "Keyboard stop";
1132 #endif
1133 #ifdef SIGTTIN
1134 case SIGTTIN:
1135 return "Background read from tty";
1136 #endif
1137 #ifdef SIGTTOU
1138 case SIGTTOU:
1139 return "Background write to tty";
1140 #endif
1141 #ifdef SIGURG
1142 case SIGURG:
1143 return "Urgent condition on socket ";
1144 #endif
1145 #ifdef SIGXCPU
1146 case SIGXCPU:
1147 return "CPU limit exceeded";
1148 #endif
1149 #ifdef SIGXFSZ
1150 case SIGXFSZ:
1151 return "File size limit exceeded ";
1152 #endif
1153 #ifdef SIGVTALRM
1154 case SIGVTALRM:
1155 return "Virtual alarm clock ";
1156 #endif
1157 #ifdef SIGPROF
1158 case SIGPROF:
1159 return "Profiling alarm clock";
1160 #endif
1161 #ifdef SIGWINCH
1162 case SIGWINCH:
1163 return "Window size change ";
1164 #endif
1165 #ifdef SIGIO
1166 case SIGIO:
1167 return "I/O now possible";
1168 #endif
1169 #ifdef SIGPWR
1170 case SIGPWR:
1171 return "Power failure restart";
1172 #endif
1173 default:
1174 return "???";
1175 }
1176 }
1177
1178 #ifdef ANDROID
psignal_(int sig,char * str)1179 static void psignal_(int sig, char *str)
1180 {
1181 fprintf(stderr, "%s: %s\n", str, signal_to_string(sig));
1182 }
1183 #else
1184 # if !defined(__CYGWIN__)
psignal(int sig,const char * str)1185 static void psignal(int sig, const char *str)
1186 {
1187 fprintf(stderr, "%s: %s\n", str, signal_to_string(sig));
1188 }
1189 # endif
1190 #endif
1191 #elif defined(__BEOS__)
psignal_(int sig,char * str)1192 static void psignal_(int sig, char *str)
1193 {
1194 fprintf(stderr, "%s: %s\n", str, strsignal(sig));
1195 }
1196 #endif
1197
signal_handler(int sig)1198 static void signal_handler(int sig)
1199 {
1200 #if defined(HAVE_EXECINFO) && !defined(ANDROID) && !defined(NACL)
1201 #include <execinfo.h>
1202
1203 {
1204 int j, nptrs;
1205 #define SIZE 100
1206 void *buffer[SIZE];
1207 char **strings;
1208
1209 nptrs = backtrace(buffer, SIZE);
1210 printf("backtrace() returned %d addresses\n", nptrs);
1211
1212 /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
1213 would produce similar output to the following: */
1214
1215 strings = backtrace_symbols(buffer, nptrs);
1216 if (UNLIKELY(strings == NULL)) {
1217 perror("backtrace_symbols");
1218 exit(EXIT_FAILURE);
1219 }
1220
1221 for (j = 0; j < nptrs; j++)
1222 printf("%s\n", strings[j]);
1223
1224 free(strings);
1225 }
1226 #endif
1227
1228 #if defined(SIGPIPE)
1229 if (sig == (int) SIGPIPE) {
1230 #ifdef ANDROID
1231 psignal_(sig, "Csound ignoring SIGPIPE");
1232 #else
1233 psignal(sig, "Csound ignoring SIGPIPE");
1234 #endif
1235 return;
1236 }
1237 #endif
1238 #ifdef ANDROID
1239 psignal_(sig, "Csound tidy up");
1240 #else
1241 psignal(sig, "Csound tidy up");
1242 #endif
1243 if ((sig == (int) SIGINT || sig == (int) SIGTERM) && !exitNow_) {
1244 exitNow_ = -1;
1245 return;
1246 }
1247 exit(1);
1248 }
1249
1250 static const int sigs[] = {
1251 #if defined(LINUX) || defined(SGI) || defined(sol) || defined(__MACH__)
1252 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, SIGBUS,
1253 SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, SIGXCPU, SIGXFSZ,
1254 #elif defined(WIN32)
1255 SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTERM,
1256 #elif defined(__EMX__)
1257 SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE,
1258 SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGTERM, SIGCHLD,
1259 #endif
1260 -1
1261 };
1262
install_signal_handler(void)1263 static void install_signal_handler(void)
1264 {
1265 unsigned int i;
1266 for (i = 0; sigs[i] >= 0; i++) {
1267 signal(sigs[i], signal_handler);
1268 }
1269 }
1270
1271 static int getTimeResolution(void);
1272
csoundInitialize(int flags)1273 PUBLIC int csoundInitialize(int flags)
1274 {
1275 int n;
1276
1277 do {
1278 csoundLock();
1279 n = init_done;
1280 switch (n) {
1281 case 2:
1282 csoundUnLock();
1283 csoundSleep(1);
1284 case 0:
1285 break;
1286 default:
1287 csoundUnLock();
1288 return n;
1289 }
1290 } while (n);
1291 init_done = 2;
1292 csoundUnLock();
1293 if (getTimeResolution() != 0) {
1294 csoundLock();
1295 init_done = -1;
1296 csoundUnLock();
1297 return -1;
1298 }
1299 if (!(flags & CSOUNDINIT_NO_SIGNAL_HANDLER)) {
1300 install_signal_handler();
1301 }
1302 #if !defined(WIN32)
1303 if (!(flags & CSOUNDINIT_NO_ATEXIT))
1304 atexit(destroy_all_instances);
1305 #endif
1306 csoundLock();
1307 init_done = 1;
1308 csoundUnLock();
1309 return 0;
1310 }
1311
1312 static char *opcodedir = NULL;
1313
csoundSetOpcodedir(const char * s)1314 PUBLIC void csoundSetOpcodedir(const char *s) {
1315 opcodedir = (char *) s;
1316 }
1317
1318
csoundCreate(void * hostdata)1319 PUBLIC CSOUND *csoundCreate(void *hostdata)
1320 {
1321 CSOUND *csound;
1322 csInstance_t *p;
1323 _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
1324
1325 if (init_done != 1) {
1326 if (csoundInitialize(0) < 0) return NULL;
1327 }
1328 csound = (CSOUND*) malloc(sizeof(CSOUND));
1329 if (UNLIKELY(csound == NULL)) return NULL;
1330 memcpy(csound, &cenviron_, sizeof(CSOUND));
1331 init_getstring(csound);
1332 csound->oparms = &(csound->oparms_);
1333 csound->hostdata = hostdata;
1334 p = (csInstance_t*) malloc(sizeof(csInstance_t));
1335 if (UNLIKELY(p == NULL)) {
1336 free(csound);
1337 return NULL;
1338 }
1339 csoundLock();
1340 p->csound = csound;
1341 p->nxt = (csInstance_t*) instance_list;
1342 instance_list = p;
1343 csound->opcodedir = cs_strdup(csound, opcodedir);
1344 csoundUnLock();
1345 csoundReset(csound);
1346 csound->API_lock = csoundCreateMutex(1);
1347 allocate_message_queue(csound);
1348 /* NB: as suggested by F Pinot, keep the
1349 address of the pointer to CSOUND inside
1350 the struct, so it can be cleared later */
1351 //csound->self = &csound;
1352
1353 return csound;
1354 }
1355
1356 /* dummy real time MIDI functions */
1357 int DummyMidiInOpen(CSOUND *csound, void **userData,
1358 const char *devName);
1359 int DummyMidiRead(CSOUND *csound, void *userData,
1360 unsigned char *buf, int nbytes);
1361 int DummyMidiOutOpen(CSOUND *csound, void **userData,
1362 const char *devName);
1363 int DummyMidiWrite(CSOUND *csound, void *userData,
1364 const unsigned char *buf, int nbytes);
1365 /* random.c */
1366 extern void csound_init_rand(CSOUND *);
1367
1368 /*
1369 PUBLIC int csoundQueryInterface(const char *name, void **iface, int *version)
1370 {
1371 if (strcmp(name, "CSOUND") != 0)
1372 return 1;
1373 *iface = csoundCreate(NULL);
1374 *version = csoundGetAPIVersion();
1375 return 0;
1376 }
1377 */
1378
1379 typedef struct CsoundCallbackEntry_s CsoundCallbackEntry_t;
1380
1381 struct CsoundCallbackEntry_s {
1382 unsigned int typeMask;
1383 CsoundCallbackEntry_t *nxt;
1384 void *userData;
1385 int (*func)(void *, void *, unsigned int);
1386 };
1387
csoundDestroy(CSOUND * csound)1388 PUBLIC void csoundDestroy(CSOUND *csound)
1389 {
1390 csInstance_t *p, *prv = NULL;
1391
1392 csoundLock();
1393 p = (csInstance_t*) instance_list;
1394 while (p != NULL && p->csound != csound) {
1395 prv = p;
1396 p = p->nxt;
1397 }
1398 if (p == NULL) {
1399 csoundUnLock();
1400 return;
1401 }
1402 if (prv == NULL)
1403 instance_list = p->nxt;
1404 else
1405 prv->nxt = p->nxt;
1406 csoundUnLock();
1407 free(p);
1408
1409 reset(csound);
1410
1411 if (csound->csoundCallbacks_ != NULL) {
1412 CsoundCallbackEntry_t *pp, *nxt;
1413 pp = (CsoundCallbackEntry_t*) csound->csoundCallbacks_;
1414 do {
1415 nxt = pp->nxt;
1416 free((void*) pp);
1417 pp = nxt;
1418 } while (pp != (CsoundCallbackEntry_t*) NULL);
1419 }
1420 if (csound->API_lock != NULL) {
1421 //csoundLockMutex(csound->API_lock);
1422 csoundDestroyMutex(csound->API_lock);
1423 }
1424 /* clear the pointer */
1425 // *(csound->self) = NULL;
1426 free((void*) csound);
1427 }
1428
csoundGetVersion(void)1429 PUBLIC int csoundGetVersion(void)
1430 {
1431 return (int) (CS_VERSION * 1000 + CS_SUBVER * 10 + CS_PATCHLEVEL);
1432 }
1433
csoundGetAPIVersion(void)1434 PUBLIC int csoundGetAPIVersion(void)
1435 {
1436 return CS_APIVERSION * 100 + CS_APISUBVER;
1437 }
1438
csoundGetHostData(CSOUND * csound)1439 PUBLIC void *csoundGetHostData(CSOUND *csound)
1440 {
1441 return csound->hostdata;
1442 }
1443
csoundSetHostData(CSOUND * csound,void * hostData)1444 PUBLIC void csoundSetHostData(CSOUND *csound, void *hostData)
1445 {
1446 csound->hostdata = hostData;
1447 }
1448
1449 /*
1450 * PERFORMANCE
1451 */
1452
1453 extern int sensevents(CSOUND *);
1454
1455 /**
1456 * perform currently active instrs for one kperiod
1457 * & send audio result to output buffer
1458 * returns non-zero if this kperiod was skipped
1459 */
1460
getThreadIndex(CSOUND * csound,void * threadId)1461 static int getThreadIndex(CSOUND *csound, void *threadId)
1462 {
1463 int index = 0;
1464 THREADINFO *current = csound->multiThreadedThreadInfo;
1465
1466 if (current == NULL) {
1467 return -1;
1468 }
1469
1470 while (current != NULL) {
1471 #ifdef HAVE_PTHREAD
1472 if (pthread_equal(*(pthread_t *)threadId, *(pthread_t *)current->threadId))
1473 #elif defined(WIN32)
1474 DWORD* d = (DWORD*)threadId;
1475 if (*d == GetThreadId((HANDLE)current->threadId))
1476 #else
1477 // FIXME - need to verify this works...
1478 if (threadId == current->threadId)
1479 #endif
1480 return index;
1481
1482 index++;
1483 current = current->next;
1484 }
1485 return -1;
1486 }
1487
1488 #if 0
1489 static int getNumActive(INSDS *start, INSDS *end)
1490 {
1491 INSDS *current = start;
1492 int counter = 1;
1493 while (((current = current->nxtact) != NULL) && current != end) {
1494 counter++;
1495 }
1496 return counter;
1497 }
1498 #endif
1499
advanceINSDSPointer(INSDS *** start,int num)1500 inline void advanceINSDSPointer(INSDS ***start, int num)
1501 {
1502 int i;
1503 INSDS *s = **start;
1504
1505 if (s == NULL) return;
1506 for (i = 0; i < num; i++) {
1507 s = s->nxtact;
1508
1509 if (s == NULL) {
1510 **start = NULL;
1511 return;
1512 }
1513 }
1514 **start = s;
1515 }
1516
1517 int dag_get_task(CSOUND *csound, int index, int numThreads, int next_task);
1518 int dag_end_task(CSOUND *csound, int task);
1519 void dag_build(CSOUND *csound, INSDS *chain);
1520 void dag_reinit(CSOUND *csound);
1521
nodePerf(CSOUND * csound,int index,int numThreads)1522 inline static int nodePerf(CSOUND *csound, int index, int numThreads)
1523 {
1524 INSDS *insds = NULL;
1525 OPDS *opstart = NULL;
1526 int played_count = 0;
1527 int which_task;
1528 INSDS **task_map = (INSDS**)csound->dag_task_map;
1529 double time_end;
1530 #define INVALID (-1)
1531 #define WAIT (-2)
1532 int next_task = INVALID;
1533 IGN(index);
1534
1535 while (1) {
1536 int done;
1537 which_task = dag_get_task(csound, index, numThreads, next_task);
1538 //printf("******** Select task %d\n", which_task);
1539 if (which_task==WAIT) continue;
1540 if (which_task==INVALID) return played_count;
1541 /* VL: the validity of icurTime needs to be checked */
1542 time_end = (csound->ksmps+csound->icurTime)/csound->esr;
1543 insds = task_map[which_task];
1544 if (insds->offtim > 0 && time_end > insds->offtim){
1545 /* this is the last cycle of performance */
1546 insds->ksmps_no_end = insds->no_end;
1547 }
1548 #if defined(MSVC)
1549 done = InterlockedExchangeAdd(&insds->init_done, 0);
1550 #elif defined(HAVE_ATOMIC_BUILTIN)
1551 done = __atomic_load_n((int *) &insds->init_done, __ATOMIC_SEQ_CST);
1552 #else
1553 done = insds->init_done;
1554 #endif
1555 if (done) {
1556 opstart = (OPDS*)task_map[which_task];
1557 if (insds->ksmps == csound->ksmps) {
1558 insds->spin = csound->spin;
1559 insds->spout = csound->spraw;
1560 insds->kcounter = csound->kcounter;
1561 csound->mode = 2;
1562 while ((opstart = opstart->nxtp) != NULL) {
1563 /* In case of jumping need this repeat of opstart */
1564 opstart->insdshead->pds = opstart;
1565 csound->op = opstart->optext->t.opcod;
1566 (*opstart->opadr)(csound, opstart); /* run each opcode */
1567 opstart = opstart->insdshead->pds;
1568 }
1569 csound->mode = 0;
1570 } else {
1571 int i, n = csound->nspout, start = 0;
1572 int lksmps = insds->ksmps;
1573 int incr = csound->nchnls*lksmps;
1574 int offset = insds->ksmps_offset;
1575 int early = insds->ksmps_no_end;
1576 OPDS *opstart;
1577 insds->spin = csound->spin;
1578 insds->spout = csound->spraw;
1579 insds->kcounter = csound->kcounter*csound->ksmps;
1580
1581 /* we have to deal with sample-accurate code
1582 whole CS_KSMPS blocks are offset here, the
1583 remainder is left to each opcode to deal with.
1584 */
1585 while (offset >= lksmps) {
1586 offset -= lksmps;
1587 start += csound->nchnls;
1588 }
1589 insds->ksmps_offset = offset;
1590 if (UNLIKELY(early)) {
1591 n -= (early*csound->nchnls);
1592 insds->ksmps_no_end = early % lksmps;
1593 }
1594
1595 for (i=start; i < n; i+=incr, insds->spin+=incr, insds->spout+=incr) {
1596 opstart = (OPDS*) insds;
1597 csound->mode = 2;
1598 while ((opstart = opstart->nxtp) != NULL) {
1599 opstart->insdshead->pds = opstart;
1600 csound->op = opstart->optext->t.opcod;
1601 (*opstart->opadr)(csound, opstart); /* run each opcode */
1602 opstart = opstart->insdshead->pds;
1603 }
1604 csound->mode = 0;
1605 insds->kcounter++;
1606 }
1607 }
1608 insds->ksmps_offset = 0; /* reset sample-accuracy offset */
1609 insds->ksmps_no_end = 0; /* reset end of loop samples */
1610 played_count++;
1611 }
1612 //printf("******** finished task %d\n", which_task);
1613 next_task = dag_end_task(csound, which_task);
1614 }
1615 return played_count;
1616 }
1617
make_interleave(CSOUND * csound,uint32_t lksmps)1618 inline static void make_interleave(CSOUND *csound, uint32_t lksmps)
1619 {
1620 uint32_t nsmps = csound->ksmps, nchan = csound->nchnls,i, j, n, k=0;
1621 MYFLT *spout = csound->spout;
1622
1623 if (!csound->spoutactive) {
1624 memset(spout, '\0', csound->nspout*sizeof(MYFLT));
1625 }
1626 else if (lksmps == nsmps|| nchan==1 ) {
1627 for (j=0; j<nsmps; j++) {
1628 for (i=0; i<nchan; i++) {
1629 // Will be copy t ad when complette
1630 spout[k + i] = csound->spraw[i*nsmps+j];
1631 }
1632 k += nchan;
1633 }
1634 }
1635 else {
1636 int m = 0;
1637 for (n=0; n<nsmps/lksmps; n++) {
1638 for (j=0; j<lksmps; j++) {
1639 for (i=0; i<nchan; i++) {
1640 // Will be copy t ad when complette
1641 spout[k + i] = csound->spraw[i*lksmps+j+m];
1642 }
1643 k += nchan;
1644 }
1645 m += nchan*lksmps;
1646 }
1647 }
1648 }
1649
1650
kperfThread(void * cs)1651 unsigned long kperfThread(void * cs)
1652 {
1653 //INSDS *start;
1654 CSOUND *csound = (CSOUND *)cs;
1655 void *threadId;
1656 int index;
1657 int numThreads;
1658 _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
1659
1660 csound->WaitBarrier(csound->barrier2);
1661
1662 threadId = csound->GetCurrentThreadID();
1663 index = getThreadIndex(csound, threadId);
1664 numThreads = csound->oparms->numThreads;
1665 //start = NULL;
1666 csound->Message(csound,
1667 Str("Multithread performance:thread %d of "
1668 "%d starting.\n"),
1669 /* start ? start->insno : */
1670 index+1,
1671 numThreads);
1672 if (UNLIKELY(index < 0)) {
1673 csound->Die(csound, Str("Bad ThreadId"));
1674 return ULONG_MAX;
1675 }
1676 index++;
1677
1678 while (1) {
1679
1680 csound->WaitBarrier(csound->barrier1);
1681
1682 // FIXME:PTHREAD_WORK - need to check if this is necessary and, if so,
1683 // use some other kind of locking mechanism as it isn't clear why a
1684 //global mutex would be necessary versus a per-CSOUND instance mutex
1685 /*csound_global_mutex_lock();*/
1686 if (csound->multiThreadedComplete == 1) {
1687 /*csound_global_mutex_unlock();*/
1688 free(threadId);
1689 return 0UL;
1690 }
1691 /*csound_global_mutex_unlock();*/
1692
1693 nodePerf(csound, index, numThreads);
1694
1695 csound->WaitBarrier(csound->barrier2);
1696 }
1697 }
1698
kperf_nodebug(CSOUND * csound)1699 int kperf_nodebug(CSOUND *csound)
1700 {
1701 INSDS *ip;
1702 int lksmps = csound->ksmps;
1703 /* update orchestra time */
1704 csound->kcounter = ++(csound->global_kcounter);
1705 csound->icurTime += csound->ksmps;
1706 csound->curBeat += csound->curBeat_inc;
1707
1708 /* call message_dequeue to run API calls */
1709 message_dequeue(csound);
1710
1711
1712 /* if skipping time on request by 'a' score statement: */
1713 if (UNLIKELY(UNLIKELY(csound->advanceCnt))) {
1714 csound->advanceCnt--;
1715 return 1;
1716 }
1717 /* if i-time only, return now */
1718 if (UNLIKELY(csound->initonly))
1719 return 1;
1720 /* PC GUI needs attention, but avoid excessively frequent */
1721 /* calls of csoundYield() */
1722 if (UNLIKELY(--(csound->evt_poll_cnt) < 0)) {
1723 csound->evt_poll_cnt = csound->evt_poll_maxcnt;
1724 if (UNLIKELY(!csoundYield(csound))) csound->LongJmp(csound, 1);
1725 }
1726
1727 /* for one kcnt: */
1728 if (csound->oparms_.sfread) /* if audio_infile open */
1729 csound->spinrecv(csound); /* fill the spin buf */
1730 csound->spoutactive = 0; /* make spout inactive */
1731 /* clear spout */
1732 memset(csound->spout, 0, csound->nspout*sizeof(MYFLT));
1733 memset(csound->spraw, 0, csound->nspout*sizeof(MYFLT));
1734 ip = csound->actanchor.nxtact;
1735
1736 if (ip != NULL) {
1737 /* There are 2 partitions of work: 1st by inso,
1738 2nd by inso count / thread count. */
1739 if (csound->multiThreadedThreadInfo != NULL) {
1740 if (csound->dag_changed) dag_build(csound, ip);
1741 else dag_reinit(csound); /* set to initial state */
1742
1743 /* process this partition */
1744 csound->WaitBarrier(csound->barrier1);
1745
1746 (void) nodePerf(csound, 0, 1);
1747
1748 /* wait until partition is complete */
1749 csound->WaitBarrier(csound->barrier2);
1750 csound->multiThreadedDag = NULL;
1751 }
1752 else {
1753 int done;
1754 double time_end = (csound->ksmps+csound->icurTime)/csound->esr;
1755
1756 while (ip != NULL) { /* for each instr active: */
1757 INSDS *nxt = ip->nxtact;
1758 if (UNLIKELY(csound->oparms->sampleAccurate &&
1759 ip->offtim > 0 &&
1760 time_end > ip->offtim)) {
1761 /* this is the last cycle of performance */
1762 // csound->Message(csound, "last cycle %d: %f %f %d\n",
1763 // ip->insno, csound->icurTime/csound->esr,
1764 // ip->offtim, ip->no_end);
1765 ip->ksmps_no_end = ip->no_end;
1766 }
1767 done = ATOMIC_GET(ip->init_done);
1768 if (done == 1) {/* if init-pass has been done */
1769 int error = 0;
1770 OPDS *opstart = (OPDS*) ip;
1771 ip->spin = csound->spin;
1772 ip->spout = csound->spraw;
1773 ip->kcounter = csound->kcounter;
1774 if (ip->ksmps == csound->ksmps) {
1775 csound->mode = 2;
1776 while (error == 0 &&
1777 (opstart = opstart->nxtp) != NULL &&
1778 ip->actflg) {
1779 opstart->insdshead->pds = opstart;
1780 csound->op = opstart->optext->t.opcod;
1781 error = (*opstart->opadr)(csound, opstart); /* run each opcode */
1782 opstart = opstart->insdshead->pds;
1783 }
1784 csound->mode = 0;
1785 } else {
1786 int error = 0;
1787 int i, n = csound->nspout, start = 0;
1788 lksmps = ip->ksmps;
1789 int incr = csound->nchnls*lksmps;
1790 int offset = ip->ksmps_offset;
1791 int early = ip->ksmps_no_end;
1792 OPDS *opstart;
1793 ip->spin = csound->spin;
1794 ip->spout = csound->spraw;
1795 ip->kcounter = csound->kcounter*csound->ksmps/lksmps;
1796
1797 /* we have to deal with sample-accurate code
1798 whole CS_KSMPS blocks are offset here, the
1799 remainder is left to each opcode to deal with.
1800 */
1801 while (offset >= lksmps) {
1802 offset -= lksmps;
1803 start += csound->nchnls;
1804 }
1805 ip->ksmps_offset = offset;
1806 if (UNLIKELY(early)) {
1807 n -= (early*csound->nchnls);
1808 ip->ksmps_no_end = early % lksmps;
1809 }
1810
1811 for (i=start; i < n; i+=incr, ip->spin+=incr, ip->spout+=incr) {
1812 opstart = (OPDS*) ip;
1813 csound->mode = 2;
1814 while (error == 0 && (opstart = opstart->nxtp) != NULL
1815 && ip->actflg) {
1816 opstart->insdshead->pds = opstart;
1817 csound->op = opstart->optext->t.opcod;
1818 //csound->ids->optext->t.oentry->opname;
1819 error = (*opstart->opadr)(csound, opstart); /* run each opcode */
1820 opstart = opstart->insdshead->pds;
1821 }
1822 csound->mode = 0;
1823 ip->kcounter++;
1824 }
1825 }
1826 }
1827 /*else csound->Message(csound, "time %f\n",
1828 csound->kcounter/csound->ekr);*/
1829 ip->ksmps_offset = 0; /* reset sample-accuracy offset */
1830 ip->ksmps_no_end = 0; /* reset end of loop samples */
1831 ip = nxt; /* but this does not allow for all deletions */
1832 }
1833 }
1834 }
1835
1836 if (!csound->spoutactive) { /* results now in spout? */
1837 memset(csound->spout, 0, csound->nspout * sizeof(MYFLT));
1838 memset(csound->spraw, 0, csound->nspout * sizeof(MYFLT));
1839 }
1840 make_interleave(csound, lksmps);
1841 csound->spoutran(csound); /* send to audio_out */
1842 //#ifdef ANDROID
1843 //struct timespec ts;
1844 //clock_gettime(CLOCK_MONOTONIC, &ts);
1845 //csound->Message(csound, "kperf kcount, %d,%d.%06d\n",
1846 // csound->kcounter, ts.tv_sec, ts.tv_nsec/1000);
1847 //#endif
1848 return 0;
1849 }
1850
opcode_perf_debug(CSOUND * csound,csdebug_data_t * data,INSDS * ip)1851 static inline void opcode_perf_debug(CSOUND *csound,
1852 csdebug_data_t *data, INSDS *ip)
1853 {
1854 OPDS *opstart = (OPDS*) ip;
1855 while ((opstart = opstart->nxtp) != NULL) {
1856 /* check if we have arrived at a line breakpoint */
1857 bkpt_node_t *bp_node = data->bkpt_anchor->next;
1858 if (data->debug_opcode_ptr) {
1859 opstart = data->debug_opcode_ptr;
1860 data->debug_opcode_ptr = NULL;
1861 }
1862 int linenum = opstart->optext->t.linenum;
1863 while (bp_node) {
1864 if (bp_node->instr == ip->p1.value || (bp_node->instr == 0)) {
1865 if ((bp_node->line) == linenum) { /* line matches */
1866 if (bp_node->count < 2) { /* skip of 0 or 1 has the same effect */
1867 if (data->debug_opcode_ptr != opstart) { /* did we just stop here */
1868 data->debug_instr_ptr = ip;
1869 data->debug_opcode_ptr = opstart;
1870 data->status = CSDEBUG_STATUS_STOPPED;
1871 data->cur_bkpt = bp_node;
1872 csoundDebuggerBreakpointReached(csound);
1873 bp_node->count = bp_node->skip;
1874 return;
1875 }
1876 else {
1877 data->debug_opcode_ptr = NULL; /* if just stopped here-continue */
1878 }
1879 } else {
1880 bp_node->count--;
1881 }
1882 }
1883 }
1884 bp_node = bp_node->next;
1885 }
1886 opstart->insdshead->pds = opstart;
1887 csound->mode = 2;
1888 (*opstart->opadr)(csound, opstart); /* run each opcode */
1889 opstart = opstart->insdshead->pds;
1890 csound->mode = 0;
1891 }
1892 }
1893
process_debug_buffers(CSOUND * csound,csdebug_data_t * data)1894 static inline void process_debug_buffers(CSOUND *csound, csdebug_data_t *data)
1895 {
1896 bkpt_node_t *bkpt_node;
1897 while (csoundReadCircularBuffer(csound,
1898 data->bkpt_buffer, &bkpt_node, 1) == 1) {
1899 if (bkpt_node->mode == CSDEBUG_BKPT_CLEAR_ALL) {
1900 bkpt_node_t *n;
1901 while (data->bkpt_anchor->next) {
1902 n = data->bkpt_anchor->next;
1903 data->bkpt_anchor->next = n->next;
1904 csound->Free(csound, n); /* TODO this should be moved from kperf to a
1905 non-realtime context */
1906 }
1907 csound->Free(csound, bkpt_node);
1908 } else if (bkpt_node->mode == CSDEBUG_BKPT_DELETE) {
1909 bkpt_node_t *n = data->bkpt_anchor->next;
1910 bkpt_node_t *prev = data->bkpt_anchor;
1911 while (n) {
1912 if (n->line == bkpt_node->line && n->instr == bkpt_node->instr) {
1913 prev->next = n->next;
1914 if (data->cur_bkpt == n)
1915 data->cur_bkpt = n->next;
1916 csound->Free(csound, n); /* TODO this should be moved from kperf to a
1917 non-realtime context */
1918 n = prev->next;
1919 continue;
1920 }
1921 prev = n;
1922 n = n->next;
1923 }
1924 // csound->Free(csound, bkpt_node); /* TODO move to non rt context */
1925 } else {
1926 // FIXME sort list to optimize
1927 bkpt_node->next = data->bkpt_anchor->next;
1928 data->bkpt_anchor->next = bkpt_node;
1929 }
1930 }
1931 }
1932
kperf_debug(CSOUND * csound)1933 int kperf_debug(CSOUND *csound)
1934 {
1935 INSDS *ip;
1936 csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data;
1937 int lksmps = csound->ksmps;
1938 /* call message_dequeue to run API calls */
1939 message_dequeue(csound);
1940
1941 if (!data || data->status != CSDEBUG_STATUS_STOPPED) {
1942 /* update orchestra time */
1943 csound->kcounter = ++(csound->global_kcounter);
1944 csound->icurTime += csound->ksmps;
1945 csound->curBeat += csound->curBeat_inc;
1946 }
1947
1948 /* if skipping time on request by 'a' score statement: */
1949 if (UNLIKELY(csound->advanceCnt)) {
1950 csound->advanceCnt--;
1951 return 1;
1952 }
1953 /* if i-time only, return now */
1954 if (UNLIKELY(csound->initonly))
1955 return 1;
1956 /* PC GUI needs attention, but avoid excessively frequent */
1957 /* calls of csoundYield() */
1958 if (UNLIKELY(--(csound->evt_poll_cnt) < 0)) {
1959 csound->evt_poll_cnt = csound->evt_poll_maxcnt;
1960 if (UNLIKELY(!csoundYield(csound))) csound->LongJmp(csound, 1);
1961 }
1962
1963 if (data) { /* process debug commands*/
1964 process_debug_buffers(csound, data);
1965 }
1966
1967 if (!data || data->status == CSDEBUG_STATUS_RUNNING)
1968 {
1969 /* for one kcnt: */
1970 if (csound->oparms_.sfread) /* if audio_infile open */
1971 csound->spinrecv(csound); /* fill the spin buf */
1972 csound->spoutactive = 0; /* make spout inactive */
1973 /* clear spout */
1974 memset(csound->spout, 0, csound->nspout*sizeof(MYFLT));
1975 memset(csound->spraw, 0, csound->nspout*sizeof(MYFLT));
1976 }
1977
1978 ip = csound->actanchor.nxtact;
1979 /* Process debugger commands */
1980 debug_command_t command = CSDEBUG_CMD_NONE;
1981 if (data) {
1982 csoundReadCircularBuffer(csound, data->cmd_buffer, &command, 1);
1983 if (command == CSDEBUG_CMD_STOP && data->status != CSDEBUG_STATUS_STOPPED) {
1984 data->debug_instr_ptr = ip;
1985 data->status = CSDEBUG_STATUS_STOPPED;
1986 csoundDebuggerBreakpointReached(csound);
1987 }
1988 if (command == CSDEBUG_CMD_CONTINUE &&
1989 data->status == CSDEBUG_STATUS_STOPPED) {
1990 if (data->cur_bkpt && data->cur_bkpt->skip <= 2) data->cur_bkpt->count = 2;
1991 data->status = CSDEBUG_STATUS_RUNNING;
1992 if (data->debug_instr_ptr) {
1993 /* if not NULL, resume from last active */
1994 ip = data->debug_instr_ptr;
1995 data->debug_instr_ptr = NULL;
1996 }
1997 }
1998 if (command == CSDEBUG_CMD_NEXT && data->status == CSDEBUG_STATUS_STOPPED) {
1999 data->status = CSDEBUG_STATUS_NEXT;
2000 }
2001 }
2002 if (ip != NULL && data != NULL && (data->status != CSDEBUG_STATUS_STOPPED) ) {
2003 /* There are 2 partitions of work: 1st by inso,
2004 2nd by inso count / thread count. */
2005 if (csound->multiThreadedThreadInfo != NULL) {
2006 if (csound->dag_changed) dag_build(csound, ip);
2007 else dag_reinit(csound); /* set to initial state */
2008
2009 /* process this partition */
2010 csound->WaitBarrier(csound->barrier1);
2011
2012 (void) nodePerf(csound, 0, 1);
2013
2014 /* wait until partition is complete */
2015 csound->WaitBarrier(csound->barrier2);
2016 csound->multiThreadedDag = NULL;
2017 }
2018 else {
2019 int done;
2020 double time_end = (csound->ksmps+csound->icurTime)/csound->esr;
2021
2022 while (ip != NULL) { /* for each instr active: */
2023 if (UNLIKELY(csound->oparms->sampleAccurate &&
2024 ip->offtim > 0 &&
2025 time_end > ip->offtim)) {
2026 /* this is the last cycle of performance */
2027 // csound->Message(csound, "last cycle %d: %f %f %d\n",
2028 // ip->insno, csound->icurTime/csound->esr,
2029 // ip->offtim, ip->no_end);
2030 ip->ksmps_no_end = ip->no_end;
2031 }
2032 done = ATOMIC_GET(ip->init_done);
2033 if (done == 1) {/* if init-pass has been done */
2034 /* check if next command pending and we are on the
2035 first instrument in the chain */
2036 /* coverity says data already dereferenced by here */
2037 if (/*data &&*/ data->status == CSDEBUG_STATUS_NEXT) {
2038 if (data->debug_instr_ptr == NULL) {
2039 data->debug_instr_ptr = ip;
2040 data->debug_opcode_ptr = NULL;
2041 data->status = CSDEBUG_STATUS_STOPPED;
2042 csoundDebuggerBreakpointReached(csound);
2043 return 0;
2044 } else {
2045 ip = data->debug_instr_ptr;
2046 data->debug_instr_ptr = NULL;
2047 }
2048 }
2049 /* check if we have arrived at an instrument breakpoint */
2050 bkpt_node_t *bp_node = data->bkpt_anchor->next;
2051 while (bp_node && data->status != CSDEBUG_STATUS_NEXT) {
2052 if (bp_node->instr == ip->p1.value && (bp_node->line == -1) ) {
2053 if (bp_node->count < 2) {
2054 /* skip of 0 or 1 has the same effect */
2055 data->debug_instr_ptr = ip;
2056 data->debug_opcode_ptr = NULL;
2057 data->cur_bkpt = bp_node;
2058 data->status = CSDEBUG_STATUS_STOPPED;
2059 csoundDebuggerBreakpointReached(csound);
2060 bp_node->count = bp_node->skip;
2061 return 0;
2062 } else {
2063 bp_node->count--;
2064 }
2065 }
2066 bp_node = bp_node->next;
2067 }
2068 ip->spin = csound->spin;
2069 ip->spout = csound->spraw;
2070 ip->kcounter = csound->kcounter;
2071 if (ip->ksmps == csound->ksmps) {
2072 opcode_perf_debug(csound, data, ip);
2073 } else { /* when instrument has local ksmps */
2074 int i, n = csound->nspout, start = 0;
2075 lksmps = ip->ksmps;
2076 int incr = csound->nchnls*lksmps;
2077 int offset = ip->ksmps_offset;
2078 int early = ip->ksmps_no_end;
2079 ip->spin = csound->spin;
2080 ip->spout = csound->spraw;
2081 ip->kcounter = csound->kcounter*csound->ksmps/lksmps;
2082
2083 /* we have to deal with sample-accurate code
2084 whole CS_KSMPS blocks are offset here, the
2085 remainder is left to each opcode to deal with.
2086 */
2087 while (offset >= lksmps) {
2088 offset -= lksmps;
2089 start += csound->nchnls;
2090 }
2091 ip->ksmps_offset = offset;
2092 if (UNLIKELY(early)) {
2093 n -= (early*csound->nchnls);
2094 ip->ksmps_no_end = early % lksmps;
2095 }
2096
2097 for (i=start; i < n; i+=incr, ip->spin+=incr, ip->spout+=incr) {
2098 opcode_perf_debug(csound, data, ip);
2099 ip->kcounter++;
2100 }
2101 }
2102 }
2103 ip->ksmps_offset = 0; /* reset sample-accuracy offset */
2104 ip->ksmps_no_end = 0; /* reset end of loop samples */
2105 ip = ip->nxtact; /* but this does not allow for all deletions */
2106 if (/*data &&*/ data->status == CSDEBUG_STATUS_NEXT) {
2107 data->debug_instr_ptr = ip; /* we have reached the next
2108 instrument. Break */
2109 data->debug_opcode_ptr = NULL;
2110 if (ip != NULL) { /* must defer break until next kperf */
2111 data->status = CSDEBUG_STATUS_STOPPED;
2112 csoundDebuggerBreakpointReached(csound);
2113 return 0;
2114 }
2115 }
2116 }
2117 }
2118 }
2119
2120 if (!data || data->status != CSDEBUG_STATUS_STOPPED)
2121 {
2122 if (!csound->spoutactive) { /* results now in spout? */
2123 memset(csound->spout, 0, csound->nspout * sizeof(MYFLT));
2124 memset(csound->spraw, 0, csound->nspout * sizeof(MYFLT));
2125 }
2126 else
2127 make_interleave(csound, lksmps);
2128 csound->spoutran(csound); /* send to audio_out */
2129 }
2130 return 0;
2131 }
2132
2133
csoundReadScoreInternal(CSOUND * csound,const char * str)2134 int csoundReadScoreInternal(CSOUND *csound, const char *str)
2135 {
2136 OPARMS *O = csound->oparms;
2137 /* protect resource */
2138 if (csound->scorestr != NULL &&
2139 csound->scorestr->body != NULL)
2140 corfile_rewind(csound->scorestr);
2141 csound->scorestr = corfile_create_w(csound);
2142 corfile_puts(csound, (char *)str, csound->scorestr);
2143 //#ifdef SCORE_PARSER
2144 if (csound->engineStatus&CS_STATE_COMP)
2145 corfile_puts(csound, "\n#exit\n", csound->scorestr);
2146 else
2147 corfile_puts(csound, "\ne\n#exit\n", csound->scorestr);
2148 //#endif
2149 corfile_flush(csound, csound->scorestr);
2150 /* copy sorted score name */
2151 if (csound->scstr == NULL && (csound->engineStatus & CS_STATE_COMP) == 0) {
2152 scsortstr(csound, csound->scorestr);
2153 O->playscore = csound->scstr;
2154 //corfile_rm(csound, &(csound->scorestr));
2155 //printf("%s\n", O->playscore->body);
2156 }
2157 else {
2158 char *sc = scsortstr(csound, csound->scorestr);
2159 //printf("%s\n", sc);
2160 csoundInputMessageInternal(csound, (const char *) sc);
2161 csound->Free(csound, sc);
2162 corfile_rm(csound, &(csound->scorestr));
2163 }
2164 return CSOUND_SUCCESS;
2165 }
2166
2167
csoundPerformKsmps(CSOUND * csound)2168 PUBLIC int csoundPerformKsmps(CSOUND *csound)
2169 {
2170 int done;
2171 /* VL: 1.1.13 if not compiled (csoundStart() not called) */
2172 if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) {
2173 csound->Warning(csound,
2174 Str("Csound not ready for performance: csoundStart() "
2175 "has not been called\n"));
2176 return CSOUND_ERROR;
2177 }
2178 if (csound->jumpset == 0) {
2179 int returnValue;
2180 csound->jumpset = 1;
2181 /* setup jmp for return after an exit() */
2182 if (UNLIKELY((returnValue = setjmp(csound->exitjmp))))
2183 return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
2184 }
2185 if(!csound->oparms->realtime) // no API lock in realtime mode
2186 csoundLockMutex(csound->API_lock);
2187 do {
2188 done = sensevents(csound);
2189 if (UNLIKELY(done)) {
2190 if(!csound->oparms->realtime) // no API lock in realtime mode
2191 csoundUnlockMutex(csound->API_lock);
2192 csoundMessage(csound,
2193 Str("Score finished in csoundPerformKsmps() with %d.\n"),
2194 done);
2195 return done;
2196 }
2197 } while (csound->kperf(csound));
2198 if(!csound->oparms->realtime) // no API lock in realtime mode
2199 csoundUnlockMutex(csound->API_lock);
2200 return 0;
2201 }
2202
csoundPerformKsmpsInternal(CSOUND * csound)2203 static int csoundPerformKsmpsInternal(CSOUND *csound)
2204 {
2205 int done;
2206 int returnValue;
2207
2208 /* VL: 1.1.13 if not compiled (csoundStart() not called) */
2209 if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) {
2210 csound->Warning(csound,
2211 Str("Csound not ready for performance: csoundStart() "
2212 "has not been called\n"));
2213 return CSOUND_ERROR;
2214 }
2215 /* setup jmp for return after an exit() */
2216 if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) {
2217 #ifndef MACOSX
2218 csoundMessage(csound, Str("Early return from csoundPerformKsmps().\n"));
2219 #endif
2220 return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
2221 }
2222 do {
2223 if (UNLIKELY((done = sensevents(csound)))) {
2224 csoundMessage(csound,
2225 Str("Score finished in csoundPerformKsmpsInternal().\n"));
2226 return done;
2227 }
2228 } while (csound->kperf(csound));
2229 return 0;
2230 }
2231
2232 /* external host's outbuffer passed in csoundPerformBuffer() */
csoundPerformBuffer(CSOUND * csound)2233 PUBLIC int csoundPerformBuffer(CSOUND *csound)
2234 {
2235 int returnValue;
2236 int done;
2237 /* VL: 1.1.13 if not compiled (csoundStart() not called) */
2238 if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) {
2239 csound->Warning(csound,
2240 Str("Csound not ready for performance: csoundStart() "
2241 "has not been called\n"));
2242 return CSOUND_ERROR;
2243 }
2244 /* Setup jmp for return after an exit(). */
2245 if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) {
2246 #ifndef MACOSX
2247 csoundMessage(csound, Str("Early return from csoundPerformBuffer().\n"));
2248 #endif
2249 return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
2250 }
2251 csound->sampsNeeded += csound->oparms_.outbufsamps;
2252 while (csound->sampsNeeded > 0) {
2253 if(!csound->oparms->realtime) {// no API lock in realtime mode
2254 csoundLockMutex(csound->API_lock);
2255 }
2256 do {
2257 if (UNLIKELY((done = sensevents(csound)))){
2258 if(!csound->oparms->realtime) // no API lock in realtime mode
2259 csoundUnlockMutex(csound->API_lock);
2260 return done;
2261 }
2262 } while (csound->kperf(csound));
2263 if(!csound->oparms->realtime) { // no API lock in realtime mode
2264 csoundUnlockMutex(csound->API_lock);
2265 }
2266 csound->sampsNeeded -= csound->nspout;
2267 }
2268 return 0;
2269 }
2270
2271 /* perform an entire score */
2272
csoundPerform(CSOUND * csound)2273 PUBLIC int csoundPerform(CSOUND *csound)
2274 {
2275 int done;
2276 int returnValue;
2277
2278 /* VL: 1.1.13 if not compiled (csoundStart() not called) */
2279 if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) {
2280 csound->Warning(csound,
2281 Str("Csound not ready for performance: csoundStart() "
2282 "has not been called\n"));
2283 return CSOUND_ERROR;
2284 }
2285
2286 csound->performState = 0;
2287 /* setup jmp for return after an exit() */
2288 if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) {
2289 #ifndef MACOSX
2290 csoundMessage(csound, Str("Early return from csoundPerform().\n"));
2291 #endif
2292 return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
2293 }
2294 do {
2295 if(!csound->oparms->realtime)
2296 csoundLockMutex(csound->API_lock);
2297 do {
2298 if (UNLIKELY((done = sensevents(csound)))) {
2299 csoundMessage(csound, Str("Score finished in csoundPerform().\n"));
2300 if(!csound->oparms->realtime)
2301 csoundUnlockMutex(csound->API_lock);
2302 if (csound->oparms->numThreads > 1) {
2303 csound->multiThreadedComplete = 1;
2304 csound->WaitBarrier(csound->barrier1);
2305 }
2306 return done;
2307 }
2308 } while (csound->kperf(csound));
2309 if(!csound->oparms->realtime)
2310 csoundUnlockMutex(csound->API_lock);
2311 } while ((unsigned char) csound->performState == (unsigned char) '\0');
2312 csoundMessage(csound, Str("csoundPerform(): stopped.\n"));
2313 csound->performState = 0;
2314 return 0;
2315 }
2316
2317 /* stop a csoundPerform() running in another thread */
2318
csoundGetNamedGens(CSOUND * csound)2319 PUBLIC void *csoundGetNamedGens(CSOUND *csound)
2320 {
2321 return csound->namedgen;
2322 }
2323
csoundStop(CSOUND * csound)2324 PUBLIC void csoundStop(CSOUND *csound)
2325 {
2326 csound->performState = -1;
2327 }
2328
2329 /*
2330 * ATTRIBUTES
2331 */
2332
csoundGetCurrentTimeSamples(CSOUND * csound)2333 PUBLIC int64_t csoundGetCurrentTimeSamples(CSOUND *csound){
2334 return csound->icurTime;
2335 }
2336
csoundGetSr(CSOUND * csound)2337 PUBLIC MYFLT csoundGetSr(CSOUND *csound)
2338 {
2339 return csound->esr;
2340 }
2341
csoundGetKr(CSOUND * csound)2342 PUBLIC MYFLT csoundGetKr(CSOUND *csound)
2343 {
2344 return csound->ekr;
2345 }
2346
csoundGetKsmps(CSOUND * csound)2347 PUBLIC uint32_t csoundGetKsmps(CSOUND *csound)
2348 {
2349 return csound->ksmps;
2350 }
2351
csoundGetNchnls(CSOUND * csound)2352 PUBLIC uint32_t csoundGetNchnls(CSOUND *csound)
2353 {
2354 return csound->nchnls;
2355 }
2356
csoundGetNchnlsInput(CSOUND * csound)2357 PUBLIC uint32_t csoundGetNchnlsInput(CSOUND *csound)
2358 {
2359 if (csound->inchnls >= 0)
2360 return (uint32_t) csound->inchnls;
2361 else return csound->nchnls;
2362 }
2363
csoundGet0dBFS(CSOUND * csound)2364 PUBLIC MYFLT csoundGet0dBFS(CSOUND *csound)
2365 {
2366 return csound->e0dbfs;
2367 }
2368
csoundGetInputBufferSize(CSOUND * csound)2369 PUBLIC long csoundGetInputBufferSize(CSOUND *csound)
2370 {
2371 return csound->oparms_.inbufsamps;
2372 }
2373
csoundGetOutputBufferSize(CSOUND * csound)2374 PUBLIC long csoundGetOutputBufferSize(CSOUND *csound)
2375 {
2376 return csound->oparms_.outbufsamps;
2377 }
2378
csoundGetSpin(CSOUND * csound)2379 PUBLIC MYFLT *csoundGetSpin(CSOUND *csound)
2380 {
2381 return csound->spin;
2382 }
2383
csoundSetSpinSample(CSOUND * csound,int frame,int channel,MYFLT sample)2384 PUBLIC void csoundSetSpinSample(CSOUND *csound, int frame,
2385 int channel, MYFLT sample)
2386 {
2387 int index = (frame * csound->inchnls) + channel;
2388 csound->spin[index] = sample;
2389 }
2390
csoundClearSpin(CSOUND * csound)2391 PUBLIC void csoundClearSpin(CSOUND *csound) {
2392
2393 memset(csound->spin, 0, sizeof(MYFLT)*csound->ksmps*csound->nchnls);
2394 }
2395
csoundAddSpinSample(CSOUND * csound,int frame,int channel,MYFLT sample)2396 PUBLIC void csoundAddSpinSample(CSOUND *csound, int frame,
2397 int channel, MYFLT sample)
2398 {
2399
2400 int index = (frame * csound->inchnls) + channel;
2401 csound->spin[index] += sample;
2402 }
2403
csoundGetSpout(CSOUND * csound)2404 PUBLIC MYFLT *csoundGetSpout(CSOUND *csound)
2405 {
2406 return csound->spout;
2407 }
2408
csoundGetSpoutSample(CSOUND * csound,int frame,int channel)2409 PUBLIC MYFLT csoundGetSpoutSample(CSOUND *csound, int frame, int channel)
2410 {
2411 int index = (frame * csound->nchnls) + channel;
2412 return csound->spout[index];
2413 }
2414
csoundGetOutputName(CSOUND * csound)2415 PUBLIC const char *csoundGetOutputName(CSOUND *csound)
2416 {
2417 return (const char*) csound->oparms_.outfilename;
2418 }
2419
csoundGetInputName(CSOUND * csound)2420 PUBLIC const char *csoundGetInputName(CSOUND *csound)
2421 {
2422 return (const char*) csound->oparms_.infilename;
2423 }
2424
2425 /**
2426 * Calling this function with a non-zero will disable all default
2427 * handling of sound I/O by the Csound library, allowing the host
2428 * application to use the spin/<spout/input/output buffers directly.
2429 * If 'bufSize' is greater than zero, the buffer size (-b) will be
2430 * set to the integer multiple of ksmps that is nearest to the value
2431 * specified.
2432 */
2433
csoundSetHostImplementedAudioIO(CSOUND * csound,int state,int bufSize)2434 PUBLIC void csoundSetHostImplementedAudioIO(CSOUND *csound,
2435 int state, int bufSize)
2436 {
2437 csound->enableHostImplementedAudioIO = state;
2438 csound->hostRequestedBufferSize = (bufSize > 0 ? bufSize : 0);
2439 }
2440
csoundSetHostImplementedMIDIIO(CSOUND * csound,int state)2441 PUBLIC void csoundSetHostImplementedMIDIIO(CSOUND *csound,
2442 int state)
2443 {
2444 csound->enableHostImplementedMIDIIO = state;
2445 }
2446
csoundGetScoreTime(CSOUND * csound)2447 PUBLIC double csoundGetScoreTime(CSOUND *csound)
2448 {
2449 double curtime = csound->icurTime;
2450 double esr = csound->esr;
2451 return curtime/esr;
2452 }
2453
2454 /*
2455 * SCORE HANDLING
2456 */
2457
csoundIsScorePending(CSOUND * csound)2458 PUBLIC int csoundIsScorePending(CSOUND *csound)
2459 {
2460 return csound->csoundIsScorePending_;
2461 }
2462
csoundSetScorePending(CSOUND * csound,int pending)2463 PUBLIC void csoundSetScorePending(CSOUND *csound, int pending)
2464 {
2465 csound->csoundIsScorePending_ = pending;
2466 }
2467
csoundSetScoreOffsetSeconds(CSOUND * csound,MYFLT offset)2468 PUBLIC void csoundSetScoreOffsetSeconds(CSOUND *csound, MYFLT offset)
2469 {
2470 double aTime;
2471 MYFLT prv = (MYFLT) csound->csoundScoreOffsetSeconds_;
2472
2473 csound->csoundScoreOffsetSeconds_ = offset;
2474 if (offset < FL(0.0))
2475 return;
2476 /* if csoundCompile() was not called yet, just store the offset */
2477 if (!(csound->engineStatus & CS_STATE_COMP))
2478 return;
2479 /* otherwise seek to the requested time now */
2480 aTime = (double) offset - (csound->icurTime/csound->esr);
2481 if (aTime < 0.0 || offset < prv) {
2482 csoundRewindScore(csound); /* will call csoundSetScoreOffsetSeconds */
2483 return;
2484 }
2485 if (aTime > 0.0) {
2486 EVTBLK evt;
2487 memset(&evt, 0, sizeof(EVTBLK));
2488 evt.strarg = NULL; evt.scnt = 0;
2489 evt.opcod = 'a';
2490 evt.pcnt = 3;
2491 evt.p[2] = evt.p[1] = FL(0.0);
2492 evt.p[3] = (MYFLT) aTime;
2493 insert_score_event_at_sample(csound, &evt, csound->icurTime);
2494 }
2495 }
2496
csoundGetScoreOffsetSeconds(CSOUND * csound)2497 PUBLIC MYFLT csoundGetScoreOffsetSeconds(CSOUND *csound)
2498 {
2499 return csound->csoundScoreOffsetSeconds_;
2500 }
2501
2502 extern void musmon_rewind_score(CSOUND *csound); /* musmon.c */
2503 extern void midifile_rewind_score(CSOUND *csound); /* midifile.c */
2504
csoundRewindScore(CSOUND * csound)2505 PUBLIC void csoundRewindScore(CSOUND *csound)
2506 {
2507 musmon_rewind_score(csound);
2508 if (csound->oparms->FMidiname != NULL) midifile_rewind_score(csound);
2509 }
2510
csoundSetCscoreCallback(CSOUND * p,void (* cscoreCallback)(CSOUND *))2511 PUBLIC void csoundSetCscoreCallback(CSOUND *p,
2512 void (*cscoreCallback)(CSOUND *))
2513 {
2514 p->cscoreCallback_ = (cscoreCallback != NULL ? cscoreCallback : cscore_);
2515 }
2516
csoundDefaultMessageCallback(CSOUND * csound,int attr,const char * format,va_list args)2517 static void csoundDefaultMessageCallback(CSOUND *csound, int attr,
2518 const char *format, va_list args)
2519 {
2520 #if defined(WIN32)
2521 switch (attr & CSOUNDMSG_TYPE_MASK) {
2522 case CSOUNDMSG_ERROR:
2523 case CSOUNDMSG_WARNING:
2524 case CSOUNDMSG_REALTIME:
2525 vfprintf(stderr, format, args);
2526 break;
2527 default:
2528 vfprintf(stdout, format, args);
2529 }
2530 #else
2531 FILE *fp = stderr;
2532 if ((attr & CSOUNDMSG_TYPE_MASK) == CSOUNDMSG_STDOUT)
2533 fp = stdout;
2534 if (!attr || !csound->enableMsgAttr) {
2535 vfprintf(fp, format, args);
2536 return;
2537 }
2538 if ((attr & CSOUNDMSG_TYPE_MASK) == CSOUNDMSG_ORCH)
2539 if (attr & CSOUNDMSG_BG_COLOR_MASK)
2540 fprintf(fp, "\033[4%cm", ((attr & 0x70) >> 4) + '0');
2541 if (attr & CSOUNDMSG_FG_ATTR_MASK) {
2542 if (attr & CSOUNDMSG_FG_BOLD)
2543 fprintf(fp, "\033[1m");
2544 if (attr & CSOUNDMSG_FG_UNDERLINE)
2545 fprintf(fp, "\033[4m");
2546 }
2547 if (attr & CSOUNDMSG_FG_COLOR_MASK)
2548 fprintf(fp, "\033[3%cm", (attr & 7) + '0');
2549 vfprintf(fp, format, args);
2550 fprintf(fp, "\033[m");
2551 #endif
2552 }
2553
csoundSetDefaultMessageCallback(void (* csoundMessageCallback)(CSOUND * csound,int attr,const char * format,va_list args))2554 PUBLIC void csoundSetDefaultMessageCallback(
2555 void (*csoundMessageCallback)(CSOUND *csound,
2556 int attr,
2557 const char *format,
2558 va_list args))
2559 {
2560 if (csoundMessageCallback) {
2561 msgcallback_ = csoundMessageCallback;
2562 } else {
2563 msgcallback_ = csoundDefaultMessageCallback;
2564 }
2565 }
2566
2567
2568
csoundSetMessageStringCallback(CSOUND * csound,void (* csoundMessageStrCallback)(CSOUND * csound,int attr,const char * str))2569 PUBLIC void csoundSetMessageStringCallback(CSOUND *csound,
2570 void (*csoundMessageStrCallback)(CSOUND *csound,
2571 int attr,
2572 const char *str)) {
2573
2574 if (csoundMessageStrCallback) {
2575 if(csound->message_string == NULL)
2576 csound->message_string = (char *) csound->Calloc(csound, MAX_MESSAGE_STR);
2577 csound->csoundMessageStringCallback = csoundMessageStrCallback;
2578 csound->csoundMessageCallback_ = NULL;
2579 }
2580
2581 }
2582
csoundSetMessageCallback(CSOUND * csound,void (* csoundMessageCallback)(CSOUND * csound,int attr,const char * format,va_list args))2583 PUBLIC void csoundSetMessageCallback(CSOUND *csound,
2584 void (*csoundMessageCallback)(CSOUND *csound,
2585 int attr,
2586 const char *format,
2587 va_list args))
2588 {
2589 /* Protect against a null callback. */
2590 if (csoundMessageCallback) {
2591 csound->csoundMessageCallback_ = csoundMessageCallback;
2592 } else {
2593 csound->csoundMessageCallback_ = csoundDefaultMessageCallback;
2594 }
2595 }
2596
csoundMessageV(CSOUND * csound,int attr,const char * format,va_list args)2597 PUBLIC void csoundMessageV(CSOUND *csound,
2598 int attr, const char *format, va_list args)
2599 {
2600 if(csound->csoundMessageCallback_) {
2601 csound->csoundMessageCallback_(csound, attr, format, args);
2602 } else {
2603 vsnprintf(csound->message_string, MAX_MESSAGE_STR, format, args);
2604 csound->csoundMessageStringCallback(csound, attr, csound->message_string);
2605 }
2606 }
2607
csoundMessage(CSOUND * csound,const char * format,...)2608 PUBLIC void csoundMessage(CSOUND *csound, const char *format, ...)
2609 {
2610 va_list args;
2611 va_start(args, format);
2612 if(csound->csoundMessageCallback_)
2613 csound->csoundMessageCallback_(csound, 0, format, args);
2614 else {
2615 vsnprintf(csound->message_string, MAX_MESSAGE_STR, format, args);
2616 csound->csoundMessageStringCallback(csound, 0, csound->message_string);
2617 }
2618 va_end(args);
2619 }
2620
csoundMessageS(CSOUND * csound,int attr,const char * format,...)2621 PUBLIC void csoundMessageS(CSOUND *csound, int attr, const char *format, ...)
2622 {
2623 va_list args;
2624 va_start(args, format);
2625 if(csound->csoundMessageCallback_)
2626 csound->csoundMessageCallback_(csound, attr, format, args);
2627 else {
2628 vsnprintf(csound->message_string, MAX_MESSAGE_STR, format, args);
2629 csound->csoundMessageStringCallback(csound, attr, csound->message_string);
2630 }
2631 va_end(args);
2632 }
2633
csoundDie(CSOUND * csound,const char * msg,...)2634 void csoundDie(CSOUND *csound, const char *msg, ...)
2635 {
2636 va_list args;
2637 va_start(args, msg);
2638 csound->ErrMsgV(csound, (char*) 0, msg, args);
2639 va_end(args);
2640 csound->perferrcnt++;
2641 csound->LongJmp(csound, 1);
2642 }
2643
csoundWarning(CSOUND * csound,const char * msg,...)2644 void csoundWarning(CSOUND *csound, const char *msg, ...)
2645 {
2646 va_list args;
2647 if (!(csound->oparms_.msglevel & WARNMSG))
2648 return;
2649 csoundMessageS(csound, CSOUNDMSG_WARNING, Str("WARNING: "));
2650 va_start(args, msg);
2651 csoundMessageV(csound, CSOUNDMSG_WARNING, msg, args);
2652 va_end(args);
2653 csoundMessageS(csound, CSOUNDMSG_WARNING, "\n");
2654 }
2655
csoundDebugMsg(CSOUND * csound,const char * msg,...)2656 void csoundDebugMsg(CSOUND *csound, const char *msg, ...)
2657 {
2658 va_list args;
2659 if (!(csound->oparms_.odebug))
2660 return;
2661 va_start(args, msg);
2662 csoundMessageV(csound, 0, msg, args);
2663 va_end(args);
2664 csoundMessage(csound, "\n");
2665 }
2666
csoundErrorMsg(CSOUND * csound,const char * msg,...)2667 void csoundErrorMsg(CSOUND *csound, const char *msg, ...)
2668 {
2669 va_list args;
2670 va_start(args, msg);
2671 csoundMessageV(csound, CSOUNDMSG_ERROR, msg, args);
2672 va_end(args);
2673 csound->MessageS(csound, CSOUNDMSG_ERROR, "\n");
2674 }
2675
csoundErrMsgV(CSOUND * csound,const char * hdr,const char * msg,va_list args)2676 void csoundErrMsgV(CSOUND *csound,
2677 const char *hdr, const char *msg, va_list args)
2678 {
2679 if (hdr != NULL)
2680 csound->MessageS(csound, CSOUNDMSG_ERROR, "%s", hdr);
2681 csoundMessageV(csound, CSOUNDMSG_ERROR, msg, args);
2682 csound->MessageS(csound, CSOUNDMSG_ERROR, "\n");
2683 }
2684
csoundLongJmp(CSOUND * csound,int retval)2685 void csoundLongJmp(CSOUND *csound, int retval)
2686 {
2687 int n = CSOUND_EXITJMP_SUCCESS;
2688
2689 n = (retval < 0 ? n + retval : n - retval) & (CSOUND_EXITJMP_SUCCESS - 1);
2690 //printf("**** n = %d\n", n);
2691 if (!n)
2692 n = CSOUND_EXITJMP_SUCCESS;
2693
2694 csound->curip = NULL;
2695 csound->ids = NULL;
2696 csound->reinitflag = 0;
2697 csound->tieflag = 0;
2698 csound->perferrcnt += csound->inerrcnt;
2699 csound->inerrcnt = 0;
2700 csound->engineStatus |= CS_STATE_JMP;
2701 //printf("**** longjmp with %d\n", n);
2702 longjmp(csound->exitjmp, n);
2703 }
2704
csoundSetMessageLevel(CSOUND * csound,int messageLevel)2705 PUBLIC void csoundSetMessageLevel(CSOUND *csound, int messageLevel)
2706 {
2707 csound->oparms_.msglevel = messageLevel;
2708 }
2709
csoundGetMessageLevel(CSOUND * csound)2710 PUBLIC int csoundGetMessageLevel(CSOUND *csound)
2711 {
2712 return csound->oparms_.msglevel;
2713 }
2714
csoundKeyPress(CSOUND * csound,char c)2715 PUBLIC void csoundKeyPress(CSOUND *csound, char c)
2716 {
2717 csound->inChar_ = (int) ((unsigned char) c);
2718 }
2719
2720 /*
2721 * CONTROL AND EVENTS
2722 */
2723
2724 PUBLIC void
csoundSetInputChannelCallback(CSOUND * csound,channelCallback_t inputChannelCalback)2725 csoundSetInputChannelCallback(CSOUND *csound,
2726 channelCallback_t inputChannelCalback)
2727 {
2728 csound->InputChannelCallback_ = inputChannelCalback;
2729 }
2730
2731 PUBLIC void
csoundSetOutputChannelCallback(CSOUND * csound,channelCallback_t outputChannelCalback)2732 csoundSetOutputChannelCallback(CSOUND *csound,
2733 channelCallback_t outputChannelCalback)
2734 {
2735 csound->OutputChannelCallback_ = outputChannelCalback;
2736 }
2737
csoundScoreEventInternal(CSOUND * csound,char type,const MYFLT * pfields,long numFields)2738 int csoundScoreEventInternal(CSOUND *csound, char type,
2739 const MYFLT *pfields, long numFields)
2740 {
2741 EVTBLK evt;
2742 int i;
2743 int ret;
2744 memset(&evt, 0, sizeof(EVTBLK));
2745
2746 evt.strarg = NULL; evt.scnt = 0;
2747 evt.opcod = type;
2748 evt.pcnt = (int16) numFields;
2749 for (i = 0; i < (int) numFields; i++)
2750 evt.p[i + 1] = pfields[i];
2751 ret = insert_score_event_at_sample(csound, &evt, csound->icurTime);
2752 return ret;
2753 }
2754
csoundScoreEventAbsoluteInternal(CSOUND * csound,char type,const MYFLT * pfields,long numFields,double time_ofs)2755 int csoundScoreEventAbsoluteInternal(CSOUND *csound, char type,
2756 const MYFLT *pfields, long numFields,
2757 double time_ofs)
2758 {
2759 EVTBLK evt;
2760 int i;
2761 int ret;
2762 memset(&evt, 0, sizeof(EVTBLK));
2763
2764 evt.strarg = NULL; evt.scnt = 0;
2765 evt.opcod = type;
2766 evt.pcnt = (int16) numFields;
2767 for (i = 0; i < (int) numFields; i++)
2768 evt.p[i + 1] = pfields[i];
2769 ret = insert_score_event(csound, &evt, time_ofs);
2770 return ret;
2771 }
2772
2773 /*
2774 * REAL-TIME AUDIO
2775 */
2776
2777 /* dummy functions for the case when no real-time audio module is available */
2778
get_dummy_rtaudio_globals(CSOUND * csound)2779 static double *get_dummy_rtaudio_globals(CSOUND *csound)
2780 {
2781 double *p;
2782
2783 p = (double*) csound->QueryGlobalVariable(csound, "__rtaudio_null_state");
2784 if (p == NULL) {
2785 if (UNLIKELY(csound->CreateGlobalVariable(csound, "__rtaudio_null_state",
2786 sizeof(double) * 4) != 0))
2787 csound->Die(csound, Str("rtdummy: failed to allocate globals"));
2788 csound->Message(csound, Str("rtaudio: dummy module enabled\n"));
2789 p = (double*) csound->QueryGlobalVariable(csound, "__rtaudio_null_state");
2790 }
2791 return p;
2792 }
2793
dummy_rtaudio_timer(CSOUND * csound,double * p)2794 static void dummy_rtaudio_timer(CSOUND *csound, double *p)
2795 {
2796 double timeWait;
2797 int i;
2798
2799 timeWait = p[0] - csoundGetRealTime(csound->csRtClock);
2800 i = (int) (timeWait * 1000.0 + 0.5);
2801 if (i > 0)
2802 csoundSleep((size_t) i);
2803 }
2804
playopen_dummy(CSOUND * csound,const csRtAudioParams * parm)2805 int playopen_dummy(CSOUND *csound, const csRtAudioParams *parm)
2806 {
2807 double *p;
2808 char *s;
2809
2810 /* find out if the use of dummy real-time audio functions was requested, */
2811 /* or an unknown plugin name was specified; the latter case is an error */
2812 s = (char*) csoundQueryGlobalVariable(csound, "_RTAUDIO");
2813 if (s != NULL && !(strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 ||
2814 strcmp(s, "NULL") == 0)) {
2815 if (s[0] == '\0')
2816 csoundErrorMsg(csound,
2817 Str(" *** error: rtaudio module set to empty string"));
2818 else {
2819 // print_opcodedir_warning(csound);
2820 csoundErrorMsg(csound,
2821 Str(" unknown rtaudio module: '%s', using dummy module"),
2822 s);
2823 }
2824 // return CSOUND_ERROR;
2825 }
2826 p = get_dummy_rtaudio_globals(csound);
2827 csound->rtPlay_userdata = (void*) p;
2828 p[0] = csound->GetRealTime(csound->csRtClock);
2829 p[1] = 1.0 / ((double) ((int) sizeof(MYFLT) * parm->nChannels)
2830 * (double) parm->sampleRate);
2831 return CSOUND_SUCCESS;
2832 }
2833
rtplay_dummy(CSOUND * csound,const MYFLT * outBuf,int nbytes)2834 void rtplay_dummy(CSOUND *csound, const MYFLT *outBuf, int nbytes)
2835 {
2836 double *p = (double*) csound->rtPlay_userdata;
2837 (void) outBuf;
2838 p[0] += ((double) nbytes * p[1]);
2839 dummy_rtaudio_timer(csound, p);
2840 }
2841
recopen_dummy(CSOUND * csound,const csRtAudioParams * parm)2842 int recopen_dummy(CSOUND *csound, const csRtAudioParams *parm)
2843 {
2844 double *p;
2845 char *s;
2846
2847 /* find out if the use of dummy real-time audio functions was requested, */
2848 /* or an unknown plugin name was specified; the latter case is an error */
2849 s = (char*) csoundQueryGlobalVariable(csound, "_RTAUDIO");
2850 if (s != NULL && !(strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 ||
2851 strcmp(s, "NULL") == 0)) {
2852 if (s[0] == '\0')
2853 csoundErrorMsg(csound,
2854 Str(" *** error: rtaudio module set to empty string"));
2855 else {
2856 // print_opcodedir_warning(csound);
2857 csoundErrorMsg(csound,
2858 Str(" unknown rtaudio module: '%s', using dummy module"),
2859 s);
2860 }
2861 // return CSOUND_ERROR;
2862 }
2863 p = (double*) get_dummy_rtaudio_globals(csound) + 2;
2864 csound->rtRecord_userdata = (void*) p;
2865 p[0] = csound->GetRealTime(csound->csRtClock);
2866 p[1] = 1.0 / ((double) ((int) sizeof(MYFLT) * parm->nChannels)
2867 * (double) parm->sampleRate);
2868 return CSOUND_SUCCESS;
2869 }
2870
rtrecord_dummy(CSOUND * csound,MYFLT * inBuf,int nbytes)2871 int rtrecord_dummy(CSOUND *csound, MYFLT *inBuf, int nbytes)
2872 {
2873 double *p = (double*) csound->rtRecord_userdata;
2874
2875 /* for (i = 0; i < (nbytes / (int) sizeof(MYFLT)); i++) */
2876 /* ((MYFLT*) inBuf)[i] = FL(0.0); */
2877 memset(inBuf, 0, nbytes);
2878
2879 p[0] += ((double) nbytes * p[1]);
2880 dummy_rtaudio_timer(csound, p);
2881
2882 return nbytes;
2883 }
2884
rtclose_dummy(CSOUND * csound)2885 void rtclose_dummy(CSOUND *csound)
2886 {
2887 csound->rtPlay_userdata = NULL;
2888 csound->rtRecord_userdata = NULL;
2889 }
2890
audio_dev_list_dummy(CSOUND * csound,CS_AUDIODEVICE * list,int isOutput)2891 int audio_dev_list_dummy(CSOUND *csound,
2892 CS_AUDIODEVICE *list, int isOutput)
2893 {
2894 IGN(csound); IGN(list); IGN(isOutput);
2895 return 0;
2896 }
2897
midi_dev_list_dummy(CSOUND * csound,CS_MIDIDEVICE * list,int isOutput)2898 int midi_dev_list_dummy(CSOUND *csound, CS_MIDIDEVICE *list, int isOutput){
2899 IGN(csound); IGN(list); IGN(isOutput);
2900 return 0;
2901 }
2902
csoundSetPlayopenCallback(CSOUND * csound,int (* playopen__)(CSOUND *,const csRtAudioParams * parm))2903 PUBLIC void csoundSetPlayopenCallback(CSOUND *csound,
2904 int (*playopen__)(CSOUND *,
2905 const csRtAudioParams
2906 *parm))
2907 {
2908 csound->playopen_callback = playopen__;
2909 }
2910
csoundSetRtplayCallback(CSOUND * csound,void (* rtplay__)(CSOUND *,const MYFLT * outBuf,int nbytes))2911 PUBLIC void csoundSetRtplayCallback(CSOUND *csound,
2912 void (*rtplay__)(CSOUND *,
2913 const MYFLT *outBuf,
2914 int nbytes))
2915 {
2916 csound->rtplay_callback = rtplay__;
2917 }
2918
csoundSetRecopenCallback(CSOUND * csound,int (* recopen__)(CSOUND *,const csRtAudioParams * parm))2919 PUBLIC void csoundSetRecopenCallback(CSOUND *csound,
2920 int (*recopen__)(CSOUND *,
2921 const csRtAudioParams *parm))
2922 {
2923 csound->recopen_callback = recopen__;
2924 }
2925
csoundSetRtrecordCallback(CSOUND * csound,int (* rtrecord__)(CSOUND *,MYFLT * inBuf,int nbytes))2926 PUBLIC void csoundSetRtrecordCallback(CSOUND *csound,
2927 int (*rtrecord__)(CSOUND *,
2928 MYFLT *inBuf,
2929 int nbytes))
2930 {
2931 csound->rtrecord_callback = rtrecord__;
2932 }
2933
csoundSetRtcloseCallback(CSOUND * csound,void (* rtclose__)(CSOUND *))2934 PUBLIC void csoundSetRtcloseCallback(CSOUND *csound,
2935 void (*rtclose__)(CSOUND *))
2936 {
2937 csound->rtclose_callback = rtclose__;
2938 }
2939
csoundSetAudioDeviceListCallback(CSOUND * csound,int (* audiodevlist__)(CSOUND *,CS_AUDIODEVICE * list,int isOutput))2940 PUBLIC void csoundSetAudioDeviceListCallback(CSOUND *csound,
2941 int (*audiodevlist__)(CSOUND *, CS_AUDIODEVICE *list, int isOutput))
2942 {
2943 csound->audio_dev_list_callback = audiodevlist__;
2944 }
2945
csoundSetMIDIDeviceListCallback(CSOUND * csound,int (* mididevlist__)(CSOUND *,CS_MIDIDEVICE * list,int isOutput))2946 PUBLIC void csoundSetMIDIDeviceListCallback(CSOUND *csound,
2947 int (*mididevlist__)(CSOUND *, CS_MIDIDEVICE *list, int isOutput))
2948 {
2949 csound->midi_dev_list_callback = mididevlist__;
2950 }
2951
csoundGetAudioDevList(CSOUND * csound,CS_AUDIODEVICE * list,int isOutput)2952 PUBLIC int csoundGetAudioDevList(CSOUND *csound,
2953 CS_AUDIODEVICE *list, int isOutput){
2954 return csound->audio_dev_list_callback(csound,list,isOutput);
2955 }
2956
csoundGetMIDIDevList(CSOUND * csound,CS_MIDIDEVICE * list,int isOutput)2957 PUBLIC int csoundGetMIDIDevList(CSOUND *csound, CS_MIDIDEVICE *list, int isOutput)
2958 {
2959 return csound->midi_dev_list_callback(csound,list,isOutput);
2960 }
2961
2962
2963 /* dummy real time MIDI functions */
DummyMidiInOpen(CSOUND * csound,void ** userData,const char * devName)2964 int DummyMidiInOpen(CSOUND *csound, void **userData,
2965 const char *devName)
2966 {
2967 char *s;
2968
2969 (void) devName;
2970 *userData = NULL;
2971 s = (char*) csoundQueryGlobalVariable(csound, "_RTMIDI");
2972 if (UNLIKELY(s == NULL ||
2973 (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 ||
2974 strcmp(s, "NULL") == 0))) {
2975 csoundMessage(csound, Str("!!WARNING: real time midi input disabled, "
2976 "using dummy functions\n"));
2977 return 0;
2978 }
2979 if (s[0] == '\0')
2980 csoundErrorMsg(csound, Str("error: -+rtmidi set to empty string"));
2981 else {
2982 print_opcodedir_warning(csound);
2983 csoundErrorMsg(csound, Str("error: -+rtmidi='%s': unknown module"), s);
2984 }
2985 return -1;
2986 }
2987
DummyMidiRead(CSOUND * csound,void * userData,unsigned char * buf,int nbytes)2988 int DummyMidiRead(CSOUND *csound, void *userData,
2989 unsigned char *buf, int nbytes)
2990 {
2991 (void) csound;
2992 (void) userData;
2993 (void) buf;
2994 (void) nbytes;
2995 return 0;
2996 }
2997
DummyMidiOutOpen(CSOUND * csound,void ** userData,const char * devName)2998 int DummyMidiOutOpen(CSOUND *csound, void **userData,
2999 const char *devName)
3000 {
3001 char *s;
3002
3003 (void) devName;
3004 *userData = NULL;
3005 s = (char*) csoundQueryGlobalVariable(csound, "_RTMIDI");
3006 if (s == NULL ||
3007 (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 ||
3008 strcmp(s, "NULL") == 0)) {
3009 csoundMessage(csound, Str("WARNING: real time midi output disabled, "
3010 "using dummy functions\n"));
3011 return 0;
3012 }
3013 if (s[0] == '\0')
3014 csoundErrorMsg(csound, Str("error: -+rtmidi set to empty string"));
3015 else {
3016 print_opcodedir_warning(csound);
3017 csoundErrorMsg(csound, Str("error: -+rtmidi='%s': unknown module"), s);
3018 }
3019 return -1;
3020 }
3021
DummyMidiWrite(CSOUND * csound,void * userData,const unsigned char * buf,int nbytes)3022 int DummyMidiWrite(CSOUND *csound, void *userData,
3023 const unsigned char *buf, int nbytes)
3024 {
3025 (void) csound;
3026 (void) userData;
3027 (void) buf;
3028 return nbytes;
3029 }
3030
3031 static const char *midi_err_msg = Str_noop("Unknown MIDI error");
3032
3033 /**
3034 * Returns pointer to a string constant storing an error massage
3035 * for error code 'errcode'.
3036 */
csoundExternalMidiErrorString(CSOUND * csound,int errcode)3037 const char *csoundExternalMidiErrorString(CSOUND *csound, int errcode)
3038 {
3039 if (csound->midiGlobals->MidiErrorStringCallback == NULL)
3040 return midi_err_msg;
3041 return (csound->midiGlobals->MidiErrorStringCallback(errcode));
3042 }
3043
3044 /* Set real time MIDI function pointers. */
3045
csoundSetExternalMidiInOpenCallback(CSOUND * csound,int (* func)(CSOUND *,void **,const char *))3046 PUBLIC void csoundSetExternalMidiInOpenCallback(CSOUND *csound,
3047 int (*func)(CSOUND *,
3048 void **,
3049 const char *))
3050 {
3051 csound->midiGlobals->MidiInOpenCallback = func;
3052 }
3053
csoundSetExternalMidiReadCallback(CSOUND * csound,int (* func)(CSOUND *,void *,unsigned char *,int))3054 PUBLIC void csoundSetExternalMidiReadCallback(CSOUND *csound,
3055 int (*func)(CSOUND *,
3056 void *,
3057 unsigned char *, int))
3058 {
3059 csound->midiGlobals->MidiReadCallback = func;
3060 }
3061
csoundSetExternalMidiInCloseCallback(CSOUND * csound,int (* func)(CSOUND *,void *))3062 PUBLIC void csoundSetExternalMidiInCloseCallback(CSOUND *csound,
3063 int (*func)(CSOUND *, void *))
3064 {
3065 csound->midiGlobals->MidiInCloseCallback = func;
3066 }
3067
csoundSetExternalMidiOutOpenCallback(CSOUND * csound,int (* func)(CSOUND *,void **,const char *))3068 PUBLIC void csoundSetExternalMidiOutOpenCallback(CSOUND *csound,
3069 int (*func)(CSOUND *,
3070 void **,
3071 const char *))
3072 {
3073 csound->midiGlobals->MidiOutOpenCallback = func;
3074 }
3075
csoundSetExternalMidiWriteCallback(CSOUND * csound,int (* func)(CSOUND *,void *,const unsigned char *,int))3076 PUBLIC void csoundSetExternalMidiWriteCallback(CSOUND *csound,
3077 int (*func)(CSOUND *,
3078 void *,
3079 const unsigned char *,
3080 int))
3081 {
3082 csound->midiGlobals->MidiWriteCallback = func;
3083 }
3084
csoundSetExternalMidiOutCloseCallback(CSOUND * csound,int (* func)(CSOUND *,void *))3085 PUBLIC void csoundSetExternalMidiOutCloseCallback(CSOUND *csound,
3086 int (*func)(CSOUND *, void *))
3087 {
3088 csound->midiGlobals->MidiOutCloseCallback = func;
3089 }
3090
csoundSetExternalMidiErrorStringCallback(CSOUND * csound,const char * (* func)(int))3091 PUBLIC void csoundSetExternalMidiErrorStringCallback(CSOUND *csound,
3092 const char *(*func)(int))
3093 {
3094 csound->midiGlobals->MidiErrorStringCallback = func;
3095 }
3096
3097 /*
3098 * FUNCTION TABLE DISPLAY.
3099 */
3100
csoundSetIsGraphable(CSOUND * csound,int isGraphable)3101 PUBLIC int csoundSetIsGraphable(CSOUND *csound, int isGraphable)
3102 {
3103 int prv = csound->isGraphable_;
3104 csound->isGraphable_ = isGraphable;
3105 return prv;
3106 }
3107
csoundSetMakeGraphCallback(CSOUND * csound,void (* makeGraphCB)(CSOUND * csound,WINDAT * windat,const char * name))3108 PUBLIC void csoundSetMakeGraphCallback(CSOUND *csound,
3109 void (*makeGraphCB)(CSOUND *csound,
3110 WINDAT *windat,
3111 const char *name))
3112 {
3113 csound->csoundMakeGraphCallback_ = makeGraphCB;
3114 }
3115
csoundSetDrawGraphCallback(CSOUND * csound,void (* drawGraphCallback)(CSOUND * csound,WINDAT * windat))3116 PUBLIC void csoundSetDrawGraphCallback(CSOUND *csound,
3117 void (*drawGraphCallback)(CSOUND *csound,
3118 WINDAT *windat))
3119 {
3120 csound->csoundDrawGraphCallback_ = drawGraphCallback;
3121 }
3122
csoundSetKillGraphCallback(CSOUND * csound,void (* killGraphCallback)(CSOUND * csound,WINDAT * windat))3123 PUBLIC void csoundSetKillGraphCallback(CSOUND *csound,
3124 void (*killGraphCallback)(CSOUND *csound,
3125 WINDAT *windat))
3126 {
3127 csound->csoundKillGraphCallback_ = killGraphCallback;
3128 }
3129
3130
csoundSetExitGraphCallback(CSOUND * csound,int (* exitGraphCallback)(CSOUND *))3131 PUBLIC void csoundSetExitGraphCallback(CSOUND *csound,
3132 int (*exitGraphCallback)(CSOUND *))
3133 {
3134 csound->csoundExitGraphCallback_ = exitGraphCallback;
3135 }
3136
3137 /*
3138 * OPCODES
3139 */
3140
opcode_list_new_oentry(CSOUND * csound,const OENTRY * ep)3141 static CS_NOINLINE int opcode_list_new_oentry(CSOUND *csound,
3142 const OENTRY *ep)
3143 {
3144 CONS_CELL *head;
3145 OENTRY *entryCopy;
3146 char *shortName;
3147
3148 if (UNLIKELY(ep->opname == NULL || csound->opcodes == NULL))
3149 return CSOUND_ERROR;
3150
3151 shortName = get_opcode_short_name(csound, ep->opname);
3152
3153 head = cs_hash_table_get(csound, csound->opcodes, shortName);
3154 entryCopy = csound->Malloc(csound, sizeof(OENTRY));
3155 //printf("%p\n", entryCopy);
3156 memcpy(entryCopy, ep, sizeof(OENTRY));
3157 entryCopy->useropinfo = NULL;
3158
3159 if (head != NULL) {
3160 cs_cons_append(head, cs_cons(csound, entryCopy, NULL));
3161 } else {
3162 head = cs_cons(csound, entryCopy, NULL);
3163 cs_hash_table_put(csound, csound->opcodes, shortName, head);
3164 }
3165
3166 if (shortName != ep->opname) {
3167 csound->Free(csound, shortName);
3168 }
3169
3170 return 0;
3171 }
3172
csoundAppendOpcode(CSOUND * csound,const char * opname,int dsblksiz,int flags,int thread,const char * outypes,const char * intypes,int (* iopadr)(CSOUND *,void *),int (* kopadr)(CSOUND *,void *),int (* aopadr)(CSOUND *,void *))3173 PUBLIC int csoundAppendOpcode(CSOUND *csound,
3174 const char *opname, int dsblksiz, int flags,
3175 int thread, const char *outypes,
3176 const char *intypes,
3177 int (*iopadr)(CSOUND *, void *),
3178 int (*kopadr)(CSOUND *, void *),
3179 int (*aopadr)(CSOUND *, void *))
3180 {
3181 OENTRY tmpEntry;
3182 int err;
3183
3184 tmpEntry.opname = (char*) opname;
3185 tmpEntry.dsblksiz = (uint16) dsblksiz;
3186 tmpEntry.flags = (uint16) flags;
3187 tmpEntry.thread = (uint8_t) thread;
3188 tmpEntry.outypes = (char*) outypes;
3189 tmpEntry.intypes = (char*) intypes;
3190 tmpEntry.iopadr = iopadr;
3191 tmpEntry.kopadr = kopadr;
3192 tmpEntry.aopadr = aopadr;
3193 err = opcode_list_new_oentry(csound, &tmpEntry);
3194 if (UNLIKELY(err))
3195 csoundErrorMsg(csound, Str("Failed to allocate new opcode entry."));
3196 return err;
3197 }
3198
3199 /**
3200 * Appends a list of opcodes implemented by external software to Csound's
3201 * internal opcode list. The list should either be terminated with an entry
3202 * that has a NULL opname, or the number of entries (> 0) should be specified
3203 * in 'n'. Returns zero on success.
3204 */
3205
csoundAppendOpcodes(CSOUND * csound,const OENTRY * opcodeList,int n)3206 int csoundAppendOpcodes(CSOUND *csound, const OENTRY *opcodeList, int n)
3207 {
3208 OENTRY *ep = (OENTRY*) opcodeList;
3209 int err, retval = 0;
3210
3211 if (UNLIKELY(opcodeList == NULL))
3212 return -1;
3213 if (UNLIKELY(n <= 0))
3214 n = 0x7FFFFFFF;
3215 while (n && ep->opname != NULL) {
3216 if (UNLIKELY((err = opcode_list_new_oentry(csound, ep)) != 0)) {
3217 csoundErrorMsg(csound, Str("Failed to allocate opcode entry for %s."),
3218 ep->opname);
3219 retval = err;
3220 }
3221
3222 n--, ep++;
3223 }
3224 return retval;
3225 }
3226
3227 /*
3228 * MISC FUNCTIONS
3229 */
3230
defaultCsoundYield(CSOUND * csound)3231 int defaultCsoundYield(CSOUND *csound)
3232 {
3233 (void) csound;
3234 return 1;
3235 }
3236
csoundSetYieldCallback(CSOUND * csound,int (* yieldCallback)(CSOUND *))3237 PUBLIC void csoundSetYieldCallback(CSOUND *csound,
3238 int (*yieldCallback)(CSOUND *))
3239 {
3240 csound->csoundYieldCallback_ = yieldCallback;
3241 }
3242
SetInternalYieldCallback(CSOUND * csound,int (* yieldCallback)(CSOUND *))3243 void SetInternalYieldCallback(CSOUND *csound,
3244 int (*yieldCallback)(CSOUND *))
3245 {
3246 csound->csoundInternalYieldCallback_ = yieldCallback;
3247 }
3248
csoundYield(CSOUND * csound)3249 int csoundYield(CSOUND *csound)
3250 {
3251 if (exitNow_)
3252 csound->LongJmp(csound, CSOUND_SIGNAL);
3253 csound->csoundInternalYieldCallback_(csound);
3254 return csound->csoundYieldCallback_(csound);
3255 }
3256
3257 extern void csoundDeleteAllGlobalVariables(CSOUND *csound);
3258
3259 typedef struct resetCallback_s {
3260 void *userData;
3261 int (*func)(CSOUND *, void *);
3262 struct resetCallback_s *nxt;
3263 } resetCallback_t;
3264
3265
reset(CSOUND * csound)3266 static void reset(CSOUND *csound)
3267 {
3268 CSOUND *saved_env;
3269 void *p1, *p2;
3270 uintptr_t length;
3271 uintptr_t end, start;
3272 int n = 0;
3273
3274 csoundCleanup(csound);
3275
3276 /* call registered reset callbacks */
3277 while (csound->reset_list != NULL) {
3278 resetCallback_t *p = (resetCallback_t*) csound->reset_list;
3279 p->func(csound, p->userData);
3280 csound->reset_list = (void*) p->nxt;
3281 free(p);
3282 }
3283 /* call local destructor routines of external modules */
3284 /* should check return value... */
3285 csoundDestroyModules(csound);
3286
3287 /* IV - Feb 01 2005: clean up configuration variables and */
3288 /* named dynamic "global" variables of Csound instance */
3289 csoundDeleteAllConfigurationVariables(csound);
3290 csoundDeleteAllGlobalVariables(csound);
3291
3292 #ifdef CSCORE
3293 cscoreRESET(csound);
3294 #endif
3295 if (csound->opcodes != NULL) {
3296 free_opcode_table(csound);
3297 csound->opcodes = NULL;
3298 }
3299
3300 csound->oparms_.odebug = 0;
3301 /* RWD 9:2000 not terribly vital, but good to do this somewhere... */
3302 pvsys_release(csound);
3303 close_all_files(csound);
3304 /* delete temporary files created by this Csound instance */
3305 remove_tmpfiles(csound);
3306 rlsmemfiles(csound);
3307
3308 while (csound->filedir[n]) /* Clear source directory */
3309 csound->Free(csound,csound->filedir[n++]);
3310
3311 memRESET(csound);
3312
3313 /**
3314 * Copy everything EXCEPT the function pointers.
3315 * We do it by saving them and copying them back again...
3316 * hope that this does not fail...
3317 */
3318 /* VL 07.06.2013 - check if the status is COMP before
3319 resetting.
3320 */
3321 //CSOUND **self = csound->self;
3322 saved_env = (CSOUND*) malloc(sizeof(CSOUND));
3323 memcpy(saved_env, csound, sizeof(CSOUND));
3324 memcpy(csound, &cenviron_, sizeof(CSOUND));
3325 end = (uintptr_t) &(csound->first_callback_); /* used to be &(csound->ids) */
3326 start =(uintptr_t) csound;
3327 length = end - start;
3328 memcpy((void*) csound, (void*) saved_env, (size_t) length);
3329 csound->oparms = &(csound->oparms_);
3330 csound->hostdata = saved_env->hostdata;
3331 p1 = (void*) &(csound->first_callback_);
3332 p2 = (void*) &(csound->last_callback_);
3333 length = (uintptr_t) p2 - (uintptr_t) p1;
3334 memcpy(p1, (void*) &(saved_env->first_callback_), (size_t) length);
3335 csound->csoundCallbacks_ = saved_env->csoundCallbacks_;
3336 csound->API_lock = saved_env->API_lock;
3337 #ifdef HAVE_PTHREAD_SPIN_LOCK
3338 csound->memlock = saved_env->memlock;
3339 csound->spinlock = saved_env->spinlock;
3340 csound->spoutlock = saved_env->spoutlock;
3341 csound->spinlock1= saved_env->spinlock1;
3342 #endif
3343 csound->enableHostImplementedMIDIIO = saved_env->enableHostImplementedMIDIIO;
3344 memcpy(&(csound->exitjmp), &(saved_env->exitjmp), sizeof(jmp_buf));
3345 csound->memalloc_db = saved_env->memalloc_db;
3346 //csound->self = self;
3347 free(saved_env);
3348
3349 }
3350
3351
csoundSetRTAudioModule(CSOUND * csound,const char * module)3352 PUBLIC void csoundSetRTAudioModule(CSOUND *csound, const char *module){
3353 char *s;
3354 if ((s = csoundQueryGlobalVariable(csound, "_RTAUDIO")) != NULL)
3355 strNcpy(s, module, 20);
3356 if (UNLIKELY(s==NULL)) return; /* Should not happen */
3357 if (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 ||
3358 strcmp(s, "NULL") == 0) {
3359 csound->Message(csound, Str("setting dummy interface\n"));
3360 csound->SetPlayopenCallback(csound, playopen_dummy);
3361 csound->SetRecopenCallback(csound, recopen_dummy);
3362 csound->SetRtplayCallback(csound, rtplay_dummy);
3363 csound->SetRtrecordCallback(csound, rtrecord_dummy);
3364 csound->SetRtcloseCallback(csound, rtclose_dummy);
3365 csound->SetAudioDeviceListCallback(csound, audio_dev_list_dummy);
3366 return;
3367 }
3368 if (csoundInitModules(csound) != 0)
3369 csound->LongJmp(csound, 1);
3370 }
3371
3372
csoundSetMIDIModule(CSOUND * csound,const char * module)3373 PUBLIC void csoundSetMIDIModule(CSOUND *csound, const char *module){
3374 char *s;
3375
3376 if ((s = csoundQueryGlobalVariable(csound, "_RTMIDI")) != NULL)
3377 strNcpy(s, module, 20);
3378 if (UNLIKELY(s==NULL)) return; /* Should not happen */
3379 if (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 ||
3380 strcmp(s, "NULL") == 0) {
3381 csound->SetMIDIDeviceListCallback(csound, midi_dev_list_dummy);
3382 csound->SetExternalMidiInOpenCallback(csound, DummyMidiInOpen);
3383 csound->SetExternalMidiReadCallback(csound, DummyMidiRead);
3384 csound->SetExternalMidiInCloseCallback(csound, NULL);
3385 csound->SetExternalMidiOutOpenCallback(csound, DummyMidiOutOpen);
3386 csound->SetExternalMidiWriteCallback(csound, DummyMidiWrite);
3387 csound->SetExternalMidiOutCloseCallback(csound, NULL);
3388
3389 return;
3390 }
3391 if (csoundInitModules(csound) != 0)
3392 csound->LongJmp(csound, 1);
3393 }
3394
3395
csoundGetModule(CSOUND * csound,int no,char ** module,char ** type)3396 PUBLIC int csoundGetModule(CSOUND *csound, int no, char **module, char **type){
3397 MODULE_INFO **modules =
3398 (MODULE_INFO **) csoundQueryGlobalVariable(csound, "_MODULES");
3399 if (UNLIKELY(modules[no] == NULL || no >= MAX_MODULES)) return CSOUND_ERROR;
3400 *module = modules[no]->module;
3401 *type = modules[no]->type;
3402 return CSOUND_SUCCESS;
3403 }
3404
csoundLoadPlugins(CSOUND * csound,const char * dir)3405 PUBLIC int csoundLoadPlugins(CSOUND *csound, const char *dir){
3406 if (dir != NULL) {
3407 int err = csoundLoadAndInitModules(csound, dir);
3408 if(!err) {
3409 csound->Message(csound, "loaded plugins from %s\n", dir);
3410 return CSOUND_SUCCESS;
3411 }
3412 else return err;
3413 }
3414 else return CSOUND_ERROR;
3415 }
3416
csoundReset(CSOUND * csound)3417 PUBLIC void csoundReset(CSOUND *csound)
3418 {
3419 char *s;
3420 int i, max_len;
3421 OPARMS *O = csound->oparms;
3422 char *opdir = csound->opcodedir;
3423
3424 if (csound->engineStatus & CS_STATE_COMP ||
3425 csound->engineStatus & CS_STATE_PRE) {
3426 /* and reset */
3427 csound->Message(csound, "resetting Csound instance\n");
3428 reset(csound);
3429 /* clear compiled flag */
3430 csound->engineStatus |= ~(CS_STATE_COMP);
3431 } else {
3432 csoundSpinLockInit(&csound->spoutlock);
3433 csoundSpinLockInit(&csound->spinlock);
3434 csoundSpinLockInit(&csound->memlock);
3435 csoundSpinLockInit(&csound->spinlock1);
3436 if (UNLIKELY(O->odebug))
3437 csound->Message(csound,"init spinlocks\n");
3438 }
3439
3440 if (msgcallback_ != NULL) {
3441 csoundSetMessageCallback(csound, msgcallback_);
3442 } else {
3443 csoundSetMessageCallback(csound, csoundDefaultMessageCallback);
3444 }
3445 csound->printerrormessagesflag = (void*)1234;
3446 /* copysystem environment variables */
3447 i = csoundInitEnv(csound);
3448 if (UNLIKELY(i != CSOUND_SUCCESS)) {
3449 csound->engineStatus |= CS_STATE_JMP;
3450 csound->Die(csound, Str("Failed during csoundInitEnv"));
3451 }
3452 csound_init_rand(csound);
3453
3454 csound->engineState.stringPool = cs_hash_table_create(csound);
3455 csound->engineState.constantsPool = cs_hash_table_create(csound);
3456 if (csound->symbtab != NULL)
3457 cs_hash_table_mfree_complete(csound, csound->symbtab);
3458 csound->symbtab = NULL;
3459 csound->engineStatus |= CS_STATE_PRE;
3460 csound_aops_init_tables(csound);
3461 create_opcode_table(csound);
3462 /* now load and pre-initialise external modules for this instance */
3463 /* this function returns an error value that may be worth checking */
3464 {
3465 int err = csoundInitStaticModules(csound);
3466 if (csound->delayederrormessages &&
3467 csound->printerrormessagesflag==NULL) {
3468 csound->Warning(csound, "%s",csound->delayederrormessages);
3469 csound->Free(csound, csound->delayederrormessages);
3470 csound->delayederrormessages = NULL;
3471 }
3472 if (UNLIKELY(err==CSOUND_ERROR))
3473 csound->Die(csound, Str("Failed during csoundInitStaticModules"));
3474
3475
3476 csoundCreateGlobalVariable(csound, "_MODULES",
3477 (size_t) MAX_MODULES*sizeof(MODULE_INFO *));
3478 char *modules = (char *) csoundQueryGlobalVariable(csound, "_MODULES");
3479 memset(modules, 0, sizeof(MODULE_INFO *)*MAX_MODULES);
3480
3481 /* VL now load modules has opcodedir override */
3482 csound->opcodedir = opdir;
3483 err = csoundLoadModules(csound);
3484 if (csound->delayederrormessages &&
3485 csound->printerrormessagesflag==NULL) {
3486 csound->Warning(csound, "%s", csound->delayederrormessages);
3487 csound->Free(csound, csound->delayederrormessages);
3488 csound->delayederrormessages = NULL;
3489 }
3490 if (UNLIKELY(err != CSOUND_SUCCESS))
3491 csound->Die(csound, Str("Failed during csoundLoadModules"));
3492
3493 if (csoundInitModules(csound) != 0)
3494 csound->LongJmp(csound, 1);
3495
3496
3497 init_pvsys(csound);
3498 /* utilities depend on this as well as orchs; may get changed by an orch */
3499 dbfs_init(csound, DFLT_DBFS);
3500 csound->csRtClock = (RTCLOCK*) csound->Calloc(csound, sizeof(RTCLOCK));
3501 csoundInitTimerStruct(csound->csRtClock);
3502 csound->engineStatus |= /*CS_STATE_COMP |*/ CS_STATE_CLN;
3503
3504 print_csound_version(csound);
3505 {
3506 char buffer[128];
3507 sf_command(NULL, SFC_GET_LIB_VERSION, buffer, 128);
3508 csound->Message(csound, "%s\n", buffer);
3509 }
3510
3511 /* do not know file type yet */
3512 O->filetyp = -1;
3513 O->sfheader = 0;
3514 csound->peakchunks = 1;
3515 csound->typePool = csound->Calloc(csound, sizeof(TYPE_POOL));
3516 csound->engineState.varPool = csoundCreateVarPool(csound);
3517 csoundAddStandardTypes(csound, csound->typePool);
3518 /* csoundLoadExternals(csound); */
3519 }
3520
3521 /* allow selecting real time audio module */
3522 max_len = 21;
3523 csoundCreateGlobalVariable(csound, "_RTAUDIO", (size_t) max_len);
3524 s = csoundQueryGlobalVariable(csound, "_RTAUDIO");
3525 #ifndef LINUX
3526 #ifdef __HAIKU__
3527 strcpy(s, "haiku");
3528 #else
3529 strcpy(s, "PortAudio");
3530 #endif
3531 #else
3532 strcpy(s, "alsa");
3533 #endif
3534 csoundCreateConfigurationVariable(csound, "rtaudio", s, CSOUNDCFG_STRING,
3535 0, NULL, &max_len,
3536 Str("Real time audio module name"), NULL);
3537
3538 /* initialise real time MIDI */
3539 csound->midiGlobals = (MGLOBAL*) csound->Calloc(csound, sizeof(MGLOBAL));
3540 csound->midiGlobals->bufp = &(csound->midiGlobals->mbuf[0]);
3541 csound->midiGlobals->endatp = csound->midiGlobals->bufp;
3542 csoundCreateGlobalVariable(csound, "_RTMIDI", (size_t) max_len);
3543 csound->SetMIDIDeviceListCallback(csound, midi_dev_list_dummy);
3544 csound->SetExternalMidiInOpenCallback(csound, DummyMidiInOpen);
3545 csound->SetExternalMidiReadCallback(csound, DummyMidiRead);
3546 csound->SetExternalMidiOutOpenCallback(csound, DummyMidiOutOpen);
3547 csound->SetExternalMidiWriteCallback(csound, DummyMidiWrite);
3548
3549 s = csoundQueryGlobalVariable(csound, "_RTMIDI");
3550 strcpy(s, "null");
3551 if (csound->enableHostImplementedMIDIIO == 0)
3552 #ifndef LINUX
3553 #ifdef __HAIKU__
3554 strcpy(s, "haiku");
3555 #else
3556 strcpy(s, "portmidi");
3557 #endif
3558 #else
3559 strcpy(s, "alsa");
3560 #endif
3561 else strcpy(s, "hostbased");
3562
3563 csoundCreateConfigurationVariable(csound, "rtmidi", s, CSOUNDCFG_STRING,
3564 0, NULL, &max_len,
3565 Str("Real time MIDI module name"), NULL);
3566 max_len = 256; /* should be the same as in csoundCore.h */
3567 csoundCreateConfigurationVariable(csound, "mute_tracks",
3568 &(csound->midiGlobals->muteTrackList[0]),
3569 CSOUNDCFG_STRING, 0, NULL, &max_len,
3570 Str("Ignore events (other than tempo "
3571 "changes) in tracks defined by pattern"),
3572 NULL);
3573 csoundCreateConfigurationVariable(csound, "raw_controller_mode",
3574 &(csound->midiGlobals->rawControllerMode),
3575 CSOUNDCFG_BOOLEAN, 0, NULL, NULL,
3576 Str("Do not handle special MIDI controllers"
3577 " (sustain pedal etc.)"), NULL);
3578 /* sound file tag options */
3579 max_len = 201;
3580 i = (max_len + 7) & (~7);
3581 csound->SF_id_title = (char*) csound->Calloc(csound, (size_t) i * (size_t) 6);
3582 csoundCreateConfigurationVariable(csound, "id_title", csound->SF_id_title,
3583 CSOUNDCFG_STRING, 0, NULL, &max_len,
3584 Str("Title tag in output soundfile "
3585 "(no spaces)"), NULL);
3586 csound->SF_id_copyright = (char*) csound->SF_id_title + (int) i;
3587 csoundCreateConfigurationVariable(csound, "id_copyright",
3588 csound->SF_id_copyright,
3589 CSOUNDCFG_STRING, 0, NULL, &max_len,
3590 Str("Copyright tag in output soundfile"
3591 " (no spaces)"), NULL);
3592 csoundCreateConfigurationVariable(csound, "id_scopyright",
3593 &csound->SF_id_scopyright,
3594 CSOUNDCFG_INTEGER, 0, NULL, &max_len,
3595 Str("Short Copyright tag in"
3596 " output soundfile"), NULL);
3597 csound->SF_id_software = (char*) csound->SF_id_copyright + (int) i;
3598 csoundCreateConfigurationVariable(csound, "id_software",
3599 csound->SF_id_software,
3600 CSOUNDCFG_STRING, 0, NULL, &max_len,
3601 Str("Software tag in output soundfile"
3602 " (no spaces)"), NULL);
3603 csound->SF_id_artist = (char*) csound->SF_id_software + (int) i;
3604 csoundCreateConfigurationVariable(csound, "id_artist", csound->SF_id_artist,
3605 CSOUNDCFG_STRING, 0, NULL, &max_len,
3606 Str("Artist tag in output soundfile "
3607 "(no spaces)"),
3608 NULL);
3609 csound->SF_id_comment = (char*) csound->SF_id_artist + (int) i;
3610 csoundCreateConfigurationVariable(csound, "id_comment",
3611 csound->SF_id_comment,
3612 CSOUNDCFG_STRING, 0, NULL, &max_len,
3613 Str("Comment tag in output soundfile"
3614 " (no spaces)"), NULL);
3615 csound->SF_id_date = (char*) csound->SF_id_comment + (int) i;
3616 csoundCreateConfigurationVariable(csound, "id_date", csound->SF_id_date,
3617 CSOUNDCFG_STRING, 0, NULL, &max_len,
3618 Str("Date tag in output soundfile "
3619 "(no spaces)"),
3620 NULL);
3621 {
3622
3623 MYFLT minValF = FL(0.0);
3624
3625 csoundCreateConfigurationVariable(csound, "msg_color",
3626 &(csound->enableMsgAttr),
3627 CSOUNDCFG_BOOLEAN, 0, NULL, NULL,
3628 Str("Enable message attributes "
3629 "(colors etc.)"),
3630 NULL);
3631 csoundCreateConfigurationVariable(csound, "skip_seconds",
3632 &(csound->csoundScoreOffsetSeconds_),
3633 CSOUNDCFG_MYFLT, 0, &minValF, NULL,
3634 Str("Start score playback at the specified"
3635 " time, skipping earlier events"),
3636 NULL);
3637 }
3638 csoundCreateConfigurationVariable(csound, "ignore_csopts",
3639 &(csound->disable_csd_options),
3640 CSOUNDCFG_BOOLEAN, 0, NULL, NULL,
3641 Str("Ignore <CsOptions> in CSD files"
3642 " (default: no)"), NULL);
3643 }
3644
csoundGetDebug(CSOUND * csound)3645 PUBLIC int csoundGetDebug(CSOUND *csound)
3646 {
3647 return csound->oparms_.odebug;
3648 }
3649
csoundSetDebug(CSOUND * csound,int debug)3650 PUBLIC void csoundSetDebug(CSOUND *csound, int debug)
3651 {
3652 csound->oparms_.odebug = debug;
3653 }
3654
csoundTableLength(CSOUND * csound,int table)3655 PUBLIC int csoundTableLength(CSOUND *csound, int table)
3656 {
3657 MYFLT *tablePtr;
3658 return csoundGetTable(csound, &tablePtr, table);
3659 }
3660
csoundTableGet(CSOUND * csound,int table,int index)3661 PUBLIC MYFLT csoundTableGet(CSOUND *csound, int table, int index)
3662 {
3663 return csound->flist[table]->ftable[index];
3664 }
3665
csoundTableSetInternal(CSOUND * csound,int table,int index,MYFLT value)3666 void csoundTableSetInternal(CSOUND *csound,
3667 int table, int index, MYFLT value)
3668 {
3669 if (csound->oparms->realtime) csoundLockMutex(csound->init_pass_threadlock);
3670 csound->flist[table]->ftable[index] = value;
3671 if (csound->oparms->realtime) csoundUnlockMutex(csound->init_pass_threadlock);
3672 }
3673
csoundTableCopyOutInternal(CSOUND * csound,int table,MYFLT * ptable)3674 void csoundTableCopyOutInternal(CSOUND *csound, int table, MYFLT *ptable){
3675 int len;
3676 MYFLT *ftab;
3677 /* in realtime mode init pass is executed in a separate thread, so
3678 we need to protect it */
3679 if (csound->oparms->realtime) csoundLockMutex(csound->init_pass_threadlock);
3680 len = csoundGetTable(csound, &ftab, table);
3681 if (UNLIKELY(len>0x00ffffff)) len = 0x00ffffff; // As coverity is unhappy
3682 memcpy(ptable, ftab, (size_t) (len*sizeof(MYFLT)));
3683 if (csound->oparms->realtime) csoundUnlockMutex(csound->init_pass_threadlock);
3684 }
3685
csoundTableCopyInInternal(CSOUND * csound,int table,MYFLT * ptable)3686 void csoundTableCopyInInternal(CSOUND *csound, int table, MYFLT *ptable){
3687 int len;
3688 MYFLT *ftab;
3689 /* in realtime mode init pass is executed in a separate thread, so
3690 we need to protect it */
3691 if (csound->oparms->realtime) csoundLockMutex(csound->init_pass_threadlock);
3692 len = csoundGetTable(csound, &ftab, table);
3693 if (UNLIKELY(len>0x00ffffff)) len = 0x00ffffff; // As coverity is unhappy
3694 memcpy(ftab, ptable, (size_t) (len*sizeof(MYFLT)));
3695 if (csound->oparms->realtime) csoundUnlockMutex(csound->init_pass_threadlock);
3696 }
3697
csoundDoCallback_(CSOUND * csound,void * p,unsigned int type)3698 static int csoundDoCallback_(CSOUND *csound, void *p, unsigned int type)
3699 {
3700 if (csound->csoundCallbacks_ != NULL) {
3701 CsoundCallbackEntry_t *pp;
3702 pp = (CsoundCallbackEntry_t*) csound->csoundCallbacks_;
3703 do {
3704 if (pp->typeMask & type) {
3705 int retval = pp->func(pp->userData, p, type);
3706 if (retval != CSOUND_SUCCESS)
3707 return retval;
3708 }
3709 pp = pp->nxt;
3710 } while (pp != (CsoundCallbackEntry_t*) NULL);
3711 }
3712 return 1;
3713 }
3714
3715 /**
3716 * Sets a callback function that will be called on keyboard
3717 * events. The callback is preserved on csoundReset(), and multiple
3718 * callbacks may be set and will be called in reverse order of
3719 * registration. If the same function is set again, it is only moved
3720 * in the list of callbacks so that it will be called first, and the
3721 * user data and type mask parameters are updated. 'typeMask' can be the
3722 * bitwise OR of callback types for which the function should be called,
3723 * or zero for all types.
3724 * Returns zero on success, CSOUND_ERROR if the specified function
3725 * pointer or type mask is invalid, and CSOUND_MEMORY if there is not
3726 * enough memory.
3727 *
3728 * The callback function takes the following arguments:
3729 * void *userData
3730 * the "user data" pointer, as specified when setting the callback
3731 * void *p
3732 * data pointer, depending on the callback type
3733 * unsigned int type
3734 * callback type, can be one of the following (more may be added in
3735 * future versions of Csound):
3736 * CSOUND_CALLBACK_KBD_EVENT
3737 * CSOUND_CALLBACK_KBD_TEXT
3738 * called by the sensekey opcode to fetch key codes. The data
3739 * pointer is a pointer to a single value of type 'int', for
3740 * returning the key code, which can be in the range 1 to 65535,
3741 * or 0 if there is no keyboard event.
3742 * For CSOUND_CALLBACK_KBD_EVENT, both key press and release
3743 * events should be returned (with 65536 (0x10000) added to the
3744 * key code in the latter case) as unshifted ASCII codes.
3745 * CSOUND_CALLBACK_KBD_TEXT expects key press events only as the
3746 * actual text that is typed.
3747 * The return value should be zero on success, negative on error, and
3748 * positive if the callback was ignored (for example because the type is
3749 * not known).
3750 */
3751
csoundRegisterKeyboardCallback(CSOUND * csound,int (* func)(void * userData,void * p,unsigned int type),void * userData,unsigned int typeMask)3752 PUBLIC int csoundRegisterKeyboardCallback(CSOUND *csound,
3753 int (*func)(void *userData, void *p,
3754 unsigned int type),
3755 void *userData, unsigned int typeMask)
3756 {
3757 CsoundCallbackEntry_t *pp;
3758
3759 if (UNLIKELY(func == (int (*)(void *, void *, unsigned int)) NULL ||
3760 (typeMask
3761 & (~(CSOUND_CALLBACK_KBD_EVENT | CSOUND_CALLBACK_KBD_TEXT)))
3762 != 0U))
3763 return CSOUND_ERROR;
3764 csoundRemoveKeyboardCallback(csound, func);
3765 pp = (CsoundCallbackEntry_t*) malloc(sizeof(CsoundCallbackEntry_t));
3766 if (UNLIKELY(pp == (CsoundCallbackEntry_t*) NULL))
3767 return CSOUND_MEMORY;
3768 pp->typeMask = (typeMask ? typeMask : 0xFFFFFFFFU);
3769 pp->nxt = (CsoundCallbackEntry_t*) csound->csoundCallbacks_;
3770 pp->userData = userData;
3771 pp->func = func;
3772 csound->csoundCallbacks_ = (void*) pp;
3773
3774 return CSOUND_SUCCESS;
3775 }
3776
3777
3778 /**
3779 * Removes a callback previously set with csoundSetCallback().
3780 */
3781
csoundRemoveKeyboardCallback(CSOUND * csound,int (* func)(void *,void *,unsigned int))3782 PUBLIC void csoundRemoveKeyboardCallback(CSOUND *csound,
3783 int (*func)(void *, void *, unsigned int))
3784 {
3785 CsoundCallbackEntry_t *pp, *prv;
3786
3787 pp = (CsoundCallbackEntry_t*) csound->csoundCallbacks_;
3788 prv = (CsoundCallbackEntry_t*) NULL;
3789 while (pp != (CsoundCallbackEntry_t*) NULL) {
3790 if (pp->func == func) {
3791 if (prv != (CsoundCallbackEntry_t*) NULL)
3792 prv->nxt = pp->nxt;
3793 else
3794 csound->csoundCallbacks_ = (void*) pp->nxt;
3795 free((void*) pp);
3796 return;
3797 }
3798 prv = pp;
3799 pp = pp->nxt;
3800 }
3801 }
3802
3803
csoundSetFileOpenCallback(CSOUND * p,void (* fileOpenCallback)(CSOUND *,const char *,int,int,int))3804 PUBLIC void csoundSetFileOpenCallback(CSOUND *p,
3805 void (*fileOpenCallback)(CSOUND*,
3806 const char*,
3807 int, int, int))
3808 {
3809 p->FileOpenCallback_ = fileOpenCallback;
3810 }
3811
3812 /* csoundNotifyFileOpened() should be called by plugins via
3813 csound->NotifyFileOpened() to let Csound know that they opened a file
3814 without using one of the standard mechanisms (csound->FileOpen2() or
3815 ldmemfile2withCB()). The notification is passed on to the host if it
3816 has set the FileOpen callback. */
csoundNotifyFileOpened(CSOUND * csound,const char * pathname,int csFileType,int writing,int temporary)3817 void csoundNotifyFileOpened(CSOUND* csound, const char* pathname,
3818 int csFileType, int writing, int temporary)
3819 {
3820 if (csound->FileOpenCallback_ != NULL)
3821 csound->FileOpenCallback_(csound, pathname, csFileType, writing,
3822 temporary);
3823 return;
3824
3825 }
3826
3827 /* -------- IV - Jan 27 2005: timer functions -------- */
3828
3829 #ifdef HAVE_GETTIMEOFDAY
3830 #undef HAVE_GETTIMEOFDAY
3831 #endif
3832 #if defined(LINUX) || defined(__unix) || defined(__unix__) || defined(__MACH__)
3833 #define HAVE_GETTIMEOFDAY 1
3834 #include <sys/time.h>
3835 #endif
3836
3837 /* enable use of high resolution timer (Linux/i586/GCC only) */
3838 /* could in fact work under any x86/GCC system, but do not */
3839 /* know how to query the actual CPU frequency ... */
3840
3841 //#define HAVE_RDTSC 1
3842
3843 /* ------------------------------------ */
3844
3845 #if defined(HAVE_RDTSC)
3846 #if !(defined(LINUX) && defined(__GNUC__) && defined(__i386__)) || !(defined(__FreeBSD__) && defined(__i386__))
3847 #undef HAVE_RDTSC
3848 #endif
3849 #endif
3850
3851 /* hopefully cannot change during performance */
3852 static double timeResolutionSeconds = -1.0;
3853
3854 /* find out CPU frequency based on /proc/cpuinfo */
3855
getTimeResolution(void)3856 static int getTimeResolution(void)
3857 {
3858 #if defined(HAVE_RDTSC)
3859 #if defined(__FreeBSD__)
3860 size_t size;
3861 int timeResolutionSeconds;
3862 size = sizeof timeResolutionSeconds;
3863 sysctlbyname("hw.clockrate", &timeResolutionSeconds, &size, NULL, 0);
3864
3865 #else
3866 FILE *f;
3867 char buf[256];
3868
3869 /* if frequency is not known yet */
3870 f = fopen("/proc/cpuinfo", "r");
3871 if (UNLIKELY(f == NULL)) {
3872 fprintf(stderr, Str("Cannot open /proc/cpuinfo. "
3873 "Support for RDTSC is not available.\n"));
3874 return -1;
3875 }
3876 /* find CPU frequency */
3877 while (fgets(buf, 256, f) != NULL) {
3878 int i;
3879 char *s = (char*) buf - 1;
3880 buf[255] = '\0'; /* safety */
3881 if (strlen(buf) < 9)
3882 continue; /* too short, skip */
3883 while (*++s != '\0')
3884 if (isupper(*s))
3885 *s = tolower(*s); /* convert to lower case */
3886 if (strncmp(buf, "cpu mhz", 7) != 0)
3887 continue; /* check key name */
3888 s = strchr(buf, ':'); /* find frequency value */
3889 if (s == NULL) continue; /* invalid entry */
3890 do {
3891 s++;
3892 } while (isblank(*s)); /* skip white space */
3893 i = CS_SSCANF(s, "%lf", &timeResolutionSeconds);
3894
3895 if (i < 1 || timeResolutionSeconds < 1.0) {
3896 timeResolutionSeconds = -1.0; /* invalid entry */
3897 continue;
3898 }
3899 }
3900 fclose(f);
3901 #endif /* __FreeBSD__ */
3902 if (UNLIKELY(timeResolutionSeconds <= 0.0)) {
3903 fprintf(stderr, Str("No valid CPU frequency entry "
3904 #if defined(__FreeBSD__)
3905 "was found.\n"));
3906 #else
3907 "was found in /proc/cpuinfo.\n"));
3908 #endif /* __FreeBSD__ */
3909 return -1;
3910 }
3911 /* MHz -> seconds */
3912 timeResolutionSeconds = 0.000001 / timeResolutionSeconds;
3913 #elif defined(WIN32)
3914 LARGE_INTEGER tmp1;
3915 int_least64_t tmp2;
3916 QueryPerformanceFrequency(&tmp1);
3917 tmp2 = (int_least64_t) tmp1.LowPart + ((int_least64_t) tmp1.HighPart << 32);
3918 timeResolutionSeconds = 1.0 / (double) tmp2;
3919 #elif defined(HAVE_GETTIMEOFDAY)
3920 timeResolutionSeconds = 0.000001;
3921 #else
3922 timeResolutionSeconds = 1.0;
3923 #endif
3924 #ifdef BETA
3925 fprintf(stderr, "time resolution is %.3f ns\n",
3926 1.0e9 * timeResolutionSeconds);
3927 #endif
3928 return 0;
3929 }
3930
3931 /* function for getting real time */
3932
get_real_time(void)3933 static inline int_least64_t get_real_time(void)
3934 {
3935 #if defined(HAVE_RDTSC)
3936 /* optimised high resolution timer for Linux/i586/GCC only */
3937 uint32_t l, h;
3938 #ifndef __STRICT_ANSI__
3939 asm volatile ("rdtsc" : "=a" (l), "=d" (h));
3940 #else
3941 __asm__ volatile ("rdtsc" : "=a" (l), "=d" (h));
3942 #endif
3943 return ((int_least64_t) l + ((int_least64_t) h << 32));
3944 #elif defined(WIN32)
3945 /* Win32: use QueryPerformanceCounter - resolution depends on system, */
3946 /* but is expected to be better than 1 us. GetSystemTimeAsFileTime */
3947 /* seems to have much worse resolution under Win95. */
3948 LARGE_INTEGER tmp;
3949 QueryPerformanceCounter(&tmp);
3950 return ((int_least64_t) tmp.LowPart + ((int_least64_t) tmp.HighPart <<32));
3951 #elif defined(HAVE_GETTIMEOFDAY)
3952 /* UNIX: use gettimeofday() - allows 1 us resolution */
3953 struct timeval tv;
3954 gettimeofday(&tv, NULL);
3955 return ((int_least64_t) tv.tv_usec
3956 + (int_least64_t) ((uint32_t) tv.tv_sec * (uint64_t) 1000000));
3957 #else
3958 /* other systems: use time() - allows 1 second resolution */
3959 return ((int_least64_t) time(NULL));
3960 #endif
3961 }
3962
3963 /* function for getting CPU time */
3964
get_CPU_time(void)3965 static inline int_least64_t get_CPU_time(void)
3966 {
3967 return ((int_least64_t) ((uint32_t) clock()));
3968 }
3969
3970 /* initialise a timer structure */
3971
csoundInitTimerStruct(RTCLOCK * p)3972 PUBLIC void csoundInitTimerStruct(RTCLOCK *p)
3973 {
3974 p->starttime_real = get_real_time();
3975 p->starttime_CPU = get_CPU_time();
3976 }
3977
3978 /**
3979 * return the elapsed real time (in seconds) since the specified timer
3980 * structure was initialised
3981 */
csoundGetRealTime(RTCLOCK * p)3982 PUBLIC double csoundGetRealTime(RTCLOCK *p)
3983 {
3984 return ((double) (get_real_time() - p->starttime_real)
3985 * (double) timeResolutionSeconds);
3986 }
3987
3988 /**
3989 * return the elapsed CPU time (in seconds) since the specified timer
3990 * structure was initialised
3991 */
csoundGetCPUTime(RTCLOCK * p)3992 PUBLIC double csoundGetCPUTime(RTCLOCK *p)
3993 {
3994 return ((double) ((uint32_t) get_CPU_time() - (uint32_t) p->starttime_CPU)
3995 * (1.0 / (double) CLOCKS_PER_SEC));
3996 }
3997
3998 /* return a 32-bit unsigned integer to be used as seed from current time */
3999
csoundGetRandomSeedFromTime(void)4000 PUBLIC uint32_t csoundGetRandomSeedFromTime(void)
4001 {
4002 return (uint32_t) get_real_time();
4003 }
4004
4005 /**
4006 * Return the size of MYFLT in bytes.
4007 */
csoundGetSizeOfMYFLT(void)4008 PUBLIC int csoundGetSizeOfMYFLT(void)
4009 {
4010 return (int) sizeof(MYFLT);
4011 }
4012
4013 /**
4014 * Return pointer to user data pointer for real time audio input.
4015 */
csoundGetRtRecordUserData(CSOUND * csound)4016 PUBLIC void **csoundGetRtRecordUserData(CSOUND *csound)
4017 {
4018 return &(csound->rtRecord_userdata);
4019 }
4020
4021 /**
4022 * Return pointer to user data pointer for real time audio output.
4023 */
csoundGetRtPlayUserData(CSOUND * csound)4024 PUBLIC void **csoundGetRtPlayUserData(CSOUND *csound)
4025 {
4026 return &(csound->rtPlay_userdata);
4027 }
4028
4029 typedef struct opcodeDeinit_s {
4030 void *p;
4031 int (*func)(CSOUND *, void *);
4032 void *nxt;
4033 } opcodeDeinit_t;
4034
4035 /**
4036 * Register a function to be called at note deactivation.
4037 * Should be called from the initialisation routine of an opcode.
4038 * 'p' is a pointer to the OPDS structure of the opcode, and 'func'
4039 * is the function to be called, with the same arguments and return
4040 * value as in the case of opcode init/perf functions.
4041 * The functions are called in reverse order of registration.
4042 * Returns zero on success.
4043 */
4044
csoundRegisterDeinitCallback(CSOUND * csound,void * p,int (* func)(CSOUND *,void *))4045 int csoundRegisterDeinitCallback(CSOUND *csound, void *p,
4046 int (*func)(CSOUND *, void *))
4047 {
4048 INSDS *ip = ((OPDS*) p)->insdshead;
4049 opcodeDeinit_t *dp = (opcodeDeinit_t*) malloc(sizeof(opcodeDeinit_t));
4050
4051 (void) csound;
4052 if (UNLIKELY(dp == NULL))
4053 return CSOUND_MEMORY;
4054 dp->p = p;
4055 dp->func = func;
4056 dp->nxt = ip->nxtd;
4057 ip->nxtd = dp;
4058 return CSOUND_SUCCESS;
4059 }
4060
4061 /**
4062 * Register a function to be called by csoundReset(), in reverse order
4063 * of registration, before unloading external modules. The function takes
4064 * the Csound instance pointer as the first argument, and the pointer
4065 * passed here as 'userData' as the second, and is expected to return zero
4066 * on success.
4067 * The return value of csoundRegisterResetCallback() is zero on success.
4068 */
4069
csoundRegisterResetCallback(CSOUND * csound,void * userData,int (* func)(CSOUND *,void *))4070 int csoundRegisterResetCallback(CSOUND *csound, void *userData,
4071 int (*func)(CSOUND *, void *))
4072 {
4073 resetCallback_t *dp = (resetCallback_t*) malloc(sizeof(resetCallback_t));
4074
4075 if (UNLIKELY(dp == NULL))
4076 return CSOUND_MEMORY;
4077 dp->userData = userData;
4078 dp->func = func;
4079 dp->nxt = csound->reset_list;
4080 csound->reset_list = (void*) dp;
4081 return CSOUND_SUCCESS;
4082 }
4083
4084 /* call the opcode deinitialisation routines of an instrument instance */
4085 /* called from deact() in insert.c */
4086
csoundDeinitialiseOpcodes(CSOUND * csound,INSDS * ip)4087 int csoundDeinitialiseOpcodes(CSOUND *csound, INSDS *ip)
4088 {
4089 int err = 0;
4090
4091 while (ip->nxtd != NULL) {
4092 opcodeDeinit_t *dp = (opcodeDeinit_t*) ip->nxtd;
4093 err |= dp->func(csound, dp->p);
4094 ip->nxtd = (void*) dp->nxt;
4095 free(dp);
4096 }
4097 return err;
4098 }
4099
4100 /**
4101 * Returns the name of the opcode of which the data structure
4102 * is pointed to by 'p'.
4103 */
csoundGetOpcodeName(void * p)4104 char *csoundGetOpcodeName(void *p)
4105 {
4106 return ((OPDS*) p)->optext->t.oentry->opname;
4107 }
4108
4109 /** Returns the CS_TYPE for an opcode's arg pointer */
4110
csoundGetTypeForArg(void * argPtr)4111 CS_TYPE* csoundGetTypeForArg(void* argPtr) {
4112 char* ptr = (char*)argPtr;
4113 CS_TYPE* varType = *(CS_TYPE**)(ptr - CS_VAR_TYPE_OFFSET);
4114 return varType;
4115 }
4116
4117 /**
4118 * Returns the number of input arguments for opcode 'p'.
4119 */
csoundGetInputArgCnt(void * p)4120 int csoundGetInputArgCnt(void *p)
4121 {
4122 return (int) ((OPDS*) p)->optext->t.inArgCount;
4123 }
4124
4125
4126 /**
4127 * Returns the name of input argument 'n' (counting from 0) for opcode 'p'.
4128 */
csoundGetInputArgName(void * p,int n)4129 char *csoundGetInputArgName(void *p, int n)
4130 {
4131 if ((unsigned int) n >=
4132 (unsigned int) ((OPDS*) p)->optext->t.inArgCount)
4133 return (char*) NULL;
4134 return (char*) ((OPDS*) p)->optext->t.inlist->arg[n];
4135 }
4136
4137 /**
4138 * Returns the number of output arguments for opcode 'p'.
4139 */
csoundGetOutputArgCnt(void * p)4140 int csoundGetOutputArgCnt(void *p)
4141 {
4142 return (int) ((OPDS*) p)->optext->t.outArgCount;
4143 }
4144
4145 /**
4146 * Returns the name of output argument 'n' (counting from 0) for opcode 'p'.
4147 */
csoundGetOutputArgName(void * p,int n)4148 char *csoundGetOutputArgName(void *p, int n)
4149 {
4150 if ((unsigned int) n
4151 >= (unsigned int) ((OPDS*) p)->optext->t.outArgCount)
4152 return (char*) NULL;
4153 return (char*) ((OPDS*) p)->optext->t.outlist->arg[n];
4154 }
4155
4156 /**
4157 * Set release time in control periods (1 / csound->ekr second units)
4158 * for opcode 'p' to 'n'. If the current release time is longer than
4159 * the specified value, it is not changed.
4160 * Returns the new release time.
4161 */
csoundSetReleaseLength(void * p,int n)4162 int csoundSetReleaseLength(void *p, int n)
4163 {
4164 if (n > (int) ((OPDS*) p)->insdshead->xtratim)
4165 ((OPDS*) p)->insdshead->xtratim = n;
4166 return (int) ((OPDS*) p)->insdshead->xtratim;
4167 }
4168
4169 /**
4170 * Set release time in seconds for opcode 'p' to 'n'.
4171 * If the current release time is longer than the specified value,
4172 * it is not changed.
4173 * Returns the new release time in seconds.
4174 */
csoundSetReleaseLengthSeconds(void * p,MYFLT n)4175 MYFLT csoundSetReleaseLengthSeconds(void *p, MYFLT n)
4176 {
4177 int kcnt = (int) (n * ((OPDS*) p)->insdshead->csound->ekr + FL(0.5));
4178 if (kcnt > (int) ((OPDS*) p)->insdshead->xtratim)
4179 ((OPDS*) p)->insdshead->xtratim = kcnt;
4180 return ((MYFLT) ((OPDS*) p)->insdshead->xtratim
4181 * ((OPDS*) p)->insdshead->csound->onedkr);
4182 }
4183
4184 /**
4185 * Returns MIDI channel number (0 to 15) for the instrument instance
4186 * that called opcode 'p'.
4187 * In the case of score notes, -1 is returned.
4188 */
csoundGetMidiChannelNumber(void * p)4189 int csoundGetMidiChannelNumber(void *p)
4190 {
4191 MCHNBLK *chn = ((OPDS*) p)->insdshead->m_chnbp;
4192 int i;
4193 if (chn == NULL)
4194 return -1;
4195 for (i = 0; i < 256; i++) {
4196 if (chn == ((OPDS*) p)->insdshead->csound->m_chnbp[i])
4197 return i;
4198 }
4199 return -1;
4200 }
4201
4202 /**
4203 * Returns a pointer to the MIDI channel structure for the instrument
4204 * instance that called opcode 'p'.
4205 * In the case of score notes, NULL is returned.
4206 */
csoundGetMidiChannel(void * p)4207 MCHNBLK *csoundGetMidiChannel(void *p)
4208 {
4209 return ((OPDS*) p)->insdshead->m_chnbp;
4210 }
4211
4212 /**
4213 * Returns MIDI note number (in the range 0 to 127) for opcode 'p'.
4214 * If the opcode was not called from a MIDI activated instrument
4215 * instance, the return value is undefined.
4216 */
csoundGetMidiNoteNumber(void * p)4217 int csoundGetMidiNoteNumber(void *p)
4218 {
4219 return (int) ((OPDS*) p)->insdshead->m_pitch;
4220 }
4221
4222 /**
4223 * Returns MIDI velocity (in the range 0 to 127) for opcode 'p'.
4224 * If the opcode was not called from a MIDI activated instrument
4225 * instance, the return value is undefined.
4226 */
csoundGetMidiVelocity(void * p)4227 int csoundGetMidiVelocity(void *p)
4228 {
4229 return (int) ((OPDS*) p)->insdshead->m_veloc;
4230 }
4231
4232 /**
4233 * Returns non-zero if the current note (owning opcode 'p') is releasing.
4234 */
csoundGetReleaseFlag(void * p)4235 int csoundGetReleaseFlag(void *p)
4236 {
4237 return (int) ((OPDS*) p)->insdshead->relesing;
4238 }
4239
4240 /**
4241 * Returns the note-off time in seconds (measured from the beginning of
4242 * performance) of the current instrument instance, from which opcode 'p'
4243 * was called. The return value may be negative if the note has indefinite
4244 * duration.
4245 */
csoundGetOffTime(void * p)4246 double csoundGetOffTime(void *p)
4247 {
4248 return (double) ((OPDS*) p)->insdshead->offtim;
4249 }
4250
4251 /**
4252 * Returns the array of p-fields passed to the instrument instance
4253 * that owns opcode 'p', starting from p0. Only p1, p2, and p3 are
4254 * guaranteed to be available. p2 is measured in seconds from the
4255 * beginning of the current section.
4256 */
csoundGetPFields(void * p)4257 MYFLT *csoundGetPFields(void *p)
4258 {
4259
4260 /* FIXME - this is no longer valid, should return CS_VAR_MEM*
4261 and use ->p0_type */
4262 return (MYFLT*) &(((OPDS*) p)->insdshead->p0);
4263 }
4264
4265 /**
4266 * Returns the instrument number (p1) for opcode 'p'.
4267 */
csoundGetInstrumentNumber(void * p)4268 int csoundGetInstrumentNumber(void *p)
4269 {
4270 return (int) ((OPDS*) p)->insdshead->p1.value;
4271 }
4272
4273 typedef struct csMsgStruct_ {
4274 struct csMsgStruct_ *nxt;
4275 int attr;
4276 char s[1];
4277 } csMsgStruct;
4278
4279 typedef struct csMsgBuffer_ {
4280 void *mutex_;
4281 csMsgStruct *firstMsg;
4282 csMsgStruct *lastMsg;
4283 int msgCnt;
4284 char *buf;
4285 } csMsgBuffer;
4286
4287 // callback for storing messages in the buffer only
4288 static void csoundMessageBufferCallback_1_(CSOUND *csound, int attr,
4289 const char *fmt, va_list args);
4290
4291 // callback for writing messages to the buffer, and also stdout/stderr
4292 static void csoundMessageBufferCallback_2_(CSOUND *csound, int attr,
4293 const char *fmt, va_list args);
4294
4295 /**
4296 * Creates a buffer for storing messages printed by Csound.
4297 * Should be called after creating a Csound instance; note that
4298 * the message buffer uses the host data pointer, and the buffer
4299 * should be freed by calling csoundDestroyMessageBuffer() before
4300 * deleting the Csound instance.
4301 * If 'toStdOut' is non-zero, the messages are also printed to
4302 * stdout and stderr (depending on the type of the message),
4303 * in addition to being stored in the buffer.
4304 */
4305
csoundCreateMessageBuffer(CSOUND * csound,int toStdOut)4306 void PUBLIC csoundCreateMessageBuffer(CSOUND *csound, int toStdOut)
4307 {
4308 csMsgBuffer *pp;
4309 size_t nBytes;
4310
4311 pp = (csMsgBuffer*) csound->message_buffer;
4312 if (pp) {
4313 csoundDestroyMessageBuffer(csound);
4314 }
4315 nBytes = sizeof(csMsgBuffer);
4316 if (!toStdOut) {
4317 nBytes += (size_t) 16384;
4318 }
4319 pp = (csMsgBuffer*) malloc(nBytes);
4320 pp->mutex_ = csoundCreateMutex(0);
4321 pp->firstMsg = (csMsgStruct*) NULL;
4322 pp->lastMsg = (csMsgStruct*) NULL;
4323 pp->msgCnt = 0;
4324 if (!toStdOut) {
4325 pp->buf = (char*) pp + (int) sizeof(csMsgBuffer);
4326 pp->buf[0] = (char) '\0';
4327 } else {
4328 pp->buf = (char*) NULL;
4329 }
4330 csound->message_buffer = (void*) pp;
4331 if (toStdOut) {
4332 csoundSetMessageCallback(csound, csoundMessageBufferCallback_2_);
4333 } else {
4334 csoundSetMessageCallback(csound, csoundMessageBufferCallback_1_);
4335 }
4336 }
4337
4338 /**
4339 * Returns the first message from the buffer.
4340 */
4341 #ifdef MSVC
csoundGetFirstMessage(CSOUND * csound)4342 const char PUBLIC *csoundGetFirstMessage(CSOUND *csound)
4343 #else
4344 const char */*PUBLIC*/ csoundGetFirstMessage(CSOUND *csound)
4345 #endif
4346 {
4347 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4348 char *msg = NULL;
4349
4350 if (pp && pp->msgCnt) {
4351 csoundLockMutex(pp->mutex_);
4352 if (pp->firstMsg)
4353 msg = &(pp->firstMsg->s[0]);
4354 csoundUnlockMutex(pp->mutex_);
4355 }
4356 return msg;
4357 }
4358
4359 /**
4360 * Returns the attribute parameter (see msg_attr.h) of the first message
4361 * in the buffer.
4362 */
4363
csoundGetFirstMessageAttr(CSOUND * csound)4364 int PUBLIC csoundGetFirstMessageAttr(CSOUND *csound)
4365 {
4366 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4367 int attr = 0;
4368
4369 if (pp && pp->msgCnt) {
4370 csoundLockMutex(pp->mutex_);
4371 if (pp->firstMsg) {
4372 attr = pp->firstMsg->attr;
4373 }
4374 csoundUnlockMutex(pp->mutex_);
4375 }
4376 return attr;
4377 }
4378
4379 /**
4380 * Removes the first message from the buffer.
4381 */
4382
csoundPopFirstMessage(CSOUND * csound)4383 void PUBLIC csoundPopFirstMessage(CSOUND *csound)
4384 {
4385 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4386
4387 if (pp) {
4388 csMsgStruct *tmp;
4389 csoundLockMutex(pp->mutex_);
4390 tmp = pp->firstMsg;
4391 if (tmp) {
4392 pp->firstMsg = tmp->nxt;
4393 pp->msgCnt--;
4394 if (!pp->firstMsg)
4395 pp->lastMsg = (csMsgStruct*) 0;
4396 }
4397 csoundUnlockMutex(pp->mutex_);
4398 if (tmp)
4399 free((void*) tmp);
4400 }
4401 }
4402
4403 /**
4404 * Returns the number of pending messages in the buffer.
4405 */
4406
csoundGetMessageCnt(CSOUND * csound)4407 int PUBLIC csoundGetMessageCnt(CSOUND *csound)
4408 {
4409 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4410 int cnt = -1;
4411
4412 if (pp) {
4413 csoundLockMutex(pp->mutex_);
4414 cnt = pp->msgCnt;
4415 csoundUnlockMutex(pp->mutex_);
4416 }
4417 return cnt;
4418 }
4419
4420 /**
4421 * Releases all memory used by the message buffer.
4422 */
4423
csoundDestroyMessageBuffer(CSOUND * csound)4424 void PUBLIC csoundDestroyMessageBuffer(CSOUND *csound)
4425 {
4426 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4427 if (!pp) {
4428 csound->Warning(csound,
4429 Str("csoundDestroyMessageBuffer: "
4430 "Message buffer not allocated."));
4431 return;
4432 }
4433 csMsgStruct *msg = pp->firstMsg;
4434 while (msg) {
4435 csMsgStruct *tmp = msg;
4436 msg = tmp->nxt;
4437 free(tmp);
4438 }
4439 csound->message_buffer = NULL;
4440 csoundSetMessageCallback(csound, NULL);
4441 while (csoundGetMessageCnt(csound) > 0) {
4442 csoundPopFirstMessage(csound);
4443 }
4444 csoundSetHostData(csound, NULL);
4445 csoundDestroyMutex(pp->mutex_);
4446 free((void*) pp);
4447 }
4448
csoundMessageBufferCallback_1_(CSOUND * csound,int attr,const char * fmt,va_list args)4449 static void csoundMessageBufferCallback_1_(CSOUND *csound, int attr,
4450 const char *fmt, va_list args)
4451 {
4452 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4453 csMsgStruct *p;
4454 int len;
4455
4456 csoundLockMutex(pp->mutex_);
4457 len = vsnprintf(pp->buf, 16384, fmt, args); // FIXEDME: this can overflow
4458 va_end(args);
4459 if (UNLIKELY((unsigned int) len >= (unsigned int) 16384)) {
4460 csoundUnlockMutex(pp->mutex_);
4461 fprintf(stderr, Str("csound: internal error: message buffer overflow\n"));
4462 exit(-1);
4463 }
4464 p = (csMsgStruct*) malloc(sizeof(csMsgStruct) + (size_t) len);
4465 p->nxt = (csMsgStruct*) NULL;
4466 p->attr = attr;
4467 strcpy(&(p->s[0]), pp->buf);
4468 if (pp->firstMsg == (csMsgStruct*) 0) {
4469 pp->firstMsg = p;
4470 } else {
4471 pp->lastMsg->nxt = p;
4472 }
4473 pp->lastMsg = p;
4474 pp->msgCnt++;
4475 csoundUnlockMutex(pp->mutex_);
4476 }
4477
csoundMessageBufferCallback_2_(CSOUND * csound,int attr,const char * fmt,va_list args)4478 static void csoundMessageBufferCallback_2_(CSOUND *csound, int attr,
4479 const char *fmt, va_list args)
4480 {
4481 csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer;
4482 csMsgStruct *p;
4483 int len = 0;
4484 va_list args_save;
4485
4486 va_copy(args_save, args);
4487 switch (attr & CSOUNDMSG_TYPE_MASK) {
4488 case CSOUNDMSG_ERROR:
4489 case CSOUNDMSG_REALTIME:
4490 case CSOUNDMSG_WARNING:
4491 len = vfprintf(stderr, fmt, args);
4492 break;
4493 default:
4494 len = vfprintf(stdout, fmt, args);
4495 }
4496 va_end(args);
4497 p = (csMsgStruct*) malloc(sizeof(csMsgStruct) + (size_t) len);
4498 p->nxt = (csMsgStruct*) NULL;
4499 p->attr = attr;
4500 vsnprintf(&(p->s[0]), len, fmt, args_save);
4501 va_end(args_save);
4502 csoundLockMutex(pp->mutex_);
4503 if (pp->firstMsg == (csMsgStruct*) NULL)
4504 pp->firstMsg = p;
4505 else
4506 pp->lastMsg->nxt = p;
4507 pp->lastMsg = p;
4508 pp->msgCnt++;
4509 csoundUnlockMutex(pp->mutex_);
4510 }
4511
csoundGetInstrumentList(CSOUND * csound)4512 static INSTRTXT **csoundGetInstrumentList(CSOUND *csound){
4513 return csound->engineState.instrtxtp;
4514 }
4515
csoundGetKcounter(CSOUND * csound)4516 uint64_t csoundGetKcounter(CSOUND *csound){
4517 return csound->kcounter;
4518 }
4519
set_util_sr(CSOUND * csound,MYFLT sr)4520 static void set_util_sr(CSOUND *csound, MYFLT sr){ csound->esr = sr; }
set_util_nchnls(CSOUND * csound,int nchnls)4521 static void set_util_nchnls(CSOUND *csound, int nchnls){ csound->nchnls = nchnls; }
4522
csoundGetA4(CSOUND * csound)4523 MYFLT csoundGetA4(CSOUND *csound) { return (MYFLT) csound->A4; }
4524
csoundErrCnt(CSOUND * csound)4525 int csoundErrCnt(CSOUND *csound) { return csound->perferrcnt; }
4526
csoundGetInstrument(CSOUND * csound,int insno,const char * name)4527 INSTRTXT *csoundGetInstrument(CSOUND *csound, int insno, const char *name) {
4528 if (name != NULL)
4529 insno = named_instr_find(csound, (char *)name);
4530 return csound->engineState.instrtxtp[insno];
4531 }
4532
4533 #if 0
4534 PUBLIC int csoundPerformKsmpsAbsolute(CSOUND *csound)
4535 {
4536 int done = 0;
4537 int returnValue;
4538
4539 /* VL: 1.1.13 if not compiled (csoundStart() not called) */
4540 if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) {
4541 csound->Warning(csound,
4542 Str("Csound not ready for performance: csoundStart() "
4543 "has not been called\n"));
4544 return CSOUND_ERROR;
4545 }
4546 /* setup jmp for return after an exit() */
4547 if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) {
4548 #ifndef MACOSX
4549 csoundMessage(csound, Str("Early return from csoundPerformKsmps().\n"));
4550 #endif
4551 return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS);
4552 }
4553 csoundLockMutex(csound->API_lock);
4554 do {
4555 done |= sensevents(csound);
4556 } while (csound->kperf(csound));
4557 csoundUnlockMutex(csound->API_lock);
4558 return done;
4559 }
4560 #endif
4561
4562
4563 //#ifdef __cplusplus
4564 //}
4565 //#endif
4566