SOUND API for UCB (UVic flavor) LOGO 
Aaron Hechmer, 6 September 2005
copyright University of Victoria



ACTIVATING
----------

SOUNDON
Open a stream to the audio device.  In otherwords, this needs to be
called before using any sound producing method described here (except
TONE).  SOUNDON is sort of an audio equivalent to PENDOWN in turtle
graphics.  The sound is on by default.

SOUNDOFF
The opposite of SOUNDON.



FUNCTIONS THAT USE A WAVETABLE
------------------------------

TONE freq amplitude msec
Make a sinewave tone with a fixed envelope.  This function will call
SOUNDON if necessary.  TONE will output to the audiocard, ie. it
should make a noise.

	ex. TONE 220 .9 1000



SOUND freq [list of lists describing envelope]
SOUND extends upon TONE.  The audio is still a simple sinewave.
However, the envelope can be specified as a list of value pairs.  The
first value gives the amplitude (0 -> 1) and the second value the
number of milliseconds to reach that amplitude (changing linearly).

       ex. SOUND 220 [[.9 10] [0 800]]

This will produce a sinewave with frequency of 220Hz that reaches an
amplitude of .9 (90% of full volume) in 10 msec before decaying
linearly to silence over 800 msec.

HARMONY [list of [freq [list of lists describing envelope]]]
HARMONY extends SOUND.  Sinewave oscillators can be combined... each
uses a frequency and envelope description similar to that of SOUND.

     ex. MAKE "a LIST 220 [[.9 10] [0 990]]
	 MAKE "b LIST 440 [[.4 10] [0 660]]
	 HARMONY LIST a b

REST msec
Pause for a duration given in milliseconds.

TIME
Returns the system time in milliseconds as a float, ie. providing
microsecond resolution (one millionth of a second).  Currently this
only works on unix platforms.

TONEWT wave_array [frequency amplitude msec]
This function is very similar to TONE.  Here one may specifiy an
arbitrary array to use as the wavetable.

     ex. make "a sinewave 220
         tonewt a [220 .9 1000] 

SOUNDWT wave_array [freq [ list of lists describing envelope ] ]
Similar to SOUND, SOUNDWT provides a finer level of control in
defining an amplitude envelope.

     ex. make "a squarewave 220
	 soundwt a [220 [[.9 1000]]]


HARMONYWT wave_array [ lists of [freq [ lists describing envelope ] ] ]
HARMONYWT provides the finest level of control over wavetables.  It
operates similarly to its sinusoidal cousin HARMONY.  Note that the
same wavetable, given by wavearray, will be used for all frequencies.

     ex. make "a trianglewave 220
   	 harmonywt a [ [220 [[.9 1000]]]
	               [440 [[.9 1000]]] ]

SETTIME envelope base_time
SETTIME is essentially a normalizing function implemented as a library
procedure.  SOUND and HARMONY functions all use a list of amplitude
and duration pairs such as [[.9 50] [0 950]].  SETTIME will take such
a list and normalize it using base_time as a denominator.  It's
intention is to allow many different envelopes to be easily forced
into the same time signature.

     ex. make "new_envelope settime [[.9 50] [0 950]] 500
         
Here, "new_envelope would have the value of [[.9 25] [0 475]] where
the durations sum to 500.


FUNCTIONS THAT USE LOGO ARRAYS TO HOLD AUDIO CLIPS
--------------------------------------------------

SINEWAVE freq
Generate one cycle of sine wave values at the specified frequency.

	 ex. MAKE "wave SINEWAVE 220

TRIANGLEWAVE freq
Generate one cycle of triangle wave values at the specified frequency.

	 ex. MAKE "wave TRIANGLEWAVE 220

SQUAREWAVE freq
Generate one cycle of square wave values at the specified frequency.

	 ex. MAKE "wave SQUAREWAVE 220

NOISE msec
Generate msec milliseconds of noise:)

	 ex. MAKE "wave NOISE 1000

PLAYWAVE wave_array
Play, ie. send the data to the speakers, the clip specified in the
wave_array arguement.  Sound must have be turned on first via SOUNDON.

	 ex. PLAYWAVE wave

COPYWAVE wave_array num_copies
Make num_copies number of copies of wave_array.  So, if wave_array has
a COUNT of 800, COPYWAVE wave_array 2 will return a new array of
COUNT 1600.  The following example should produce (more or less) one
second of a 220Hz sine wave.

         ex. MAKE "a SINEWAVE 220
	     MAKE "a COPYWAVE a 220
  
WAVEENVELOPE wave_array [envelope similar to that of SOUND function]
This can be used to add an amplitude envelope to a sound clip
(ie. what we've been calling a wave array).  The form of the argument
is very similar to that for SOUND.

	 ex. MAKE "a SINEWAVE 220
	     MAKE "a COPYWAVE a 220
	     MAKE "a WAVEENVELOPE a [[.9 50] [0 950]]

COMBINEWAVES [wave_1 wave_2 ... wave_n]
This function will combine its wave arguments into a new wave array
with a COUNT equal to that of the longest of the arguments.  The
shorter arguments will simply be repeated as necessary to fill the
space.  It's likely that the addition of waves causes the amplitude to
exceed the capability of the soundcard and speakers, ie. clip.  To
bring the amplitude back to a reasonable level, use the library
procedure NORMALIZEWAVE.

	 ex. MAKE "a SINEWAVE 220
	     MAKE "a COPYWAVE a 220
	     MAKE "b SINEWAVE 440	      
	     MAKE "b COPYWAVE b 440
	     MAKE "wave COMBINEWAVES LIST a b

ADDWAVEAT wave_1 wave_2 msec
This will insert wave_2 into wave_1 at msec milliseconds after its
start.  If msec happens to fall after the end of wave_1, a silence
will be played as necessary before wave_2 commences.  As with
COMBINEWAVES, it may be necessary to adjust the volume using VOLUME or
NORMALIZEWAVE procedures.

CUTWAVE wave_array [start end]
Cuts a segment out of the wave array argument starting at "start"
samples until "end" samples.  One can use LOGO's COUNT function to
query for the total length of an array.

          ex. MAKE "a SINEWAVE 220 
	      ;; COUNT a shows its length to be 200 samples
	      MAKE "a CUTWAVE a [0 50]
	      MAKE "a COPYWAVE a 880

REVERSEARRAY wave_array
Returns a new array with the order of indices reversed.  REVERSEARRAY
is implemented as a Logo primitive for performance.  Still, large
arrays may be slow to reverse.

          ex. MAKE "drum READAUDIO "drumhit
              MAKE "reversed_array REVERSEARRAY "drumhit

REVERSEWAVE wave_array
Syntactically this is identical to REVERSEARRAY; however, it is
implemented in Logo as a library procedure.  Although considerably
slower, library procedures are more readily available to the student
as a code example.

FFT wave_array
Transforms via fast fourier transform the wave_array from a time
domain to a frequency array, zero padding as necessary.

          ex. MAKE "w COPYWAVE SINEWAVE 220 220
              MAKE "wf FFT w

IFFT frequency_array
Transforms via fast fourier transform from the frequency domain to the
time domain.  Using FFT followed by IFFT yields almost the same wave
originally fed to the FFT.

          ex. MAKE "w IFFT wf

NORMALIZEWAVE wave_array
Implemented as a library procedure, NORMALIZEWAVE will set the highest
amplitude in wave_array to the max volume, adjusting all other values
accordingly.  This is particularly useful if COMBINEWAVES has created
a clipped signal.  To further adjust the volume, try the SCALE_WAVE or
VOLUME controls.

          ex. MAKE "wave NORMALIZEWAVE wave


EVENWT wave_array
EVENWT is a library procedure intended to be used on wave arrays that
will serve as wave tables.  Since a wave table array is potentially
played many thousands of times a second, it's useful if the first
value and last value are nearly similar.  Large differences may
introduce a clicking or buzz.  EVENWT chops off the end of the input
wave_array until the first and last values are similar (but not
necessarily identical).  This does run the risk of clipping the entire
wave!

          ex. MAKE "wt EVENWT wt   


DOWNSAMPLE wave_array factor
This library procedure subsamples a wave array by the factor specified
in the second argument.  It will return a smaller array (unless the
factor is 1) that uses less memory and will be quicker to manipulate.
However, the subsampled wave also has poorer frequency resolution.

          ex. make "w DOWNSAMPLE (TRIANGLEWAVE 440) 2

SCALEWAVE wave_array delta
This library procedure will modify the amplitude of wave_array by the
factor delta.

          ex. make "w COPYWAVE (SQUAREWAVE 440) 440
              make "w_quiet SCALEWAVE w .5


VOLUME wave_array delta
This library procedure is simply an alias of SCALEWAVE.


RECORDWAVE msec
Will record msec of audio into an array via the audio card's audio to
digital converter.  Of course, some sort of analog sound capture or producing
device needs to be plugged into the audio-in, such as a microphone,
electric guitar or tone generator.
	   
	  ex. MAKE "w RECORDWAVE 1000

DRAWWAVE wave
This function is implemented in logo as a library procedure.  So one
may view it's code by looking for the file 'drawwave' in the logolib
directory.  

DRAWWAVE renders a drawing of the wave into a turtle graphics window
compressing the time axis, by its best guess, to fit more or less
across the width of the window.  All sample points are accounted for
to avoid any potential aliases due to subsamling.  Note that if a new
wave is drawn into the same window, it will also take up the whole
width of the window but not necessarily have the same time axis scale.

            ex. MAKE "w SINEWAVE 60
		DRAWWAVE w


MISCELLANEOUS
-------------

READAUDIO filename
Reads an audio file and returns an array of the data.  The file format
is really just a subset of the Sun/NEXT .au format: stereo or mono
16bit linear at a 44.1kHz sampling rate.  This procedure will give a
warning if the file type looks incorrect, but will read in the file
anyway.  If you have trouble reading .au files, you may want to check
its format and convert it to the above specs using a program like sox.
  
            ex. MAKE "w READAUDIO "cool_song.au
                PLAYWAVE w

WRITEAUDIO filename wave
Write an array to disk.  While this will write any Logo array to disk,
it's really meant to be used with audio data.  Because of the
quantization in converting to 16bit PCM data (from the native floating
point format), there's no guarantee that the exact same numbers will
be read back in using READAUDIO as existed in the original array; they
should, however, be close enough for the ear.  The format is Sun/NEXT
.au.  However, the .au suffix is optional.

            ex. WRITEAUDIO "my_new_cool_song.au wave

BEATBOX [ instruction list ] scale
This library procedure acts as sort of a bucket for all of the sound
producing procedures such as tone, tonewt, sound, soundwt, harmony,
harmonywt and playwave.  The procedures will simply be called in the
order in which they appear in the instruction list supplied as the
first argument.

            ex. make "wv readaudio "drumhit
                make "beat [ [playwave wv] [rest 100] 
                             [playwave wv]  [rest 100] 
                             [tone 220 .6 500] [rest 100] ]
                beatbox beat 1

Notice how, in this example, everyother instruction is a rest.  The
scale parameter will adjust these rests causing the beat to speed up
or slow down.  For instance, a scale of 2 will cause the beat to be
played twice as fast; a scale of .5 will affect a beat half as fast.
