/* * C S O U N D * * An auto-extensible system for making music on computers * by means of software alone. * * Copyright (C) 2001-2006 Michael Gogins, Matt Ingalls, John D. Ramsdell, * John P. ffitch, Istvan Varga, Victor Lazzarini, * Steven Yi * * L I C E N S E * * This software is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ //#ifdef __cplusplus //extern "C" { //#endif #if defined(HAVE_UNISTD_H) || defined (__unix) || defined(__unix__) #include #endif #include "csoundCore.h" #include "csmodule.h" #include "corfile.h" #include "csGblMtx.h" #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #if defined(WIN32) && !defined(__CYGWIN__) # include # include #endif #include #include "oload.h" #include "fgens.h" #include "namedins.h" #include "pvfileio.h" #include "fftlib.h" #include "lpred.h" #include "cs_par_base.h" #include "cs_par_orc_semantics.h" #include "namedins.h" //#include "cs_par_dispatch.h" #include "find_opcode.h" #if defined(linux) || defined(__FreeBSD__) || defined(__HAIKU__)|| defined(__EMSCRIPTEN__)||defined(__CYGWIN__) #define PTHREAD_SPINLOCK_INITIALIZER 0 #endif #if defined(__FreeBSD__) #include #endif #include "csound_standard_types.h" #include "csdebug.h" #include extern void allocate_message_queue(CSOUND *csound); static void SetInternalYieldCallback(CSOUND *, int (*yieldCallback)(CSOUND *)); int playopen_dummy(CSOUND *, const csRtAudioParams *parm); void rtplay_dummy(CSOUND *, const MYFLT *outBuf, int nbytes); int recopen_dummy(CSOUND *, const csRtAudioParams *parm); int rtrecord_dummy(CSOUND *, MYFLT *inBuf, int nbytes); void rtclose_dummy(CSOUND *); int audio_dev_list_dummy(CSOUND *, CS_AUDIODEVICE *, int); int midi_dev_list_dummy(CSOUND *, CS_MIDIDEVICE *, int); static void csoundDefaultMessageCallback(CSOUND *, int, const char *, va_list); static int defaultCsoundYield(CSOUND *); static int csoundDoCallback_(CSOUND *, void *, unsigned int); static void reset(CSOUND *); static int csoundPerformKsmpsInternal(CSOUND *csound); void csoundTableSetInternal(CSOUND *csound, int table, int index, MYFLT value); static INSTRTXT **csoundGetInstrumentList(CSOUND *csound); uint64_t csoundGetKcounter(CSOUND *csound); static void set_util_sr(CSOUND *csound, MYFLT sr); static void set_util_nchnls(CSOUND *csound, int nchnls); extern void cscoreRESET(CSOUND *); extern void memRESET(CSOUND *); extern MYFLT csoundPow2(CSOUND *csound, MYFLT a); extern int csoundInitStaticModules(CSOUND *); extern void close_all_files(CSOUND *); extern void csoundInputMessageInternal(CSOUND *csound, const char *message); extern int isstrcod(MYFLT ); extern int fterror(const FGDATA *ff, const char *s, ...); PUBLIC int csoundErrCnt(CSOUND *); void (*msgcallback_)(CSOUND *, int, const char *, va_list) = NULL; INSTRTXT *csoundGetInstrument(CSOUND *csound, int insno, const char *name); void csoundDebuggerBreakpointReached(CSOUND *csound); void message_dequeue(CSOUND *csound); extern OENTRY opcodlst_1[]; #define STRING_HASH(arg) STRSH(arg) #define STRSH(arg) #arg void print_csound_version(CSOUND* csound) { #ifdef USE_DOUBLE #ifdef BETA csound->Message(csound, Str("--Csound version %s beta (double samples) %s\n" "[commit: %s]\n"), CS_PACKAGE_VERSION, CS_PACKAGE_DATE, STRING_HASH(GIT_HASH_VALUE)); #else csound->Message(csound, Str("--Csound version %s (double samples) %s\n" "[commit: %s]\n"), CS_PACKAGE_VERSION, CS_PACKAGE_DATE , STRING_HASH(GIT_HASH_VALUE)); #endif #else #ifdef BETA csound->Message(csound, Str("--Csound version %s beta (float samples) %s\n" "[commit: %s]\n"), CS_PACKAGE_VERSION, CS_PACKAGE_DATE, STRING_HASH(GIT_HASH_VALUE)); #else csound->Message(csound, Str("--Csound version %s (float samples) %s\n" "[commit: %s]\n"), CS_PACKAGE_VERSION, CS_PACKAGE_DATE, STRING_HASH(GIT_HASH_VALUE)); #endif #endif } static void free_opcode_table(CSOUND* csound) { int i; CS_HASH_TABLE_ITEM* bucket; CONS_CELL* head; for (i = 0; i < csound->opcodes->table_size; i++) { bucket = csound->opcodes->buckets[i]; while (bucket != NULL) { head = bucket->value; cs_cons_free_complete(csound, head); bucket = bucket->next; } } cs_hash_table_free(csound, csound->opcodes); } static void create_opcode_table(CSOUND *csound) { int err; if (csound->opcodes != NULL) { free_opcode_table(csound); } csound->opcodes = cs_hash_table_create(csound); /* Basic Entry1 stuff */ err = csoundAppendOpcodes(csound, &(opcodlst_1[0]), -1); if (UNLIKELY(err)) csoundDie(csound, Str("Error allocating opcode list")); } #define MAX_MODULES 64 static void module_list_add(CSOUND *csound, char *drv, char *type){ MODULE_INFO **modules = (MODULE_INFO **) csoundQueryGlobalVariable(csound, "_MODULES"); if (modules != NULL){ int i = 0; while (modules[i] != NULL && i < MAX_MODULES) { if (!strcmp(modules[i]->module, drv)) return; i++; } modules[i] = (MODULE_INFO *) csound->Malloc(csound, sizeof(MODULE_INFO)); strNcpy(modules[i]->module, drv, 11); strNcpy(modules[i]->type, type, 11); } } static int csoundGetRandSeed(CSOUND *csound, int which){ if (which > 1) return csound->randSeed1; else return csound->randSeed2; } static char *csoundGetStrsets(CSOUND *csound, long p){ if (csound->strsets == NULL) return NULL; else return csound->strsets[p]; } static int csoundGetStrsmax(CSOUND *csound){ return csound->strsmax; } static void csoundGetOParms(CSOUND *csound, OPARMS *p){ memcpy(p, csound->oparms, sizeof(OPARMS)); } static int csoundGetDitherMode(CSOUND *csound){ return csound->dither_output; } #include "Opcodes/zak.h" static int csoundGetZakBounds(CSOUND *csound, MYFLT **zkstart){ ZAK_GLOBALS *zz; zz = (ZAK_GLOBALS*) csound->QueryGlobalVariable(csound, "_zak_globals"); if (zz==NULL) { *zkstart = NULL; return -1; } *zkstart = zz->zkstart; return zz->zklast; } static int csoundGetZaBounds(CSOUND *csound, MYFLT **zastart){ ZAK_GLOBALS *zz; zz = (ZAK_GLOBALS*) csound->QueryGlobalVariable(csound, "_zak_globals"); if (zz==NULL) { *zastart = NULL; return -1; } *zastart = zz->zastart; return zz->zalast; } static int csoundGetReinitFlag(CSOUND *csound){ return csound->reinitflag; } static int csoundGetTieFlag(CSOUND *csound){ return csound->tieflag; } MYFLT csoundSystemSr(CSOUND *csound, MYFLT val) { if (val > 0) csound->_system_sr = val; return csound->_system_sr; } static const CSOUND cenviron_ = { /* attributes */ csoundGetSr, csoundGetKr, csoundGetKsmps, csoundGetNchnls, csoundGetNchnlsInput, csoundGet0dBFS, csoundGetKcounter, csoundGetCurrentTimeSamples, csoundGetInputBufferSize, csoundGetOutputBufferSize, csoundGetInputBuffer, csoundGetOutputBuffer, csoundSetDebug, csoundGetDebug, csoundGetSizeOfMYFLT, csoundGetOParms, csoundGetEnv, /* message printout */ csoundMessage, csoundMessageS, csoundMessageV, csoundGetMessageLevel, csoundSetMessageLevel, csoundSetMessageCallback, /* Event and MIDI functionality for opcodes */ csoundSetReleaseLength, csoundSetReleaseLengthSeconds, csoundGetMidiChannelNumber, csoundGetMidiChannel, csoundGetMidiNoteNumber, csoundGetMidiVelocity, csoundGetReleaseFlag, csoundGetOffTime, csoundGetPFields, csoundGetInstrumentNumber, csoundGetZakBounds, csoundGetTieFlag, csoundGetReinitFlag, csoundGetStrsmax, csoundGetStrsets, csoundPow2, intpow, type2string, /* arguments to opcodes */ csoundGetTypeForArg, csoundGetInputArgCnt, csoundGetInputArgName, csoundGetOutputArgCnt, csoundGetOutputArgName, get_arg_string, strarg2insno, strarg2name, /* memory allocation */ csoundAuxAlloc, mmalloc, mcalloc, mrealloc, cs_strdup, mfree, /* function tables */ hfgens, csoundFTAlloc, csoundFTDelete, csoundFTFind, csoundFTFindP, csoundFTnp2Find, csoundGetTable, csoundTableLength, csoundTableGet, csoundTableSetInternal, csoundGetNamedGens, /* global and config variable manipulation */ csoundCreateGlobalVariable, csoundQueryGlobalVariable, csoundQueryGlobalVariableNoCheck, csoundDestroyGlobalVariable, csoundCreateConfigurationVariable, csoundSetConfigurationVariable, csoundParseConfigurationVariable, csoundQueryConfigurationVariable, csoundListConfigurationVariables, csoundDeleteConfigurationVariable, csoundCfgErrorCodeToString, /* FFT support */ csoundGetInverseComplexFFTScale, csoundGetInverseRealFFTScale, csoundComplexFFT, csoundInverseComplexFFT, csoundRealFFT, csoundInverseRealFFT, csoundRealFFTMult, csoundRealFFTnp2, csoundInverseRealFFTnp2, /* PVOC-EX system */ pvoc_createfile, pvoc_openfile, pvoc_closefile, pvoc_putframes, pvoc_getframes, pvoc_framecount, pvoc_fseek, pvoc_errorstr, PVOCEX_LoadFile, /* error messages */ csoundDie, csoundInitError, csoundPerfError, csoundWarning, csoundDebugMsg, csoundLongJmp, csoundErrorMsg, csoundErrMsgV, /* random numbers */ csoundGetRandomSeedFromTime, csoundSeedRandMT, csoundRandMT, csoundRand31, csoundGetRandSeed, /* threads and locks */ csoundCreateThread, csoundJoinThread, csoundCreateThreadLock, csoundDestroyThreadLock, csoundWaitThreadLock, csoundNotifyThreadLock, csoundWaitThreadLockNoTimeout, csoundCreateMutex, csoundLockMutexNoWait, csoundLockMutex, csoundUnlockMutex, csoundDestroyMutex, csoundCreateBarrier, csoundDestroyBarrier, csoundWaitBarrier, csoundGetCurrentThreadId, csoundSleep, csoundInitTimerStruct, csoundGetRealTime, csoundGetCPUTime, /* circular buffer */ csoundCreateCircularBuffer, csoundReadCircularBuffer, csoundWriteCircularBuffer, csoundFlushCircularBuffer, csoundDestroyCircularBuffer, /* File access */ csoundFindInputFile, csoundFindOutputFile, SAsndgetset, sndgetset, getsndin, rewriteheader, csoundLoadSoundFile, fdrecord, csound_fd_close, csoundCreateFileHandle, csoundGetFileName, csoundFileClose, csoundFileOpenWithType, type2csfiletype, csoundNotifyFileOpened, sftype2csfiletype, ldmemfile2withCB, csoundFileOpenWithType_Async, csoundReadAsync, csoundWriteAsync, csoundFSeekAsync, getstrformat, sfsampsize, /* RT audio IO and callbacks */ csoundSetPlayopenCallback, csoundSetRtplayCallback, csoundSetRecopenCallback, csoundSetRtrecordCallback, csoundSetRtcloseCallback, csoundSetAudioDeviceListCallback, csoundGetRtRecordUserData, csoundGetRtPlayUserData, csoundGetDitherMode, /* MIDI and callbacks */ csoundSetExternalMidiInOpenCallback, csoundSetExternalMidiReadCallback, csoundSetExternalMidiInCloseCallback, csoundSetExternalMidiOutOpenCallback, csoundSetExternalMidiWriteCallback, csoundSetExternalMidiOutCloseCallback, csoundSetExternalMidiErrorStringCallback, csoundSetMIDIDeviceListCallback, module_list_add, /* displays & graphs */ dispset, display, dispexit, dispinit, csoundSetIsGraphable, csoundSetMakeGraphCallback, csoundSetDrawGraphCallback, csoundSetKillGraphCallback, csoundSetExitGraphCallback, /* generic callbacks */ csoundSetYieldCallback, csoundRegisterKeyboardCallback, csoundRemoveKeyboardCallback, csoundRegisterSenseEventCallback, csoundRegisterDeinitCallback, csoundRegisterResetCallback, SetInternalYieldCallback, /* opcodes and instruments */ csoundAppendOpcode, csoundAppendOpcodes, csoundGetOpcodeName, csoundGetInstrumentList, /* events and performance */ csoundYield, insert_score_event, insert_score_event_at_sample, csoundPerformKsmpsInternal, /* utilities */ csoundAddUtility, csoundRunUtility, csoundListUtilities, csoundSetUtilityDescription, csoundGetUtilityDescription, set_util_sr, set_util_nchnls, /* miscellaneous */ csoundRunCommand, csoundOpenLibrary, csoundCloseLibrary, csoundGetLibrarySymbol, csoundLocalizeString, cs_strtok_r, cs_strtod, cs_sprintf, cs_sscanf, csoundSystemSr, csoundGetScoreOffsetSeconds, csoundSetScoreOffsetSeconds, csoundRewindScore, csoundInputMessageInternal, isstrcod, csoundRealFFT2Setup, csoundRealFFT2, fterror, csoundGetA4, csoundAuxAllocAsync, csoundGetHostData, strNcpy, csoundGetZaBounds, find_opcode_new, find_opcode_exact, csoundGetChannelPtr, csoundListChannels, csoundErrCnt, csoundFTnp2Finde, csoundGetInstrument, csoundAutoCorrelation, csoundLPsetup, csoundLPfree, csoundLPred, csoundLPCeps, csoundCepsLP, csoundLPrms, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, /* ------- private data (not to be used by hosts or externals) ------- */ /* callback function pointers */ (SUBR) NULL, /* first_callback_ */ (channelCallback_t) NULL, (channelCallback_t) NULL, csoundDefaultMessageCallback, (int (*)(CSOUND *)) NULL, (void (*)(CSOUND *, WINDAT *, const char *)) NULL, /* was: MakeAscii,*/ (void (*)(CSOUND *, WINDAT *windat)) NULL, /* was: DrawAscii,*/ (void (*)(CSOUND *, WINDAT *windat)) NULL, /* was: KillAscii,*/ (int (*)(CSOUND *)) NULL, /* was: defaultCsoundExitGraph, */ defaultCsoundYield, cscore_, /* cscoreCallback_ */ (void(*)(CSOUND*, const char*, int, int, int)) NULL, /* FileOpenCallback_ */ (SUBR) NULL, /* last_callback_ */ /* these are not saved on RESET */ playopen_dummy, rtplay_dummy, recopen_dummy, rtrecord_dummy, rtclose_dummy, audio_dev_list_dummy, midi_dev_list_dummy, csoundDoCallback_, /* doCsoundCallback */ defaultCsoundYield, /* csoundInternalYieldCallback_*/ /* end of callbacks */ (void (*)(CSOUND *)) NULL, /* spinrecv */ (void (*)(CSOUND *)) NULL, /* spoutran */ (int (*)(CSOUND *, MYFLT *, int)) NULL, /* audrecv */ (void (*)(CSOUND *, const MYFLT *, int)) NULL, /* audtran */ NULL, /* hostdata */ NULL, NULL, /* orchname, scorename */ NULL, NULL, /* orchstr, *scorestr */ (OPDS*) NULL, /* ids */ { (CS_VAR_POOL*)NULL, (CS_HASH_TABLE *) NULL, (CS_HASH_TABLE *) NULL, -1, (INSTRTXT**)NULL, { NULL, { 0,0, NULL, NULL, NULL, NULL, 0,0, NULL, 0,0,0}, 0,0,0, //0, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, FL(0.0), NULL, NULL, 0, 0, 0 }, NULL, MAXINSNO, /* engineState */ }, (INSTRTXT *) NULL, /* instr0 */ (INSTRTXT**)NULL, /* dead_instr_pool */ 0, /* dead_instr_no */ (TYPE_POOL*)NULL, DFLT_KSMPS, /* ksmps */ DFLT_NCHNLS, /* nchnls */ -1, /* inchns */ 0, /* spoutactive */ 0L, /* kcounter */ 0L, /* global_kcounter */ DFLT_SR, /* esr */ DFLT_KR, /* ekr */ 0l, /* curTime */ 0l, /* curTime_inc */ 0.0, /* timeOffs */ 0.0, /* beatOffs */ 0.0, /* curBeat */ 0.0, /* curBeat_inc */ 0L, /* beatTime */ (EVTBLK*) NULL, /* currevent */ (INSDS*) NULL, /* curip */ FL(0.0), /* cpu_power_busy */ (char*) NULL, /* xfilename */ 1, /* peakchunks */ 0, /* keep_tmp */ (CS_HASH_TABLE*)NULL, /* Opcode hash table */ 0, /* nrecs */ NULL, /* Linepipe */ 0, /* Linefd */ NULL, /* csoundCallbacks_ */ (FILE*)NULL, /* scfp */ (CORFIL*)NULL, /* scstr */ NULL, /* oscfp */ { FL(0.0) }, /* maxamp */ { FL(0.0) }, /* smaxamp */ { FL(0.0) }, /* omaxamp */ {0}, {0}, {0}, /* maxpos, smaxpos, omaxpos */ NULL, NULL, /* scorein, scoreout */ NULL, /* argoffspace */ NULL, /* frstoff */ NULL, /* stdOp_Env */ 2345678, /* holdrand */ 0, /* randSeed1 */ 0, /* randSeed2 */ NULL, /* csRandState */ NULL, /* csRtClock */ // 16384, /* strVarMaxLen */ 0, /* strsmax */ (char**) NULL, /* strsets */ NULL, /* spin */ NULL, /* spout */ NULL, /* spraw */ 0, /* nspin */ 0, /* nspout */ NULL, /* auxspin */ (OPARMS*) NULL, /* oparms */ { NULL }, /* m_chnbp */ 0, /* dither_output */ FL(0.0), /* onedsr */ FL(0.0), /* sicvt */ FL(-1.0), /* tpidsr */ FL(-1.0), /* pidsr */ FL(-1.0), /* mpidsr */ FL(-1.0), /* mtpdsr */ FL(0.0), /* onedksmps */ FL(0.0), /* onedkr */ FL(0.0), /* kicvt */ 0, /* reinitflag */ 0, /* tieflag */ DFLT_DBFS, /* e0dbfs */ FL(1.0) / DFLT_DBFS, /* dbfs_to_float ( = 1.0 / e0dbfs) */ 440.0, /* A4 base frequency */ NULL, /* rtRecord_userdata */ NULL, /* rtPlay_userdata */ #if defined(MSVC) ||defined(__POWERPC__) || defined(MACOSX) {0}, #else {{{0}}}, /* exitjmp of type jmp_buf */ #endif NULL, /* frstbp */ 0, /* sectcnt */ 0, 0, 0, /* inerrcnt, synterrcnt, perferrcnt */ /* {NULL}, */ /* instxtanchor in engineState */ { /* actanchor */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0, NULL, 0, 0, 0, 0, 0, 0.0, 0.0, NULL, NULL, 0, 0, FL(0.0), FL(0.0), FL(0.0), FL(0.0), NULL, {FL(0.0), FL(0.0), FL(0.0), FL(0.0)}, NULL, NULL,NULL, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, FL(0.0), NULL, NULL, {NULL, FL(0.0)}, {NULL, FL(0.0)}, {NULL, FL(0.0)}, {NULL, FL(0.0)} }, {0L }, /* rngcnt */ 0, 0, /* rngflg, multichan */ NULL, /* evtFuncChain */ NULL, /* OrcTrigEvts */ NULL, /* freeEvtNodes */ 1, /* csoundIsScorePending_ */ 0, /* advanceCnt */ 0, /* initonly */ 0, /* evt_poll_cnt */ 0, /* evt_poll_maxcnt */ 0, 0, 0, /* Mforcdecs, Mxtroffs, MTrkend */ NULL, /* opcodeInfo */ NULL, /* flist */ 0, /* maxfnum */ NULL, /* gensub */ GENMAX+1, /* genmax */ NULL, /* namedGlobals */ NULL, /* cfgVariableDB */ FL(0.0), FL(0.0), FL(0.0), /* prvbt, curbt, nxtbt */ FL(0.0), FL(0.0), /* curp2, nxtim */ 0, /* cyclesRemaining */ { 0, NULL, NULL, '\0', 0, FL(0.0), FL(0.0), { FL(0.0) }, {NULL}}, /* evt */ NULL, /* memalloc_db */ (MGLOBAL*) NULL, /* midiGlobals */ NULL, /* envVarDB */ (MEMFIL*) NULL, /* memfiles */ NULL, /* pvx_memfiles */ 0, /* FFT_max_size */ NULL, /* FFT_table_1 */ NULL, /* FFT_table_2 */ NULL, NULL, NULL, /* tseg, tpsave, unused */ (MYFLT*) NULL, /* gbloffbas */ NULL, /* file_io_thread */ 0, /* file_io_start */ NULL, /* file_io_threadlock */ 0, /* realtime_audio_flag */ NULL, /* init pass thread */ 0, /* init pass loop */ NULL, /* init pass threadlock */ NULL, /* API_lock */ SPINLOCK_INIT, SPINLOCK_INIT, /* spinlocks */ SPINLOCK_INIT, SPINLOCK_INIT, /* spinlocks */ NULL, NULL, /* Delayed messages */ { NULL, NULL, NULL, NULL, /* bp, prvibp, sp, nx */ 0, 0, 0, 0, /* op warpin linpos lincnt */ -FL(1.0), FL(0.0), FL(1.0), /* prvp2 clock_base warp_factor */ NULL, /* curmem */ NULL, /* memend */ NULL, /* macros */ -1, /* next_name */ NULL, NULL, /* inputs, str */ 0,0,0, /* input_size, input_cnt, pop */ 1, /* ingappop */ -1, /* linepos */ {{NULL, 0, 0}}, /* names */ {""}, /* repeat_name_n[RPTDEPTH][NAMELEN] */ {0}, /* repeat_cnt_n[RPTDEPTH] */ {0}, /* repeat_point_n[RPTDEPTH] */ 1, {NULL}, 0, /* repeat_inc_n,repeat_mm_n repeat_index */ "", /* repeat_name[NAMELEN] */ 0,0,1, /* repeat_cnt, repeat_point, repeat_inc */ NULL, /* repeat_mm */ 0 }, { NULL, NULL, NULL, NULL, /* orcname, sconame, midname */ 0, 0 /* midiSet, csdlinecount */ }, { NULL, NULL, /* Linep, Linebufend */ 0, /* stdmode */ { 0, NULL, NULL, 0, 0, FL(0.0), FL(0.0), { FL(0.0) }, {NULL}, }, /* EVTBLK prve */ NULL, /* Linebuf */ 0, /* linebufsiz */ NULL, NULL, 0 }, { {0,0}, {0,0}, /* srngcnt, orngcnt */ 0, 0, 0, 0, 0, /* srngflg, sectno, lplayed, segamps, sormsg */ NULL, NULL, /* ep, epend */ NULL /* lsect */ }, //NULL, /* musmonGlobals */ { NULL, /* outfile */ NULL, /* infile */ NULL, /* sfoutname; */ NULL, /* inbuf */ NULL, /* outbuf */ NULL, /* outbufp */ 0, /* inbufrem */ 0, /* outbufrem */ 0,0, /* inbufsiz, outbufsiz */ 0, /* isfopen */ 0, /* osfopen */ 0,0, /* pipdevin, pipdevout */ 1U, /* nframes */ NULL, NULL, /* pin, pout */ 0, /*dither */ }, 0, /* warped */ 0, /* sstrlen */ (char*) NULL, /* sstrbuf */ 1, /* enableMsgAttr */ 0, /* sampsNeeded */ FL(0.0), /* csoundScoreOffsetSeconds_ */ -1, /* inChar_ */ 0, /* isGraphable_ */ 0, /* delayr_stack_depth */ NULL, /* first_delayr */ NULL, /* last_delayr */ { 0L, 0L, 0L, 0L, 0L, 0L }, /* revlpsiz */ 0L, /* revlpsum */ 0.5, /* rndfrac */ NULL, /* logbase2 */ NULL, NULL, /* omacros, smacros */ NULL, /* namedgen */ NULL, /* open_files */ NULL, /* searchPathCache */ NULL, /* sndmemfiles */ NULL, /* reset_list */ NULL, /* pvFileTable */ 0, /* pvNumFiles */ 0, /* pvErrorCode */ // NULL, /* pluginOpcodeFiles */ 0, /* enableHostImplementedAudioIO */ 0, /* MIDI IO */ 0, /* hostRequestedBufferSize */ 0, /* engineStatus */ 0, /* stdin_assign_flg */ 0, /* stdout_assign_flg */ 0, /* orcname_mode */ 0, /* use_only_orchfile */ NULL, /* csmodule_db */ (char*) NULL, /* dl_opcodes_oplibs */ (char*) NULL, /* SF_csd_licence */ (char*) NULL, /* SF_id_title */ (char*) NULL, /* SF_id_copyright */ -1, /* SF_id_scopyright */ (char*) NULL, /* SF_id_software */ (char*) NULL, /* SF_id_artist */ (char*) NULL, /* SF_id_comment */ (char*) NULL, /* SF_id_date */ NULL, /* utility_db */ (int16*) NULL, /* isintab */ NULL, /* lprdaddr */ 0, /* currentLPCSlot */ 0, /* max_lpc_slot */ NULL, /* chn_db */ 1, /* opcodedirWasOK */ 0, /* disable_csd_options */ { 0, { 0U } }, /* randState_ */ 0, /* performState */ 1000, /* ugens4_rand_16 */ 1000, /* ugens4_rand_15 */ NULL, /* schedule_kicked */ (MYFLT*) NULL, /* disprep_fftcoefs */ NULL, /* winEPS_globals */ { /* oparms_ */ 0, /* odebug */ 0, 1, 1, 0, /* sfread, ... */ 0, 0, 0, 0, /* inbufsamps, ... */ 0, /* sfsampsize */ 1, /* displays */ 1, 0, 135, /* graphsoff ... */ 0, 0, /* Beatmode, ... */ 0, 0, /* usingcscore, ... */ 0, 0, 0, 0, /* RTevents, ... */ 0, 0, /* ringbell, ... */ 0, 0, 0, /* rewrt_hdr, ... */ 0.0, /* cmdTempo */ 0.0f, 0.0f, /* sr_override ... */ 0, 0, /* nchnls_override ... */ (char*) NULL, (char*) NULL, NULL, (char*) NULL, (char*) NULL, (char*) NULL, (char*) NULL, (char*) NULL, 0, /* midiKey */ 0, /* midiKeyCps */ 0, /* midiKeyOct */ 0, /* midiKeyPch */ 0, /* midiVelocity */ 0, /* midiVelocityAmp */ 0, /* noDefaultPaths */ 1, /* numThreads */ 0, /* syntaxCheckOnly */ 1, /* useCsdLineCounts */ 0, /* samp acc */ 0, /* realtime */ 0.0, /* 0dbfs override */ 0, /* no exit on compile error */ 0.4, /* vbr quality */ 0, /* ksmps_override */ 0, /* fft_lib */ 0 }, {0, 0, {0}}, /* REMOT_BUF */ NULL, /* remoteGlobals */ 0, 0, /* nchanof, nchanif */ NULL, NULL, /* chanif, chanof */ 0, /* multiThreadedComplete */ NULL, /* multiThreadedThreadInfo */ NULL, /* multiThreadedDag */ NULL, /* barrier1 */ NULL, /* barrier2 */ NULL, /* pointer1 was global_var_lock_root */ NULL, /* pointer2 was global_var_lock_cache */ 0, /* int1 was global_var_lock_count */ /* statics from cs_par_orc_semantic_analysis */ NULL, /* instCurr */ NULL, /* instRoot */ 0, /* inInstr */ /* new dag model statics */ 1, /* dag_changed */ 0, /* dag_num_active */ NULL, /* dag_task_map */ NULL, /* dag_task_status */ NULL, /* dag_task_watch */ NULL, /* dag_wlmm */ NULL, /* dag_task_dep */ 100, /* dag_task_max_size */ 0, /* tempStatus */ 1, /* orcLineOffset */ 0, /* scoLineOffset */ NULL, /* csdname */ -1, /* parserUdoflag */ 0, /* parserNamedInstrFlag */ 0, /* tran_nchnlsi */ 0, /* Count of score strings */ 0, /* length of current strings space */ NULL, /* sinetable */ 16384, /* sinesize */ NULL, /* unused *** pow2 table */ NULL, /* cps conv table */ NULL, /* output of preprocessor */ NULL, /* output of preprocessor */ {NULL}, /* filedir */ NULL, /* message buffer struct */ 0, /* jumpset */ 0, /* info_message_request */ 0, /* modules loaded */ -1, /* audio system sr */ 0, /* csdebug_data */ kperf_nodebug, /* current kperf function - nodebug by default */ 0, /* which score parser */ NULL, /* symbtab */ 0, /* print_version */ 1, /* inZero */ NULL, /* msg_queue */ 0, /* msg_queue_wget */ 0, /* msg_queue_wput */ 0, /* msg_queue_rstart */ 0, /* msg_queue_items */ 127, /* aftouch */ NULL, /* directory for corfiles */ NULL, /* alloc_queue */ 0, /* alloc_queue_items */ 0, /* alloc_queue_wp */ SPINLOCK_INIT, /* alloc_spinlock */ NULL, /* init_event */ NULL, /* message string callback */ NULL, /* message_string */ 0, /* message_string_queue_items */ 0, /* message_string_queue_wp */ NULL, /* message_string_queue */ 0, /* io_initialised */ NULL, /* op */ 0, /* mode */ NULL, /* opcodedir */ NULL /* score_srt */ }; void csound_aops_init_tables(CSOUND *cs); typedef struct csInstance_s { CSOUND *csound; struct csInstance_s *nxt; } csInstance_t; /* initialisation state: */ /* 0: not done yet, 1: complete, 2: in progress, -1: failed */ static volatile int init_done = 0; /* chain of allocated Csound instances */ static volatile csInstance_t *instance_list = NULL; /* non-zero if performance should be terminated now */ static volatile int exitNow_ = 0; #if !defined(WIN32) static void destroy_all_instances(void) { volatile csInstance_t *p; csoundLock(); init_done = -1; /* prevent the creation of any new instances */ if (instance_list == NULL) { csoundUnLock(); return; } csoundUnLock(); csoundSleep(250); while (1) { csoundLock(); p = instance_list; csoundUnLock(); if (p == NULL) { break; } csoundDestroy(p->csound); } } #endif #if defined(ANDROID) || (!defined(LINUX) && !defined(SGI) && \ !defined(__HAIKU__) && !defined(__BEOS__) && \ !defined(__MACH__) && !defined(__EMSCRIPTEN__)) static char *signal_to_string(int sig) { switch(sig) { #ifdef SIGHUP case SIGHUP: return "Hangup"; #endif #ifdef SIGINT case SIGINT: return "Interrupt"; #endif #ifdef SIGQUIT case SIGQUIT: return "Quit"; #endif #ifdef SIGILL case SIGILL: return "Illegal instruction"; #endif #ifdef SIGTRAP case SIGTRAP: return "Trace trap"; #endif #ifdef SIGABRT case SIGABRT: return "Abort"; #endif #ifdef SIGBUS case SIGBUS: return "BUS error"; #endif #ifdef SIGFPE case SIGFPE: return "Floating-point exception"; #endif #ifdef SIGUSR1 case SIGUSR1: return "User-defined signal 1"; #endif #ifdef SIGSEGV case SIGSEGV: return "Segmentation violation"; #endif #ifdef SIGUSR2 case SIGUSR2: return "User-defined signal 2"; #endif #ifdef SIGPIPE case SIGPIPE: return "Broken pipe"; #endif #ifdef SIGALRM case SIGALRM: return "Alarm clock"; #endif #ifdef SIGTERM case SIGTERM: return "Termination"; #endif #ifdef SIGSTKFLT case SIGSTKFLT: return "???"; #endif #ifdef SIGCHLD case SIGCHLD: return "Child status has changed"; #endif #ifdef SIGCONT case SIGCONT: return "Continue"; #endif #ifdef SIGSTOP case SIGSTOP: return "Stop, unblockable"; #endif #ifdef SIGTSTP case SIGTSTP: return "Keyboard stop"; #endif #ifdef SIGTTIN case SIGTTIN: return "Background read from tty"; #endif #ifdef SIGTTOU case SIGTTOU: return "Background write to tty"; #endif #ifdef SIGURG case SIGURG: return "Urgent condition on socket "; #endif #ifdef SIGXCPU case SIGXCPU: return "CPU limit exceeded"; #endif #ifdef SIGXFSZ case SIGXFSZ: return "File size limit exceeded "; #endif #ifdef SIGVTALRM case SIGVTALRM: return "Virtual alarm clock "; #endif #ifdef SIGPROF case SIGPROF: return "Profiling alarm clock"; #endif #ifdef SIGWINCH case SIGWINCH: return "Window size change "; #endif #ifdef SIGIO case SIGIO: return "I/O now possible"; #endif #ifdef SIGPWR case SIGPWR: return "Power failure restart"; #endif default: return "???"; } } #ifdef ANDROID static void psignal_(int sig, char *str) { fprintf(stderr, "%s: %s\n", str, signal_to_string(sig)); } #else # if !defined(__CYGWIN__) static void psignal(int sig, const char *str) { fprintf(stderr, "%s: %s\n", str, signal_to_string(sig)); } # endif #endif #elif defined(__BEOS__) static void psignal_(int sig, char *str) { fprintf(stderr, "%s: %s\n", str, strsignal(sig)); } #endif static void signal_handler(int sig) { #if defined(HAVE_EXECINFO) && !defined(ANDROID) && !defined(NACL) #include { int j, nptrs; #define SIZE 100 void *buffer[SIZE]; char **strings; nptrs = backtrace(buffer, SIZE); printf("backtrace() returned %d addresses\n", nptrs); /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO) would produce similar output to the following: */ strings = backtrace_symbols(buffer, nptrs); if (UNLIKELY(strings == NULL)) { perror("backtrace_symbols"); exit(EXIT_FAILURE); } for (j = 0; j < nptrs; j++) printf("%s\n", strings[j]); free(strings); } #endif #if defined(SIGPIPE) if (sig == (int) SIGPIPE) { #ifdef ANDROID psignal_(sig, "Csound ignoring SIGPIPE"); #else psignal(sig, "Csound ignoring SIGPIPE"); #endif return; } #endif #ifdef ANDROID psignal_(sig, "Csound tidy up"); #else psignal(sig, "Csound tidy up"); #endif if ((sig == (int) SIGINT || sig == (int) SIGTERM) && !exitNow_) { exitNow_ = -1; return; } exit(1); } static const int sigs[] = { #if defined(LINUX) || defined(SGI) || defined(sol) || defined(__MACH__) SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, SIGBUS, SIGFPE, SIGSEGV, SIGPIPE, SIGTERM, SIGXCPU, SIGXFSZ, #elif defined(WIN32) SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTERM, #elif defined(__EMX__) SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGTERM, SIGCHLD, #endif -1 }; static void install_signal_handler(void) { unsigned int i; for (i = 0; sigs[i] >= 0; i++) { signal(sigs[i], signal_handler); } } static int getTimeResolution(void); PUBLIC int csoundInitialize(int flags) { int n; do { csoundLock(); n = init_done; switch (n) { case 2: csoundUnLock(); csoundSleep(1); case 0: break; default: csoundUnLock(); return n; } } while (n); init_done = 2; csoundUnLock(); if (getTimeResolution() != 0) { csoundLock(); init_done = -1; csoundUnLock(); return -1; } if (!(flags & CSOUNDINIT_NO_SIGNAL_HANDLER)) { install_signal_handler(); } #if !defined(WIN32) if (!(flags & CSOUNDINIT_NO_ATEXIT)) atexit(destroy_all_instances); #endif csoundLock(); init_done = 1; csoundUnLock(); return 0; } static char *opcodedir = NULL; PUBLIC void csoundSetOpcodedir(const char *s) { opcodedir = (char *) s; } PUBLIC CSOUND *csoundCreate(void *hostdata) { CSOUND *csound; csInstance_t *p; _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); if (init_done != 1) { if (csoundInitialize(0) < 0) return NULL; } csound = (CSOUND*) malloc(sizeof(CSOUND)); if (UNLIKELY(csound == NULL)) return NULL; memcpy(csound, &cenviron_, sizeof(CSOUND)); init_getstring(csound); csound->oparms = &(csound->oparms_); csound->hostdata = hostdata; p = (csInstance_t*) malloc(sizeof(csInstance_t)); if (UNLIKELY(p == NULL)) { free(csound); return NULL; } csoundLock(); p->csound = csound; p->nxt = (csInstance_t*) instance_list; instance_list = p; csound->opcodedir = cs_strdup(csound, opcodedir); csoundUnLock(); csoundReset(csound); csound->API_lock = csoundCreateMutex(1); allocate_message_queue(csound); /* NB: as suggested by F Pinot, keep the address of the pointer to CSOUND inside the struct, so it can be cleared later */ //csound->self = &csound; return csound; } /* dummy real time MIDI functions */ int DummyMidiInOpen(CSOUND *csound, void **userData, const char *devName); int DummyMidiRead(CSOUND *csound, void *userData, unsigned char *buf, int nbytes); int DummyMidiOutOpen(CSOUND *csound, void **userData, const char *devName); int DummyMidiWrite(CSOUND *csound, void *userData, const unsigned char *buf, int nbytes); /* random.c */ extern void csound_init_rand(CSOUND *); /* PUBLIC int csoundQueryInterface(const char *name, void **iface, int *version) { if (strcmp(name, "CSOUND") != 0) return 1; *iface = csoundCreate(NULL); *version = csoundGetAPIVersion(); return 0; } */ typedef struct CsoundCallbackEntry_s CsoundCallbackEntry_t; struct CsoundCallbackEntry_s { unsigned int typeMask; CsoundCallbackEntry_t *nxt; void *userData; int (*func)(void *, void *, unsigned int); }; PUBLIC void csoundDestroy(CSOUND *csound) { csInstance_t *p, *prv = NULL; csoundLock(); p = (csInstance_t*) instance_list; while (p != NULL && p->csound != csound) { prv = p; p = p->nxt; } if (p == NULL) { csoundUnLock(); return; } if (prv == NULL) instance_list = p->nxt; else prv->nxt = p->nxt; csoundUnLock(); free(p); reset(csound); if (csound->csoundCallbacks_ != NULL) { CsoundCallbackEntry_t *pp, *nxt; pp = (CsoundCallbackEntry_t*) csound->csoundCallbacks_; do { nxt = pp->nxt; free((void*) pp); pp = nxt; } while (pp != (CsoundCallbackEntry_t*) NULL); } if (csound->API_lock != NULL) { //csoundLockMutex(csound->API_lock); csoundDestroyMutex(csound->API_lock); } /* clear the pointer */ // *(csound->self) = NULL; free((void*) csound); } PUBLIC int csoundGetVersion(void) { return (int) (CS_VERSION * 1000 + CS_SUBVER * 10 + CS_PATCHLEVEL); } PUBLIC int csoundGetAPIVersion(void) { return CS_APIVERSION * 100 + CS_APISUBVER; } PUBLIC void *csoundGetHostData(CSOUND *csound) { return csound->hostdata; } PUBLIC void csoundSetHostData(CSOUND *csound, void *hostData) { csound->hostdata = hostData; } /* * PERFORMANCE */ extern int sensevents(CSOUND *); /** * perform currently active instrs for one kperiod * & send audio result to output buffer * returns non-zero if this kperiod was skipped */ static int getThreadIndex(CSOUND *csound, void *threadId) { int index = 0; THREADINFO *current = csound->multiThreadedThreadInfo; if (current == NULL) { return -1; } while (current != NULL) { #ifdef HAVE_PTHREAD if (pthread_equal(*(pthread_t *)threadId, *(pthread_t *)current->threadId)) #elif defined(WIN32) DWORD* d = (DWORD*)threadId; if (*d == GetThreadId((HANDLE)current->threadId)) #else // FIXME - need to verify this works... if (threadId == current->threadId) #endif return index; index++; current = current->next; } return -1; } #if 0 static int getNumActive(INSDS *start, INSDS *end) { INSDS *current = start; int counter = 1; while (((current = current->nxtact) != NULL) && current != end) { counter++; } return counter; } #endif inline void advanceINSDSPointer(INSDS ***start, int num) { int i; INSDS *s = **start; if (s == NULL) return; for (i = 0; i < num; i++) { s = s->nxtact; if (s == NULL) { **start = NULL; return; } } **start = s; } int dag_get_task(CSOUND *csound, int index, int numThreads, int next_task); int dag_end_task(CSOUND *csound, int task); void dag_build(CSOUND *csound, INSDS *chain); void dag_reinit(CSOUND *csound); inline static int nodePerf(CSOUND *csound, int index, int numThreads) { INSDS *insds = NULL; OPDS *opstart = NULL; int played_count = 0; int which_task; INSDS **task_map = (INSDS**)csound->dag_task_map; double time_end; #define INVALID (-1) #define WAIT (-2) int next_task = INVALID; IGN(index); while (1) { int done; which_task = dag_get_task(csound, index, numThreads, next_task); //printf("******** Select task %d\n", which_task); if (which_task==WAIT) continue; if (which_task==INVALID) return played_count; /* VL: the validity of icurTime needs to be checked */ time_end = (csound->ksmps+csound->icurTime)/csound->esr; insds = task_map[which_task]; if (insds->offtim > 0 && time_end > insds->offtim){ /* this is the last cycle of performance */ insds->ksmps_no_end = insds->no_end; } #if defined(MSVC) done = InterlockedExchangeAdd(&insds->init_done, 0); #elif defined(HAVE_ATOMIC_BUILTIN) done = __atomic_load_n((int *) &insds->init_done, __ATOMIC_SEQ_CST); #else done = insds->init_done; #endif if (done) { opstart = (OPDS*)task_map[which_task]; if (insds->ksmps == csound->ksmps) { insds->spin = csound->spin; insds->spout = csound->spraw; insds->kcounter = csound->kcounter; csound->mode = 2; while ((opstart = opstart->nxtp) != NULL) { /* In case of jumping need this repeat of opstart */ opstart->insdshead->pds = opstart; csound->op = opstart->optext->t.opcod; (*opstart->opadr)(csound, opstart); /* run each opcode */ opstart = opstart->insdshead->pds; } csound->mode = 0; } else { int i, n = csound->nspout, start = 0; int lksmps = insds->ksmps; int incr = csound->nchnls*lksmps; int offset = insds->ksmps_offset; int early = insds->ksmps_no_end; OPDS *opstart; insds->spin = csound->spin; insds->spout = csound->spraw; insds->kcounter = csound->kcounter*csound->ksmps; /* we have to deal with sample-accurate code whole CS_KSMPS blocks are offset here, the remainder is left to each opcode to deal with. */ while (offset >= lksmps) { offset -= lksmps; start += csound->nchnls; } insds->ksmps_offset = offset; if (UNLIKELY(early)) { n -= (early*csound->nchnls); insds->ksmps_no_end = early % lksmps; } for (i=start; i < n; i+=incr, insds->spin+=incr, insds->spout+=incr) { opstart = (OPDS*) insds; csound->mode = 2; while ((opstart = opstart->nxtp) != NULL) { opstart->insdshead->pds = opstart; csound->op = opstart->optext->t.opcod; (*opstart->opadr)(csound, opstart); /* run each opcode */ opstart = opstart->insdshead->pds; } csound->mode = 0; insds->kcounter++; } } insds->ksmps_offset = 0; /* reset sample-accuracy offset */ insds->ksmps_no_end = 0; /* reset end of loop samples */ played_count++; } //printf("******** finished task %d\n", which_task); next_task = dag_end_task(csound, which_task); } return played_count; } inline static void make_interleave(CSOUND *csound, uint32_t lksmps) { uint32_t nsmps = csound->ksmps, nchan = csound->nchnls,i, j, n, k=0; MYFLT *spout = csound->spout; if (!csound->spoutactive) { memset(spout, '\0', csound->nspout*sizeof(MYFLT)); } else if (lksmps == nsmps|| nchan==1 ) { for (j=0; jspraw[i*nsmps+j]; } k += nchan; } } else { int m = 0; for (n=0; nspraw[i*lksmps+j+m]; } k += nchan; } m += nchan*lksmps; } } } unsigned long kperfThread(void * cs) { //INSDS *start; CSOUND *csound = (CSOUND *)cs; void *threadId; int index; int numThreads; _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); csound->WaitBarrier(csound->barrier2); threadId = csound->GetCurrentThreadID(); index = getThreadIndex(csound, threadId); numThreads = csound->oparms->numThreads; //start = NULL; csound->Message(csound, Str("Multithread performance:thread %d of " "%d starting.\n"), /* start ? start->insno : */ index+1, numThreads); if (UNLIKELY(index < 0)) { csound->Die(csound, Str("Bad ThreadId")); return ULONG_MAX; } index++; while (1) { csound->WaitBarrier(csound->barrier1); // FIXME:PTHREAD_WORK - need to check if this is necessary and, if so, // use some other kind of locking mechanism as it isn't clear why a //global mutex would be necessary versus a per-CSOUND instance mutex /*csound_global_mutex_lock();*/ if (csound->multiThreadedComplete == 1) { /*csound_global_mutex_unlock();*/ free(threadId); return 0UL; } /*csound_global_mutex_unlock();*/ nodePerf(csound, index, numThreads); csound->WaitBarrier(csound->barrier2); } } int kperf_nodebug(CSOUND *csound) { INSDS *ip; int lksmps = csound->ksmps; /* update orchestra time */ csound->kcounter = ++(csound->global_kcounter); csound->icurTime += csound->ksmps; csound->curBeat += csound->curBeat_inc; /* call message_dequeue to run API calls */ message_dequeue(csound); /* if skipping time on request by 'a' score statement: */ if (UNLIKELY(UNLIKELY(csound->advanceCnt))) { csound->advanceCnt--; return 1; } /* if i-time only, return now */ if (UNLIKELY(csound->initonly)) return 1; /* PC GUI needs attention, but avoid excessively frequent */ /* calls of csoundYield() */ if (UNLIKELY(--(csound->evt_poll_cnt) < 0)) { csound->evt_poll_cnt = csound->evt_poll_maxcnt; if (UNLIKELY(!csoundYield(csound))) csound->LongJmp(csound, 1); } /* for one kcnt: */ if (csound->oparms_.sfread) /* if audio_infile open */ csound->spinrecv(csound); /* fill the spin buf */ csound->spoutactive = 0; /* make spout inactive */ /* clear spout */ memset(csound->spout, 0, csound->nspout*sizeof(MYFLT)); memset(csound->spraw, 0, csound->nspout*sizeof(MYFLT)); ip = csound->actanchor.nxtact; if (ip != NULL) { /* There are 2 partitions of work: 1st by inso, 2nd by inso count / thread count. */ if (csound->multiThreadedThreadInfo != NULL) { if (csound->dag_changed) dag_build(csound, ip); else dag_reinit(csound); /* set to initial state */ /* process this partition */ csound->WaitBarrier(csound->barrier1); (void) nodePerf(csound, 0, 1); /* wait until partition is complete */ csound->WaitBarrier(csound->barrier2); csound->multiThreadedDag = NULL; } else { int done; double time_end = (csound->ksmps+csound->icurTime)/csound->esr; while (ip != NULL) { /* for each instr active: */ INSDS *nxt = ip->nxtact; if (UNLIKELY(csound->oparms->sampleAccurate && ip->offtim > 0 && time_end > ip->offtim)) { /* this is the last cycle of performance */ // csound->Message(csound, "last cycle %d: %f %f %d\n", // ip->insno, csound->icurTime/csound->esr, // ip->offtim, ip->no_end); ip->ksmps_no_end = ip->no_end; } done = ATOMIC_GET(ip->init_done); if (done == 1) {/* if init-pass has been done */ int error = 0; OPDS *opstart = (OPDS*) ip; ip->spin = csound->spin; ip->spout = csound->spraw; ip->kcounter = csound->kcounter; if (ip->ksmps == csound->ksmps) { csound->mode = 2; while (error == 0 && (opstart = opstart->nxtp) != NULL && ip->actflg) { opstart->insdshead->pds = opstart; csound->op = opstart->optext->t.opcod; error = (*opstart->opadr)(csound, opstart); /* run each opcode */ opstart = opstart->insdshead->pds; } csound->mode = 0; } else { int error = 0; int i, n = csound->nspout, start = 0; lksmps = ip->ksmps; int incr = csound->nchnls*lksmps; int offset = ip->ksmps_offset; int early = ip->ksmps_no_end; OPDS *opstart; ip->spin = csound->spin; ip->spout = csound->spraw; ip->kcounter = csound->kcounter*csound->ksmps/lksmps; /* we have to deal with sample-accurate code whole CS_KSMPS blocks are offset here, the remainder is left to each opcode to deal with. */ while (offset >= lksmps) { offset -= lksmps; start += csound->nchnls; } ip->ksmps_offset = offset; if (UNLIKELY(early)) { n -= (early*csound->nchnls); ip->ksmps_no_end = early % lksmps; } for (i=start; i < n; i+=incr, ip->spin+=incr, ip->spout+=incr) { opstart = (OPDS*) ip; csound->mode = 2; while (error == 0 && (opstart = opstart->nxtp) != NULL && ip->actflg) { opstart->insdshead->pds = opstart; csound->op = opstart->optext->t.opcod; //csound->ids->optext->t.oentry->opname; error = (*opstart->opadr)(csound, opstart); /* run each opcode */ opstart = opstart->insdshead->pds; } csound->mode = 0; ip->kcounter++; } } } /*else csound->Message(csound, "time %f\n", csound->kcounter/csound->ekr);*/ ip->ksmps_offset = 0; /* reset sample-accuracy offset */ ip->ksmps_no_end = 0; /* reset end of loop samples */ ip = nxt; /* but this does not allow for all deletions */ } } } if (!csound->spoutactive) { /* results now in spout? */ memset(csound->spout, 0, csound->nspout * sizeof(MYFLT)); memset(csound->spraw, 0, csound->nspout * sizeof(MYFLT)); } make_interleave(csound, lksmps); csound->spoutran(csound); /* send to audio_out */ //#ifdef ANDROID //struct timespec ts; //clock_gettime(CLOCK_MONOTONIC, &ts); //csound->Message(csound, "kperf kcount, %d,%d.%06d\n", // csound->kcounter, ts.tv_sec, ts.tv_nsec/1000); //#endif return 0; } static inline void opcode_perf_debug(CSOUND *csound, csdebug_data_t *data, INSDS *ip) { OPDS *opstart = (OPDS*) ip; while ((opstart = opstart->nxtp) != NULL) { /* check if we have arrived at a line breakpoint */ bkpt_node_t *bp_node = data->bkpt_anchor->next; if (data->debug_opcode_ptr) { opstart = data->debug_opcode_ptr; data->debug_opcode_ptr = NULL; } int linenum = opstart->optext->t.linenum; while (bp_node) { if (bp_node->instr == ip->p1.value || (bp_node->instr == 0)) { if ((bp_node->line) == linenum) { /* line matches */ if (bp_node->count < 2) { /* skip of 0 or 1 has the same effect */ if (data->debug_opcode_ptr != opstart) { /* did we just stop here */ data->debug_instr_ptr = ip; data->debug_opcode_ptr = opstart; data->status = CSDEBUG_STATUS_STOPPED; data->cur_bkpt = bp_node; csoundDebuggerBreakpointReached(csound); bp_node->count = bp_node->skip; return; } else { data->debug_opcode_ptr = NULL; /* if just stopped here-continue */ } } else { bp_node->count--; } } } bp_node = bp_node->next; } opstart->insdshead->pds = opstart; csound->mode = 2; (*opstart->opadr)(csound, opstart); /* run each opcode */ opstart = opstart->insdshead->pds; csound->mode = 0; } } static inline void process_debug_buffers(CSOUND *csound, csdebug_data_t *data) { bkpt_node_t *bkpt_node; while (csoundReadCircularBuffer(csound, data->bkpt_buffer, &bkpt_node, 1) == 1) { if (bkpt_node->mode == CSDEBUG_BKPT_CLEAR_ALL) { bkpt_node_t *n; while (data->bkpt_anchor->next) { n = data->bkpt_anchor->next; data->bkpt_anchor->next = n->next; csound->Free(csound, n); /* TODO this should be moved from kperf to a non-realtime context */ } csound->Free(csound, bkpt_node); } else if (bkpt_node->mode == CSDEBUG_BKPT_DELETE) { bkpt_node_t *n = data->bkpt_anchor->next; bkpt_node_t *prev = data->bkpt_anchor; while (n) { if (n->line == bkpt_node->line && n->instr == bkpt_node->instr) { prev->next = n->next; if (data->cur_bkpt == n) data->cur_bkpt = n->next; csound->Free(csound, n); /* TODO this should be moved from kperf to a non-realtime context */ n = prev->next; continue; } prev = n; n = n->next; } // csound->Free(csound, bkpt_node); /* TODO move to non rt context */ } else { // FIXME sort list to optimize bkpt_node->next = data->bkpt_anchor->next; data->bkpt_anchor->next = bkpt_node; } } } int kperf_debug(CSOUND *csound) { INSDS *ip; csdebug_data_t *data = (csdebug_data_t *) csound->csdebug_data; int lksmps = csound->ksmps; /* call message_dequeue to run API calls */ message_dequeue(csound); if (!data || data->status != CSDEBUG_STATUS_STOPPED) { /* update orchestra time */ csound->kcounter = ++(csound->global_kcounter); csound->icurTime += csound->ksmps; csound->curBeat += csound->curBeat_inc; } /* if skipping time on request by 'a' score statement: */ if (UNLIKELY(csound->advanceCnt)) { csound->advanceCnt--; return 1; } /* if i-time only, return now */ if (UNLIKELY(csound->initonly)) return 1; /* PC GUI needs attention, but avoid excessively frequent */ /* calls of csoundYield() */ if (UNLIKELY(--(csound->evt_poll_cnt) < 0)) { csound->evt_poll_cnt = csound->evt_poll_maxcnt; if (UNLIKELY(!csoundYield(csound))) csound->LongJmp(csound, 1); } if (data) { /* process debug commands*/ process_debug_buffers(csound, data); } if (!data || data->status == CSDEBUG_STATUS_RUNNING) { /* for one kcnt: */ if (csound->oparms_.sfread) /* if audio_infile open */ csound->spinrecv(csound); /* fill the spin buf */ csound->spoutactive = 0; /* make spout inactive */ /* clear spout */ memset(csound->spout, 0, csound->nspout*sizeof(MYFLT)); memset(csound->spraw, 0, csound->nspout*sizeof(MYFLT)); } ip = csound->actanchor.nxtact; /* Process debugger commands */ debug_command_t command = CSDEBUG_CMD_NONE; if (data) { csoundReadCircularBuffer(csound, data->cmd_buffer, &command, 1); if (command == CSDEBUG_CMD_STOP && data->status != CSDEBUG_STATUS_STOPPED) { data->debug_instr_ptr = ip; data->status = CSDEBUG_STATUS_STOPPED; csoundDebuggerBreakpointReached(csound); } if (command == CSDEBUG_CMD_CONTINUE && data->status == CSDEBUG_STATUS_STOPPED) { if (data->cur_bkpt && data->cur_bkpt->skip <= 2) data->cur_bkpt->count = 2; data->status = CSDEBUG_STATUS_RUNNING; if (data->debug_instr_ptr) { /* if not NULL, resume from last active */ ip = data->debug_instr_ptr; data->debug_instr_ptr = NULL; } } if (command == CSDEBUG_CMD_NEXT && data->status == CSDEBUG_STATUS_STOPPED) { data->status = CSDEBUG_STATUS_NEXT; } } if (ip != NULL && data != NULL && (data->status != CSDEBUG_STATUS_STOPPED) ) { /* There are 2 partitions of work: 1st by inso, 2nd by inso count / thread count. */ if (csound->multiThreadedThreadInfo != NULL) { if (csound->dag_changed) dag_build(csound, ip); else dag_reinit(csound); /* set to initial state */ /* process this partition */ csound->WaitBarrier(csound->barrier1); (void) nodePerf(csound, 0, 1); /* wait until partition is complete */ csound->WaitBarrier(csound->barrier2); csound->multiThreadedDag = NULL; } else { int done; double time_end = (csound->ksmps+csound->icurTime)/csound->esr; while (ip != NULL) { /* for each instr active: */ if (UNLIKELY(csound->oparms->sampleAccurate && ip->offtim > 0 && time_end > ip->offtim)) { /* this is the last cycle of performance */ // csound->Message(csound, "last cycle %d: %f %f %d\n", // ip->insno, csound->icurTime/csound->esr, // ip->offtim, ip->no_end); ip->ksmps_no_end = ip->no_end; } done = ATOMIC_GET(ip->init_done); if (done == 1) {/* if init-pass has been done */ /* check if next command pending and we are on the first instrument in the chain */ /* coverity says data already dereferenced by here */ if (/*data &&*/ data->status == CSDEBUG_STATUS_NEXT) { if (data->debug_instr_ptr == NULL) { data->debug_instr_ptr = ip; data->debug_opcode_ptr = NULL; data->status = CSDEBUG_STATUS_STOPPED; csoundDebuggerBreakpointReached(csound); return 0; } else { ip = data->debug_instr_ptr; data->debug_instr_ptr = NULL; } } /* check if we have arrived at an instrument breakpoint */ bkpt_node_t *bp_node = data->bkpt_anchor->next; while (bp_node && data->status != CSDEBUG_STATUS_NEXT) { if (bp_node->instr == ip->p1.value && (bp_node->line == -1) ) { if (bp_node->count < 2) { /* skip of 0 or 1 has the same effect */ data->debug_instr_ptr = ip; data->debug_opcode_ptr = NULL; data->cur_bkpt = bp_node; data->status = CSDEBUG_STATUS_STOPPED; csoundDebuggerBreakpointReached(csound); bp_node->count = bp_node->skip; return 0; } else { bp_node->count--; } } bp_node = bp_node->next; } ip->spin = csound->spin; ip->spout = csound->spraw; ip->kcounter = csound->kcounter; if (ip->ksmps == csound->ksmps) { opcode_perf_debug(csound, data, ip); } else { /* when instrument has local ksmps */ int i, n = csound->nspout, start = 0; lksmps = ip->ksmps; int incr = csound->nchnls*lksmps; int offset = ip->ksmps_offset; int early = ip->ksmps_no_end; ip->spin = csound->spin; ip->spout = csound->spraw; ip->kcounter = csound->kcounter*csound->ksmps/lksmps; /* we have to deal with sample-accurate code whole CS_KSMPS blocks are offset here, the remainder is left to each opcode to deal with. */ while (offset >= lksmps) { offset -= lksmps; start += csound->nchnls; } ip->ksmps_offset = offset; if (UNLIKELY(early)) { n -= (early*csound->nchnls); ip->ksmps_no_end = early % lksmps; } for (i=start; i < n; i+=incr, ip->spin+=incr, ip->spout+=incr) { opcode_perf_debug(csound, data, ip); ip->kcounter++; } } } ip->ksmps_offset = 0; /* reset sample-accuracy offset */ ip->ksmps_no_end = 0; /* reset end of loop samples */ ip = ip->nxtact; /* but this does not allow for all deletions */ if (/*data &&*/ data->status == CSDEBUG_STATUS_NEXT) { data->debug_instr_ptr = ip; /* we have reached the next instrument. Break */ data->debug_opcode_ptr = NULL; if (ip != NULL) { /* must defer break until next kperf */ data->status = CSDEBUG_STATUS_STOPPED; csoundDebuggerBreakpointReached(csound); return 0; } } } } } if (!data || data->status != CSDEBUG_STATUS_STOPPED) { if (!csound->spoutactive) { /* results now in spout? */ memset(csound->spout, 0, csound->nspout * sizeof(MYFLT)); memset(csound->spraw, 0, csound->nspout * sizeof(MYFLT)); } else make_interleave(csound, lksmps); csound->spoutran(csound); /* send to audio_out */ } return 0; } int csoundReadScoreInternal(CSOUND *csound, const char *str) { OPARMS *O = csound->oparms; /* protect resource */ if (csound->scorestr != NULL && csound->scorestr->body != NULL) corfile_rewind(csound->scorestr); csound->scorestr = corfile_create_w(csound); corfile_puts(csound, (char *)str, csound->scorestr); //#ifdef SCORE_PARSER if (csound->engineStatus&CS_STATE_COMP) corfile_puts(csound, "\n#exit\n", csound->scorestr); else corfile_puts(csound, "\ne\n#exit\n", csound->scorestr); //#endif corfile_flush(csound, csound->scorestr); /* copy sorted score name */ if (csound->scstr == NULL && (csound->engineStatus & CS_STATE_COMP) == 0) { scsortstr(csound, csound->scorestr); O->playscore = csound->scstr; //corfile_rm(csound, &(csound->scorestr)); //printf("%s\n", O->playscore->body); } else { char *sc = scsortstr(csound, csound->scorestr); //printf("%s\n", sc); csoundInputMessageInternal(csound, (const char *) sc); csound->Free(csound, sc); corfile_rm(csound, &(csound->scorestr)); } return CSOUND_SUCCESS; } PUBLIC int csoundPerformKsmps(CSOUND *csound) { int done; /* VL: 1.1.13 if not compiled (csoundStart() not called) */ if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) { csound->Warning(csound, Str("Csound not ready for performance: csoundStart() " "has not been called\n")); return CSOUND_ERROR; } if (csound->jumpset == 0) { int returnValue; csound->jumpset = 1; /* setup jmp for return after an exit() */ if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS); } if(!csound->oparms->realtime) // no API lock in realtime mode csoundLockMutex(csound->API_lock); do { done = sensevents(csound); if (UNLIKELY(done)) { if(!csound->oparms->realtime) // no API lock in realtime mode csoundUnlockMutex(csound->API_lock); csoundMessage(csound, Str("Score finished in csoundPerformKsmps() with %d.\n"), done); return done; } } while (csound->kperf(csound)); if(!csound->oparms->realtime) // no API lock in realtime mode csoundUnlockMutex(csound->API_lock); return 0; } static int csoundPerformKsmpsInternal(CSOUND *csound) { int done; int returnValue; /* VL: 1.1.13 if not compiled (csoundStart() not called) */ if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) { csound->Warning(csound, Str("Csound not ready for performance: csoundStart() " "has not been called\n")); return CSOUND_ERROR; } /* setup jmp for return after an exit() */ if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) { #ifndef MACOSX csoundMessage(csound, Str("Early return from csoundPerformKsmps().\n")); #endif return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS); } do { if (UNLIKELY((done = sensevents(csound)))) { csoundMessage(csound, Str("Score finished in csoundPerformKsmpsInternal().\n")); return done; } } while (csound->kperf(csound)); return 0; } /* external host's outbuffer passed in csoundPerformBuffer() */ PUBLIC int csoundPerformBuffer(CSOUND *csound) { int returnValue; int done; /* VL: 1.1.13 if not compiled (csoundStart() not called) */ if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) { csound->Warning(csound, Str("Csound not ready for performance: csoundStart() " "has not been called\n")); return CSOUND_ERROR; } /* Setup jmp for return after an exit(). */ if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) { #ifndef MACOSX csoundMessage(csound, Str("Early return from csoundPerformBuffer().\n")); #endif return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS); } csound->sampsNeeded += csound->oparms_.outbufsamps; while (csound->sampsNeeded > 0) { if(!csound->oparms->realtime) {// no API lock in realtime mode csoundLockMutex(csound->API_lock); } do { if (UNLIKELY((done = sensevents(csound)))){ if(!csound->oparms->realtime) // no API lock in realtime mode csoundUnlockMutex(csound->API_lock); return done; } } while (csound->kperf(csound)); if(!csound->oparms->realtime) { // no API lock in realtime mode csoundUnlockMutex(csound->API_lock); } csound->sampsNeeded -= csound->nspout; } return 0; } /* perform an entire score */ PUBLIC int csoundPerform(CSOUND *csound) { int done; int returnValue; /* VL: 1.1.13 if not compiled (csoundStart() not called) */ if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) { csound->Warning(csound, Str("Csound not ready for performance: csoundStart() " "has not been called\n")); return CSOUND_ERROR; } csound->performState = 0; /* setup jmp for return after an exit() */ if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) { #ifndef MACOSX csoundMessage(csound, Str("Early return from csoundPerform().\n")); #endif return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS); } do { if(!csound->oparms->realtime) csoundLockMutex(csound->API_lock); do { if (UNLIKELY((done = sensevents(csound)))) { csoundMessage(csound, Str("Score finished in csoundPerform().\n")); if(!csound->oparms->realtime) csoundUnlockMutex(csound->API_lock); if (csound->oparms->numThreads > 1) { csound->multiThreadedComplete = 1; csound->WaitBarrier(csound->barrier1); } return done; } } while (csound->kperf(csound)); if(!csound->oparms->realtime) csoundUnlockMutex(csound->API_lock); } while ((unsigned char) csound->performState == (unsigned char) '\0'); csoundMessage(csound, Str("csoundPerform(): stopped.\n")); csound->performState = 0; return 0; } /* stop a csoundPerform() running in another thread */ PUBLIC void *csoundGetNamedGens(CSOUND *csound) { return csound->namedgen; } PUBLIC void csoundStop(CSOUND *csound) { csound->performState = -1; } /* * ATTRIBUTES */ PUBLIC int64_t csoundGetCurrentTimeSamples(CSOUND *csound){ return csound->icurTime; } PUBLIC MYFLT csoundGetSr(CSOUND *csound) { return csound->esr; } PUBLIC MYFLT csoundGetKr(CSOUND *csound) { return csound->ekr; } PUBLIC uint32_t csoundGetKsmps(CSOUND *csound) { return csound->ksmps; } PUBLIC uint32_t csoundGetNchnls(CSOUND *csound) { return csound->nchnls; } PUBLIC uint32_t csoundGetNchnlsInput(CSOUND *csound) { if (csound->inchnls >= 0) return (uint32_t) csound->inchnls; else return csound->nchnls; } PUBLIC MYFLT csoundGet0dBFS(CSOUND *csound) { return csound->e0dbfs; } PUBLIC long csoundGetInputBufferSize(CSOUND *csound) { return csound->oparms_.inbufsamps; } PUBLIC long csoundGetOutputBufferSize(CSOUND *csound) { return csound->oparms_.outbufsamps; } PUBLIC MYFLT *csoundGetSpin(CSOUND *csound) { return csound->spin; } PUBLIC void csoundSetSpinSample(CSOUND *csound, int frame, int channel, MYFLT sample) { int index = (frame * csound->inchnls) + channel; csound->spin[index] = sample; } PUBLIC void csoundClearSpin(CSOUND *csound) { memset(csound->spin, 0, sizeof(MYFLT)*csound->ksmps*csound->nchnls); } PUBLIC void csoundAddSpinSample(CSOUND *csound, int frame, int channel, MYFLT sample) { int index = (frame * csound->inchnls) + channel; csound->spin[index] += sample; } PUBLIC MYFLT *csoundGetSpout(CSOUND *csound) { return csound->spout; } PUBLIC MYFLT csoundGetSpoutSample(CSOUND *csound, int frame, int channel) { int index = (frame * csound->nchnls) + channel; return csound->spout[index]; } PUBLIC const char *csoundGetOutputName(CSOUND *csound) { return (const char*) csound->oparms_.outfilename; } PUBLIC const char *csoundGetInputName(CSOUND *csound) { return (const char*) csound->oparms_.infilename; } /** * Calling this function with a non-zero will disable all default * handling of sound I/O by the Csound library, allowing the host * application to use the spin/enableHostImplementedAudioIO = state; csound->hostRequestedBufferSize = (bufSize > 0 ? bufSize : 0); } PUBLIC void csoundSetHostImplementedMIDIIO(CSOUND *csound, int state) { csound->enableHostImplementedMIDIIO = state; } PUBLIC double csoundGetScoreTime(CSOUND *csound) { double curtime = csound->icurTime; double esr = csound->esr; return curtime/esr; } /* * SCORE HANDLING */ PUBLIC int csoundIsScorePending(CSOUND *csound) { return csound->csoundIsScorePending_; } PUBLIC void csoundSetScorePending(CSOUND *csound, int pending) { csound->csoundIsScorePending_ = pending; } PUBLIC void csoundSetScoreOffsetSeconds(CSOUND *csound, MYFLT offset) { double aTime; MYFLT prv = (MYFLT) csound->csoundScoreOffsetSeconds_; csound->csoundScoreOffsetSeconds_ = offset; if (offset < FL(0.0)) return; /* if csoundCompile() was not called yet, just store the offset */ if (!(csound->engineStatus & CS_STATE_COMP)) return; /* otherwise seek to the requested time now */ aTime = (double) offset - (csound->icurTime/csound->esr); if (aTime < 0.0 || offset < prv) { csoundRewindScore(csound); /* will call csoundSetScoreOffsetSeconds */ return; } if (aTime > 0.0) { EVTBLK evt; memset(&evt, 0, sizeof(EVTBLK)); evt.strarg = NULL; evt.scnt = 0; evt.opcod = 'a'; evt.pcnt = 3; evt.p[2] = evt.p[1] = FL(0.0); evt.p[3] = (MYFLT) aTime; insert_score_event_at_sample(csound, &evt, csound->icurTime); } } PUBLIC MYFLT csoundGetScoreOffsetSeconds(CSOUND *csound) { return csound->csoundScoreOffsetSeconds_; } extern void musmon_rewind_score(CSOUND *csound); /* musmon.c */ extern void midifile_rewind_score(CSOUND *csound); /* midifile.c */ PUBLIC void csoundRewindScore(CSOUND *csound) { musmon_rewind_score(csound); if (csound->oparms->FMidiname != NULL) midifile_rewind_score(csound); } PUBLIC void csoundSetCscoreCallback(CSOUND *p, void (*cscoreCallback)(CSOUND *)) { p->cscoreCallback_ = (cscoreCallback != NULL ? cscoreCallback : cscore_); } static void csoundDefaultMessageCallback(CSOUND *csound, int attr, const char *format, va_list args) { #if defined(WIN32) switch (attr & CSOUNDMSG_TYPE_MASK) { case CSOUNDMSG_ERROR: case CSOUNDMSG_WARNING: case CSOUNDMSG_REALTIME: vfprintf(stderr, format, args); break; default: vfprintf(stdout, format, args); } #else FILE *fp = stderr; if ((attr & CSOUNDMSG_TYPE_MASK) == CSOUNDMSG_STDOUT) fp = stdout; if (!attr || !csound->enableMsgAttr) { vfprintf(fp, format, args); return; } if ((attr & CSOUNDMSG_TYPE_MASK) == CSOUNDMSG_ORCH) if (attr & CSOUNDMSG_BG_COLOR_MASK) fprintf(fp, "\033[4%cm", ((attr & 0x70) >> 4) + '0'); if (attr & CSOUNDMSG_FG_ATTR_MASK) { if (attr & CSOUNDMSG_FG_BOLD) fprintf(fp, "\033[1m"); if (attr & CSOUNDMSG_FG_UNDERLINE) fprintf(fp, "\033[4m"); } if (attr & CSOUNDMSG_FG_COLOR_MASK) fprintf(fp, "\033[3%cm", (attr & 7) + '0'); vfprintf(fp, format, args); fprintf(fp, "\033[m"); #endif } PUBLIC void csoundSetDefaultMessageCallback( void (*csoundMessageCallback)(CSOUND *csound, int attr, const char *format, va_list args)) { if (csoundMessageCallback) { msgcallback_ = csoundMessageCallback; } else { msgcallback_ = csoundDefaultMessageCallback; } } PUBLIC void csoundSetMessageStringCallback(CSOUND *csound, void (*csoundMessageStrCallback)(CSOUND *csound, int attr, const char *str)) { if (csoundMessageStrCallback) { if(csound->message_string == NULL) csound->message_string = (char *) csound->Calloc(csound, MAX_MESSAGE_STR); csound->csoundMessageStringCallback = csoundMessageStrCallback; csound->csoundMessageCallback_ = NULL; } } PUBLIC void csoundSetMessageCallback(CSOUND *csound, void (*csoundMessageCallback)(CSOUND *csound, int attr, const char *format, va_list args)) { /* Protect against a null callback. */ if (csoundMessageCallback) { csound->csoundMessageCallback_ = csoundMessageCallback; } else { csound->csoundMessageCallback_ = csoundDefaultMessageCallback; } } PUBLIC void csoundMessageV(CSOUND *csound, int attr, const char *format, va_list args) { if(csound->csoundMessageCallback_) { csound->csoundMessageCallback_(csound, attr, format, args); } else { vsnprintf(csound->message_string, MAX_MESSAGE_STR, format, args); csound->csoundMessageStringCallback(csound, attr, csound->message_string); } } PUBLIC void csoundMessage(CSOUND *csound, const char *format, ...) { va_list args; va_start(args, format); if(csound->csoundMessageCallback_) csound->csoundMessageCallback_(csound, 0, format, args); else { vsnprintf(csound->message_string, MAX_MESSAGE_STR, format, args); csound->csoundMessageStringCallback(csound, 0, csound->message_string); } va_end(args); } PUBLIC void csoundMessageS(CSOUND *csound, int attr, const char *format, ...) { va_list args; va_start(args, format); if(csound->csoundMessageCallback_) csound->csoundMessageCallback_(csound, attr, format, args); else { vsnprintf(csound->message_string, MAX_MESSAGE_STR, format, args); csound->csoundMessageStringCallback(csound, attr, csound->message_string); } va_end(args); } void csoundDie(CSOUND *csound, const char *msg, ...) { va_list args; va_start(args, msg); csound->ErrMsgV(csound, (char*) 0, msg, args); va_end(args); csound->perferrcnt++; csound->LongJmp(csound, 1); } void csoundWarning(CSOUND *csound, const char *msg, ...) { va_list args; if (!(csound->oparms_.msglevel & WARNMSG)) return; csoundMessageS(csound, CSOUNDMSG_WARNING, Str("WARNING: ")); va_start(args, msg); csoundMessageV(csound, CSOUNDMSG_WARNING, msg, args); va_end(args); csoundMessageS(csound, CSOUNDMSG_WARNING, "\n"); } void csoundDebugMsg(CSOUND *csound, const char *msg, ...) { va_list args; if (!(csound->oparms_.odebug)) return; va_start(args, msg); csoundMessageV(csound, 0, msg, args); va_end(args); csoundMessage(csound, "\n"); } void csoundErrorMsg(CSOUND *csound, const char *msg, ...) { va_list args; va_start(args, msg); csoundMessageV(csound, CSOUNDMSG_ERROR, msg, args); va_end(args); csound->MessageS(csound, CSOUNDMSG_ERROR, "\n"); } void csoundErrMsgV(CSOUND *csound, const char *hdr, const char *msg, va_list args) { if (hdr != NULL) csound->MessageS(csound, CSOUNDMSG_ERROR, "%s", hdr); csoundMessageV(csound, CSOUNDMSG_ERROR, msg, args); csound->MessageS(csound, CSOUNDMSG_ERROR, "\n"); } void csoundLongJmp(CSOUND *csound, int retval) { int n = CSOUND_EXITJMP_SUCCESS; n = (retval < 0 ? n + retval : n - retval) & (CSOUND_EXITJMP_SUCCESS - 1); //printf("**** n = %d\n", n); if (!n) n = CSOUND_EXITJMP_SUCCESS; csound->curip = NULL; csound->ids = NULL; csound->reinitflag = 0; csound->tieflag = 0; csound->perferrcnt += csound->inerrcnt; csound->inerrcnt = 0; csound->engineStatus |= CS_STATE_JMP; //printf("**** longjmp with %d\n", n); longjmp(csound->exitjmp, n); } PUBLIC void csoundSetMessageLevel(CSOUND *csound, int messageLevel) { csound->oparms_.msglevel = messageLevel; } PUBLIC int csoundGetMessageLevel(CSOUND *csound) { return csound->oparms_.msglevel; } PUBLIC void csoundKeyPress(CSOUND *csound, char c) { csound->inChar_ = (int) ((unsigned char) c); } /* * CONTROL AND EVENTS */ PUBLIC void csoundSetInputChannelCallback(CSOUND *csound, channelCallback_t inputChannelCalback) { csound->InputChannelCallback_ = inputChannelCalback; } PUBLIC void csoundSetOutputChannelCallback(CSOUND *csound, channelCallback_t outputChannelCalback) { csound->OutputChannelCallback_ = outputChannelCalback; } int csoundScoreEventInternal(CSOUND *csound, char type, const MYFLT *pfields, long numFields) { EVTBLK evt; int i; int ret; memset(&evt, 0, sizeof(EVTBLK)); evt.strarg = NULL; evt.scnt = 0; evt.opcod = type; evt.pcnt = (int16) numFields; for (i = 0; i < (int) numFields; i++) evt.p[i + 1] = pfields[i]; ret = insert_score_event_at_sample(csound, &evt, csound->icurTime); return ret; } int csoundScoreEventAbsoluteInternal(CSOUND *csound, char type, const MYFLT *pfields, long numFields, double time_ofs) { EVTBLK evt; int i; int ret; memset(&evt, 0, sizeof(EVTBLK)); evt.strarg = NULL; evt.scnt = 0; evt.opcod = type; evt.pcnt = (int16) numFields; for (i = 0; i < (int) numFields; i++) evt.p[i + 1] = pfields[i]; ret = insert_score_event(csound, &evt, time_ofs); return ret; } /* * REAL-TIME AUDIO */ /* dummy functions for the case when no real-time audio module is available */ static double *get_dummy_rtaudio_globals(CSOUND *csound) { double *p; p = (double*) csound->QueryGlobalVariable(csound, "__rtaudio_null_state"); if (p == NULL) { if (UNLIKELY(csound->CreateGlobalVariable(csound, "__rtaudio_null_state", sizeof(double) * 4) != 0)) csound->Die(csound, Str("rtdummy: failed to allocate globals")); csound->Message(csound, Str("rtaudio: dummy module enabled\n")); p = (double*) csound->QueryGlobalVariable(csound, "__rtaudio_null_state"); } return p; } static void dummy_rtaudio_timer(CSOUND *csound, double *p) { double timeWait; int i; timeWait = p[0] - csoundGetRealTime(csound->csRtClock); i = (int) (timeWait * 1000.0 + 0.5); if (i > 0) csoundSleep((size_t) i); } int playopen_dummy(CSOUND *csound, const csRtAudioParams *parm) { double *p; char *s; /* find out if the use of dummy real-time audio functions was requested, */ /* or an unknown plugin name was specified; the latter case is an error */ s = (char*) csoundQueryGlobalVariable(csound, "_RTAUDIO"); if (s != NULL && !(strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 || strcmp(s, "NULL") == 0)) { if (s[0] == '\0') csoundErrorMsg(csound, Str(" *** error: rtaudio module set to empty string")); else { // print_opcodedir_warning(csound); csoundErrorMsg(csound, Str(" unknown rtaudio module: '%s', using dummy module"), s); } // return CSOUND_ERROR; } p = get_dummy_rtaudio_globals(csound); csound->rtPlay_userdata = (void*) p; p[0] = csound->GetRealTime(csound->csRtClock); p[1] = 1.0 / ((double) ((int) sizeof(MYFLT) * parm->nChannels) * (double) parm->sampleRate); return CSOUND_SUCCESS; } void rtplay_dummy(CSOUND *csound, const MYFLT *outBuf, int nbytes) { double *p = (double*) csound->rtPlay_userdata; (void) outBuf; p[0] += ((double) nbytes * p[1]); dummy_rtaudio_timer(csound, p); } int recopen_dummy(CSOUND *csound, const csRtAudioParams *parm) { double *p; char *s; /* find out if the use of dummy real-time audio functions was requested, */ /* or an unknown plugin name was specified; the latter case is an error */ s = (char*) csoundQueryGlobalVariable(csound, "_RTAUDIO"); if (s != NULL && !(strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 || strcmp(s, "NULL") == 0)) { if (s[0] == '\0') csoundErrorMsg(csound, Str(" *** error: rtaudio module set to empty string")); else { // print_opcodedir_warning(csound); csoundErrorMsg(csound, Str(" unknown rtaudio module: '%s', using dummy module"), s); } // return CSOUND_ERROR; } p = (double*) get_dummy_rtaudio_globals(csound) + 2; csound->rtRecord_userdata = (void*) p; p[0] = csound->GetRealTime(csound->csRtClock); p[1] = 1.0 / ((double) ((int) sizeof(MYFLT) * parm->nChannels) * (double) parm->sampleRate); return CSOUND_SUCCESS; } int rtrecord_dummy(CSOUND *csound, MYFLT *inBuf, int nbytes) { double *p = (double*) csound->rtRecord_userdata; /* for (i = 0; i < (nbytes / (int) sizeof(MYFLT)); i++) */ /* ((MYFLT*) inBuf)[i] = FL(0.0); */ memset(inBuf, 0, nbytes); p[0] += ((double) nbytes * p[1]); dummy_rtaudio_timer(csound, p); return nbytes; } void rtclose_dummy(CSOUND *csound) { csound->rtPlay_userdata = NULL; csound->rtRecord_userdata = NULL; } int audio_dev_list_dummy(CSOUND *csound, CS_AUDIODEVICE *list, int isOutput) { IGN(csound); IGN(list); IGN(isOutput); return 0; } int midi_dev_list_dummy(CSOUND *csound, CS_MIDIDEVICE *list, int isOutput){ IGN(csound); IGN(list); IGN(isOutput); return 0; } PUBLIC void csoundSetPlayopenCallback(CSOUND *csound, int (*playopen__)(CSOUND *, const csRtAudioParams *parm)) { csound->playopen_callback = playopen__; } PUBLIC void csoundSetRtplayCallback(CSOUND *csound, void (*rtplay__)(CSOUND *, const MYFLT *outBuf, int nbytes)) { csound->rtplay_callback = rtplay__; } PUBLIC void csoundSetRecopenCallback(CSOUND *csound, int (*recopen__)(CSOUND *, const csRtAudioParams *parm)) { csound->recopen_callback = recopen__; } PUBLIC void csoundSetRtrecordCallback(CSOUND *csound, int (*rtrecord__)(CSOUND *, MYFLT *inBuf, int nbytes)) { csound->rtrecord_callback = rtrecord__; } PUBLIC void csoundSetRtcloseCallback(CSOUND *csound, void (*rtclose__)(CSOUND *)) { csound->rtclose_callback = rtclose__; } PUBLIC void csoundSetAudioDeviceListCallback(CSOUND *csound, int (*audiodevlist__)(CSOUND *, CS_AUDIODEVICE *list, int isOutput)) { csound->audio_dev_list_callback = audiodevlist__; } PUBLIC void csoundSetMIDIDeviceListCallback(CSOUND *csound, int (*mididevlist__)(CSOUND *, CS_MIDIDEVICE *list, int isOutput)) { csound->midi_dev_list_callback = mididevlist__; } PUBLIC int csoundGetAudioDevList(CSOUND *csound, CS_AUDIODEVICE *list, int isOutput){ return csound->audio_dev_list_callback(csound,list,isOutput); } PUBLIC int csoundGetMIDIDevList(CSOUND *csound, CS_MIDIDEVICE *list, int isOutput) { return csound->midi_dev_list_callback(csound,list,isOutput); } /* dummy real time MIDI functions */ int DummyMidiInOpen(CSOUND *csound, void **userData, const char *devName) { char *s; (void) devName; *userData = NULL; s = (char*) csoundQueryGlobalVariable(csound, "_RTMIDI"); if (UNLIKELY(s == NULL || (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 || strcmp(s, "NULL") == 0))) { csoundMessage(csound, Str("!!WARNING: real time midi input disabled, " "using dummy functions\n")); return 0; } if (s[0] == '\0') csoundErrorMsg(csound, Str("error: -+rtmidi set to empty string")); else { print_opcodedir_warning(csound); csoundErrorMsg(csound, Str("error: -+rtmidi='%s': unknown module"), s); } return -1; } int DummyMidiRead(CSOUND *csound, void *userData, unsigned char *buf, int nbytes) { (void) csound; (void) userData; (void) buf; (void) nbytes; return 0; } int DummyMidiOutOpen(CSOUND *csound, void **userData, const char *devName) { char *s; (void) devName; *userData = NULL; s = (char*) csoundQueryGlobalVariable(csound, "_RTMIDI"); if (s == NULL || (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 || strcmp(s, "NULL") == 0)) { csoundMessage(csound, Str("WARNING: real time midi output disabled, " "using dummy functions\n")); return 0; } if (s[0] == '\0') csoundErrorMsg(csound, Str("error: -+rtmidi set to empty string")); else { print_opcodedir_warning(csound); csoundErrorMsg(csound, Str("error: -+rtmidi='%s': unknown module"), s); } return -1; } int DummyMidiWrite(CSOUND *csound, void *userData, const unsigned char *buf, int nbytes) { (void) csound; (void) userData; (void) buf; return nbytes; } static const char *midi_err_msg = Str_noop("Unknown MIDI error"); /** * Returns pointer to a string constant storing an error massage * for error code 'errcode'. */ const char *csoundExternalMidiErrorString(CSOUND *csound, int errcode) { if (csound->midiGlobals->MidiErrorStringCallback == NULL) return midi_err_msg; return (csound->midiGlobals->MidiErrorStringCallback(errcode)); } /* Set real time MIDI function pointers. */ PUBLIC void csoundSetExternalMidiInOpenCallback(CSOUND *csound, int (*func)(CSOUND *, void **, const char *)) { csound->midiGlobals->MidiInOpenCallback = func; } PUBLIC void csoundSetExternalMidiReadCallback(CSOUND *csound, int (*func)(CSOUND *, void *, unsigned char *, int)) { csound->midiGlobals->MidiReadCallback = func; } PUBLIC void csoundSetExternalMidiInCloseCallback(CSOUND *csound, int (*func)(CSOUND *, void *)) { csound->midiGlobals->MidiInCloseCallback = func; } PUBLIC void csoundSetExternalMidiOutOpenCallback(CSOUND *csound, int (*func)(CSOUND *, void **, const char *)) { csound->midiGlobals->MidiOutOpenCallback = func; } PUBLIC void csoundSetExternalMidiWriteCallback(CSOUND *csound, int (*func)(CSOUND *, void *, const unsigned char *, int)) { csound->midiGlobals->MidiWriteCallback = func; } PUBLIC void csoundSetExternalMidiOutCloseCallback(CSOUND *csound, int (*func)(CSOUND *, void *)) { csound->midiGlobals->MidiOutCloseCallback = func; } PUBLIC void csoundSetExternalMidiErrorStringCallback(CSOUND *csound, const char *(*func)(int)) { csound->midiGlobals->MidiErrorStringCallback = func; } /* * FUNCTION TABLE DISPLAY. */ PUBLIC int csoundSetIsGraphable(CSOUND *csound, int isGraphable) { int prv = csound->isGraphable_; csound->isGraphable_ = isGraphable; return prv; } PUBLIC void csoundSetMakeGraphCallback(CSOUND *csound, void (*makeGraphCB)(CSOUND *csound, WINDAT *windat, const char *name)) { csound->csoundMakeGraphCallback_ = makeGraphCB; } PUBLIC void csoundSetDrawGraphCallback(CSOUND *csound, void (*drawGraphCallback)(CSOUND *csound, WINDAT *windat)) { csound->csoundDrawGraphCallback_ = drawGraphCallback; } PUBLIC void csoundSetKillGraphCallback(CSOUND *csound, void (*killGraphCallback)(CSOUND *csound, WINDAT *windat)) { csound->csoundKillGraphCallback_ = killGraphCallback; } PUBLIC void csoundSetExitGraphCallback(CSOUND *csound, int (*exitGraphCallback)(CSOUND *)) { csound->csoundExitGraphCallback_ = exitGraphCallback; } /* * OPCODES */ static CS_NOINLINE int opcode_list_new_oentry(CSOUND *csound, const OENTRY *ep) { CONS_CELL *head; OENTRY *entryCopy; char *shortName; if (UNLIKELY(ep->opname == NULL || csound->opcodes == NULL)) return CSOUND_ERROR; shortName = get_opcode_short_name(csound, ep->opname); head = cs_hash_table_get(csound, csound->opcodes, shortName); entryCopy = csound->Malloc(csound, sizeof(OENTRY)); //printf("%p\n", entryCopy); memcpy(entryCopy, ep, sizeof(OENTRY)); entryCopy->useropinfo = NULL; if (head != NULL) { cs_cons_append(head, cs_cons(csound, entryCopy, NULL)); } else { head = cs_cons(csound, entryCopy, NULL); cs_hash_table_put(csound, csound->opcodes, shortName, head); } if (shortName != ep->opname) { csound->Free(csound, shortName); } return 0; } PUBLIC int 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 *)) { OENTRY tmpEntry; int err; tmpEntry.opname = (char*) opname; tmpEntry.dsblksiz = (uint16) dsblksiz; tmpEntry.flags = (uint16) flags; tmpEntry.thread = (uint8_t) thread; tmpEntry.outypes = (char*) outypes; tmpEntry.intypes = (char*) intypes; tmpEntry.iopadr = iopadr; tmpEntry.kopadr = kopadr; tmpEntry.aopadr = aopadr; err = opcode_list_new_oentry(csound, &tmpEntry); if (UNLIKELY(err)) csoundErrorMsg(csound, Str("Failed to allocate new opcode entry.")); return err; } /** * Appends a list of opcodes implemented by external software to Csound's * internal opcode list. The list should either be terminated with an entry * that has a NULL opname, or the number of entries (> 0) should be specified * in 'n'. Returns zero on success. */ int csoundAppendOpcodes(CSOUND *csound, const OENTRY *opcodeList, int n) { OENTRY *ep = (OENTRY*) opcodeList; int err, retval = 0; if (UNLIKELY(opcodeList == NULL)) return -1; if (UNLIKELY(n <= 0)) n = 0x7FFFFFFF; while (n && ep->opname != NULL) { if (UNLIKELY((err = opcode_list_new_oentry(csound, ep)) != 0)) { csoundErrorMsg(csound, Str("Failed to allocate opcode entry for %s."), ep->opname); retval = err; } n--, ep++; } return retval; } /* * MISC FUNCTIONS */ int defaultCsoundYield(CSOUND *csound) { (void) csound; return 1; } PUBLIC void csoundSetYieldCallback(CSOUND *csound, int (*yieldCallback)(CSOUND *)) { csound->csoundYieldCallback_ = yieldCallback; } void SetInternalYieldCallback(CSOUND *csound, int (*yieldCallback)(CSOUND *)) { csound->csoundInternalYieldCallback_ = yieldCallback; } int csoundYield(CSOUND *csound) { if (exitNow_) csound->LongJmp(csound, CSOUND_SIGNAL); csound->csoundInternalYieldCallback_(csound); return csound->csoundYieldCallback_(csound); } extern void csoundDeleteAllGlobalVariables(CSOUND *csound); typedef struct resetCallback_s { void *userData; int (*func)(CSOUND *, void *); struct resetCallback_s *nxt; } resetCallback_t; static void reset(CSOUND *csound) { CSOUND *saved_env; void *p1, *p2; uintptr_t length; uintptr_t end, start; int n = 0; csoundCleanup(csound); /* call registered reset callbacks */ while (csound->reset_list != NULL) { resetCallback_t *p = (resetCallback_t*) csound->reset_list; p->func(csound, p->userData); csound->reset_list = (void*) p->nxt; free(p); } /* call local destructor routines of external modules */ /* should check return value... */ csoundDestroyModules(csound); /* IV - Feb 01 2005: clean up configuration variables and */ /* named dynamic "global" variables of Csound instance */ csoundDeleteAllConfigurationVariables(csound); csoundDeleteAllGlobalVariables(csound); #ifdef CSCORE cscoreRESET(csound); #endif if (csound->opcodes != NULL) { free_opcode_table(csound); csound->opcodes = NULL; } csound->oparms_.odebug = 0; /* RWD 9:2000 not terribly vital, but good to do this somewhere... */ pvsys_release(csound); close_all_files(csound); /* delete temporary files created by this Csound instance */ remove_tmpfiles(csound); rlsmemfiles(csound); while (csound->filedir[n]) /* Clear source directory */ csound->Free(csound,csound->filedir[n++]); memRESET(csound); /** * Copy everything EXCEPT the function pointers. * We do it by saving them and copying them back again... * hope that this does not fail... */ /* VL 07.06.2013 - check if the status is COMP before resetting. */ //CSOUND **self = csound->self; saved_env = (CSOUND*) malloc(sizeof(CSOUND)); memcpy(saved_env, csound, sizeof(CSOUND)); memcpy(csound, &cenviron_, sizeof(CSOUND)); end = (uintptr_t) &(csound->first_callback_); /* used to be &(csound->ids) */ start =(uintptr_t) csound; length = end - start; memcpy((void*) csound, (void*) saved_env, (size_t) length); csound->oparms = &(csound->oparms_); csound->hostdata = saved_env->hostdata; p1 = (void*) &(csound->first_callback_); p2 = (void*) &(csound->last_callback_); length = (uintptr_t) p2 - (uintptr_t) p1; memcpy(p1, (void*) &(saved_env->first_callback_), (size_t) length); csound->csoundCallbacks_ = saved_env->csoundCallbacks_; csound->API_lock = saved_env->API_lock; #ifdef HAVE_PTHREAD_SPIN_LOCK csound->memlock = saved_env->memlock; csound->spinlock = saved_env->spinlock; csound->spoutlock = saved_env->spoutlock; csound->spinlock1= saved_env->spinlock1; #endif csound->enableHostImplementedMIDIIO = saved_env->enableHostImplementedMIDIIO; memcpy(&(csound->exitjmp), &(saved_env->exitjmp), sizeof(jmp_buf)); csound->memalloc_db = saved_env->memalloc_db; //csound->self = self; free(saved_env); } PUBLIC void csoundSetRTAudioModule(CSOUND *csound, const char *module){ char *s; if ((s = csoundQueryGlobalVariable(csound, "_RTAUDIO")) != NULL) strNcpy(s, module, 20); if (UNLIKELY(s==NULL)) return; /* Should not happen */ if (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 || strcmp(s, "NULL") == 0) { csound->Message(csound, Str("setting dummy interface\n")); csound->SetPlayopenCallback(csound, playopen_dummy); csound->SetRecopenCallback(csound, recopen_dummy); csound->SetRtplayCallback(csound, rtplay_dummy); csound->SetRtrecordCallback(csound, rtrecord_dummy); csound->SetRtcloseCallback(csound, rtclose_dummy); csound->SetAudioDeviceListCallback(csound, audio_dev_list_dummy); return; } if (csoundInitModules(csound) != 0) csound->LongJmp(csound, 1); } PUBLIC void csoundSetMIDIModule(CSOUND *csound, const char *module){ char *s; if ((s = csoundQueryGlobalVariable(csound, "_RTMIDI")) != NULL) strNcpy(s, module, 20); if (UNLIKELY(s==NULL)) return; /* Should not happen */ if (strcmp(s, "null") == 0 || strcmp(s, "Null") == 0 || strcmp(s, "NULL") == 0) { csound->SetMIDIDeviceListCallback(csound, midi_dev_list_dummy); csound->SetExternalMidiInOpenCallback(csound, DummyMidiInOpen); csound->SetExternalMidiReadCallback(csound, DummyMidiRead); csound->SetExternalMidiInCloseCallback(csound, NULL); csound->SetExternalMidiOutOpenCallback(csound, DummyMidiOutOpen); csound->SetExternalMidiWriteCallback(csound, DummyMidiWrite); csound->SetExternalMidiOutCloseCallback(csound, NULL); return; } if (csoundInitModules(csound) != 0) csound->LongJmp(csound, 1); } PUBLIC int csoundGetModule(CSOUND *csound, int no, char **module, char **type){ MODULE_INFO **modules = (MODULE_INFO **) csoundQueryGlobalVariable(csound, "_MODULES"); if (UNLIKELY(modules[no] == NULL || no >= MAX_MODULES)) return CSOUND_ERROR; *module = modules[no]->module; *type = modules[no]->type; return CSOUND_SUCCESS; } PUBLIC int csoundLoadPlugins(CSOUND *csound, const char *dir){ if (dir != NULL) { int err = csoundLoadAndInitModules(csound, dir); if(!err) { csound->Message(csound, "loaded plugins from %s\n", dir); return CSOUND_SUCCESS; } else return err; } else return CSOUND_ERROR; } PUBLIC void csoundReset(CSOUND *csound) { char *s; int i, max_len; OPARMS *O = csound->oparms; char *opdir = csound->opcodedir; if (csound->engineStatus & CS_STATE_COMP || csound->engineStatus & CS_STATE_PRE) { /* and reset */ csound->Message(csound, "resetting Csound instance\n"); reset(csound); /* clear compiled flag */ csound->engineStatus |= ~(CS_STATE_COMP); } else { csoundSpinLockInit(&csound->spoutlock); csoundSpinLockInit(&csound->spinlock); csoundSpinLockInit(&csound->memlock); csoundSpinLockInit(&csound->spinlock1); if (UNLIKELY(O->odebug)) csound->Message(csound,"init spinlocks\n"); } if (msgcallback_ != NULL) { csoundSetMessageCallback(csound, msgcallback_); } else { csoundSetMessageCallback(csound, csoundDefaultMessageCallback); } csound->printerrormessagesflag = (void*)1234; /* copysystem environment variables */ i = csoundInitEnv(csound); if (UNLIKELY(i != CSOUND_SUCCESS)) { csound->engineStatus |= CS_STATE_JMP; csound->Die(csound, Str("Failed during csoundInitEnv")); } csound_init_rand(csound); csound->engineState.stringPool = cs_hash_table_create(csound); csound->engineState.constantsPool = cs_hash_table_create(csound); if (csound->symbtab != NULL) cs_hash_table_mfree_complete(csound, csound->symbtab); csound->symbtab = NULL; csound->engineStatus |= CS_STATE_PRE; csound_aops_init_tables(csound); create_opcode_table(csound); /* now load and pre-initialise external modules for this instance */ /* this function returns an error value that may be worth checking */ { int err = csoundInitStaticModules(csound); if (csound->delayederrormessages && csound->printerrormessagesflag==NULL) { csound->Warning(csound, "%s",csound->delayederrormessages); csound->Free(csound, csound->delayederrormessages); csound->delayederrormessages = NULL; } if (UNLIKELY(err==CSOUND_ERROR)) csound->Die(csound, Str("Failed during csoundInitStaticModules")); csoundCreateGlobalVariable(csound, "_MODULES", (size_t) MAX_MODULES*sizeof(MODULE_INFO *)); char *modules = (char *) csoundQueryGlobalVariable(csound, "_MODULES"); memset(modules, 0, sizeof(MODULE_INFO *)*MAX_MODULES); /* VL now load modules has opcodedir override */ csound->opcodedir = opdir; err = csoundLoadModules(csound); if (csound->delayederrormessages && csound->printerrormessagesflag==NULL) { csound->Warning(csound, "%s", csound->delayederrormessages); csound->Free(csound, csound->delayederrormessages); csound->delayederrormessages = NULL; } if (UNLIKELY(err != CSOUND_SUCCESS)) csound->Die(csound, Str("Failed during csoundLoadModules")); if (csoundInitModules(csound) != 0) csound->LongJmp(csound, 1); init_pvsys(csound); /* utilities depend on this as well as orchs; may get changed by an orch */ dbfs_init(csound, DFLT_DBFS); csound->csRtClock = (RTCLOCK*) csound->Calloc(csound, sizeof(RTCLOCK)); csoundInitTimerStruct(csound->csRtClock); csound->engineStatus |= /*CS_STATE_COMP |*/ CS_STATE_CLN; print_csound_version(csound); { char buffer[128]; sf_command(NULL, SFC_GET_LIB_VERSION, buffer, 128); csound->Message(csound, "%s\n", buffer); } /* do not know file type yet */ O->filetyp = -1; O->sfheader = 0; csound->peakchunks = 1; csound->typePool = csound->Calloc(csound, sizeof(TYPE_POOL)); csound->engineState.varPool = csoundCreateVarPool(csound); csoundAddStandardTypes(csound, csound->typePool); /* csoundLoadExternals(csound); */ } /* allow selecting real time audio module */ max_len = 21; csoundCreateGlobalVariable(csound, "_RTAUDIO", (size_t) max_len); s = csoundQueryGlobalVariable(csound, "_RTAUDIO"); #ifndef LINUX #ifdef __HAIKU__ strcpy(s, "haiku"); #else strcpy(s, "PortAudio"); #endif #else strcpy(s, "alsa"); #endif csoundCreateConfigurationVariable(csound, "rtaudio", s, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Real time audio module name"), NULL); /* initialise real time MIDI */ csound->midiGlobals = (MGLOBAL*) csound->Calloc(csound, sizeof(MGLOBAL)); csound->midiGlobals->bufp = &(csound->midiGlobals->mbuf[0]); csound->midiGlobals->endatp = csound->midiGlobals->bufp; csoundCreateGlobalVariable(csound, "_RTMIDI", (size_t) max_len); csound->SetMIDIDeviceListCallback(csound, midi_dev_list_dummy); csound->SetExternalMidiInOpenCallback(csound, DummyMidiInOpen); csound->SetExternalMidiReadCallback(csound, DummyMidiRead); csound->SetExternalMidiOutOpenCallback(csound, DummyMidiOutOpen); csound->SetExternalMidiWriteCallback(csound, DummyMidiWrite); s = csoundQueryGlobalVariable(csound, "_RTMIDI"); strcpy(s, "null"); if (csound->enableHostImplementedMIDIIO == 0) #ifndef LINUX #ifdef __HAIKU__ strcpy(s, "haiku"); #else strcpy(s, "portmidi"); #endif #else strcpy(s, "alsa"); #endif else strcpy(s, "hostbased"); csoundCreateConfigurationVariable(csound, "rtmidi", s, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Real time MIDI module name"), NULL); max_len = 256; /* should be the same as in csoundCore.h */ csoundCreateConfigurationVariable(csound, "mute_tracks", &(csound->midiGlobals->muteTrackList[0]), CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Ignore events (other than tempo " "changes) in tracks defined by pattern"), NULL); csoundCreateConfigurationVariable(csound, "raw_controller_mode", &(csound->midiGlobals->rawControllerMode), CSOUNDCFG_BOOLEAN, 0, NULL, NULL, Str("Do not handle special MIDI controllers" " (sustain pedal etc.)"), NULL); /* sound file tag options */ max_len = 201; i = (max_len + 7) & (~7); csound->SF_id_title = (char*) csound->Calloc(csound, (size_t) i * (size_t) 6); csoundCreateConfigurationVariable(csound, "id_title", csound->SF_id_title, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Title tag in output soundfile " "(no spaces)"), NULL); csound->SF_id_copyright = (char*) csound->SF_id_title + (int) i; csoundCreateConfigurationVariable(csound, "id_copyright", csound->SF_id_copyright, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Copyright tag in output soundfile" " (no spaces)"), NULL); csoundCreateConfigurationVariable(csound, "id_scopyright", &csound->SF_id_scopyright, CSOUNDCFG_INTEGER, 0, NULL, &max_len, Str("Short Copyright tag in" " output soundfile"), NULL); csound->SF_id_software = (char*) csound->SF_id_copyright + (int) i; csoundCreateConfigurationVariable(csound, "id_software", csound->SF_id_software, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Software tag in output soundfile" " (no spaces)"), NULL); csound->SF_id_artist = (char*) csound->SF_id_software + (int) i; csoundCreateConfigurationVariable(csound, "id_artist", csound->SF_id_artist, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Artist tag in output soundfile " "(no spaces)"), NULL); csound->SF_id_comment = (char*) csound->SF_id_artist + (int) i; csoundCreateConfigurationVariable(csound, "id_comment", csound->SF_id_comment, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Comment tag in output soundfile" " (no spaces)"), NULL); csound->SF_id_date = (char*) csound->SF_id_comment + (int) i; csoundCreateConfigurationVariable(csound, "id_date", csound->SF_id_date, CSOUNDCFG_STRING, 0, NULL, &max_len, Str("Date tag in output soundfile " "(no spaces)"), NULL); { MYFLT minValF = FL(0.0); csoundCreateConfigurationVariable(csound, "msg_color", &(csound->enableMsgAttr), CSOUNDCFG_BOOLEAN, 0, NULL, NULL, Str("Enable message attributes " "(colors etc.)"), NULL); csoundCreateConfigurationVariable(csound, "skip_seconds", &(csound->csoundScoreOffsetSeconds_), CSOUNDCFG_MYFLT, 0, &minValF, NULL, Str("Start score playback at the specified" " time, skipping earlier events"), NULL); } csoundCreateConfigurationVariable(csound, "ignore_csopts", &(csound->disable_csd_options), CSOUNDCFG_BOOLEAN, 0, NULL, NULL, Str("Ignore in CSD files" " (default: no)"), NULL); } PUBLIC int csoundGetDebug(CSOUND *csound) { return csound->oparms_.odebug; } PUBLIC void csoundSetDebug(CSOUND *csound, int debug) { csound->oparms_.odebug = debug; } PUBLIC int csoundTableLength(CSOUND *csound, int table) { MYFLT *tablePtr; return csoundGetTable(csound, &tablePtr, table); } PUBLIC MYFLT csoundTableGet(CSOUND *csound, int table, int index) { return csound->flist[table]->ftable[index]; } void csoundTableSetInternal(CSOUND *csound, int table, int index, MYFLT value) { if (csound->oparms->realtime) csoundLockMutex(csound->init_pass_threadlock); csound->flist[table]->ftable[index] = value; if (csound->oparms->realtime) csoundUnlockMutex(csound->init_pass_threadlock); } void csoundTableCopyOutInternal(CSOUND *csound, int table, MYFLT *ptable){ int len; MYFLT *ftab; /* in realtime mode init pass is executed in a separate thread, so we need to protect it */ if (csound->oparms->realtime) csoundLockMutex(csound->init_pass_threadlock); len = csoundGetTable(csound, &ftab, table); if (UNLIKELY(len>0x00ffffff)) len = 0x00ffffff; // As coverity is unhappy memcpy(ptable, ftab, (size_t) (len*sizeof(MYFLT))); if (csound->oparms->realtime) csoundUnlockMutex(csound->init_pass_threadlock); } void csoundTableCopyInInternal(CSOUND *csound, int table, MYFLT *ptable){ int len; MYFLT *ftab; /* in realtime mode init pass is executed in a separate thread, so we need to protect it */ if (csound->oparms->realtime) csoundLockMutex(csound->init_pass_threadlock); len = csoundGetTable(csound, &ftab, table); if (UNLIKELY(len>0x00ffffff)) len = 0x00ffffff; // As coverity is unhappy memcpy(ftab, ptable, (size_t) (len*sizeof(MYFLT))); if (csound->oparms->realtime) csoundUnlockMutex(csound->init_pass_threadlock); } static int csoundDoCallback_(CSOUND *csound, void *p, unsigned int type) { if (csound->csoundCallbacks_ != NULL) { CsoundCallbackEntry_t *pp; pp = (CsoundCallbackEntry_t*) csound->csoundCallbacks_; do { if (pp->typeMask & type) { int retval = pp->func(pp->userData, p, type); if (retval != CSOUND_SUCCESS) return retval; } pp = pp->nxt; } while (pp != (CsoundCallbackEntry_t*) NULL); } return 1; } /** * Sets a callback function that will be called on keyboard * events. The callback is preserved on csoundReset(), and multiple * callbacks may be set and will be called in reverse order of * registration. If the same function is set again, it is only moved * in the list of callbacks so that it will be called first, and the * user data and type mask parameters are updated. 'typeMask' can be the * bitwise OR of callback types for which the function should be called, * or zero for all types. * Returns zero on success, CSOUND_ERROR if the specified function * pointer or type mask is invalid, and CSOUND_MEMORY if there is not * enough memory. * * The callback function takes the following arguments: * void *userData * the "user data" pointer, as specified when setting the callback * void *p * data pointer, depending on the callback type * unsigned int type * callback type, can be one of the following (more may be added in * future versions of Csound): * CSOUND_CALLBACK_KBD_EVENT * CSOUND_CALLBACK_KBD_TEXT * called by the sensekey opcode to fetch key codes. The data * pointer is a pointer to a single value of type 'int', for * returning the key code, which can be in the range 1 to 65535, * or 0 if there is no keyboard event. * For CSOUND_CALLBACK_KBD_EVENT, both key press and release * events should be returned (with 65536 (0x10000) added to the * key code in the latter case) as unshifted ASCII codes. * CSOUND_CALLBACK_KBD_TEXT expects key press events only as the * actual text that is typed. * The return value should be zero on success, negative on error, and * positive if the callback was ignored (for example because the type is * not known). */ PUBLIC int csoundRegisterKeyboardCallback(CSOUND *csound, int (*func)(void *userData, void *p, unsigned int type), void *userData, unsigned int typeMask) { CsoundCallbackEntry_t *pp; if (UNLIKELY(func == (int (*)(void *, void *, unsigned int)) NULL || (typeMask & (~(CSOUND_CALLBACK_KBD_EVENT | CSOUND_CALLBACK_KBD_TEXT))) != 0U)) return CSOUND_ERROR; csoundRemoveKeyboardCallback(csound, func); pp = (CsoundCallbackEntry_t*) malloc(sizeof(CsoundCallbackEntry_t)); if (UNLIKELY(pp == (CsoundCallbackEntry_t*) NULL)) return CSOUND_MEMORY; pp->typeMask = (typeMask ? typeMask : 0xFFFFFFFFU); pp->nxt = (CsoundCallbackEntry_t*) csound->csoundCallbacks_; pp->userData = userData; pp->func = func; csound->csoundCallbacks_ = (void*) pp; return CSOUND_SUCCESS; } /** * Removes a callback previously set with csoundSetCallback(). */ PUBLIC void csoundRemoveKeyboardCallback(CSOUND *csound, int (*func)(void *, void *, unsigned int)) { CsoundCallbackEntry_t *pp, *prv; pp = (CsoundCallbackEntry_t*) csound->csoundCallbacks_; prv = (CsoundCallbackEntry_t*) NULL; while (pp != (CsoundCallbackEntry_t*) NULL) { if (pp->func == func) { if (prv != (CsoundCallbackEntry_t*) NULL) prv->nxt = pp->nxt; else csound->csoundCallbacks_ = (void*) pp->nxt; free((void*) pp); return; } prv = pp; pp = pp->nxt; } } PUBLIC void csoundSetFileOpenCallback(CSOUND *p, void (*fileOpenCallback)(CSOUND*, const char*, int, int, int)) { p->FileOpenCallback_ = fileOpenCallback; } /* csoundNotifyFileOpened() should be called by plugins via csound->NotifyFileOpened() to let Csound know that they opened a file without using one of the standard mechanisms (csound->FileOpen2() or ldmemfile2withCB()). The notification is passed on to the host if it has set the FileOpen callback. */ void csoundNotifyFileOpened(CSOUND* csound, const char* pathname, int csFileType, int writing, int temporary) { if (csound->FileOpenCallback_ != NULL) csound->FileOpenCallback_(csound, pathname, csFileType, writing, temporary); return; } /* -------- IV - Jan 27 2005: timer functions -------- */ #ifdef HAVE_GETTIMEOFDAY #undef HAVE_GETTIMEOFDAY #endif #if defined(LINUX) || defined(__unix) || defined(__unix__) || defined(__MACH__) #define HAVE_GETTIMEOFDAY 1 #include #endif /* enable use of high resolution timer (Linux/i586/GCC only) */ /* could in fact work under any x86/GCC system, but do not */ /* know how to query the actual CPU frequency ... */ //#define HAVE_RDTSC 1 /* ------------------------------------ */ #if defined(HAVE_RDTSC) #if !(defined(LINUX) && defined(__GNUC__) && defined(__i386__)) || !(defined(__FreeBSD__) && defined(__i386__)) #undef HAVE_RDTSC #endif #endif /* hopefully cannot change during performance */ static double timeResolutionSeconds = -1.0; /* find out CPU frequency based on /proc/cpuinfo */ static int getTimeResolution(void) { #if defined(HAVE_RDTSC) #if defined(__FreeBSD__) size_t size; int timeResolutionSeconds; size = sizeof timeResolutionSeconds; sysctlbyname("hw.clockrate", &timeResolutionSeconds, &size, NULL, 0); #else FILE *f; char buf[256]; /* if frequency is not known yet */ f = fopen("/proc/cpuinfo", "r"); if (UNLIKELY(f == NULL)) { fprintf(stderr, Str("Cannot open /proc/cpuinfo. " "Support for RDTSC is not available.\n")); return -1; } /* find CPU frequency */ while (fgets(buf, 256, f) != NULL) { int i; char *s = (char*) buf - 1; buf[255] = '\0'; /* safety */ if (strlen(buf) < 9) continue; /* too short, skip */ while (*++s != '\0') if (isupper(*s)) *s = tolower(*s); /* convert to lower case */ if (strncmp(buf, "cpu mhz", 7) != 0) continue; /* check key name */ s = strchr(buf, ':'); /* find frequency value */ if (s == NULL) continue; /* invalid entry */ do { s++; } while (isblank(*s)); /* skip white space */ i = CS_SSCANF(s, "%lf", &timeResolutionSeconds); if (i < 1 || timeResolutionSeconds < 1.0) { timeResolutionSeconds = -1.0; /* invalid entry */ continue; } } fclose(f); #endif /* __FreeBSD__ */ if (UNLIKELY(timeResolutionSeconds <= 0.0)) { fprintf(stderr, Str("No valid CPU frequency entry " #if defined(__FreeBSD__) "was found.\n")); #else "was found in /proc/cpuinfo.\n")); #endif /* __FreeBSD__ */ return -1; } /* MHz -> seconds */ timeResolutionSeconds = 0.000001 / timeResolutionSeconds; #elif defined(WIN32) LARGE_INTEGER tmp1; int_least64_t tmp2; QueryPerformanceFrequency(&tmp1); tmp2 = (int_least64_t) tmp1.LowPart + ((int_least64_t) tmp1.HighPart << 32); timeResolutionSeconds = 1.0 / (double) tmp2; #elif defined(HAVE_GETTIMEOFDAY) timeResolutionSeconds = 0.000001; #else timeResolutionSeconds = 1.0; #endif #ifdef BETA fprintf(stderr, "time resolution is %.3f ns\n", 1.0e9 * timeResolutionSeconds); #endif return 0; } /* function for getting real time */ static inline int_least64_t get_real_time(void) { #if defined(HAVE_RDTSC) /* optimised high resolution timer for Linux/i586/GCC only */ uint32_t l, h; #ifndef __STRICT_ANSI__ asm volatile ("rdtsc" : "=a" (l), "=d" (h)); #else __asm__ volatile ("rdtsc" : "=a" (l), "=d" (h)); #endif return ((int_least64_t) l + ((int_least64_t) h << 32)); #elif defined(WIN32) /* Win32: use QueryPerformanceCounter - resolution depends on system, */ /* but is expected to be better than 1 us. GetSystemTimeAsFileTime */ /* seems to have much worse resolution under Win95. */ LARGE_INTEGER tmp; QueryPerformanceCounter(&tmp); return ((int_least64_t) tmp.LowPart + ((int_least64_t) tmp.HighPart <<32)); #elif defined(HAVE_GETTIMEOFDAY) /* UNIX: use gettimeofday() - allows 1 us resolution */ struct timeval tv; gettimeofday(&tv, NULL); return ((int_least64_t) tv.tv_usec + (int_least64_t) ((uint32_t) tv.tv_sec * (uint64_t) 1000000)); #else /* other systems: use time() - allows 1 second resolution */ return ((int_least64_t) time(NULL)); #endif } /* function for getting CPU time */ static inline int_least64_t get_CPU_time(void) { return ((int_least64_t) ((uint32_t) clock())); } /* initialise a timer structure */ PUBLIC void csoundInitTimerStruct(RTCLOCK *p) { p->starttime_real = get_real_time(); p->starttime_CPU = get_CPU_time(); } /** * return the elapsed real time (in seconds) since the specified timer * structure was initialised */ PUBLIC double csoundGetRealTime(RTCLOCK *p) { return ((double) (get_real_time() - p->starttime_real) * (double) timeResolutionSeconds); } /** * return the elapsed CPU time (in seconds) since the specified timer * structure was initialised */ PUBLIC double csoundGetCPUTime(RTCLOCK *p) { return ((double) ((uint32_t) get_CPU_time() - (uint32_t) p->starttime_CPU) * (1.0 / (double) CLOCKS_PER_SEC)); } /* return a 32-bit unsigned integer to be used as seed from current time */ PUBLIC uint32_t csoundGetRandomSeedFromTime(void) { return (uint32_t) get_real_time(); } /** * Return the size of MYFLT in bytes. */ PUBLIC int csoundGetSizeOfMYFLT(void) { return (int) sizeof(MYFLT); } /** * Return pointer to user data pointer for real time audio input. */ PUBLIC void **csoundGetRtRecordUserData(CSOUND *csound) { return &(csound->rtRecord_userdata); } /** * Return pointer to user data pointer for real time audio output. */ PUBLIC void **csoundGetRtPlayUserData(CSOUND *csound) { return &(csound->rtPlay_userdata); } typedef struct opcodeDeinit_s { void *p; int (*func)(CSOUND *, void *); void *nxt; } opcodeDeinit_t; /** * Register a function to be called at note deactivation. * Should be called from the initialisation routine of an opcode. * 'p' is a pointer to the OPDS structure of the opcode, and 'func' * is the function to be called, with the same arguments and return * value as in the case of opcode init/perf functions. * The functions are called in reverse order of registration. * Returns zero on success. */ int csoundRegisterDeinitCallback(CSOUND *csound, void *p, int (*func)(CSOUND *, void *)) { INSDS *ip = ((OPDS*) p)->insdshead; opcodeDeinit_t *dp = (opcodeDeinit_t*) malloc(sizeof(opcodeDeinit_t)); (void) csound; if (UNLIKELY(dp == NULL)) return CSOUND_MEMORY; dp->p = p; dp->func = func; dp->nxt = ip->nxtd; ip->nxtd = dp; return CSOUND_SUCCESS; } /** * Register a function to be called by csoundReset(), in reverse order * of registration, before unloading external modules. The function takes * the Csound instance pointer as the first argument, and the pointer * passed here as 'userData' as the second, and is expected to return zero * on success. * The return value of csoundRegisterResetCallback() is zero on success. */ int csoundRegisterResetCallback(CSOUND *csound, void *userData, int (*func)(CSOUND *, void *)) { resetCallback_t *dp = (resetCallback_t*) malloc(sizeof(resetCallback_t)); if (UNLIKELY(dp == NULL)) return CSOUND_MEMORY; dp->userData = userData; dp->func = func; dp->nxt = csound->reset_list; csound->reset_list = (void*) dp; return CSOUND_SUCCESS; } /* call the opcode deinitialisation routines of an instrument instance */ /* called from deact() in insert.c */ int csoundDeinitialiseOpcodes(CSOUND *csound, INSDS *ip) { int err = 0; while (ip->nxtd != NULL) { opcodeDeinit_t *dp = (opcodeDeinit_t*) ip->nxtd; err |= dp->func(csound, dp->p); ip->nxtd = (void*) dp->nxt; free(dp); } return err; } /** * Returns the name of the opcode of which the data structure * is pointed to by 'p'. */ char *csoundGetOpcodeName(void *p) { return ((OPDS*) p)->optext->t.oentry->opname; } /** Returns the CS_TYPE for an opcode's arg pointer */ CS_TYPE* csoundGetTypeForArg(void* argPtr) { char* ptr = (char*)argPtr; CS_TYPE* varType = *(CS_TYPE**)(ptr - CS_VAR_TYPE_OFFSET); return varType; } /** * Returns the number of input arguments for opcode 'p'. */ int csoundGetInputArgCnt(void *p) { return (int) ((OPDS*) p)->optext->t.inArgCount; } /** * Returns the name of input argument 'n' (counting from 0) for opcode 'p'. */ char *csoundGetInputArgName(void *p, int n) { if ((unsigned int) n >= (unsigned int) ((OPDS*) p)->optext->t.inArgCount) return (char*) NULL; return (char*) ((OPDS*) p)->optext->t.inlist->arg[n]; } /** * Returns the number of output arguments for opcode 'p'. */ int csoundGetOutputArgCnt(void *p) { return (int) ((OPDS*) p)->optext->t.outArgCount; } /** * Returns the name of output argument 'n' (counting from 0) for opcode 'p'. */ char *csoundGetOutputArgName(void *p, int n) { if ((unsigned int) n >= (unsigned int) ((OPDS*) p)->optext->t.outArgCount) return (char*) NULL; return (char*) ((OPDS*) p)->optext->t.outlist->arg[n]; } /** * Set release time in control periods (1 / csound->ekr second units) * for opcode 'p' to 'n'. If the current release time is longer than * the specified value, it is not changed. * Returns the new release time. */ int csoundSetReleaseLength(void *p, int n) { if (n > (int) ((OPDS*) p)->insdshead->xtratim) ((OPDS*) p)->insdshead->xtratim = n; return (int) ((OPDS*) p)->insdshead->xtratim; } /** * Set release time in seconds for opcode 'p' to 'n'. * If the current release time is longer than the specified value, * it is not changed. * Returns the new release time in seconds. */ MYFLT csoundSetReleaseLengthSeconds(void *p, MYFLT n) { int kcnt = (int) (n * ((OPDS*) p)->insdshead->csound->ekr + FL(0.5)); if (kcnt > (int) ((OPDS*) p)->insdshead->xtratim) ((OPDS*) p)->insdshead->xtratim = kcnt; return ((MYFLT) ((OPDS*) p)->insdshead->xtratim * ((OPDS*) p)->insdshead->csound->onedkr); } /** * Returns MIDI channel number (0 to 15) for the instrument instance * that called opcode 'p'. * In the case of score notes, -1 is returned. */ int csoundGetMidiChannelNumber(void *p) { MCHNBLK *chn = ((OPDS*) p)->insdshead->m_chnbp; int i; if (chn == NULL) return -1; for (i = 0; i < 256; i++) { if (chn == ((OPDS*) p)->insdshead->csound->m_chnbp[i]) return i; } return -1; } /** * Returns a pointer to the MIDI channel structure for the instrument * instance that called opcode 'p'. * In the case of score notes, NULL is returned. */ MCHNBLK *csoundGetMidiChannel(void *p) { return ((OPDS*) p)->insdshead->m_chnbp; } /** * Returns MIDI note number (in the range 0 to 127) for opcode 'p'. * If the opcode was not called from a MIDI activated instrument * instance, the return value is undefined. */ int csoundGetMidiNoteNumber(void *p) { return (int) ((OPDS*) p)->insdshead->m_pitch; } /** * Returns MIDI velocity (in the range 0 to 127) for opcode 'p'. * If the opcode was not called from a MIDI activated instrument * instance, the return value is undefined. */ int csoundGetMidiVelocity(void *p) { return (int) ((OPDS*) p)->insdshead->m_veloc; } /** * Returns non-zero if the current note (owning opcode 'p') is releasing. */ int csoundGetReleaseFlag(void *p) { return (int) ((OPDS*) p)->insdshead->relesing; } /** * Returns the note-off time in seconds (measured from the beginning of * performance) of the current instrument instance, from which opcode 'p' * was called. The return value may be negative if the note has indefinite * duration. */ double csoundGetOffTime(void *p) { return (double) ((OPDS*) p)->insdshead->offtim; } /** * Returns the array of p-fields passed to the instrument instance * that owns opcode 'p', starting from p0. Only p1, p2, and p3 are * guaranteed to be available. p2 is measured in seconds from the * beginning of the current section. */ MYFLT *csoundGetPFields(void *p) { /* FIXME - this is no longer valid, should return CS_VAR_MEM* and use ->p0_type */ return (MYFLT*) &(((OPDS*) p)->insdshead->p0); } /** * Returns the instrument number (p1) for opcode 'p'. */ int csoundGetInstrumentNumber(void *p) { return (int) ((OPDS*) p)->insdshead->p1.value; } typedef struct csMsgStruct_ { struct csMsgStruct_ *nxt; int attr; char s[1]; } csMsgStruct; typedef struct csMsgBuffer_ { void *mutex_; csMsgStruct *firstMsg; csMsgStruct *lastMsg; int msgCnt; char *buf; } csMsgBuffer; // callback for storing messages in the buffer only static void csoundMessageBufferCallback_1_(CSOUND *csound, int attr, const char *fmt, va_list args); // callback for writing messages to the buffer, and also stdout/stderr static void csoundMessageBufferCallback_2_(CSOUND *csound, int attr, const char *fmt, va_list args); /** * Creates a buffer for storing messages printed by Csound. * Should be called after creating a Csound instance; note that * the message buffer uses the host data pointer, and the buffer * should be freed by calling csoundDestroyMessageBuffer() before * deleting the Csound instance. * If 'toStdOut' is non-zero, the messages are also printed to * stdout and stderr (depending on the type of the message), * in addition to being stored in the buffer. */ void PUBLIC csoundCreateMessageBuffer(CSOUND *csound, int toStdOut) { csMsgBuffer *pp; size_t nBytes; pp = (csMsgBuffer*) csound->message_buffer; if (pp) { csoundDestroyMessageBuffer(csound); } nBytes = sizeof(csMsgBuffer); if (!toStdOut) { nBytes += (size_t) 16384; } pp = (csMsgBuffer*) malloc(nBytes); pp->mutex_ = csoundCreateMutex(0); pp->firstMsg = (csMsgStruct*) NULL; pp->lastMsg = (csMsgStruct*) NULL; pp->msgCnt = 0; if (!toStdOut) { pp->buf = (char*) pp + (int) sizeof(csMsgBuffer); pp->buf[0] = (char) '\0'; } else { pp->buf = (char*) NULL; } csound->message_buffer = (void*) pp; if (toStdOut) { csoundSetMessageCallback(csound, csoundMessageBufferCallback_2_); } else { csoundSetMessageCallback(csound, csoundMessageBufferCallback_1_); } } /** * Returns the first message from the buffer. */ #ifdef MSVC const char PUBLIC *csoundGetFirstMessage(CSOUND *csound) #else const char */*PUBLIC*/ csoundGetFirstMessage(CSOUND *csound) #endif { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; char *msg = NULL; if (pp && pp->msgCnt) { csoundLockMutex(pp->mutex_); if (pp->firstMsg) msg = &(pp->firstMsg->s[0]); csoundUnlockMutex(pp->mutex_); } return msg; } /** * Returns the attribute parameter (see msg_attr.h) of the first message * in the buffer. */ int PUBLIC csoundGetFirstMessageAttr(CSOUND *csound) { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; int attr = 0; if (pp && pp->msgCnt) { csoundLockMutex(pp->mutex_); if (pp->firstMsg) { attr = pp->firstMsg->attr; } csoundUnlockMutex(pp->mutex_); } return attr; } /** * Removes the first message from the buffer. */ void PUBLIC csoundPopFirstMessage(CSOUND *csound) { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; if (pp) { csMsgStruct *tmp; csoundLockMutex(pp->mutex_); tmp = pp->firstMsg; if (tmp) { pp->firstMsg = tmp->nxt; pp->msgCnt--; if (!pp->firstMsg) pp->lastMsg = (csMsgStruct*) 0; } csoundUnlockMutex(pp->mutex_); if (tmp) free((void*) tmp); } } /** * Returns the number of pending messages in the buffer. */ int PUBLIC csoundGetMessageCnt(CSOUND *csound) { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; int cnt = -1; if (pp) { csoundLockMutex(pp->mutex_); cnt = pp->msgCnt; csoundUnlockMutex(pp->mutex_); } return cnt; } /** * Releases all memory used by the message buffer. */ void PUBLIC csoundDestroyMessageBuffer(CSOUND *csound) { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; if (!pp) { csound->Warning(csound, Str("csoundDestroyMessageBuffer: " "Message buffer not allocated.")); return; } csMsgStruct *msg = pp->firstMsg; while (msg) { csMsgStruct *tmp = msg; msg = tmp->nxt; free(tmp); } csound->message_buffer = NULL; csoundSetMessageCallback(csound, NULL); while (csoundGetMessageCnt(csound) > 0) { csoundPopFirstMessage(csound); } csoundSetHostData(csound, NULL); csoundDestroyMutex(pp->mutex_); free((void*) pp); } static void csoundMessageBufferCallback_1_(CSOUND *csound, int attr, const char *fmt, va_list args) { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; csMsgStruct *p; int len; csoundLockMutex(pp->mutex_); len = vsnprintf(pp->buf, 16384, fmt, args); // FIXEDME: this can overflow va_end(args); if (UNLIKELY((unsigned int) len >= (unsigned int) 16384)) { csoundUnlockMutex(pp->mutex_); fprintf(stderr, Str("csound: internal error: message buffer overflow\n")); exit(-1); } p = (csMsgStruct*) malloc(sizeof(csMsgStruct) + (size_t) len); p->nxt = (csMsgStruct*) NULL; p->attr = attr; strcpy(&(p->s[0]), pp->buf); if (pp->firstMsg == (csMsgStruct*) 0) { pp->firstMsg = p; } else { pp->lastMsg->nxt = p; } pp->lastMsg = p; pp->msgCnt++; csoundUnlockMutex(pp->mutex_); } static void csoundMessageBufferCallback_2_(CSOUND *csound, int attr, const char *fmt, va_list args) { csMsgBuffer *pp = (csMsgBuffer*) csound->message_buffer; csMsgStruct *p; int len = 0; va_list args_save; va_copy(args_save, args); switch (attr & CSOUNDMSG_TYPE_MASK) { case CSOUNDMSG_ERROR: case CSOUNDMSG_REALTIME: case CSOUNDMSG_WARNING: len = vfprintf(stderr, fmt, args); break; default: len = vfprintf(stdout, fmt, args); } va_end(args); p = (csMsgStruct*) malloc(sizeof(csMsgStruct) + (size_t) len); p->nxt = (csMsgStruct*) NULL; p->attr = attr; vsnprintf(&(p->s[0]), len, fmt, args_save); va_end(args_save); csoundLockMutex(pp->mutex_); if (pp->firstMsg == (csMsgStruct*) NULL) pp->firstMsg = p; else pp->lastMsg->nxt = p; pp->lastMsg = p; pp->msgCnt++; csoundUnlockMutex(pp->mutex_); } static INSTRTXT **csoundGetInstrumentList(CSOUND *csound){ return csound->engineState.instrtxtp; } uint64_t csoundGetKcounter(CSOUND *csound){ return csound->kcounter; } static void set_util_sr(CSOUND *csound, MYFLT sr){ csound->esr = sr; } static void set_util_nchnls(CSOUND *csound, int nchnls){ csound->nchnls = nchnls; } MYFLT csoundGetA4(CSOUND *csound) { return (MYFLT) csound->A4; } int csoundErrCnt(CSOUND *csound) { return csound->perferrcnt; } INSTRTXT *csoundGetInstrument(CSOUND *csound, int insno, const char *name) { if (name != NULL) insno = named_instr_find(csound, (char *)name); return csound->engineState.instrtxtp[insno]; } #if 0 PUBLIC int csoundPerformKsmpsAbsolute(CSOUND *csound) { int done = 0; int returnValue; /* VL: 1.1.13 if not compiled (csoundStart() not called) */ if (UNLIKELY(!(csound->engineStatus & CS_STATE_COMP))) { csound->Warning(csound, Str("Csound not ready for performance: csoundStart() " "has not been called\n")); return CSOUND_ERROR; } /* setup jmp for return after an exit() */ if (UNLIKELY((returnValue = setjmp(csound->exitjmp)))) { #ifndef MACOSX csoundMessage(csound, Str("Early return from csoundPerformKsmps().\n")); #endif return ((returnValue - CSOUND_EXITJMP_SUCCESS) | CSOUND_EXITJMP_SUCCESS); } csoundLockMutex(csound->API_lock); do { done |= sensevents(csound); } while (csound->kperf(csound)); csoundUnlockMutex(csound->API_lock); return done; } #endif //#ifdef __cplusplus //} //#endif