CSOUND JOURNAL ISSUE 23

INDEX | ABOUT | LINKS

Introduction

After designing Csound instruments for signal generation or production, a higher level of function is useful for the organization and manipulation of instruments leading toward the facilitation of phrases, sections, structures, form or complete compositions. Csound opcodes, which lead towards higher organization, are not one type of opcode, but are rather many different opcodes, dispersed throughout the general collection, each designed for a specific purpose. Csound contains several opcodes for instrument manipulation as tools to aid in the creation of larger structures which we might call macro or meta level processing. These opcodes allow for compiling, building, combining, mixing, loading, reading, removing, and time placement, among other tasks, which we may describe as meta things. Versions used for this article were Fedora 24, Csound Version 6.08.

I. Top-down, Bottom-up

Working at the level of instrument design and audio quality is important for a solid beginning design foundation, but at a certain point we need to begin to think about the organization of the performance of the sounds. In Csound, the note list or score is still the standard means for placing instrument output in time, although it also possible to chose a scoreless design. On a higher level we might design lists of note lists, which then can become a meta level task. Gottfried Michael Koening has written that "sound production is not interesting as a composition process until it becomes integral, i.e. until the structure-generating grammar refers to sound data instead of to given sound elements"[1]. Koening seems to be writing about the awareness of process and procedure, moving from the small to the large, and by extension to the extra large.

In Csound, many opcodes were created to fulfill a needs requirement. For example, a tool is needed to perform a specific task, and because that task might also be useful to others, an opcode is implemented. An opcode can fall into a general pattern of usability or usefulness based on how amazing, functional, predictable, robust or utilitarian its performance. In some cases a developer discovers the need for an opcode thru their own creative work, for performing calculations, opening pathways, facilitating interoperability, establishing a theorem, or supporting a frontend feature, among other tasks. The opcode is implemented for all to use, but others may not utilize the tool in quite the same manner as the original developer. In practice, as opcodes are placed into blocks, based on their output values, instruments are fashioned, and a functional orchestra file or files begin to emerge. Then moving to a higher level of organization, additional opcodes, so designed, can provide the means to further the work of our existing instruments and scores. Thus Koening makes a good point about sound production becoming compositionally interesting when the structure-generating grammar refers to the sound data, instead of the sound elements.

Much of the musical discussion concerning the progress towards a higher level of organization tends to be centered around the general subject of algorithmic composition. Nick Collins cites several authors and theories in his article "Musical Form and Algorithmic Composition"[2] and writes about the bottom-up (material-driven) or top-down (template-determined) construction for works. While this article is not about composition in the main, we can continue the top-down, or bottom-up approach looking also at computer coding in general. Turing, for example, wrote about the bottom-up approach as connectionism, and interestingly found the top-down approach more useful for symbolic artificial intelligence[3]. But the attempt here in this article is only to describe a few opcodes which may be useful in what might be described then as a bottom-up approach.

Viewing the current list of opcodes there can be many opcodes which could be seen as furthering the work of instruments and scores. Compileorc, compilecsd, and compilestr can be utilized to help with the initial compilation of external files. Scoreline, scoreline_i, readf, readscore, directory, and ftsamplebank read from external files and directories. Ficlose, and fiopen can be used for saving, closing, and opening files, for example. Below is a short list of additional opcodes which may be useful for higher level organization or meta things.

    clockon, clockoff - turning on/off clocks
    cpumeter, cpuprc - memory management
    system - external operating system calls
    imageload - external image file loading
    insremot - controlling remotely
    remove - remove an instrument definition
    setscorepos - set score playback position
    turnoff, turnon - turning on/off instruments
    macros - various macros which function like C preprocessor macros
    zak - mixing, combining instruments
    various opcodes for mixing - combining sounds, sources, or streams

There may be other opcodes too, which help with overall higher level organization, but only a few of these opcodes with specific examples will be provided below.

II. Compiling

Compilecsd, compilestr, and compileorc opcodes [4][5][6] by Victor Lazzarini, all allow for compiling a new orchestra from an ASCII file. The opcodes, defined in the file compile_ops.c, rely also upon their API function counterparts listed in the file csound.h, and compile, but do not perform, one or more instruments at init time[4]. With these opcodes, we are able to read code from external files, and place the files as strings in memory to be compiled for the current running engine. Thus we could, for example, utilize one file to call several external files, place them in memory, compile them, and then add code to perform the compiled instruments in some order by calling opcodes such as using schedule or event.

You can view the examples for the opcodes shown below in "The Canonical Csound Reference Manual" using the links in the References section below, and you can also download and view the complete examples shown in this article from the following link: meta.zip. In the examples provided, proof of concept is rendered by simple beeps. The meta or higher level organization is the focus for these examples, and not the details of the sound performing instrument or opcodes, which in most cases is represented by a simple oscillator. Therefore all the examples are meant to be considered basic ones, or starter code, to be expanded upon more creatively for a final compositional result. A detailed analysis of a lengthy, complex compositional example is beyond the scope of this article which is only intended to present some initial possibilities using several opcodes, as tools to aid in creativity. To view the console output, and print statements for data of some of the examples, it is helpful to have a compiled Csound version without parser output. For more efficient compilation, all printing could be turned off.

For compiling, compilecsd can return a negative value, shown the code except shown below, to indicate the compilation failed. External file or files should be able to be compiled or else an error will result when trying to employ this opcode.

ires compilecsd "instr1 does_not_exist.csd"
print ires ; -1 as could not compileires compilecsd "
/home/myfiles/mytest.csd"
print ires ; 0 as compiled successfully

Using compilestr, it is also possible to write and compile an instrument from within an existing outer or encapsulating instrument block, and perform it with the help of the opcode scoreline_i. The code below performs one long tone from instr 1, as the outer instrument, but also calls the inner instrument, 2002 with four shorter tones to be performed at the same time.

<CsoundSynthesizer>
<CsOptions>
  csound -s -d -+rtaudio=ALSA -odevaudio -b1024 -B16384 
</CsOptions>
<CsInstruments>
  sr = 44100
  kr = 4410
  ksmps = 10
  nchnls = 2
  0dbfs = 1
instr 1
  kenv linseg 0, p3*0.25, .5, p3*0.75, 0
  a1	oscil	kenv, p4, p5
  outs	a1, a1
ires compilestr {{
  instr	2002
  kenv linseg 0, p3*0.25, .5, p3*0.75, 0
  a1	oscil	kenv, p4, p5
  outs	a1, a1
  endin
  }}
  print ires ; ... and returns 0 if successful
 ;call the new instrument from within instr1
  scoreline_i {{
  i 2002 0  5 400 1
  i 2002 6  5 500 2
  i 2002 12 5 600 3
  i 2002 18 5 500 4
  }}
  endin
</CsInstruments>
<CsScore>
  ; One period of a sine wave
  f 1	0	8192	10	1
  ; One period of an approximate sawtooth wave
  f 2	0	8192	10	1 0.5 0.333 0.25 0.2 0.1667 0.1429 0.125 0.111 0.1
  ; One period of an approximate square wave
  f 3	0	8192	10	1 0 0.333 0 0.2 0 0.1429 0 0.111 0
  ; One period of an approximate triangle wave
  f 4	0	8192	10	1 0 -0.111 0 0.04 0 -0.0204 0 0.0123 0 -0.0083 0 0.0059
i1 0  20 1200 4
</CsScore>
</CsoundSynthesizer>

III. Scoreline

Scoreline and scoreline_i [7][8] by Victor Lazzarini, are opcodes which can be used to read lines of score from within an instrument, or from an external file, if used along with the readf, or readfi opcodes[9][10] by John ffitch and Joachim Heintz. The code excerpt shown below shows the instrument reading four score lines from an external file at i-rate. The complete example, along with score lines in an external file, are provided with the downloadable examples for this articles.

gSfilename = "myscore.txt"
instr 1
read:
Sline, iline readfi gSfilename
scoreline_i Sline
  if iline < 4 then
    igoto read
  else
    turnoff
  endif
endin

IV. Ftsamplebank

The source code for ftsamplebank and directory [11][12] by Rory Walsh, reward further study. Defined in ftsamplebank.cpp within the Opcodes directory of the Csound source code, the opcodes are not listed per usual in entry.c or loaded dynamically, but instead are listed as external modules defined in int_static_modules.c of the Top directory of the source code. Thus ftsamplebank.cpp, which includes the code for directory, is a statically linked, self-contained external module, and after a cmake build, on my machine, results in the library, ftsamplebank.so.

The example below shows the use of ftsamplebank, to read a directory of similar formatted samples, such as all .wav files, at the k-rate. kNumberOfFiles holds the output value of the opcode which can be utilized in a loop to access the samples which are loaded into function tables and performed using the event opcode.

instr 1
   kFirstTableNumber = 60;
   kFileCount init 0
   kTrig = 1
   kNumberOfFiles ftsamplebank "/ftsamplebank/examples", kFirstTableNumber, kTrig, 0, 4, 0
  play:	
   event "i", 1000, kFileCount + 1 , 1, kFirstTableNumber+kFileCount
   kFileCount = kFileCount+1
        if (kFileCount < kNumberOfFiles) then
          kgoto play
        elseif (kFileCount >= kNumberOfFiles) then
          turnoff
        endif
endin

instr 1000
   iTable = p4
   aOut loscil3 1, 1, iTable, 1, 0;
   outs aOut, aOut
endin

V. Directory

Directory outputs string arrays of file names it reads from an indicated path to a directory which can be performed by an opcode such as schedule. With the use of directory, the sample types do not necessarily need to be the same format, but your code should take that into account too, by passing the correct file extension as a string. Also "The Canonical Csound Reference Manual" mentions it is more efficient to use an array to play several files when using diskin2 for the performance part of your code[12]. The example below also shows instr1 reading the directory, storing the files to an array as SFilenames, applying the schedule opcode, and in instr2 using an a-rate array with diskin2 to perform the samples.

<CsoundSynthesizer>
<CsOptions>
csound -s -d -+rtaudio=ALSA -odevaudio -b1024 -B16384 
</CsOptions>
<CsInstruments>

sr = 48000
kr	= 4800
ksmps = 10
nchnls = 2
0dbfs = 1

giCntr init 0
giNum init 0
gaArr[] init 7
giArrLen = 7
gSArr[] init giArrLen
;-------------------------------------
instr 1
SFilenames[] directory "/directory/mydirectory", ".wav"
iNumberOfFiles lenarray SFilenames
printf_i "***iNumberOfFiles = %d \n", 1, iNumberOfFiles
idur = 5
iwhen = 0
  while giCntr < iNumberOfFiles do
    schedule 2, iwhen, idur
    iwhen = iwhen + 5
    printf_i "***instr1, GiCntr = %d \n", 1, giCntr
    giCntr = giCntr+1
  od
endin
;-------------------------------------
instr 2
gSArr[] directory "/directory/mydirectory", ".wav"
iNumberOfFiles lenarray gSArr
printf_i "----instr2, GiNum = %d \n", 1, giNum
  if (giNum == 6) then
    turnoff
  else
    igoto play
  endif

play:
gaArr[giNum] diskin2 gSArr[giNum], 1, 0, 0, 0, 1, 0
outs gaArr[giNum], gaArr[giNum]
giNum = giNum+1
end:
endin

</CsInstruments>
<CsScore>
i1 0 30
</CsScore>
</CsoundSynthesizer>

VI. Include

Include can be of two types: the c or c++ preprocessor include, or Csound's own #include[13] by John ffitch. We can utilize the Csound API, compiling it with c or c++, using the c or c++ preprocessor to include functions from additional applications within our API code. The preprocessor adds and calls header files which contain data needed for compilation for certain parts of the code. We can demonstrate the use of include as an additional API application header by performing a simple Csound .csd file, and at the same time including additional headers for something simple such as opening a GL window to display a shape by including the use of gl and freeglut headers in our code. This approach is also shown in the readf example further below, where the CsoundAPI and Boost are used to generate files of random numbers and also perform those numbers as frequencies. To compile the code below, linking to the Csound library and the additional required libraries, such as GL, GLU, and glut is also needed.

gcc -Wall -w -O2 -DUSE_DOUBLE -I/opt/csound6-git -I/usr/include -L/usr/lib64 -lGL -lGLU -lglut -o triangletest triangletest.c -L. -lcsound64 -lsndfile -ldl -lm -lpthread -lfftw3
#include "GL/freeglut.h"
#include "GL/gl.h"
#include "stdio.h"
#include "stdlib.h"
#include "include/csound.h" 

uintptr_t csThread(void *clientData); 

typedef struct { 
  int result; 
  CSOUND *csound; 
  int PERF_STATUS; 
} userData; 

void drawTriangle()
{
    glClearColor(0.4, 0.4, 0.4, 0.4);
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
        glBegin(GL_TRIANGLES);
                glVertex3f(-0.7, 0.7, 0);
                glVertex3f(0.7, 0.7, 0);
                glVertex3f(0, -1, 0);
        glEnd();
    glFlush();
}

int main(void) 
{
  int finish;
  void *ThreadID; 
  userData *ud; 
  ud = (userData *)malloc(sizeof(userData));  
  MYFLT *pvalue; 
  
const char *argv[] = {"csound", "-+rtaudio=ALSA", "-odac", "-s", "-d", "-b1024", "-B1024","/triangletest.csd" };

  char *myargv [1];
  int myargc=1;
  myargv [0]=strdup ("Myappname");

    //glut init and create window
    glutInit(&myargc, myargv);
    glutInitDisplayMode(GLUT_SINGLE);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    int win = glutCreateWindow("OpenGL - Creating a triangle");
    
  //create and compile csound  
  ud->csound = csoundCreate(NULL);  
  ud->result = csoundCompile(ud->csound, 8, (char **)argv);

  if (!ud->result) {  
    ud->PERF_STATUS = 1; 
    ThreadID = csoundCreateThread(csThread, (void *)ud); 

    //draw the glut gl triangle from the thread
    glutDisplayFunc(drawTriangle);
    glutMainLoop();

  } 
  else { 
    return 1; 
  }  

  void glutDestroyWindow(win);
//triangletest.csd
<CsoundSynthesizer>
<CsOptions>
csound -s -d -+rtaudio=ALSA -odevaudio -b1024 -B16384 
</CsOptions>
<CsInstruments>

sr = 44100
kr = 4410
ksmps = 10
nchnls = 2
0dbfs = 1

	instr	2002
kenv linseg	0.01,p3*.33,1,p3*.33,1,p3*.33,0.01
a1	oscil	kenv, 440, p4
 	outs	a1, a1
 	endin

</CsInstruments>
<CsScore>
; One period of an approximate sawtooth wave
f 2	0	8192	10	1 0.5 0.333 0.25 0.2 0.1667 0.1429 0.125 0.111 0.1
i 2002	0	4	2
</CsScore>
</CsoundSynthesizer>

From within a Csound file we can also utilize Csound's own #include statement to include portions of code which may be distributed in various other files. For example we may have score data placed in a separate .inc file, and call that file using a Csound #include statement from within the score section of a Csound .csd file, as shown below.

<CsScore>
#include "/examples/mylist.inc"
e
</CsScore>

The contents of the external .inc file may represent the usual score statements.

;mylist.inc
; One period of a sine wave
f 1	0	8192	10	1
; One period of an approximate sawtooth wave
f 2	0	8192	10	1 0.5 0.333 0.25 0.2 0.1667 0.1429 0.125 0.111 0.1
; One period of an approximate square wave
f 3	0	8192	10	1 0 0.333 0 0.2 0 0.1429 0 0.111 0
; One period of an approximate triangle wave
f 4	0	8192	10	1 0 -0.111 0 0.04 0 -0.0204 0 0.0123 0 -0.0083 0 0.0059

i 2002	0	5	1
i 2002	6	5	2
i 2002	12	5	3
i 2002	18	5	4

VII. Readf

Readf [9] reads files from disc. The following example shows using fprints in the first instrument to write an external file of random numbers. The second instrument calls the event opcode to perform instrument 2. Instrument 3 uses readk to read the external frequences and perform them using poscil.

<CsoundSynthesizer>
<CsOptions>
csound -s -d -+rtaudio=ALSA -odevaudio -b1024 -B16384 
</CsOptions>
<CsInstruments>

sr = 44100
ksmps = 32
nchnls = 2
0dbfs  = 1

giSine ftgen 0, 0, 2^10, 10, 1
gSname =  "/readf/test."
gSext init "something"
gSwholename init "something"

instr 1 ;write files, at i-rate
icntr init 0
ifreq init 0
  until icntr >= 5 do
    iprint init 0
    gSext sprintf "%d", int(icntr)
    Sout strcat gSname, gSext
    ;puts Sout, icntr
      while iprint < 10 do 
        ifreq random 300, 2300 
        fprints Sout, "%f\n", ifreq
        iprint = iprint + 1
      od
    icntr = icntr + 1
  enduntil
endin
;---------------------------------
instr 2 ;calls event_i at i-rate
icntr init 0;
iNumberOfFiles init 5;
iname init 0;
iwhen init 0;
idur init 3;
  while icntr < iNumberOfFiles do
    print icntr, iname
    event_i "i", 3, iwhen, idur, iname
    iwhen += idur
    icntr += 1
    iname += 1
  od
endin
;---------------------------
instr 3  ; read and perform files
itrig init 1;
gSext sprintf "%d", p4 ;convert kcntr to string
printf_i  "ext is now: '%s'\n", itrig, gSext
gSwholename strcat gSname, gSext ;concat strings
printf_i  "filename is now: '%s'\n", itrig, gSwholename

kfreq readk  gSwholename, 7, .25
      if (kfreq > 0) then
      printk2 kfreq
      endif
aout  poscil 1, kfreq, giSine
      outs   aout, aout
endin

</CsInstruments>
<CsScore>
 i 1 0 5
 i 2 6 25
e
</CsScore>
</CsoundSynthesizer>

A final example shown uses the Csound API and Boost to first generate an external file of random numbers, then perform a simple .csd file from the API, to read and play the random generated numbers as a list of frequencies. Parts of the code have been omitted here to save space here, however the complete example is provided from the downloadable examples link listed above.

uintptr_t csThread(void *clientData); 

typedef struct { 
  int result; 
  CSOUND *csound; 
  int PERF_STATUS; 
  //int initialized;
} userData; 

int main()
{
  int finish;
  void *ThreadID; 
  userData *ud; 
  ud = (userData *)malloc(sizeof(userData));  
  MYFLT *pvalue; 
  
  const char *argv[] = {"csound", "-+rtaudio=ALSA", "-odevaudio", "-s", "-d", "-b1024", "-B16384","readBoost.csd" };

//BOOST code begins here
string path ("/test/readf");
int k;
double x;	

    // Define a base random number generator and initialize it with a seed.
    boost::minstd_rand baseGen(static_cast (std::time(0)));

    // Define a distribution
        const double median = 1050.0;
    const double sigma = 600.0;
    boost::cauchy_distribution<> cauReal(median, sigma);

    // Define a random variate generator using the base generator and distribution
    boost::variate_generator<boost::minstd_rand&, boost::cauchy_distribution<> > cauRealGen(baseGen, cauReal);

    std::cout << endl;
    std::cout << "Ten samples of reals in a cauchy distribution:\n" <<endl;

   //file IO 

    string CauchyDatAppend ("/cauchy.");
    string CauchyDatPath = path + CauchyDatAppend;
    
    //adds numbers as file extension
    while (k < 5)
    {
    ofstream outf1(CauchyDatPath.c_str() + std::to_string(k)); 

    // ...stdout and also print to file
    for(int i = 0; i < 10; i++) {
        next:
        x = cauRealGen();
            if (x<=0 )
             goto next;
        //std::cout << cauRealGen() << '\n';
        std::cout << x << '\n';
        //print to file
        outf1 << x << '\n';   
    }
      std::cout << '\n';
      outf1.close();
      k++;
   } //end while

   //BOOST code ends here
 
  ud->csound = csoundCreate(NULL);  
  ud->result=csoundCompile(ud->csound, 8, (char **)argv);

  if (!ud->result) {  
    ud->PERF_STATUS = 1; 
    ThreadID = csoundCreateThread(csThread, (void *)ud); 
  } 
  else { 
    return 1; 
  }  

  /* keep performing until user types a number and presses enter */
  scanf("%d", &finish);
  ud->PERF_STATUS = 0; 
  csoundDestroy(ud->csound); 
  free(ud);  
  return 0; 
} 

/* performance thread function */
uintptr_t csThread(void *data) 
{ 
  userData *udata = (userData *)data; 
  if (!udata->result) {
    while ((csoundPerformKsmps(udata->csound) == 0) &&
           (udata->PERF_STATUS == 1));
    csoundDestroy(udata->csound); 
  }        
  udata->PERF_STATUS = 0;    
  return 1; 
} 
;readBoost.csd

giSine ftgen 0, 0, 2^10, 10, 1
gSname =  "/test/cauchy."
gSext init "something"
gSwholename init "something"

;---------------------------------
instr 1 ;event_i i-rate
icntr init 0;
iNumberOfFiles init 5;
iname init 0;
iwhen init 0;
idur init 3;
  while icntr < iNumberOfFiles do
    print icntr, iname
    event_i "i", 2, iwhen, idur, iname
    iwhen += idur
    icntr += 1
    iname += 1
  od
endin
;---------------------------
instr 2  ; read files
itrig init 1;
gSext sprintf "%d", p4 ;convert kcntr to string
printf_i  "ext is now: '%s'\n", itrig, gSext
gSwholename strcat gSname, gSext ;concatenate strings
printf_i  "filename is now: '%s'\n", itrig, gSwholename

kfreq readk  gSwholename, 7, .25
      if (kfreq > 0) then
      printk2 kfreq
      endif
aout  poscil 1, kfreq, giSine
      outs   aout, aout
endin

</CsInstruments>
<CsScore>
 i 1 1 25
</CsScore>

VIII. Conclusion

External file inclusion for compilation or the use of opcodes which read needed data from external files, utilized in various combinations, can help provide powerful methods for the expansion of a variety of instruments, note lists, and data. Being able to write code which manages other bits of code is a higher level organizational design which can lead to efficient and productive results.

A brief look at the console output, below, for the scoreline_i.csd example which reads four lines of score from an external file, shows the efficiency for compiling, sorting, and performance.

Elapsed time at end of orchestra compile: real: 0.005s, CPU: 0.004s
Elapsed time at end of score sort: real: 0.005s, CPU: 0.005s
Elapsed time at end of performance: real: 8.690s, CPU: 0.203s
388 2048 sample blks of 64-bit floats written to devaudio

If the printing of data to the console is disabled in the example, then there is a slight gain in overall performance when running the example again and viewing the console output.

Elapsed time at end of orchestra compile: real: 0.002s, CPU: 0.002s
Elapsed time at end of score sort: real: 0.003s, CPU: 0.002s
Elapsed time at end of performance: real: 8.649s, CPU: 0.179s
388 2048 sample blks of 64-bit floats written to devaudio

When our Csound session work calls for a higher level of function for the organization and manipulation of instruments, Csound contains several powerful, efficient, and useful opcodes for instrument manipulation as tools to aid in the creation of larger structures for meta level processing.

References

[1]Gottfried Michael Koening, 1980. "Composition Processes." In M. Battier and B. Truax, eds. "UNESCO Computer Music: Report on an international project including the international workshop held at Aarhus, Denmark in 1978." Canadian Commission for UNESCO, pp. 105-126.

[2]Nick Collins, 2009. "Musical Form and Algorithmic Composition." Contemporary Music Review, Vol 28, No. 1, February 2009, 103-114.

[3]Jack Copeland, 1999 - 2016. "What is Articicial Intelligence." AlanTurning.net, Reference Articles on Turing, "Top-Down AI vs Bottom-Up AI." [Online] Available: http://www.alanturing.net/turing_archive/pages/reference%20articles/what_is_AI/What%20is%20AI09.html. [Accessed November 20, 2016].

[4] Barry Vercoe et al., 2003. "compilecsd." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/compilecsd.html. [Accessed November 20, 2016].

[5] Barry Vercoe et al., 2003. "compilestr." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/compilestr.html. [Accessed November 20, 2016].

[6] Barry Vercoe et al., 2003. "compileorc." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/compileorc.html. [Accessed November 20, 2016].

[7] Barry Vercoe et al., 2003. "scoreline." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/scoreline.html. [Accessed November 20, 2016].

[8] Barry Vercoe et al., 2003. "scoreline_i." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/scoreline_i.html. [Accessed November 20, 2016].

[9] Barry Vercoe et al., 2003. "readf." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/readf.html. [Accessed November 20, 2016].

[10] Barry Vercoe et al., 2003. "readfi." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/readfi.html. [Accessed November 20, 2016].

[11] Barry Vercoe et al., 2003. "ftsamplebank." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/ftsamplebank.html. [Accessed November 20, 2016].

[12] Barry Vercoe et al., 2003. "directory." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/directory.html. [Accessed November 20, 2016].

[13] Barry Vercoe et al., 2003. "#include." The Canonical Csound Reference Manual, Version 6.07 [Online] Available: http://csound.github.io/docs/manual/include.html. [Accessed November 20, 2016].

Additional Links and Info

Beman Dawes, et al., 2016. "Boost c++ Libraries." [Online] Available: http://www.boost.org/. [Accessed November 20, 2016].

Khronos Group. "OpenGL SDK." [Online] Available: https://www.opengl.org/sdk/. [Accessed November 21, 2016].

Khronos Group. "GLUT - The OpenGL Utility Toolkit." [Online] Available: https://www.opengl.org/resources/libraries/glut/. [Accessed November 21, 2016].

Biography

Jim Hearon has been Csounding since the early 1990s, and has helped to edit "Csound Journal" since 2005. Jim's articles continue to cover a wide range of topics and approaches. In his spare time Jim also enjoys playing electric violin, piano, and tenor guitar.

email: j_hearon AT hotmail.com