
2000-aug-16
with synthesizer version 1.3

          --------------------------------
          Chrisitian's Virtual Synthesizer
          --------------------------------

                 Tech-Documentation

Synth is a virtual synthesizer that can produce wave 
output from text input. This is not (yet?) a full fledged 
application or a complete library with fancy API.
However, the source contains the full functionality.

                     ---------
                     THE SYNTH
                     ---------

The synthesizer uses subtractive synthesis. It starts from 
a waveform and passes that through an amplitude envelope
and a lowpass filter.


WAVEFORM GENERATOR

In the current version, the waveform generator can give
6 basic waveform types, that are further modifyable by a 
width parameter that goes from 0% to 100%. For the rectangle
wave, "width" means the width of the duty cycle, for other
waves, the width parameter has a different effect. See
the following table for a very sketchy illustration of
what the waveform generator will do for which parameters:


   Wave Type		width = 0	  width = 25 %	    width = 50 %


   0 = impulse	       |   |   |   |
                      _|___|___|___|_   _||__||__||__||_   _|_|_|_|_|_|_|_

    
   1 = alternating impulse      

                      _______________   _|___|___|___|__   _|___|___|___|_
                                          |   |   |   |       |   |   |
   2 = sawtooth         
                       |\  |\  |\  |\    
                       | \ | \ | \ |     |\\ |\\ |\\ |\\    
                      \|  \|  \|  \|    \|  \|  \|  \|  \  \|\|\|\|\|\|\|\
   3 = rectangle  
                                         __  __  __  __     ___ ___ ___ __
                      _______________   _||__||__||__||_   _| |_| |_| |_|

   4 = parabol           _   _   _   
                      \ / \ / \ / \ /   \  /\  /\  /\  /   _ _ _ _ _ _ _ _
                       Y   Y   Y   Y     YY  YY  YY  YY     Y Y Y Y Y Y Y

   5 = triangle 
                                          _   _   _   _
                      _______________   _/ -_/ -_/ -_/ -   \  /\  /\  /\
                                                            \/  \/  \/  \/


The wave generator can do width modulation, ie. the width param
changes while playing. By default, the modulation is ascending 
and cycles from 0% to 100%. New in 1.2 is the possibility to
specify a time for how long the modulation is ascending and
how long it descending, so the width parameter does ping-pong 
within a limited range while playing the note.

The wave generator gives you the option to decide between 
relative or absolute width. Relative with will be a constant 
percentage, absolute with a constant time:

   relative width              absolute width 

   __  __  __                  __  __  __
  _||__||__||__               _||__||__||__
   ___   ___   ___             __    __    __
  _| |___| |___| |__          _||____||____||__
   ____    ____    ____        __      __      __
  _|  |____|  |____|  |__     _||______||______||__


New in 1.2 is the option to limit the number of harmonics 
that the output wave contains. Harmonics are sine waves that 
are of integer frequency. Every periodic signal can be 
decomposed into harmonics. For instance, a sawtooth wave
(type 2) at width 0% is decomposed into

             1            1            1
   sin x  +  - sin 2x  +  - sin 3x  +  - sin 4x  +  ...
             2            3            4
   
Now by default, the number of harmonics that the wave generator
outputs is unlimited, that is, the waves contain as many 
harmonics as there is fit up to half the sample-rate. But if 
limited to, for instance 5 harmonics the composition of the 
above example would stop after the 5th component. If the base
frequency was note "A" (440 Hz), there would then be no output 
beyond 2200 Hz. 

Limiting harmonics is in fact another way of low-pass filtering, 
but it is of a different quality (and thus sounds different) 
than that archieved with the ordinary resonant lowpass filter 
(see below).


ENVELOPE GENERATOR

The envelope generator produces a kind of ADSR envelopes, 
which stands for Attack-Decay-Sustain-Release.
When starting a note, the attack phase begins and the level 
ramps up. Directly afterwards in the decay phase the level 
goes down to sustain level. In the sustain phase it holds 
until the release phase. When the note releases it goes 
back to zero.


        trigger                     release
 
  100 %    |                           |
           |    /\                     |
           |   /  \                    |
              /    \___________________     ----- sustain level
             /                         \
    0 %  ___/                           \_____

              A   D          S         R  

The four parameters of the ADSR are: (1) how fast attack is,
(2) how fast decay is, (3) what level sustain is, (4) how
fast release is. In this implementation of the ADSR, attack 
cannot be slower than decay (otherwise you get weired results), 
and the phases are no real phases, but reather go smoothly into 
each other. Furthermore, how much the attack overshoots before
sustain depends on how faster the attack is than the decay. If 
both are equal, then the level will not overshoot at all but 
ramp directly to the sustain level instead. Furthermore, sustain
can be 0% so there is no sustain at all or can be 100% so 
there is no decay:


   Attack much faster than decay            Sustain 0%


      |\                                      |\
      | \_______________                      | \
    __|                 \________           __|  \___________________


   Attack a bit faster than decay           Sustain 100 %
                                               _________________
                                              |                 \
        /\_______________                     |                  \
    ___/                 \_______           __|                   \__


   Attack = Decay 


           _______________
    ___.-''               \______


   Attack slower than decay
   (this is not a bug, it's a feature)

              ____________
    ___   _.-'            \______
       \_-


There are 2 ADSR envelopes for each voice, which can be programmed 
independently. One evelope is for the overall level and the other 
modulates the cutoff of the filter (see below).


FILTER SECTION

The filter is equivalent to a 2nd order infinite impulse
response filter, capable of doing 12 dB/octave rolloff.
The filter has 2 parameters: cutoff frequency and quality
factor. The first controls how open or closed the filter
is and the latter controls how much the filter is resonant.

In the current version, the filter is always a lowpass 
filter, ie. low frequencies pass. The following diagram 
shows a typical frequency response of a filter with zero 
resonance. The is a passband from 0 Hz to the cutoff 
frequency (this is where the respose falls to 70.7%) and
a transition band from cutoff to half the sample-rate with
6 dB / octave rolloff.

              cutoff freq

                   |
                   |
 100%  ________    
               ''-. 
                   '.                 <----  6 dB / octave rolloff
                     ''..
                         ''--..__
  0%                             ''
       0 Hz                      SR/2


For a non-zero quality factor the filter is resonant; there 
is an amplification peak where the cutoff is. In addition, the 
transition band gets steeper:

                  _
                 / \
 100%  ________.'   \ 
                     \
                      '.               <----  more than 6 dB / octave
                        '.
                          '-.
  0%                         '-..__
       0 Hz                      SR/2


For very high resonant modes the filter becomes it's own 
oscillator. Keep in mind that the software provides no 
protection against excess resonance. The filter will dive 
happily into chaos then.


SUMMARY

The signal flow for one synthesizer voice is as follows.
The original wave comes from the wave generator (WG) and
is then multiplied by the amplitude envelope (AENV).
After this, the wave goes through the filter, where the
cutoff frequency is controlled by the filter envelope.
Filter and amplitude envelope are triggered synchronously
but can have different parameters.

                      FENV
            AENV       ||
             |         \/
    WG ---- (*) ---> FILTER ---> out



THE BOOSTER

The booster is available in the chord voice, which is an 
aggregate of 3 solo voices, and operates on the sum
output of the three. The booster is a simple simulation of 
a guitar amplifier. It multiplies the signal by a variable
factor  (the boost factor) and then does a soft clipping along 
a hardcoded hyperbolic s-curve. The higher the boost factor, the 
more the soft clipping becomes hard clipping. 
            

   Example:
                
      /\    /\            .-.     .-.         .---.   .---.
     /  \  /  \  /       |   |   |   |        |   |   |   |   |
         \/    \/             '-'     '-'         '---'   '---'
    
       original            boost = 100          boost = 10000

Boosting is fairly expensive since it involves 64 bit integer
division in the inner loops.


RING MODULATION

New in 1.2 is ring modulation of two voices. Ring modulation
results in a convolution of the spectra of the two signals that
are put together, so this thing creates sounds with "unharmonic"
harmonics (bell, gong, tube, etc...)

The voices that are beeing modulated can be of any type (mono, 
chord, drum). There is a source and a destination for ring 
modulation. The voice that wants to be modulated selects 
the voice number (1-16) that it wants to use as modulation source. 
The source voice is completely unaffected by ring modulation, you 
will hear it as normal, unless it is muted.


                   -------------
                   THE SEQUENCER
                   -------------

The music is made up of serveral sequencer tracks that begin
with a % character. The output of each track is added together. 

Each sequencer holds a voice object, which is polymorph and 
can be of different type and thus understand different commands. 
The type of the voice object can be changed while playing.

Some commands are for controlling the sequencer itself and 
are the same regardless of voice type. All commands that 
are not understood by the sequencer are passed to the voice 
to interpret. If the voice doesn't know them they're 
beeing ignored.

As of Version 1.2 all parameters have a meaningful default
value so you are safe to leave out anything.

                      -------------------
                      SUMMARY OF COMMANDS
                      -------------------

%                       begin track
 
l <hex digit>           set volume level

@ M                     set type to a mono voice (default)
@ C                     set type to a chord voice
@ D                     set type to drums

@ 125 8                 set tempo to 125 bpm and a precision of 
                        8 subdivisions per beat, could also be:
                        @ 90 4
                        @ 135 16

{                       begin pattern definition
  <capital letter>      pattern ID
  ...                   pattern data
}                       end pattern definition

<capital letter>        play pattern

<number 1..8>           delay for that number of subdivisions
                        use this to hold notes and pause between notes

   --- new in 1.2 ---

r <decimal>             ring modulate this voice with output of voice 
                        number #, count starts with 1, r0 turns off
                        ring modulation

m <boolean>             m1 turns muting on, m0 turns muting off
                        A muted voice produces output but isn't mixed
                        in. Useful for using a voice only as source for
                        ring modulation.
                        
   --- new in 1.3 ---
  
                     The following commands may only appear
                     once in the whole file and the effects
                     of them are global

@enhancer <decimal>	set enhancer 0, 1 or 2
@transpose <decimal>	set global transpose -16 to 16 semitones
@gain <decimal>		set global gain -20 to 20 dB
@samplerate <decimal>	set the destination sample rate

@tempostretch <decimal>	set global tempo stretch in x/10000, 
                        higher = faster

@reverbenator 		parameters for the reverbenator
<9 decimals>		(see reverb.txt)


MONO VOICE COMMANDS

+                       trigger note
++                      trigger note hard
+-                      trigger note soft

-                       release note

c#3                     tune to c#3
                        this is only an example, could also be
                        a3, f#7, b2, etc...
                        the octave is 0..9 and can be omitted, the
                        last specified octave will be used then
                        - note that the scale begins with 'a', not
                        with 'c' in this program, so after g#3 
                        comes a4

c#.3                    use . to separate the delay from the note
                        so that the 3 is not interpreted as octave
                        (results in legato, only pitch change but
                        no new note)
 
t <signed hex-digit>    set transpose in semitones
                        so if transpose is -5, c3 will tune to g2 
                        instead

                   VOICE PARAMETER CONTROL
                   all commands are followed by a number of 
                   hexadecimal digits, one digit for each parameter,
                   0 beeing minimum and f beeing maximum within
                   sensible limits of that parameter

iw <hex-digit>          set waveform type
ip <2 hex-digits>       set pulse-width and pulse-width-modulation
ip <..>+<hex-digit>     as above but with absolute width,
                           the additional digit controls together with the very
                           first digit, how wide the width actually is
ia <4 hex-digits>       set ADSR envelope for amplitude
if <4 hex-digits>       set ADSR envelope for filter
ic <2 hex-digits>       set maximum cutoff-frequency and quality
                           the maximum cutoff says, what is 100% for the 
                           filter envelope
iv <3 hex-digits>       set vibrato delay, -frequency and -level

   --- new in 1.2 ---

ih <decimal>            set the maximum number of harmonics that the wave
                           is constructed of, ih0 sets to unlimited (default)

ip <..>-<2 hex digits>  set the time for how long width modulation goes up
                        (1st digit) and down (2nd digit). If set to 00 or
                        left out, width modulation acsending only. Must
                        be combined with absolute width like this: 

                           ip <..>-<..>+<.>

CHORD VOICE COMMANDS
Inherits all of the MONO VOICE commands, plus this is different:

c#3                     Sets only the base note, the actual chord
                        is tuned with the = command. The chord must
                        then be triggred with + to be played.

=<3 signed hex-digits>  set up the chord as 3 offsets to the base
                        note in semitones, example
                        =047    major chord
                        =47c    another major chord
                        =-8-50  this is also a major chord
                        =037    minor chord

   --- new in 1.2 ---

ib <decimal>            set boost factor, ib0 turns booster off (default)


DRUMS COMMANDS
This are fairly simple as there are only 4

b                       hit base drum
s                       hit snare
hc                      close hi hat
ho                      open hi hat (o and c can be omitted)

   --- new in 1.2 ---

ib <8 decimals>         parameters for the drum models
is <6 decimals>         see drums.txt for explanation
ih <6 decimals>   

