Difference between revisions of "Sound"

From Gamebuino Wiki
Jump to: navigation, search
m (Commands)
m (Instrument sets: typo)
 
(13 intermediate revisions by 2 users not shown)
Line 1: Line 1:
The power of the sound library of the Gamebuino is that is allow you to play sounds and musics in the background while you play your game without having to care about it. Just ask "play this sound", and forget about it, the library takes care of everything. But if you want to create sound FX an compose chiptunes, you should understand what happens under the hood. The goal of this article is to explain you how sound is generated and structured.
+
== Intro==
 +
The power of the sound library of the Gamebuino is that it allows you to play sounds and musics in the background while you play your game without having to care about it. Just ask "play this sound", and forget about it, the library takes care of everything. But if you want to create sound effects or compose chiptunes, you should understand what happens under the hood. The goal of this article is to explain you how sound is generated and structured.
  
 
== Layers ==
 
== Layers ==
The sound library slices the sound data in different layers. We'll start from the deeper layer (wave form generation) and up to "chains".
+
The sound is sliced in different layers in the Gamebuino sound library (just like in any tracker). We'll start from the deeper layer (wave form generation) and go up to "tracks".
  
=== Wave form generation ===
+
=== Wave forms ===
PWM is used at 32 KHz to generate an analog output. To be able to play several sounds at the same time, the library generate one waveform per channel and add them to output the result into the speaker. This is done using interruptions at a rate of 56 KHz. The waveform of each channel is changed once per frame, which is 20 Hz by default. A waveform has the following characteristics :
+
PWM is used at 32 KHz to generate an analog output. To be able to play several sounds at the same time, the library simply generates one waveform per channel and add them. This is done using interruptions at a rate of 56 KHz. The waveform of each channel is changed once per frame, which is at 20 Hz by default. A waveform has the following characteristics :
* Frequency, picked from a list of predefined frequencies which corresponds to different note pitches.
+
* Frequency
 
* Wave form
 
* Wave form
 
** Square wave, 50% duty cycle
 
** Square wave, 50% duty cycle
Line 13: Line 14:
  
 
=== Instruments ===
 
=== Instruments ===
Instruments allow to play play sounds different than just plain square waves. It allows you to add variation in the sound of each note. And instrument in fact a succession of "steps", and each "step" has the following characteristics:
+
Instruments allow to play different kinds of sounds, not just plain square waves. It allows you to add variations in the sound of each note. An instrument is a succession of "steps", and each "step" has the following characteristics:
 
* step duration in number of frames (from 0 to 63)
 
* step duration in number of frames (from 0 to 63)
* step waveform, it defines if this step should be played either using square or noise waveform.
+
* step waveform, it defines if this step should be played either using square wave or noise.
* step volume (from 0 to 7), it allows to create a volume envelope
+
* step volume (from 0 to 7), it allows to create a volume envelope.
 
* pitch offset (from 0 to 63), to allow you to add arpeggio, glissando for example. We'll see later that you can also use commands to add effects to certain notes.
 
* pitch offset (from 0 to 63), to allow you to add arpeggio, glissando for example. We'll see later that you can also use commands to add effects to certain notes.
Each instrument has a "last step looping" attribute. When a note duration in longer than the instruments' it's played with, the instrument will loop on the last X steps. Or won't loop if it's set to 0.
+
Each instrument has a "last step looping" attribute. When a note duration is longer than the instrument it's played with, the instrument will loop on the last X steps. Or won't loop if it's set to 0.
 
Note: You can't directly access to this layer. You can't play an "instrument", you have to play a "note" using an "instrument".
 
Note: You can't directly access to this layer. You can't play an "instrument", you have to play a "note" using an "instrument".
  
 
=== Instrument sets ===
 
=== Instrument sets ===
An instrument set is just an array of instruments you can attach to a channel using <code>changeInstuemenSet()</code>. The ID of the first instrument in the set is 0, the ID of the second instrument is 1, and so on. We'll see later how to select which instrument ID to use when you want to play a note.
+
An instrument set is just an array of instruments you can attach to a channel using <code>changeInstrumentSet()</code>. The ID of the first instrument in the set is 0, the ID of the second instrument is 1, and so on. We'll see later how to select which instrument ID to use when you want to play a note.
 +
 
 +
By default, instrument 0 is plain square wave and instrument 1 is noise.
  
 
=== Notes ===
 
=== Notes ===
Line 28: Line 31:
 
* Pitch (from 0 to 58) is the ID of a predefined frequency from A#2 to D#8. If the pitch ID is equal to 63, the note is muted.
 
* Pitch (from 0 to 58) is the ID of a predefined frequency from A#2 to D#8. If the pitch ID is equal to 63, the note is muted.
 
* Duration (from 0 to 255) in number of frames, each frame lasts 1/20s by default. A duration of 8 at 20 frames/second corresponds to a quarter note at 150 BPM (the most common BPM in chiptunes according to [http://www.giantbomb.com/profile/x19/blog/chip-music-and-my-attempt-to-write-in-that-style/82269/ this interesting video about chiptunes]).
 
* Duration (from 0 to 255) in number of frames, each frame lasts 1/20s by default. A duration of 8 at 20 frames/second corresponds to a quarter note at 150 BPM (the most common BPM in chiptunes according to [http://www.giantbomb.com/profile/x19/blog/chip-music-and-my-attempt-to-write-in-that-style/82269/ this interesting video about chiptunes]).
 +
* Channel (from 0 to 3) on which channel you want the note to be played. 0 for the first channel, 1 for the second channel, etc. By default there is only 1 channel so you should use the value 0. To increase the number of channels to up to 4, edit <code>NUM_CHANNELS</code> in arduino/libraries/gamebuino/settings.c.
  
 
=== Commands ===
 
=== Commands ===
Line 33: Line 37:
  
 
The command's ID defines which command to pass. Each command has an one or two parameters, X and Y. Unless specified X is from 0 to 31 and Y is from -16 to 15.
 
The command's ID defines which command to pass. Each command has an one or two parameters, X and Y. Unless specified X is from 0 to 31 and Y is from -16 to 15.
* 0: Set note volume, X: volume (from 0 to 7)
+
* 0: Set note volume, X: volume (from 0 to 9)
 
* 1: Select Instrument, X: instrument ID
 
* 1: Select Instrument, X: instrument ID
* 2: Volume slide, X: duration, Y: depth
+
* 2: Volume slide, X: step duration, Y: step depth
* 3: Arpeggio/partamento, X: duration, Y: depth
+
* 3: Pitch slide, X: step duration, Y: step depth
* 4: Tremolo, X: duration, Y: depth
+
* 4: Tremolo, X: step duration, Y: step depth
  
 
For example, <code>gb.sound.command(3,4,-5)</code> will make a descending arpeggio by of 5 semitone every 4 frame.
 
For example, <code>gb.sound.command(3,4,-5)</code> will make a descending arpeggio by of 5 semitone every 4 frame.
  
 
=== Patterns ===
 
=== Patterns ===
 +
Now that we know how to make instruments, play notes using these instruments, and alter these notes with commands, that'd be cool to be able to put all that together to make some actual music. That's why we'll use "patterns". A pattern is a mixed array containing notes and commands. It starts from the first note, and play the next one when the first reached its end. And of course it will execute commands if there are some.
 +
 +
'''Note''' : Pattern is the recommended layer level to create game sounds.
  
 
=== Pattern sets ===
 
=== Pattern sets ===
 +
A "pattern set" is simply an array of patterns. This way you can refer to a pattern using its ID. The first pattern's ID is 0, the second is 1, and so on.
  
=== Chains ===
+
You can assign a "pattern set" to a channel using <code>changePatternSet(pattern, channel)</code>. It allows us to easily re-use pattern, which is pretty cool as it spares memory (and also because musicians a lazy).
 
 
= OLD =
 
The following is outdated but stays here for reference until I finish to rewrite this article
 
 
 
The simplest way to make sound with your Gamebuino is to use the 3 predefined sounds (<code>gb.sound.playOK()</code>, <code>gb.sound.playCancel()</code> and <code>gb.sound.playTick()</code>). But this is quite limiting, and I'm sure you want some cool sound FX and chiptunes. To do so, you can compose your own musics and sounds using the tracker (you can download it from [https://github.com/Rodot/Gamebuino/tree/master/utilities/music GitHub]). But first you should understand how sound is made and structured.
 
== Sound structure ==
 
This part explains how music is structured. In short, there is up to 4 channels, each channel plays a track, which is a mixed set of notes and commands. Each note is played using an instrument, which is a succession of steps. Commands are used to alter the way notes are played.
 
 
 
=== Channels ===
 
The sound library supports up to 4 channels. It means that you can play 4 different notes at the same time. But playing notes is not really interesting, we want to play chiptunes and bad-ass sound effects! That why we use "tracks". You can play one track per channel. For example, using <code>gb.sound.playTrack(myTrack, 0)</code> you play the track "myTrack" on the channel 0. Let's see what's inside a track
 
 
 
=== Chain ===
 
A chain is to top-level structure in a music. It it a array of pattern ID (picked from the pattern set defined using changePatternSet) along with a transposition for each pattern.
 
 
 
=== Pattern ===
 
A pattern is a mixed array of commands and notes (actually a 16 bit integers array).
 
 
 
=== Commands ===
 
Commands are used to alter the way notes are played.
 
Each command has 2 parameters: X is between 0 and 31 and Y is between -16 and 15.
 
A command remains active as long as it's not cancel by passing the command again with X = 0.
 
 
 
Available commands:
 
* 0 set note volume, X = volume (0 to 9)
 
* 1 select instrument, X = instrument ID
 
* 2 volume slide, X = step duration, Y = step size
 
* 3 arpeggio/portamento, X = step duration, Y = step size
 
* 4 tremolo, X = step duration, Y = step size
 
  
=== Notes ===
+
=== Tracks ===
Each note have the following parameters:
+
To be able to easily re-use patterns from a pattern set, we use "tracks". A track is an array of pattern IDs along with a pitch offset (or transposition) to apply to each of them when they are played. To play a track, simply call <code>gb.sound.playTrack(track, channel)</code>.
* Pitch, 0 to 58 for pitches from A#2 to D#8. 63 for a silent note.
 
* Duration in number of frames (1/20s by default). From 0 to 255.
 
 
 
=== Instrument set ===
 
Each channel has a instrument set assigned to it. An instrument set is an array of instruments. When you use the command "select instrument" in a pattern, it select and instrument from the active instrument set. By default, the instruments are
 
* 0 : continuous square wave
 
* 1 : continuous noise
 
But these are really basic instruments. It's better to create your own instruments.
 
 
 
=== Instrument ===
 
An instrument is an array of 16 bits integers. The first int (the header) define 2 parameters:
 
* instrument length (from 0 to 255) : how many steps there are in the instrument
 
* last steps looping (from 0 to 255) : when the note duration is longer than the instrument's duration (which is the sum of the duration of its steps), the track will loop on the last X steps of the instrument.
 
Each following int in the array correspond to a "step". Each step has the following parameters:
 
* volume (from 0 to 7) : used to create a volume envelope
 
* waveform: should this step be play either as square wave or as noise
 
* step duration in number of frames (from 0 to 63)
 
* pitch offset (from 0 to 63) : an offset to apply to the note's pitch.
 

Latest revision as of 2016-11-30T19:55:06

Intro

The power of the sound library of the Gamebuino is that it allows you to play sounds and musics in the background while you play your game without having to care about it. Just ask "play this sound", and forget about it, the library takes care of everything. But if you want to create sound effects or compose chiptunes, you should understand what happens under the hood. The goal of this article is to explain you how sound is generated and structured.

Layers

The sound is sliced in different layers in the Gamebuino sound library (just like in any tracker). We'll start from the deeper layer (wave form generation) and go up to "tracks".

Wave forms

PWM is used at 32 KHz to generate an analog output. To be able to play several sounds at the same time, the library simply generates one waveform per channel and add them. This is done using interruptions at a rate of 56 KHz. The waveform of each channel is changed once per frame, which is at 20 Hz by default. A waveform has the following characteristics :

  • Frequency
  • Wave form
    • Square wave, 50% duty cycle
    • Noise

Note : You can't directly access this layer of the sound generation. The value this characteristics take will depend on the above layers : instruments and notes.

Instruments

Instruments allow to play different kinds of sounds, not just plain square waves. It allows you to add variations in the sound of each note. An instrument is a succession of "steps", and each "step" has the following characteristics:

  • step duration in number of frames (from 0 to 63)
  • step waveform, it defines if this step should be played either using square wave or noise.
  • step volume (from 0 to 7), it allows to create a volume envelope.
  • pitch offset (from 0 to 63), to allow you to add arpeggio, glissando for example. We'll see later that you can also use commands to add effects to certain notes.

Each instrument has a "last step looping" attribute. When a note duration is longer than the instrument it's played with, the instrument will loop on the last X steps. Or won't loop if it's set to 0. Note: You can't directly access to this layer. You can't play an "instrument", you have to play a "note" using an "instrument".

Instrument sets

An instrument set is just an array of instruments you can attach to a channel using changeInstrumentSet(). The ID of the first instrument in the set is 0, the ID of the second instrument is 1, and so on. We'll see later how to select which instrument ID to use when you want to play a note.

By default, instrument 0 is plain square wave and instrument 1 is noise.

Notes

The "note" layer is the first you can directly access, using the function playNote(pitch, duration, channel). As you may guess, each note has the following parameters:

  • Pitch (from 0 to 58) is the ID of a predefined frequency from A#2 to D#8. If the pitch ID is equal to 63, the note is muted.
  • Duration (from 0 to 255) in number of frames, each frame lasts 1/20s by default. A duration of 8 at 20 frames/second corresponds to a quarter note at 150 BPM (the most common BPM in chiptunes according to this interesting video about chiptunes).
  • Channel (from 0 to 3) on which channel you want the note to be played. 0 for the first channel, 1 for the second channel, etc. By default there is only 1 channel so you should use the value 0. To increase the number of channels to up to 4, edit NUM_CHANNELS in arduino/libraries/gamebuino/settings.c.

Commands

Commands are used to alter the way the notes are played, arpeggio tremolo and stuff like that. A command remains active on all following notes as long as it's not passed again with a null value. You can manually pass a command using gb.sound.command(ID, X, Y, channel).

The command's ID defines which command to pass. Each command has an one or two parameters, X and Y. Unless specified X is from 0 to 31 and Y is from -16 to 15.

  • 0: Set note volume, X: volume (from 0 to 9)
  • 1: Select Instrument, X: instrument ID
  • 2: Volume slide, X: step duration, Y: step depth
  • 3: Pitch slide, X: step duration, Y: step depth
  • 4: Tremolo, X: step duration, Y: step depth

For example, gb.sound.command(3,4,-5) will make a descending arpeggio by of 5 semitone every 4 frame.

Patterns

Now that we know how to make instruments, play notes using these instruments, and alter these notes with commands, that'd be cool to be able to put all that together to make some actual music. That's why we'll use "patterns". A pattern is a mixed array containing notes and commands. It starts from the first note, and play the next one when the first reached its end. And of course it will execute commands if there are some.

Note : Pattern is the recommended layer level to create game sounds.

Pattern sets

A "pattern set" is simply an array of patterns. This way you can refer to a pattern using its ID. The first pattern's ID is 0, the second is 1, and so on.

You can assign a "pattern set" to a channel using changePatternSet(pattern, channel). It allows us to easily re-use pattern, which is pretty cool as it spares memory (and also because musicians a lazy).

Tracks

To be able to easily re-use patterns from a pattern set, we use "tracks". A track is an array of pattern IDs along with a pitch offset (or transposition) to apply to each of them when they are played. To play a track, simply call gb.sound.playTrack(track, channel).