<!-- Converted to DocBook/SGML by Kevin Conder -->
<section id="CscoreMain">
  <title>Writing a Main Program</title>

  <para>
    The general format for a control program is:

    <informalexample>
      <programlisting>
#include  &quot;cscore.h&quot; 
cscore() 
{ 
 /*  VARIABLE DECLARATIONS  */ 
 /*  PROGRAM BODY  */ 
}
      </programlisting>
    </informalexample>
  </para>

  <para>
    The include statement will define the event and list structures for the program. The following C program will read from a<emphasis> standard numeric score,</emphasis> up to (but not including) the first <emphasis>s</emphasis> or <emphasis>e statement</emphasis>, then write that data (unaltered) as output.
  </para>

  <para>
    <informalexample>
      <programlisting>
#include  &quot;cscore.h&quot; 
cscore() 
{ 
     EVLIST *a;       /* a is allowed to point to an event list */ 
     a = lget();      /* read events in, return the list pointer */ 
     lput(a);         /* write these events out (unchanged) */ 
     putstr(&quot;e&quot;);     /* write the string e to output */ 
}
      </programlisting>
    </informalexample>
  </para>

  <para>
    After execution of <emphasis>lget()</emphasis>, the variable a points to a list of event addresses, each of which points to a stored event. We have used that same pointer to enable another list function (<emphasis>lput</emphasis>) to access and write out all of the events that were read. If we now define another symbol <emphasis>e</emphasis> to be an event pointer, then the statement

    <informalexample>
      <programlisting>
e = a-e[4];
      </programlisting>
    </informalexample>

    will set it to the contents of the 4th slot in the <emphasis>evlist</emphasis> structure. The contents is a pointer to an event, which is itself comprised of an <emphasis>array </emphasis>of parameter field values. Thus the term <emphasis>e-p[5]</emphasis> will mean the value of parameter field 5 of the 4th event in the<emphasis> evlist</emphasis> denoted by <emphasis>a</emphasis>. The program below will multiply the value of that <emphasis>pfield </emphasis>by 2 before writing it out.

    <informalexample>
      <programlisting>
#include  &quot;cscore.h&quot; 
cscore() 
{ 
     EVENT  *e;       /* a pointer to an event   */ 
     EVLIST *a; 
     a = lget();      /* read a score as a list of events */ 
     e = a-e[4];     /* point to event 4 in event list a  */ 
     e-p[5] *= 2;    /* find pfield 5, multiply its value by 2 */ 
     lput(a);         /* write out the list of events  */ 
     putstr(&quot;e&quot;);     /* add a &quot;score end&quot; statement */ 
}
      </programlisting>
    </informalexample>
  </para>

  <para>
    Now consider the following score, in which <emphasis>p[5]</emphasis> contains frequency in Hz.

    <informalexample>
      <programlisting>
f 1 0 257 10 1 
f 2 0 257 7 0 300 1 212 .8 
i 1 1 3 0 440 10000 
i 1 4 3 0 256 10000 
i 1 7 3 0 880 10000 
e
      </programlisting>
    </informalexample>
  </para>

  <para>
    If this score were given to the preceding main program, the resulting output would look like this:

    <informalexample>
      <programlisting>
f 1 0 257 10 1 
f 2 0 257 7 0 300 1 212 .8 
i 1 1 3 0 440 10000 
i 1 4 3 0 512 10000        ; p[5] has become 512 instead of 256. 
i 1 7 3 0 880 10000 
e
      </programlisting>
    </informalexample>
  </para>

  <para>
    Note that the 4th event is in fact the second note of the score. So far we have not distinguished between notes and function table setup in a numeric score. Both can be classed as events. Also note that our 4th event has been stored in <emphasis>e[4]</emphasis> of the structure. For compatibility with Csound <emphasis>pfield</emphasis> notation, we will ignore <emphasis>p[0]</emphasis> and <emphasis>e[0]</emphasis> of the event and list structures, storing <emphasis>p1</emphasis> in <emphasis>p[1]</emphasis>, event 1 in <emphasis>e[1]</emphasis>, etc. The<emphasis> Cscore </emphasis>functions all adopt this convention.
  </para>

  <para>
    As an extension to the above, we could decide to use <emphasis>a</emphasis> and <emphasis>e</emphasis> to examine each of the events in the list. Note that e has not preserved the numeral 4, but the contents of that slot. To inspect <emphasis>p5</emphasis> of the previous listed event we need only redefine e with the assignment

    <informalexample>
      <programlisting>
e = a-e[3];
      </programlisting>
    </informalexample>
  </para>

  <para>
    More generally, if we declare a new variable <emphasis>f </emphasis>to be a pointer to a pointer to an event, the statement

    <informalexample>
      <programlisting>
f = &amp;a-e[4];
      </programlisting>
    </informalexample>

    will set <emphasis>f</emphasis> to the address of the fourth event in the event list <emphasis>a,</emphasis> and <emphasis>*f</emphasis> will signify the contents of the slot, namely the event pointer itself. The expression

    <informalexample>
      <programlisting>
(*f)-p[5],
      </programlisting>
    </informalexample>

    like <emphasis>e-p[5]</emphasis>, signifies the fifth pfield of the selected event. However, we can advance to the next slot in the <emphasis>evlist</emphasis> by advancing the pointer <emphasis>f</emphasis>. In C this is denoted by <emphasis>f++</emphasis>.
  </para>

  <para>
    In the following program we will use the same input score. This time we will separate the <emphasis>ftable</emphasis> statements from the <emphasis>note </emphasis>statements. We will next write the three note-events stored in the list<emphasis> a,</emphasis> then create a second score section consisting of the original pitch set and a transposed version of itself. This will bring about an octave doubling.
  </para>

  <para>
    By pointing the variable<emphasis> f</emphasis> to the first note-event and incrementing <emphasis>f</emphasis> inside a while block which iterates<emphasis> n </emphasis>times (the number of events in the list), one statement can be made to act upon the same <emphasis>pfield</emphasis> of each successive event.

    <informalexample>
      <programlisting>
#include  &quot;cscore.h&quot;
 cscore()
 {
      EVENT *e,**f;            /* declarations. see pp.8-9 in the */ 
      EVLIST *a,*b;            /* C language programming manual */ 
      int n; 
      a = lget();              /* read score into event list &quot;a&quot; */ 
      b = lsepf(a);            /* separate f statements */ 
      lput(b);                 /* write f statements out to score */ 
      lrelev(b);               /* and release the spaces used */ 
      e = defev(&quot;t 0 120&quot;);    /* define event for tempo statement */ 
      putev(e);                /* write tempo statement to score */ 
      lput(a);                 /* write the notes */ 
      putstr(&quot;s&quot;);             /* section end */ 
      putev(e);                /* write tempo statement again */ 
      b = lcopyev(a);          /* make a copy of the notes in &quot;a&quot; */ 
      n = b-nevents;          /* and get the number present */ 
      f = &amp;a-e[1]; 
      while (n--)              /* iterate the following line n times: */ 
          (*f++)-p[5] *= .5;  /*   transpose pitch down one octave */ 
      a = lcat(b,a);           /* now add these notes to original pitches */ 
      lput(a); 
      putstr(&quot;e&quot;);
     }
      </programlisting>
    </informalexample>

    The output of this program is:

    <informalexample>
      <programlisting>
f 1 0 257 10 1 
f 2 0 257 7 0 300 1 212 .8 
t 0 120 
i 1 1 3 0 440 10000 
i 1 4 3 0 256 10000 
i 1 7 3 0 880 10000 
s 
t 0 120 
i 1 1 3 0 440 10000 
i 1 4 3 0 256 10000 
i 1 7 3 0 880 10000 
i 1 1 3 0 220 10000 
i 1 4 3 0 128 10000 
i 1 7 3 0 440 10000 
e
      </programlisting>
    </informalexample>
  </para>

  <para>
    Next we extend the above program by using the while statement to look at <emphasis>p[5]</emphasis> and <emphasis>p[6]</emphasis>. In the original score <emphasis>p[6]</emphasis> denotes amplitude. To create a diminuendo in the added lower octave, which is independent from the original set of notes, a variable called <emphasis>dim</emphasis> will be used.

    <informalexample>
      <programlisting>
#include &quot;cscore.h&quot; 
cscore() 
{ 
  EVENT *e,**f; 
  EVLIST *a,*b; 
  int n, dim;                /* declare two integer variables   */ 
  a = lget(); 
  b = lsepf(a); 
  lput(b); 
  lrelev(b); 
  e = defev(&quot;t 0 120&quot;); 
  putev(e); 
  lput(a); 
  putstr(&quot;s&quot;); 
  putev(e);                  /* write out another tempo statement */ 
  b = lcopyev(a); 
  n = b-nevents; 
  dim = 0;                   /* initialize dim to 0 */ 
  f = &amp;a-e[1]; 
  while (n--){ 
       (*f)-p[6] -= dim;    /* subtract current value of dim */ 
       (*f++)-p[5] *= .5;   /* transpose, move f to next event */ 
       dim += 2000;          /* increase dim for each note */ 
  } 
  a = lcat(b,a); 
  lput(a); 
  putstr(&quot;e&quot;);
} 
      </programlisting>
    </informalexample>
  </para>

  <para>
    The increment of <emphasis>f</emphasis> in the above programs has depended on certain precedence rules of C.  Although this keeps the code tight, the practice can be dangerous for beginners.  Incrementing may alternately be written as a separate statement to make it more clear.

    <informalexample>
      <programlisting>
while (n--){ 
     (*f)-p[6] -= dim; 
     (*f)-p[5] *= .5; 
     dim += 2000; 
     f++; 
}
      </programlisting>
    </informalexample>
  </para>

  <para>
    Using the same input score again, the output from this program is:

    <informalexample>
      <programlisting>
f 1 0 257 10 1 
f 2 0 257 7 0 300 1 212 .8 
t 0 120 
i 1 1 3 0 440 10000 
i 1 4 3 0 256 10000 
i 1 7 3 0 880 10000 
s 
t 0 120 
i 1 1 3 0 440 10000     ; Three original notes at 
i 1 4 3 0 256 10000     ; beats 1,4 and 7 with no dim. 
i 1 7 3 0 880 10000 
i 1 1 3 0 220 10000     ; three notes transposed down one octave 
i 1 4 3 0 128 8000      ; also at beats 1,4 and 7 with dim. 
i 1 7 3 0 440 6000 
e
      </programlisting>
    </informalexample>
  </para>

  <para>
    In the following program the same three-note sequence will be repeated at various time intervals. The starting time of each group is determined by the values of the <emphasis>array</emphasis> cue. This time the <emphasis>dim</emphasis> will occur for each group of notes rather than each note. Note the position of the statement which increments the variable <emphasis>dim</emphasis> outside the inner while block.

    <informalexample>
      <programlisting>
#include  &quot;cscore.h&quot; 
int cue[3]={0,10,17};              /* declare an array of 3 integers */ 
cscore() 
{
     EVENT *e, **f;
     EVLIST *a, *b;
     int n, dim, cuecount, holdn;  /* declare new variables */ 
     a = lget(); 
     b = lsepf(a); 
     lput(b); 
     lrelev(b); 
     e = defev(&quot;t 0 120&quot;); 
     putev(e); 
     n = a-nevents; 
     holdn = n;                    /* hold the value of &quot;n&quot; to reset below */ 
     cuecount = 0;                 /* initialize cuecount to &quot;0&quot; */ 
     dim = 0; 
     while (cuecount &lt;= 2) {       /* count 3 iterations of inner &quot;while&quot; */ 
          f = &amp;a-e[1];            /* reset pointer to first event of list &quot;a&quot; */ 
          n = holdn;               /* reset value of &quot;n&quot; to original note count */ 
          while (n--) { 
              (*f)-p[6] -= dim; 
              (*f)-p[2] += cue[cuecount];   /* add values of cue */ 
              f++; 
          } 
          printf(&quot;; diagnostic:  cue = %d\n&quot;, cue[cuecount]); 
          cuecount++; 
          dim += 2000; 
           lput(a); 
     } 
     putstr(&quot;e&quot;); 
}
      </programlisting>
    </informalexample>
  </para>

  <para>
    Here the inner while block looks at the events of list a (the notes) and the outer while block looks at each repetition of the<emphasis> events</emphasis> of list a (the pitch group repetitions). This program also demonstrates a useful trouble-shooting device with the <emphasis>printf</emphasis> function. The <emphasis>semi-colon</emphasis> is first in the character string to produce a comment statement in the resulting score file. In this case the value of cue is being printed in the output to insure that the program is taking the proper <emphasis>array</emphasis> member at the proper time. When output data is wrong or error messages are encountered, the <emphasis>printf</emphasis> function can help to pinpoint the problem.
  </para>

  <para>
    Using the identical input file, the C program above will generate:

    <informalexample>
      <programlisting>
f 1 0 257 10 1 
f 2 0 257 7 0 300 1 212 .8 
t 0 120 
; diagnostic:  cue = 0 
i 1 1 3 0 440 10000 
i 1 4 3 0 256 10000 
i 1 7 3 0 880 10000 
; diagnostic:  cue = 10 
i 1 11 3 0 440 8000 
i 1 14 3 0 256 8000 
i 1 17 3 0 880 8000 
; diagnostic:  cue = 17 
i 1 28 3 0 440 4000 
i 1 31 3 0 256 4000 
i 1 34 3 0 880 4000 
e;
      </programlisting>
    </informalexample>
  </para>
</section>
