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