-
Notifications
You must be signed in to change notification settings - Fork 1
Home
Here the basics of how to use Flizzer tracker are collected. Note that some things related to trackers in general will be omitted, so if you are new to the tracker things, consider digging into basics first somewhere else.
Note: Flizzer tracker possesses a lot of similarities with klystrack, because I have been developing a fork of it for more than a year now, so some pieces of code are copy-pasted there...
This is a pretty much generic (not including instrument program, because most chiptune trackers go "macros" way) 4-channel chiptune tracker with basic waveforms and effects. It's capabilities are on par with SID chip, although it has one more channel and independent filter on each channel... Okay I am carried away a bit. So it is a real tracker where you can do real multi-channel chiptune-like songs, as opposed to Zero Tracker and Music Beeper. The goal was to make a feature-rich program and fit it on crappy 128x64 pixels display and make the controls using 6 buttons (lol LSDJ moment). Well, it kinda works...
Tracker files (modules and settings config file) are in apps_data/flizzer_tracker
folder on SD card.
Hold Back to go to the menu where you can exit, load/save song, access settings and show help (actually a QR code lol). When in pattern editing mode, the pattern editor occupies all screen and holding Back brings you to pretty self-explanatory copypaste stuff menu. It treats pattern your cursor is on as current pattern. To exit the menu or help, press back once. You can't exit saving/loading keyboards without typing at least one character and pressing SAVE
(they are from flipper firmware and I can't tell them to exit when you press Back, sadly, so the only way is to type some garbage there).
In settings you can change the audio ouput -- internal means that it plays through internal piezo speaker, external means that the signal is on PA6 pin (to record it, connect it directly to LINE IN on your soundcard (better for me, less noise) or to mic input but through ~400 kOhm resistance).
The main screen consists of pattern editor (lower half), sequence editor (top left) and song info (top right). Using these, you edit the song parameters, the patterns, and tell the tracker in which order you want to play the patterns.
Your current position is indicated by tiny frame with curved borders. To actually edit something, press Ok briefly to switch into editing mode, where the frame is replaced by a box that inverts the color of any text that is inside. To exit edit mode, press Ok again.
To switch between editors, press Back briefly while not in editing mode.
To switch to instrument editor, press Back twice.
To play/stop the song, hold Ok.
Patterns are arranged side by side, and you can move your cursor using the arrow buttons across the patterns. Long press Up lets you jump to the beginning of the pattern, long press Down -- to the end of it. If you press Down on the bottommost pattern row, it will jump to the next pattern in sequence (if present), if you press Up on topmost -- to the previous pattern (if present). Note that the same pattern can be placed on several channels, so if you edit it in one channel it will update on other channels as well.
In editing mode you can edit the contents of pattern rows using Up and Down buttons for increasing/decreasing the value of selected parameter, which are grouped as follows:
Note that volume row volume values are relative to instrument volume.
Pressing Back deletes the contents of selected parameter. Long press Ok on note or octave columns to enter release note (triggers ADSR release; looks like long horizontal rectangle). You can press Down to change it to OFF
note (triggers release + immediately cuts the channel, setting the volume to zero).
Tracker remembers the last note, instrument and volume you placed, so if you placed G-4
and after that press Up on some row with empty note parameter, it will place G#4
, if you are on octave parameter -- G-5
. The same applies for instrument and volume, although it would not allow to place an instrument that does not exist.
Long press Left on any channel mutes or unmutes it (see the tiny icons on top of the pattern editor).
This is where you place patterns in a sort of matrix structure. When the tracker ends playing the pattern, it jumps to the next position of this matrix and starts playing patterns that are there.
The controls are the same, except deleting means placing 00
pattern index in current cell.
There is also looping available: long press Right to place start and end points, long press Left to clear them. The loop is labeled as square bracket:
Displays various parameters related to song. Editing works as in other places, although there is no deleting function.
Pattern position: displays the current pattern position. The second number is total pattern length and is changeable in 00-FF
range. Note: shrinking and then expanding the pattern again will erase all data beyond the pattern end after shrinking.
Sequence position: displays the current sequence matrix position. The second number is total sequence length and is changeable in 00-FF
range. Note: shrinking and then expanding the sequence again will NOT erase any data beyond the pattern end after shrinking.
Speed: displays (and allows to change) song speed (how many ticks it takes to advance one pattern row).
Rate: displays (and allows to change) song rate (how many ticks are there in one second). Default is 0x32
which is 50 in decimal, so tracker engine runs at 50 Hz.
Volume: displays (and allows to change) tracker master volume. Treat it as simply a volume slider. Large values will lead to clipping and signal inversion (since there is no clipping handling and the value is just overflowing).
Song: this field lets you edit the song name. Press Up when in editing mode to open the keyboard.
Inst: this field lets you edit the current instrument name and number.
Tune:
and Free:
: let you see how much RAM is occupied by the song and how much is free. Do not recommend to go as far as less than 30 kB of free memory since flipper may crash when connected to a PC or smartphone while the tracker is running. You use more memory by adding patterns and instruments or making the patterns longer. And also yeah, nod to first Amiga trackers.
This is where the infamous chiptune magic happens. Here you make the instruments using the controls on the left side and the program on the right side.
Hold Back to enter the menu where you can load and save instruments in separate .fzi
files.
Inst: the same as in song info above.
Note: sets the base note. How it works: the base note determines divergence from C-4
. So if base note is C-5
and you place C-4
in the pattern, the actual note will be C-5
. If base note is C-3
and you place C-4
in the pattern, the actual note will be C-3
.
Finetune: Lets you detune the actual frequency. Ranges from -128 to 127 which covers base - 0.5 semitones to base + 0.5 semitones. The frequency between adjacent notes is linearly interpolated.
Slide speed: How many 1/64th of a semitone the note is changed when slide (auto portamento) is used. The larger the value, the faster the slide.
Set PW: set pulse width on keydown. To the right is initial PW value (00-FF covers 100% to 0% range).
Set cutoff: set filter cutoff and resonance on keydown, also resets the filter.
Below are the waveforms from left to right.
Noise: C64-like noise. Pulse: pulse wave with variable pulse width. Triangle: triangle wave. Saw: sawtooth wave. Metal: metallic noise, can be used with or without the noise enabled. Basically loops over the same repeating part of the noise, thus producing somewhat tonal sound. Can detune on high notes. Sine: 256-step sine wave from a LUT. Has some aliasing because of that on low notes.
If you enable multiple waves at once, the result will be the wave of bitwise ANDed basic waves. This can lead to many new and interesting sounds, e.g. triangle + sawtooth produce an interesting fractal-shaped wave which sounds kinda like C64 tripulse wave.
Attack: envelope attack period. The higher the number, the longer the attack.
Decay: envelope decay period.
Sustain: envelope sustain level. FF
means max level (the peak between attack and decay phases).
Release: envelope release period.
Volume: instrument envelope volume.
If you have series of notes which are just placed one after another without gaps of silence between them, set attack and decay to 00
, sustain to FF
, and manipulate the volume with pattern effects or volume column (Amiga MOD style).
Filter: enables filter at instrument trigger.
Cutoff: filter cutoff. The filter is not stable and may output cracks and overflow at high cutoff values. This can kinda be fixed by cranking up the resonance but it would change sound texture, so experiment.
Resonance: filter resonance (additional amplification of cutoff frequency).
Type: NONE
means filter is initialized but not enabled. There are also lowpass, highpass, bandpass and all their possible combinations (as in SID chip).
Ring: enable ring modulation Source: ring modulation source channel (F = self).
Hard: enable oscillators' hard sync between channels. Source: hard sync source channel (F = self).
Slide retrig: retrigger on slide command. Restarts the instrument even if the note has slide command next to it.
Key sync: sync oscillator on keypress. Not recommended if you have series of notes which are just placed one after another without gaps of silence between them. This also enables keypress sync for vibrato and PWM LFOs.
Vibrato: enables vibrato.
Vibrato speed: speed of the vibrato.
Vibrato depth: depth of the vibrato. FF
means swing between -1
semitone and +1
semitone.
Vibrato delay: how many tracker engine ticks to wait from instrument trigger. After this number of ticks passes, the vibrato is enabled.
PWM: enables PWM (pulse width modification).
PWM speed: speed of the PWM.
PWM depth: depth of the PWM. FF
means swing between 0
semitone and FFF
pulse widths (0-100% range).
PWM delay: how many tracker engine ticks to wait from instrument trigger. After this number of ticks passes, the PWM is enabled.
No program restart: do not restart instrument program on instrument trigger.
Sample: enable DPCM sample playback. Sample signal is added to channel signal. OENV: override volume envelope. This means that sample will always play at max volume regardless of volume settings and ADSR envelope. It will, however, stop, if it ends (if not looped) or if your ADSR finishes its release phase. L: lock to base note. This means sample pitch will not change, so no matter what vibrato/portamento you use or what note you trigger the instrument with, it will always play at maximum sample rate.
Program period: How many ticks does it take to advance one program step.
Basically a stolen klystrack program, no more, no less.
Program is executed step by step. There are 16 steps in the program. If no special commands are placed, it just loops through its contents infinitely.
You can create loops, use jump command and a special HALT
-like command (see effects list below; they are entered by pressing Down on the lefmost digit of instrument program step):
Unknown commands are displayed as ?xx
. If you keep pressing Up after Zxx
command you will encounter such commands. Just delete it or go back to valid commands.
Sample editor is incomplete and is in dev version only.
Here you can import samples from wav files and adjust their settings.
Samples are NES-style DPCM samples so expect that they will sound much much worse than original files. DPCM samples are used because there is too little RAM space available.
Maximum sample rate is 44100 Hz, but sample can play at lower pitch. Max sample rate is at instrument base note, if note is lower sample will play slower. Sample obeys all vibrato/slide/portamento stuff (unless lock to base note flag is set in instrument editor). If note goes higher than instrument base note, sample plays at max sample rate.
Sample can be looped. Start and end points are available. If start point is not at the very beginning, then sample will play this part only once and then loop through the part between loop start and loop end points.
If your sample is large and you set loop start point relatively far from beginning, there will be some freeze time. It is because Flipper needs to calculate delta counter position on loop start point, which means it needs to "play" the sample from the very beginning to the loop start point (because that's how DPCM works: you need to go through all previous steps to know current delta counter value) which it tries to do as fast as it can (not bound by sample rate, obviously), but is still can take several seconds.
Speaking of slow things: wav import is very slow (12 seconds long sample (nearly the longest sample you can use) import takes 1+ minute) because it reads wav file 1 sample at a time which is very slow (see 1st line of SD card benchmark).
While I coded it so you can't import sample which wouldn't fit in RAM, you still may see Flipper crashing when trying to import long sample. This is probably because of fragmentation and I have no power here, so it is as it is. Pay attention to FREE:
thing on main screen and use samples in such a way that you have at least 20 KiB of RAM free.
So I suggest using samples for drums, short looped synth sounds or very short vocal things. You may layer samples with Flizzer Tracker synth sound, e.g. play snare sample and noise at the same channel so noise would make for lacking high frequencies in the sample (classic NES DPCM sample snare trick).
Wave: select current sample. Up to 32 samples can be used. To the right you can write sample name. Loop: make sample loop. Start: loop start point End: loop end point
You may notice that length is exactly 8 times larger than sample size in bytes. That's because 1 byte codes 8 consecutive steps of the sample, and start and end loop points are set relatively to steps, not the size in bytes.
You can use a bunch of effects in pattern and instrument program, most of them are interchangeable between them (unless stated otherwise).
Some of the commands loosely follow klystrack and original Amiga tracker "standards".
xx
, yy
= parameter to command
Command | Description |
---|---|
0xx |
set arpeggio note (final played note = played note + arpeggio note + vibrato etc.). 0F0 enables first external note, 0F1 sets second external note. Used as 0xy in pattern to set external arpeggio notes (x = 1st note, y = 2nd, so 047 with appropriate commands in instrument program makes a classic major chord arpeggio). |
1xx |
portamento up, xx/64th of a semitone per tick |
2xx |
portamento down, xx/64th of a semitone per tick |
3xx |
slide to a note with speed of xx/64th of a semitone per tick |
4xy |
vibrato with speed x and depth y |
5xy |
PWM with speed x and depth y |
6xx |
set pulse width |
7xx |
pulse width down |
8xx |
pulse width up |
9xx |
set filter cutoff |
axy |
Fade volume x steps up and y steps down, axx obviously does nothing (fade up and fade down cancel each out if x = y). Note that it caps volume at 0x80 even if before the volume was higher. |
bxx |
Set waveform. xx is a binary number where LSB is for noise, the next bit is for pulse etc. So b03 = pulse + noise. |
cxx |
Set channel volume. |
dxx |
Skip to next pattern, parameter is discarded |
e0x |
e00 disables filter, e0x where x is 1-F enables filter |
e1x |
fine portamento up (x/256th of a semitone, runs only in the first tick of program or pattern step, as all other exy effects where applicable) |
e2x |
fine portamento down |
e3x |
set filter mode |
e6x |
Works only in pattern! e60 marks loop begin, e6x where x is 1-F marks loop end. Loop runs x times. |
e9x |
Retrigger instrument at tick x-1 , so e90 does not work |
eax |
Fine volume down fade |
ebx |
Fine volume up fade |
ecx |
Cut note at tick x, same as OFF note but with optional tick offset |
edx |
Delay the note trigger for x ticks, x should be lower than (song_speed - 1) |
efx |
Phase rest on tick x (reset oscillator) |
fxx |
In pattern sets song speed, in instrument program sets its program period |
gxx |
Filter cutoff up |
hxx |
Filter cutoff down |
ixx |
Set filter resonance |
jxx |
Filter resonance up |
kxx |
Filter resonance down |
lxx |
Set envelope attack period. If envelope is in attack phase, its speed changes immediately |
mxx |
Set envelope decay period. If envelope is in decay phase, its speed changes immediately |
nxx |
Set envelope sustain level |
oxx |
Set envelope release period. If envelope is in release phase, its speed changes immediately |
pxx |
Works only in pattern! Restart instrument program |
qxx |
Set tracker engine rate (in Hz) |
rxx |
Set ring modulation source channel (FF = self) |
sxx |
Set hard sync source channel (FF = self) |
txx |
Portamento up xx semitones per tick |
uxx |
Portamento down xx semitones per tick |
vxx |
Set detune. v80 is no detune. v00 is minus one semitone. vff is just shy plus one semitone. |
Xxx |
Legato (like slide: no instrument retrigger but note changes immediately rather than smoothly) |
yxx |
Works only in instrument program! Set absolute arpeggio note (does not depend on what is base note, note in pattern etc.) |
zxx |
Trigger release (works like release note). xx is the tick when release is triggered (can't be larger than song_speed - 1 ) |
The following commands work only in instrument program! | |
<xx |
Loop begin, the parameter is discarded |
>xx |
Loop end, loop xx times |
^xx |
Go to (jump to) step xx |
:FF |
Program end. Its execution is stopped until it is restarted by command or new note trigger. |
But how does it work? Well, like flipper wav player! There is an array in RAM used as double buffer. DMA in circular buffer mode loops through the buffer and puts samples into TIM16 compare register which in turn generates a 60 kHz 10-bit PWM signal which is then routed either to internal shitty buzzer or on "3" (aka A6 aka PA6) pin you can find amongst GPIO pins. Connect it to your PC microphone input through a ~400kOhm resistance (or to line in without any resistors) to have clean sound. Don't plug in any usb cable while listening to/recording this sound, because the common ground or whatever introduces audible noise.
So, let's continue with hardware abuse. Obviously, I want to adjust sample rate of sound engine independently from PWM frequency, so for that I am using TIM1. It is the timer that triggers DMA transfers.
So, are we OK with that? Well, not quite... Because we also have a tracker engine running on its own rate! (typically 50-60 Hz) I could just approximate the rate through sound engine sample rate, but why would I go this miserable silly way, if I can... Yes, abuse third timer!
TIM2 is a unique one in Flipper ARM Cortex M4 main core because it has a 32-bit counter, so without any prescaler fuckery you have a 1-255 Hz range with quite a precision (ofc the master clock (64 MHz) is not itself so precise, but comparing wav recordings playback with my PC ones it's close enough for you to not notice until you launch playback on these two simultaneously). It's interrupt priority is one level higher than sound engine DMA interrupt, so effects timings precision is within one sample duration (and by default you have 44100 Hz sample rate, is it enough precision?).
So these three timers are working together to provide a smooth tracker operation. I am surprized it still has time to update the screen: even when I enable filters on all 4 channels, it still manages to have like 0.5 FPS.