wcnt logo & demo sound

Introduction to sequencing in wcnt Top

Sequencing is broken down into a number of parts:

  • time_map - module to handle tempo and time signature
  • riff - data object which contains notes
  • sequencer - module that translates note data in a riff
  • osc_clock - module that translates frequency

Note sequencing in wcnt is monophonic. That is a riff can only contain one note at any given position, and the sequencer can only output the information for one note at a time. However, due to modularity, and the ability to group modules together it is not too difficult to simulate sequenced note polyphony.

Creating the time_map Top

First, the time_map. Here's a definition which initialises to the bpm and signature values set in the header portion of a .wc file.

    // empty!
    // time signature changes are inserted here
    // empty!
    // bpm/tempo changes are inserted here

You need to use the time_map module if you are going to be using the sequencer, even if tempo and signature changes are not used. The time_map provides a trigger at the start of a bar, a ratio for the rate of progression through the bar at given tempo and time signature, and the number of bars passed through.

When you insert a tempo change you should be aware that the value you use is relative to the bpm at that point. To insert a tempo change add the following between the two bpm_map's.

        tempo bpm -20 bar 1

In the sinewave.wc example on the basic usage page, the bpm value set in the header portion is 120. The time_map will begin with a tempo of 120 bpm, then gradually decrease it until the start of bar 1 where the tempo change is complete. Instead of gradually changing the tempo like this, it can be forced to jump to it. If you added the following:

        tempo bpm 20 bar 1

to the above example, the tempo would still fall from 120 bpm at bar 0 to 100 bpm at the end of bar 0, but it would suddenly be back at 120bpm when bar 1 started.

Creating a riff of notes Top

Here is a simple riff data object definition.

    quarter_value 4
        name c0 pos 0.0 len 1.75 vel 1.0
        name d0 pos 2.0 len 1.75 vel 0.9
        name e0 pos 4.0 len 1.75 vel 0.8
        name f0 pos 6.0 len 1.75 vel 0.7
        name g0 pos 8.0 len 1.75 vel 0.7
        name a0 pos 10.0 len 1.75 vel 0.8
        name b0 pos 12.0 len 1.75 vel 0.9
        name c1 pos 14.0 len 1.75 vel 1.0

The riff is named riff1. Every riff must specifiy the quarter_value parameter. Here it is set to 4, which means the length of a bar in the riff is 16 (provided you are using 4/4 time). So adding a note with a pos (position) of 8, adds it halfway through the first bar. In this particular riff, notes are added at intervals of eighths through the bar, each with a length between a dotted 16th and an 8th.

Using a quarter_value set to 4 makes it easy to add notes at 16ths and 8ths etc, but tricky to add triplets. A quarter_value set at 12 is ok for using triplets. Changing the quarter_value of a riff without changing the note length and positions will effect them. In this riff, setting quarter_value to 2 will double the length of the riff. The riff is not restricted in length, but can only be inserted into the sequencer at bar positions.

In wcnt, c0 is middle c, with a frequency of 277.183 hrtz, usually expressed as c4 in other systems. c-1 is an octave below middle c, and c1 is an octave above. notes in wcnt can only express sharp values such as g#1, not flat values such as bb1. wcnt uses the equal temperament scale, (12tet I believe) that is note pitchs are equally spaced along the frequency scale, halving the frequency reduces the pitch by an octave and doubling the frequency increases by an octave.

Edit Notes Top

A note can also express a note/riff editing command, for example:

note name <P+N pos 16 len 5 vel 0.0

which will transpose all notes before position 16 by adding 5 semitones to them.

In detail, the first two characters of the note edit command always express how notes will be selected for processing. The first character, <, indicates to search for notes LESS THAN. The second character, P, makes the basis of the selection to be on position. Combined, it means to search for notes with a position less than. Because it is position we are dealing with, it searchs for notes with a position less than that specified for the edit notes position which here is pos 16.

The third and fourth characters, +N, specify what to do to the notes it finds meeting that search criteria. The first character, a plus sign +, indicates exactly that, add to. The N, means name, so together means add to the note name, or transpose. The value which is added (or subtracted or multiplied or divided) is always after the search value(s), position has been used for the search, which leaves len and vel. In this case it uses len (as it's next to pos) to add five semitones to each of the selected notes names.

When using edit notes it is important where you place them in the riff. They only effect the notes that they are placed after, if you insert notes after the edit note, they will be uneffected by it.

Here's another example of an edit note:

note name IL-P pos 8.0 len 4.0 vel 8.0
//(select by length inside range, and bring forward position)

The first character I, means search inside range. And a range needs two values. Because the selection (2nd character in edit note name) will be based on length this time, the first search value is held in len, which is 4.0. The second search value is always immediately after the first, which here is vel which is 8.0. The second search value is added to the first value so it means select notes with lengths inside range 4.0 to 12.0, but not lengths 4 or 12. As len and vel have been used for the selection range, it only leaves pos available for specifying the value to subtract. the last character of the edit command is a P, so subtract from the selected notes positions (ie bring them forward). Any notes which get repositioned before 0.0 - the start of the riff, will be removed.

Here's one last example I'll bore you with:

note name ON!Pc#-1 pos 8.0 len 0.0 vel 0.0 //(select by name outside range and delete.)

The O is the compliment to I, meaning search outside range, with N specifying a note name based search. Remember that actual note name edit commands are always four characters long. The exclamation mark !, states without mercy, DELETE notes, therefor, the P is redundant. That leaves four apparently extraneous characters which happen to be the first search term, c#-1, that is c sharp octave minus one, or c#3 in the more common octave system. So altogether it means delete all notes outside of c-1 to c-1 + 8 semitones (now you can see why the second search term is relative to the first).

Here are the characters that can be used in note editing commands:

-character---1---meaning---------------------number of search terms-
             =  select notes equal to               1
             <  select notes less than              1
 one of {    >  select notes more than              1
             I  select notes inside range           2
             O  select notes outside range          2

-character---2---meaning------------------placement of 1st search term-
             N  select notes by name        last part of edit command
             P  select notes by position            pos
 one of {    L  select notes by length              len
             V  select notes by velocity            vel

             !  delete selected notes
             +  add to selected notes value
 one of {    -  subtract from selected notes value
             *  multiply selected notes value
             /  divide selected notes value

             N  process notes name
 one of {    P  process notes position
             L  process notes length
             V  process notes velocity
             Q  process notes position, but keep originals (Qopy)

The ! delete character is not strictly necessary, as multiplying the length of a note by zero, or, moving the note before position 0, or divided it's length or position by zero will delete it. But by using it, it is easier to see what is happening to the notes.

The sequencer Top

The sequencer definition below, sequences riff1, at bar position, 0, and again at bar 1.

             riff riff1 bar 0 transpose 0
             repeat 1 repeat_stripe 1
    in_bar time1 out_bar
    in_bar_trig time1 out_bar_trig
    in_pos_step_size time1 out_pos_step_size
    in_beats_per_bar time1 out_beats_per_bar
    in_beat_value time1 out_beat_value
    velocity_response_time 5

In the sequencer is the data object track. To this are added data objects called riff_node. The riff_node contains five parameters. The first parameter riff, is the name of the riff to be added.

Through riff_node the sequencer can be instructed to transpose the notes in the riff being added. The transpose parameter is used to transpose the entire riff by a number of semitones, which can be positive or negative. The repeat and repeat_stripe tell the sequencer how many times to add the riff and how to space it out. Setting repeat to 0 does not repeat the riff, but it still gets added, repeat specifies how many more times to add it. Setting repeat_stripe to 1 says repeat it at every bar, a value of 2 would mean every other bar, and so on.

The sequencer has five inputs which should be connected to the outputs of a time_map module. Only those with strong elements of perversity in their character should consider connecting the sequencer inputs to any modules other than a single time_map. The results of doing so have not been tested.

Lastly is the velocity_response_time parameter. It is used to specifiy a duration to ramp the velocity from one value to the next, and effects only the sequencer out_velocity_ramp output. You would use this instead of out_velocity if you are applying velocity changes using the mono_amp module.

Using the osc_clock Top

The osc_clock module is one of several modules used to translate the sequencer output. Its main job is to change to a new frequency when the sequencer encounters a new note. Here's a definition.

    in_note_on_trig seq1 out_note_on_trig
    in_note_slide_trig seq1 out_note_slide_trig
    in_play_state adsr1 out_play_state
    in_frequency seq1 out_frequency
    in_freq_mod1 off
    in_freq_mod2 off
    octave_offset 0
    tuning_semitones 0.0
    portamento_time 150.0
    response_time 10.0
    freq_mod1_size 1.0
    freq_mod2_size 1.0

The osc_clock does not check it's input in_frequency to see if it should change frequency. Instead, it waits until in_note_on_trig triggers, and then it looks to see what frequency to change to. Or, in_note_slide_trig may trigger instead, which tells the osc_clock to use the portamento_time to gradually change to the new frequency.

The in_play_state input corresponds with the response_time parameter in how the new frequency change triggered by in_note_on_trig is treated. Assuming that adsr1 shapes the sound of a waveform that osc1 controls, then it knows if the sound can be heard or not. When adsr1 out_play_state provides on, then the sound can be heard so the osc_clock takes the number of milliseconds specified by response_time to make the frequency change, otherwise it makes the change instantaneously.

Tuning of the osc_clock can be adjusted by octaves, and/or semitones, with the parameter tuning_semitones allowing fractional amounts.

Note events Top

The sequencer has an out_note_slide_trig output, and the osc_clock has an in_note_slide_trig input, but how are these generated?

These events are handled differently by both the osc_clock and the sequencer to normal note on events, and it is the list of notes in a riff which determine which type is generated.

If you have a monophonic synthesisor with portamento, you can keep a key held down and then tap other keys and the pitch will slide up and down to the new notes and back to the old again. This is how the sequencer in wcnt-1.2 is programmed to behave with its out_note_slide_trig connected to an osc_clock's in_note_slide_trig input.

Therefor to get sliding notes you must make the notes in a riff overlap (and set the relevant modules up correctly).



Basic usage



Trigger modules

File inclusion

Groups and Copying





SourceForge.net Logo