1 /*  bus.c:
2 
3  Copyright (C) 2004 John ffitch
4  (C) 2005, 2006 Istvan Varga
5  (c) 2006 Victor Lazzarini
6 
7   This file is part of Csound.
8 
9    The Csound Library is free software; you can redistribute it
10    and/or modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 2.1 of the License, or (at your option) any later version.
13 
14     Csound is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU Lesser General Public License for more details.
18 
19          You should have received a copy of the GNU Lesser General Public
20          License along with Csound; if not, write to the Free Software
21          Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22          02110-1301 USA
23 */
24 
25 /*                      BUS.C           */
26 #include "csoundCore.h"
27 #include <setjmp.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <stdio.h>
31 #ifdef NACL
32 #include <sys/select.h>
33 #endif
34 
35 #include "bus.h"
36 #include "namedins.h"
37 
38 /* For sensing opcodes */
39 #if defined(__unix) || defined(__unix__) || defined(__MACH__)
40 #  ifdef HAVE_SYS_TIME_H
41 #    include <sys/time.h>
42 #  endif
43 #  ifdef HAVE_SYS_TYPES_H
44 #    include <sys/types.h>
45 #  endif
46 #  ifdef HAVE_TERMIOS_H
47 #    include <termios.h>
48 #  endif
49 #elif defined(WIN32)
50 #  include <conio.h>
51 #endif
52 
53 
54 /* ------------------------------------------------------------------------ */
55 
56 #ifdef HAVE_C99
57 #  ifdef MYFLT2LRND
58 #    undef MYFLT2LRND
59 #  endif
60 #  ifndef USE_DOUBLE
61 #    define MYFLT2LRND  lrintf
62 #  else
63 #    define MYFLT2LRND  lrint
64 #  endif
65 #endif
66 
67 #ifdef USE_DOUBLE
68 #  define MYFLT_INT_TYPE int64_t
69 #else
70 #  define MYFLT_INT_TYPE int32_t
71 #endif
72 
73 
74 
chani_opcode_perf_k(CSOUND * csound,CHNVAL * p)75 int32_t chani_opcode_perf_k(CSOUND *csound, CHNVAL *p)
76 {
77     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
78     char chan_name[16];
79     int32_t   err;
80     MYFLT *val;
81 
82     if (UNLIKELY(n < 0))
83         return csound->PerfError(csound, &(p->h),Str("chani: invalid index"));
84 
85     snprintf(chan_name, 16, "%i", n);
86     err = csoundGetChannelPtr(csound, &val, chan_name,
87                               CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
88 
89     if (UNLIKELY(err))
90         return csound->PerfError(csound, &(p->h),
91                                  Str("chani error %d:"
92                                      "channel not found or not right type"), err);
93     *(p->r) = *val;
94     return OK;
95 }
96 
chano_opcode_perf_k(CSOUND * csound,CHNVAL * p)97 int32_t chano_opcode_perf_k(CSOUND *csound, CHNVAL *p)
98 {
99     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
100     char chan_name[16];
101     int32_t   err;
102     MYFLT *val;
103 
104     if (UNLIKELY(n < 0))
105         return csound->PerfError(csound,&(p->h),Str("chani: invalid index"));
106 
107     snprintf(chan_name, 16, "%i", n);
108     err = csoundGetChannelPtr(csound, &val, chan_name,
109                               CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
110 
111     if (UNLIKELY(err))
112         return csound->PerfError(csound, &(p->h),
113                                  Str("chano error %d:"
114                                      "channel not found or not right type"), err);
115     *val = *(p->r);
116     return OK;
117 }
118 
chani_opcode_perf_a(CSOUND * csound,CHNVAL * p)119 int32_t chani_opcode_perf_a(CSOUND *csound, CHNVAL *p)
120 {
121     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
122     uint32_t offset = p->h.insdshead->ksmps_offset;
123     uint32_t early  = p->h.insdshead->ksmps_no_end;
124 
125     char chan_name[16];
126     int32_t   err;
127     MYFLT *val;
128 
129     if (UNLIKELY(n < 0))
130         return csound->PerfError(csound, &(p->h),Str("chani: invalid index"));
131 
132     snprintf(chan_name, 16, "%i", n);
133     err = csoundGetChannelPtr(csound, &val, chan_name,
134                               CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL);
135     if (UNLIKELY(err))
136         return csound->PerfError(csound, &(p->h),
137                                  Str("chani error %d:"
138                                      "channel not found or not right type"), err);
139     if (UNLIKELY(offset)) memset(p->r, '\0', offset * sizeof(MYFLT));
140     memcpy(&p->r[offset], &val[offset],
141            sizeof(MYFLT) * (CS_KSMPS-offset-early));
142     if (UNLIKELY(early))
143         memset(&p->r[CS_KSMPS-early], '\0', early * sizeof(MYFLT));
144     return OK;
145 }
146 
chano_opcode_perf_a(CSOUND * csound,CHNVAL * p)147 int32_t chano_opcode_perf_a(CSOUND *csound, CHNVAL *p)
148 {
149     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
150     uint32_t offset = p->h.insdshead->ksmps_offset;
151     uint32_t early  = p->h.insdshead->ksmps_no_end;
152 
153     char chan_name[16];
154     int32_t   err;
155     MYFLT *val;
156 
157     if (UNLIKELY(n < 0))
158         return csound->PerfError(csound, &(p->h),Str("chani: invalid index"));
159 
160     snprintf(chan_name, 16, "%i", n);
161     err = csoundGetChannelPtr(csound, &val, chan_name,
162                               CSOUND_AUDIO_CHANNEL | CSOUND_OUTPUT_CHANNEL);
163     if (UNLIKELY(err))
164         return csound->PerfError(csound, &(p->h),
165                                  Str("chano error %d:"
166                                      "channel not found or not right type"), err);
167 
168     if (UNLIKELY(offset)) memset(&val, '\0', offset * sizeof(MYFLT));
169     memcpy(&val[offset], &p->r[offset],
170            sizeof(MYFLT) * (CS_KSMPS-offset-early));
171 
172     if (UNLIKELY(early))
173         memset(&val[CS_KSMPS-early], '\0', early * sizeof(MYFLT));
174     return OK;
175 }
176 
pvsin_init(CSOUND * csound,FCHAN * p)177 int32_t pvsin_init(CSOUND *csound, FCHAN *p)
178 {
179     int32_t N;
180     MYFLT *pp;
181     PVSDATEXT *f;
182     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
183     char name[16];
184     snprintf(name, 16, "%i", n);
185     if (csoundGetChannelPtr(csound, &pp, name,
186                             CSOUND_PVS_CHANNEL | CSOUND_INPUT_CHANNEL)
187         == CSOUND_SUCCESS){
188         spin_lock_t  *lock = (spin_lock_t *)
189                 csoundGetChannelLock(csound, name);
190         f = (PVSDATEXT *) pp;
191         csoundSpinLock(lock);
192         memcpy(&(p->init), f, sizeof(PVSDAT)-sizeof(AUXCH));
193         csoundSpinUnLock(lock);
194     }
195 
196     N = p->init.N = (int32_t)(*p->N ? *p->N : p->init.N);
197     p->init.overlap = (int32_t) (*p->overlap ? *p->overlap : p->init.overlap);
198     p->init.winsize = (int32_t) (*p->winsize ? *p->winsize : p->init.winsize);
199     p->init.wintype = (int32_t)(*p->wintype);
200     p->init.format = (int32_t)(*p->format);
201     p->init.framecount = 0;
202     memcpy(p->r, &p->init, sizeof(PVSDAT)-sizeof(AUXCH));
203     if (p->r->frame.auxp == NULL ||
204         p->r->frame.size < sizeof(float) * (N + 2))
205         csound->AuxAlloc(csound, (N + 2) * sizeof(float), &p->r->frame);
206     return OK;
207 }
208 
pvsin_perf(CSOUND * csound,FCHAN * p)209 int32_t pvsin_perf(CSOUND *csound, FCHAN *p)
210 {
211     PVSDAT *fout = p->r;
212     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
213     char chan_name[16];
214     int32_t   err, size;
215     PVSDATEXT *fin;
216     MYFLT      *pp;
217 
218     if (UNLIKELY(n < 0))
219         return csound->PerfError(csound, &(p->h),Str("pvsin: invalid index"));
220 
221     snprintf(chan_name, 16, "%i", n);
222     err = csoundGetChannelPtr(csound, &pp, chan_name,
223                               CSOUND_PVS_CHANNEL | CSOUND_INPUT_CHANNEL);
224     fin = (PVSDATEXT *) pp;
225     if (UNLIKELY(err))
226         return csound->PerfError(csound, &(p->h),
227                                  Str("pvsin error %d:"
228                                      "channel not found or not right type"), err);
229 
230     size = fin->N < fout->N ? fin->N : fout->N;
231     spin_lock_t  *lock = (spin_lock_t *) csoundGetChannelLock(csound, chan_name);
232     csoundSpinLock(lock);
233     memcpy(fout, fin, sizeof(PVSDAT)-sizeof(AUXCH));
234     //printf("fout=%p fout->frame.auxp=%p fin=%p fin->frame=%p\n",
235     //       fout, fout->frame.auxp, fin, fin->frame);
236     if(fin->frame != NULL)
237         memcpy(fout->frame.auxp, fin->frame, sizeof(float)*(size+2));
238     else memset(fout->frame.auxp, 0, sizeof(float)*(size+2));
239     csoundSpinUnLock(lock);
240     return OK;
241 }
242 
pvsout_init(CSOUND * csound,FCHAN * p)243 int32_t pvsout_init(CSOUND *csound, FCHAN *p)
244 {
245     PVSDAT *fin = p->r;
246     MYFLT *pp;
247     PVSDATEXT *f;
248     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
249     char name[16];
250 
251     snprintf(name, 16, "%i", n);
252     if (csoundGetChannelPtr(csound, &pp, name,
253                             CSOUND_PVS_CHANNEL | CSOUND_OUTPUT_CHANNEL)
254         == CSOUND_SUCCESS){
255         spin_lock_t  *lock = (spin_lock_t *)
256                 csoundGetChannelLock(csound, name);
257         f = (PVSDATEXT *) pp;
258         csoundSpinLock(lock);
259         if(f->frame == NULL) {
260             f->frame = csound->Calloc(csound, sizeof(float)*(fin->N+2));
261         } else if(f->N < fin->N) {
262             f->frame = csound->ReAlloc(csound, f->frame, sizeof(float)*(fin->N+2));
263         }
264         memcpy(f, fin, sizeof(PVSDAT)-sizeof(AUXCH));
265         csoundSpinUnLock(lock);
266     }
267     return OK;
268 }
269 
270 
pvsout_perf(CSOUND * csound,FCHAN * p)271 int32_t pvsout_perf(CSOUND *csound, FCHAN *p)
272 {
273 
274     PVSDAT *fin = p->r;
275     int32_t     n = (int32_t)MYFLT2LRND(*(p->a));
276     char chan_name[16];
277     int32_t   err, size;
278     PVSDATEXT *fout;
279     MYFLT *pp;
280 
281     if (UNLIKELY(n < 0))
282         return csound->PerfError(csound, &(p->h),Str("pvsout: invalid index"));
283 
284     snprintf(chan_name, 16, "%i", n);
285     err = csoundGetChannelPtr(csound, &pp, chan_name,
286                               CSOUND_PVS_CHANNEL | CSOUND_OUTPUT_CHANNEL);
287     fout = (PVSDATEXT *) pp;
288     if (UNLIKELY(err))
289         return csound->PerfError(csound, &(p->h),
290                                  Str("pvsout error %d:"
291                                      "channel not found or not right type"), err);
292 
293     spin_lock_t  *lock = (spin_lock_t *) csoundGetChannelLock(csound, chan_name);
294     csoundSpinLock(lock);
295     size = fin->N < fout->N ? fin->N : fout->N;
296     memcpy(fout, fin, sizeof(PVSDAT)-sizeof(AUXCH));
297     if(fout->frame != NULL)
298         memcpy(fout->frame, fin->frame.auxp, sizeof(float)*(size+2));
299     csoundSpinUnLock(lock);
300     return OK;
301 }
302 /* ======================================================================== */
303 
304 /* "chn" opcodes and bus interface by Istvan Varga */
305 
delete_channel_db(CSOUND * csound,void * p)306 static int32_t delete_channel_db(CSOUND *csound, void *p)
307 {
308     CONS_CELL *head, *values;
309     IGN(p);
310     if (csound->chn_db == NULL) {
311         return 0;
312     }
313 
314     head = values = cs_hash_table_values(csound, csound->chn_db);
315 
316     if (head != NULL) {
317         while(values != NULL) {
318             CHNENTRY* entry = values->value;
319 
320             if ((entry->type & CSOUND_CHANNEL_TYPE_MASK) != CSOUND_CONTROL_CHANNEL) {
321                 csound->Free(csound, entry->hints.attributes);
322             }
323             /* SY - 2014.07.14 - Don't free entry->data and rely on Csound memory db
324                to free it; fixes issue with RTTI and chnexport of a global var, which
325                maps to the CS_VAR_MEM's memblock, which is not what is allocated; other
326                vars will be freed since they were Calloc'd */
327             /*          csound->Free(csound, entry->data); */
328             entry->datasize = 0;
329             values = values->next;
330         }
331         cs_cons_free(csound, head);
332     }
333 
334     cs_hash_table_mfree_complete(csound, csound->chn_db);
335     csound->chn_db = NULL;
336     return 0;
337 }
338 
find_channel(CSOUND * csound,const char * name)339 static inline CHNENTRY *find_channel(CSOUND *csound, const char *name)
340 {
341     if (csound->chn_db != NULL && name[0]) {
342         return (CHNENTRY*) cs_hash_table_get(csound, csound->chn_db, (char*) name);
343     }
344     return NULL;
345 }
346 
set_channel_data_ptr(CSOUND * csound,const char * name,void * ptr,int32_t newSize)347 void set_channel_data_ptr(CSOUND *csound,
348                           const char *name, void *ptr, int32_t newSize)
349 {
350     find_channel(csound, name)->data = (MYFLT *) ptr;
351     find_channel(csound, name)->datasize = newSize;
352 }
353 
354 #define INIT_STRING_CHANNEL_DATASIZE 256
355 
alloc_channel(CSOUND * csound,const char * name,int32_t type)356 static CS_NOINLINE CHNENTRY *alloc_channel(CSOUND *csound,
357                                            const char *name, int32_t type)
358 {
359     CHNENTRY      *pp;
360     int32_t           dsize = 0;
361     switch (type & CSOUND_CHANNEL_TYPE_MASK) {
362         case CSOUND_CONTROL_CHANNEL:
363             dsize = sizeof(MYFLT);
364             break;
365         case CSOUND_AUDIO_CHANNEL:
366             dsize = ((int32_t)sizeof(MYFLT) * csound->ksmps);
367             break;
368         case CSOUND_STRING_CHANNEL:
369             dsize = (sizeof(STRINGDAT));
370             break;
371         case CSOUND_PVS_CHANNEL:
372             dsize = (sizeof(PVSDATEXT));
373             break;
374     }
375     pp = (CHNENTRY *) csound->Calloc(csound,
376                                      (size_t) sizeof(CHNENTRY) + strlen(name) + 1);
377     if (pp == NULL) return (CHNENTRY*) NULL;
378     pp->data = (MYFLT *) csound->Calloc(csound, dsize);
379 
380     if ((type & CSOUND_CHANNEL_TYPE_MASK) == CSOUND_STRING_CHANNEL) {
381         ((STRINGDAT*) pp->data)->size = 128;
382         ((STRINGDAT*) pp->data)->data = csound->Calloc(csound, 128 * sizeof(char));
383     }
384 
385     csoundSpinLockInit(&pp->lock);
386     pp->datasize = dsize;
387 
388     return (CHNENTRY*) pp;
389 }
390 
create_new_channel(CSOUND * csound,const char * name,int32_t type)391 static CS_NOINLINE int32_t create_new_channel(CSOUND *csound, const char *name,
392                                               int32_t type)
393 {
394     CHNENTRY      *pp;
395     /* check for valid parameters and calculate hash value */
396     if (UNLIKELY(!(type & 48)))
397         return CSOUND_ERROR;
398 
399     /* create new empty database if not allocated */
400     if (csound->chn_db == NULL) {
401         csound->chn_db = cs_hash_table_create(csound);
402         if (UNLIKELY(csound->RegisterResetCallback(csound, NULL,
403                                                    delete_channel_db) != 0))
404             return CSOUND_MEMORY;
405         if (UNLIKELY(csound->chn_db == NULL))
406             return CSOUND_MEMORY;
407     }
408     /* allocate new entry */
409     pp = alloc_channel(csound, name, type);
410     if (UNLIKELY(pp == NULL))
411         return CSOUND_MEMORY;
412     pp->hints.behav = 0;
413     pp->type = type;
414     strcpy(&(pp->name[0]), name);
415 
416     cs_hash_table_put(csound, csound->chn_db, (char*)name, pp);
417 
418     return CSOUND_SUCCESS;
419 }
420 
421 
csoundGetChannelPtr(CSOUND * csound,MYFLT ** p,const char * name,int32_t type)422 PUBLIC int32_t csoundGetChannelPtr(CSOUND *csound,
423                                    MYFLT **p, const char *name, int32_t type)
424 {
425     CHNENTRY  *pp;
426 
427     *p = (MYFLT*) NULL;
428     if (UNLIKELY(name == NULL))
429         return CSOUND_ERROR;
430     pp = find_channel(csound, name);
431     if (!pp) {
432         if (create_new_channel(csound, name, type) == CSOUND_SUCCESS) {
433             pp = find_channel(csound, name);
434         }
435     }
436     if (pp != NULL) {
437         if ((pp->type ^ type) & CSOUND_CHANNEL_TYPE_MASK)
438             return pp->type;
439         pp->type |= (type & (CSOUND_INPUT_CHANNEL | CSOUND_OUTPUT_CHANNEL));
440         *p = pp->data;
441         return CSOUND_SUCCESS;
442     }
443     return CSOUND_ERROR;
444 }
445 
csoundGetChannelDatasize(CSOUND * csound,const char * name)446 PUBLIC int32_t csoundGetChannelDatasize(CSOUND *csound, const char *name){
447 
448     CHNENTRY  *pp;
449     pp = find_channel(csound, name);
450     if (pp == NULL) return 0;
451     else {
452         /* the reason for this is that if chnexport is
453            used with strings, the datasize might become
454            invalid */
455         if ((pp->type & CSOUND_STRING_CHANNEL) == CSOUND_STRING_CHANNEL)
456             return ((STRINGDAT*)pp->data)->size;
457         return pp->datasize;
458     }
459 }
460 
461 
csoundGetChannelLock(CSOUND * csound,const char * name)462 PUBLIC int32_t *csoundGetChannelLock(CSOUND *csound,
463                                      const char *name)
464 {
465     CHNENTRY  *pp;
466 
467     if (UNLIKELY(name == NULL))
468         return NULL;
469     pp = find_channel(csound, name);
470     if (pp) {
471         return (int32_t*) &pp->lock;
472     }
473     else return NULL;
474 }
475 
cmp_func(const void * p1,const void * p2)476 static int32_t cmp_func(const void *p1, const void *p2)
477 {
478     return strcmp(((controlChannelInfo_t*) p1)->name,
479                   ((controlChannelInfo_t*) p2)->name);
480 }
481 
csoundListChannels(CSOUND * csound,controlChannelInfo_t ** lst)482 PUBLIC int32_t csoundListChannels(CSOUND *csound, controlChannelInfo_t **lst)
483 {
484     CHNENTRY  *pp;
485     size_t     n;
486     CONS_CELL* channels;
487 
488     *lst = (controlChannelInfo_t*) NULL;
489     if (csound->chn_db == NULL)
490         return 0;
491 
492     channels = cs_hash_table_values(csound, csound->chn_db);
493     n = cs_cons_length(channels);
494 
495     if (!n)
496         return 0;
497 
498     /* create list, initially in unsorted order */
499     //  csound->Malloc and the caller has to free it.
500     // if not, it will be freed on reset
501     *lst = (controlChannelInfo_t*) csound->Malloc(csound,
502                                                   n * sizeof(controlChannelInfo_t));
503     if (UNLIKELY(*lst == NULL))
504         return CSOUND_MEMORY;
505 
506     n = 0;
507     while (channels != NULL) {
508         pp = channels->value;
509         (*lst)[n].name = pp->name;
510         (*lst)[n].type = pp->type;
511         (*lst)[n].hints = pp->hints;
512         channels = channels->next;
513         n++;
514     }
515 
516     /* sort list */
517     qsort((void*) (*lst), n, sizeof(controlChannelInfo_t), cmp_func);
518     /* return the number of channels */
519     return (int32_t)n;
520 }
521 
csoundDeleteChannelList(CSOUND * csound,controlChannelInfo_t * lst)522 PUBLIC void csoundDeleteChannelList(CSOUND *csound, controlChannelInfo_t *lst)
523 {
524     //(void) csound;
525     if (lst != NULL) csound->Free(csound, lst);
526 }
527 
csoundSetControlChannelHints(CSOUND * csound,const char * name,controlChannelHints_t hints)528 PUBLIC int32_t csoundSetControlChannelHints(CSOUND *csound, const char *name,
529                                             controlChannelHints_t hints)
530 {
531     CHNENTRY  *pp;
532 
533     if (UNLIKELY(name == NULL))
534         return CSOUND_ERROR;
535     pp = find_channel(csound, name);
536     if (UNLIKELY(pp == NULL))
537         return CSOUND_ERROR;
538     if (UNLIKELY((pp->type & CSOUND_CHANNEL_TYPE_MASK) != CSOUND_CONTROL_CHANNEL))
539         return CSOUND_ERROR;
540     if  (hints.behav == CSOUND_CONTROL_CHANNEL_NO_HINTS) {
541         pp->hints.behav = CSOUND_CONTROL_CHANNEL_NO_HINTS;
542         return 0;
543     }
544     if  (hints.behav == CSOUND_CONTROL_CHANNEL_INT) {
545         hints.dflt = (MYFLT) ((int32_t) MYFLT2LRND(hints.dflt));
546         hints.min  = (MYFLT) ((int32_t) MYFLT2LRND(hints.min));
547         hints.max  = (MYFLT) ((int32_t) MYFLT2LRND(hints.max));
548     }
549     if (UNLIKELY(hints.min > hints.max || hints.dflt < hints.min ||
550                  hints.dflt > hints.max ||
551                  (hints.behav == CSOUND_CONTROL_CHANNEL_EXP &&
552                   ((hints.min * hints.max) <= FL(0.0))))) {
553         return CSOUND_ERROR;
554     }
555 
556     pp->hints = hints;
557     if (hints.attributes) {
558         pp->hints.attributes
559                 = (char *) csound->Malloc(csound,
560                                           (strlen(hints.attributes) + 1)* sizeof(char));
561         strcpy(pp->hints.attributes, hints.attributes);
562     }
563     return CSOUND_SUCCESS;
564 }
565 
566 /**
567 * Returns special parameters (assuming there are any) of a control channel,
568 * previously set with csoundSetControlChannelHints().
569 * If the channel exists, is a control channel, and has the special parameters
570 * assigned, then the default, minimum, and maximum value is stored in *dflt,
571 * *min, and *max, respectively, and a positive value that is one of
572 * CSOUND_CONTROL_CHANNEL_INT, CSOUND_CONTROL_CHANNEL_LIN, and
573 * CSOUND_CONTROL_CHANNEL_EXP is returned.
574 * In any other case, *dflt, *min, and *max are not changed, and the return
575 * value is zero if the channel exists, is a control channel, but has no
576 * special parameters set; otherwise, a negative error code is returned.
577 */
578 
csoundGetControlChannelHints(CSOUND * csound,const char * name,controlChannelHints_t * hints)579 PUBLIC int32_t csoundGetControlChannelHints(CSOUND *csound, const char *name,
580                                             controlChannelHints_t *hints)
581 {
582     CHNENTRY  *pp;
583 
584     if (UNLIKELY(name == NULL))
585         return CSOUND_ERROR;
586     pp = find_channel(csound, name);
587     if (pp == NULL)
588         return CSOUND_ERROR;
589     if ((pp->type & CSOUND_CHANNEL_TYPE_MASK) != CSOUND_CONTROL_CHANNEL)
590         return CSOUND_ERROR;
591     if (pp->hints.behav == 0)
592         return CSOUND_ERROR;
593     *hints = pp->hints;
594     if (pp->hints.attributes) {
595         hints->attributes
596                 = (char *) csound->Malloc(csound,
597                                           strlen(pp->hints.attributes) + 1);
598         strcpy(hints->attributes, pp->hints.attributes);
599     }
600     return 0;
601 }
602 
603 /* ------------------------------------------------------------------------ */
604 
605 /* perf time stub for printing "not initialised" error message */
606 
notinit_opcode_stub(CSOUND * csound,void * p)607 int32_t notinit_opcode_stub(CSOUND *csound, void *p)
608 {
609     return csound->PerfError(csound, &(((CHNGET *)p)->h),
610                              Str("%s: not initialised"),
611                              csound->GetOpcodeName(p));
612 }
613 
614 /* print error message on failed channel query */
615 
print_chn_err_perf(void * p,int32_t err)616 static CS_NOINLINE void print_chn_err_perf(void *p, int32_t err)
617 {
618     CSOUND      *csound = ((OPDS*) p)->insdshead->csound;
619     const char  *msg;
620 
621     if (((OPDS*) p)->opadr != (SUBR) NULL)
622         ((OPDS*) p)->opadr = (SUBR) notinit_opcode_stub;
623     if (err == CSOUND_MEMORY)
624         msg = "memory allocation failure";
625     else if (err < 0)
626         msg = "invalid channel name";
627     else
628         msg = "channel already exists with incompatible type";
629     csound->Warning(csound, "%s", Str(msg));
630 }
631 
print_chn_err(void * p,int32_t err)632 static CS_NOINLINE int32_t print_chn_err(void *p, int32_t err)
633 {
634     CSOUND      *csound = ((OPDS*) p)->insdshead->csound;
635     const char  *msg;
636 
637     if (((OPDS*) p)->opadr != (SUBR) NULL)
638         ((OPDS*) p)->opadr = (SUBR) notinit_opcode_stub;
639     if (err == CSOUND_MEMORY)
640         msg = "memory allocation failure";
641     else if (err < 0)
642         msg = "invalid channel name";
643     else
644         msg = "channel already exists with incompatible type";
645     return csound->InitError(csound, "%s", Str(msg));
646 }
647 
648 
649 /* receive control value from bus at performance time */
chnget_opcode_perf_k(CSOUND * csound,CHNGET * p)650 static int32_t chnget_opcode_perf_k(CSOUND* csound, CHNGET* p)
651 {
652     if (strncmp(p->chname, p->iname->data, MAX_CHAN_NAME) || !strcmp(p->iname->data, ""))
653     {
654         int32_t err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
655                                           CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
656         if (err==0){
657             p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
658             strNcpy(p->chname, p->iname->data, MAX_CHAN_NAME);
659         }
660         else {
661             print_chn_err_perf(p, err);
662             return OK;
663         }
664     }
665 
666 #if defined(MSVC)
667     volatile union {
668     MYFLT d;
669     MYFLT_INT_TYPE i;
670     } x;
671     x.i = InterlockedExchangeAdd64((MYFLT_INT_TYPE *) p->fp, 0);
672     *(p->arg) = x.d;
673 #elif defined(HAVE_ATOMIC_BUILTIN)
674     volatile union {
675         MYFLT d;
676         MYFLT_INT_TYPE i;
677     } x;
678     x.i = __atomic_load_n((MYFLT_INT_TYPE*) p->fp, __ATOMIC_SEQ_CST);
679     *(p->arg) = x.d;
680 #else
681     *(p->arg) = *(p->fp);
682 #endif
683     return OK;
684 }
685 
686 /* receive audio data from bus at performance time */
chnget_opcode_perf_a(CSOUND * csound,CHNGET * p)687 static int32_t chnget_opcode_perf_a(CSOUND* csound, CHNGET* p)
688 {
689     uint32_t offset = p->h.insdshead->ksmps_offset;
690     uint32_t early = p->h.insdshead->ksmps_no_end;
691 
692     if (strncmp(p->chname, p->iname->data, MAX_CHAN_NAME)  || !strcmp(p->iname->data, ""))
693     {
694         int32_t err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
695                                           CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL);
696         if (err==0){
697             p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
698             strNcpy(p->chname, p->iname->data, MAX_CHAN_NAME);
699         }
700         else {
701             print_chn_err_perf(p, err);
702             return OK;
703         }
704     }
705 
706     if (CS_KSMPS==(uint32_t) csound->ksmps){
707         csoundSpinLock(p->lock);
708         if (UNLIKELY(offset)) memset(p->arg, '\0', offset);
709         memcpy(&p->arg[offset], p->fp, sizeof(MYFLT)*(CS_KSMPS-offset-early));
710         if (UNLIKELY(early))
711             memset(&p->arg[CS_KSMPS-early], '\0', sizeof(MYFLT)*early);
712         csoundSpinUnLock(p->lock);
713     }
714     else {
715         csoundSpinLock(p->lock);
716         if (UNLIKELY(offset)) memset(p->arg, '\0', offset);
717         memcpy(&p->arg[offset], &(p->fp[offset+p->pos]),
718                sizeof(MYFLT)*(CS_KSMPS-offset-early));
719         if (UNLIKELY(early))
720             memset(&p->arg[CS_KSMPS-early], '\0', sizeof(MYFLT)*early);
721         p->pos += CS_KSMPS;
722         p->pos %= (csound->ksmps-offset);
723         csoundSpinUnLock(p->lock);
724     }
725 
726     return OK;
727 }
728 
729 /* receive control value from bus at init time */
chnget_opcode_init_i(CSOUND * csound,CHNGET * p)730 int32_t chnget_opcode_init_i(CSOUND *csound, CHNGET *p)
731 {
732     int32_t   err;
733     err = csoundGetChannelPtr(csound, &(p->fp), p->iname->data,
734                               CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
735     if (UNLIKELY(err))
736         return print_chn_err(p, err);
737 #if defined(MSVC)
738     {
739     union {
740         MYFLT d;
741         MYFLT_INT_TYPE i;
742     } x;
743     x.i = InterlockedExchangeAdd64((MYFLT_INT_TYPE *)p->fp, 0);
744     *(p->arg) = x.d;
745     }
746 #elif defined(HAVE_ATOMIC_BUILTIN)
747     {
748         union {
749             MYFLT d;
750             MYFLT_INT_TYPE i;
751         } x;
752         x.i = __atomic_load_n((MYFLT_INT_TYPE *) p->fp, __ATOMIC_SEQ_CST);
753         *(p->arg) =  x.d;
754     }
755 #else
756     *(p->arg) = *(p->fp);
757 #endif
758 
759     return OK;
760 }
761 
762 /* init routine for i-rate chnget array opcode (control data) */
763 
chnget_array_opcode_init_i(CSOUND * csound,CHNGETARRAY * p)764 int32_t chnget_array_opcode_init_i(CSOUND* csound, CHNGETARRAY* p)
765 {
766     int index = 0;
767     ARRAYDAT* arr = (ARRAYDAT*) p->iname;
768 
769     p->arraySize = arr->sizes[0];
770     p->channels = (STRINGDAT*) arr->data;
771 
772     tabinit(csound, p->arrayDat, p->arraySize);
773 
774     int32_t err;
775     MYFLT* fp;
776 
777     for (index = 0; index<p->arraySize; index++)
778     {
779         err = csoundGetChannelPtr(csound, &(fp), p->channels[index].data,
780                                   CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
781 
782         if (UNLIKELY(err))
783             return print_chn_err(p, err);
784 #if defined(MSVC)
785         {
786         union {
787             MYFLT d;
788             MYFLT_INT_TYPE i;
789         } x;
790         x.i = InterlockedExchangeAdd64((MYFLT_INT_TYPE *)fp, 0);
791         p->arrayDat->data[index] = x.d;
792         }
793 #elif defined(HAVE_ATOMIC_BUILTIN)
794         {
795             union {
796                 MYFLT d;
797                 MYFLT_INT_TYPE i;
798             } x;
799             x.i = __atomic_load_n((MYFLT_INT_TYPE*) fp, __ATOMIC_SEQ_CST);
800             p->arrayDat->data[index] = x.d;
801         }
802 #else
803         p->arrayDat->data[index] = *(fp);
804 #endif
805     }
806     return OK;
807 }
808 
809 /* init routine for k, a and S chnget array opcodes */
chnget_array_opcode_init(CSOUND * csound,CHNGETARRAY * p)810 int32_t chnget_array_opcode_init(CSOUND* csound, CHNGETARRAY* p)
811 {
812     ARRAYDAT* arr = (ARRAYDAT*) p->iname;
813     int index = 0;
814     p->arraySize = arr->sizes[0];
815     p->channels = (STRINGDAT*) arr->data;
816     p->channelPtrs = malloc(p->arraySize*sizeof(MYFLT));
817     tabinit(csound, p->arrayDat, p->arraySize);
818 
819     int32_t err;
820     int32_t channelType;
821 
822     if (strcmp("k", p->arrayDat->arrayType->varTypeName) == 0)
823         channelType = CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL;
824     else if(strcmp("a", p->arrayDat->arrayType->varTypeName) == 0)
825         channelType = CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL;
826     else
827         channelType = CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL;
828 
829     STRINGDAT *strings = (STRINGDAT *)p->arrayDat->data;
830     for (index = 0; index<p->arraySize; index++)
831     {
832         if(strcmp(p->channels[index].data, "")) {
833             err = csoundGetChannelPtr(csound, &p->channelPtrs[index], p->channels[index].data,
834                                       channelType);
835 
836             if (LIKELY(!err)) {
837                 p->lock = (spin_lock_t *) csoundGetChannelLock(csound, p->channels[index].data);
838                 strNcpy(p->chname, p->channels[index].data, MAX_CHAN_NAME);
839 
840                 if(channelType == (CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL)){
841                     csoundSpinLock(p->lock);
842                     strings[index].data = cs_strdup(csound, ((STRINGDAT *)p->channelPtrs[index])->data);
843                     strings[index].size = strlen(((STRINGDAT *)p->channelPtrs[index])->data + 1);
844                     csoundSpinUnLock(p->lock);
845                 }
846             }
847         }
848         else{
849             return csound->InitError(csound, "%s%s", Str("invalid channel name:"),
850                     !strcmp(p->channels[index].data, "") ? Str("\"empty\"") : Str(p->channels[index].data));
851         }
852     }
853 
854     if(channelType == (CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL))
855         p->h.opadr = (SUBR) chnget_array_opcode_perf_k;
856     else if(channelType == (CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL))
857         p->h.opadr = (SUBR) chnget_array_opcode_perf_a;
858     else
859         p->h.opadr = (SUBR) chnget_array_opcode_perf_S;
860 
861     return OK;
862 }
863 
864 /* perf routine for chnget array opcode (control data) */
865 
chnget_array_opcode_perf_k(CSOUND * csound,CHNGETARRAY * p)866 int32_t chnget_array_opcode_perf_k(CSOUND* csound, CHNGETARRAY* p)
867 {
868     int index = 0;
869 
870     for (index = 0; index<p->arraySize; index++)
871     {
872 #if defined(MSVC)
873         volatile union {
874         MYFLT d;
875         MYFLT_INT_TYPE i;
876         } x;
877         x.i = InterlockedExchangeAdd64((MYFLT_INT_TYPE *) p->channelPtrs[index], 0);
878         p->arrayDat->data[index] = x.d;
879 #elif defined(HAVE_ATOMIC_BUILTIN)
880         volatile union {
881             MYFLT d;
882             MYFLT_INT_TYPE i;
883         } x;
884         x.i = __atomic_load_n((MYFLT_INT_TYPE*) p->channelPtrs[index], __ATOMIC_SEQ_CST);
885         p->arrayDat->data[index] = x.d;
886 //        csound->Message(csound, Str("%f"), p->channelPtrs[index]);
887 #else
888         p->arrayDat->data[index] = *(p->channelPtrs[index]);
889 #endif
890 
891     }
892     return OK;
893 }
894 
895 /* perf routine for chnget array opcode (audio data) */
896 
chnget_array_opcode_perf_a(CSOUND * csound,CHNGETARRAY * p)897 int32_t chnget_array_opcode_perf_a(CSOUND *csound, CHNGETARRAY *p)
898 {
899     uint32_t offset = p->h.insdshead->ksmps_offset;
900     uint32_t early  = p->h.insdshead->ksmps_no_end;
901 
902     int index = 0;
903     int blockIndex = 0;
904     MYFLT* outPtr;
905     for (index = 0; index<p->arraySize; index++) {
906         blockIndex = csound->ksmps*index;
907 
908         if (CS_KSMPS == (uint32_t) csound->ksmps) {
909             csoundSpinLock(p->lock);
910             if (UNLIKELY(offset)) memset(&p->arrayDat->data[blockIndex], '\0', offset);
911             memcpy(&p->arrayDat->data[blockIndex+offset], p->channelPtrs[index], sizeof(MYFLT) * (CS_KSMPS - offset - early));
912             if (UNLIKELY(early))
913                 memset(&p->arrayDat->data[blockIndex+CS_KSMPS - early], '\0', sizeof(MYFLT) * early);
914             csoundSpinUnLock(p->lock);
915         } else {
916             csoundSpinLock(p->lock);
917             if (UNLIKELY(offset)) memset(&outPtr, '\0', offset);
918             memcpy(&p->arrayDat->data[blockIndex+offset], &(p->channelPtrs[index][offset + p->pos]),
919                    sizeof(MYFLT) * (CS_KSMPS - offset - early));
920             if (UNLIKELY(early))
921                 memset(&p->arrayDat->data[blockIndex+CS_KSMPS - early], '\0', sizeof(MYFLT) * early);
922             p->pos += CS_KSMPS;
923             p->pos %= (csound->ksmps - offset);
924             csoundSpinUnLock(p->lock);
925         }
926     }
927 
928     return OK;
929 }
930 
931 
chnget_array_opcode_perf_S(CSOUND * csound,CHNGETARRAY * p)932 int32_t chnget_array_opcode_perf_S(CSOUND* csound, CHNGETARRAY* p)
933 {
934     STRINGDAT *strings = (STRINGDAT *)p->arrayDat->data;
935     int32_t err;
936     int index = 0;
937 
938     for (index = 0; index<p->arraySize; index++) {
939         err = csoundGetChannelPtr(csound, &p->channelPtrs[index], p->channels[index].data,
940                                   CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL);
941 
942         if (UNLIKELY(err))
943             return print_chn_err(p, err);
944 
945         p->lock = (spin_lock_t *) csoundGetChannelLock(csound, (char *) p->channels[index].data);
946         csoundSpinLock(p->lock);
947         strings[index].data = cs_strdup(csound, ((STRINGDAT *)p->channelPtrs[index])->data);
948         strings[index].size = strlen(((STRINGDAT *)p->channelPtrs[index])->data + 1);
949         csoundSpinUnLock(p->lock);
950     }
951 
952     return OK;
953 }
954 
955 /* chnset array opcode init function for S arrays */
956 
chnset_array_opcode_init_i(CSOUND * csound,CHNGETARRAY * p)957 int32_t chnset_array_opcode_init_i(CSOUND *csound, CHNGETARRAY *p)
958 {
959     int32_t   err;
960 
961     int index = 0;
962     ARRAYDAT* valueArr = (ARRAYDAT*) p->arrayDat;
963     ARRAYDAT* channelArr = (ARRAYDAT*) p->iname;
964     p->arraySize = channelArr->sizes[0];
965     p->channels = (STRINGDAT*) channelArr->data;
966     p->channelPtrs = malloc(p->arraySize*sizeof(MYFLT));
967 
968     for (index = 0; index<p->arraySize; index++) {
969         err = csoundGetChannelPtr(csound, &p->channelPtrs[index], (char *) p->channels[index].data,
970                                   CSOUND_CONTROL_CHANNEL | CSOUND_OUTPUT_CHANNEL);
971         if (UNLIKELY(err))
972             return print_chn_err(p, err);
973 
974 #if defined(MSVC)
975         volatile union {
976       MYFLT d;
977       MYFLT_INT_TYPE i;
978     } x;
979     x.d = valueArr->data[index];
980     InterlockedExchange64((MYFLT_INT_TYPE *) p->channelPtrs[index], x.i);
981 #elif defined(HAVE_ATOMIC_BUILTIN)
982         union {
983             MYFLT d;
984             MYFLT_INT_TYPE i;
985         } x;
986         x.d = valueArr->data[index];
987         __atomic_store_n((MYFLT_INT_TYPE *)(p->channelPtrs[index]),x.i, __ATOMIC_SEQ_CST);
988 #else
989         {
990       spin_lock_t *lock;       /* Need lock for the channel */
991       p->lock = lock =  (spin_lock_t *)
992         csoundGetChannelLock(csound, (char*) p->iname->data);
993       csoundSpinLock(lock);
994       *(p->channelPtrs[index]) =  valueArr->data[index];
995       csoundSpinUnLock(lock);
996     }
997 #endif
998     }
999 
1000 
1001     return OK;
1002 }
1003 
1004 /* init routine for chnset array opcodes - a, k and S */
1005 
chnset_array_opcode_init(CSOUND * csound,CHNGETARRAY * p)1006 int32_t chnset_array_opcode_init(CSOUND* csound, CHNGETARRAY* p)
1007 {
1008     int32_t err;
1009     int index = 0;
1010 
1011     ARRAYDAT* channelArr = (ARRAYDAT*) p->iname;
1012     p->arraySize = channelArr->sizes[0];
1013     p->channels = (STRINGDAT*) channelArr->data;
1014     p->channelPtrs = malloc(p->arraySize*sizeof(MYFLT));
1015 
1016     int32_t channelType;
1017 
1018     if (strcmp("k", p->arrayDat->arrayType->varTypeName) == 0)
1019         channelType = CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL;
1020     else if(strcmp("a", p->arrayDat->arrayType->varTypeName) == 0)
1021         channelType = CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL;
1022     else
1023         channelType = CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL;
1024 
1025     for (index = 0; index<p->arraySize; index++) {
1026         err = csoundGetChannelPtr(csound, &(p->channelPtrs[index]), (char *) p->channels[index].data,
1027                                   channelType);
1028         if (LIKELY(!err)) {
1029             p->lock = (spin_lock_t *) csoundGetChannelLock(csound, (char *) p->channels[index].data);
1030             strNcpy(p->chname, p->channels[index].data, MAX_CHAN_NAME);
1031         }
1032     }
1033 
1034     if(channelType == (CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL))
1035         p->h.opadr = (SUBR) chnset_array_opcode_perf_k;
1036     else if(channelType == (CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL))
1037         p->h.opadr = (SUBR) chnset_array_opcode_perf_a;
1038     else
1039         p->h.opadr = (SUBR) chnset_array_opcode_perf_S;
1040 
1041     return OK;
1042 }
1043 
1044 /* send control value to bus at performance time */
1045 
chnset_array_opcode_perf_k(CSOUND * csound,CHNGETARRAY * p)1046 int32_t chnset_array_opcode_perf_k(CSOUND *csound, CHNGETARRAY *p)
1047 {
1048     int index = 0;
1049     ARRAYDAT* valueArr = (ARRAYDAT*) p->arrayDat;
1050 
1051     for (index = 0; index<p->arraySize; index++) {
1052         if (strncmp(p->chname, p->channels[index].data, MAX_CHAN_NAME)) {
1053             int32_t err = csoundGetChannelPtr(csound, &(p->channelPtrs[index]), (char *) p->channels[index].data,
1054                                               CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
1055             if (err == 0) {
1056                 p->lock = (spin_lock_t *) csoundGetChannelLock(csound, (char *) p->channels[index].data);
1057             } else
1058                 print_chn_err_perf(p, err);
1059         }
1060 
1061 #if defined(MSVC)
1062         volatile union {
1063           MYFLT d;
1064           MYFLT_INT_TYPE i;
1065         } x;
1066         x.d = valueArr->data[index];
1067         InterlockedExchange64((MYFLT_INT_TYPE *) p->channelPtrs[index], x.i);
1068 #elif defined(HAVE_ATOMIC_BUILTIN)
1069         union {
1070             MYFLT d;
1071             MYFLT_INT_TYPE i;
1072         } x;
1073         x.d = valueArr->data[index];
1074         __atomic_store_n((MYFLT_INT_TYPE *) (p->channelPtrs[index]), x.i, __ATOMIC_SEQ_CST);
1075 #else
1076         csoundSpinLock(p->lock);
1077         *(p->channelPtrs[index]) = valueArr->data[index];
1078         csoundSpinUnLock(p->lock);
1079 #endif
1080     }
1081     return OK;
1082 }
1083 
1084 /* perf routine for chnset array opcode (audio data) */
1085 
chnset_array_opcode_perf_a(CSOUND * csound,CHNGETARRAY * p)1086 int32_t chnset_array_opcode_perf_a(CSOUND *csound, CHNGETARRAY *p)
1087 {
1088     uint32_t offset = p->h.insdshead->ksmps_offset;
1089     uint32_t early  = p->h.insdshead->ksmps_no_end;
1090     ARRAYDAT* valueArr = (ARRAYDAT*) p->arrayDat;
1091     int index = 0;
1092     int blockIndex = 0;
1093 
1094     for (index = 0; index<p->arraySize; index++) {
1095         if(CS_KSMPS == (uint32_t) csound->ksmps){
1096             blockIndex = csound->ksmps*index;
1097             /* Need lock for the channel */
1098             csoundSpinLock(p->lock);
1099             if (UNLIKELY(offset)) memset(p->channelPtrs[index], '\0', sizeof(MYFLT)*offset);
1100             memcpy(&p->channelPtrs[index][offset], &valueArr->data[blockIndex+offset],
1101                    sizeof(MYFLT)*(CS_KSMPS-offset-early));
1102             if (UNLIKELY(early))
1103                 memset(&p->channelPtrs[index][early], '\0', sizeof(MYFLT)*(CS_KSMPS-early));
1104             csoundSpinUnLock(p->lock);
1105         } else {
1106             /* Need lock for the channel */
1107             csoundSpinLock(p->lock);
1108             if (UNLIKELY(offset)) memset(p->channelPtrs[index], '\0', sizeof(MYFLT)*offset);
1109             memcpy(&p->channelPtrs[index][offset+p->pos], &valueArr->data[blockIndex+offset],
1110                    sizeof(MYFLT)*(CS_KSMPS-offset-early));
1111             if (UNLIKELY(early))
1112                 memset(&p->channelPtrs[index][early], '\0', sizeof(MYFLT)*(CS_KSMPS-early));
1113             p->pos += CS_KSMPS;
1114             p->pos %= (csound->ksmps-offset);
1115             csoundSpinUnLock(p->lock);
1116         }
1117     }
1118 
1119     return OK;
1120 }
1121 
chnset_array_opcode_perf_S(CSOUND * csound,CHNGETARRAY * p)1122 int32_t chnset_array_opcode_perf_S(CSOUND* csound, CHNGETARRAY* p)
1123 {
1124     int32_t err;
1125     int index = 0;
1126     STRINGDAT *strings = (STRINGDAT *)p->arrayDat->data;
1127 
1128     for (index = 0; index<p->arraySize; index++)
1129     {
1130         if(strcmp(p->channels[index].data, "")) {
1131             err = csoundGetChannelPtr(csound, &p->channelPtrs[index], (char *) p->channels[index].data,
1132                                       CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL);
1133 
1134             if (UNLIKELY(err))
1135                 return print_chn_err(p, err);
1136 
1137             p->lock = (spin_lock_t *) csoundGetChannelLock(csound, (char *) p->channels[index].data);
1138             csoundSpinLock(p->lock);
1139             ((STRINGDAT *)p->channelPtrs[index])->data = cs_strdup(csound, strings[index].data);
1140             ((STRINGDAT *)p->channelPtrs[index])->size = strlen(strings[index].data + 1);
1141             csoundSpinUnLock(p->lock);
1142         }
1143     }
1144 
1145     return OK;
1146 }
1147 
1148 /* init routine for chnget opcode (control data) */
1149 
chnget_opcode_init_k(CSOUND * csound,CHNGET * p)1150 int32_t chnget_opcode_init_k(CSOUND *csound, CHNGET *p)
1151 {
1152     int32_t   err;
1153     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1154                               CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
1155 
1156     if (LIKELY(!err)) {
1157         p->lock =   (spin_lock_t *)csoundGetChannelLock(csound, (char*) p->iname->data);
1158         strNcpy(p->chname, p->iname->data, MAX_CHAN_NAME);
1159     }
1160 
1161     p->h.opadr = (SUBR) chnget_opcode_perf_k;
1162     return OK;
1163 }
1164 
1165 /* init routine for chnget opcode (audio data) */
1166 
chnget_opcode_init_a(CSOUND * csound,CHNGET * p)1167 int32_t chnget_opcode_init_a(CSOUND* csound, CHNGET* p)
1168 {
1169     int32_t err;
1170     p->pos = 0;
1171     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1172                               CSOUND_AUDIO_CHANNEL | CSOUND_INPUT_CHANNEL);
1173 
1174     if (LIKELY(!err))
1175     {
1176         p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
1177         strNcpy(p->chname, p->iname->data, MAX_CHAN_NAME);
1178     }
1179 
1180     p->h.opadr = (SUBR) chnget_opcode_perf_a;
1181     return OK;
1182 }
1183 
1184 /* receive string value from bus at init time */
1185 
chnget_opcode_init_S(CSOUND * csound,CHNGET * p)1186 int32_t chnget_opcode_init_S(CSOUND* csound, CHNGET* p)
1187 {
1188     int32_t err;
1189     char* s = ((STRINGDAT*) p->arg)->data;
1190     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1191                               CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL);
1192     p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
1193 
1194     if (LIKELY(!err))
1195     {
1196         csoundSpinLock(p->lock);
1197         if (((STRINGDAT*) p->fp)->data!=NULL)
1198         {
1199             if (((STRINGDAT*) p->fp)->size>((STRINGDAT*) p->arg)->size)
1200             {
1201                 if (s!=NULL) csound->Free(csound, s);
1202                 s = cs_strdup(csound, ((STRINGDAT*) p->fp)->data);
1203                 ((STRINGDAT*) p->arg)->data = s;
1204                 ((STRINGDAT*) p->arg)->size = strlen(s)+1;
1205             }
1206             else strcpy(((STRINGDAT*) p->arg)->data, ((STRINGDAT*) p->fp)->data);
1207         }
1208         csoundSpinUnLock(p->lock);
1209     }
1210     return OK;
1211 }
1212 
1213 
chnget_opcode_perf_S(CSOUND * csound,CHNGET * p)1214 int32_t chnget_opcode_perf_S(CSOUND* csound, CHNGET* p)
1215 {
1216     int32_t err;
1217     char* s = ((STRINGDAT*) p->arg)->data;
1218     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1219                               CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL);
1220     p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
1221 
1222     if (UNLIKELY(err))
1223         return print_chn_err(p, err);
1224 
1225     if (s!=NULL && ((STRINGDAT*) p->fp)->data!=NULL &&
1226         strcmp(s, ((STRINGDAT*) p->fp)->data)==0)
1227         return OK;
1228 
1229     csoundSpinLock(p->lock);
1230 
1231     if (((STRINGDAT*) p->fp)->data!=NULL)
1232     {
1233         if (((STRINGDAT*) p->arg)->size<=((STRINGDAT*) p->fp)->size)
1234         {
1235             if (s!=NULL) csound->Free(csound, s);
1236             s = cs_strdup(csound, ((STRINGDAT*) p->fp)->data);
1237             ((STRINGDAT*) p->arg)->data = s;
1238             ((STRINGDAT*) p->arg)->size = strlen(s)+1;
1239         }
1240         else strcpy(((STRINGDAT*) p->arg)->data, ((STRINGDAT*) p->fp)->data);
1241     }
1242     csoundSpinUnLock(p->lock);
1243     return OK;
1244 }
1245 
1246 
1247 /* send control value to bus at performance time */
1248 
chnset_opcode_perf_k(CSOUND * csound,CHNGET * p)1249 static int32_t chnset_opcode_perf_k(CSOUND *csound, CHNGET *p)
1250 {
1251     if(strncmp(p->chname, p->iname->data, MAX_CHAN_NAME)){
1252         int32_t err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1253                                           CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL);
1254         if(err == 0) {
1255             p->lock = (spin_lock_t *) csoundGetChannelLock(csound, (char*) p->iname->data);
1256             strNcpy(p->chname, p->iname->data, MAX_CHAN_NAME);
1257         }
1258         else
1259             print_chn_err_perf(p, err);
1260     }
1261 
1262 #if defined(MSVC)
1263     volatile union {
1264       MYFLT d;
1265       MYFLT_INT_TYPE i;
1266     } x;
1267     x.d = *(p->arg);
1268     InterlockedExchange64((MYFLT_INT_TYPE *) p->fp, x.i);
1269 #elif defined(HAVE_ATOMIC_BUILTIN)
1270     union {
1271         MYFLT d;
1272         MYFLT_INT_TYPE i;
1273     } x;
1274     x.d = *(p->arg);
1275     __atomic_store_n((MYFLT_INT_TYPE *)(p->fp),x.i, __ATOMIC_SEQ_CST);
1276 #else
1277     csoundSpinLock(p->lock);
1278     *(p->fp) = *(p->arg);
1279     csoundSpinUnLock(p->lock);
1280 #endif
1281     return OK;
1282 }
1283 
1284 /* send audio data to bus at performance time */
1285 
chnset_opcode_perf_a(CSOUND * csound,CHNGET * p)1286 static int32_t chnset_opcode_perf_a(CSOUND *csound, CHNGET *p)
1287 {
1288     uint32_t offset = p->h.insdshead->ksmps_offset;
1289     uint32_t early  = p->h.insdshead->ksmps_no_end;
1290     if(CS_KSMPS == (uint32_t) csound->ksmps){
1291         /* Need lock for the channel */
1292         csoundSpinLock(p->lock);
1293         if (UNLIKELY(offset)) memset(p->fp, '\0', sizeof(MYFLT)*offset);
1294         memcpy(&p->fp[offset], &p->arg[offset],
1295                sizeof(MYFLT)*(CS_KSMPS-offset-early));
1296         if (UNLIKELY(early))
1297             memset(&p->fp[early], '\0', sizeof(MYFLT)*(CS_KSMPS-early));
1298         csoundSpinUnLock(p->lock);
1299     } else {
1300         /* Need lock for the channel */
1301         csoundSpinLock(p->lock);
1302         if (UNLIKELY(offset)) memset(p->fp, '\0', sizeof(MYFLT)*offset);
1303         memcpy(&p->fp[offset+p->pos], &p->arg[offset],
1304                sizeof(MYFLT)*(CS_KSMPS-offset-early));
1305         if (UNLIKELY(early))
1306             memset(&p->fp[early], '\0', sizeof(MYFLT)*(CS_KSMPS-early));
1307         p->pos += CS_KSMPS;
1308         p->pos %= (csound->ksmps-offset);
1309         csoundSpinUnLock(p->lock);
1310     }
1311     return OK;
1312 }
1313 
1314 /* send audio data to bus at performance time, mixing to previous output */
1315 
chnmix_opcode_perf(CSOUND * csound,CHNGET * p)1316 static int32_t chnmix_opcode_perf(CSOUND *csound, CHNGET *p)
1317 {
1318     uint32_t n = 0;
1319     IGN(csound);
1320     uint32_t nsmps = CS_KSMPS;
1321     uint32_t offset = p->h.insdshead->ksmps_offset;
1322     uint32_t early  = p->h.insdshead->ksmps_no_end;
1323     if (UNLIKELY(early)) nsmps -= early;
1324     /* Need lock for the channel */
1325     csoundSpinLock(p->lock);
1326     for (n=offset; n<nsmps; n++) {
1327         p->fp[n] += p->arg[n];
1328     }
1329     csoundSpinUnLock(p->lock);
1330     return OK;
1331 }
1332 
1333 /* clear an audio channel to zero at performance time */
1334 
chnclear_opcode_perf(CSOUND * csound,CHNCLEAR * p)1335 static int32_t chnclear_opcode_perf(CSOUND *csound, CHNCLEAR *p)
1336 {
1337     int32_t i, n=p->INCOUNT;
1338     /* Need lock for the channel */
1339     IGN(csound);
1340     for (i=0; i<n; i++) {
1341         csoundSpinLock(p->lock[i]);
1342         memset(p->fp[i], 0, CS_KSMPS*sizeof(MYFLT)); /* Should this leave start? */
1343         csoundSpinUnLock(p->lock[i]);
1344     }
1345     return OK;
1346 }
1347 
1348 /* send control value to bus at init time */
1349 
chnset_opcode_init_i(CSOUND * csound,CHNGET * p)1350 int32_t chnset_opcode_init_i(CSOUND *csound, CHNGET *p)
1351 {
1352     int32_t   err;
1353 
1354     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1355                               CSOUND_CONTROL_CHANNEL | CSOUND_OUTPUT_CHANNEL);
1356     if (UNLIKELY(err))
1357         return print_chn_err(p, err);
1358 
1359 
1360 #if defined(MSVC)
1361     volatile union {
1362       MYFLT d;
1363       MYFLT_INT_TYPE i;
1364     } x;
1365     x.d = *(p->arg);
1366     InterlockedExchange64((MYFLT_INT_TYPE *) p->fp, x.i);
1367 #elif defined(HAVE_ATOMIC_BUILTIN)
1368     union {
1369         MYFLT d;
1370         MYFLT_INT_TYPE i;
1371     } x;
1372     x.d = *(p->arg);
1373     __atomic_store_n((MYFLT_INT_TYPE *)(p->fp),x.i, __ATOMIC_SEQ_CST);
1374 #else
1375     {
1376       spin_lock_t *lock;       /* Need lock for the channel */
1377       p->lock = lock =  (spin_lock_t *)
1378         csoundGetChannelLock(csound, (char*) p->iname->data);
1379       csoundSpinLock(lock);
1380       *(p->fp) = *(p->arg);
1381       csoundSpinUnLock(lock);
1382     }
1383 #endif
1384     return OK;
1385 }
1386 
1387 /* init routine for chnset opcode (control data) */
1388 
chnset_opcode_init_k(CSOUND * csound,CHNGET * p)1389 int32_t chnset_opcode_init_k(CSOUND* csound, CHNGET* p)
1390 {
1391     int32_t err;
1392 
1393     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1394                               CSOUND_CONTROL_CHANNEL | CSOUND_OUTPUT_CHANNEL);
1395     if (LIKELY(!err)) {
1396         p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
1397     }
1398 
1399     p->h.opadr = (SUBR) chnset_opcode_perf_k;
1400     return OK;
1401 }
1402 
1403 /* init routine for chnset opcode (audio data) */
1404 
chnset_opcode_init_a(CSOUND * csound,CHNGET * p)1405 int32_t chnset_opcode_init_a(CSOUND* csound, CHNGET* p)
1406 {
1407     int32_t err;
1408     p->pos = 0;
1409     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1410                               CSOUND_AUDIO_CHANNEL | CSOUND_OUTPUT_CHANNEL);
1411     if (!err) {
1412         p->lock = (spin_lock_t*) csoundGetChannelLock(csound, (char*) p->iname->data);
1413     }
1414 
1415     p->h.opadr = (SUBR) chnset_opcode_perf_a;
1416     return OK;
1417 }
1418 
1419 /* init routine for chnmix opcode */
1420 
chnmix_opcode_init(CSOUND * csound,CHNGET * p)1421 int32_t chnmix_opcode_init(CSOUND *csound, CHNGET *p)
1422 {
1423     int32_t   err;
1424 
1425     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1426                               CSOUND_AUDIO_CHANNEL | CSOUND_OUTPUT_CHANNEL);
1427     if (LIKELY(!err)) {
1428         p->lock = (spin_lock_t *)csoundGetChannelLock(csound, (char*) p->iname->data);
1429         p->h.opadr = (SUBR) chnmix_opcode_perf;
1430         return OK;
1431     }
1432     return print_chn_err(p, err);
1433 }
1434 
1435 /* init routine for chnclear opcode */
1436 
chnclear_opcode_init(CSOUND * csound,CHNCLEAR * p)1437 int32_t chnclear_opcode_init(CSOUND *csound, CHNCLEAR *p)
1438 {
1439     int32_t   err;
1440     int32_t   i, n = (int32_t)p->INCOUNT;
1441     for (i=0; i<n; i++) {
1442         /* NOTE: p->imode is a pointer to the channel data here */
1443         err = csoundGetChannelPtr(csound, &(p->fp[i]), (char*) p->iname[i]->data,
1444                                   CSOUND_AUDIO_CHANNEL | CSOUND_OUTPUT_CHANNEL);
1445         if (LIKELY(!err)) {
1446             p->lock[i] = (spin_lock_t *)csoundGetChannelLock(csound,
1447                                                              (char*) p->iname[i]->data);
1448         }
1449         else return print_chn_err(p, err);
1450     }
1451     p->h.opadr = (SUBR) chnclear_opcode_perf;
1452     return OK;
1453 }
1454 
1455 /* send string to bus at init time */
1456 
chnset_opcode_init_S(CSOUND * csound,CHNGET * p)1457 int32_t chnset_opcode_init_S(CSOUND* csound, CHNGET* p)
1458 {
1459     int32_t err;
1460     spin_lock_t* lock;
1461     char* s = ((STRINGDAT*) p->arg)->data;
1462 
1463     err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1464                               CSOUND_STRING_CHANNEL | CSOUND_OUTPUT_CHANNEL);
1465     // size = csoundGetChannelDatasize(csound, p->iname->data);
1466     if (LIKELY(!err))
1467     {
1468 
1469         if (s==NULL) return NOTOK;
1470         p->lock = lock = (spin_lock_t*)
1471                 csoundGetChannelLock(csound, (char*) p->iname->data);
1472         csoundSpinLock(lock);
1473         if (strlen(s)>=(uint32_t) ((STRINGDAT*) p->fp)->size)
1474         {
1475             if (((STRINGDAT*) p->fp)->data!=NULL)
1476                 csound->Free(csound, ((STRINGDAT*) p->fp)->data);
1477             ((STRINGDAT*) p->fp)->data = cs_strdup(csound, s);
1478             ((STRINGDAT*) p->fp)->size = strlen(s)+1;
1479 
1480             //set_channel_data_ptr(csound, p->iname->data,p->fp, strlen(s)+1);
1481         }
1482         else if (((STRINGDAT*) p->fp)->data!=NULL)
1483             strcpy(((STRINGDAT*) p->fp)->data, s);
1484         csoundSpinUnLock(lock);
1485     }
1486 
1487     return OK;
1488 }
1489 
chnset_opcode_perf_S(CSOUND * csound,CHNGET * p)1490 int32_t chnset_opcode_perf_S(CSOUND* csound, CHNGET* p)
1491 {
1492     int32_t err;
1493     spin_lock_t* lock;
1494     char* s = ((STRINGDAT*) p->arg)->data;
1495 
1496     if ((err = csoundGetChannelPtr(csound, &(p->fp), (char*) p->iname->data,
1497                                    CSOUND_STRING_CHANNEL | CSOUND_OUTPUT_CHANNEL)))
1498         return err;
1499     // size = csoundGetChannelDatasize(csound, p->iname->data);
1500 
1501     if (s==NULL) return NOTOK;
1502     if (((STRINGDAT*) p->fp)->data
1503         && strcmp(s, ((STRINGDAT*) p->fp)->data)==0)
1504         return OK;
1505 
1506     p->lock = lock = (spin_lock_t*)
1507             csoundGetChannelLock(csound, (char*) p->iname->data);
1508     csoundSpinLock(lock);
1509     if (strlen(s)>=(uint32_t) ((STRINGDAT*) p->fp)->size)
1510     {
1511         if (((STRINGDAT*) p->fp)->data!=NULL)
1512             csound->Free(csound, ((STRINGDAT*) p->fp)->data);
1513         ((STRINGDAT*) p->fp)->data = cs_strdup(csound, s);
1514         ((STRINGDAT*) p->fp)->size = strlen(s)+1;
1515         //set_channel_data_ptr(csound, p->iname->data,p->fp, strlen(s)+1);
1516         //printf("p: %s: %s \n", p->iname->data, ((STRINGDAT *)p->fp)->data);
1517     }
1518     else if (((STRINGDAT*) p->fp)->data!=NULL)
1519         strcpy(((STRINGDAT*) p->fp)->data, s);
1520     csoundSpinUnLock(lock);
1521     //printf("%s \n", (char *)p->fp);
1522     return OK;
1523 }
1524 
1525 /* declare control channel, optionally with special parameters */
1526 
chn_k_opcode_init_(CSOUND * csound,CHN_OPCODE_K * p,int mode)1527 int32_t chn_k_opcode_init_(CSOUND *csound, CHN_OPCODE_K *p, int mode)
1528 {
1529     MYFLT *dummy;
1530     int32_t   type, err;
1531     controlChannelHints_t hints;
1532     hints.attributes = NULL;
1533     hints.max = hints.min = hints.dflt = FL(0.0);
1534     hints.x = hints.y = hints.height = hints.width = 0;
1535 
1536     // mode = (int32_t)MYFLT2LRND(*(p->imode));
1537     if (UNLIKELY(mode < 1 || mode > 3))
1538         return csound->InitError(csound, Str("invalid mode parameter"));
1539     type = CSOUND_CONTROL_CHANNEL;
1540     if (mode & 1)
1541         type |= CSOUND_INPUT_CHANNEL;
1542     if (mode & 2)
1543         type |= CSOUND_OUTPUT_CHANNEL;
1544 
1545     err = csoundGetChannelPtr(csound, &dummy, (char*) p->iname->data, type);
1546     if (err)
1547         return print_chn_err(p, err);
1548     hints.behav = CSOUND_CONTROL_CHANNEL_NO_HINTS;
1549     if ((int)MYFLT2LRND(*(p->itype)) == 1)
1550         hints.behav = CSOUND_CONTROL_CHANNEL_INT;
1551     else if ((int32_t)MYFLT2LRND(*(p->itype)) == 2)
1552         hints.behav |= CSOUND_CONTROL_CHANNEL_LIN;
1553     else if ((int32_t)MYFLT2LRND(*(p->itype)) == 3)
1554         hints.behav |= CSOUND_CONTROL_CHANNEL_EXP;
1555     if ((int32_t)MYFLT2LRND(*(p->itype)) != 0) {
1556         hints.attributes = 0;
1557         if (p->INOCOUNT > 10) {
1558             hints.attributes = p->Sattributes->data;
1559         }
1560         hints.dflt = *(p->idflt);
1561         hints.min = *(p->imin);
1562         hints.max = *(p->imax);
1563         hints.x = *(p->ix);
1564         hints.y = *(p->iy);
1565         hints.width = *(p->iwidth);
1566         hints.height = *(p->iheight);
1567     }
1568     err = csoundSetControlChannelHints(csound, (char*) p->iname->data, hints);
1569     if (LIKELY(!err)) {
1570         p->lock = (spin_lock_t *)csoundGetChannelLock(csound, (char*) p->iname->data);
1571         return OK;
1572     }
1573     if (err == CSOUND_MEMORY)
1574         return print_chn_err(p, err);
1575     return csound->InitError(csound, Str("invalid channel parameters"));
1576 }
1577 
chn_k_opcode_init(CSOUND * csound,CHN_OPCODE_K * p)1578 int32_t chn_k_opcode_init(CSOUND *csound, CHN_OPCODE_K *p)
1579 {
1580     int32_t mode = (int32_t)MYFLT2LRND(*(p->imode));
1581     return chn_k_opcode_init_(csound, p, mode);
1582 }
1583 
chn_k_opcode_init_S(CSOUND * csound,CHN_OPCODE_K * p)1584 int32_t chn_k_opcode_init_S(CSOUND *csound, CHN_OPCODE_K *p)
1585 {
1586     STRINGDAT *smode = (STRINGDAT *)p->imode;
1587     int32_t mode;
1588     if(!strcmp("rw", smode->data))
1589         mode = 3;
1590     else if(!strcmp("r", smode->data))
1591         mode = 1;
1592     else if(!strcmp("w", smode->data))
1593         mode = 2;
1594     else
1595         return csound->InitError(csound, Str("invalid mode, should be r, w, rw"));
1596     return chn_k_opcode_init_(csound, p, mode);
1597 }
1598 
1599 
1600 /* declare audio channel */
1601 
chn_a_opcode_init(CSOUND * csound,CHN_OPCODE * p)1602 int32_t chn_a_opcode_init(CSOUND *csound, CHN_OPCODE *p)
1603 {
1604     MYFLT *dummy;
1605     int32_t   type, mode, err;
1606 
1607     mode = (int32_t)MYFLT2LRND(*(p->imode));
1608     if (UNLIKELY(mode < 1 || mode > 3))
1609         return csound->InitError(csound, Str("invalid mode parameter"));
1610     type = CSOUND_AUDIO_CHANNEL;
1611     if (mode & 1)
1612         type |= CSOUND_INPUT_CHANNEL;
1613     if (mode & 2)
1614         type |= CSOUND_OUTPUT_CHANNEL;
1615     err = csoundGetChannelPtr(csound, &dummy, (char*) p->iname->data, type);
1616     if (UNLIKELY(err))
1617         return print_chn_err(p, err);
1618     return OK;
1619 }
1620 
1621 /* declare string channel */
1622 
chn_S_opcode_init(CSOUND * csound,CHN_OPCODE * p)1623 int32_t chn_S_opcode_init(CSOUND *csound, CHN_OPCODE *p)
1624 {
1625     MYFLT *dummy;
1626     int32_t   type, mode, err;
1627 
1628     mode = (int32_t)MYFLT2LRND(*(p->imode));
1629     if (UNLIKELY(mode < 1 || mode > 3))
1630         return csound->InitError(csound, Str("invalid mode parameter"));
1631     type = CSOUND_STRING_CHANNEL;
1632     if (mode & 1)
1633         type |= CSOUND_INPUT_CHANNEL;
1634     if (mode & 2)
1635         type |= CSOUND_OUTPUT_CHANNEL;
1636     err = csoundGetChannelPtr(csound, &dummy, (char*) p->iname->data, type);
1637     if (UNLIKELY(err))
1638         return print_chn_err(p, err);
1639     p->lock = (spin_lock_t *) csoundGetChannelLock(csound, (char*) p->iname->data);
1640     return OK;
1641 }
1642 
1643 /* export new channel from global orchestra variable */
1644 
chnexport_opcode_init(CSOUND * csound,CHNEXPORT_OPCODE * p)1645 int32_t chnexport_opcode_init(CSOUND *csound, CHNEXPORT_OPCODE *p)
1646 {
1647     MYFLT       *dummy;
1648     const char  *argName;
1649     int32_t         type = CSOUND_CONTROL_CHANNEL, mode, err;
1650     controlChannelHints_t hints;
1651     CHNENTRY *chn;
1652 
1653     /* must have an output argument of type 'gi', 'gk', 'ga', or 'gS' */
1654     if (UNLIKELY(csound->GetOutputArgCnt(p) != 1))
1655         goto arg_err;
1656     argName = csound->GetOutputArgName(p, 0);
1657     if (UNLIKELY(argName == NULL))
1658         goto arg_err;
1659     if (UNLIKELY(argName[0] != 'g'))
1660         goto arg_err;
1661     switch ((int32_t)argName[1]) {
1662         case 'i':
1663         case 'k':
1664             break;
1665         case 'a':
1666             type = CSOUND_AUDIO_CHANNEL;
1667             break;
1668         case 'S':
1669             type = CSOUND_STRING_CHANNEL;
1670             break;
1671         default:
1672             goto arg_err;
1673     }
1674     /* mode (input and/or output) */
1675     mode = (int32_t)MYFLT2LRND(*(p->imode));
1676     if (UNLIKELY(mode < 1 || mode > 3))
1677         return csound->InitError(csound, Str("invalid mode parameter"));
1678     if (mode & 1)
1679         type |= CSOUND_INPUT_CHANNEL;
1680     if (mode & 2)
1681         type |= CSOUND_OUTPUT_CHANNEL;
1682     /* check if the channel already exists (it should not) */
1683     err = csoundGetChannelPtr(csound, &dummy, (char*) p->iname->data, 0);
1684     if (UNLIKELY(err >= 0))
1685         return csound->InitError(csound, Str("channel already exists"));
1686     /* now create new channel, using output variable for data storage */
1687 //    dummy = p->arg;
1688     /* THIS NEEDS A LOCK BUT DOES NOT EXIST YET */
1689     /* lock = csoundGetChannelLock(csound, (char*) p->iname->data); */
1690     /* csoundSpinLock(lock); */
1691     err = create_new_channel(csound, (char*) p->iname->data, type);
1692 
1693     /* csoundSpinLock(lock); */
1694     if (err)
1695         return print_chn_err(p, err);
1696 
1697     /* Now we need to find the channel entry */
1698     chn = find_channel(csound, (char*) p->iname->data);
1699     /* free the allocated memory (we will not use it) */
1700     csound->Free(csound, chn->data);
1701     /* point to the arg var */
1702     chn->data = p->arg;
1703 
1704     /* if control channel, set additional parameters */
1705     if ((type & CSOUND_CHANNEL_TYPE_MASK) != CSOUND_CONTROL_CHANNEL)
1706         return OK;
1707     type = (int32_t)MYFLT2LRND(*(p->itype));
1708     hints.behav = CSOUND_CONTROL_CHANNEL_LIN;
1709     hints.dflt = *(p->idflt);
1710     hints.min = *(p->imin);
1711     hints.max = *(p->imax);
1712     hints.x = hints.y = hints.width = hints.height = 0;
1713     hints.attributes = NULL;
1714     err = csoundSetControlChannelHints(csound, (char*) p->iname->data, hints);
1715     if (LIKELY(!err))
1716         return OK;
1717     if (err == CSOUND_MEMORY)
1718         return print_chn_err(p, err);
1719     return csound->InitError(csound, Str("invalid channel parameters"));
1720 
1721     arg_err:
1722     return csound->InitError(csound, Str("invalid export variable"));
1723 }
1724 
1725 /* returns all parameters of a channel */
1726 
chnparams_opcode_init(CSOUND * csound,CHNPARAMS_OPCODE * p)1727 int32_t chnparams_opcode_init(CSOUND *csound, CHNPARAMS_OPCODE *p)
1728 {
1729     MYFLT *dummy;
1730     int32_t   err;
1731 
1732     /* all values default to zero... */
1733     *(p->itype)    = FL(0.0);
1734     *(p->imode)    = FL(0.0);
1735     *(p->ictltype) = FL(0.0);
1736     *(p->idflt)    = FL(0.0);
1737     *(p->imin)     = FL(0.0);
1738     *(p->imax)     = FL(0.0);
1739     err = csoundGetChannelPtr(csound, &dummy, (char*) p->iname->data, 0);
1740     /* ...if channel does not exist */
1741     if (err <= 0)
1742         return OK;
1743     /* type (control/audio/string) */
1744     *(p->itype) = (MYFLT) (err & 15);
1745     /* mode (input and/or output) */
1746     *(p->imode) = (MYFLT) ((err & 48) >> 4);
1747     /* check for control channel parameters */
1748     if ((err & 15) == CSOUND_CONTROL_CHANNEL) {
1749         controlChannelHints_t hints;
1750         err = csoundGetControlChannelHints(csound, (char*) p->iname->data, &hints);
1751         if (UNLIKELY(err > 0))
1752             *(p->ictltype) = (MYFLT) err;
1753         *(p->ictltype) = hints.behav;
1754         *(p->idflt) = hints.dflt;
1755         *(p->imin) = hints.min;
1756         *(p->imax) = hints.max;
1757     }
1758     return OK;
1759 }
1760 
1761 /* ********************************************************************** */
1762 /* *************** SENSING ********************************************** */
1763 /* ********************************************************************** */
1764 
sensekey_perf(CSOUND * csound,KSENSE * p)1765 int32_t sensekey_perf(CSOUND *csound, KSENSE *p)
1766 {
1767     int32_t     keyCode = 0;
1768     int32_t     retval;
1769 
1770     retval = csound->doCsoundCallback(csound, &keyCode,
1771                                       (p->keyDown != NULL ?
1772                                        CSOUND_CALLBACK_KBD_EVENT
1773                                                           : CSOUND_CALLBACK_KBD_TEXT));
1774     if (retval > 0) {
1775         if (!p->evtbuf) {
1776 #if defined(__unix) || defined(__unix__) || defined(__MACH__)
1777             if (csound->inChar_ < 0) {
1778 #  if defined(WIN32)
1779                 setvbuf(stdin, NULL, _IONBF, 0);  /* Does not seem to work */
1780 #  elif defined(HAVE_TERMIOS_H)
1781                 struct termios  tty;
1782                 tcgetattr(0, &tty);
1783                 tty.c_lflag &= (~ICANON);
1784                 tcsetattr(0, TCSANOW, &tty);
1785 #  endif
1786             }
1787 #endif
1788             p->evtbuf = -1;
1789         }
1790         if (csound->inChar_ < 0) {
1791 #if defined(__unix) || defined(__unix__) || defined(__MACH__)
1792             fd_set  rfds;
1793             struct timeval  tv;
1794             /* Watch stdin (fd 0) to see when it has input. */
1795             FD_ZERO(&rfds);
1796             FD_SET(0, &rfds);
1797             /* No waiting */
1798             tv.tv_sec = 0;
1799             tv.tv_usec = 0;
1800 
1801             retval = select(1, &rfds, NULL, NULL, &tv);
1802 
1803             if (retval>0) {
1804                 char    ch = '\0';
1805                 int32_t n=0;
1806                 if (UNLIKELY((n=read(0, &ch, 1))<0)) {
1807                     csound->PerfError(csound, &(p->h),
1808                                       Str("read failure in sensekey\n"));
1809                     return NOTOK;
1810                 }
1811                 //if n==0 then EOF which we treat as empty
1812                 if(n==0) ch = '\0';
1813                 keyCode = (int32_t)((unsigned char) ch);
1814                 /* FD_ISSET(0, &rfds) will be true. */
1815             }
1816             else if (retval<0) perror(Str("sensekey error:"));
1817 #else
1818             unsigned char ch = (unsigned char) '\0';
1819 #  ifdef WIN32
1820         if (_kbhit())
1821           ch = (unsigned char) _getch();
1822 #  else
1823         ch = (unsigned char) getchar();
1824 #  endif
1825         keyCode = (int32_t)ch;
1826 #endif
1827         }
1828         else if (csound->inChar_ > 0) {
1829             keyCode = csound->inChar_;
1830             csound->inChar_ = 0;
1831         }
1832         if (p->evtbuf != -1) {
1833             int32_t     tmp = keyCode;
1834             keyCode = p->evtbuf;
1835             tmp = (keyCode < 0 ? tmp : (-1 - keyCode));
1836             p->evtbuf = (tmp != 0 ? tmp : -1);
1837         }
1838         // *** Cannot see point of next 2 lines *** JPff
1839         /* else if (p->OUTOCOUNT>1 && p->keyDown != NULL) */
1840         /*   p->evtbuf = -1 - keyCode; */
1841         if (keyCode < 0)
1842             keyCode = 65535 - keyCode;
1843     }
1844     else if (retval < 0) {
1845         keyCode = 0;
1846     }
1847     *(p->ans) = (MYFLT) ((keyCode & (int32_t)0xFFFF) ?
1848                          (keyCode & (int32_t)0xFFFF) : -1);
1849     if (p->OUTOCOUNT>1 && p->keyDown != NULL)
1850         *(p->keyDown) = (MYFLT) ((keyCode > 0 && keyCode < 65536) ? 1 : 0);
1851 
1852     return OK;
1853 }
1854 
1855 
1856 /* k-rate and string i/o opcodes */
1857 /* invalue and outvalue are used with the csoundAPI */
1858 /*     ma++ ingalls      matt@sonomatics.com */
1859 
kinval(CSOUND * csound,INVAL * p)1860 int32_t kinval(CSOUND *csound, INVAL *p)
1861 {
1862     if (csound->InputChannelCallback_) {
1863         csound->InputChannelCallback_(csound,
1864                                       (char*) p->channelName.auxp,
1865                                       p->value, p->channelType);
1866     }
1867     else
1868         *(p->value) = FL(0.0);
1869 
1870     return OK;
1871 }
1872 
kinvalS(CSOUND * csound,INVAL * p)1873 int32_t kinvalS(CSOUND *csound, INVAL *p)
1874 {
1875 
1876     if (csound->InputChannelCallback_) {
1877         csound->InputChannelCallback_(csound,
1878                                       (char*) p->channelName.auxp,
1879                                       ((STRINGDAT *)p->value)->data,
1880                                       p->channelType);
1881 
1882     }
1883     else {
1884         ((STRINGDAT *)p->value)->data[0]  = '\0';
1885     }
1886 
1887     return OK;
1888 }
1889 
1890 
invalset_string_S(CSOUND * csound,INVAL * p)1891 int32_t invalset_string_S(CSOUND *csound, INVAL *p)
1892 {
1893     int32_t   err;
1894     int32_t type;
1895     STRINGDAT *out = (STRINGDAT *) p->value;
1896 
1897     const char  *s = ((STRINGDAT *)p->valID)->data;
1898     csound->AuxAlloc(csound, strlen(s) + 1, &p->channelName);
1899     strcpy((char*) p->channelName.auxp, s);
1900 
1901     p->channelType = &CS_VAR_TYPE_S;
1902     type = CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL;
1903 
1904     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
1905                               (char*) p->channelName.auxp,
1906                               type);
1907     if (UNLIKELY(err))
1908         return print_chn_err(p, err);
1909 
1910     if (out->data == NULL || out->size < 256) {
1911         if(out->data != NULL)
1912             csound->Free(csound, out->data);
1913         out->data = csound->Calloc(csound, 256);
1914         out->size = 256;
1915     }
1916 
1917     /* grab input now for use during i-pass */
1918     kinvalS(csound, p);
1919     if (!csound->InputChannelCallback_) {
1920         csound->Warning(csound,Str("InputChannelCallback not set."));
1921     }
1922     return OK;
1923 }
1924 
invalset_S(CSOUND * csound,INVAL * p)1925 int32_t invalset_S(CSOUND *csound, INVAL *p)
1926 {
1927     int32_t   err;
1928     int32_t type;
1929 
1930     const char  *s = ((STRINGDAT *)p->valID)->data;
1931     csound->AuxAlloc(csound, strlen(s) + 1, &p->channelName);
1932     strcpy((char*) p->channelName.auxp, s);
1933 
1934     p->channelType = &CS_VAR_TYPE_K;
1935     type = CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL;
1936 
1937     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
1938                               (char*) p->channelName.auxp,
1939                               type);
1940     if (UNLIKELY(err))
1941         return print_chn_err(p, err);
1942 
1943     /* grab input now for use during i-pass */
1944     kinval(csound, p);
1945     if (!csound->InputChannelCallback_) {
1946         csound->Warning(csound,Str("InputChannelCallback not set."));
1947     }
1948     return OK;
1949 }
1950 
invalsetgo(CSOUND * csound,INVAL * p)1951 int32_t invalsetgo(CSOUND *csound, INVAL *p)
1952 {
1953     int32_t ans = invalset(csound, p);
1954     if (ans==OK) ans = kinval(csound, p);
1955     return ans;
1956 }
1957 
invalsetSgo(CSOUND * csound,INVAL * p)1958 int32_t invalsetSgo(CSOUND *csound, INVAL *p)
1959 {
1960     int32_t ans = invalset_S(csound, p);
1961     if (ans==OK) ans = kinval(csound, p);
1962     return ans;
1963 }
1964 
1965 
invalset_string(CSOUND * csound,INVAL * p)1966 int32_t invalset_string(CSOUND *csound, INVAL *p)
1967 {
1968     int32_t   err;
1969     int32_t type;
1970 
1971     /* convert numerical channel to string name */
1972     csound->AuxAlloc(csound, 64, &p->channelName);
1973     snprintf((char*) p->channelName.auxp, 64, "%d", (int32_t)MYFLT2LRND(*p->valID));
1974 
1975     p->channelType = &CS_VAR_TYPE_S;
1976     type = CSOUND_STRING_CHANNEL | CSOUND_INPUT_CHANNEL;
1977 
1978     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
1979                               (char*) p->channelName.auxp,
1980                               type);
1981     if (UNLIKELY(err))
1982         return print_chn_err(p, err);
1983 
1984     /* grab input now for use during i-pass */
1985     kinvalS(csound, p);
1986     if (!csound->InputChannelCallback_) {
1987         csound->Warning(csound,Str("InputChannelCallback not set."));
1988     }
1989     return OK;
1990 }
1991 
1992 
invalset(CSOUND * csound,INVAL * p)1993 int32_t invalset(CSOUND *csound, INVAL *p)
1994 {
1995     int32_t   err;
1996     int32_t type;
1997 
1998     /* convert numerical channel to string name */
1999     csound->AuxAlloc(csound, 32, &p->channelName);
2000     snprintf((char*) p->channelName.auxp, 32, "%d", (int32_t)MYFLT2LRND(*p->valID));
2001 
2002     p->channelType = &CS_VAR_TYPE_K;
2003     type = CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL;
2004 
2005     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
2006                               (char*) p->channelName.auxp,
2007                               type);
2008     if (UNLIKELY(err))
2009         return print_chn_err(p, err);
2010 
2011     /* grab input now for use during i-pass */
2012     kinval(csound, p);
2013     if (!csound->InputChannelCallback_) {
2014         csound->Warning(csound,Str("InputChannelCallback not set."));
2015     }
2016     return OK;
2017 }
2018 
2019 
2020 
koutvalS(CSOUND * csound,OUTVAL * p)2021 int32_t koutvalS(CSOUND *csound, OUTVAL *p)
2022 {
2023     char    *chan = (char*)p->channelName.auxp;
2024 
2025     if (csound->OutputChannelCallback_) {
2026         csound->OutputChannelCallback_(csound, chan,
2027                                        ((STRINGDAT *)p->value)->data,
2028                                        p->channelType);
2029     }
2030     return OK;
2031 }
2032 
koutval(CSOUND * csound,OUTVAL * p)2033 int32_t koutval(CSOUND *csound, OUTVAL *p)
2034 {
2035     char    *chan = (char*)p->channelName.auxp;
2036 
2037     if (csound->OutputChannelCallback_) {
2038         csound->OutputChannelCallback_(csound, chan, p->value, p->channelType);
2039         *((MYFLT *) p->channelptr) = *(p->value);
2040     }
2041 
2042     return OK;
2043 }
2044 
outvalset_string_S(CSOUND * csound,OUTVAL * p)2045 int32_t outvalset_string_S(CSOUND *csound, OUTVAL *p)
2046 {
2047     int32_t type, err;
2048     const char  *s = ((STRINGDAT *)p->valID)->data;
2049     csound->AuxAlloc(csound, strlen(s) + 1, &p->channelName);
2050     strcpy((char*) p->channelName.auxp, s);
2051 
2052 
2053     p->channelType = &CS_VAR_TYPE_S;
2054     type = CSOUND_STRING_CHANNEL | CSOUND_OUTPUT_CHANNEL;
2055 
2056     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
2057                               (char*) p->channelName.auxp, type);
2058 
2059     if (UNLIKELY(err))
2060         return print_chn_err(p, err);
2061 
2062     /* send output now for use during i-pass */
2063     koutvalS(csound, p);
2064     if (!csound->OutputChannelCallback_) {
2065         csound->Warning(csound,Str("OutputChannelCallback not set."));
2066     }
2067 
2068     return OK;
2069 }
2070 
2071 
2072 
outvalset_S(CSOUND * csound,OUTVAL * p)2073 int32_t outvalset_S(CSOUND *csound, OUTVAL *p)
2074 {
2075     int32_t type, err;
2076     const char  *s = ((STRINGDAT *)p->valID)->data;
2077     csound->AuxAlloc(csound, strlen(s) + 1, &p->channelName);
2078     strcpy((char*) p->channelName.auxp, s);
2079 
2080     p->channelType = &CS_VAR_TYPE_K;
2081     type = CSOUND_CONTROL_CHANNEL | CSOUND_OUTPUT_CHANNEL;
2082 
2083     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
2084                               (char*) p->channelName.auxp, type);
2085     if (UNLIKELY(err))
2086         return print_chn_err(p, err);
2087 
2088     /* send output now for use during i-pass */
2089     koutval(csound, p);
2090     if (!csound->OutputChannelCallback_) {
2091         csound->Warning(csound,Str("OutputChannelCallback not set."));
2092     }
2093 
2094     return OK;
2095 }
2096 
2097 
outvalset_string(CSOUND * csound,OUTVAL * p)2098 int32_t outvalset_string(CSOUND *csound, OUTVAL *p)
2099 {
2100     int32_t type, err;
2101 
2102     /* convert numerical channel to string name */
2103     if(p->channelName.auxp == NULL)
2104         csound->AuxAlloc(csound, 32, &p->channelName);
2105     snprintf((char*)p->channelName.auxp,  32, "%d",
2106              (int32_t)MYFLT2LRND(*p->valID));
2107 
2108     p->channelType = &CS_VAR_TYPE_S;
2109     type = CSOUND_STRING_CHANNEL | CSOUND_OUTPUT_CHANNEL;
2110 
2111     err = csoundGetChannelPtr(csound, (MYFLT **) &(p->channelptr),
2112                               (char*) p->channelName.auxp, type);
2113     if (UNLIKELY(err))
2114         return print_chn_err(p, err);
2115 
2116     /* send output now for use during i-pass */
2117     koutvalS(csound, p);
2118     if (!csound->OutputChannelCallback_) {
2119         csound->Warning(csound,Str("OutputChannelCallback not set."));
2120     }
2121 
2122     return OK;
2123 }
2124 
outvalset(CSOUND * csound,OUTVAL * p)2125 int32_t outvalset(CSOUND *csound, OUTVAL *p)
2126 {
2127     int32_t type, err;
2128 
2129     /* convert numerical channel to string name */
2130     csound->AuxAlloc(csound, 64, &p->channelName);
2131     snprintf((char*)p->channelName.auxp,  64, "%d",
2132              (int32_t)MYFLT2LRND(*p->valID));
2133 
2134     p->channelType = &CS_VAR_TYPE_K;
2135     type = CSOUND_CONTROL_CHANNEL | CSOUND_OUTPUT_CHANNEL;
2136 
2137     err = csoundGetChannelPtr(csound,(MYFLT **)  &(p->channelptr),
2138                               (char*) p->channelName.auxp, type);
2139     if (UNLIKELY(err))
2140         return print_chn_err(p, err);
2141 
2142     /* send output now for use during i-pass */
2143     koutval(csound, p);
2144     if (!csound->OutputChannelCallback_) {
2145         csound->Warning(csound,Str("OutputChannelCallback not set."));
2146     }
2147 
2148     return OK;
2149 }
2150 
outvalsetgo(CSOUND * csound,OUTVAL * p)2151 int32_t outvalsetgo(CSOUND *csound, OUTVAL *p)
2152 {
2153     int32_t ans = outvalset(csound,p);
2154     // if (ans==OK) ans = koutval(csound,p);
2155     return ans;
2156 }
2157 
outvalsetSgo(CSOUND * csound,OUTVAL * p)2158 int32_t outvalsetSgo(CSOUND *csound, OUTVAL *p)
2159 {
2160     int32_t ans = outvalset_S(csound,p);
2161     // if (ans==OK) ans = koutval(csound,p);
2162     return ans;
2163 }
2164