1 /*
2     ugrw1.c:
3 
4     Copyright (C) 1997 Robin Whittle
5 
6     This file is part of Csound.
7 
8     The Csound Library is free software; you can redistribute it
9     and/or modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     Csound is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with Csound; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21     02110-1301 USA
22 */
23 
24 /* These files are based on Robin Whittle's
25  *       ugrw1.c of 27 August 1996
26  * and   ugrw1.h of 7 January 1995
27  *
28  * In February 1997, John Fitch reformatted the comments and
29  * cleaned up some code in printksset() - which was working fine
30  * but was inelegantly coded.
31  * In February 1998, John Fitch modified the code wrt types so it
32  * compiled with MicroSoft C without warnings.
33  *
34  *
35  * Copyright notice - Robin Whittle  25 February 1997
36  *
37  * Documentation files, and the original .c and .h files, with more
38  * spaced out comments, are available from http://www.firstpr.com.au
39  *
40  * The code in both ugrw1 and ugrw2 is copyright Robin Whittle.
41  * Permission is granted to use this in whole or in part for any
42  * purpose, provided this copyright notice remains intact and
43  * any alterations to the source code, including comments, are
44  * clearly indicated as such.
45  */
46 
47 #include "csoundCore.h"
48 #include "ugrw1.h"
49 #include <math.h>
50 #include <ctype.h>
51 
52 /*****************************************************************************/
53 /*****************************************************************************/
54 /*****************************************************************************/
55 /*****************************************************************************/
56 
57 /* Subroutines for reading absolute time. */
58 
59 /* timek()
60  *
61  * Called at i rate or k rate, by timek, itimek, timesr or itemes.
62  *
63  * This is based on global variable kcounter in insert.c.
64  * Since is apparently is not declared in a header file, we must declare it
65  * an external.
66  * Actually moved to the glob structure -- JPff march 2002
67  */
68 
timek(CSOUND * csound,RDTIME * p)69 int32_t timek(CSOUND *csound, RDTIME *p)
70 {
71     IGN(csound);
72     /* Read the global variable kcounter and turn it into a float.   */
73     *p->rslt = (MYFLT) CS_KCNT;
74     return OK;
75 }
76 
77 /* timesr() */
timesr(CSOUND * csound,RDTIME * p)78 int32_t timesr(CSOUND *csound, RDTIME *p)
79 {
80     /* Read the global variable kcounter divide it by the k rate.    */
81     IGN(csound);
82     *p->rslt = (MYFLT) CS_KCNT * CS_ONEDKR;
83     return OK;
84 }
85 
86 /*-----------------------------------*/
87 
88 /* Subroutines to read time for this instance of the instrument. */
89 
90 /* instimset() runs at init time and keeps a record of the time then
91  * in the RDTIME data structure.
92  * Returns 0.
93  */
instimset(CSOUND * csound,RDTIME * p)94 int32_t instimset(CSOUND *csound, RDTIME *p)
95 {
96    IGN(csound);
97     p->instartk = CS_KCNT;
98     *p->rslt = FL(0.0);
99     return OK;
100 }
101 
102 /* instimek()
103  *
104  * Read difference between the global variable kcounter and the starting
105  * time of this instance. Return it as a float.
106  */
instimek(CSOUND * csound,RDTIME * p)107 int32_t instimek(CSOUND *csound, RDTIME *p)
108 {
109     IGN(csound);
110     *p->rslt = (MYFLT) (CS_KCNT - p->instartk);
111     return OK;
112 }
113 
114 /* insttimes()
115  *
116  * Read difference between the global variable kcounter and the starting
117  * time of this instance.  Return it as a float in seconds.
118  */
instimes(CSOUND * csound,RDTIME * p)119 int32_t instimes(CSOUND *csound, RDTIME *p)
120 {
121     IGN(csound);
122     *p->rslt = (MYFLT) (CS_KCNT - p->instartk) * CS_ONEDKR;
123     return OK;
124 }
125 
126 /*****************************************************************************/
127 /*****************************************************************************/
128 
129 /* Printing at k rate - printk. */
130 
131 /* printkset is called when the instance of the instrument is initialised. */
132 
printkset(CSOUND * csound,PRINTK * p)133 int32_t printkset(CSOUND *csound, PRINTK *p)
134 {
135     /* Set up ctime so that if it was 0 or negative, it is set to a low value
136      * to ensure that the print cycle happens every k cycle.  This low value is
137      * 1 / ekr     */
138     /* Not sure this mattersin revised version.  Would just work! -- JPff */
139     if (*p->ptime < CS_ONEDKR)
140       p->ctime = FL(0.0);
141     else
142       p->ctime = *p->ptime * csound->ekr;
143 
144     /* Set up the number of spaces.
145        Limit to 120 for people with big screens or printers.
146      */
147     p->pspace = (int32_t) *p->space;
148     if (UNLIKELY(p->pspace < 0L))
149       p->pspace = 0L;
150     else if (UNLIKELY(p->pspace > 120L))
151       p->pspace = 120L;
152 
153     //printf("printkset: ctime = %f\n", p->ctime);
154     p->printat = CS_KCNT;
155     p->initialised = -1;
156     return OK;
157 }
158 /*************************************/
159 
160 /* printk
161  *
162  * Called on every k cycle. It must decide when to do a print operation.
163  */
printk(CSOUND * csound,PRINTK * p)164 int32_t printk(CSOUND *csound, PRINTK *p)
165 {
166     if (UNLIKELY(p->initialised != -1))
167       csound->PerfError(csound, &(p->h), Str("printk not initialised"));
168 
169     //printf("printk: KCNT = %lu\n", CS_KCNT);
170     //printf("printat = %lf\n", p->printat);
171     /* Now test if the cycle number has reached the next print time */
172     if (p->printat <= CS_KCNT-1) {
173       /* Do the print cycle.
174        * Print instrument number and time. Instrument number stuff from
175        * printv() in disprep.c.
176        */
177       csound->MessageS(csound, CSOUNDMSG_ORCH, " i%4d ",
178                                (int32_t)p->h.insdshead->p1.value);
179       csound->MessageS(csound, CSOUNDMSG_ORCH, Str("time %11.5f: "),
180                                csound->icurTime/csound->esr-CS_ONEDKR);
181       /* Print spaces and then the value we want to read.   */
182       if (p->pspace > 0L) {
183         char  s[128];   /* p->pspace is limited to 120 in printkset() above */
184         memset(s, ' ', 128 /*(size_t) p->pspace */);
185         s[p->pspace] = '\0';
186         csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", s);
187       }
188       if (*p->named)
189         csound->MessageS(csound, CSOUNDMSG_ORCH, "%s = %11.5f\n",
190                          p->h.optext->t.inlist->arg[1], *p->val);
191       else
192         csound->MessageS(csound, CSOUNDMSG_ORCH, "%11.5f\n", *p->val);
193       p->printat = CS_KCNT + p->ctime - 1;
194     }
195     return OK;
196 }
197 
198 /*---------------------------------------------------------------------------*/
199 
200 /* printks() and printksset() */
201 
202 /* Printing at k rate with a string * and up to four variables - printks. */
203 
204 #define ESC (0x1B)
205 
206 /* printksset is called when the instance of the instrument is initialised. */
printksset_(CSOUND * csound,PRINTKS * p,char * sarg)207 int32_t printksset_(CSOUND *csound, PRINTKS *p, char *sarg)
208 {
209     char        *sdest;
210     char        temp, tempn;
211 
212     if (*p->ptime < CS_ONEDKR)
213       p->ctime = CS_ONEDKR;
214     else
215       p->ctime = *p->ptime * csound->ekr;
216     if(!p->h.insdshead->reinitflag)
217        p->printat = CS_KCNT;
218     memset(p->txtstring, 0, 8192);   /* This line from matt ingalls */
219     sdest = p->txtstring;
220     /* Copy the string to the storage place in PRINTKS.
221      *
222      * We will look out for certain special codes and write special
223      * bytes directly to the string.
224      *
225      * There is probably a more elegant way of doing this, then using
226      * the look flag.  I could use goto - but I would rather not.      */
227     /* This is really a if then else if...
228      * construct and is currently grotty -- JPff */
229     while (*sarg) {
230       temp  = *sarg++;
231       tempn = *sarg--;
232       /* Look for a single caret and insert an escape char.  */
233       if ((temp  == '^') && (tempn != '^')) {
234         *sdest++ = ESC;
235       }
236 /* Look for a double caret and insert a single caret - stepping forward  one */
237       else if ((temp  == '^') && (tempn == '^')) {
238         *sdest++ = '^';
239         sarg++;
240       }
241 /* Look for a single tilde and insert an escape followed by a '['.
242  * ESC[ is the escape sequence for ANSI consoles */
243       else if ((temp  == '~') && (tempn != '~')) {
244         *sdest++ = ESC;
245         *sdest++ = '[';
246       }
247 /* Look for a double tilde and insert a tilde caret - stepping forward one.  */
248       else if ((temp  == '~') && (tempn == '~')) {
249         *sdest++ = '~';
250         sarg++;
251       }
252       /* Look for \n, \N etc */
253       else if (temp == '\\') {
254         switch (tempn) {
255         case 'r': case 'R':
256           *sdest++ = '\r';
257           sarg++;
258           break;
259         case 'n': case 'N':
260           *sdest++ = '\n';
261           sarg++;
262           break;
263         case 't': case 'T':
264           *sdest++ = '\t';
265           sarg++;
266           break;
267         case 'a': case 'A':
268           *sdest++ = '\a';
269           sarg++;
270           break;
271         case 'b': case 'B':
272           *sdest++ = '\b';
273           sarg++;
274           break;
275         case '\\':
276           *sdest++ = '\\';
277           sarg++;
278           break;
279         default:
280           *sdest++ = tempn;
281           sarg++;
282           break;
283         }
284       }
285       /* This case is from matt ingalls */
286       else if (temp == '%' && tempn != '%' ) {
287         /* an extra option to specify tab and
288            return as %t and %r*/
289         /* allowing for %% escape -- VL */
290         switch (tempn) {
291         case 'r': case 'R':
292           *sdest++ = '\r';
293           sarg++;
294           break;
295         case 'n': case 'N':
296           *sdest++ = '\n';
297           sarg++;
298           break;
299         case 't': case 'T':
300           *sdest++ = '\t';
301           sarg++;
302           break;
303         case '!':     /* and a ';' */
304           *sdest++ = ';';
305           sarg++;
306           break;
307           // case '%':             /* Should we do this? JPff */
308           // *sdest++ = '%';       /* No. VL */
309           // sarg++;
310           // break;
311         default:
312           *sdest++ = temp;
313           break;
314         }
315       }
316       else {
317         /* If none of these match, then copy the character directly
318          * and try again.      */
319         *sdest++ = temp;
320       }
321       /* Increment pointer and process next character until end of string.  */
322       ++sarg;
323     }
324     if(!p->h.insdshead->reinitflag)
325        p->printat = CS_KCNT;
326     p->initialised = -1;
327     return OK;
328 }
329 
printksset_S(CSOUND * csound,PRINTKS * p)330 int32_t printksset_S(CSOUND *csound, PRINTKS *p){
331     char *sarg;
332     sarg = ((STRINGDAT*)p->ifilcod)->data;
333     if (sarg == NULL) return csoundInitError(csound, Str("null string\n"));
334     p->old = cs_strdup(csound, sarg);
335     return printksset_(csound, p, sarg);
336 }
337 
printksset(CSOUND * csound,PRINTKS * p)338 int32_t printksset(CSOUND *csound, PRINTKS *p){
339     char* arg_string = get_arg_string(csound, *p->ifilcod);
340 
341     if (arg_string == NULL) {
342         return csoundInitError(csound, Str("null string\n"));
343     }
344     return printksset_(csound, p, arg_string);
345 }
346 
347 
348 //perform a sprintf-style format  -- matt ingalls
349 /* void sprints_local(char *outstring, char *fmt, MYFLT **kvals, int32_t numVals) */
350 /* { */
351 /*     char strseg[8192]; */
352 /*     int32_t i = 0, j = 0; */
353 /*     char *segwaiting = 0; */
354 /*     puts(fmt); */
355 /*     while (*fmt) { */
356 /*       if (*fmt == '%') { */
357 /*         /\* if already a segment waiting, then lets print it *\/ */
358 /*         if (segwaiting) { */
359 /*           MYFLT xx = (j>=numVals? FL(0.0) : *kvals[j]); */
360 /*           /\* printf("***xx = %f (int32_t)(xx+.5)=%d round=%d mode=%d\n", *\/ */
361 /*           /\*        xx, (int32_t)(xx+.5), MYFLT2LRND(xx), fegetround()); *\/ */
362 /*           strseg[i] = '\0'; */
363 
364 /*           switch (*segwaiting) { */
365 /*           case 'd': */
366 /*           case 'i': */
367 /*           case 'o': */
368 /*           case 'x': */
369 /*           case 'X': */
370 /*           case 'u': */
371 /*           case 'c': */
372 /*             snprintf(outstring, 8196, strseg, (int32_t)MYFLT2LRND(xx)); */
373 /*             break; */
374 /*           case 'h': */
375 /*             snprintf(outstring, 8196, strseg, (int32_t16)MYFLT2LRND(xx)); */
376 /*             break; */
377 /*           case 'l': */
378 /*             snprintf(outstring, 8196, strseg, (int32_t32)MYFLT2LRND(xx)); */
379 /*             break; */
380 
381 /*           default: */
382 /*          printf("strseg:%s - %c\n", strseg, *segwaiting); */
383 /*             CS_SPRINTF(outstring, strseg, xx); */
384 /*             break; */
385 /*           } */
386 /*           outstring += strlen(outstring); */
387 
388 /*           i = 0; */
389 /*           segwaiting = 0; */
390 
391 /* // prevent potential problems if user didnt give enough input params */
392 /*           if (j < numVals-1) */
393 /*             j++; */
394 /*         } */
395 
396 /*         /\* copy the '%' *\/ */
397 /*         strseg[i++] = *fmt++; */
398 
399 /*         /\* find the format code *\/ */
400 /*         segwaiting = fmt; */
401 /*         while (*segwaiting && !isalpha(*segwaiting)) */
402 /*           segwaiting++; */
403 /*       } */
404 /*       else */
405 /*         strseg[i++] = *fmt++; */
406 /*     } */
407 
408 /*     if (i) { */
409 /*       strseg[i] = '\0'; */
410 /*       if (segwaiting) { */
411 /*         MYFLT xx = (j>=numVals? FL(0.0) : *kvals[j]); */
412 /*            /\* printf("***xx = %f (int32_t)(xx+.5)=%d round=%d mode=%d\n", *\/ */
413 /*            /\*       xx, (int32_t)(xx+.5), MYFLT2LRND(xx), fegetround()); *\/ */
414 /*        switch (*segwaiting) { */
415 /*         case 'd': */
416 /*         case 'i': */
417 /*         case 'o': */
418 /*         case 'x': */
419 /*         case 'X': */
420 /*         case 'u': */
421 /*         case 'c': */
422 /*           snprintf(outstring, 8196, strseg, (int32_t)MYFLT2LRND(xx)); */
423 /*           break; */
424 /*         case 'h': */
425 /*           snprintf(outstring, 8196, strseg, (int16)MYFLT2LRND(xx)); */
426 /*           break; */
427 /*         case 'l': */
428 /*           snprintf(outstring, 8196, strseg, (int32_t)MYFLT2LRND(xx)); */
429 /*           break; */
430 
431 /*         default: */
432 /*           CS_SPRINTF(outstring, strseg, xx); */
433 /*           break; */
434 /*         } */
435 /*       } */
436 /*       else */
437 /*         snprintf(outstring, 8196, "%s", strseg); */
438 /*     } */
439 /* } */
440 /* VL - rewritten 1/16
441    escaping %% correctly now.
442  */
sprints(char * outstring,char * fmt,MYFLT ** kvals,int32_t numVals)443 static int32_t sprints(char *outstring,  char *fmt, MYFLT **kvals, int32_t numVals)
444 {
445     char tmp[8],cc;
446     int32_t j = 0;
447     int32_t len = 8192;
448     while (*fmt) {
449       if (*fmt == '%') {
450         if (*(fmt+1) == '%') {
451           *outstring++ = *fmt++;
452           /* *outstring++ = */ fmt++;
453           len-=1;
454         }
455         else if (*(fmt+1) && isspace(*(fmt+1))) {
456           *outstring++ = *fmt++;
457           *outstring++ = '%';
458           *outstring++ = *fmt++;
459           len-=3;
460         }
461         else {
462           int32_t n = 1;
463           char check='%';
464           tmp[0] = check;
465           while (*(fmt+n) &&
466                 !isblank(*(fmt+n))) {
467             tmp[n] = *(fmt+n);
468             if (isalpha(tmp[n])) { check = tmp[n]; break;}
469             n++;
470           }
471           tmp[n] = *(fmt+n);
472           tmp[n+1] = '\0';
473           n++;
474           if (j>=numVals) return NOTOK;
475           switch (check) {
476           case 'd':
477           case 'i':
478           case 'o':
479           case 'x':
480           case 'X':
481           case 'u':
482             snprintf(outstring, len, tmp, MYFLT2LRND(*kvals[j]));
483             break;
484           case 'c':
485             cc  = (char) MYFLT2LRND(*kvals[j]);
486             if (cc == '%') {
487               *outstring++ = '%';
488             }
489             snprintf(outstring, len, tmp, cc);
490             break;
491           case 's':
492             {
493               if (csoundGetTypeForArg(kvals[j]) == &CS_VAR_TYPE_S)
494                 snprintf(outstring, len, tmp,  ((STRINGDAT*)kvals[j])->data);
495               else snprintf(outstring, len, tmp, "??");
496               break;
497             }
498           default:
499             //puts(fmt);
500             snprintf(outstring, len, tmp, *kvals[j]);
501             break;
502           }
503           if (j < numVals-1)
504             j++;
505           fmt += n;
506           outstring += strlen(outstring);
507           len -= strlen(outstring);
508         }
509       }
510       else {
511         *outstring++ = *fmt++; *outstring = '\0';
512         len--;
513       }
514     }
515     return OK;
516 }
517 
518 
519 /*************************************/
520 
521 /* printks is called on every k cycle
522  * It must decide when to do a
523  * print operation.
524  */
printks(CSOUND * csound,PRINTKS * p)525 int32_t printks(CSOUND *csound, PRINTKS *p)
526 {
527     char        string[8192]; /* matt ingals replacement */
528 
529     if (csound->ISSTRCOD(*p->ifilcod) == 0) {
530       char *sarg;
531       sarg = ((STRINGDAT*)p->ifilcod)->data;
532       if (sarg == NULL)
533         return csoundPerfError(csound, &(p->h), Str("null string\n"));
534       if (p->old==NULL || strcmp(sarg, p->old) != 0) {
535         printksset_(csound, p, sarg);
536         csound->Free(csound, p->old);
537         p->old = cs_strdup(csound, sarg);
538       }
539     }
540 
541     /*-----------------------------------*/
542     if (UNLIKELY(p->initialised != -1))
543       csound->PerfError(csound, &(p->h), Str("printks not initialised"));
544     if (p->printat <= CS_KCNT-1) {
545       //string[0]='\0';           /* incase of empty string */
546       memset(string,0,8192);
547       if (sprints(string, p->txtstring, p->kvals, p->INOCOUNT-2)!=OK)
548         return
549           csound->PerfError(csound,  &(p->h),
550                             Str("Insufficient arguments in formatted printing"));
551       csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", string);
552       p->printat = CS_KCNT + p->ctime -1;
553     }
554     return OK;
555 }
556 
557 /* matt ingalls --  i-rate prints */
printsset(CSOUND * csound,PRINTS * p)558 int32_t printsset(CSOUND *csound, PRINTS *p)
559 {
560     PRINTKS pk;
561     char    string[8192];
562     MYFLT ptime = 1;
563     string[0] = '\0';    /* necessary as sprints is not nice */
564     pk.h = p->h;
565     pk.ifilcod = p->ifilcod;
566     pk.ptime = &ptime;
567     printksset(csound, &pk);
568     memset(string,0,8192);
569     memset(pk.txtstring,0,sizeof(pk.txtstring));
570     if (sprints(string, pk.txtstring, p->kvals, p->INOCOUNT-1)!=OK)
571         return
572           csound->InitError(csound,
573                             Str("Insufficient arguments in formatted printing"));
574     csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", string);
575     return OK;
576 }
577 
printsset_S(CSOUND * csound,PRINTS * p)578 int32_t printsset_S(CSOUND *csound, PRINTS *p)
579 {
580     PRINTKS pk;
581     char   string[8192];
582     MYFLT ptime = 1;
583     string[0] = '\0';    /* necessary as sprints is not nice */
584     pk.h = p->h;
585     pk.ifilcod = p->ifilcod;
586     pk.ptime = &ptime;
587     printksset_S(csound, &pk);
588     if (strlen(pk.txtstring) < 8191){
589       memset(string,0,8192);
590     if (sprints(string, pk.txtstring, p->kvals, p->INOCOUNT-1)!=OK)
591         return
592           csound->InitError(csound,
593                             Str("Insufficient arguments in formatted printing"));
594     csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", string);
595     } else {
596       csound->Warning(csound,
597                       Str("Formatting string too long: %s"), pk.txtstring);
598     }
599     return OK;
600 }
601 
602 /*****************************************************************************/
603 
604 /* peakk and peak ugens */
605 
606 /* peakk()
607  *
608  * Write the absolute value of the input argument to the output if the former
609  * is higher. */
peakk(CSOUND * csound,PEAK * p)610 int32_t peakk(CSOUND *csound, PEAK *p)
611 {
612    IGN(csound);
613     if (*p->kpeakout < FABS(*p->xsigin)) {
614       *p->kpeakout = FABS(*p->xsigin);
615     }
616     return OK;
617 }
618 
619 /* peaka()
620  *
621  * Similar to peakk, but looks at an a rate input variable. */
peaka(CSOUND * csound,PEAK * p)622 int32_t peaka(CSOUND *csound, PEAK *p)
623 {
624     IGN(csound);
625     uint32_t offset = p->h.insdshead->ksmps_offset;
626     uint32_t early  = p->h.insdshead->ksmps_no_end;
627     uint32_t n, nsmps = CS_KSMPS;
628     MYFLT   *peak, pp;
629     MYFLT   *asigin;
630 
631     asigin = p->xsigin;
632     peak = p->kpeakout;
633     pp = *peak;
634     if (UNLIKELY(early)) nsmps -= early;
635     for (n=offset;n<nsmps;n++) {
636       MYFLT x = FABS(asigin[n]);
637       if (pp < x) pp = x;
638     }
639     *peak = pp;
640     return OK;
641 }
642 
643 /*****************************************************************************/
644 
645 /* Gab 21-8-97 */
646 /* print a k variable each time it changes (useful for MIDI control sliders) */
647 
printk2set(CSOUND * csound,PRINTK2 * p)648 int32_t printk2set(CSOUND *csound, PRINTK2 *p)
649 {
650     IGN(csound);
651     p->pspace = (int32_t)*p->space;
652     if (UNLIKELY(p->pspace < 0))
653       p->pspace = 0;
654     else if (UNLIKELY(p->pspace > 120))
655       p->pspace = 120;
656     p->oldvalue = FL(-1.12123e35);  /* hack to force printing first value */
657     return OK;
658 }
659 
660 /* Gab 21-8-97 */
661 /* print a k variable each time it changes (useful for MIDI control sliders) */
662 
printk2(CSOUND * csound,PRINTK2 * p)663 int32_t printk2(CSOUND *csound, PRINTK2 *p)
664 {
665     MYFLT   value = *p->val;
666 
667     if (p->oldvalue != value) {
668       csound->MessageS(csound, CSOUNDMSG_ORCH, " i%d ",
669                                                (int32_t)p->h.insdshead->p1.value);
670       if (p->pspace > 0) {
671         char  s[128];   /* p->pspace is limited to 120 in printk2set() above */
672         memset(s, ' ', (size_t) p->pspace);
673         s[p->pspace] = '\0';
674         csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", s);
675       }
676       if (*p->named)
677         csound->MessageS(csound, CSOUNDMSG_ORCH, "%s = %11.5f\n",
678                          *p->h.optext->t.inlist->arg, *p->val);
679       else
680         csound->MessageS(csound, CSOUNDMSG_ORCH, "%11.5f\n", *p->val);
681       p->oldvalue = value;
682     }
683     return OK;
684 }
685 
printk3set(CSOUND * csound,PRINTK3 * p)686 int32_t printk3set(CSOUND *csound, PRINTK3 *p)
687 {
688     IGN(csound);
689     p->oldvalue = FL(-1.12123e35);  /* hack to force printing first value */
690     p->sarg = ((STRINGDAT*)p->iformat)->data;
691     return OK;
692 }
693 
printk3(CSOUND * csound,PRINTK3 * p)694 int32_t printk3(CSOUND *csound, PRINTK3 *p)
695 {
696     MYFLT   value = *p->val;
697 
698     if (p->oldvalue != value) {
699       char buff[8196];
700       MYFLT *vv[1];
701       vv[0] = &value;
702       buff[0] = '\0';
703       if (sprints(buff, p->sarg, vv, 1)!=OK)
704         return
705           csound->PerfError(csound,  &(p->h),
706                             Str("Insufficient arguments in formatted printing"));
707       csound->MessageS(csound, CSOUNDMSG_ORCH, "%s", buff);
708       p->oldvalue = value;
709     }
710     //else printf("....%f %f\n", p->oldvalue, value);
711     return OK;
712 }
713 
714 /* inz writes to za space at a rate as many channels as can. */
inz(CSOUND * csound,IOZ * p)715 int32_t inz(CSOUND *csound, IOZ *p)
716 {
717     int32_t    indx, i;
718     int32_t     nchns = csound->GetNchnls(csound);
719     uint32_t offset = p->h.insdshead->ksmps_offset;
720     uint32_t early  = p->h.insdshead->ksmps_no_end;
721     uint32_t n, nsmps = CS_KSMPS;
722     /* Check to see this index is within the limits of za space.     */
723     MYFLT* zastart;
724     int zalast = csound->GetZaBounds(csound, &zastart);
725     indx = (int32_t) *p->ndx;
726     if (UNLIKELY(indx + nchns >= zalast)) goto err1;
727     else if (UNLIKELY(indx < 0)) goto err2;
728     else {
729       MYFLT *writeloc;
730       /* Now write to the array in za space pointed to by indx.    */
731       writeloc = zastart + (indx * nsmps);
732       early = nsmps - early;
733       for (i = 0; i < nchns; i++)
734         for (n = 0; n < nsmps; n++)
735           *writeloc++ = ((n>=offset && n<early) ?
736                          CS_SPIN[i * nsmps+n] : FL(0.0));
737     }
738     return OK;
739  err1:
740     return csound->PerfError(csound, &(p->h),
741                              Str("inz index > isizea. Not writing."));
742  err2:
743     return csound->PerfError(csound, &(p->h),
744                              Str("inz index < 0. Not writing."));
745 }
746 
747 /* outz reads from za space at a rate to output. */
outz(CSOUND * csound,IOZ * p)748 int32_t outz(CSOUND *csound, IOZ *p)
749 {
750     int32_t    indx;
751     int32_t     i;
752     uint32_t offset = p->h.insdshead->ksmps_offset;
753     uint32_t early  = p->h.insdshead->ksmps_no_end;
754     uint32_t n, nsmps = CS_KSMPS;
755     int32_t     nchns = csound->GetNchnls(csound);
756     MYFLT *spout = csound->spraw;
757 
758     /* Check to see this index is within the limits of za space.    */
759     MYFLT* zastart;
760     int zalast = csound->GetZaBounds(csound, &zastart);
761     indx = (int32) *p->ndx;
762     if (UNLIKELY((indx + nchns) >= zalast)) goto err1;
763     else if (UNLIKELY(indx < 0)) goto err2;
764     else {
765       MYFLT *readloc;
766       /* Now read from the array in za space and write to the output. */
767       readloc = zastart + (indx * nsmps);
768       early = nsmps-early;
769       if (!csound->spoutactive) {
770         memset(spout, '\0', nchns*nsmps*sizeof(MYFLT));
771         for (i = 0; i < nchns; i++) {
772           memcpy(&spout[i * nsmps+offset], readloc+offset,
773                  (early-offset)*sizeof(MYFLT));
774           readloc += nsmps;
775         }
776         csound->spoutactive = 1;
777       }
778       else {
779         for (i = 0; i < nchns; i++) {
780           for (n = offset; n < nsmps-early; n++) {
781             spout[n + i*nsmps] += readloc[n];
782           }
783           readloc += nsmps;
784         }
785       }
786     }
787     return OK;
788  err1:
789     return csound->PerfError(csound, &(p->h),
790                              Str("outz index > isizea. No output"));
791  err2:
792     return csound->PerfError(csound, &(p->h),
793                              Str("outz index < 0. No output."));
794 }
795