[Csnd] Debugging a GEN Routine C-Code

Hello everybody!
I’m diving into GEN routine development to learn some C and for a university class.

Over the past few days, I’ve written a GEN routine based on the Lorenz attractor to generate control data. My C code compiles and runs inside Csound, but I’m confused about the output of the GEN routine.
I’ve implemented a scaling function to map the values in the table to a specified range (e.g., between a minimum and maximum), but the results aren’t as expected. To debug, I’ve added printf statements in the C code to check the intermediate values, and everything seems fine there.

However, when I use ftprint in Csound, the table values don’t match what the C code prints. For example, if I scale the values to the range [3, 10], I end up with values in Csound between 0.3 and 1.0. The scaling logic in the C code seems correct, so I’m unsure why the output is wrong.

Here are some thoughts on what might be causing the issue:
    • Csound might be normalizing the table values to fit within the range [-1, 1], and values outside this range might not be allowed.
    • I could be compiling my GEN routine incorrectly.

Below is my C code and my compile command — maybe there’s an error I’ve overlooked. Any help would be greatly appreciated!
Thank you!
—Philipp

gcc -shared -o lorenz-gen.dylib -I/Library/Frameworks/CsoundLib64.framework/Versions/6.0/Headers/ lorenz-gen.c

\#include "csdl\.h"
\#include "csoundCore\.h"
/\*
  p3 = size
  p4 = GEN routine
  p5 = choose axis to write; 0 = x, 1 = y, 2 = z
  p6 = min output
  p7 = max output
  p8 = stepsize
  p9 = x start
  p10 = y start
  p11 = z start
  f1 0 4096 "lorenz" "x" \-1 1 5

\*/
void scale\_array\(MYFLT \*fp, MYFLT min\_out, MYFLT max\_out, int32\_t size\)
\{
  MYFLT min\_in = fp\[0\];
  MYFLT max\_in = fp\[0\];
  
  for\(int i = 1; i < size; i\+\+\)\{
    if\(fp\[i\] < min\_in\)
      min\_in = fp\[i\];
    if\(fp\[i\] > max\_in\)
      max\_in = fp\[i\];
  \}

  MYFLT old\_value;
  for\(int j = 0; j < size; j\+\+\)\{
    old\_value = fp\[j\];
    printf\("old value: %f\\n", old\_value\);
    fp\[j\] =  min\_out \+ \(\(old\_value \- min\_in\) / \(max\_in \- min\_in\)\)
      \* \(max\_out \- min\_out\);
    printf\("new value: %f\\ns",fp\[j\]\);
    printf\("sohuld value: %f\\n", \(min\_out \+ \(\(old\_value \- min\_in\) / \(max\_in \- min\_in\)\)
      \* \(max\_out \- min\_out\)\)\);
  \}
\}

static int32\_t lorenztable\(FGDATA \*ff, FUNC \*ftp\)
\{
  /\* function table \*/
  MYFLT \*fp = ftp\->ftable;
    
  /\* default arguments \*/
  MYFLT sigma = 10;
  MYFLT rho = 28;
  MYFLT beta = 8\.0/3\.0;
  MYFLT time = 0\.001;

  /\* p\-field arguments \*/
  int32\_t ft\_size = ftp\->flen;
  MYFLT min\_out = ff\->e\.p\[6\];
  MYFLT max\_out = ff\->e\.p\[7\];
  MYFLT step\_size = ff\->e\.p\[8\];
  MYFLT x = ff\->e\.p\[9\];
  MYFLT y = ff\->e\.p\[10\];
  MYFLT z = ff\->e\.p\[11\];

  /\* write raw data to ft \*/
  for \(int i = 0; i < ft\_size; i\+\+\)
    \{
      if \(ff\->e\.p\[5\] == 0\)\{
  fp\[i\] = x;
      \} else if \(ff\->e\.p\[5\] == 1\)\{
  fp\[i\] = y;
      \} else if \(ff\->e\.p\[5\] == 2\)\{
  fp\[i\] = z;
      \}
      
      for \(int j = 0; j < step\_size; j\+\+\)\{
  x \+= \(sigma \* \(y \- z\)\) \* time;
  y \+= \(x \* \(rho \- z\) \- y\) \* time;
  z \+= \(\(x \* y\) \- \(beta \* z\)\) \* time;
      \}
    \}

  /\* scale data of ft \*/
  scale\_array\(fp, min\_out, max\_out, ft\_size\);

  return OK;
\}

static NGFENS localfgens\[\] = \{
  \{ "lorenz", lorenztable\},
  \{ NULL, NULL\}
\};

FLINKAGE\_BUILTIN\(localfgens\)

\`\`\`
Csound mailing list
Csound@listserv\.heanet\.ie
https://listserv.heanet.ie/cgi-bin/wa?A0=CSOUND
Send bugs reports to
        https://github.com/csound/csound/issues
Discussions of bugs and features can be posted here

Hi Philip. If you use a negative gen number in your score it will prevent automatic normalisation of your table data. :+1:

Thanks Rory!
But i implemented the GEN routine as GEN“lorenz“ and i call it by the string „lorenz“. How can i use this with a string?
And is this a default method to every GEN routine or must this implemented in the GEN code?

This is default for all gen routines afaik. As to your first question, I’m not sure. Can you simply prepend a -?

Thank you for this hint!

I always thought this is something you had to implement to the code and is not a csound default!

And in the „tanh“ exxample i found the solution to this:
you have to implement a p-field designated to the rescaling function and then you can make the p4 field negativ

  if(resc!=0.0)
    ff->e.p[4] = -1;