CCSSOOUUNNDD AA MMaannuuaall ffoorr tthhee AAuuddiioo PPrroocceessssiinngg SSyysstteemm aanndd SSuuppppoorrttiinngg PPrrooggrraammss BBaarrrryy VVeerrccooee MMeeddiiaa LLaabb MM..II..TT.. Copyright 1986 by the Massachusetts Institute of Technology. All rights reserved. Developed by Barry L. Vercoe at the Experimental Music Studio, Media Laboratory, M.I.T., Cambridge, Massachusetts, with partial support from the System Development Foundation and from National Science Foundation Grant # IRI-8704665. -------------------------------------------------------------------- Permission to use, copy, or modify these programs and their documentation for educational and research purposes only and without fee is hereby granted, provided that this copyright and permission notice appear on all copies and supporting documentation. For any other uses of this software, in original or modified form, including but not limited to dis- tribution in whole or in part, specific prior permission from M.I.T. must be obtained. M.I.T. makes no representa- tions about the suitability of this software for any pur- pose. It is provided "as is" without express or implied warranty. -------------------------------------------------------------------- CCOONNTTEENNTTSS PPRREEFFAACCEE v 11.. AA BBEEGGIINNNNIINNGG TTUUTTOORRIIAALL 1 Introduction 1 The Orchestra File 1 The Score File 3 The Perf Command 4 More about the Orchestra 5 22.. SSYYNNTTAAXX OOFF TTHHEE OORRCCHHEESSTTRRAA 6 STATEMENT TYPES 6 CONSTANTS AND VARIABLES 7 VALUE CONVERTERS: iinntt,, ffrraacc,, aabbss,, ffttlleenn,, ii,, eexxpp,, lloogg,, ssqqrrtt,, ssiinn,, ccooss,, ddbbaammpp,, aammppddbb 8 PITCH CONVERTERS: ooccttppcchh,, ppcchhoocctt,, ccppssppcchh,, ooccttccppss,, ccppssoocctt 9 ARITHMETIC OPERATIONS 10 CONDITIONAL VALUES 10 EXPRESSIONS 11 ASSIGNMENT STATEMENTS: ==,, iinniitt,, ttiivvaall,, ddiivvzz 12 ORCHESTRA HEADER: ssrr,, kkrr,, kkssmmppss,, nncchhnnllss 13 INSTRUMENT BLOCKS: iinnssttrr,, eennddiinn 14 PROGRAM CONTROL: ggoottoo,, ttiiggoottoo,, iiff ...... ggoottoo,, ttiimmoouutt 15 rreeiinniitt,, rriiggoottoo,, rriirreettuurrnn 16 DURATIONAL CONTROL: iihhoolldd,, ttuurrnnooffff 17 SIGNAL GENERATORS: lliinnee,, eexxppoonn,, lliinnsseegg,, eexxppsseegg 18 pphhaassoorr 19 ttaabbllee,, ttaabblleeii,, oosscciill11,, oosscciill11ii 20 oosscciill,, oosscciillii,, ffoosscciill,, ffoosscciillii 21 bbuuzzzz,, ggbbuuzzzz 22 aaddssyynn,, ppvvoocc 23 ffooff 24 pplluucckk 25 rraanndd,, rraannddhh,, rraannddii 26 SIGNAL MODIFIERS: lliinneenn,, eennvvllppxx 27 ppoorrtt,, ttoonnee,, aattoonnee,, rreessoonn,, aarreessoonn 29 llpprreeaadd,, llpprreessoonn,, llppffrreessoonn 30 rrmmss,, ggaaiinn,, bbaallaannccee 31 ddoowwnnssaammpp,, uuppssaammpp,, iinntteerrpp,, iinntteegg,, ddiiffff,, ssaammpphhoolldd 32 ddeellaayyrr,, ddeellaayyww,, ddeellaayy,, ddeellaayy11 33 ddeellttaapp,, ddeellttaappii 34 ccoommbb,, aallppaassss,, rreevveerrbb 35 SIGNAL DISPLAY: pprriinntt,, ddiissppllaayy,, ddssppddfftt,, ddssppfffftt 36 SOUNDFILE INPUT & OUTPUT: ppaann 37 ssoouunnddiinn,, oouutt,, oouuttss,, oouuttqq 38 33.. SSTTAANNDDAARRDD NNUUMMEERRIICC SSCCOORREE 39 Preprocessing of Standard Scores 39 Next-P and Previous-P Symbols 40 Ramping 41 Function Table Statement 42 Instrument Note Statements 43 Advance Statement 44 Tempo Statement 45 Sections of Score 46 End of Score 47 44.. GGEENN RROOUUTTIINNEESS GEN01, GEN02 48 GEN03 49 GEN04 50 GEN05, GEN07 51 GEN06 52 GEN08 53 GEN09, GEN10 54 GEN11 55 GEN13, GEN14 56 GEN15 57 55.. CCSSCCOORREE 58 Events, Lists, and Operations 58 Writing a Main Program 59 Compiling a Cscore Program 64 66.. SSCCOOTT:: AA SSccoorree TTrraannssllaattoorr 65 Orchestra Declaration 65 Function Declaration 66 Score Section 66 Pitch and Rhythm 66 Scot Example I 68 Groupettes 69 Slurs and Ties 69 Parameters 70 Pfield Macros 70 Divisi 71 Scot Example II 71 Additional Features 72 Output Scores 74 77.. TThhee CCssoouunndd PPEERRFF CCoommmmaanndd 76 The Extract Feature 78 Independent Preprocessing 78 88.. TThhee MMaacc CCssoouunndd EEnnvviirroonnmmeenntt 79 AAppppeennddiixx 11.. AAnn OOrrcchheessttrraa QQUUIICCKK RREEFFEERREENNCCEE 80 PPRREEFFAACCEE The concept of realizing music by digital computer involves synthesizing audio signals with a series of dis- crete points or _s_a_m_p_l_e_s that are representative of continu- ous waveforms. There are several ways of doing this digi- tally, each affording a different manner of control. The method of _d_i_r_e_c_t _s_y_n_t_h_e_s_i_s generates waveforms by sampling a stored picture or _f_u_n_c_t_i_o_n _t_a_b_l_e representing a single cycle. The method of _a_d_d_i_t_i_v_e _s_y_n_t_h_e_s_i_s generates the many partials of a complex tone one at a time, each with its own loudness envelope. _S_u_b_t_r_a_c_t_i_v_e _s_y_n_t_h_e_s_i_s takes a complex tone and then filters it as required. _N_o_n_-_l_i_n_e_a_r _s_y_n_t_h_e_s_i_s employs techniques such as frequency modulation and wave shaping to imbue simple signals with complex characteris- tics. _S_a_m_p_l_i_n_g _s_y_n_t_h_e_s_i_s involves digital storage of natu- ral sound, which can be recalled over and over in structur- ing a piece. Comprehensive moment-by-moment specification of an electronic composition can be tedious. As a practical mea- sure, control is prescribed in two ways: 1) by the structure of _i_n_s_t_r_u_m_e_n_t_s within an _o_r_c_h_e_s_t_r_a, and 2) by the details of _e_v_e_n_t_s within a _s_c_o_r_e. An orchestra is really a computer program that can produce sound, while a score is a body of data which that program can read and react to. Whether a characteristic such as a rise-time is a fixed constant in an instrument, or a variable prescribed by each note in the score, depends on just how the user wishes to control it. The instruments in a CCssoouunndd orchestra are user-defined in a simple high-level syntax that then invokes complex audio processing routines. A score passed to this orchestra is made up of numerically coded pitch and control informa- tion, in a form known as _s_t_a_n_d_a_r_d _n_u_m_e_r_i_c _s_c_o_r_e format. Although many users are content to work in this format, higher level score representation and processing languages are often convenient. Two are described in these pages. The SSccoott language uses simple alphanumeric encoding of pitch and time data, in a fashion that parallels traditional music notation; its translator will produce a _s_t_a_n_d_a_r_d _n_u_m_e_r_i_c score from this. The CCssccoorree program can expand an existing numeric score (or create one from scratch), according to user-supplied processing algorithms written in the CC lan- guage. One strategy, then, is to define a _k_e_r_n_e_l score in SSccoott, translate it to _n_u_m_e_r_i_c form, then expand and modify the data using CCssccoorree before sending it on to a CCssoouunndd orchestra for performance. This provides a powerful way of exploring score structures. The programs and languages making up the CCssoouunnddssyysstteemm hhaavvee aa lloonngg hhiissttoorryy ooff ddeevveellooppmmeenntt,, bbeeggiinnnniinngg wwiitthh tthhee _M_u_s_i_c _4 program written at Bell Telephone Laboratories in the early 1960's by Max Mathews. That initiated the stored table concept and much of the terminology that has since enabled computer music researchers to communicate. Valuable additions were made at Princeton by the late Godfrey Winham in _M_u_s_i_c _4_B, and my own _M_u_s_i_c _3_6_0 (1968) was very indebted to his work. With _M_u_s_i_c _1_1 (1973) I took a different tack. The division into two clear networks of _c_o_n_t_r_o_l and _a_u_d_i_o signal processing stemmed from my intensive involvement in the two preceding years in hardware synthesizer concepts and design, and this division has been retained in CCssoouunndd. I am indebted to many staff and student assistants for their con- tributions along the way. Because it is written entirely in CC,, CCssoouunndd is easily installed on any machine running Unix, and on many others that have a good C compiler. At MIT it runs on Vaxes, MicroVaxes and SUNs under Unix 4.3 BSD, and on Hewlett Packard Bobcat workstations under HP-Unix (essentially Sys- tem 5); it also runs on the Mac II under MPW. With a com- mon language for audio signal processing, users can move easily from machine to machine. This is aided by ethernet links that transfer both text and sound files between machines. At MIT a subset of Csound also runs in realtime on experimental MacII DSP boards. With suitable experience in both, the two worlds of software synthesis and realtime performance are thus merged into a single context of inter- active experiment and informed creative control. B.V. 11.. AA BBEEGGIINNNNIINNGG TTUUTTOORRIIAALL IInnttrroodduuccttiioonn The purpose of this section is to expose the reader to the fundamentals of designing and using computer music instruments in CCssoouunndd. Only a small portion of the language will be covered here, sufficient to implement some simple instrument examples. The remaining sections in the text are arranged as a _R_e_f_e_r_e_n_c_e manual (not a tutorial), since that is the form the user will eventually find most helpful when inventing instruments. Once the basic concepts are grasped from this tutorial, the reader might let himself into the remainder of the text by locating the information presented here in the Reference entries that follow. TThhee OOrrcchheessttrraa FFiillee CCssoouunndd runs from two basic files: an _o_r_c_h_e_s_t_r_a file and a _s_c_o_r_e file. The orchestra file is a set of _i_n_s_t_r_u_- _m_e_n_t_s that tell the computer how to synthesize sound; the score file tells the computer when. An instrument is a col- lection of modular statements which either _g_e_n_e_r_a_t_e or _m_o_d_- _i_f_y a signal; signals are represented by _s_y_m_b_o_l_s, which can be "patched" from one module to another. For example, the following two statements will generate a 440 Hz sine tone and send it to an output channel: asig oscil 10000, 440, 1 out asig The first line sets up an oscillator whose whose controlling inputs are an amplitude of 10000, a frequency of 440 Hz, and a waveform number, and whose output is the audio signal _a_s_i_g. The second line takes the signal _a_s_i_g and sends it to an (implicit) output channel. The two may be encased in another pair of statements that identify the instrument as a whole: instr 1 asig oscil 10000, 440, 1 out asig endin In general, an orchestra statement in CCssoouunndd consists of an action symbol followed by a set of input variables and preceded by a result symbol. Its _a_c_t_i_o_n is to process the inputs and deposit the result where told. The meaning of the input variables depends on the action requested. The 10000 above is interpreted as an amplitude value because it occupies the first input slot of an oscil unit; 440 signi- fies a frequency in Hertz because that is how an oscil unit interprets its second input argument; the waveform number is -2- taken to point indirectly to a stored function table, and before we invoke this instrument in a score we must fill function table #1 with some waveform. The output of CCssoouunndd computation is not a real audio signal, but a stream of numbers which describe such a sig- nal. When written onto a sound file these can later be con- verted to sound by an independent program; for now, we will think of variables such as _a_s_i_g as tangible audio signals. Let us now add some extra features to this instrument. First, we will allow the pitch of the tone to be defined as a _p_a_r_a_m_e_t_e_r in the score. Score parameters can be repre- sented by orchestra variables which take on their different values on successive notes. These variables are named sequentially: p1, p2, p3, ... The first three have a fixed meaning (see the Score File), while the remainder are assignable by the user. Those of significance here are: p3 - duration of the current note (always in seconds). p5 - pitch of the current note (in units agreed upon by score and orchestra). Thus in asig oscil 10000, p5, 1 the oscillator will take its pitch (presumably in cps) from score parameter 5. If the score had forwarded pitch values in units other than cycles-per-second (Hertz), then these must first be converted. One convenient score encoding, for instance, combines _p_i_t_c_h _c_l_a_s_s representation (00 for C, 01 for C#, 02 for D, ... 11 for B) with _o_c_t_a_v_e representation (8. for mid- dle C, 9. for the C above, etc.) to give pitch values such as 8.00, 9.03, 7.11. The expression cpspch(8.09) will convert the pitch A (above middle C) to its cps equiva- lent (440 Hz). Likewise, the expression cpspch(p5) will first read a value from p5, then convert it from octave.pitch-class units to cps. This expression could be imbedded in our orchestra statement as asig oscil 10000, cpspch(p5), 1 to give the score-controlled frequency we sought. Next, suppose we want to shape the amplitude of our tone with a linear rise from 0 to 10000. This can be done with a new action statement amp line 0, p3, 10000 Here, _a_m_p will take on values that move from 0 to 10000 over time p3 (the duration of the note in seconds). The instru- ment will then become instr 1 amp line 0, p3, 10000 asig oscil amp, cpspch(p5), 1 out asig endin -3- The signal _a_m_p is not something we would expect to lis- ten to directly. It is really a variable whose purpose is to control the amplitude of the audio oscillator. Although audio output requires fine resolution in time for good fidelity, a controlling signal often does not need that much resolution. We could use another kind of signal for this amplitude control kamp line 0, p3, 10000 in which the result is a new kind of signal. Signal names up to this point have always begun with the letter aa (signi- fying an _a_u_d_i_o signal); this one begins with kk (for _c_o_n_- _t_r_o_l). Control signals are identical to audio signals, dif- fering only in their resolution in time. A control signal changes its value less often than an audio signal, and is thus faster to generate. Using one of these, our instrument would then become instr 1 kamp line 0, p3, 10000 asig oscil kamp, cpspch(p5), 1 out asig endin This would likely be indistinguishable in sound from the first version, but would run a little faster. In general, instruments take constants and parameter values, and use calculations and signal processing to move first towards the generation of control signals, then finally audio signals. Remembering this flow will help you write efficient instru- ments with faster execution times. We are now ready to create our first orchestra file. Type in the following orchestra using the system editor, and name it "intro.orc". sr = 20000 ; audio sampling rate is 20 kHz kr = 500 ; control rate is 500 Hz ksmps = 40 ; number of samples in a control period (sr/kr) nchnls = 1 ; number of channels of audio output instr 1 kctrl line 0, p3, 10000 ; amplitude envelope asig oscil kctrl, cpspch(p5), 1 ; audio oscillator out asig ; send signal to channel 1 endin It is seen that comments may follow a semi-colon, and extend to the end of a line. There can also be blank lines, or lines with just a comment. Once you have saved your orches- tra file on disk, we can next consider the score file that will drive it. TThhee SSccoorree FFiillee The purpose of the score is to tell the instruments when to play and with what parameter values. The score has a different syntax from that of the orchestra, but similarly permits one statement per line and comments after a -4- semicolon. The first character of a score statement is an ooppccooddee, determining an action request; the remaining data consists of numeric parameter fields (pfields) to be used by that action. Suppose we want a sine-tone generator to play a penta- tonic scale starting at C-sharp above middle-C, with notes of 1/2 second duration. We would create the following score: ; a sine wave function table f1 0 256 10 1 ; a pentatonic scale i1 0 .5 0 8.01 i1 .5 . . 8.03 i1 1.0 . . 8.06 i1 1.5 . . 8.08 i1 2.0 . . 8.10 e The first statement creates a stored sine table. The proto- col for generating wave tables is simple but powerful. Lines with opcode ff interpret their parameter fields as fol- lows: p1 - function table _n_u_m_b_e_r being created p2 - _c_r_e_a_t_i_o_n _t_i_m_e, or time at which the table becomes readable p3 - table _s_i_z_e (number of points), which must be a power of two or one greater p4 - _g_e_n_e_r_a_t_i_n_g _s_u_b_r_o_u_t_i_n_e, chosen from a prescribed list. Here the value 10 in p4 indicates a request for subroutine GEN10 to fill the table. GEN10 mixes harmonic sinusoids in phase, with relative strengths of consecutive partials given by the succeeding parameter fields. Our score requests just a single sinusoid. An alternative statement f1 0 256 10 1 0 3 would produce one cycle of a waveform whose third harmonic is three times as strong as the first. The _i-statements, or note statements, will invoke the p1 instrument at time p2, then turn it off after p3 seconds; it will pass all of its p-fields to that instrument. Indi- vidual score parameters are separated by any number of spaces or tabs; neat formatting of parameters in columns is nice but unnecessary. The dots in p-fields 3 and 4 of the last four notes invoke a _c_a_r_r_y _f_e_a_t_u_r_e, in which values are simply copied from the immediately preceding note _o_f _t_h_e _s_a_m_e _i_n_s_t_r_u_m_e_n_t. A score normally ends with an _e-statement. The unit of time in a CCssoouunndd score is the beat. In the absence of a _T_e_m_p_o statement, one beat takes one second. To double the speed of the pentatonic scale in the above score, we could either modify p2 and p3 for all the notes in the score, or simply insert the line t 0 120 to specify a tempo of 120 beats per minute from beat 0. -5- Two more points should be noted. First, neither the _f- statements nor the _i-statements need be typed in time order; CCssoouunndd will sort the score automatically before use. Sec- ond, it is permissable to play more than one note at a time with a single instrument. To play the same notes as a three-second pentatonic chord we would create the following: ; a sine wave function f1 0 256 10 1 ; five notes at once i1 0 3 0 8.01 i1 0 . . 8.03 i1 0 . . 8.06 i1 0 . . 8.08 i1 0 . . 8.10 e Now go into the editor once more and create your own score file. Name it "intro.sco". TThhee PPeerrff CCoommmmaanndd To request your orchestra to perform your score, type the command perf intro.orc intro.sco The resulting performance will take place in three phases: 1) sort the score file into chronological order. If score syntax errors are encountered they will be reported on your console. 2) translate and load your orchestra. The console will sig- nal the start of translating each _i_n_s_t_r block, and will report any errors. If the error messages are not immedi- ately meaningful, translate again with the _v_e_r_b_o_s_e flag turned on: perf -v intro.orc intro.sco 3) fill the wave tables and perform the score. Information about this performance will be displayed throughout in mes- sages resembling B 4.000 .. 6.000 T 3.000 TT 3.000 M 7929. 7929. A message of this form will appear for every _e_v_e_n_t in your score. An event is defined as any change of state (as when a new note begins or an old one ends). The first two num- bers refer to beats in your original score, and they delimit the current segment of sound synthesis between successive events (e.g. from beat 4 to beat 6). The second beat value is next restated in real seconds of time, and reflects the _t_e_m_p_o of the score. That is followed by the Total Time elapsed for all sections of the score so far. The last val- ues on the line show the maximum amplitude of the audio sig- nal, measured over just this segment of time, and reported separately for each channel. Console messages are printed to assist you in following the orchestra's handling of your score. You should aim at becoming an intelligent reader of your console reports. When you begin working with longer scores and your -6- instruments no longer cause surprises, the above detail may be excessive. You can elect to receive abbreviated messages using the -m option of the ppeerrff command. When your performance goes to completion, it will have created a sound file named _t_e_s_t in your soundfile directory. You can now listen to your sound file by typing play test MMoorree aabboouutt tthhee OOrrcchheessttrraa Suppose we next wished to introduce a small vibrato, whose rate is 1/50 the frequency of the note (i.e. A440 is to have a vibrato rate of 8.8 Hz.). To do this we will gen- erate a control signal using a second oscillator, then add this signal to the basic frequency derived from p5. This might result in the instrument instr 1 kamp line 0, p3, 10000 kvib oscil 2.75, cpspch(p5)/50, 1 a1 oscil kamp, cpspch(p5)+kvib, 1 out a1 endin Here there are two control signals, one controlling the amplitude and the other modifiying the basic pitch of the audio oscillator. For small vibratos, this instrument is quite practical; however it does contain a misconception that is worth noting. This scheme has added a sine wave deviation to the cps value of an audio oscillator. The value 2.75 determines the _w_i_d_t_h of vibrato in cps, and will cause an A440 to be modified about one-tenth of one semitone in each direction (1/160 of the frequency in cps). In real- ity, a cps deviation produces a different musical interval above than it does below. To see this, consider an exagger- ated deviation of 220 cps, which would extend a perfect 5th above A440 but a whole octave below. To be more correct, we should first convert p5 into a _t_r_u_e _d_e_c_i_m_a_l _o_c_t_a_v_e (not cps), so that an _i_n_t_e_r_v_a_l deviation above is equivalent to that below. In general, pitch modification is best done in true octave units rather than pitch-class or cps units, and there exists a group of pitch converters to make this task easier. The modified instrument would be instr 1 ioct = octpch(p5) kamp line 0, p3, 10000 kvib oscil 1/120, cpspch(p5)/50, 1 asig oscil kamp, cpsoct(ioct+kvib), 1 out asig endin This instrument is seen to use a third type of orches- tra variable, an _i-variable. The variable _i_o_c_t receives its value at an _i_n_i_t_i_a_l_i_z_a_t_i_o_n pass through the instrument, and -7- does not change during the lifespan of this note. There may be many such _i_n_i_t _t_i_m_e calculations in an instrument. As each note in a score is encountered, the event space is allocated and the instrument is initialized by a special pre-performance pass. _i_-_v_a_r_i_a_b_l_e_s receive their values at this time, and any other expressions involving just con- stants and _i-variables are evaluated. At this time also, modules such as lliinnee set up their target values (such as beginning and end points of the line), and units such as oosscciill do phase setup and other bookkeeping in preparation for performance. A full description of init-time and per- formance-time activities, however, must be deferred to a general consideration of the orchestra syntax. -8- 22.. SSYYNNTTAAXX OOFF TTHHEE OORRCCHHEESSTTRRAA An orchestra statement in CCssoouunndd has the format: label: result opcode argument1, argument2,... ;comments The label is optional and identifies the basic statement that follows as the potential target of a go-to operation (see Program Control Statements). A label has no effect on the statement per se. Comments are optional and are for the purpose of letting the user document his orchestra code. Comments always begin with a semicolon (;) and extend to the end of the line. The remainder (result, opcode, and arguments) form the _b_a_s_i_c _s_t_a_t_e_m_e_n_t. This also is optional, i.e. a line may have only a label or comment or be entirely blank. If present, the basic statement must be complete on one line. The opcode determines the operation to be performed; it usually takes some number of input values (arguments); and it usually has a result field variable to which it sends output values at some fixed rate. There are four possible rates: 1) once only, at orchestra setup time (effectively a permanent assignment); 2) once at the beginning of each note (at initialization (init) time: _I_-_r_a_t_e); 3) once every performance-time control loop (perf time control rate, or _K_-_r_a_t_e); 4) once each sound sample of every control loop (perf time audio rate, or _A_-_r_a_t_e). STATEMENT TYPES An orchestra program in CCssoouunndd is comprised of _o_r_c_h_e_s_t_r_a _h_e_a_d_e_r _s_t_a_t_e_m_e_n_t_s which set various global parameters, fol- lowed by a number of _i_n_s_t_r_u_m_e_n_t _b_l_o_c_k_s representing differ- ent instrument types. An instrument block, in turn, is com- prised of _o_r_d_i_n_a_r_y _s_t_a_t_e_m_e_n_t_s that set values, control the logical flow, or invoke the various signal processing sub- routines that lead to audio output. An _o_r_c_h_e_s_t_r_a _h_e_a_d_e_r _s_t_a_t_e_m_e_n_t operates once only, at orches- tra setup time. It is most commonly an assignment of some value to a _g_l_o_b_a_l _r_e_s_e_r_v_e_d _s_y_m_b_o_l, e.g. sr = 20000. All orchestra header statements belong to a pseudo instrument 0, an _i_n_i_t pass of which is run prior to all other instruments at score time 0. Any _o_r_d_i_n_a_r_y _s_t_a_t_e_m_e_n_t can serve as an orchestra header statement, eg. gifreq = cpspch(8.09), pro- vided it is an init-time only operation. An _o_r_d_i_n_a_r_y _s_t_a_t_e_m_e_n_t runs at either init time or perfor- mance time or both. Operations which produce a result for- mally run at the rate of that result (that is, at init time for I-rate results; at performance time for K- and A-rate -9- results), with the sole exception of the iinniitt opcode (q.v.). Most ggeenneerraattoorrss and mmooddiiffiieerrss, however, produce signals that depend not only on the instantaneous value of their argu- ments but also on some preserved internal state. These per- formance-time units therefore have an implicit init-time component to set up that state. The run time of an opera- tion which produces no result is apparent in the opcode. Arguments are values that are sent to an operation. Most arguments will accept arithmetic expressions composed of constants, variables, reserved globals, value converters, arithmetic operations and conditional values; these are described below. -10- CONSTANTS AND VARIABLES ccoonnssttaannttss are floating point numbers, such as 1, 3.14159, or -73.45 . They are available continuously and do not change in value. vvaarriiaabblleess are named cells containing numbers. They are available continuously and may be updated at one of the four update rates (setup only, I-rate, K-rate, or A-rate). I- and K-rate variables are scalars (i.e. they take on only one value at any given time) and are primarily used to store and recall controlling data, that is, data that changes at the note rate (for I-variables) or at the control rate (for K- variables). I- and K-variables are therefore useful for storing note parameter values, pitches, durations, slow-mov- ing frequencies, vibratos, etc. A-variables, on the other hand, are arrays or vectors of information. Though renewed on the same perf-time control pass as K-variables, these array cells represent a finer resolution of time by dividing the control period into sample periods (see _k_s_m_p_s below). A-variables are used to store and recall data changing at the audio sampling rate (e.g. output signals of oscillators, filters, etc.). A further distinction is that between local and global vari- ables. llooccaall variables are private to a particular instru- ment, and cannot be read from or written into by any other instrument. Their values are preserved, and they may carry information from pass to pass (e.g. from initialization time to performance time) within a single instrument. Local variable names begin with the letter pp,, ii,, kk,, or aa.. The same local variable name may appear in two or more different instrument blocks without conflict. gglloobbaall variables are cells that are accessible by all instruments. The names are either like local names preceded by the letter gg,, or are special reserved symbols. Global variables are used for broadcasting general values, for com- municating between instruments (semaphores), or for sending sound from one instrument to another (e.g. mixing prior to reverberation). Given these distinctions, there are eight forms of local and global variables: type when renewable LLooccaall GGlloobbaall reserved symbols permanent -- rsymbol score parameter fields I-time ppnumber -- init variables I-time iiname ggiiname control signals P-time, K-rate kkname ggkkname audio signals P-time, A-rate aaname ggaaname where _r_s_y_m_b_o_l is a special reserved symbol (e.g. ssrr,, kkrr), _n_u_m_b_e_r is a positive integer referring to a score statement pfield, and _n_a_m_e is a string of letters and/or digits with local or global meaning. As might be inferred, score -11- parameters are local I-variables whose values are copied from the invoking score statement just prior to the Init pass through an instrument. -12- VALUE CONVERTERS: ffttlleenn(x) (init-rate args only) iinntt(x) (init- or control-rate args only) ffrraacc(x) " " ddbbaammpp(x) " " ii(x) (control-rate args only) aabbss(x) (no rate restriction) eexxpp(x) " " lloogg(x) " " ssqqrrtt(x) " " ssiinn(x) " " ccooss(x) " " aammppddbb(x) " " where the argument within the parentheses may be an expres- sion. Value converters perform arithmetic translation from units of one kind to units of another. The result can then be a term in a further expression. ffttlleenn(x) returns the size (no. of points) of stored function table no. _x. iinntt(x) " " integer part of _x. ffrraacc(x) " " fractional part of _x. ddbbaammpp(x) " " decibel equivalent of the raw amplitude _x. ii(x) " an Init-type equivalent of the argument, thus permitting a K-time value to be accessed in at init-time or reinit- time, whenever valid. aabbss(x) " the absolute value of _x. eexxpp(x) " _e raised to the _xth power. lloogg(x) " the natural log of _x (_x positive only). ssqqrrtt(x) " " square root of _x (_x non-negative). ssiinn(x) " " sine of _x (_x in radians). ccooss(x) " " cosine of _x (_x in radians). aammppddbb(x) " " amplitude equivalent of the decibel value _x. Thus 60 db gives 1000, 66 db gives 2000, 72 db gives 4000, -13- 78 db gives 8000, 84 db gives 16000 and 90 db gives 32000. Note that for lloogg, ssqqrrtt, and ffttlleenn the argument value is restricted. Note also that ffttlleenn will always return a power-of-2 value, i.e. the function table guard point (see F statement) is not included. -14- PITCH CONVERTERS ooccttppcchh(pch) (init- or control-rate args only) ppcchhoocctt(oct) " " ccppssppcchh(pch) " " ooccttccppss(cps) " " ccppssoocctt(oct) (no rate restriction) where the argument within the parentheses may be a further expression. These are really vvaalluuee ccoonnvveerrtteerrss with a special function of manipulating pitch data. Data concerning pitch and frequency can exist in any of the following forms: name abbreviation octave point pitch-class (8ve.pc) ppcchh octave point decimal oocctt cycles per second ccppss The first two forms consist of a whole number, representing octave registration, followed by a specially interpreted fractional part. For ppcchh the fraction is read as two deci- mal digits representing the 12 equal-tempered pitch classes from .00 for C to .11 for B. For oocctt, the fraction is interpreted as a true decimal fractional part of an octave. The two fractional forms are thus related by the factor 100/12. In both forms, the fraction is preceded by a whole number octave index such that 8.00 represents Middle C, 9.00 the C above, etc. Thus A440 can be represented alterna- tively by 440 (ccppss), 8.09 (ppcchh), 8.75 (oocctt), or 7.21 (ppcchh), etc. Microtonal divisions of the ppcchh semitone can be encoded by using more than two decimal places. The mnemonics of the pitch conversion units are derived from morphemes of the forms involved, the second morpheme describing the source and the first morpheme the object (result). Thus ccppssppcchh(8.09) will convert the pitch argument 8.09 to its c.p.s. (or hertz) equivalent, giving the value of 440. Since the argu- ment is constant over the duration of the note, this conver- sion will take place at I-time, before any samples for the current note are produced. By contrast, the conversion ccppssoocctt(8.75 + K1) which gives the value of A440 transposed by the octave interval K1, will repeat the calculation every K-period since that is the rate at which K1 varies. NN..BB. The conversion from ppcchh or oocctt into ccppss is not a -15- linear operation but involves an exponential process which may be time-consuming if executed repeatedly at audio rates. Audio-rate arguments within ccppssoocctt are permitted but should be used sparingly. -16- ARITHMETIC OPERATIONS: _-_a _+_a _a _&_& _b (logical AND; not audio-rate) _a _|_| _b (logical OR; not audio-rate) _a _+ _b _a _- _b _a _* _b _a _/ _b where the arguments _a and _b may be further expressions. Arithmetic operators perform operations of change-sign (negate), don't-change-sign, logical AND, logical OR, add, subtract, multiply and divide. Note that a value or an expression may fall between two of these operators, either of which could take it as its left or right argument, as in _a _+ _b _* _c. In such cases three rules apply: 1) * and / bind to their neighbors more strongly than + and -. Thus the above expression is taken as _a _+ _(_b _* _c_), with * taking _b and _c and then + taking _a and _b_*_c. 2) + and - bind more strongly than &&, which in turn is stronger than ||: _a _&_& _b _- _c _|_| _d is taken as _(_a _&_& _(_b _- _c_)_) _|_| _d 3) When both operators bind equally strongly, the operations are done left to right: _a _- _b _- _c is taken as _(_a _- _b_) _- _c. Parentheses may be used as above to force particular group- ings. CONDITIONAL VALUES: (_a > _b ? v1 : v2) (_a < _b ? v1 : v2) (_a >= _b ? v1 : v2) (_a <= _b ? v1 : v2) (_a == _b ? v1 : v2) (_a != _b ? v1 : v2) where _a, _b, v1 and v2 may be expressions, but _a, _b not audio-rate. In the above conditionals, _a and _b are first compared. If the indicated relation is true (_a greater than _b, _a less than _b, _a greater than or equal to _b, _a less than or equal to _b, _a equal to _b, _a not equal to _b), then the conditional expression has the value of v1; if the relation is false, the expression has the value of v2. (For convenience, a sole '=' will function as '=='.) NN..BB..:: If v1 or v2 are expressions, these will be evaluated -17- _b_e_f_o_r_e the conditional is determined. In terms of binding strength, all conditional operators (i.e., the relational operators (>, <, etc.), and ? and :) are weaker than the arithmetic and logical operators (+ , - , *, /, && and ||). Example: (k1 < p5/2 + p6 ? k1 : p7) binds the terms p5/2 and p6. It will return the value k1 below this threshold, else the value p7. -18- EXPRESSIONS: Expressions may be composed to any depth from the components shown above. Each sub-expression (part of an expression) is evaluated at its own proper rate. For instance, if the terms within a sub-expression all change at the control rate or slower, the sub-expression will be evaluated only at the control rate; that result might then be used in an audio-rate evaluation. Examples: k1 + abs(p5/2 + sqrt(k2)) int(p5) + frac(p5) * 100/12 The above are legal expressions. They may be placed in unit generator argument positions or be part of an assignment statement (q.v.). STATEMENT TYPES: There are nine statement types, each of which provides a heading for the descriptive sections that follow in this document: assignment statements orchestra header statements instrument block statements program control statements duration control statements signal generator statements signal modifier statements signal display statements soundfile access statements INTERPRETIVE NOTE: Throughout this document, opcodes are indicated in bboollddffaaccee and their argument and result mnemonics, when mentioned in the text, are given in _i_t_a_l_i_c_s. Argument names are gener- ally mnemonic (_a_m_p_, _p_h_s), and the result is denoted the let- ter _r. Both are preceded by a type qualifier _i_, _k_, _a or _x (e.g. _k_a_m_p_, _i_p_h_s_, _a_r). The prefix _i denotes scalar values valid at note Init time; prefixes _k or _a denote control (scalar) and audio (vector) values, modified and referenced continuously throughout performance (i.e. at every control period while the instrument is active). Arguments are _u_s_e_d at the prefix-listed times; results are _c_r_e_a_t_e_d at their listed times, then remain available for use as inputs -19- elsewhere. The validity of inputs is defined by the follow- ing: arguments with prefix _i must be valid at Init time; arguments with prefix _k can be either control or Init values (which remain valid); arguments with prefix _a must be vector inputs; arguments with prefix _x may be either vector or scalar (the compiler will distinguish). All arguments, unless otherwise stated, can be expressions whose results conform to the above. Most opcodes (such as lliinneenn and oosscciill) can be used in more than one mode, which one being determined by the prefix of the result symbol. -20- ASSIGNMENT STATEMENTS ir = iarg kr = karg ar = xarg kr iinniitt iarg ar iinniitt iarg ir ttiivvaall ir ddiivvzz ia, ib, isubst (these not yet implemented) kr ddiivvzz ka, kb, ksubst ar ddiivvzz xa, xb, ksubst == (simple assignment) - Put the value of the expression _i_a_r_g _(_k_a_r_g_, _x_a_r_g_) into the named result. This provides a means of saving an evaluated result for later use. iinniitt - Put the value of the I-time expression _i_a_r_g into a K- or A-variable, i.e., initialize the result. Note that iinniitt provides the only case of an Init-time statement being per- mitted to write into a Perf-time (K- or A-rate) result cell; the statement has no effect at Perf-time. ttiivvaall - Put the value of the instrument's internal "tie-in" flag into the named I-variable. Assigns 1 if this note has been 'tied' onto a previously held note (see I Statement); assigns 0 if no tie actually took place. (See also ttiiggoottoo.) ddiivvzz - Whenever _b is not zero, set the result to the value of _a_/_b; when _b is zero, set it to the value of _s_u_b_s_t instead. Example: kcps = i2/3 + cpsoct(k2 + octpch(p5)) -21- ORCHESTRA HEADER STATEMENTS ssrr = n1 kkrr = n2 kkssmmppss = n3 nncchhnnllss = n4 These statements are global value _a_s_s_i_g_n_m_e_n_t_s, made at the beginning of an orchestra, before any instrument block is defined. Their function is to set certain _r_e_s_e_r_v_e_d _s_y_m_b_o_l _v_a_r_i_a_b_l_e_s that are required for performance. Once set, these reserved symbols can be used in expressions anywhere in the orchestra. ssrr= (optional) - set sampling rate to _n_1 samples per second per channel. The default value is 10000. kkrr= (optional) - set control rate to _n_2 samples per second. The default value is 1000. kkssmmppss= (optional) - set the number of samples in a Control Period. TThhiiss vvaalluuee mmuusstt eeqquuaall ssrr//kkrr. The default value is 10. nncchhnnllss= (optional) - set number of channels of audio output to _n_4. (1 = mono, 2 = stereo, 4 = quadraphonic.) The default value is 1 (mono). In addition, any gglloobbaall vvaarriiaabbllee can be initialized by an _i_n_i_t_-_t_i_m_e _a_s_s_i_g_n_m_e_n_t anywhere before the first iinnssttrr state- ment. All of the above assignments are run as instrument 0 (i-pass only) at the start of real performance. Example of header assignments: sr = 10000 kr = 500 ksmps = 20 gi1 = sr / 2. ga1 init 0 gitranspose = octpch(.01) -22- INSTRUMENT BLOCK STATEMENTS iinnssttrr i, j, ... . . . eennddiinn These statements delimit an instrument block. They must always occur in pairs. iinnssttrr - begin an instrument block defining instruments _i_, _j, ... _i_, _j, ... must be numbers, not expressions. Any positive integer is legal, and in any order, but excessively high numbers are best avoided. eennddiinn - end the current instrument block. Note: There may be any number of instrument blocks in an orches- tra. Instruments can be defined in any order (but they will always be both initialized and performed in ascending instrument number order). Instrument blocks cannot be nested (i.e. one block cannot contain another). -23- PROGRAM CONTROL STATEMENTS iiggoottoo label ttiiggoottoo label kkggoottoo label ggoottoo label iiff ia R ib iiggoottoo label iiff ka R kb kkggoottoo label iiff ia R ib ggoottoo label ttiimmoouutt istrt, idur, label where _l_a_b_e_l is in the same instrument block and is not an expression, and where _R is one of the Relational operators (>, <, >=, <=, ==, !=) (and = for convenience, see also under Conditional values). These statements are used to control the order in which statements in an instrument block are to be executed. I- time and P-time passes can be controlled separately as fol- lows: iiggoottoo - During the I-time pass only, unconditionally trans- fer control to the statement labeled by _l_a_b_e_l. ttiiggoottoo - similar to iiggoottoo, but effective only during an I- time pass at which a new note is being 'tied' onto a previ- ously held note (see I Statement); no-op when a tie has not taken place. Allows an instrument to skip initialization of units according to whether a proposed tie was in fact suc- cessful (see also ttiivvaall, ddeellaayy). kkggoottoo - During the P-time passes only, unconditionally transfer control to the statement labeled by _l_a_b_e_l. ggoottoo - (combination of iiggoottoo and kkggoottoo) Transfer control to _l_a_b_e_l on every pass. iiff......iiggoottoo - conditional branch at I-time, depending on the truth value of the logical expression "ia R ib". The branch is taken only if the result is true. iiff......kkggoottoo - conditional branch during P-time, depending on the truth value of the logical expression "ka R kb". The branch is taken only if the result is true. iiff......ggoottoo - combination of the above. Condition tested on every pass. ttiimmoouutt - conditional branch during P-time, depending on elapsed note time. _i_s_t_r_t and _i_d_u_r specify time in seconds. The branch to _l_a_b_e_l will become effective at time _i_s_t_r_t, and will remain so for just _i_d_u_r seconds. Note that ttiimmoouutt can be reinitialized for multiple activation within a single note (see example next page). -24- Example: if k3 > p5+10 kgoto next -25- rreeiinniitt label rriiggoottoo label rriirreettuurrnn These statements permit an instrument to reinitialize itself during performance. rreeiinniitt - whenever this statement is encountered during a P- time pass, performance is temporarily suspended while a spe- cial Initialization pass, beginning at _l_a_b_e_l and continuing to rriirreettuurrnn or eennddiinn, is executed. Performance will then be resumed from where it left off. rriiggoottoo - similar to iiggoottoo, but effective only during a rreeiinniitt pass (i.e., No-op at standard I-time). This state- ment is useful for bypassing units that are not to be reini- tialized. rriirreettuurrnn - terminates a rreeiinniitt pass (i.e., No-op at standard I-time). This statement, or an eennddiinn, will cause normal performance to be resumed. Example: The following statements will generate an exponential con- trol signal whose value moves from 440 to 880 exactly ten times over the duration p3. reset: timout 0, p3/10, contin ;after p3/10 seconds, reinit reset ; reinit both timout contin: k1 expon 440, p3/10, 880 ; and expon rireturn ; then resume perf -26- DURATION CONTROL STATEMENTS iihhoolldd ttuurrnnooffff These statements permit the current note to modify its own duration. iihhoolldd - this I-time statement causes a finite-duration note to become a 'held' note. It thus has the same effect as a negative p3 (see Score I-statement), except that p3 here remains positive and the instrument reclassifies itself to being held indefinitely. The note can be turned off explic- itly with ttuurrnnooffff, or its space taken over by another note of the same instrument number (i.e. it is tied into that note). Effective at I-time only; no-op during a rreeiinniitt pass. ttuurrnnooffff - this P-time statement enables an instrument to turn itself off. Whether of finite duration or 'held', the note currently being performed by this instrument is immedi- ately removed from the active note list. No other notes are affected. Example: The following statements will cause a note to terminate when a control signal passes a certain threshold (here the Nyquist frequency). k1 expon 440, p3/10, 880 ;begin gliss and continue if k1 < sr/2 kgoto contin ; until Nyquist detected turnoff ; then quit contin: a1 oscil a1, k1, 1 -27- SIGNAL GENERATORS kr lliinnee ia, idur1, ib ar lliinnee ia, idur1, ib kr eexxppoonn ia, idur1, ib ar eexxppoonn ia, idur1, ib kr lliinnsseegg ia, idur1, ib[, idur2, ic[...]] ar lliinnsseegg ia, idur1, ib[, idur2, ic[...]] kr eexxppsseegg ia, idur1, ib[, idur2, ic[...]] ar eexxppsseegg ia, idur1, ib[, idur2, ic[...]] Output values _k_r or _a_r trace a straight line (exponential curve) or a series of line segments (exponential segments) between specified points. INITIALIZATION _i_a - starting value. Zero is illegal for exponentials. _i_b_, _i_c, etc. - value after _d_u_r_1 seconds, etc. For exponen- tials, must be non-zero and must agree in sign with _i_a. _i_d_u_r_1 - duration in seconds of first segment. A zero or negative value will cause all initialization to be skipped. _i_d_u_r_2_, _i_d_u_r_3, etc. - duration in seconds of subsequent seg- ments. A zero or negative value will terminate the initial- ization process with the preceding point, permitting the last-defined line or curve to be continued indefinitely in performance. The default is zero. PERFORMANCE These units generate control or audio signals whose values can pass through 2 or more specified points. The sum of _d_u_r values may or may not equal the instrument's performance time: a shorter performance will truncate the specified pattern, while a longer one will cause the last-defined seg- ment to continue on in the same direction. Example: k2 expseg 440, p3/2, 880, p3/2, 440 This statement creates a control signal which moves exponen- tially from 440 to 880 and back, over the duration p3. -28- kr pphhaassoorr kcps[, iphs] ar pphhaassoorr xcps[, iphs] Produce a normalized moving phase value. INITIALIZATION _i_p_h_s (optional) - initial phase, expressed as a fraction of a cycle (0 to 1). A negative value will cause phase ini- tialization to be skipped. The default value is zero. PERFORMANCE An internal phase is successively accumulated in accordance with the cps frequency to produce a moving phase value, nor- malized to lie in the range 0.<= phs < 1. When used as the index to a ttaabbllee unit, this phase (multi- plied by the desired function table length) will cause it to behave like an oscillator. Note that pphhaassoorr is a special kind of integrator, accumulat- ing phase increments that represent frequency settings. Example: k1 pphhaassoorr 1 ;cycle once per second kpch ttaabbllee k1*12, 1 ;through 12-note pch table a1 oosscciill p4, cpspch(kpch), 2 ;with continuous sound -29- ir ttaabbllee indx, ifn[, ixmode][, ixoff][, iwrap] ir ttaabblleeii indx, ifn[, ixmode][, ixoff][, iwrap] kr ttaabbllee kndx, ifn[, ixmode][, ixoff][, iwrap] kr ttaabblleeii kndx, ifn[, ixmode][, ixoff][, iwrap] ar ttaabbllee andx, ifn[, ixmode][, ixoff][, iwrap] ar ttaabblleeii andx, ifn[, ixmode][, ixoff][, iwrap] kr oosscciill11 idel, kamp, idur, ifn kr oosscciill11ii idel, kamp, idur, ifn Table values are accessed by direct indexing or by incremen- tal sampling. INITIALIZATION _i_f_n - function table number. ttaabblleeii,, oosscciill11ii require the extended guard point. _i_x_m_o_d_e (optional) - ndx data mode. 0 = raw ndx, 1 = normal- ized (0 to 1). The default value is 0. _i_x_o_f_f (optional) - amount by which ndx is to be offset. For a table with origin at center, use tablesize/2 (raw) or .5 (normalized). The default value is 0. _i_w_r_a_p (optional) - wraparound ndx flag. 0 = nowrap (ndx<0 treated as ndx=0; ndx>tablesize sticks at ndx=size), 1 = wraparound. The default value is 0. _i_d_e_l - delay in seconds before oosscciill11 incremental sampling begins. _i_d_u_r - duration in seconds to sample through the oosscciill11 table just once. A zero or negative value will cause all initialization to be skipped. PERFORMANCE ttaabbllee invokes table lookup on behalf of init, control or audio indices. These indices can be raw entry numbers (0,1,2...siz-1) or scaled values (0 to 1-e). Indices are first modified by the offset value then checked for range before table lookup (see _i_w_r_a_p). If ndx is likely to be full scale, or if interpolation is being used, the table should have an extended guard point. ttaabbllee indexed by a periodic phasor (see pphhssoorr) will simulate an oscillator. oosscciill11 accesses values by sampling once through the function table at a rate determined by _i_d_u_r. For the first _i_d_e_l sec- onds, the point of scan will reside at the first location of the table; it will then begin moving through the table at a constant rate, reaching the end in another _i_d_u_r seconds; from that time on (i.e. after _i_d_e_l _+ _i_d_u_r seconds) it will remain pointing at the last location. Each value obtained -30- from sampling is then multiplied by an amplitude factor _k_a_m_p before being written into the result. ttaabblleeii and oosscciill11ii are interpolating units in which the fractional part of ndx is used to interpolate between adja- cent table entries. The smoothness gained by interpolation is at some small cost in execution time (see also oosscciillii, etc.), but the interpolating and non-interpolating units are otherwise interchangable. Note that when ttaabblleeii uses a periodic index whose modulo _n is less than the power of 2 table length, the interpolation process requires that there be an (_n+1)th table value that is a repeat of the 1st (see F statement in Score). -31- kr oosscciill kamp, kcps, ifn[, iphs] kr oosscciillii kamp, kcps, ifn[, iphs] ar oosscciill xamp, xcps, ifn[, iphs] ar oosscciillii xamp, xcps, ifn[, iphs] ar ffoosscciill xamp, kcps, kcar, kmod, kndx, ifn[, iphs] ar ffoosscciillii xamp, kcps, kcar, kmod, kndx, ifn[, iphs] Table _i_f_n is incrementally sampled modulo the table length and the value obtained is multiplied by _a_m_p. INITIALIZATION _i_f_n - function table number. Requires a wrap-around guard point. _i_p_h_s (optional) - initial phase of sampling, expressed as a fraction of a cycle (0 to 1). A negative value will cause phase initialization to be skipped. The default value is 0. PERFORMANCE The oosscciill units output periodic control (or audio) signals consisting of the value of _k_a_m_p(xamp) times the value returned from control rate (audio rate) sampling of a stored function table. The internal phase is simultaneously advanced in accordance with the _c_p_s input value. While the amplitude and frequency inputs to the K-rate oosscciills are scalar only, the corresponding inputs to the audio-rate oosscciills may each be either scalar or vector, thus permitting amplitude and frequency modulation at either sub-audio or audio frequencies. ffoosscciill is a composite unit that effectively banks two oosscciills in the familiar Chowning FM setup, wherein the audio-rate output of one generator is used to modulate the frequency input of another (the "carrier"). Effective carrier fre- quency = _k_c_p_s_*_k_c_a_r_, and modulating frequency = _k_c_p_s_*_k_m_o_d_. For integral values of _k_c_a_r and _k_m_o_d_, the perceived funda- mental will be the minimum positive value of _k_c_p_s _* _(_k_c_a_r _- _n_*_k_m_o_d_)_, _n _= _0_,_1_,_2_,_._._. The input _k_n_d_x is the index of modu- lation (usually time-varying and ranging 0 to 4 or so) which determines the spread of acoustic energy over the partial positions given by n = 0,1,2,..,etc. _i_f_n should point to a stored sine wave. oosscciillii and ffoosscciillii differ from oosscciill and ffoosscciill respectively in that the standard procedure of using a truncated phase as a sampling index is here replaced by a process that inter- polates between two successive lookups. Interpolating gen- erators will produce a noticeably cleaner output signal, but they may take as much as twice as long to run. Adequate accuracy can also be gained without the time cost of -32- interpolation by using large stored function tables of 2K, 4K or 8K points if the space is available. Example: k1 oscil 10, 5, 1 ;5 cps vibrato a1 oscil 5000, 440+k1, 1 ;around A440 +-10 cps -33- ar bbuuzzzz xamp, xcps, knh, ifn[, iphs] ar ggbbuuzzzz xamp, xcps, knh, klh, kr, ifn[, iphs] Output is a set of harmonically related cosine partials. INITIALIZATION _i_f_n - table number of a stored function containing (for bbuuzzzz) a sine wave, or (for ggbbuuzzzz) a cosine wave. In either case a large table of at least 8192 points is recommended. _i_p_h_s (optional) - initial phase of the fundamental fre- quency, expressed as a fraction of a cycle (0 to 1). A neg- ative value will cause phase initialization to be skipped. The default value is zero. PERFORMANCE These units generate an additive set of harmonically related cosine partials of fundamental frequency _x_c_p_s, and whose amplitudes are scaled so their summation peak equals _x_a_m_p. The selection and strength of partials is determined by the following control parameters: _k_n_h - total number of harmonics requested. Must be posi- tive. _k_l_h - lowest harmonic present. Can be positive, zero or negative. In ggbbuuzzzz the set of partials can begin at any partial number and proceeds upwards; if _k_l_h is negative, all partials below zero will reflect as positive partials without phase change (since cosine is an even function), and will add constructively to any positive partials in the set. _k_r - specifies the multiplier in the series of amplitude coefficients. This is a power series: if the _k_l_hth partial has a strength coefficient of A, the (_k_l_h+n)th partial will have a coefficient of A * (_k_r**n), i.e. strength values trace an exponential curve. _k_r may be positive, zero or negative, and is not restricted to integers. bbuuzzzz and ggbbuuzzzz are useful as complex sound sources in sub- tractive synthesis. bbuuzzzz is a special case of the more gen- eral ggbbuuzzzz in which _k_l_h = _k_r = 1; it thus produces a set of _k_n_h equal-strength harmonic partials, beginning with the fundamental. (This is a band-limited pulse train; if the partials extend to the Nyquist, i.e. _k_n_h = int(sr/2/funda- mental freq.), the result is a real pulse train of amplitude _x_a_m_p.) Although both _k_n_h and _k_l_h may be varied during per- formance, their internal values are necessarily integer and may cause "pops" due to discontinuities in the output; _k_r, however, can be varied during performance to good effect. -34- Both bbuuzzzz and ggbbuuzzzz can be amplitude- and/or frequency-modu- lated by either control or audio signals. NN..BB.. These two units have their analogs in GEN11, in which the same set of cosines can be stored in a function table for sampling by an oscillator. Although computationally more efficient, the stored pulse train has a fixed spectral content, not a time-varying one as above. -35- ar aaddssyynn kamod, kfmod, ifilno ar ppvvoocc ktimpnt, ifmod, ifilno Output is an additive set of individually controlled sinu- soids, using either an oscillator bank or phase vocoder resynthesis. INITIALIZATION _i_f_i_l_n_o - control-file suffix (m) of a file named _a_d_s_y_n_._m or _p_v_o_c_._m, stemming from analysis of an audio signal. aaddssyynn control contains breakpoint amplitude- and frequency-enve- lope values organized for oscillator resynthesis, while ppvvoocc control contains similar data organized for fft resynthesis. NN..BB.. Storage space for the breakpoint values depends on the size of the control file involved. _i_f_m_o_d - transposition factor for this segment of phase vocoder resynthesis. A value of 1 denotes no transposition, 1.5 transposes up a perfect fifth, and .5 down an octave. PERFORMANCE aaddssyynn affords a powerful means of synthesizing complex time- varying timbres through the method of additive synthesis. Any number of sinusoids, each individually controlled in frequency and amplitude, can be summed by high-speed arith- metic to produce a high-fidelity result. Component sinusoids are described by a control file (format described elsewhere) that specifies both frequency and amplitude tracks in breakpoint fashion (to the millisecond). Through interpolation, the instantaneous frequency and amplitude values are used by an internal fixed-point oscil- lator that adds each active partial into an accumulated out- put signal. There are no limits here, either on the number of contribut- ing partials or on their behavior over time. Any sound com- plex that can be described in terms of the behavior of sinu- soids can be synthesized by aaddssyynn alone. In addition, the sound described by the control file can be modified during actual synthesis. The signals _k_a_m_o_d_, _k_f_m_o_d_, will modify the amplitude and frequency, respectively, of each contributing partial. Note that these are multiplying factors, with _k_f_m_o_d being applied to the cps frequency. Thus the values .7,1.5 will give rise to a softer sound, a perfect fifth higher; the values 1,1 will leave the sound unmodified. Each of these inputs can be a control signal, permitting the sound to be amplitude modulated and/or fre- quency shifted at the control rate. -36- ppvvoocc implements signal reconstruction using an fft-based phase vocoder. The control data stems from a precomputed analysis file with a known frame rate. The passage of time through this file is specified by _k_t_i_m_p_n_t, which represents the time in seconds. _k_t_i_m_p_n_t must always be positive, but can move forwards or backwards in time, be stationary or discontinuous, as a pointer into the analysis file. -37- ar ffooff kamp, kcps, knh, ifn[, iphs] Singing voice synthesis. INITIALIZATION _i_f_n - table number of a stored function containing a sine wave. A large table of at least 8192 points is recommended. _i_p_h_s (optional) - initial phase of the fundamental fre- quency, expressed as a fraction of a cycle (0 to 1). A neg- ative value will cause phase initialization to be skipped. The default value is zero. PERFORMANCE -38- ar pplluucckk kamp, kcps, icps, ifn, imeth [, iparm1, iparm2] Audio output is a naturally decaying plucked string or drum sound based on the Karplus-Strong algorithms. INITIALIZATION _i_c_p_s - intended pitch value in cps, used to set up a buffer of 1 cycle of audio samples which will be smoothed over time by a chosen decay method. _i_c_p_s normally anticipates the value of _k_c_p_s, but may be set artificially high or low to influence the size of the sample buffer. _i_f_n - table number of a stored function used to initialize the cyclic decay buffer. If _i_f_n = 0, a random sequence will be used instead. _i_m_e_t_h - method of natural decay. There are six, some of which use parameters values that follow. 1 - simple averaging. A simple smoothing process, uninflu- enced by parameter values. 2 - stretched averaging. As above, with smoothing time stretched by a factor of _i_p_a_r_m_1 ( >= 1 ). 3 - simple drum. The range from pitch to noise is con- trolled by a 'roughness factor' in _i_p_a_r_m_1 (0 to 1). Zero gives the plucked string effect, while 1 reverses the polarity of every sample (octave down, odd harmonics). The setting .5 gives an optimum snare drum. 4 - stretched drum. Combines both roughness and stretch factors. _i_p_a_r_m_1 is roughness (0 to 1), and _i_p_a_r_m_2 the stretch factor ( >= 1 ). 5 - weighted averaging. As method 1, with _i_p_a_r_m_1 weighting the current sample (the status quo) and _i_p_a_r_m_2 weighting the previous adjacent one. _i_p_a_r_m_1 _+ _i_p_a_r_m_2 must be <= 1. 6 - 1st order recursive filter, with coefs .5. Unaffected by parameter values. _i_p_a_r_m_1_, _i_p_a_r_m_2 (optional) - parameter values for use by the smoothing algorithms (above). The default values are both 0. PERFORMANCE An internal audio buffer, filled at I-time according to _i_f_n, is continually resampled with periodicity _k_c_p_s and the resulting output is multiplied by _k_a_m_p. Parallel with the sampling, the buffer is smoothed to simulate the effect of natural decay. Plucked strings (1,2,5,6) are best realized by starting with a random noise source, which is rich in initial harmonics. Drum sounds (methods 3, 4) work best with a flat source (wide pulse), which produces a deep noise attack and sharp decay. -39- The original Karplus-Strong algorithm used a fixed number of samples per cycle, which caused serious quantization of the pitches available and their intonation. This implementation resamples a buffer at the exact pitch given by _k_c_p_s, which can be varied for vibrato and glissando effects. For low values of the orch sampling rate (e.g. _s_r = 10000), high frequencies will store only very few samples ( = _s_r_/_i_c_p_s). Since this may cause noticeable noise in the resampling pro- cess, the internal buffer has a minimum size of 64 samples. This can be further enlarged by setting _i_c_p_s to some artifi- cially lower pitch. -40- kr rraanndd xamp[, iseed] kr rraannddhh kamp, kcps[, iseed] kr rraannddii kamp, kcps[, iseed] ar rraanndd xamp[, iseed] ar rraannddhh xamp, xcps[, iseed] ar rraannddii xamp, xcps[, iseed] Output is a controlled random number series between _+_a_m_p and _-_a_m_p. INITIALIZATION _i_s_e_e_d (optional) - seed value for the recursive psuedo-ran- dom formula. A value between 0 and +1 will produce an ini- tial output of _k_a_m_p _* _i_s_e_e_d_. A negative value will cause seed re-initialization to be skipped. The default seed value is .5 . PERFORMANCE The internal psuedo-random formula produces values which are uniformly distributed over the range _k_a_m_p to _-_k_a_m_p. rraanndd will thus generate uniform white noise with an R.M.S value of _k_a_m_p_/_r_o_o_t _2. The remaining units produce band-limited noise: the cps parameters permit the user to specify that new random num- bers are to be generated at a rate less than the sampling or control frequencies. rraannddhh will hold each new number for the period of the specified cycle; rraannddii will produce straight-line interpolation between each new number and the next. Example: i1 = octpch(p5) ;center pitch, to be modified k1 rraannddhh 1,10 ;10 times/sec by random dis- ;placements up to 1 octave a1 oosscciill 5000, cpsoct(i1+k1), 1 -41- SIGNAL MODIFIERS kr lliinneenn kamp, irise, idur, idec ar lliinneenn xamp, irise, idur, idec kr eennvvllppxx kamp, irise, idur, idec, ifn, iatss, iatdec[, ixmod] ar eennvvllppxx xamp, irise, idur, idec, ifn, iatss, iatdec[, ixmod] lliinneenn - apply a straight line rise and decay pattern to an input amp signal. eennvvllppxx - apply an envelope consisting of 3 segments: 1) stored function rise shape, 2) modified exponential "pseudo steady state", 3) true exponential decay INITIALIZATION _i_r_i_s_e - rise time in seconds. A zero or negative value sig- nifies no rise modification. _i_d_u_r - overall duration in seconds. A zero or negative value will cause all initialization to be skipped. _i_d_e_c - decay time in seconds. A zero value indicates no decay modification. A value greater than _i_d_u_r will cause a truncated decay pattern. _i_f_n - function table number of stored rise shape with extended guard point. _i_a_t_s_s - attenuation factor, by which the last value of eennvvllppxx rise pattern will become modified during the note's pseudo "steady state." A factor >1 will cause an exponen- tial growth, and a factor <1 an exponential decay. The value 1 will maintain a true steady state at the last rise value. Note that this attenuation is not by fixed rate (as in a piano), but is sensitive to a note's duration. How- ever, if _i_a_t_s_s is negative (or if "steady state" < 4 k-peri- ods) a fixed attenuation rate of _a_b_s_(_i_a_t_s_s_) per second will be used. 0 is illegal. _i_a_t_d_e_c - attenuation factor by which the closing "steady state" value is to be reduced exponentially over the decay period. This value must be positive and will normally be of the order of .01 . A large or an excessively small value is apt to produce a cutoff which is audible. A zero or neg value is illegal. _i_x_m_o_d (optional, between +-.9 or so) - exponential curve modifier, influencing the "steepness" of the exponential trajectory during the "steady state." Values less than zero will cause an accelerated growth or decay towards the target (e.g. _s_u_b_i_t_o _p_i_a_n_o). Values greater than zero will cause a retarded growth or decay. The default value is zero (unmod- ified exponential). -42- PERFORMANCE Rise-time modifications are applied for the first _i_r_i_s_e sec- onds, and decay-time modifications from time _i_d_u_r _- _i_d_e_c. If these two modification periods are separated in time there will be a real "steady state" period during which _a_m_p will be unmodified (lliinneenn) or modified by the first exponen- tial pattern (eennvvllppxx). For lliinneenn, if the rise and decay periods overlap then both modifications will be in effect for that time; for eennvvllppxx an overlap will simply cause a truncated decay pattern. If the overall duration _i_d_u_r is exceeded in performance, the final decay pattern will con- tinue on in the same direction, going negative for lliinneenn but tending asymptotically to zero in the case of eennvvllppxx. -43- Examples: _____________ . . / `. . . / `. . / `. . . / `. . ,.`. / `. . ,` `. / `. .' `. / `. / `. / `. / `. /____________________________`___/____________` Ex 1. lliinneenn a) normal, b) with overlapping rise and decay _ / `. / `. / ` . / ` . / ` . . . /` / ` / `/ `. / `. / ` / ` . /__________________________________________`... Ex 2. eennvvllppxx with _i_a_t_s_s = .5 and _i_x_m_o_d = 0 /` / | / | / . / . / `- - - - . . . . . _ _ _ /` / ` / `/ `. / `. / ` / ` . /__________________________________________`... Ex 3. eennvvllppxx with _i_a_t_s_s = .5 and _i_x_m_o_d = -.9 -44- kr ppoorrtt ksig, ihtim[, isig] ar ttoonnee asig, khp[, istor] ar aattoonnee asig, khp[, istor] ar rreessoonn asig, kcf, kbw[, iscl, istor] ar aarreessoonn asig, kcf, kbw[, iscl, istor] A control or audio signal is modified by a low- or band-pass recursive filter with variable frequency response. INITIALIZATION _i_s_i_g - initial (i.e. previous) value for internal feedback. The default value is 0. _i_s_t_o_r - initial disposition of internal data space. Since filtering incorporates a feedback loop of previous output, the initial status of the storage space used is significant. A zero value will clear the space; a non-zero value will allow previous information to remain. The default value is 0. _i_s_c_l - coded scaling factor for resonators. A value of 1 signifies a peak response factor of 1, i.e. all frequencies other than _k_c_f are attenuated in accordance with the (nor- malized) response curve. A value of 2 raises the response factor so that its overall RMS value equals 1. (This intended equalization of input and ouput power assumes all frequencies are physically present; hence it is most appli- cable to white noise.) A zero value signifies no scaling of the signal, leaving that to some later adjustment (e.g. see bbaallaannccee). The default value is 0. PERFORMANCE ppoorrtt applies portamento to a step-valued control signal. At each new step value, _k_s_i_g is low-pass filtered to move towards that value at a rate determined by _i_h_t_i_m_. _i_h_t_i_m is the "half-time" of the function (in seconds), during which the curve will traverse half the distance towards the new value, then half as much again, etc., theoretically never reaching its asymptote. ttoonnee implements a first-order recursive low-pass filter in which the variable _k_h_p (in c.p.s.) determines the response curve's half-power point. Half power is defined as peak power / root 2. rreessoonn is a second-order filter in which _k_c_f controls the center frequency, or cps position of the peak response, and _k_b_w controls its bandwidth (the cps difference between the upper and lower half-power points). -45- aattoonnee,, aarreessoonn are filters whose transfer functions are the complements of ttoonnee and rreessoonn. aattoonnee is thus a form of high-pass filter and aarreessoonn a notch filter whose transfer functions represent the "filtered out" apsects of their com- plements. Note, however, that power scaling is not normal- ized in aattoonnee,, aarreessoonn, but remains the true complement of the corresponding unit. Thus an audio signal, filtered by parallel matching rreessoonn and aarreessoonn units, would under addi- tion simply reconstruct the original spectrum. This prop- erty is particularly useful for controlled mixing of differ- ent sources (e.g., see llpprreessoonn). Complex response curves such as those with multiple peaks can be obtained by using a bank of suitable filters in series. (The resultant response is the product of the com- ponent responses.) In such cases, the combined attenuation may result in a serious loss of signal power, but this can be regained by the use of bbaallaannccee. -46- krmsr,krmso,kerr,kcps llpprreeaadd ktimpnt, ifilno[, inpoles][, ifrmrate] ar llpprreessoonn asig ar llppffrreessoonn asig, kfrqratio These units, used as a read/reson pair, use a control file of time-varying filter coefficients to dynamically modify the spectrum of an audio signal. INITIALIZATION _i_f_i_l_n_o - control-file suffix (m) referring to a file named 'lp.m' containing frames of reflection coefficients and four special parameter values derived from n-pole linear predic- tive spectral analysis of a source file. A negative value will cause file opening and initialization to be skipped. _i_n_p_o_l_e_s_, _i_f_r_m_r_a_t_e (optional) - number of poles, and frame rate per second in the lpc analysis. These arguments are required only when the control file does not have a header; they are ignored when a header is detected. The default value for both is zero. PERFORMANCE llpprreeaadd accesses a control file of time-ordered information frames, each containing n-pole filter coefficients derived from linear predictive analysis of a source signal at fixed time intervals (e.g. 1/100 of a second), plus four parameter values: _k_r_m_s_r - root-mean-square (rms) of the residual of anal- ysis, _k_r_m_s_o - rms of the original signal, _k_e_r_r - the normalized error signal, _k_c_p_s - pitch in cps. llpprreeaadd gets its values from the control file according to the input value _k_t_i_m_p_n_t (in seconds). If _k_t_i_m_p_n_t proceeds at the analysis rate, time-normal synthesis will result; proceeding at a faster, slower, or variable rate will result in time-warped synthesis. At each K-period, llpprreeaadd automat- ically interpolates between adjacent frames to more accu- rately determine the parameter values (presented as output) and the filter coefficient settings (passed internally to a subsequent llpprreessoonn). The error signal _k_e_r_r (between 0 and 1) derived during pre- dictive analysis reflects the deterministic/random nature of the analyzed source. This will emerge low for pitched (periodic) material and higher for noisy material. The transition from voiced to unvoiced speech, for example, pro- duces an error signal value of about .3. During synthesis, the error signal value can be used to determine the nature of the llpprreessoonn driving function: for example, by -47- arbitrating between pitched and non-pitched input, or even by determining a mix of the two. In normal speech resynthe- sis, the pitched input to llpprreessoonn is a wideband periodic signal or pulse train derived from a unit such as bbuuzzzz, and the non-pitched source is usually derived from rraanndd. How- ever, any audio signal can be used as the driving function, the only assumption of the analysis being that it has a flat response. llppffrreessoonn is a formant shifted llpprreessoonn, in which _k_f_r_q_r_a_t_i_o is the (cps) ratio of shifted to original formant positions. This permits synthesis in which the source object changes its apparent acoustic size. llppffrreessoonn with _k_f_r_q_r_a_t_i_o = 1 is equivalent to llpprreessoonn. Generally, llpprreessoonn provides a means whereby the time-varying content and spectral shaping of a composite audio signal can be controlled by the dynamic spectral content of another. There can be any number of llpprreeaadd//llpprreessoonn (or llppffrreessoonn) pairs in an instrument or in an orchestra; they can read from the same or different control files independently. -48- kr rrmmss asig[, ihp, istor] ar ggaaiinn asig, krms[, ihp, istor] ar bbaallaannccee asig, acomp[, ihp, istor] The rrmmss power of _a_s_i_g can be interrogated, set, or adjusted to match that of a comparator signal. INITIALIZATION _i_h_p (optional) - half-power point (in cps) of a special internal low-pass filter. The default value is 10. _i_s_t_o_r (optional) - initial disposition of internal data space (see rreessoonn). The default value is 0. PERFORMANCE rrmmss output values kr will trace the rrmmss value of the audio input _a_s_i_g. This unit is not a signal modifier, but func- tions rather as a signal power-guage. ggaaiinn provides an amplitude modification of _a_s_i_g so that the output _a_r has rrmmss power equal to _k_r_m_s. rrmmss and ggaaiinn used together (and given matching ihp values) will provide the same effect as bbaallaannccee. bbaallaannccee outputs a version of _a_s_i_g, amplitude-modified so that its rrmmss power is equal to that of a comparator signal _a_c_o_m_p. Thus a signal that has suffered loss of power (eg., in passing through a filter bank) can be restored by match- ing it with, for instance, its own source. It should be noted that ggaaiinn and bbaallaannccee provide amplitude modification only - output signals are not altered in any other respect. Example: asrc buzz 10000, 440, sr/440, 1 ;band-limited pulse train a1 reson asrc, 1000, 100 ;sent through a2 reson a1, 3000, 500 ;2 filters afin balance a2, asrc ;then balanced with source -49- kr ddoowwnnssaammpp asig[, iwlen] ar uuppssaammpp ksig ar iinntteerrpp ksig[, istor] kr iinntteegg ksig[, istor] ar iinntteegg asig[, istor] kr ddiiffff ksig[, istor] ar ddiiffff asig[, istor] kr ssaammpphhoolldd xsig, kgate[, ival, ivstor] ar ssaammpphhoolldd asig, xgate[, ival, ivstor] Modify a signal by up- or down-sampling, integration, and differentiation. INITIALIZATION _i_w_l_e_n (optional) - window length in samples over which the audio signal is averaged to determine a downsampled value. Maximum length is _k_s_m_p_s; 0 and 1 imply no window averaging. The default value is 0. _i_s_t_o_r (optional) - initial disposition of internal save space (see rreessoonn). The default value is 0. _i_v_a_l_, _i_v_s_t_o_r (optional) - controls initial disposition of internal save space. If _i_v_s_t_o_r is zero the internal "hold" value is set to _i_v_a_l; else it retains its previous value. The defaults are 0, 0 (i.e. init to zero). PERFORMANCE ddoowwnnssaammpp converts an _a_u_d_i_o signal to a _c_o_n_t_r_o_l signal by downsampling. It produces one kval for each audio control period. The optional window invokes a simple averaging pro- cess to supress foldover. uuppssaammpp,, iinntteerrpp convert a _c_o_n_t_r_o_l signal to an _a_u_d_i_o signal. The first does it by simple repetition of the kval, the sec- ond by linear interpolation between successive kvals. uuppssaammpp is a slightly more efficient form of the assignment 'asig = ksig'. iinntteegg,, ddiiffff perform _i_n_t_e_g_r_a_t_i_o_n and _d_i_f_f_e_r_e_n_t_i_a_t_i_o_n on an input control signal or audio signal. Each is the converse of the other, and applying both will reconstruct the origi- nal signal. Since these units are special cases of low-pass and high-pass filters, they produce a scaled (and phase shifted) output that is frequency-dependent. Thus ddiiffff of a sine produces a cosine, with amplitude _2_*_s_i_n_(_p_i_*_c_p_s_/_s_r_) that of the original (for each component partial); iinntteegg will inversely affect the magnitudes of its component inputs. With this understanding, these units can provide useful sig- nal modification. -50- ssaammpphhoolldd performs a sample-and-hold operation on its input according to the value of _g_a_t_e. If _g_a_t_e _> _0, the input sam- ples are passed to the output; if _g_a_t_e _<_= _0, the last out- put value is repeated. The controlling _g_a_t_e can be a con- stant, a control signal, or an audio signal. Example: asrc buzz 10000, 440, 20, 1 ;band-limited pulse train adif diff asrc ;emphasize the highs anew balance adif, asrc ; but retain the power agate reson asrc, 0, 440 ;use a lowpass of the original asamp samphold anew, agate ; to gate the new audiosig aout tone asamp, 100 ;smooth out the rough edges -51- ar ddeellaayyrr idlt[, istor] ddeellaayyww asig ar ddeellaayy asig, idlt[, istor] ar ddeellaayy11 asig[, istor] A signal can be read from or written into a delay path, or it can be automatically delayed by some time interval. INITIALIZATION _i_d_l_t - requested delay time in seconds. This can be as large as available memory will permit. The space required for _n seconds of delay is 4_n * ssrr bytes. It is allocated at the time the instrument is first initialized, and returned to the pool at the end of a score section. _i_s_t_o_r (optional) - initial disposition of delay-loop data space (see rreessoonn). The default value is 0. PERFORMANCE ddeellaayyrr reads from an automatically established digital delay line, in which the signal retrieved has been resident for _i_d_l_t seconds. This unit must be paired with and precede an accompanying ddeellaayyww unit. Any other CCssoouunndd statements can intervene. ddeellaayyww writes _a_s_i_g into the delay area established by the preceding ddeellaayyrr unit. Viewed as a pair, these two units permit the formation of modified feedback loops, etc. How- ever, there is a lower bound on the value of _i_d_l_t, which must be at least 1 control period (or 1/kkrr). ddeellaayy is a composite of the above two units, both reading from and writing into its own storage area. It can thus accomplish signal time-shift, although modified feedback is not possible. There is no minimum delay period. ddeellaayy11 is a special form of ddeellaayy that serves to delay the audio signal _a_s_i_g by just one sample. It is thus function- ally equivalent to "ddeellaayy asig,1/srate" but is more effi- cient in both time and space. This unit is particularly useful in the fabrication of generalized non-recursive fil- ters. Example: ttiiggoottoo contin ;except on a tie, a2 ddeellaayy a1, .05, 0 ;begin 50 msec clean delay of sig contin: -52- ar ddeellttaapp kdlt ar ddeellttaappii xdlt Tap a delay line at variable offset times. PERFORMANCE These units can tap into a ddeellaayyrr//ddeellaayyww pair, extracting delayed audio from the _i_d_l_t seconds of stored sound. There can be any number of ddeellttaapp and/or ddeellttaappii units between a read/write pair. Each receives an audio tap with no change of original amplitude. ddeellttaapp extracts sound by reading the stored samples directly; ddeellttaappii extracts sound by _i_n_t_e_r_p_o_l_a_t_e_d _r_e_a_d_o_u_t. By interpolating between adjacent stored samples ddeellttaappii represents a particular delay time with more accuracy, but it will take about twice as long to run. The arguments _k_d_l_t_, _x_d_l_t specify the tapped delay time in seconds. Each can range from 1 Control Period to the full delay time of the read/write pair; however, since there is no internal check for adherence to this range, the user is wholly responsible. Each argument can be a constant, a variable, or a time-varying signal; the _x_d_l_t argument in ddeellttaappii implies that an audio-varying delay is permitted there. These units can provide multiple delay taps for arbitrary delay path and feedback networks. They can deliver either constant-time or time-varying taps, and are useful for building chorus effects, harmonizers, and doppler shifts. Constant-time delay taps (and some slowly changing ones) do not need interpolated readout; they are well served by ddeellttaapp. Medium-paced or fast varying _d_l_t_'_s, however, will need the extra services of ddeellttaappii. N.B. K-rate delay times are not internally interpolated, but rather lay down stepped time-shifts of audio samples; this will be found quite adequate for slowly changing tap times. For medium to fast-paced changes, however, one should provide a higher resolution audio-rate timeshift as input. Example: asource buzz 1, 440, 20, 1 atime linseg 1, p3/2, .01, p3/2, 1 ;trace a distance in secs -53- ampfac = 1/atime/atime ; and calc an amp factor adump delayr 1 ;set maximum distance amove deltapi atime ;move sound source past delayw asource ; the listener out amove * ampfac -54- ar ccoommbb asig, krvt, ilpt[, istor] ar aallppaassss asig, krvt, ilpt[, istor] ar rreevveerrbb asig, krvt[, istor] An input signal is reverberated for _k_r_v_t seconds with "col- ored" (ccoommbb), flat (aallppaassss), or "natural room" (rreevveerrbb) fre- quency response. INITIALIZATION _i_l_p_t - loop time in seconds, which determines the "echo den- sity" of the reverberation. This in turn characterizes the "color" of the ccoommbb filter whose frequency response curve will contain _i_l_p_t _* _s_r_/_2 peaks spaced evenly between 0 and _s_r_/_2 (the Nyquist frequency). Loop time can be as large as available memory will permit. The space required for an _n second loop is 4_n _* _s_r bytes. ccoommbb and aallppaassss delay space is allocated and returned as in ddeellaayy. _i_s_t_o_r (optional) - initial disposition of delay-loop data space (cf. rreessoonn). The default value is 0. PERFORMANCE These filters reiterate input with an echo density deter- mined by loop time _i_l_p_t. The attenuation rate is indepen- dent and is determined by _k_r_v_t, the reverberation time (defined as the time in seconds for a signal to decay to 1/1000, or 60 db down from its original amplitude). Output from a ccoommbb filter will appear only after _i_l_p_t seconds; aallppaassss output will begin to appear immediately. A rreevveerrbb unit is composed of four ccoommbb filters in parallel followed by two aallppaassss units in series. Looptimes are set for optimal "natural room response." Core storage require- ments for this unit are proportional only to the sampling rate, each unit requiring approximately 3K words for every 10KC. It is usually expedient to mix several signals together before reverberation. Since rreevveerrbb output will begin to appear only after 1/20 second or so of delay, and often with less than three-fourths of the original power, it is common to output both the source and the reverberated signal together. Example: a1 oscili k1, a1, 1 ;create two signals a2 oscili k2, a2, 2 a3 reverb a1+a2, 1.5 ;mix, then reverberate outs a1+a3, a2+a3 ;send 1 source + both reverbs -55- ;through each speaker -56- SIGNAL DISPLAY pprriinntt iarg[, iarg, ...] ddiissppllaayy xsig, iprd ddssppddfftt asig, iprd, iwsiz[, iwtyp][, idbout] ddssppfffftt asig, iprd, iwsiz[, iwtyp][, idbout] These units permit initialization values to be printed, or control signals and audio signals to be displayed in graphic form. INITIALIZATION _i_p_r_d - the period of display in seconds. _i_w_s_i_z - size of the input window in samples. A window of _i_w_s_i_z points will produce a Fourier transform of _i_w_s_i_z_/_2 points, spread linearly in frequency from 0 to sr/2. _i_w_s_i_z can be any positive number for ddssppddfftt, but must be a power of 2 for ddssppfffftt. The window are permitted to overlap. _i_w_t_y_p (optional) - window type. 0 = rectangular, 1 = han- ning. The default value is 0 (rectangular). _i_d_b_o_u_t (optional) - units of output for the Fourier coeffi- cients. 0 = magnitude, 1 = decibels. The default is 0 (magnitude). PERFORMANCE pprriinntt - print the current value of the I-time arguments (or expressions) _i_a_r_g at every I-pass through the instrument. ddiissppllaayy - display the audio or control signal _x_s_i_g every _i_p_r_d seconds, as an amplitude vs time graph. ddssppddfftt - display the Discrete Fourier Transform of the audio signal _a_s_i_g every _i_p_r_d seconds. ddssppfffftt - display the Fourier Transform of the audio signal _a_s_i_g every _i_p_r_d seconds using the Fast Fourier Transform method. Example: k1 envlpx 1,.03,p3,.05,1,.5,.01 ;generate a note envelope display k1, p3 ;and display entire shape -57- SOUNDFILE INPUT & OUTPUT a1, a2, a3, a4 ppaann asig, kx, ky, ifn[, imode][, ioffset] Distribute an audio signal amongst four channels with local- ization control. INITIALIZATION _i_f_n - function table number of a stored pattern describing the amplitude growth in a speaker channel as sound moves towards it from an adjacent speaker. Requires extended guard-point. _i_m_o_d_e (optional) - mode of the _k_x_, _k_y position values. 0 signifies raw index mode, 1 means the inputs are normalized (0-1). The default value is 0. _i_o_f_f_s_e_t (optional) - offset indicator for _k_x_, _k_y. 0 infers the origin to be at channel 3 (left rear); 1 requests an axis shift to the quadraphonic center. The default value is 0. PERFORMANCE ppaann takes an input signal _a_s_i_g and distributes it amongst four outputs (essentially quad speakers) according to the controls _k_x and _k_y. For normalized input (mode=1) and no offset, the four output locations are in order: left-front at (0,1), right-front at (1,1), left-rear at the origin (0,0), and right-rear at (1,0). In the notation _(_k_x_, _k_y_), the coordinates _k_x and _k_y, each ranging 0-1, thus control the 'rightness' and 'forwardness' of a sound location. Movement between speakers is by amplitude variation, con- trolled by the stored function table _i_f_n. As _k_x goes from 0 to 1, the strength of the right-hand signals will grow from the left-most table value to the right-most, while that of the left-hand signals will progress from the right-most table value to the left-most. For a simple linear pan, the table might contain the linear function 0-1. A more correct pan that maintains constant power would be obtained by stor- ing the first quadrant of a sinusoid. Since ppaann will scale and truncate _k_x and _k_y in simple table lookup, a medium- large table (say 8193) should be used. _k_x_, _k_y values are not restricted to 0-1. A circular motion passing through all four speakers (escribed) would have a diameter of root 2, and might be defined by a circle of radius R = root 1/2 with center at (.5,.5). _k_x_, _k_y would then come from Rcos(angle), Rsin(angle), with an implicit -58- origin at (.5,.5) (i.e. ioffset=1). Unscaled raw values operate similarly. Sounds can thus be located anywhere in the polar or cartesian plane; points lying outside the speaker square are projected correctly onto the square's perimeter as for a listener at the center. Example: instr 1 k1 phasor 1/p3 ;fraction of circle k2 tablei k1, 1, 1 ;sin of angle (sinusoid in f1) k3 tablei k1, 1, 1, .25, 1 ;cos of angle (sin offset 1/4 circle) a1 oscili 10000, 440, 1 ;audio signal .. a1,a2,a3,a4 pan a1, k2/2, k3/2, 2, 1, 1 ; sent in a circle (f2=1st quad sin) outq a1, a2, a3, a4 endin -59- a1 ssoouunnddiinn ifilno[, iskptim] a1, a2 ssoouunnddiinn ifilno[, iskptim] a1, a2, a3, a4 ssoouunnddiinn ifilno[, iskptim] oouutt asig oouuttss11 asig oouuttss22 asig oouuttss asig1, asig2 oouuttqq11 asig oouuttqq22 asig oouuttqq33 asig oouuttqq44 asig oouuttqq asig1, asig2, asig3, asig4 These units read from and write to an external sound-file device. INITIALIZATION _i_f_i_l_n_o - integer suffix (n) of a binary file named 'soundin.n', assumed to be in the directory SFDIR (see also GEN01). This is normally a soundfile (with header), whose samples may be either shorts or floats. If the file has no soundfile header, they are assumed floats. _i_s_k_p_t_i_m (optional) - time in seconds of input sound to be skipped. The default value is zero. PERFORMANCE ssoouunnddiinn is functionally a signal generator that happens to derive its signal from a pre-existing file. The number of channels read in is set by the number of result cells, a1, a2, etc. A ssoouunnddiinn unit opens this file whenever the host instrument is initialized, then closes it again each time the instrument is turned off. There can be any number of ssoouunnddiinn units within a single instrument or orchestra; also, two or more of them can read simultaneously from the same external file. oouutt,, oouuttss,, oouuttqq, on the other hand, do not deal directly with an external sound file, but send audio samples to an accumulating output buffer (created at the beginning of per- formance) which serves to collect the output of all active instruments before the sound is written to disk. There can be any number of these output units in an instrument. The type (mono, stereo, or quad) must agree with nncchhnnllss, but units can be chosen to direct sound to any particular chan- nel: oouuttss11 sends to stereo channel 1, oouuttqq33 to quad channel 3, etc. Soundfile statements are most commonly used in direct sound generation. However, they also lend themselves to the -60- standard studio tasks of mixing, splicing, editing, post reverberating, etc. By doing these operations digitally, the problem of accumulated analog tape noise is thus avoided. -61- 33.. TTHHEE SSTTAANNDDAARRDD NNUUMMEERRIICC SSCCOORREE A score is a data file that provides information to an orchestra about its performance. Like an orchestra file, a score file is made up of statements in a known format. The CCssoouunndd orchestra expects to be handed a score comprised mainly of _a_s_c_i_i _n_u_m_e_r_i_c _c_h_a_r_a_c_t_e_r_s. Although most users will prefer a higher level score language such as provided by CCssccoorree,, SSccoott, or other score-generating programs, each resulting score must eventually appear in the format expected by the orchestra. A Standard Numeric Score can be created and edited directly by the beginner using standard text editors; indeed, some users continue to prefer it. The purpose of this section is to describe this format in detail. The basic format of a standard numeric score statement is: opcode p1 p2 p3 p4 ... ;comments The _o_p_c_o_d_e is a single character, always alphabetic. Legal opcodes are ff,, ii,, aa,, tt,, ss, and ee, the meanings of which are described in the following pages. The opcode is normally the first character of a line; leading spaces or tabs will be ignored. Spaces or tabs between the opcode and _p_1 are optional. _p_1_, _p_2_, _p_3_, etc. are _p_a_r_a_m_e_t_e_r _f_i_e_l_d_s _(_p_f_i_e_l_d_s_)_. Each con- tains a floating point number comprised of an optional sign, digits, and an optional decimal point. Expressions are not permitted in Standard Score files. _p_f_i_e_l_d_s are separated from each other by one or more spaces or tabs, all but one space of which will be ignored. Continuation lines are permitted. If the first printing character of a new scoreline is not an opcode, that line will be regarded as a continuation of the pfields from the previous scoreline. Comments are optional and are for the purpose of permitting the user to document his score file. Comments always begin with a semicolon (;) and extend to the end of the line. Comments will not affect the pfield continuation feature. Blank lines or comment-only lines are legal (and will be ignored). PPrreepprroocceessssiinngg ooff SSttaannddaarrdd SSccoorreess A Score (a collection of score statements) is divided into time-ordered _s_e_c_t_i_o_n_s by the ss statement. Before being read by the orchestra, a score is _p_r_e_p_r_o_c_e_s_s_e_d one section -62- at a time. Each section is normally processed by 3 rou- tines: Carry, Tempo, and Sort. 11.. CCaarrrryy - within a group of consecutive ii statements whose p1 whole numbers correspond, any pfield left empty will take its value from the same pfield of the preceding statement. An empty pfield can be denoted by a single point (.) delim- ited by spaces. No point is required after the last non- empty pfield. The output of Carry preprocessing will show the carried values explicitly. The Carry Feature is not affected by intervening comments or blank lines; it is turned off only by a _n_o_n_-_i statement or by an ii statement with unlike p1 whole number. An additional feature is available for p2 alone. The symbol + in p2 will be given the value of p2+p3 from the preceding ii statement. This enables note action times to be automati- cally determined from the sum of preceding durations. The + symbol can itself be carried. The + symbol is legal only in p2. E.g., the statements i1 0 .5 100 will result in i1 0 .5 100 i. + i1 .5 .5 100 i i1 1 .5 100 The Carry feature should be used liberally. Its use, espe- cially in large scores, can greatly reduce input typing and will simplify later changes. 22.. TTeemmppoo - this operation time warps a score section accord- ing to the information in a tt statement. The tempo opera- tion converts p2 (and, for ii statements, p3) from original beats into real seconds, since those are the units required by the orchestra. After time warping, score files will be seen to have orchestra-readable format demonstrated by the following: ii p1 p2beats p2seconds p3beats p3seconds p4 p5 .... 33.. SSoorrtt - this routine sorts all action-time statements into chronological order by p2 value. It also sorts coincident events into precedence order. Whenever an ff statement and an ii statement have the same p2 value, the ff statement will precede. Whenever two or more ii statements have the same p2 value, they will be sorted into ascending p1 value order. If they also have the same p1 value, they will be sorted into ascending p3 value order. Score sorting is done sec- tion by section (see ss statement). Automatic sorting implies that score statements may appear in any order within a section. NN..BB.. The procedures performing the above operations can be run either independently or in batched mode. The ppeerrff com- mand, for instance, invokes a module containing all three operations Carry, Tempo and Sort in a single pass over the score file, to produce a new file in orchestra-readable for- mat (see the Tempo example). The Carry procedure invoked alone will give the user a visual check of its operation; -63- its output format is still that of the source (i.e. not yet orchestra readable). Source-format files and orchestra- readable files are nevertheless both in ascii-character form, and may be either perused or further modified by stan- dard text editors. Additional user-written routines can be used to modify score files before or after any of the above processes, provided the final orchestra-readable statement format is not violated. NNeexxtt--PP aanndd PPrreevviioouuss--PP SSyymmbboollss At the close of any of the above operation, three addi- tional score features are interpreted during file writeout: next-p, previous-p, and ramping. ii statement pfields containing the symbols nnpp_x or pppp_x (where x is some integer) will be replaced by the appropriate pfield value found on the next ii statement (or previous ii statement) that has the same p1. For example, the symbol np7 will be replaced by the value found in p7 of the next note that is to be played by this instrument. np and pp symbols are recursive and can reference other np and pp sym- bols which can reference others, etc. References must even- tually terminate in a real number or a ramp symbol (see below). Closed loop references should be avoided. np and pp symbols are illegal in p1,p2 and p3 (although they may reference these). np and pp symbols may be Carried. np and pp references cannot cross a Section boundary; any forward or backward reference to a non-existent note-statement will be given the value zero. For example, the statements i1 0 1 10 np4 pp5 will result in i1 0 1 10 20 0 i1 1 1 20 i1 1 1 20 30 20 i1 2 1 30 i1 2 1 30 0 30 np and pp symbols can provide an instrument with contextual knowledge of the score, enabling it to glissando or crescendo, for instance, toward the pitch or dynamic of some future event (which may or may not be immediately adjacent). Note that while the Carry feature will propagate np and pp through unsorted statements, the operation that interprets these symbols is acting on a time-warped and fully sorted version of the score. RRaammppiinngg ii statement pfields containing the symbol < will be replaced by values derived from linear interpolation of a time-based ramp. Ramps are anchored at each end by the first real number found in the same pfield of a preceding and following note played by the same instrument. For exam- ple, the statements i1 0 1 100 will result in i1 0 1 100 i1 1 1 < i1 1 1 200 i1 2 1 < i1 2 1 300 i1 3 1 400 i1 3 1 400 -64- i1 4 1 < i1 4 1 200 i1 5 1 0 i1 5 1 0 Ramps cannot cross a Section boundary. Ramps cannot be anchored by an np or pp symbol (although they may be refer- enced by these). Ramp symbols are illegal in p1,p2 and p3. Ramp symbols may be Carried. Note, however, that while the Carry feature will propagate ramp symbols through unsorted statements, the operation that interprets these symbols is acting on a time-warped and fully sorted version of the score. In fact, time-based linear interpolation is based on warped score-time, so that a ramp which spans a group of accelerating notes will remain linear with respect to strict chronological time. -65- F STATEMENT (or FUNCTION TABLE STATEMENT) ff p1 p2 p3 p4 ... This causes a GEN subroutine to place values in a stored function table for use by instruments. PFIELDS p1 Table number (from 1 to 100) by which the stored function will be known. A negative number requests that the table be destroyed. p2 Action time of function generation (or destruction) in beats p3 Size of function table (i.e. number of points). Must be a power of 2, or a power-of-2 plus 1 (see below). Maximum table size is 16777216 (2**24) points. p4 Number of the GEN routine to be called (see GEN ROUTINES). A negative value will cause rescaling to be omitted. p5 | p6 | Parameters whose meaning is determined by the particular GEN routine. . | . | . | SPECIAL CONSIDERATIONS Function tables are arrays of floating-point values. Arrays can be of any length in powers of 2; space allocation always provides for 2**n points plus an additional _g_u_a_r_d _p_o_i_n_t. The guard point value, used during interpolated lookup, can be automatically set to reflect the table's purpose: If _s_i_z_e is an exact power of 2, the guard point will be a copy of the first point; this is appropriate for _i_n_t_e_r_p_o_l_a_t_e_d _w_r_a_p_- _a_r_o_u_n_d lookup as in oosscciillii,, etc., and should even be used for non-interpolating oosscciill for safe consistency. If _s_i_z_e is set to 2**n + 1, the guard point value automatically extends the contour of table values; this is appropriate for single-scan functions such in eennvvllppxx,, oosscciill11,, oosscciill11ii, etc. Table space is allocated in primary memory, along with instrument data space. The maximum table number has a soft limit of 100; this can be extended if required. An existing function table can be removed by an ff statement containing a negative p1 and an appropriate action time. A function table is also be removed by the generation of another table with the same p1. Functions are not automati- cally erased at the end of a score section. p2 action time is treated in the same way as in ii statements with respect to sorting and modification by tt statements. If an ff statement and an ii statement have the same p2, the sorter gives the ff statement precedence so that the function table will be available during note initialization. An ff 00 statement (zero p1, positive p2) may be used to -66- create an action time with no associated action. Such time markers are useful for padding out a score section (see ss statement). -67- I STATEMENT (INSTRUMENT or NOTE STATEMENT) ii p1 p2 p3 p4 ... This statement calls for an instrument to be made active at a specific time and for a certain duration. The parameter field values are passed to that instrument prior to its Ini- tialization, and remain valid throughout its Performance. PFIELDS p1 Instrument number, usually a non-negative integer. An optional fractional part can provide an additional tag for specifying ties between particular notes of consecutive clusters. A negative p1 (including tag) can be used to turn off a particular 'held' note. p2 Starting time in arbitrary units called beats. p3 Duration time in beats (usually positive). A negative value will initiate a held note (see also iihhoolldd). A zero value will invoke an initialization pass without performance (see also iinnssttrr). p4 | p5 | Parameters whose significance is determined by the instrument. . | . | SPECIAL CONSIDERATIONS Beats are evaluated as seconds unless there is a tt statement in this section. Starting or action times are relative to the beginning of a section (see ss statement), which is assigned time 0. Note statements within a section may be placed in any order. Before being sent to an orchestra, unordered score state- ments must first be processed by Sorter, which will reorder them by ascending p2 value. Notes with the same p2 value will be ordered by ascending p1; if the same p1, then by ascending p3. Notes may be stacked, i.e., a single instrument can perform any number of notes simultaneously. (The necessary copies of the instrument's data space will be allocated dynamically by the orchestra loader.) Each note will normally turn off when its p3 duration has expired. However, an instrument may modify its own duration by modifying its p3 value during note initialization. An instrument may be turned on and left to perform indefi- nitely either by giving it a negative p3 or by including an iihhoolldd in its I-time code. If a held note is active, an ii statement _w_i_t_h _m_a_t_c_h_i_n_g _p_1 will not cause a new allocation but will take over the data space of the held note. The new pfields (including p3) will now be in effect, and an I-time pass will be executed in which the units can either be newly -68- initialized or allowed to continue as required for a tied note (see ttiiggoottoo). A held note may be succeeded either by another held note or by a note of finite duration. A held note will continue to perform across section endings (see ss statement). It is halted only by ttuurrnnooffff or by an ii state- ment with negative matching p1 or by an ee statement. -69- A STATEMENT (or ADVANCE STATEMENT) aa p1 p2 p3 This causes score time to be advanced by a specified amount without producing sound samples. PFIELDS p1 carries no meaning. Usually zero p2 Action time, in beats, at which advance is to begin. p3 Durational span (distance in beats) of time advance. p4,p5, etc carry no meaning. SPECIAL CONSIDERATIONS This statement allows the beat count within a score section to be advanced without generating intervening sound samples. This can be of use when a score section is incomplete (the beginning or middle is missing) and the user does not wish to generate and listen to a lot of silence. p2 action time and p3 distance are treated as in ii state- ments, with respect to sorting and modification by tt state- ments. An aa statement will be temporarily inserted in the score by the Score Extract feature when the extracted segment begins later than the start of a Section. The purpose of this is to preserve the beat count and time count of the original score for the benefit of the peak amplitudes messages which are reported on the user console. Whenever an aa statement is encountered by a performing orchestra, its presence and effect will be reported on the user's console. -70- T STATEMENT (TEMPO STATEMENT) tt p1 p2 p3 p4 ..... (unlimited) This statement sets the tempo and specifies the accelera- tions and decelerations for the current section. This is done by converting beats into seconds. PFIELDS p1 must be zero p2 initial tempo in beats per minute p3, p5, p7, ... times in beats (in non-decreasing order) p4, p6, p8, ... tempi for the referenced beat times SPECIAL CONSIDERATIONS Time and Tempo-for-that-time are given as ordered couples that define points on a "tempo vs time" graph. (The time- axis here is in beats so is not necessarily linear.) The beat-rate of a Section can be thought of as a movement from point to point on that graph: motion between two points of equal height signifies constant tempo, while motion between two points of unequal height will cause an accelarando or ritardando accordingly. The graph can contain discontinu- ities: two points given equal times but different tempi will cause an immediate tempo change. Motion between different tempos over non-zero time is inverse linear. That is, an accelarando between two tempos M1 and M2 proceeds by linear interpolation of the single- beat durations from 60/M1 to 60/M2. The first tempo given must be for beat 0. A tempo, once assigned, will remain in effect from that time-point unless influenced by a succeeding tempo, i.e. the last specified tempo will be held to the end of the section. A tt statement applies only to the score section in which it appears. Only one tt statement is meaningful in a section; it can be placed anywhere within that section. If a score section contains no tt statement, then beats are interpreted as seconds (i.e. with an implicit t 0 60 statement). -71- S STATEMENT ss anything The ss statement marks the end of a section. PFIELDS All pfields are ignored. SPECIAL CONSIDERATIONS Sorting of the ii,, ff and aa statements by action time is done section by section. Time warping for to the tt statement is done section by sec- tion. All action times within a section are relative to its begin- ning. A section statement establishes a new relative time of 0, but has no other reinitializing effects (e.g. stored function tables are preserved across section boundaries). A section is considered complete when all action times and finite durations have been satisfied (i.e., the "length" of a section is determined by the last occurring action or turn-off). A section can be extended by the use of an ff 00 statement. A section ending automatically invokes a Purge of inactive instrument and data spaces. Since score statements are sorted in memory, the maximum number of statements in a single section depends upon memory size. That limit is rarely encountered, but for small sys- tems of say 128K bytes, an average of 10 pfields or 50 char- acters per statement should allow at least 500 statements per section. For the end of the final section of a score, the ss statement is optional; the ee statement may be used instead. -72- E STATEMENT ee anything This statement may be used to mark the end of the last sec- tion of the score. PFIELDS All pfields are ignored SPECIAL CONSIDERATIONS The ee statement is contextually identical to an ss statement. Additionally, the ee statement terminates all signal genera- tion (including indefinite performance) and closes all input and output files. If an ee statement occurs before the end of a score, all sub- sequent score lines will be ignored. The ee statement is optional in a score file yet to be sorted. If a score file has no ee statement, then Sort pro- cessing will supply one. -73- 44.. GGEENN RROOUUTTIINNEESS The GEN subroutines are function-drawing procedures called by ff statements to construct stored wavetables. They are available throughout orchestra performance, and can be invoked at any point in the score as given by p2. p1 assigns a table _n_u_m_b_e_r, and p3 the table _s_i_z_e (see ff state- ment). p4 specifies the GEN routine to be called; each GEN routine will assign special meaning to the pfield values that follow. GEN01, GEN02 These subroutines transfer data from a soundfile (GEN01) or from the immediate pfields (GEN02) into the locations of a function table. ff # time size 1 filno skiptime ff # time size 2 v1 v2 v3 . . . _s_i_z_e - number of points in the table. Must be a power of 2 or a power-of-2 plus 1 (see ff statement). The maximum tablesize is 16777216 (2**24) points. _f_i_l_n_o_, _s_k_i_p_t_i_m_e - directs GEN01 to read from a binary file named ssoouunnddiinn.._f_i_l_n_o, beginning at a point _s_k_i_p_t_i_m_e seconds into the file. The file may be a soundfile (with header) in shorts or floats, or a simple binary file (no header) in floats; it is assumed to be in the directory SFDIR (see also ssoouunnddiinn). Reading stops at end-of-file or when the table is full. Any table locations not filled will contain zeros. _v_1_, _v_2_, _v_3_, _._._. - for GEN02 these values will be copied directly into the table space. The maximum number of values that can be sent is soft-limited by a compiler variable PMAX controlling the maximum pfields (standardly 50 but change- able). The values copied may include the table guard point; any table locations not filled will contain zeros. Note: If p4 is positive, the table will be post-normalized (rescaled to a maximum absolute value of 1 after genera- tion). A negative p4 will cause rescaling to be skipped. Example: ff 1 0 16 -2 0 1 2 3 4 5 6 7 8 9 10 11 0 This calls upon GEN02 to place 12 values plus an explicit -74- wrap-around guard value into a table of size next-highest power of 2. Rescaling is inhibited. -75- GEN03 This subroutine generates a stored function table by evalu- ating a polynomial in x over a fixed interval and with spec- ified coefficients. ff # time size 3 xval1 xval2 c0 c1 c2 . . . cn _s_i_z_e - number of points in the table. Must be a power of 2 or a power-of-2 plus 1 (see ff statement). _x_v_a_l_1_, _x_v_a_l_2 - left and right values of the x interval over which the polynomial is defined (_x_v_a_l_1 _< _x_v_a_l_2). These will produce the 1st stored value and the (power-of-2 plus 1)th stored value respectively in the generated function table. _c_0_, _c_1_, _c_2_, _._._._. _c_n - coefficients of the nth-order polyno- mial c sub 0 ~+~ c sub 1 x ~+~ c sub 2 x sup 2 ~+~ c sub 3 x sup 3 ~+~ ... ~+~ c sub n x sup n Coefficients may be positive or negative real numbers; a zero denotes a missing term in the polynomial. The coeffi- cient list begins in p7, providing an upper limit of 44 terms. Note: The defined segment [fn(_x_v_a_l_1),fn(_x_v_a_l_2)] is evenly dis- tributed. Thus a 512-point table over the interval [-1,1] will have its origin at location 257 (at the start of the 2nd half). Provided the extended guard point is requested, both fn(-1) and fn(1) will exist in the table. GEN03 is useful in conjunction with ttaabbllee or ttaabblleeii for audio waveshaping (sound modification by non-linear distor- tion). Coefficients to produce a particular formant from a sinusoidal lookup index of known amplitude can be determined at preprocessing time using algorithms such as Chebyshev formulae. See also GEN13. Example: f 1 0 1025 3 -1 1 5 4 3 2 1 This calls GEN03 to fill a table with a 4th order polynomial function over the x-interval -1 to 1. The origin will be at the offset position 512. The function is post-normalized. -76- GEN04 This subroutine generates a normalizing function by examin- ing the contents of an existing table. ff # time size 4 source# sourcemode _s_i_z_e - number of points in the table. Should be power-of-2 plus 1. Must not exceed (except by 1) the size of the source table being examined; limited to just half that size if the sourcemode is of type offset (see below). _s_o_u_r_c_e_# - table number of stored function to be examined. _s_o_u_r_c_e_m_o_d_e - a coded value, specifying how the source table is to be scanned to obtain the normalizing function. Zero indicates that the source is to be scanned from left to right. Non-zero indicates that the source has a bipolar structure; scanning will begin at the mid-point and progress outwards, looking at pairs of points equidistant from the center. Note: The normalizing function derives from the progressive abso- lute maxima of the source table being scanned. The new table is created left-to-right, with stored values equal to 1/(absolute maximum so far scanned). Stored values will thus begin with 1/(first value scanned), then get progres- sively smaller as new maxima are encountered. For a source table which is normalized (values <= 1), the derived values will range from 1/(first value scanned) down to 1. If the first value scanned is zero, that inverse will be set to 1. The normalizing function from GEN04 is not itself normal- ized. GEN04 is useful for scaling a table-derived signal so that it has a consistent peak amplitude. A particular applica- tion occurs in waveshaping when the carrier (or indexing) signal is less than full amplitude. Example: f 2 0 512 4 1 1 This creates a normalizing function for use in connection with the GEN03 table 1 example. Midpoint bipolar offset is specified. -77- GEN05, GEN07 These subroutines are used to construct functions from seg- ments of exponential curves (GEN05) or straight lines (GEN07). ff # time size 5 a n1 b n2 c . . . ff # time size 7 a n1 b n2 c . . . _s_i_z_e - number of points in the table. Must be a power of 2 or power-of-2 plus 1 (see ff statement). _a_, _b_, _c_, etc. - ordinate values, in odd-numbered pfields p5, p7, p9, ... For GEN05 these must be non-zero and must be alike in sign. No such restrictions exist for GEN07. _n_1_, _n_2_, etc. - length of segment (no. of storage locations), in even-numbered pfields. Cannot be negative, but a zero is meaningful for specifying discontinuous waveforms (e.g. in the example below). The sum n1 + n2 + .... will normally equal _s_i_z_e for fully specified functions. If the sum is smaller, the function locations not included will be set to zero; if the sum is greater, only the first _s_i_z_e locations will be stored. Note: If p4 is positive, functions are post-normalized (rescaled to a maximum absolute value of 1 after generation). A nega- tive p4 will cause rescaling to be skipped. Discrete-point linear interpolation implies an increase or decrease along a segment by equal differences between adja- cent locations; exponential interpolation implies that the progression is by equal ratio. In both forms the interpola- tion from _a to _b is such as to assume that the value _b will be attained in the n+1 th location. For discontinuous func- tions, and for the segment encompassing the end location, this value will not actually be reached, although it may eventually appear as a result of final scaling. Example: f 1 0 256 7 0 128 1 0 -1 128 0 This describes a single-cycle sawtooth whose discontinuity is mid-way in the stored function. -78- GEN06 This subroutine will generate a function comprised of seg- ments of cubic polynomials, spanning specified points just three at a time. ff # time size 6 a n1 b n2 c n3 d . . . _s_i_z_e - number of points in the table. Must be a power of 2 or power-of-2 plus 1 (see ff statement). _a_, _c_, _e _._._. - local maxima or minima of successive segments, depending on the relation of these points to adjacent inflexions. May be either positive or negative. _b_, _d_, _f _._._. - ordinate values of points of inflexion at the ends of successive curved segments. May be positive or neg- ative. _n_1_, _n_2_, _n_3 _._._. - number of stored values between specified points. Cannot be negative, but a zero is meaningful for specifying discontinuities. The sum n1 + n2 + ... will nor- mally equal _s_i_z_e for fully specified functions. (for details, see GEN05). Note: GEN06 constructs a stored function from segments of cubic polynomial functions. Segments link ordinate values in groups of 3: point of inflexion, maximum/minimum, point of inflexion. The first complete segment encompasses _b_,_c_,_d and has length _n_2_+_n_3, the next encompasses _d_,_e_,_f and has length _n_4_+_n_5, etc. The first segment (_a_,_b with length _n_1) is par- tial with only one inflexion; the last segment may be par- tial too. Although the inflexion points _b_,_d_,_f_._. each figure in two segments (to the left and right), the slope of the two segments remains independent at that common point (i.e. the 1st derivative will likely be discontinuous). When _a_,_c_,_e_._._. are alternately maximum and minimum, the inflexion joins will be relatively smooth; for successive maxima or successive minima the inflexions will be comb-like. Example: f 1 0 65 6 0 16 .5 16 1 16 0 16 -1 This creates a curve running 0 to 1 to -1, with a minimum, maximum and minimum at these values respectively. Inflex- ions are at .5 and 0, and are relatively smooth. -79- GEN08 This subroutine will generate a piecewise cubic spline curve, the smoothest possible through all specified points. ff # time size 8 a n1 b n2 c n3 d . . . _s_i_z_e - number of points in the table. Must be a power of 2 or power-of-2 plus 1 (see ff statement). _a_, _b_, _c _._._. ordinate values of the function. _n_1_, _n_2_, _n_3 _._._. length of each segment measured in stored values. May not be zero, but may be fractional. A particu- lar segment may or may not actually store any values; stored values will be generated at integral points from the begin- ning of the function. The sum n1 + n2 + ... will normally equal "size" for fully specified functions. Note: GEN08 constructs a stored table from segments of cubic poly- nomial functions. Each segment runs between two specified points but depends as well on their neighbors on each side. Neighboring segments will agree in both value and slope at their common point. (The common slope is that of a parabola through that point and its two neighbors). The slope at the two ends of the function is constrained to be zero (flat). _H_i_n_t_: to make a discontinuity in slope or value in the func- tion as stored, arrange a series of points in the interval between two stored values; likewise for a non-zero boundary slope. Examples: f 1 0 65 8 0 16 0 16 1 16 0 16 0 This example creates a curve with a smooth hump in the mid- dle, going briefly negative outside the hump then flat at its ends. f 2 0 65 8 0 16 0 .1 0 15.9 1 15.9 0 .1 0 16 0 This example is similar, but does not go negative. -80- GEN09, GEN10 These subroutines generate composite waveforms made up of weighted sums of simple sinusoids. The specification of each contributing partial requires 3 pfields using GEN09 but just 1 using GEN10. ff # time size 9 pna stra phsa pnb strb phsb . . . ff # time size 10 str1 str2 str3 str4 . . . . _s_i_z_e - number of points in the table. Must be a power of 2 or power-of-2 plus 1 (see ff statement). _p_n_a_, _p_n_b_, etc. - partial no. (relative to a fundamental that would occupy _s_i_z_e locations per cycle) of sinusoid a, sinu- soid b, etc. Must be positive, but need not be a whole num- ber, i.e., non-harmonic partials are permitted. Partials may be in any order. _s_t_r_a_, _s_t_r_b_, etc. - strength of partials _p_n_a_, _p_n_b_, etc. These are relative strengths, since the composite waveform will be rescaled later. Negative values are permitted and imply a 180 degree phase shift. _p_h_s_a_, _p_h_s_b_, etc. - inital phase of partials _p_n_a_, _p_n_b_, etc., expressed in degrees. _s_t_r_1_, _s_t_r_2_, _s_t_r_3_, etc. - relative strengths of the fixed harmonic partial numbers 1,2,3,etc., beginning in p5. Par- tials not required should be given a strength of zero. Note: Both subroutines generate stored functions as sums of sinu- soids of different frequencies. The two major restrictions on GEN10 -- that the partials be harmonic and in phase -- do not apply to GEN09. In either case the composite wave, once drawn, is then rescaled to unity if p4 was positive. A negative p4 will cause rescaling to be skipped. Example: f 1 0 512 9 1 3 0 3 1 0 9 .3333 180 This combines partials 1, 3 and 9 in the relative strengths with which they are present in a square wave, except that partial 9 is "upside down." -81- GEN11 This subroutine generates an additive set of cosine par- tials, in the manner of csound generators bbuuzzzz and ggbbuuzzzz. ff # time size 11 nh lh r _s_i_z_e - number of points in the table. Must be a power of 2 or power-of-2 plus 1 (see ff statement). _n_h - number of harmonics requested. Must be positive. _l_h (optional) - lowest harmonic partial present. Can be positive, zero or negative. The set of partials can begin at any partial number and proceeds upwards; if _l_h is nega- tive, all partials below zero will reflect in zero to pro- duce positive partials without phase change (since cosine is an even function), and will add constructively to any posi- tive partials in the set. The default value is 1. _r (optional) - multiplier in an amplitude coefficient series. This is a power series: if the _l_hth partial has a strength coefficient of A, the (_l_h+n)th partial will have a coefficient of A * _r**n, i.e. strength values trace an exponential curve. _r may be positive, zero or negative, and is not restricted to integers. The default value is 1. Note: This subroutine is a non-time-varying version of the csound bbuuzzzz and ggbbuuzzzzggeenneerraattoorrss,, aanndd iiss ssiimmiillaarrllyy uusseeffuull aass aa ccoomm-- pplleexx ssoouunndd ssoouurrccee iinn ssuubbttrraaccttiivvee ssyynntthheessiiss.. WWiitthh _l_h and _r present it parallels ggbbuuzzzz; with both absent or equal to 1. it reduces to the simpler bbuuzzzz (i.e. _n_h equal-strength har- monic partials beginning with the fundamental). Sampling the stored waveform with an oscillator is more efficient than using dynamic buzz units. However, the spec- tral content is invariant, and care is necessary lest the higher partials exceed the Nyquist during sampling to pro- duce foldover. Examples: f 1 0 2049 11 4 f 2 0 2049 11 4 1 1 f 3 0 2049 -11 7 3 .5 The first two tables will contain identical band-limited pulse waves of four equal-strength harmonic partials begin- ning with the fundamental. The third table will sum seven -82- consective harmonics, beginning with the third, and at pro- gressively weaker strengths (1, .5, .25, .125 ...). It will not be post-normalized. -83- GEN13, GEN14 These subroutines use Chebyshev coefficients to generate stored polynomial functions which, under waveshaping, can be used to split a sinusoid into harmonic partials having a predefinable spectrum. ff # time size 13 xint xamp h0 h1 h2 . . . hn ff # time size 14 xint xamp h0 h1 h2 . . . hn _s_i_z_e - number of points in the table. Must be a power of 2 or a power-of-2 plus 1 (see ff statement). The normal value is power-of-2 plus 1. _x_i_n_t - provides the left and right values [_-_x_i_n_t_,_+_x_i_n_t] of the _x interval over which the polynomial is to be drawn. These subroutines both call GEN03 to draw their functions; the p5 value here is therefor expanded to a negative-posi- tive p5,p6 pair before GEN03 is actually called. The normal value is 1. _x_a_m_p - amplitude scaling factor of the sinusoid input that is expected to produce the following spectrum. _h_0_, _h_1_, _h_2_, _._._._. _h_n - relative strength of partials 0 (DC), 1 (fundamental), 2 ... that will result when a sinusoid of amplitude _x_a_m_p _* _i_n_t_(_s_i_z_e_/_2_)_/_x_i_n_t is waveshaped using this function table. These values thus describe a frequency spectrum associated with a particular factor _x_a_m_p of the input signal. Note: GEN13 is the function generator normally employed in stan- dard waveshaping. It stores a polynomial whose coefficients derive from the Chebyshev polynomials of the first kind, so that a driving sinusoid of strength xamp will exhibit the specified spectrum at output. Note that the evolution of this spectrum is generally not linear with varying xamp. However, it is bandlimited (the only partials to appear will be those specified at generation time); and the partials will tend to occur and to develop in ascending order (the lower partials dominating at low xamp, and the spectral richness increasing for higher values of xamp). A negative hn value implies a 180 degree phase shift of that partial; the requested full-amplitude spectrum will not be affected by this shift, although the evolution of several of its com- ponent partials may be. The pattern +,+,-,-,+,+, ... for _h_0_,_h_1_,_h_2_._._. will minimize the normalization problem for low _x_a_m_p values (see above), but does not necessarily provide the smoothest pattern of evolution. GEN14 stores a polynomial whose coefficients derive from -84- Chebyshevs of the second kind. Example: f 1 0 1025 13 1 1 0 5 0 3 0 1 This creates a function which, under waveshaping, will split a sinusoid into 3 odd-harmonic partials of relative strength 5:3:1. -85- GEN15 This subroutine creates two tables of stored polynomial functions, suitable for use in phase quadrature operations. ff # time size 15 xint xamp h0 phs0 h1 phs1 h2 phs2 . . _s_i_z_e - number of points in the table. Must be a power of 2 or a power-of-2 plus 1 (see ff statement). The normal value is power-of-2 plus 1. _x_i_n_t - provides the left and right values [_-_x_i_n_t_,_+_x_i_n_t] of the _x interval over which the polynomial is to be drawn. This subroutine will eventually call GEN03 to draw both functions; this p5 value is therefor expanded to a negative- positive p5,p6 pair before GEN03 is actually called. The normal value is 1. _x_a_m_p - amplitude scaling factor of the sinusoid input that is expected to produce the following spectrum. _h_0_, _h_1_, _h_2_, _._._._. _h_n - relative strength of partials 0 (DC), 1 (fundamental), 2 ... that will result when a sinusoid of amplitude _x_a_m_p _* _i_n_t_(_s_i_z_e_/_2_)_/_x_i_n_t is waveshaped using this function table. These values thus describe a frequency spectrum associated with a particular factor _x_a_m_p of the input signal. _p_h_s_0_, _p_h_s_1_, ... - phase in degrees of desired harmonics _h_0_, _h_1_, _._._. when the two functions of GEN15 are used with phase quadrature. Note: GEN15 creates two tables of equal size, labelled ff _# and ff _#_+_1_. Table _# will contain a Chebyshev function of the first kind, drawn using GEN13 with partial strengths _h_0_c_o_s_(_p_h_s_0_)_, _h_1_c_o_s_(_p_h_s_1_)_, _._._. Table _#_+_1 will contain a Chebyshev func- tion of the 2nd kind by calling GEN14 with partials _h_1_s_i_n_(_p_h_s_1_)_, _h_2_s_i_n_(_p_h_s_2_)_, _._._. (note the harmonic displace- ment). The two tables can be used in conjunction in a wave- shaping network that exploits phase quadrature. -86- 55.. CCSSCCOORREE CCssccoorree is a program for generating and manipulating numeric score files. It comprises a number of _f_u_n_c_t_i_o_n sub- programs, called into operation by a user-written _m_a_i_n pro- gram. The _f_u_n_c_t_i_o_n programs augment the CC language library functions; they can optionally read _s_t_a_n_d_a_r_d _n_u_m_e_r_i_c score files, can massage and expand the data in various ways, then write the data out as a new score file to be read by a CCssoouunndd orchestra. The user-written _m_a_i_n program is also in CC. It is not essential to know the CC language well to write a main pro- gram, since the function calls have a simple syntax, and are powerful enough to do most of the complicated work. Addi- tional power can come from CC later as the need arises. EEvveennttss,, LLiissttss,, aanndd OOppeerraattiioonnss An _e_v_e_n_t in CCssccoorree is equivalent to one statement of a _s_t_a_n_d_a_r_d _n_u_m_e_r_i_c _s_c_o_r_e. It is either created or read in from an existing score file. An event is comprised of an _o_p_c_o_d_e and an array of _p_f_i_e_l_d values stored somewhere in memory. Storage is organized by the following structure: struct event { char op; /* opcode */ char tnum; short pcnt; float p[PMAX+1]; /* pfields */ }; Any function subprogram that creates, reads, or copies an event function will return a _p_o_i_n_t_e_r to the storage struc- ture holding the event data. The event pointer can be used to access any component of the structure, in the form of _e_-_>_o_p or _e_-_>_p_[_n_]. Each newly stored event will give rise to a new pointer, and a sequence of new events will generate a sequence of distinct pointers that must themselves be stored away. Groups of event pointers are stored in a _l_i_s_t, which has its own structure: struct evlist { int nslots; /* size of this list */ struct event *e[1]; /* list of event pointers */ }; Any function that creates or modifies a _l_i_s_t will return a _p_o_i_n_t_e_r to the new list. The list pointer can be used to access any of its component event pointers, in the form of _a_-_>_e_[_n_]. Event pointers and list pointers are thus primary tools for manipulating the data of a score file. _P_o_i_n_t_e_r_s and _l_i_s_t_s _o_f _p_o_i_n_t_e_r_s can be copied and reordered without modifying the data values they refer to. -87- This means that notes and phrases can be copied and manipu- lated from a high level of control. Alternatively, the data within an _e_v_e_n_t or _g_r_o_u_p _o_f _e_v_e_n_t_s can be modified without changing the event or list pointers. CCssccoorree provides a library of programming _m_e_t_h_o_d_s or _f_u_n_c_t_i_o_n _s_u_b_p_r_o_g_r_a_m_s by which scores can be created and manipulated in this way. In the following summary of CCssccoorree function calls, some simple naming conventions are used: the symbols _e_, _f are pointers to events (notes); the symbols _a_, _b are pointers to lists(arrays) of such events; the letters _e_v at the end of a function name signify operation on an _e_v_e_n_t; the letter _l at the start of a function name signifies operation on a _l_i_s_t. calling syntax description e = createv(n); create a blank event with n pfields e = defev("..."); defines an event as per the character string ... e = copyev(f); make a new copy of event f e = getev(); read the next event in the score input file putev(e); write event e to the score output file putstr("..."); write the character string ... to score output a = lcreat(n); create an empty event list with n slots a = lappev(a,e); append event e to list a n = lcount(a); count the events now in list a a = lcopy(b); copy the list b (but not the events) a = lcopyev(b); copy the events of b, making a new list a = lget(); read events from score input (to next s or e) lput(a); write the events of list a to score output a = lsepf(b); separate the f statements from list b into list a a = lcat(a,b); concatenate (append) the list b onto the list a lsort(a); sort the list a into chronological order by p[2] a = lxins(b,"..."); extract notes of instruments ... (no new events) a = lxtimev(b,from,to); extract notes of time-span, creating new events relev(e); release the space of event e lrel(a); release the space of list a (but not events) lrelev(a); release the events of list a, and the list space WWrriittiinngg aa MMaaiinn pprrooggrraamm.. The general format for a main program is: #include main() { /* VARIABLE DECLARATIONS */ /* PROGRAM BODY */ } The _i_n_c_l_u_d_e statement will define the event and list struc- tures for the program. The following C program will read from a standard numeric score, up to (but not including) the first ss or ee statement, then write that data (unaltered) as -88- output. #include main() { struct evlist *a; /* a is allowed to point to an event _l_i_s_t */ a = lget(); /* read events in, return the list pointer */ lput(a); /* write these events out (unchanged) */ putstr("e"); /* write the string e to output */ } After execution of _l_g_e_t_(_), 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 (_l_p_u_t) to access and write out all of the events that were read. If we now define another symbol _e to be an _e_v_e_n_t pointer, then the statement e = a->e[4]; will set it to the _c_o_n_t_e_n_t_s of the 4th slot in the evlist structure. The contents is a pointer to an event, which is itself comprised of an array of parameter field values. Thus the term e->p[5] will mean the value of parameter field 5 of the 4th event in the evlist denoted by _a_. The program below will multiply the value of that pfield by 2 before writing it out. #include main() { struct event *e; /* a pointer to an event */ struct 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 and multiply its value by 2 */ lput(a); /* write out the list of events */ putstr("e"); /* add a "score end" statement */ } Now consider the following score, in which p[5] contains frequency in cps. 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 If this score were given to the preceding main program, the resulting output would look like this: 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 Note that the 4th event is in fact the second note of the -89- 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 _4_t_h event has been stored in e[4] of the structure. For compatibility with CCssoouunndd pfield notation, we will ignore p[0] and e[0] of the event and list structures, storing p1 in p[1], event 1 in e[1], etc. The CCssccoorree functions all adopt this convention. As an extension to the above, we could decide to use _a and _e 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 p5 of the previous listed event we need only redefine _e with the assignment e = a->e[3]; More generally, if we declare a new variable _f to be a _p_o_i_n_t_e_r _t_o _a _p_o_i_n_t_e_r to an event, the statement f = &a->e[4]; will set _f to the address of the fourth event in the event list _a_, and _*_f will signify the _c_o_n_t_e_n_t_s of the slot, namely the event pointer itself. The expression (*f)->p[5], like e->p[5], signifies the fifth pfield of the selected event. However, we can advance to the next slot in the evlist by advancing the pointer _f. In C this is denoted by _f_+_+_. In the following program we will use the same input score. This time we will separate the ftable statements from the note statements. We will next write the three note- events stored in the list _a, then create a second score sec- tion consisting of the original pitch set and a transposed version of itself. This will bring about an octave dou- bling. By pointing the variable _f to the first note-event and incrementing _f inside a wwhhiillee block which iterates n times (the number of events in the list), one statement can be made to act upon the same pfield of each successive event. #include main() { struct event *e,**f; /* declarations. see pp.8-9 in the */ struct evlist *a,*b; /* C language programming manual */ int n; a = lget(); /* read score into event list "a" */ b = lsepf(a); /* separate f statements */ lput(b); /* write f statements out to score */ lrelev(b); /* and release the spaces used */ e = defev("t 0 120"); /* define event for tempo statement */ putev(e); /* write tempo statement to score */ lput(a); /* write the notes */ putstr("s"); /* section end */ putev(e); /* write tempo statement again */ -90- b = lcopyev(a); /* make a copy of the notes in "a" */ n = lcount(b); /* and count the number copied */ f = &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("e"); } The output of this program is: 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 Next we extend the above program by using the wwhhiillee statement to look at p[5] and p[6]. In the original score p[6] denotes amplitude. To create a diminuendo in the added lower octave, which is independent from the original set of notes, a variable called _d_i_m will be used. #include main() { struct event *e,**f; struct evlist *a,*b; int n, dim; /* declare new variable as integer */ a = lget(); b = lsepf(a); lput(b); lrelev(b); e = defev("t 0 120"); putev(e); lput(a); putstr("s"); putev(e); /* write out another tempo statement */ b = lcopyev(a); n = lcount(b); dim = 0; /* initialize dim to 0 */ f = &a->e[1]; while (n--){ (*f)->p[6] -= dim; /* subtract current value of dim */ (*f++)->p[5] *= .5; /* transpose, move f to next event */ -91- dim += 2000; /* increase dim for each note */ } a = lcat(b,a); lput(a); putstr("e"); } The increment of _f in the above programs has depended on certain precedence rules of CC.. Although this keeps the code tight, the practice can be dangerous for beginners. Incrementing may alternately be written as a separate state- ment to make it more clear. while (n--){ (*f)->p[6] -= dim; (*f)->p[5] *= .5; dim += 2000; f++; } Using the same input score again, the output from this pro- gram is: 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 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 array _c_u_e. This time the dim. will occur for each group of notes rather than each note. Note the position of the statement which increments the variable _d_i_m outside the inner wwhhiillee block. #include int cue[3]={0,10,17}; /* declare array of 3 integers */ main() { struct event *e, **f; struct evlist *a, *b; int n, dim, cuecount, holdn; /* declare new variables */ a = lget(); -92- b = lsepf(a); lput(b); lrelev(b); e = defev("t 0 120"); putev(e); n = lcount(a); holdn = n; /* hold the value of "n" to reset below */ cuecount = 0; /* initilize cuecount to "0" */ dim = 0; while (cuecount <= 2) { /* count 3 iterations of inner "while" */ f = &a->e[1]; /* reset pointer to first event of list "a" */ n = holdn; /* reset value of "n" to original note count */ while (n--) { (*f)->p[6] -= dim; (*f)->p[2] += cue[cuecount]; /* add values of cue */ f++; } printf("%s %d0, "; diagnostic: cue=", cue[cuecount]); cuecount++; dim += 2000; lput(a); } putstr("e"); } Here the inner wwhhiillee block looks at the events of list _a (the notes) and the outer wwhhiillee block looks at each repe- tition of the events of list _a (the pitch group repeti- tions). This program also demonstrates a useful trouble- shooting device with the pprriinnttff function. The semi-colon is first in the character string to produce a comment statement in the resulting score file. In this case the value of _c_u_e is being printed in the output to insure that the program is taking the proper array member at the proper time. When out- put data is wrong or error messages are encountered, the pprriinnttff function can help to pinpoint the problem. Using the identical input file, the C program above will generate: 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 -93- ; 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 Further development of these scores will lead the com- poser to techniques of score manipulation which are similar to serial techniques of composition. Pitch sets may be altered with regard to any of the parameter fields. The programing allows for transpositions, time warping, pitch retrograding and dynamic controls, to name a few. CCoommppiilliinngg aa CCssccoorree pprrooggrraamm A CCssccoorree program named _e_x_a_m_p_l_e_._c can be compiled and linked with its library modules by the command: $ cc example.c -lcscore The resulting executable file is called "a.out". It is run by typing: $ a.out (no input, output printed on the screen) $ a.out < scorin (input score named _s_c_o_r_i_n, output on screen) $ a.out < scorin > scorout (input as above, output into a file) -94- 66.. SSCCOOTT:: AA SSccoorree TTrraannssllaattoorr SSccoott is a language for describing scores in a fashion that parallels traditional music notation. Scot is also the name of a program which translates scores written in this language into _s_t_a_n_d_a_r_d _n_u_m_e_r_i_c _s_c_o_r_e format so that the score can be performed by CCssoouunndd.. The result of this trans- lation is placed in a file called _s_c_o_r_e_. A score file writ- ten in Scot (named _f_i_l_e_._s_c_, say) can be sent through the translator by the command scot file.sc The resulting numeric score can then be examined for errors, edited, or performed by typing perf file.orc score Alternatively, the command perf file.orc -s file.sc would combine both processes by informing ppeerrff of the ini- tial score format. Internally, a Scot score has at least three parts: a section to define instrument names, a section to define functions, and one or more actual score sections. It is generally advisable to keep your score sections short to facilitate finding errors. The overall layout of a Scot score has three main sections: orchestra { .... } functions { .... } score { .... } The last two sections may be repeated as many times as desired. The functions section is also optional. Through- out this SSccoott document, bear in mind that you are free to break up each of these divisions into as many lines as seem convenient, or to place a carriage return anywhere you are allowed to insert a space, including before and after the curly brackets. Furthermore, you may use as many spaces or tabs as you need to make the score easy to read. Scot imposes no formatting restrictions except that numbers, instrument names, and keywords (for example, _o_r_c_h_e_s_t_r_a ) may not be broken with spaces. You may insert comments (such as measure numbers) anywhere in the score by preceding them with a semicolon. A semicolon causes Scot to ignore the rest of a line. OOrrcchheessttrraa DDeeccllaarraattiioonn SSeeccttiioonn The orchestra section of a SSccoott score serves to desig- nate instrument names for use within the score. This is a matter of convenience, since an orchestra knows instruments only by numbers, not names. If you declare three instru- ments, such as: orchestra { flute=1 cello=2 trumpet=3 } CCssoouunndd will neither know nor care what you have named the note lists. However, when you use the name _$_f_l_u_t_e_, Scot will know you are referring to iinnssttrr 11 in the orchestra, -95- _$_c_e_l_l_o will refer to iinnssttrr 22, and _$_t_r_u_m_p_e_t will be iinnssttrr 33. You may meaningfully skip numbers or give several instru- ments the same number. It is up to you to make sure that your orchestra has the correct instruments and that the association between these names and the instruments is what you intend. There is no limit (or a very high one, at least) as to how many instruments you can declare. FFuunnccttiioonn DDeeccllaarraattiioonn SSeeccttiioonn The major purpose of this division is to allow you to declare function tables for waveforms, envelopes, etc. These functions are declared exactly as specified for CCssoouunndd.. In fact, everything you type between the brackets in this section will be passed directly to the resulting _n_u_m_e_r_i_c score with no modification, so that mistakes will not be caught by the Scot program, but rather by the subse- quent performance. You can use this section to write notes for instruments for which traditional pitch-rhythm notation is inappropriate. The most common example would be turning on a reverb instrument. Instruments referenced in this way need not appear in the Scot orchestra declaration. Here is a possible function declaration: functions { f1 0 256 10 1 0 .5 0 .3 f2 0 256 7 0 64 1 64 .7 64 0 i9 0 -1 3 ; this turns on instr 9 } SSccoorree SSeeccttiioonn The Scot statements contained inside the braces of each score statement is translated into a numeric score Section (q.v.). It is wise to keep score sections small, say seven or eight measures of five voices at a time. This avoids overloading the system, and simplifies error checking. The beginning of the score section is specified by typ- ing: score { Everything which follows this until the braces are closed is within a single section. Within this section you write mea- sures of notes in traditional pitch and rhythm notation for any of the instrument names listed in your orchestra decla- ration. These notes may carry additional information such as slurs, ties and parameter fields. Let us now consider the format for notes entered in a Scot score. The first thing to do is name the instrument you want and the desired meter. For example, to write some 4/4 mea- sures for the cello, type: $cello !ti "4/4" The dollar sign and exclamation point tell Scot that a -96- special declarator follows. The time signature declarator is optional; if present, Scot will check the number of beats in each measure for you. PPiittcchh aanndd RRhhyytthhmm The two basic components of a note statement are the pitch and duration. Pitch is specified using the alphabetic note name, and duration is specified using numeric charac- ters. Duration is indicated at the beginning of the note as a number representing the division of a whole beat. You may always find the number specifying a given duration by think- ing of how many times that duration would fit in a 4/4 mea- sure. Also, if the duration is followed by a dot (`.') it is increased by 50%, exactly as in traditional notation. Some sample durations are listed below: whole note 1 half note 2 double dotted quarter 4.. dotted quarter note 4. quarter note 4 half note triplet 6 eighth note 8 eighth note triplet 12 sixteenth note 16 thirty-second note 32 Pitch is indicated next by first (optionally) specify- ing the register and then the note name, followed by an accidental if desired. Normally, the "octave following" feature is in effect. This feature causes any note named to lie within the interval of an augmented fourth of the previ- ous note, unless a new register is chosen. The first note you write will always be within a fourth of middle c unless you choose a different register. For example, if the first note of an instrument part is notated g flat, the scot program assigns the pitch corre- sponding to the g flat below middle c. On the other hand, if the first note is f sharp, the pitch assigned will be the f sharp above middle c. Changes of register are indicated by a preceding apostrophe for each octave displacement upward or a preceding comma for each octave displacement downward. Commas and apostrophes always displace the pitch by the desired number of octaves starting from that note which is within an augmented fourth of the previous pitch. If you ever get lost, prefacing the pitch specification with an `=' returns the reference to middle c . It is usu- ally wise to use the equals sign in your first note state- ment and whenever you feel uncertain as to what the current registration is. Let us now write two measures for the cello part, the first starting in the octave below middle c and the second repeating but starting in the octave above -97- middle c: $cello !ti "4/4" 4=g 4e 4d 4c/ 4='g 4e 4d 4c As you can see, a slash indicates a new measure and we have chosen to use the dummy middle c to indicate the new regis- ter. A more convenient way of notating these two measures would be to type the following: $cello !ti "4/4" 4=g e d c/ ''g e d c You may observe in this example that the quarter note dura- tion carries to the following notes when the following dura- tions are left unspecified. Also, two apostrophes indicate an upward pitch displacement of two octaves from two g's below middle c, where the pitch would have fallen without any modification. It is important to remember three things, then, when specifying pitches: 1) Note pitches specified by letter name only (with or without accidental) will always fall within an interval of a fourth from the preceding pitch. 2) These pitches can be octave displaced upward or downward by preceding the note letter with the desired number of apostrophes or commas. 3) If you are unsure of the current register, you may begin the pitch component of the note with an equals sign which acts as a dummy middle c. The pitch may be modified by an accidental after the note name: n natural # sharp - (hyphen) flat ## double sharp -- (double hyphen) double flat Accidentals are carried throughout the measure just as in traditional music notation. However, an accidental speci- fied within a measure will hold for that note in all regis- ters, in contrast with traditional notation. Therefore, make sure to specify _n when you no longer want an accidental applied to that pitch-class. Pitches entered in the Scot score are translated into the appropriate octave point pitch-class value and appear as parameter p5 in the numeric score output. This means you must design your instruments to accept p5 as pitch. Rests are notated just like notes but using the letter _r instead of a pitch name. _4_r therefore indicates a quarter rest and _1_r a whole rest. Durations carry from rest to rest or to following pitches as mentioned above. -98- The tempo in beats per minute is specified in each sec- tion by choosing a single instrument part and using tempo statements (e.g. t90) at the various points in the score as needed. A quarter note is interpreted as a single beat, and tempi are interpolated between the intervening beats (see CCssoouunndd tteemmppoo)).. SSccoott EExxaammppllee II ; A BASIC Tune orchestra { guitar=1 bass=2 } functions { f1 0 512 10 1 .5 .25 .126 f2 0 256 7 1 120 1 8 0 128 1 } score { ;section 1 $guitar !ti "4/4" 4=c 8d e- f r 4='c/ 8.b- 16a a- g g- f 4e- c/ $bass 2=,,c 'a-/ g =,c/ } score { ;section 2 $guitar !ti "4/4" 6='c r c 4..c## 16e- / 6f r f 4..f## 16b / $bass 4=,,c 'g ,c 'g/ 2=a- g / } The score resulting from this Scot notation is shown at the end of this chapter. -99- GGrroouuppeetttteess Duration numbers can have any integral value; for instance, !time "4/4" 5cdefg/ would encode a measure of _5 _i_n _t_h_e _t_i_m_e _o_f _4 quarter notes. However, specification of arbitrary rhythmic groupings in this way is at best awkward. Instead, arbitrary portions of the score section may be enclosed in _g_r_o_u_p_e_t_t_e _b_r_a_c_k_e_t_s_. The durations of all notes inside groupette brackets will be multiplied by a fraction _n_/_d_, where the musical meaning is _d in the time of _n_. Assuming _d and _n here are integers, groupette brackets may take these several forms: {d:n: ..... :} d in the time of n {d:: ..... :} n will be the largest power of 2 less than d {: ..... :} d=3, n=2 (normal triplets) It can be seen that the second and third form are abbrevia- tions for the more common kinds of groupettes. (Observe the punctuation of each form carefully.) Groupettes may be nested to a reasonable depth. Also, groupette factors apply only after the written duration is carried from note to note. Thus, the following example is a correct specifica- tion for two measures of 6/8 time: !time "6/8" 8cde {4:3: fgab :} / crc 4.c / The notes inside the groupette are _4 _i_n _t_h_e _s_p_a_c_e _o_f _3 8th notes, and the written-8th-note duration carries normally into the next measure. This closely parallels the way groupette brackets and note durations interact in standard notation. SSlluurrss aanndd TTiieess Now that you understand part writing in the Scot lan- guage, we can start discussing more elaborate features. Immediately following the pitch specification of each note, one may indicate a slur or a tie into the next note (assum- ing there is one), but not both simultaneously. The slur is typed as a single underscore (`_') and a tie as a double underscore (`__'). Despite the surface similarity, there is a substantial difference in the effect of these modifiers. For purposes of Scot, tied notes are notes which, although comprised of several graphic symbols, represent only a single musical event. (Tied notes are necessary in standard music notation for several reasons, the most common being notes which span a measure line and notes with dura- tions not specifiable with a single symbol, such as quarter note tied to a sixteenth.) Notes which are tied together are summed by duration and output by Scot as a single event. This means you cannot, for example, change the parameters of a note in the middle of a tie (see below). Two or more notes may be tied together, as in the following example, -100- which plays an f# for eleven beats: !ti "4/4" 1 f#__ / 1 f#__ / 2. f# 4r / By contrast, slurred notes are treated as distinct notes at the CCssoouunndd level, and may be of arbitrary pitch. The pres- ence of a slur is reflected in parameter p4, but the slur has no other meaning beyond the interpretation of p4 by your instrument. Since instrument design is beyond the scope of this manual, it will suffice for now to explain that the Scot program gives sets p4 to one of four values depending on the existence of a slur before and after the note in question. This means Scot pays attention not only to the slur attached to a given note, but whether the preceding note specified a slur. The four possibilities are as fol- lows, where the p4 values are taken to apply to the note `d': 4c d (no slur) p4 = 0 4c d_ (slur after only) p4 = 1 4c_ d (slur before only) p4 = 2 4c_ d_ (before & after) p4 = 3 PPaarraammeetteerrss The information contained in the Scot score notation we have considered so far is manifested in the output score in parameters p1 through p5 in the following way: p1: instrument number p2: initialization time of instrument p3: duration p4: slur information p5: pitch information in octave point pitch-class notation Any additional parameters you may want to enter are listed in brackets as the last part of a note specification. These parameters start with p6 and are separated from each other with spaces. Any parameters not specified for a particular note have their value carried from the most recently speci- fied value. You may choose to change some parameters and not others, in which case you can type a dot (`.') for parameters whose values don't change, and new values for those that do. Alternatively, the construction _N_:_, where _N is an integer, may be used to indicate that the following parameter specifications apply to successive parameters starting with parameter _N_. For example: 4e[15000 3 4 12:100 150] g_ d_[10000 . 5] c Here, for the first two quarter notes p6, p7, p8, p12, and p13 respectively assume the values 15000, 3, 4, 100, and 150. The values of p9 through p11 are either unchanged, or implicitly zero if they have never been specified in the current section. On the third quarter note, the value of p6 is changed to 10000, and the value of p8 is changed to 5. All others are unchanged. Normally, parameter values are treated as globals -- that is, a value specification will carry to successive -101- notes if no new value is specified. However, if a parameter specification begins with an apostrophe, the value applies locally to the current note only, and will not carry to suc- cessive notes either horizontally or vertically (see _d_i_v_i_s_i below). PPffiieelldd MMaaccrrooss Scot has a macro text substitution facility which oper- ates only on the pfield specification text within brackets. It allows control values to be specified symbolically rather than numerically. Macro definitions appear inside brackets in the orchestra section. A single bracketed list of macro definitions preceding the first instrument declaration defines macros which apply to all instruments. An addi- tional bracketed list of definitions may follow each instru- ment to specify macros that apply to that particular instru- ment. orchestra { [ pp=2000 p=4000 mp=7000 mf=10000 f=20000 ff=30000 modi = 11: w = 1 x = 2 y = 3 z = 4 vib = "10:1 " novib = "10:0 1" ] violin = 1 [ pizz = " 20:1" arco = " 20:0" ] serpent = 3 [ ff = 25000 sfz = 'f sffz = 'ff] } score { $violin =4c[mf modi z.y novib] d e a['f vib3] / 8 b[pizz]c 4d[f] 2c[ff arco] / $serpent =,4.c[mp modi y.x] 8b 2c / 'g[f ] ,c[ff] / } As can be seen from this example, a macro definition con- sists of the macro name, which is a string of alphabetic characters, followed by an equal sign, followed by the macro value. As usual, spaces, tabs, and newlines may be used freely. The macro value may contain arbitrary characters, and may be quoted if spacing characters need to be included. When a macro name is encountered in bracketed pfield lists in a score section, that name is replaced with the macro text with no additional punctuation supplied. The macro text may itself invoke other macros, although it is a serious error for a macro to contain itself, directly or indirectly. Since macro names are identified as strings of alphabetic characters, and no additional spaces are provided when a macro is expanded, macros may easily perform such concatenations as found in the first serpent note above, where the integer and fractional parts of a single pfield are constructed. Also, a macro may do no more than define a symbolic pfield, as in the definition of modi. The primary intention of macros is in fact not only to reduce the number of characters required, but also to enable symbolic defini- tions of parameter numbers and parameter values. For -102- instance, a particular instrument's interpretation of the dynamic _f_f can be changed merely by changing a macro value, rather than changing all occurrences of that particular value in the score. DDiivviissii Notes may be stacked on top of each other by using a back arrow (`<') between the notes of the divisi. Each time Scot encounters a back arrow, it understands that the fol- lowing note is to start at the same time as the note to the left of the back arrow. Durations, accidentals and parame- ters carry from left to right through the divisi. Each time these are given new values, the notes to the right of the back arrows also take on the new values unless they are specified again. When writing divisi you can stack compound events by enclosing them in parentheses. Also, divisi which occur at the end of the measure must have the proper durations or the scot program will mis-interpret the measure duration length. SSccoott EExxaammppllee IIII orchestra { right=1 left=2 } functions { f1 0 256 10 1} score { $right !key "-b" ; since p5 is pitch, p7 is set to the pitch of next note !ti "2/4" !next p5 "p7" ;since p5 is pitch, p7 refers to pitch of next note !next p6 "p8" ;If p6 is vol, say, then p8 refers to vol of next note t90 8r c[3 np5] outfile will put a numeric score _i_n_f_i_l_e through Carry, Tempo, and Sort preprocessing, leaving the result in _o_u_t_f_i_l_e_. Likewise eexxttrraacctt,, also normally invoked as part of the ppeerrff command, can be invoked as a standalone program: extract xfile < score.sort > score.extract This command expects an already sorted score. An unsorted score should first be sent through _s_c_s_o_r_t then piped to the extract program: scsort < scorefile | extract xfile > score.extract -112- AAppppeennddiixx 11.. AAnn OOrrcchheessttrraa QQUUIICCKK RREEFFEERREENNCCEE VALUE CONVERTERS ffttlleenn(x) (init-rate args only) iinntt(x) (init- or control-rate args only) ffrraacc(x) " " ddbbaammpp(x) " " ii(x) (control-rate args only) aabbss(x) (no rate restriction) eexxpp(x) " " lloogg(x) " " ssqqrrtt(x) " " ssiinn(x) " " ccooss(x) " " aammppddbb(x) " " PITCH CONVERTERS ooccttppcchh(pch) (init- or control-rate args only) ppcchhoocctt(oct) " " ccppssppcchh(pch) " " ooccttccppss(cps) " " ccppssoocctt(oct) (no rate restriction) PROGRAM CONTROL iiggoottoo label ttiiggoottoo label kkggoottoo label ggoottoo label iiff ia R ib iiggoottoo label iiff ka R kb kkggoottoo label iiff ia R ib ggoottoo label ttiimmoouutt istrt, idur, label SIGNAL GENERATORS kr lliinnee ia, idur1, ib ar lliinnee ia, idur1, ib kr eexxppoonn ia, idur1, ib ar eexxppoonn ia, idur1, ib kr lliinnsseegg ia, idur1, ib[, idur2, ic[...]] ar lliinnsseegg ia, idur1, ib[, idur2, ic[...]] kr eexxppsseegg ia, idur1, ib[, idur2, ic[...]] ar eexxppsseegg ia, idur1, ib[, idur2, ic[...]] kr pphhaassoorr kcps[, iphs] ar pphhaassoorr xcps[, iphs] ir ttaabbllee indx, ifn[, ixmode][, ixoff][, iwrap] ir ttaabblleeii indx, ifn[, ixmode][, ixoff][, iwrap] -113- kr ttaabbllee kndx, ifn[, ixmode][, ixoff][, iwrap] kr ttaabblleeii kndx, ifn[, ixmode][, ixoff][, iwrap] ar ttaabbllee andx, ifn[, ixmode][, ixoff][, iwrap] ar ttaabblleeii andx, ifn[, ixmode][, ixoff][, iwrap] kr oosscciill11 idel, kamp, idur, ifn kr oosscciill11ii idel, kamp, idur, ifn kr oosscciill kamp, kcps, ifn[, iphs] kr oosscciillii kamp, kcps, ifn[, iphs] ar oosscciill xamp, xcps, ifn[, iphs] ar oosscciillii xamp, xcps, ifn[, iphs] ar ffoosscciill xamp, kcps, kcar, kmod, kndx, ifn[, iphs] ar ffoosscciillii xamp, kcps, kcar, kmod, kndx, ifn[, iphs] ar bbuuzzzz xamp, xcps, knh, ifn[, iphs] ar ggbbuuzzzz xamp, xcps, knh, klh, kr, ifn[, iphs] ar aaddssyynn kamod, kfmod, ifilno ar ppvvoocc ktimpnt, ifmod, ifilno ar ffooff kamp, kcps, knh, ifn[, iphs] ar pplluucckk kamp, kcps, icps, ifn, imeth [, iparm1, iparm2] kr rraanndd xamp[, iseed] kr rraannddhh kamp, kcps[, iseed] kr rraannddii kamp, kcps[, iseed] ar rraanndd xamp[, iseed] ar rraannddhh xamp, xcps[, iseed] ar rraannddii xamp, xcps[, iseed] SIGNAL MODIFIERS kr lliinneenn kamp, irise, idur, idec ar lliinneenn xamp, irise, idur, idec kr eennvvllppxx kamp, irise, idur, idec, ifn, iatss, iatdec[, ixmod] ar eennvvllppxx xamp, irise, idur, idec, ifn, iatss, iatdec[, ixmod] kr ppoorrtt ksig, ihtim[, isig] ar ttoonnee asig, khp[, istor] ar aattoonnee asig, khp[, istor] ar rreessoonn asig, kcf, kbw[, iscl, istor] ar aarreessoonn asig, kcf, kbw[, iscl, istor] krmsr,krmso,kerr,kcps llpprreeaadd ktimpnt, ifilno[, inpoles][, ifrmrate] ar llpprreessoonn asig ar llppffrreessoonn asig, kfrqratio kr rrmmss asig[, ihp, istor] ar ggaaiinn asig, krms[, ihp, istor] ar bbaallaannccee asig, acomp[, ihp, istor] kr ddoowwnnssaammpp asig[, iwlen] ar uuppssaammpp ksig -114- ar iinntteerrpp ksig[, istor] kr iinntteegg ksig[, istor] ar iinntteegg asig[, istor] kr ddiiffff ksig[, istor] ar ddiiffff asig[, istor] kr ssaammpphhoolldd xsig, kgate[, ival, ivstor] ar ssaammpphhoolldd asig, xgate[, ival, ivstor] ar ddeellaayyrr idlt[, istor] ddeellaayyww asig ar ddeellaayy asig, idlt[, istor] ar ddeellaayy11 asig[, istor] ar ddeellttaapp kdlt ar ddeellttaappii xdlt ar ccoommbb asig, krvt, ilpt[, istor] ar aallppaassss asig, krvt, ilpt[, istor] ar rreevveerrbb asig, krvt[, istor] SIGNAL DISPLAY pprriinntt iarg[, iarg, ...] ddiissppllaayy xsig, iprd ddssppddfftt asig, iprd, iwsiz[, iwtyp][, idbout] ddssppfffftt asig, iprd, iwsiz[, iwtyp][, idbout] SOUNDFILE INPUT & OUTPUT a1, a2, a3, a4 ppaann asig, kx, ky, ifn[, imode][, ioffset] a1 ssoouunnddiinn ifilno[, iskptim] a1, a2 ssoouunnddiinn ifilno[, iskptim] a1, a2, a3, a4 ssoouunnddiinn ifilno[, iskptim] oouutt asig oouuttss11 asig oouuttss22 asig oouuttss asig1, asig2 oouuttqq11 asig oouuttqq22 asig oouuttqq33 asig oouuttqq44 asig oouuttqq asig1, asig2, asig3, asig4 -115-