1 /*
2  * threadsafe.c: threadsafe API functions
3  *               Copyright (c) V Lazzarini, 2013
4  *
5  * L I C E N S E
6  *
7  * This software is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This software is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this software; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "csoundCore.h"
23 #include "csound_orc.h"
24 #include <stdlib.h>
25 
26 #ifdef USE_DOUBLE
27 #  define MYFLT_INT_TYPE int64_t
28 #else
29 #  define MYFLT_INT_TYPE int32_t
30 #endif
31 
32 int csoundKillInstanceInternal(CSOUND *csound, MYFLT instr, char *instrName,
33                                int mode, int allow_release, int async);
34 int csoundCompileTreeInternal(CSOUND *csound, TREE *root, int async);
35 int csoundCompileOrcInternal(CSOUND *csound, const char *str, int async);
36 void merge_state(CSOUND *csound, ENGINE_STATE *engineState,
37                  TYPE_TABLE* typetable, OPDS *ids);
38 void killInstance(CSOUND *csound, MYFLT instr, int insno, INSDS *ip,
39                   int mode, int allow_release);
40 void csoundInputMessageInternal(CSOUND *csound, const char *message);
41 int csoundReadScoreInternal(CSOUND *csound, const char *message);
42 void csoundTableCopyOutInternal(CSOUND *csound, int table, MYFLT *ptable);
43 void csoundTableCopyInInternal(CSOUND *csound, int table, MYFLT *ptable);
44 void csoundTableSetInternal(CSOUND *csound, int table, int index, MYFLT value);
45 int csoundScoreEventInternal(CSOUND *csound, char type,
46                              const MYFLT *pfields, long numFields);
47 int csoundScoreEventAbsoluteInternal(CSOUND *csound, char type,
48                                      const MYFLT *pfields, long numFields,
49                                      double time_ofs);
50 void set_channel_data_ptr(CSOUND *csound, const char *name,
51                           void *ptr, int newSize);
52 
53 enum {INPUT_MESSAGE=1, READ_SCORE, SCORE_EVENT, SCORE_EVENT_ABS,
54       TABLE_COPY_OUT, TABLE_COPY_IN, TABLE_SET, MERGE_STATE, KILL_INSTANCE};
55 
56 /* MAX QUEUE SIZE */
57 #define API_MAX_QUEUE 1024
58 /* ARG LIST ALIGNMENT */
59 #define ARG_ALIGN 8
60 
61 /* Message queue structure */
62 typedef struct _message_queue {
63   int64_t message;  /* message id */
64   char *args;   /* args, arg pointers */
65   int64_t rtn;  /* return value */
66 } message_queue_t;
67 
68 
69 /* atomicGetAndIncrementWithModulus */
atomicGet_Incr_Mod(volatile long * val,long mod)70 static long atomicGet_Incr_Mod(volatile long* val, long mod) {
71   volatile long oldVal, newVal;
72   do {
73     oldVal = *val;
74     newVal = (oldVal + 1) % mod;
75   } while (ATOMIC_CMP_XCH(val, newVal, oldVal));
76   return oldVal;
77 }
78 
79 /* called by csoundCreate() at the start
80    and also by csoundStart() to cover de-allocation
81    by reset
82 */
allocate_message_queue(CSOUND * csound)83 void allocate_message_queue(CSOUND *csound) {
84   if (csound->msg_queue == NULL) {
85     int i;
86     csound->msg_queue = (message_queue_t **)
87       csound->Calloc(csound, sizeof(message_queue_t*)*API_MAX_QUEUE);
88     for (i = 0; i < API_MAX_QUEUE; i++) {
89       csound->msg_queue[i] =
90         (message_queue_t*)
91         csound->Calloc(csound, sizeof(message_queue_t));
92     }
93   }
94 }
95 
96 
97 /* enqueue should be called by the relevant API function */
message_enqueue(CSOUND * csound,int32_t message,char * args,int argsiz)98 void *message_enqueue(CSOUND *csound, int32_t message, char *args,
99                       int argsiz) {
100   if(csound->msg_queue != NULL) {
101     int64_t *rtn;
102     volatile long items;
103 
104     /* block if queue is full */
105     do {
106       items = ATOMIC_GET(csound->msg_queue_items);
107     } while(items >= API_MAX_QUEUE);
108 
109     message_queue_t* msg =
110       csound->msg_queue[atomicGet_Incr_Mod(&csound->msg_queue_wget,
111                                            API_MAX_QUEUE)];
112     msg->message = message;
113     if(msg->args != NULL)
114       csound->Free(csound, msg->args);
115     msg->args = (char *)csound->Calloc(csound, argsiz);
116     memcpy(msg->args, args, argsiz);
117     rtn = &msg->rtn;
118     csound->msg_queue[atomicGet_Incr_Mod(&csound->msg_queue_wput,
119                                          API_MAX_QUEUE)] = msg;
120     ATOMIC_INCR(csound->msg_queue_items);
121     return (void *) rtn;
122   }
123   else return NULL;
124 }
125 
126 /* dequeue should be called by kperf_*()
127    NB: these calls are already in place
128 */
message_dequeue(CSOUND * csound)129 void message_dequeue(CSOUND *csound) {
130   if(csound->msg_queue != NULL) {
131     long rp = csound->msg_queue_rstart;
132     long items = csound->msg_queue_items;
133     long rend = rp + items;
134 
135     while(rp < rend) {
136       message_queue_t* msg = csound->msg_queue[rp % API_MAX_QUEUE];
137       switch(msg->message) {
138       case INPUT_MESSAGE:
139         {
140           const char *str = msg->args;
141           csoundInputMessageInternal(csound, str);
142         }
143 
144         break;
145       case READ_SCORE:
146         {
147           const char *str = msg->args;
148           csoundReadScoreInternal(csound, str);
149         }
150         break;
151       case SCORE_EVENT:
152         {
153           char type;
154           const MYFLT *pfields;
155           long numFields;
156           type = msg->args[0];
157           memcpy(&pfields, msg->args + ARG_ALIGN,
158                  sizeof(MYFLT *));
159           memcpy(&numFields, msg->args + ARG_ALIGN*2,
160                  sizeof(long));
161 
162           csoundScoreEventInternal(csound, type, pfields, numFields);
163         }
164         break;
165       case SCORE_EVENT_ABS:
166         {
167           char type;
168           const MYFLT *pfields;
169           long numFields;
170           double ofs;
171           type = msg->args[0];
172           memcpy(&pfields, msg->args + ARG_ALIGN,
173                  sizeof(MYFLT *));
174           memcpy(&numFields, msg->args + ARG_ALIGN*2,
175                  sizeof(long));
176           memcpy(&ofs, msg->args + ARG_ALIGN*3,
177                  sizeof(double));
178 
179           csoundScoreEventAbsoluteInternal(csound, type, pfields, numFields,
180                                              ofs);
181         }
182         break;
183       case TABLE_COPY_OUT:
184         {
185           int table;
186           MYFLT *ptable;
187           memcpy(&table, msg->args, sizeof(int));
188           memcpy(&ptable, msg->args + ARG_ALIGN,
189                  sizeof(MYFLT *));
190           csoundTableCopyOutInternal(csound, table, ptable);
191         }
192         break;
193       case TABLE_COPY_IN:
194         {
195           int table;
196           MYFLT *ptable;
197           memcpy(&table, msg->args, sizeof(int));
198           memcpy(&ptable, msg->args + ARG_ALIGN,
199                  sizeof(MYFLT *));
200           csoundTableCopyInInternal(csound, table, ptable);
201         }
202         break;
203       case TABLE_SET:
204         {
205           int table, index;
206           MYFLT value;
207           memcpy(&table, msg->args, sizeof(int));
208           memcpy(&index, msg->args + ARG_ALIGN,
209                  sizeof(int));
210           memcpy(&value, msg->args + 2*ARG_ALIGN,
211                  sizeof(MYFLT));
212           csoundTableSetInternal(csound, table, index, value);
213         }
214         break;
215       case MERGE_STATE:
216         {
217           ENGINE_STATE *e;
218           TYPE_TABLE *t;
219           OPDS *ids;
220           memcpy(&e, msg->args, sizeof(ENGINE_STATE *));
221           memcpy(&t, msg->args + ARG_ALIGN,
222                  sizeof(TYPE_TABLE *));
223           memcpy(&ids, msg->args + 2*ARG_ALIGN,
224                  sizeof(OPDS *));
225           merge_state(csound, e, t, ids);
226         }
227         break;
228       case KILL_INSTANCE:
229         {
230           MYFLT instr;
231           int mode, insno, rls;
232           INSDS *ip;
233           memcpy(&instr, msg->args, sizeof(MYFLT));
234           memcpy(&insno, msg->args + ARG_ALIGN,
235                  sizeof(int));
236           memcpy(&ip, msg->args + ARG_ALIGN*2,
237                  sizeof(INSDS *));
238           memcpy(&mode, msg->args + ARG_ALIGN*3,
239                  sizeof(int));
240           memcpy(&rls, msg->args  + ARG_ALIGN*4,
241                  sizeof(int));
242           killInstance(csound, instr, insno, ip, mode, rls);
243         }
244         break;
245       }
246       msg->message = 0;
247       rp += 1;
248     }
249     ATOMIC_SUB(csound->msg_queue_items, items);
250     csound->msg_queue_rstart = rp % API_MAX_QUEUE;
251   }
252 }
253 
254 /* these are the message enqueueing functions for each relevant API function */
csoundInputMessage_enqueue(CSOUND * csound,const char * str)255 static inline void csoundInputMessage_enqueue(CSOUND *csound,
256                                               const char *str){
257   message_enqueue(csound,INPUT_MESSAGE, (char *) str, strlen(str)+1);
258 }
259 
csoundReadScore_enqueue(CSOUND * csound,const char * str)260 static inline int64_t *csoundReadScore_enqueue(CSOUND *csound, const char *str){
261   return message_enqueue(csound, READ_SCORE, (char *) str, strlen(str)+1);
262 }
263 
csoundTableCopyOut_enqueue(CSOUND * csound,int table,MYFLT * ptable)264 static inline void csoundTableCopyOut_enqueue(CSOUND *csound, int table,
265                                               MYFLT *ptable){
266   const int argsize = ARG_ALIGN*2;
267   char args[ARG_ALIGN*2];
268   memcpy(args, &table, sizeof(int));
269   memcpy(args+ARG_ALIGN, &ptable, sizeof(MYFLT *));
270   message_enqueue(csound,TABLE_COPY_OUT, args, argsize);
271 }
272 
csoundTableCopyIn_enqueue(CSOUND * csound,int table,MYFLT * ptable)273 static inline void csoundTableCopyIn_enqueue(CSOUND *csound, int table,
274                                              MYFLT *ptable){
275   const int argsize = ARG_ALIGN*2;
276   char args[ARG_ALIGN*2];
277   memcpy(args, &table, sizeof(int));
278   memcpy(args+ARG_ALIGN, &ptable, sizeof(MYFLT *));
279   message_enqueue(csound,TABLE_COPY_IN, args, argsize);
280 }
281 
csoundTableSet_enqueue(CSOUND * csound,int table,int index,MYFLT value)282 static inline void csoundTableSet_enqueue(CSOUND *csound, int table, int index,
283                                           MYFLT value)
284 {
285   const int argsize = ARG_ALIGN*3;
286   char args[ARG_ALIGN*3];
287   memcpy(args, &table, sizeof(int));
288   memcpy(args+ARG_ALIGN, &index, sizeof(int));
289   memcpy(args+2*ARG_ALIGN, &value, sizeof(MYFLT));
290   message_enqueue(csound,TABLE_SET, args, argsize);
291 }
292 
293 
csoundScoreEvent_enqueue(CSOUND * csound,char type,const MYFLT * pfields,long numFields)294 static inline int64_t *csoundScoreEvent_enqueue(CSOUND *csound, char type,
295                                                 const MYFLT *pfields,
296                                                 long numFields)
297 {
298   const int argsize = ARG_ALIGN*3;
299   char args[ARG_ALIGN*3];
300   args[0] = type;
301   memcpy(args+ARG_ALIGN, &pfields, sizeof(MYFLT *));
302   memcpy(args+2*ARG_ALIGN, &numFields, sizeof(long));
303   return message_enqueue(csound,SCORE_EVENT, args, argsize);
304 }
305 
306 
csoundScoreEventAbsolute_enqueue(CSOUND * csound,char type,const MYFLT * pfields,long numFields,double time_ofs)307 static inline int64_t *csoundScoreEventAbsolute_enqueue(CSOUND *csound, char type,
308                                                         const MYFLT *pfields,
309                                                         long numFields,
310                                                         double time_ofs)
311 {
312   const int argsize = ARG_ALIGN*4;
313   char args[ARG_ALIGN*4];
314   args[0] = type;
315   memcpy(args+ARG_ALIGN, &pfields, sizeof(MYFLT *));
316   memcpy(args+2*ARG_ALIGN, &numFields, sizeof(long));
317   memcpy(args+3*ARG_ALIGN, &time_ofs, sizeof(double));
318   return message_enqueue(csound,SCORE_EVENT_ABS, args, argsize);
319 }
320 
321 /* this is to be called from
322    csoundKillInstanceInternal() in insert.c
323 */
killInstance_enqueue(CSOUND * csound,MYFLT instr,int insno,INSDS * ip,int mode,int allow_release)324 void killInstance_enqueue(CSOUND *csound, MYFLT instr, int insno,
325                           INSDS *ip, int mode,
326                           int allow_release) {
327   const int argsize = ARG_ALIGN*5;
328   char args[ARG_ALIGN*5];
329   memcpy(args, &instr, sizeof(int));
330   memcpy(args+ARG_ALIGN, &insno, sizeof(int));
331   memcpy(args+ARG_ALIGN*2, &ip, sizeof(INSDS *));
332   memcpy(args+ARG_ALIGN*3, &mode, sizeof(int));
333   memcpy(args+ARG_ALIGN*4, &allow_release, sizeof(int));
334   message_enqueue(csound,KILL_INSTANCE,args,argsize);
335 }
336 
337 /* this is to be called from
338    csoundCompileTreeInternal() in csound_orc_compile.c
339 */
mergeState_enqueue(CSOUND * csound,ENGINE_STATE * e,TYPE_TABLE * t,OPDS * ids)340 void mergeState_enqueue(CSOUND *csound, ENGINE_STATE *e, TYPE_TABLE* t, OPDS *ids) {
341   const int argsize = ARG_ALIGN*3;
342   char args[ARG_ALIGN*3];
343   memcpy(args, &e, sizeof(ENGINE_STATE *));
344   memcpy(args+ARG_ALIGN, &t, sizeof(TYPE_TABLE *));
345   memcpy(args+2*ARG_ALIGN, &ids, sizeof(OPDS *));
346   message_enqueue(csound,MERGE_STATE, args, argsize);
347 }
348 
349 /*  VL: These functions are slated to
350     be converted to message enqueueing
351     in the next API revision.
352 */
csoundInputMessage(CSOUND * csound,const char * message)353 void csoundInputMessage(CSOUND *csound, const char *message){
354   csoundLockMutex(csound->API_lock);
355   csoundInputMessageInternal(csound, message);
356   csoundUnlockMutex(csound->API_lock);
357 }
358 
csoundReadScore(CSOUND * csound,const char * message)359 int csoundReadScore(CSOUND *csound, const char *message){
360   int res;
361   csoundLockMutex(csound->API_lock);
362   res = csoundReadScoreInternal(csound, message);
363   csoundUnlockMutex(csound->API_lock);
364   return res;
365 }
366 
csoundTableCopyOut(CSOUND * csound,int table,MYFLT * ptable)367 void csoundTableCopyOut(CSOUND *csound, int table, MYFLT *ptable){
368 
369   csoundLockMutex(csound->API_lock);
370   csoundTableCopyOutInternal(csound, table, ptable);
371   csoundUnlockMutex(csound->API_lock);
372 }
373 
csoundTableCopyIn(CSOUND * csound,int table,MYFLT * ptable)374 void csoundTableCopyIn(CSOUND *csound, int table, MYFLT *ptable){
375   csoundLockMutex(csound->API_lock);
376   csoundTableCopyInInternal(csound, table, ptable);
377   csoundUnlockMutex(csound->API_lock);
378 }
379 
csoundTableSet(CSOUND * csound,int table,int index,MYFLT value)380 void csoundTableSet(CSOUND *csound, int table, int index, MYFLT value)
381 {
382   csoundLockMutex(csound->API_lock);
383   csoundTableSetInternal(csound, table, index, value);
384   csoundUnlockMutex(csound->API_lock);
385 }
386 
csoundScoreEvent(CSOUND * csound,char type,const MYFLT * pfields,long numFields)387 int csoundScoreEvent(CSOUND *csound, char type,
388                      const MYFLT *pfields, long numFields)
389 {
390 
391   csoundLockMutex(csound->API_lock);
392   csoundScoreEventInternal(csound, type, pfields, numFields);
393   csoundUnlockMutex(csound->API_lock);
394   return OK;
395 
396 }
397 
csoundScoreEventAbsolute(CSOUND * csound,char type,const MYFLT * pfields,long numFields,double time_ofs)398 int csoundScoreEventAbsolute(CSOUND *csound, char type,
399                              const MYFLT *pfields, long numFields,
400                              double time_ofs)
401 {
402   csoundLockMutex(csound->API_lock);
403   csoundScoreEventAbsoluteInternal(csound, type, pfields, numFields, time_ofs);
404   csoundUnlockMutex(csound->API_lock);
405   return OK;
406 }
407 
csoundKillInstance(CSOUND * csound,MYFLT instr,char * instrName,int mode,int allow_release)408 int csoundKillInstance(CSOUND *csound, MYFLT instr, char *instrName,
409                        int mode, int allow_release){
410   int async = 0;
411   return csoundKillInstanceInternal(csound, instr, instrName, mode,
412                                     allow_release, async);
413 }
414 
csoundCompileTree(CSOUND * csound,TREE * root)415 int csoundCompileTree(CSOUND *csound, TREE *root) {
416   int async = 0;
417   return csoundCompileTreeInternal(csound, root, async);
418 }
419 
csoundCompileOrc(CSOUND * csound,const char * str)420 int csoundCompileOrc(CSOUND *csound, const char *str) {
421   int async = 0;
422   return csoundCompileOrcInternal(csound, str, async);
423 }
424 
425 int init0(CSOUND *csound);
426 
csoundEvalCode(CSOUND * csound,const char * str)427 MYFLT csoundEvalCode(CSOUND *csound, const char *str)
428 {
429   int async = 0;
430   if (str && csoundCompileOrcInternal(csound,str,async)
431       == CSOUND_SUCCESS){
432     if(!(csound->engineStatus & CS_STATE_COMP)) {
433       init0(csound);
434     }
435       return csound->instr0->instance[0].retval;
436     }
437 #ifdef NAN
438   else return NAN;
439 #else
440   else return 0;
441 #endif
442 }
443 
444 /** Async versions of the functions above
445     To be removed once everything is made async
446 */
csoundInputMessageAsync(CSOUND * csound,const char * message)447 void csoundInputMessageAsync(CSOUND *csound, const char *message){
448   csoundInputMessage_enqueue(csound, message);
449 }
450 
csoundReadScoreAsync(CSOUND * csound,const char * message)451 void csoundReadScoreAsync(CSOUND *csound, const char *message){
452   csoundReadScore_enqueue(csound, message);
453 }
454 
csoundTableCopyOutAsync(CSOUND * csound,int table,MYFLT * ptable)455 void csoundTableCopyOutAsync(CSOUND *csound, int table, MYFLT *ptable){
456   csoundTableCopyOut_enqueue(csound, table, ptable);
457 }
458 
csoundTableCopyInAsync(CSOUND * csound,int table,MYFLT * ptable)459 void csoundTableCopyInAsync(CSOUND *csound, int table, MYFLT *ptable){
460   csoundTableCopyIn_enqueue(csound, table, ptable);
461 }
462 
csoundTableSetAsync(CSOUND * csound,int table,int index,MYFLT value)463 void csoundTableSetAsync(CSOUND *csound, int table, int index, MYFLT value)
464 {
465   csoundTableSet_enqueue(csound, table, index, value);
466 }
467 
csoundScoreEventAsync(CSOUND * csound,char type,const MYFLT * pfields,long numFields)468 void csoundScoreEventAsync(CSOUND *csound, char type,
469                            const MYFLT *pfields, long numFields)
470 {
471   csoundScoreEvent_enqueue(csound, type, pfields, numFields);
472 }
473 
csoundScoreEventAbsoluteAsync(CSOUND * csound,char type,const MYFLT * pfields,long numFields,double time_ofs)474 void csoundScoreEventAbsoluteAsync(CSOUND *csound, char type,
475                                    const MYFLT *pfields, long numFields,
476                                    double time_ofs)
477 {
478 
479   csoundScoreEventAbsolute_enqueue(csound, type, pfields, numFields, time_ofs);
480 }
481 
csoundCompileTreeAsync(CSOUND * csound,TREE * root)482 int csoundCompileTreeAsync(CSOUND *csound, TREE *root) {
483   int async = 1;
484   return csoundCompileTreeInternal(csound, root, async);
485 }
486 
csoundCompileOrcAsync(CSOUND * csound,const char * str)487 int csoundCompileOrcAsync(CSOUND *csound, const char *str) {
488   int async = 1;
489   return csoundCompileOrcInternal(csound, str, async);
490 }
491 
csoundKillInstanceAsync(CSOUND * csound,MYFLT instr,char * instrName,int mode,int allow_release)492 int csoundKillInstanceAsync(CSOUND *csound, MYFLT instr, char *instrName,
493                             int mode, int allow_release){
494   int async = 1;
495   return csoundKillInstanceInternal(csound, instr, instrName, mode,
496                                     allow_release, async);
497 }
498 
499 
500 
501 /* VL: the following do not depend on API_lock
502    therefore do not need to be in the message queue
503 */
504 
csoundGetControlChannel(CSOUND * csound,const char * name,int * err)505 MYFLT csoundGetControlChannel(CSOUND *csound, const char *name, int *err)
506 {
507   MYFLT *pval;
508   int err_;
509   union {
510     MYFLT d;
511     MYFLT_INT_TYPE i;
512   } x;
513   x.d = FL(0.0);
514   if (UNLIKELY(strlen(name) == 0)) return FL(.0);
515   if ((err_ = csoundGetChannelPtr(csound, &pval, name,
516                                   CSOUND_CONTROL_CHANNEL | CSOUND_OUTPUT_CHANNEL))
517       == CSOUND_SUCCESS) {
518 #if defined(MSVC)
519     x.i = InterlockedExchangeAdd64((MYFLT_INT_TYPE *)pval, 0);
520 #elif defined(HAVE_ATOMIC_BUILTIN)
521     x.i = __atomic_load_n((MYFLT_INT_TYPE *)pval, __ATOMIC_SEQ_CST);
522 #else
523     x.d = *pval;
524 #endif
525   }
526   if (err) {
527     *err = err_;
528   }
529   return x.d;
530 }
531 
csoundSetControlChannel(CSOUND * csound,const char * name,MYFLT val)532 void csoundSetControlChannel(CSOUND *csound, const char *name, MYFLT val){
533   MYFLT *pval;
534 #if defined(MSVC) || defined(HAVE_ATOMIC_BUILTIN)
535   union {
536     MYFLT d;
537     MYFLT_INT_TYPE i;
538   } x;
539   x.d = val;
540 #endif
541   if (csoundGetChannelPtr(csound, &pval, name,
542                           CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL)
543       == CSOUND_SUCCESS)
544 
545 #if defined(MSVC)
546     InterlockedExchange64((MYFLT_INT_TYPE *)pval, x.i);
547 #elif defined(HAVE_ATOMIC_BUILTIN)
548     __atomic_store_n((MYFLT_INT_TYPE *)pval, x.i, __ATOMIC_SEQ_CST);
549 #else
550   {
551     spin_lock_t *lock = (spin_lock_t *)
552       csoundGetChannelLock(csound, (char*) name);
553     csoundSpinLock(lock);
554     *pval  = val;
555     csoundSpinUnLock(lock);
556   }
557 #endif
558 }
559 
csoundGetAudioChannel(CSOUND * csound,const char * name,MYFLT * samples)560 void csoundGetAudioChannel(CSOUND *csound, const char *name, MYFLT *samples)
561 {
562 
563   MYFLT  *psamples;
564   if (strlen(name) == 0) return;
565   if (csoundGetChannelPtr(csound, &psamples, name,
566                           CSOUND_AUDIO_CHANNEL | CSOUND_OUTPUT_CHANNEL)
567       == CSOUND_SUCCESS) {
568     spin_lock_t *lock = (spin_lock_t *)csoundGetChannelLock(csound, (char*) name);
569     csoundSpinLock(lock);
570     memcpy(samples, psamples, csoundGetKsmps(csound)*sizeof(MYFLT));
571     csoundSpinUnLock(lock);
572   }
573 }
574 
csoundSetAudioChannel(CSOUND * csound,const char * name,MYFLT * samples)575 void csoundSetAudioChannel(CSOUND *csound, const char *name, MYFLT *samples)
576 {
577   MYFLT  *psamples;
578   if (csoundGetChannelPtr(csound, &psamples, name,
579                           CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL)
580       == CSOUND_SUCCESS){
581     spin_lock_t *lock = (spin_lock_t *)csoundGetChannelLock(csound, (char*) name);
582     csoundSpinLock(lock);
583     memcpy(psamples, samples, csoundGetKsmps(csound)*sizeof(MYFLT));
584     csoundSpinUnLock(lock);
585   }
586 }
587 
csoundSetStringChannel(CSOUND * csound,const char * name,char * string)588 void csoundSetStringChannel(CSOUND *csound, const char *name, char *string)
589 {
590   MYFLT  *pstring;
591 
592   if (csoundGetChannelPtr(csound, &pstring, name,
593                           CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL)
594       == CSOUND_SUCCESS){
595 
596     STRINGDAT* stringdat = (STRINGDAT*) pstring;
597     int    size = stringdat->size; //csoundGetChannelDatasize(csound, name);
598     spin_lock_t *lock = (spin_lock_t *) csoundGetChannelLock(csound, (char*) name);
599 
600     if (lock != NULL) {
601       csoundSpinLock(lock);
602     }
603 
604     if (strlen(string) + 1 > (unsigned int) size) {
605       if (stringdat->data!=NULL) csound->Free(csound,stringdat->data);
606       stringdat->data = cs_strdup(csound, string);
607       stringdat->size = strlen(string) + 1;
608       //set_channel_data_ptr(csound,name,(void*)pstring, strlen(string)+1);
609     } else {
610       strcpy((char *) stringdat->data, string);
611     }
612 
613     if (lock != NULL) {
614       csoundSpinUnLock(lock);
615     }
616   }
617 }
618 
csoundGetStringChannel(CSOUND * csound,const char * name,char * string)619 void csoundGetStringChannel(CSOUND *csound, const char *name, char *string)
620 {
621   MYFLT  *pstring;
622   char *chstring;
623   int n2;
624   if (strlen(name) == 0) return;
625   if (csoundGetChannelPtr(csound, &pstring, name,
626                           CSOUND_STRING_CHANNEL | CSOUND_OUTPUT_CHANNEL)
627       == CSOUND_SUCCESS){
628     spin_lock_t *lock = (spin_lock_t *) csoundGetChannelLock(csound, (char*) name);
629     chstring = ((STRINGDAT *) pstring)->data;
630     if (lock != NULL)
631       csoundSpinLock(lock);
632     if (string != NULL && chstring != NULL) {
633       n2 = strlen(chstring);
634       strNcpy(string,chstring, n2+1);
635       //string[n2] = '\0';
636     }
637     if (lock != NULL)
638       csoundSpinUnLock(lock);
639   }
640 }
641 
csoundSetPvsChannel(CSOUND * csound,const PVSDATEXT * fin,const char * name)642 PUBLIC int csoundSetPvsChannel(CSOUND *csound, const PVSDATEXT *fin,
643                                const char *name)
644 {
645   MYFLT *pp;
646   PVSDATEXT *f;
647   if (LIKELY(csoundGetChannelPtr(csound, &pp, name,
648                                  CSOUND_PVS_CHANNEL | CSOUND_INPUT_CHANNEL)
649              == CSOUND_SUCCESS)){
650     spin_lock_t *lock = (spin_lock_t *)
651       csoundGetChannelLock(csound, name);
652     f = (PVSDATEXT *) pp;
653     csoundSpinLock(lock);
654 
655 
656     if (f->frame == NULL) {
657       f->frame = csound->Calloc(csound, sizeof(float)*(fin->N+2));
658     } else if (f->N < fin->N) {
659       f->frame = csound->ReAlloc(csound, f->frame, sizeof(float)*(fin->N+2));
660     }
661 
662     memcpy(f, fin, sizeof(PVSDATEXT)-sizeof(float *));
663     if (fin->frame != NULL)
664       memcpy(f->frame, fin->frame, (f->N+2)*sizeof(float));
665     csoundSpinUnLock(lock);
666   } else {
667     return CSOUND_ERROR;
668   }
669   return CSOUND_SUCCESS;
670 }
671 
csoundGetPvsChannel(CSOUND * csound,PVSDATEXT * fout,const char * name)672 PUBLIC int csoundGetPvsChannel(CSOUND *csound, PVSDATEXT *fout,
673                                const char *name)
674 {
675   MYFLT *pp;
676   PVSDATEXT *f;
677   if (UNLIKELY(csoundGetChannelPtr(csound, &pp, name,
678                                    CSOUND_PVS_CHANNEL | CSOUND_OUTPUT_CHANNEL)
679                == CSOUND_SUCCESS)){
680     spin_lock_t *lock = (spin_lock_t *)
681       csoundGetChannelLock(csound, name);
682     f = (PVSDATEXT *) pp;
683     if (UNLIKELY(pp == NULL)) return CSOUND_ERROR;
684     csoundSpinLock(lock);
685     memcpy(fout, f, sizeof(PVSDATEXT)-sizeof(float *));
686     if (fout->frame != NULL && f->frame != NULL)
687       memcpy(fout->frame, f->frame, sizeof(float)*(fout->N));
688     csoundSpinUnLock(lock);
689   } else {
690     return CSOUND_ERROR;
691   }
692   return CSOUND_SUCCESS;
693 }
694