Samples is a program I wrote to take a text file, process
it, and produce a Csound input file ready for processing. The purpose
of the program is to allow the composer to think in terms of notes, tuning
systems, timbres, and other musical ideas, and not about digital signal
processing. The best way to illustrate is to show an example. The following
is a typical input file and the resulting output of the program. If none
of this makes sense, then there might be a better place to start. A tutorial
would help. If I write it, you will be the first to know. . .
The input file was read by the samples.pas program, interpreted, and
written out as an input file that Csound understands.
The Csound code that is created is a sample-based instrument. It assumes
that each note in the Csound score will include some key parameters, like
instrument number (always 1), start time, duration, volume, tone in scale
(I use Partch's 43 tone
scale), octave, stereo placement, envelope (choose from 0 to 1 in
this case, which correspond to f tables #298 and #297), glissando (only
one is in this score, as expressed in f table #301), and up-sample (which
is my term for picking an instrument sample that is some number of samples
up or down from the one that was originally planned for this note).
The program translates note events into Csound score instrument note
events. Note events in the input file are specified by variables with
command names and values. The command names specify such things as note
number, octave, velocity. Values are carried from one note to the next
automatically.
There are command letters, that trigger the program to do something special.
The most important are listed here:
l
Literal. Strip off the letter "L" and send the rest directly
to the output file. This is useful for comments that you would like
to appear in the output, or for actual Csound code that does not need
alteration. Notice that nothing really happens to these lines. They
are just moved to the output as is.
@ Comment. Anything
after the @ is ignored
. Period. This is the macro facility. All the text after the period
up to the first blank is the macro name. Anything after the period is
the macro contents. The first macro in this score is ".C t0".
Define a macro called "C" and place the value "t0"
in that macro. When you want to retrieve the macro, refer to C as "&C."
That is, ampersand, case sensitive macro name, period. The period is
very important, and the program does very unpredictable things if the
period is missing. If you fingernails burst into flames, it's not my
fault. I'm a composer, not an error handler. Macros are the basic tool
that allow the composer to move higher and higher in abstraction. A
macro can include other macros. In this case, all notes are referred
to by their note names. Later on, &C. is used in &c__maj1-1.
to refer to the first note in the c major scale. It can also be the
second note in the a# major scale. Combine many macros together to create
a chord. More on this later.
n
Name the instrument. This is part of a two part command n0m73. The number
after the n is the channel and the number after the m is the sample
based instrument number. In this case, we are assigning channel 0 to
instrument number 73, which is defined in the file "mcgill.dat"
as a cello martelle. The samples I use are from the McGill University
Master Samples CD-ROM of orchestra instruments. A fabulous collection
with lots of rough edges. I created a file that cross references the
samples with the file names that contain the samples. The program takes
the number in the m command and builds the Csound f tables necessary
to reproduce the notes called for in the score. Automatically, sort
of. It sometimes gets confused if you up-sample or down-sample too far,
resulting in attempts to play trumpets with envelope f tables by mistake.
Live with it.
m Master Sample number. See n above for more complete description.
c Channel number. This is used to represent the channel that the
following note should use. A note is a set of commands that ends in
a space or a new line. All the values carry from the previous note.
For example, consider "c0t0d8 t14 t25". This is a set of three
notes in channel 0 (assigned to an instrument previously with n0m73).
The first note is t0, or C. 8 beats later is played note t14, or E.
8 beats later is t25, or G. A major triad ascending. Neat. This allows
different instruments to have different channels. Assign each channel
to a different instrument with the nXmX command pair. Then play the
instrument by defining notes with the c command.
z Z value. I ran out of letters. Z value is my term for variations
in the time that the note should start. For example, in normal drum
playing, the drummer may not always hit the beat right on the nose.
A high Z value means he misses it by a mile. A low Z value means he
is close. Z0 is right on the money. Also useful for guitar chords to
simulate a fast strum.
r Random. There is lots of opportunity for indeterminacy in the program.
This is one. An R value of 16 means the note always plays. Anything
less means that it might be silent. R0 is always silent. R8 is 50% chance
of sounding. Imagine a guitar player who doesn't always stroke every
note in the guitar chord every time.
& Ampersand. What follows is the macro that needs to be replaced
with the contents of the macro. If the macro name ends in an asterisk
(*) then any macro that matches the string up to the point of the *
is o.k. There is another variable, P, which is used to influence the
macro chosen in this case. It might be a random choice, it might be
exactly what what chosen the last time, it might be the next one, the
previous one, it might be one that has been least chosen so far. See
description of P below.
p Pick a random macro using a program. This is useful if you don't
really care which chord or note comes next. I like to use indeterminacy
to pick the movement of a piece. I don't always care if it picks C E
G or E G C or some other chord. If you set up your macros with similar
names up to a point, you can let the program pick which one to use.
For example suppose you had the following macros:
.c__maj1-1 &C.
.c__maj1-2 &D+.
.c__maj1-3 &E.
.c__maj1-4 &F++.
.c__maj1-5 &G.
.c__maj1-6 &A++.
Then suppose
that at some point in the song, you didn't care if the program picked
C, D, E, or any other of the six notes. In the program, you could
use the random macro facility like this:
&c__maj1-*.
The program will then pick a macro that matches the string up to
the asterisk. The result would be either &C., &D., &E.,
&F++., &G., or &A++. These would then get rendered as t0,
t7, t14, t20, t25, or t34. Depending on the value of P, the program
would pick either a random macro that met the terms of the macro name,
or it might pick the next one in the sequence. P0 says pick the one
least often picked before. P1 says pick try to pick any random one,
but if you just picked it the last time, pick another. P8 says pick
a random one. P16 says keep picking to try to match the one you picked
last time, but if you try 8 times, pick the one you pick. P32 says pick
the one you picked last time no matter what. This is surprisingly useful
for many compositional techniques. I think it is anyway, and since I
wrote the program, I get to add the features I use. Consider a piece
where you don't really care which theme is picked at any given moment,
but if it is picked, you want to repeat it several times. But not too
many times. And just because the bass part repeats, doesn't mean the
piano part should. Consider the possibilities.
u Up-sample. This provides a mechanism to pick the "wrong"
sample. U0 picks the one that was intended for a note. U1 picks one
that is intended for higher notes and uses it for the requested tone.
The result is a much mellower sound. U255 picks one intended for lower
tones, which results in a brighter sound. U values higher than 1 pick
progressively higher samples, and more mellow sounds. U values less
than 255 pick lower samples, and result in brighter tones. Imagine a
six inch long piano, or a forty foot long piccolo.
g Glissando. Apply a function table to the pitch value. g0 applies
a flat table, which does nothing to the note. If you have other function
tables that have slopes in them, then the pitch will be multiplied by
the values in the function table as the note plays. This is useful for
sliding a note up or down to a particular destination. Imagine a slide
piano. A value of 1 in the table keeps the same pitch. 2 is an octave
higher. G0 picks glissando table F301. G1 picks table F302, if it exists.
If it doesn't, Csound fails.
h Hold value. This is how long a note should be held. The program
takes integer values for all the commands. H0 holds the note for the
same length as the note duration (see d below). H1 holds it for one
beat. H24 holds it for 24 beats. I generally use a time value of 24
beats per measure, and then warp the time value with the Csound t command.
Consider t 0 700. This sets the time to 700 beats per minute starting
at time 0. Then consider t 0 700 2000 3000. This starts at 700 beats
per minute at time zero, but gradually increases the time to 3000 at
time 2000. Lots of opportunity to move around.
t Tone. This is the particular tone to pick. It is the number that
corresponds to a table in the Csound score. T0 is C. T7 is D. I always
use macros with the note names instead of the numbers.
o Octave. Which octave to play. O5 is around the middle of the piano
keyboard, but the sample files are not consistent.
v Velocity or Volume. How loud to play. V0 is silent. V90 is pretty
loud. Pick the value that makes sense. I use macros to keep the volume
variable.
d Duration. This is how long before the next note starts. In that
sense it is not how long the note lasts. H (Hold) is how long it is
held. Duration is how long before the next note in the channel starts.
For example, to play a major chord, try c0t0d0h24 t14 t25d24. This is
a C E G chord starting at time 0, and holding for 24 beats. An arpeggio
would be stated as c0t0d24h24 t14 t25, in which each note would finish
before the next one began. It's all a matter of combining H values with
D values in the proper way. D is the time before the next note in the
channel, H is the time before this note stops sounding.
s Stereo side. The S value specifies where in the stereo field the
instrument will play this note. S0 is full right, S16 is full left.
Or is it the other way around?
e Envelope. This is the amplitude function table that will be applied
to the note to specify its sound envelope. I normally have 10-20 different
function tables set aside for different attack, decay, sustain and release
slopes. Some crescendo, others decrescendo. Some grow and shrink over
long periods of time. Lots of variety. Consider the typical Ellington
orchestra horn part. Nothing simple here. Lots of swells and pops. Envelopes
start at function table 298 and move down from there. e0 picks F298.
E1 picks F297, and so on.
The program also supports math operations on integers. In fact, only
integers are allowed. For example, if you want to double the duration
of a note, d*2 would do it. d/2 results in 1/2 the duration. v-12 cuts
the velocity by 12. v+6 increases the velocity. Supported operators are
divide, multiply, add, and subtract, but only on integers.
Samples Error Recovery
This program is terrible at error handling. It often will not realize
that an error has occurred, and keep going with meaningless and impossible
to track results. Some errors are discovered, but not many. Life is hard,
get used to it. Some errors will result in music that is better than any
you could have come up with on your own, so consider mistakes a learning
lesson.
If the program discovers errors it can understand, if exits with error
level set to non-zero values. Some of the detected errors include the
following:
Attempt to Find music file failed. Io =
Attempt to Create Sco file failed. Io =
Attempt to Find McGill Sample Description file. Io =
Attempt to create AudNoteFile failed. Io =
Could not find "McGill.dat" in current Directory. Io =
Could not find instrument #' Ins:4 ' in McGill.dat
Invalid base number for instrument sample. Sample name: "' Input
Too many instruments. Attempt to set FunctionTableNumber > 280
Invalid sample offset for instrument sample. Sample name: "'
Input
Too many samples to handle. Max is ' McGillSamples
Ran out of room in 640k limit for another macro - Can you believ I
still haven't fixed this?
No room for Macro named "' MacroName
Invalid macro. Name too long "' MacroName
A Macro near the one Named . . . did not terminate in a dot as it
should have - This one is a real stinker. It is usually caused by forgetting
to end a macro with a dot, but not always...
Too many similar macros Macro called "' Name
Wild Card Macro Not Found. Name = "' Name
Macro Not Found. Name = "' Name
Invalid factor. "' Factor - not add, subtrace, multiply or divide,
I guess?
Attempt to Create Xref file failed. Io =
lots of others that crop up at the worst possible time.
Fancy tricks and advice
The program creates a file called xref.txt,
which contains a listing of all macros and how many times they were used.
This can be helpful to track some of the indeterminacy and what the program
has decided to do in a given situation. It also shows macros that were
never used.
There are some files that need to exist for this program to work. The
first of these is mcgill.dat, which contains a list of valid sample files
and some characteristics of them (stereo or mono, looping or not, delayed
start time, among other things).
The program creates some files when it runs to store some temporary information.
These can be deleted when the program finishes. I use the following batch
file to simplify execution from the DOS command line:
The call to samples.exe includes the parameter 1997, which is used to
distinguish something that changed in 1997. I can't remember what it is,
but it has something to do with using the McGill University Master Samples
instead of some that shipped with my 1997 IBM Aptiva computer. Deldup
is a DOS program that deletes duplicate error messages from the error
log file Csound produces. The "find" commands look in the Csound
log file for error messages that are important to me, like "out of
range" or "missing sample files".
Supported Operating Systems
Any Microsoft or other operating system that has a DOS box with minimum
640k of storage. I have run it under OS/2, Windows 95, 98, ME and 2000.
Turbo Pascal is amazingly flexible. It still generates executable files
that run well on any command line interface. Since most high end Intel
and AMD chips have 512KB cache, the entire program and working data set
fit in cache. As a result the program runs real fast. A typical run with
60,000 individual notes completes in less than a minute. As it runs, the
program puts out a description of the notes it is creating, every thousand
notes.
Prent Rodgers
Mercer Island, WA
December 6, 2001
Revised March 26, 2004
"It's cold, but it's a damp cold."