wcnt logo & demo sound

Inputs and outputs Top

To differentiate inputs from parameters in a module, input names start with in_. All output names start with out_. Each module's inputs are defined in the module definition.

To connect the output of one module to the input of another module, you must specifiy the module name followed by the name of it's output. Many modules have several outputs, so specifying just the module name is not enough.

When it comes to specifying an output to use, it does not matter that the output is from a module defined further on in the file. wcnt stores connection requests which are connected once all the modules have been created.

There are several categories of input and output. The most common are triggers and floating point signals. An output can only be connected to the same category of input. All trigger inputs and outputs have _trig appended to their name. Other output types are less specific, but often what is expected is implied by the name.

The command line options can help in finding what connections can and cannot be made.

In some instances you may not wish to to connect the input at all. You can simply turn it off by specifying off. Here's a little secret, you're still actually making a connection when turning an input off. wcnt automatically creates a hidden none_zero module, the outputs of which are used when turning an input off. So what the input recieves when turned off, is 0.0, or a trigger which never triggers.

Frequency? Top

You might expect filter, waveform, and sampler modules to have an input which connects to an output which provides the frequency to operate at. But they do not. In fact there are only two modules which output a frequency, and only one with a frequency specific input.

The clock, lfo_clock, and osc_clock modules all operate with frequency. The latter being the only clock based module which can have its frequency changed, aswell as modulated. The clock modules can be used to drive a waveform such as a sine_wave.

The waveform modules have an input named in_deg_size which is for connecting to a output found in the clock based modules called out_deg_size. Deg size, is how many degrees to step through on each sample, to complete 360 degrees in the number of samples that one cycle of the frequency occupies.

A single clock could be used to drive several filters, some waveforms, and a couple of sampler modules, because the clock does the frequency to deg_size conversion (with modulation), the other modules don't waste time calculating the same data.

Generally you there's no need to know the deg size values which are being thrown about by the inputs and outputs, but occassionally it may be useful. To calculate the deg size of a given frequency and samplerate:

deg_size = 360 / (samplerate / frequency)

You can also use the --freq-info command line options. Say for example you want to generate a constant frequency sine wave. You could use a clock module, but why waste processing power calculating the deg_size constantly, when you know it does not change?

// assuming sample rate is 44100
// and t1 is a timer which triggers at first sample

constant 440hrtz value 3.59184 440hrtz

    in_phase_trig t1 out_trig
    in_deg_size 440hrtz out_output
// recycle mode is on so no need to trigger each cycle
    recycle_mode on
    on_trig_reset_phase off
    phase_cycles 1.0

Modulation Top

Modulation in modular synthesis is more complex than it would first seem. This version of wcnt-1.127, despite earlier claims, is the first wcnt version to finally get frequency modulation working in a way that makes sense.

In order for modulation to work as expected the modulating signal should ideally be within a given range. In wcnt, (and many other soft synths) many signals are within the range -1.0 to +1.0, or 0.0 to 1.0.

I think I've programmed most modules which *require* the modulating signal to be in 0.0 to 1.0 to invert negative signals to positive.  Some, such as the sampler, and pan modules also check for out of range signals, and clip them if they exceed the range.  For other modules it is merely a cosmetic requirement that the modulating signal is in a given range.

Amplitude Modulation, and ADSRs

The user should therefore, when creating an adsr for amplitude shaping, keep the levels within the 0.0 to 1.0 range.  In the mono_amp, and stereo_amp modules there is an input named in_amp_eg.  (This name reads amplitude envelope generator.)  This input, unlike the amplitude modulation inputs does not have a corresponding modulation size parameter to control how much effect it has, it has total effect.  If the output connected to in_amp_eg is set to off, then nothing will be heard what so ever, no matter what you try.

The in_amp_mod input is different.  It has a corresponding parameter amp_modsize, to control how much effect it has.  A value of 0.0 realises no effect, and a value of 1.0 causes maximum effect.  You can of course use values outside this range but that would make nonsense of the amplitude level.

Pitch/Frequency Modulation, (and ADSRs)

Pitch modulation is a different kettle of fish.  Again, there is a corresponding parameter to control how much modulation occurrs, but it uses a different set of values.  The frequency modulation input signal should be within the range of -1.0 to +1.0, but that is only to keep the freq_modsize parameter making sense, it will not break anything to have a modulating signal outside of this range.

To keep things simple I'll not go into too much detail, it should be only necessary just to tell what happens at the -1.0 and +1.0 modulation signal extremes.  The freq_modsize parameter is a ratio, ie multiply the frequency by this amount when the modulation signal is 1.0, and divide the frequency by this amount when modulating signal is -1.0.  When freq_modsize is 1.0 no modulation occurs.  Providing the modulating signal is within range, then a freq_modsize of 2.0 will modulate the frequency between -1 octave, and +1 octave.  

However, if your modulating signal is positive only, then the frequency will oscilate between +0 and+1 octaves.  So in this case, when creating an adsr for pitch modulation, it is perfectly acceptable for it's levels to drop down below zero as far as -1.0.  Again, this is not a strict rule to prevent breakage.

Note:  if you set a pitch modulation size of 0.5, then it creates the same result as 2.0, only inverted, ie -1.0 will increase the frequency instead of reducing it.

Other Modulation Types

There are several other modules which use shape modulation of some kind.  The adsr is one of them.  An ADSR in wcnt has two shapes named upper and lower.  The output from the adsr is either the upper, the lower, or a combination of both shapes.  The in_velocity input in the adsr controls which of the shapes to generate.  The latest version of wcnt (1.1z) gives you greater control over which of the shapes is generated.  This is done with up_thresh, and lo_thresh parameters.  When the value of in_velocity is below lo_thresh the lower envelope is generated, when it is above up_thresh, the upper envelope is generated, and obviously when it is between the two, a shape is generated that is also so.

The dynamic module also uses the same technique for modulation, but uses in_modulation instead of in_velocity.  The user_wave module uses  a similiar technique, but lacks the threshold parameters, and has two inputs, one for vertical shape modulation (ie levels), and the other for horizontal modulation (ie position), thus creating an even greater array of potential wave shapes.

Creation, and Run OrderTop
Modules are created and added to the module list in the order they are defined in a file.  They are also run in this order.  I recommend that the wcnt_exit module is the last module to be created after all the others, particularly the wavfileout module.  It won't cause any problems if you don't, but your output files may be one sample shorter than they should, heaven forbid.

Also, for example, if you create an adsr before the sequencer module, and it is triggered by the note_on output from the sequencer, then the adsr will be triggered one sample late.  Again, I can't really see this being critical, but  it's easily avoidable.


There are atleast two types of feedback loops which can be created in wcnt.  The obvious one is the echo and lp_filter and hp_filter modules.  The other involves a clock type module when pitch modulated by the waveform it drives.

Again, depending on the module order, one of the signals may be a sample out of sync with everything else.  However, the echo and filter modules have an in_feedback input which can be connected to the output of the same module, and in this case, nothing will be out of sync.
This section will provide information concentrated on modules which require certain knowledge to use them correctly and work as expected. Also included among thist list are those modules not quite fulfilling their function.
riff data object
I fairly sure that wcnt has different octave numbers to practically everything else on the planet.  This is because I've not got around to changing it yet, and because I'm used to it and find it more intuitive.  The note a0 in wcnt, converts to 440 hrtz.
dynamic module
when inserting dvertex's into the dynamic module, you need to make sure that you cover the range of the signal that is being processed.  If you fail to do this, then the module will not work properly and it's output will be errmm, creative.

If the processed signal's negative range is equal to it's positive range, (ie -1.0 to 1.0, not -1.0 to 0.7) and you want to treat negative values the same as positive, you can turn the parameter posneg_mirror to on, and not bother inserting dvertex's for the negative range.  Note that it will only mirror positive values to negatives, not the other way around.

Here's an example:

                        sigin_level     0.0    so_ul   0.0    so_ll   0.0
                        sigin_level     0.25   so_ul   0.45   so_ll   0.05
                        sigin_level     0.5    so_ul   0.75   so_ll   0.15
                        sigin_level     0.75   so_ul   0.95   so_ll   0.25
                        sigin_level     1.0    so_ul   1.0    so_ll   1.0

        in_signal               sampler1    out_l
        in_modulation           adsr2       out_output

        up_thresh               1.0
        lo_thresh               0.5
        posneg_mirror           on
        use_ratios              off
sigin_level = signal in level
so_ul = signal out upper level
so_ll = signal out lower level

Here the signal being processed is from sampler1 and it's range is -1.0 to +1.0.  Notice how there is a dvertex for both 0.0, and 1.0, as well as mid levels.

If the parameter use_ratios was instead set to on, then the output levels are arrived at by multiplying the input by the output level.  (which is why you cannot just turn it off or on and use the same output level data for both.)
lp_filter and hp_filter modules
When I created these modules, I had no knowledge of how filters work other than that gained from experience of using them.  I realised that if I could calculate the average signal level of a number of samples, with that number of samples correlating with the frequency, then it would act as a basic low pass filter.

This implimentation has several drawbacks.  They are very slow for low frequencies, and relatively fast for high frequencies.  There is also less ability to filter to a precise frequency, the higher up the frequency scale you go.

At a sample rate of 44100 hrtz, the following data shows how frequency correlates to the number of samples needed to be retained and processed by the filter, per sample:
frequency 22050.000000 = 2 samples
frequency 14700.000000 = 3 samples
frequency 11025.000000 = 4 samples
frequency 8820.000000 = 5 samples
frequency 7350.000000 = 6 samples
frequency 44.100000 = 1000 samples
frequency 44.055944 = 1001 samples
frequency 44.011976 = 1002 samples
frequency 43.968096 = 1003 samples
frequency 43.924303 = 1004 samples
There is also a third issue with these filters to do with cut off frequency modulation. The filter takes an out_deg_size output from any clock type module, to work out the cut off frequency, and how many samples to process.  There is no problem when that clock source remains constant, but when it is modulated then small clicks/pops occur in the output.  This is because the algorythm is not sufficient to deal with modulated cut off frequencies, and I don't know how to fix it :/

The only way around it is to create another filter to filter out these pops and clicks.  I generally use a low pass filter with a fairly high cut off frequency of around 4000 hrtz or more.  (see heading 'Where's the Frequency?', above)

delay and echo modules
There is an issue when setting delay times of over 500ms with these modules which causes wcnt to abort.  It does not always occur with 500ms delay times, and I've manage to squeeze out delay times over 1000ms (wow).  I've just not got round to fixing it yet. I think this may have been fixed, or atleast vastly improved upon. nb I probably had pointers to blocks of memory which should have not been, but have been using valgrind as a matter of course lately to detect that sort of thing.That was development speak
waveform modules
A lack of anti-aliasing is a big problem with all of wcnt's waveform type modules, and that includes the sampler. At frequencies above 1/2 the samplerate (the Nyquist frequency), other frequencies begin to creep in. This is similiar to watching wheels on a car appear to spin backwards when the car in infact going forwards, or using a video camera to record the output of a computer monitor.

The user_wave module is particulary sensitive to aliasing effects. The more complex the waveform defined, the lower the frequency in which errors occurr. At these frequencies, some vertex's get dropped from the wave form, causing a kind of urrrp sound.  The more complex the wave form you create, the greater the risk of this happening.

Solving this problem for the user_wave is more complex than other simpler waveforms, due to it's capabilities for shape modulation which would require a three dimensional array in which to store the waveform's various shapes.
note_tran module
There are not any issues with this other than it might confuse people.  It allows you to translate a note name to some other value depending on how the note was triggered - note_on, or note_slide.  If the note is outside of the range, then the appropriate output is triggered - out_note_on_trig, or out_note_slide_trig.

It's definition looks like this:
// this module has no data objects
// inputs for note_tran
        in_notename             seq1    out_notename
        in_note_on_trig         seq1    out_note_on_trig
        in_note_slide_trig      seq1    out_note_slide_trig
        in_detranspose          seq1    out_transpose
// parameters for note_tran
        no_lo_notename          c0
        no_hi_notename          c1
        min_no_out              0.0
        max_no_out              1.0
        detranspose_no          on
        no_response_time        15.0
        ns_lo_notename          c0
        ns_hi_notename          e1
        min_ns_out              -1.0
        max_ns_out              1.0
        detranspose_ns          off
        ns_response_time        0.0
// outputs for note_tran
// out_no_value
// out_ns_value
// out_note_on_trig
// out_note_slide_trig
Looking at the example, when note_on occurs, it detransposes the note, and then checks it is between c0 and c1, if it is, then it translates it with c0 representing 0.0, and c1 representing 1.0.  A note name of f0 (after detransposing), in this case, will make out_no_value to be 0.5.  If the note_name is out of the range, it will trigger out_note_on_trig.

Still looking at the example, for note_slide, there is a larger range of notes, and the output values (min_ns_out & max_ns_out) are different.  Also, the notename is not detransposed before being translated.

Copying issues

All modules which contain lists of data objects, such as the sequencer, the adsr, the user_wave etc etc , cannot have the lists edited as there is not yet any way to do it. You must either use the same or create a new module.




Basic usage



Trigger modules

File inclusion

Groups and Copying





SourceForge.net Logo