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