Skip to content

Arrange a Song

In the previous pages, each pattern played in a loop. A finished song has a form. It has an intro, verses and a chorus. On this page, you arrange a short song from start to end, and bounce it to a WAV file.

You make three sections: an intro, a verse and a chorus. Then you put them in sequence. Then you add a drum fill and a fade-in on top of the song.

Work in the hello project from Your First Sound.

The song is 28 cycles long:

CyclesPart
0–3intro
4–11verse
12–19verse
20–27chorus

Finish Your First Project, and open hello/src/main.non. Evaluate RESET; on its own, then remove that line. Check that the previous beat is silent before setting up the song. Select and evaluate each live block in order.

The song has three tracks: drums, hi-hats and keys.

  1. Write this code into src/main.non, in place of what is there.
  2. Select the code.
  3. Push Cmd+Enter.
use "std/instruments" { Sampler, SamplerMelodic, Kit };
use "std/signals" { automation };
let drums = AudioTrack("drums");
drums.set_instrument(Sampler(Kit("CR-78")));
let hats = AudioTrack("hats");
hats.set_instrument(Sampler(Kit("CR-78")));
let keys = AudioTrack("keys");
keys.set_instrument(SamplerMelodic(Kit("keys")));
drums.volume << -6;
hats.volume << -6;

You do not hear a sound yet. The tracks have instruments, but they do not have patterns. The drums and the hi-hats are 6 dB down, so that the three tracks together do not get too loud for the master.

A section is one part of the song. All the tracks in a section have the same length. Thus, the tracks always stay aligned.

Make an 8-cycle section for the verse. Give a pattern to the drums and to the keys:

let verse = section(8);
verse[drums] << [bd _ sd _];
verse[keys] << [c3 _ eb3 _ g3 _ bb3 _];
verse.play();

verse[drums] is the lane of the drums track in this section. The << operator puts a pattern into the lane. This is the same operator that you use to send a pattern to a track.

verse.play() plays the section one time from the start. Then it stops. It does not loop.

The chorus is almost the same as the verse. It has more drums and it adds the hi-hats. Do not write the chorus again. Copy the verse, and then change the copy:

let chorus = verse.clone();
chorus[drums] << [bd sd bd sd];
chorus[hats] << [_ hh _ hh _ hh _ hh];
chorus.play();

.clone() makes an independent copy. The keys in the chorus are the same as in the verse. A change to chorus does not change verse.

The intro is 4 cycles long. It has only the keys:

let intro = section(4);
intro[keys] << [c3 _ eb3 _ g3 _ bb3 _];

The intro has no drums lane and no hats lane. In the intro, these tracks are silent.

Use arrange() to put the sections one after the other. To repeat a section, multiply it by a number:

let song = arrange(#[intro, verse * 2, chorus]);
print(song.length()); // 28
song.play();

song is also a section. It is 28 cycles long. song.play() plays the song one time from the start: the intro, the verse two times, and then the chorus.

show() gives the lanes of the song. Each line is a range of cycles and the pattern that plays there:

show(song);
section — 28 cycles, 3 lanes
keys layers: base
0..4 [C3 ~ D#3 ~ G3 ~ A#3 ~]
4..12 [C3 ~ D#3 ~ G3 ~ A#3 ~]
12..20 [C3 ~ D#3 ~ G3 ~ A#3 ~]
20..28 [C3 ~ D#3 ~ G3 ~ A#3 ~]
drums layers: base
4..12 [bd ~ sd ~]
12..20 [bd ~ sd ~]
20..28 [bd sd bd sd]
hats layers: base
20..28 [~ hh ~ hh ~ hh ~ hh]

Use show() each time that you are not sure what the song will do.

Add a fill at the last cycle of the second verse. The second verse ends at cycle 20. Thus, the fill starts at cycle 19 and is 1 cycle long:

song[drums].layer("fills").at(19, 1) << [sd*8];

.at(19, 1) selects a range in the lane. The fill goes on top of the verse. It does not delete the verse. It only hides the verse for 1 cycle.

The fill is on a layer with the name fills. A layer is a group of changes. You can turn off all the changes on a layer, and then turn them on again:

song[drums].layer("fills").mute(); // no fill
song[drums].layer("fills").unmute(); // the fill is back

A track parameter also has a lane. Use .volume to get the volume lane of a track. Put an automation curve into it. This curve fades the keys in during the intro, from −36 dB to −6 dB:

song[keys].volume << -6;
song[keys].volume.at(0, 4) << automation().at(0, -36).at(4, -6);
song.play();

The first line sets the volume to −6 dB for the full song. The second line puts the fade on top of it, in cycles 0–3. The positions in the curve start at the start of its range.

You can change a song while it plays. You do not have to call play() again.

  1. Execute song.play();.
  2. While the intro plays, execute this line:
song[drums].at(20, 8) << [bd bd sd bd];

This line puts new drums on top of the chorus. When the playhead gets to the chorus, you hear them. A change to notes starts at the next cycle. A change to automation starts almost immediately.

Now make the song a piece that resonon run can bounce. The piece is every step of this page, without the lines that you ran only to try something. Put this in src/main.non, in place of what is there:

use "std/instruments" { Sampler, SamplerMelodic, Kit };
use "std/signals" { automation };
set_project_title("My Song");
set_bpm(120);
let drums = AudioTrack("drums");
drums.set_instrument(Sampler(Kit("CR-78")));
let hats = AudioTrack("hats");
hats.set_instrument(Sampler(Kit("CR-78")));
let keys = AudioTrack("keys");
keys.set_instrument(SamplerMelodic(Kit("keys")));
drums.volume << -6;
hats.volume << -6;
let verse = section(8);
verse[drums] << [bd _ sd _];
verse[keys] << [c3 _ eb3 _ g3 _ bb3 _];
let chorus = verse.clone();
chorus[drums] << [bd sd bd sd];
chorus[hats] << [_ hh _ hh _ hh _ hh];
let intro = section(4);
intro[keys] << [c3 _ eb3 _ g3 _ bb3 _];
let song = arrange(#[intro, verse * 2, chorus]);
song[drums].layer("fills").at(19, 1) << [sd*8];
song[drums].at(20, 8) << [bd bd sd bd];
song[keys].volume << -6;
song[keys].volume.at(0, 4) << automation().at(0, -36).at(4, -6);
song.play();
render(#[master], song.length());

song.play() puts the song on the tracks. render() then plays it from the start, for as many cycles as the song is long, into a WAV file. In a terminal, in the project folder, run:

Terminal window
resonon run

The file is in renders/my_song_<date>_<time>/master.wav: 56 seconds, from the fade-in to the last chorus.

You arranged a song from sections, edited it as one piece, and bounced it. Continue in this order; each tutorial says what to have ready and starts its own exercise:

  1. Live Coding Workflow — evaluate changes, recover from errors, inspect the set, and rebuild a session
  2. Language for a Reusable Piece — variables, functions, classes and modules
  3. Pattern Basics — step lengths, rests, notes and cycle-to-cycle variation
  4. Your First Groove — nested rhythms, layers, repeats and accents
  5. Melody and Harmony in a Key — scale degrees, chords and changing key
  6. Your First Mix — volume, pan, effects, sends and a reusable mixer layout
  7. Signals and Modulation — moving filters and pan, tempo and ranges

Then choose a direction:

To go further with the song: