Table of Contents
A Guide to Sound and Music on the SD-8516
Introduction
Welcome to your exciting journey into sound! The SD-8516 offers a rich array of sound and music playing capabilities, for you to discover.
Inside you will find detailed information and examples for three main kinds of sound and music:
- 1. Stellar Basic's PLAY statement
- 2. Details on programming the SD-450 on-board synthesizer
- 3. How to use the SPC-1000 and Star Tracker for sample-based sounds
1. Stellar BASIC's PLAY statement
Both Assembly and BASIC programmers can use the MML system, either via BASIC's PLAY statement, or in assembly via INT 11h music services.
Notes
Basic's PLAY statement is extremely similar to the standard BASIC PLAY statement found in typical BASIC implementations.
10 PLAY "A"
This will play the note “A” in the default waveform. You can play any note from A to G. To play a sharp, try A# or A+. To play a flat, try A-. This notation is fun and easy to remember!
The next thing you might want to do is change the length of the notes. The default length is quarter note. To play in a different length you simply add the length of the note to the note:
10 PLAY "C E8 E8 E8 F"
After playing E as an 8th note, F is played again as a quarter note. The time is essentially a fraction of a whole note; you can try playing 16th notes, 32nd notes, 64th notes, or as you like.
Rest is R:
10 PLAY "C E8 R8 E8 F"
Tempo
You can change tempo with the T command. The default tempo is 120:
10 PLAY "T160 C8 R8 E8 R16 E16 F."
This spritely little toot shows the Tempo command (T). Did you notice anything special or new here? Yes, there's a dotted note. Dotted notes are musical dot notation, where the note is held for an extra half length.
Default Note Length
If you want to change the note length to something other than quarter note, use the L command.
PLAY "L8"
This will change the default note length to an 8th note.
PLAY "MS A B C"
- The MS command makes the following notes play staccato.
- The ML command makes the following notes play legato.
- The MN command returns note playing to normal.
Octave
You can change octaves easily. > and < play up and down one octave, while On sets the octave:
10 PLAY "E16 E16 E16 R16 < G16 G16 G16 R16 > C16 D16 C16 D16 C"
This is starting to sound like music!
Waveform Synth
You can control the waveform being used via the W command.
PLAY "W0 C D E"
This plays nothing because 0 means gate-off (mute). However, W with one of the following will give you a different sound:
W1 -- Square waveform (default) W2 -- Triangle waveform W3 -- Sawtooth waveform W4 -- Sine waveform W5 -- PWM waveform (variable width)
You can set the pulse width with the extended XP command.
PLAY "W5 XP100 C XP300 D XP900 E XP2000 F XP2700 G XP3500 A"
Polyphonic sound
The MML system used by BASIC enables polyphonic (multivoice) sound. To play multivoice sound, use the XV command to change voices, and the XW command to sync all voices together.
10 REM SETUP: Tempo 132, L4 (quarter note default), MN (normal length notes)
20 PLAY "T132 L4 MN"
30 REM Main melody (violins)
40 PLAY "XV1 O5 V13 XW G4 R8 D8 G4 R8 D8 | G8 D8 G8 B8 >D4 R4 | C4 R8 <A8> C4 R8 <A8> | C8 <A8 F#8 A8 D4 R4"
50 REM Bass / cello foundation
60 PLAY "XV2 O3 V9 XW G4 R8 D8 G4 R8 D8 | G8 D8 G8 B8 >D4 R4 | C4 R8 <A8> C4 R8 <A8> | C8 <A8 F#8 A8 D4 R4"
The XW shown above is insurance that the channels will play in sync. Normally there shouldn't be an issue if you play two or three lines right after each other, but it may become more necessary for longer, multivoice songs.
When you RUN this program, it plays the music and immediately returns to the READY prompt. This is because it is playing music in the background.
Other Commands
- XC - clear current voice queue
- XT - Tuning. Ex. XT415 sets A=415hz for baroque-authentic tuning.
Demo Song: Forest
Here's a common two-voice arrangement of Forest from Ultima 4.
10 PLAY "XV1 MS W5 XP2500 O4 L16 T80"
20 PLAY "XV2 MN W5 XP3500 O4 L16 T80"
30 PLAY "XV1 XW C < B"
35 PLAY "XV2 XW R < R"
40 PLAY "XV1 MN A G MS A B MN > C8 MS C < B"
45 PLAY "XV2 < A4 F8 G8"
50 PLAY "XV1 MN A G MS A B MN > C8 MS C < B"
55 PLAY "XV2 A4 F8 G8"
60 PLAY "XV1 MN A G MS A B MN > C C- < A G"
65 PLAY "XV2 MN A4 F8 D8"
70 PLAY "XV1 A8 E8 < A8"
75 PLAY "XV2 A8 < R8 D8"
I've added MS and MN to try and bring out a little texture to a stringed-type instrument. This was taken from the sheet music in about 20 minutes.
PLAY for Assembly
You can use PLAY in assembly too. Just use the music services library, INT 11h. Here's the same demo song by Mozart as above, but for the Assembler:
mozart_demo:
LDELM @play_setup
LDAH $52
INT $11
LDELM @play_1
LDAH $52
INT $11
LDELM @play_2
LDAH $52
INT $11
RET
play_setup:
.bytes "T132 L4 MN", 0
play1:
; Main melody (violins)
.bytes "XV1 O5 V13 XW G4 R8 D8 G4 R8 D8 "
.bytes "G8 D8 G8 B8 >D4 R4 "
.bytes "C4 R8 <A8> C4 R8 <A8> "
.bytes "C8 <A8 F#8 A8 D4 R4", 0
play2:
; Bass / cello foundation
.bytes "XV2 O3 V9 XW G4 R8 D8 G4 R8 D8 "
.bytes "G8 D8 G8 B8 >D4 R4 "
.bytes "C4 R8 <A8> C4 R8 <A8> "
.bytes "C8 <A8 F#8 A8 D4 R4", 0
Here are all the MML commands you can use in Assembly:
From INT 11h:
- AH=$50: MML_STOP, Stop MML playback
- AH=$51: MML_START, Resume MML playback
- AH=$52: MML_PLAY - Parse and queue MML string
- AH=$53: MML_CLEAR - Clear all MML state and silence voices
2. The SD-450 Synthesizer Sound Chip
Your new SD-8516 comes with an on-board synthesizer that you can use to program multivoice sound effects and audio. It is mainly served by the INT 11h Sound Services library. In fact, this is the same system that is controlled by Stellar BASIC's PLAY statement; that is why the Assembly version uses INT 11h to control the player. Now it's time to introduce the other interrupts that help you control it.
It should be noted this is a general overview only. Please refer to the SD-8516 Programmer's Reference guide Appendix 5 Sound System for detailed programming information regarding the SD-450.
Programming the SD-450 directly
This is the original sound system for the SD-8516, the system all the other ones are based on. It has two parts; the SD-450 itself and Star Tracker system 1 which is used for song playback.
When implemented, this is the method you will use to create custom synth waveforms. This is slated for V2.
To play a note directly, you simply load the note frequency and open the waveform gate:
.equ SOUND0_FREQUENCY $01EF80
.equ SOUND0_GATE $01EF82
; Middle C = C4 = 262 Hz
.equ NOTE_C4 $112B ; 262 Hz / 0.0596 ≈ 4395
.equ NOTE_LEN $83 ; 131ms default note length
LDA @NOTE_C4 ;; frequency for C4
STA [@SOUND0_FREQUENCY] ;; set sound 0 frequency
LDAL @GWAVE1 ;; waveform 1 (square)
STAL [@SOUND0_GATE] ;; set gate to waveform
LDAH $48
LDC @NOTE_LEN ;; wait for note_length
INT 0x11
; Small delay for release envelope
LDAH $48
LDC $0032 ; 50ms for release to finish
INT 0x11
; Turn off sound
LDAL $00
STAL [@SOUND0_GATE]
This kind of memory-mapped programming appeals to some, but let's be honest, it's clunky. Playing any amount of real music like this tends to bloat the program – but it is great for one-off early-era sound effects.
wait_ms
The Assembly programmer will find great utility out of the library's sleep() utility, wait_ms.
LDAH $48 ; wait_ms LDC #50 ; wait for 50ms INT 0x11
Using BASIC's MML system
The recommended way to play notes and sound effects is using Stellar BASIC's MML system which was built on top of the above manual gate control.
For example, the ROBOTS.SDA game plays a single note to make an electronic-sounding BEEP.
robot_beep:
LDELM @robot_sfx
LDAH $52
INT $11
robot_sfx:
.bytes "T120 W1 V5 O2 L24 B", 0
This method is explained in detail in section 1. However, for historical reasons it is important to discuss the format for Star Tracker System 1, before dealing with System 2.
Star Tracker System 1
The Star Tracker format was designed to be a memory-aware tracker format for the SD-450 waveform-generator synth chip. Other tracker formats seemed to require too much memory for a simple oscillator-based synth. Later, the MML system (above) replaced this, but it is important to understand before dealing with sample playback (system 2).
; Initialize sound system
LDAH $40 ; init_ssl
INT 0x11
; Load our song data into the music player
;; This sets INT 11h's SONG_PTR to ELM.
LDELM @note_data
LDAH $07
INT 0x11
; Start playback: set state and prime the clock
;; This sets MSTATE_PLAYING and MP_NEXT_TIME for song timing.
LDAH $05
INT 0x11h
; Blocking playback loop: poll until song finishes
spin_wait_loop:
YIELD ; helpful in a spin-wait loop
LDAH $00
INT 0x11 ; poll music player (so it keeps playing!)
LDELM @MP_STATE
LDAL [ELM]
CMP AL, @MSTATE_PLAYING ; If player state is 'playing', loop.
JZ @spin_wait_loop
; Done
LDAH $43 ; stop_all_channels
INT 0x11
note_data:
; Tick 1: setup + note
.byte $01, $00 ; tick index 1
.byte $F1, $78, $00 ; set tempo = 120ms
.byte $F2, $04 ; min_note = 4 (sixteenth)
.byte $01, $17, $2F, $01 ; $01 (voice 1) G4 ($2F17) W1 ($01)
.byte $00
; End of song
.byte $00, $00
This may seem like a lot of work for just one note. It's true, but this format is designed for longer songs. You also have the ability to load and save your song data:
; ============================================================================ ; AH=0Ah - LOAD a Music File ; Input: BLX = desired destination address (24-bit) ; C = max bytes to load ; Output: ELM = pointer to loaded data (or 0 on cancel/error) ; ============================================================================ ; ============================================================================ ; AH=0Bh - SAVE a Music File ; Input: ELM = pointer to song data ; B = length of song data in bytes ; Output: None ; Notes: Sends data for download ; ============================================================================
These are ancient code functions from the first version of the system; they do not deal with the DATA-sette system (DLOAD and DSAVE). But, at least they let you load and save the binary song data.
It is interesting that you can also use these functions to save and load arbitrary game data such as sprites, maps, saved game files, … but let's keep that a secret between you and me for now, ok? :)
3. Programming the SPC-1000
The SPC-1000 ASU represents the pinnacle of SD-8516 sound and music programming. While the SD-450 and 850 (8 voice version, standard in most regions) is perfect for era-authentic music and sound effects in games, arcade board and console manufacturers will be most interested the SPC-1000's sample playback capabilities.
The SPC-1000 is a refinement of the common ADPCM-based sample playback chips used in many famous consoles of the 80s and 90s. It pairs well with the PPU to form the XY-85 – a high-end arcade board experience similar to a SNK Neo Geo class machine, or the famous Sega X-board.
Loading and playing a sample
To play a sample, you must first load it. Make sure the sample is in the current directory or the filename points to it, as this code is hot off the press and there is no error checking!
; ============================================================================
; Load and Play a Sample Demo #1
;
; Loads heylisten2.wav from the current directory into slot 0
; and plays it once.
; ============================================================================
.address $C000
start:
; ------------------------------------------------------------------
; Step 1: load heylisten2.wav into slot 0
; ------------------------------------------------------------------
LDA $0211 ; asu_load_sample
LDBL #0 ; slot 0
LDELM @filename ; ELM = pointer to filename
INT 0x03 ; Call ASU (AH=$02, AL=command)
LDAH $40 ; Wait for E flag (async load)
INT 0x15
; ------------------------------------------------------------------
; Step 2: verify the slot loaded successfully
; ------------------------------------------------------------------
LDA $0213 ; asu_query_slot
LDBL #0 ; slot 0
INT 0x03 ; Call ASU (AH=$02, AL=command)
CMP AL, #0 ; AL = 0 means not loaded (load failed)
JZ @load_failed
; ------------------------------------------------------------------
; Step 3: play it
; ------------------------------------------------------------------
LDA $0220 ; asu_play_sample
LDB #0 ; slot 0
LDC $80 ; volume = 50%
LDI #0 ; rate = default (1.0x)
LDJ #0 ; flags = 0 (no loop)
INT 0x03 ; Call ASU (AH=$02, AL=command)
; ------------------------------------------------------------------
; Step 4: exit
; ------------------------------------------------------------------
RET
load_failed:
HALT
; ============================================================================
; Data
; ============================================================================
filename:
.bytes "heylisten2.wav", 0
With the power to play back samples, new doors open up for game and music programming on the SD-8516.
But with such power, surely there is a song format included as well? Yes, just as there is Star Tracker System 1 for the SD-450 synth chip, there is Star Tracker System 2 for the SPC-1000.
Star Tracker System 2
Star Tracker System 2 deals with sound sample playback. It is a custom internal format based around the Amiga MOD format, as well as later developments such as Scream Tracker, Fast Tracker, Impulse Tracker, and more. Schism tracker is probably the most beloved modern incarnation of this.
The goal of Star Tracker System 2 is to be a complete tracker format for games and music programming. However, it is under construction. Not everything may be working yet! Please report any bugs you find.
Star Tracker Text Format
Star Tracker Text (.stt) files are plain text. They can be edited in any text editor, version-controlled meaningfully (diffs are readable).
Like most modern trackers (Schism tracker) it uses a text-based export format. Star Tracker is a very new system, so it does not have as many features, but the format is intended to be immediately recognizable to anyone familiar with tracker software.
A minimal example
.songname "Hello" .tempo 125 .speed 6 .channels 4 .inst 1 piano.wav .sequence 0 .endsequence .pattern 0 32 R0: |C-4 01 40 ...|... .. .. ...|..........|..........| R4: |D-4 01 40 ...|... .. .. ...|..........|..........| R8: |E-4 01 40 ...|... .. .. ...|..........|..........| R12: |F-4 01 40 ...|... .. .. ...|..........|..........| R16: |G-4 01 40 ...|... .. .. ...|..........|..........| R32: |^^^ .. .. ...|... .. .. ...|..........|..........|
This declares a song called “Hello” at tempo 125, speed 6, with 4 channels and one instrument (piano.wav). The pattern is 32 rows long; rows not listed are empty. Channel 0 plays a C major scale fragment ending on a held G that is cut at row 32. Note that although “… .. .. …” is canonical, the format allows for an abbreviated forms with at least ten dots, with or without spaces. However, filled cells must follow the format as shown.
Structure
A Star Tracker file consists of:
- Song-level directives (
.tempo,.speed,.channels, etc.) - Instrument declarations (
.inst) - A sequence – the order in which patterns play
- One or more patterns – the actual note data
Directives appear in any order, but it is conventional to put song metadata first, then instruments, then sequence, then patterns. Patterns may be in any order; the sequence determines play order.
Comments
Lines beginning with ; are comments and ignored by the parser. Inline comments (after content on a line) also begin with ;
.tempo 125 ; reasonable medium tempo .speed 6 ; six ticks per row
Only ; is recognized as a comment character. This matches the SD-8516 assembly convention.
Song-level commands.
These directives are valid for the entire song.
.songname
The name of the song.
.songname "Boss Battle Theme"
.tempo
The tempo, controlling tick rate. Range: 32 to 255. Default: 125.
The relationship between tempo and tick rate is the standard tracker formula:
tick_duration_seconds = 2.5 / tempo
This is historical and based on the Amiga's 50hz refresh rate used in MOD programming. Tempo 125 produces 50 ticks per second (the PAL Amiga reference rate); tempo 250 produces 100 ticks per second. The number is not a literal BPM, but at 6 ticks per row and 4 rows per beat, .tempo n approximates n BPM. Other speeds give different real BPMs.
.tempo 140
.speed
The number of ticks per row. Range: 1 to 31. Default: 6.
At speed 6, each row lasts 6 ticks. Lower speeds make rows pass faster (shorter notes); higher speeds make them last longer. With the standard convention of 4 rows per beat, speed 6 gives quarter notes that span 4 rows × 6 ticks = 24 ticks per beat.
.speed 4 ; faster, more dynamic feel
.channels
The number of channels in the song. Range: 1 to 16. Default: 4.
This is the channel count for every pattern in the song. Patterns cannot have more or fewer channels than declared here; cells in unused channels are simply left empty.
.channels 8
.globalvol
The global volume multiplier, applied to all channels. Range: 0 to 64. Default: 64 (full).
.globalvol 48 ; quieter overall mix
Instruments
Each instrument is declared with an .inst directive:
.inst n filename.wav
Where n is the instrument number (1-64 and filename.wav is the sample to load from d-tank. The .sfz companion file (if present alongside the .wav) provides metadata: base note, fine tune, loop points, default volume. If not present, it just plays the .wav as-is.
.inst 1 piano.wav ; loads piano.wav and (if present) piano.sfz .inst 2 strings.wav .inst 3 bass.wav .inst 4 hihat.wav
Instruments are 1-indexed because instrument 0 is reserved as a sentinel meaning “no change” in cell data. The first usable instrument is always 1.
There is no required upper limit, but practically, 64 is a very 'retro' number. 99 fits the cell representation. If more are needed maybe I'll switch it to hexidecimal.
The sequence
The sequence (or “order list”) is the list of pattern numbers played in order. This is read as one number per line and/or comma delimited numbers if listed on one line.
.sequence 0 1 2 1 3 .endsequence
Each line is a pattern number. The sequence plays these patterns in order, then ends. A pattern may appear multiple times to repeat it.
For very short sequences, here is an example of the comma-delimited version:
.sequence 0, 1, 2, 1, 3 .endsequence
Both forms are equivalent.
Patterns
A pattern is the actual note data. It is declared with:
.pattern n r
Where n is the pattern number (referenced by the sequence) and r is the row count for this pattern (typically 32 or 64; can be any positive value). Different patterns can have different row counts.
.pattern 0 64 ; pattern 0 has 64 rows
Following the .pattern directive are the row data lines, until either:
- The next
.patternor other directive - End of file
Row data format
Each row in the pattern is one line. Rows may be explicitly numbered with R#: or implicitly sequential.
.pattern 0 16 R0: |C-4 01 40 ...|..........|..........|..........| R4: |D-4 01 40 ...|..........|..........|..........| R8: |E-4 01 40 ...|..........|..........|..........|
Rows not listed are empty. The implicit form with no R#: prefix) increments from the previous row.
.pattern 0 4 |C-4 01 40 ...|..........|..........|..........| |D-4 01 40 ...|..........|..........|..........| |E-4 01 40 ...|..........|..........|..........| |F-4 01 40 ...|..........|..........|..........|
This places the four cells on rows 0, 1, 2, 3.
In practice, explicit numbering is recommended for sparse patterns because it's shorter and clearer.
.pattern 0 32 R0: |C-4 01 40 ...|... .. .. ...|G-2 03 30 ...|..........| R8: |... .. .. ...|D-4 02 40 ...|... .. .. ...|..........| R16: |E-4 01 40 ...|... .. .. ...|G-2 03 30 ...|..........| R24: |F-4 01 40 ...|D-4 02 40 ...|... .. .. ...|..........|
For dense patterns (drum machines, busy lead lines), implicit sequential rows may be cleaner. Use whichever fits the music.
Cell format
Each cell is NNN II VV EXX (13 characters):
NNN II VV EXX ^^^ ^^ ^^ ^^^ note inst vol effect
| Field | Width | Empty | Description |
|---|---|---|---|
NNN | 3 | … | Note (e.g., C-4, D#5, ^^^ for cut, === for off) |
II | 2 | .. | Instrument number in hex (01-63) |
VV | 2 | .. | Volume in hex (00-40) |
EXX | 3 | … | Effect letter + 2 hex digit parameter |
Cells are separated by |. Channels are positional. The first cell after the leading | is channel 0, the next is channel 1, and so on. The trailing | is required.
Notes
Note names use scientific pitch notation; middle C is C-4. The format is:
NNN ^^^ | ^- octave (0-9) | ^- pitch letter and accidental (C-, C#, D-, D#, E-, F-, F#, G-, G#, A-, A#, B-)
The - after a natural note (C, D, E, F, G, A, B) is a placeholder so that all notes are exactly 3 characters. Sharps use #. Flats are not standard (write D#- rather than Eb-, etc.) but I will add support for them later.
| Note | Encoded |
|---|---|
| C-4 | C-4 |
| C-sharp 4 | C#4 |
| D-4 | D-4 |
| middle C | C-4 |
| Concert A | A-4 |
| Cut (silence) | ^^^ |
| Note off (release) | === |
| Empty | … |
The valid octave range is 0-9 (covering tracker notes 1-119). Note C-0 is the lowest, B-9 is the highest.
Instruments
Two hex digits, 01 through 63 (1-99 decimal), or .. for empty (no change).
When a cell has only an instrument with no note, it changes the active instrument on that channel without retriggering. When a cell has both, the new note is played using the new instrument. When a cell has only a note (instrument is '..'), the note plays using the channel's previously-set instrument.
Volume
Two hex digits, 00 through 40 (0-64 decimal), or .. for empty.
Volume 40 is full volume; 00 is silent. Most music uses values from 20 to 40. Values are linear (not logarithmic), so 20 is half the amplitude of 40, not half the perceived loudness.
A volume change in a cell takes effect immediately when the row plays — even when there is no new note. This is how you do volume swells and fades on sustained notes.
Effects
One letter (A-Z) followed by two hex digit parameter, or … for empty.
Effects modify how a note plays or affect playback in other ways. The full effect set is documented separately; the most common are:
| Effect | Letter | Description |
|---|---|---|
| Set volume | C | Cxx set volume to xx |
| Set speed | F | Fxx set speed/tempo |
| Pattern break | D | Dxx jump to next pattern at row xx |
| Pattern jump | B | Bxx jump to order index xx |
| Volume slide | A | Axx slide volume by xx per tick |
| Vibrato | H | Hxy depth y, speed x |
| Tone portamento | G | Gxx slide pitch toward last note |
| Arpeggio | J | Jxy alternate root, root+x, root+y |
The effect letter is case-insensitive in source files but conventionally uppercase. The parameter is hex.
Some examples:
C40 ; set volume to 64 (full) F06 ; set speed to 6 D00 ; jump to next pattern, row 0 D10 ; jump to next pattern, row 16 (hex 10) H85 ; vibrato, speed 8, depth 5 A02 ; slide volume down by 2 per tick
Empty effect is … (three dots).
Example Song
; SD-8516 sample test song ; A short C major progression with bass .songname "Major Test" .tempo 125 .speed 6 .channels 4 .inst 1 piano.wav .inst 2 bass.wav .sequence 0, 1, 0 .endsequence .pattern 0 32 ; verse pattern: piano melody, bass on beats 0 and 16 R0: |C-4 01 40 ...|..........|C-3 02 40 ...|..........| R4: |E-4 01 40 ...|..........|... .. .. ...|..........| R8: |G-4 01 40 ...|..........|... .. .. ...|..........| R12: |C-5 01 40 ...|..........|... .. .. ...|..........| R16: |G-4 01 30 ...|..........|G-2 02 40 ...|..........| R20: |E-4 01 30 ...|..........|... .. .. ...|..........| R24: |C-4 01 30 ...|..........|... .. .. ...|..........| R28: |^^^ .. .. ...|..........|^^^ .. .. ...|..........| .pattern 1 32 ; chorus pattern: louder, with effect R0: |C-5 01 40 C40|... .. .. ...|C-3 02 40 ...|..........| R4: |E-5 01 40 ...|G-4 01 30 ...|... .. .. ...|..........| R8: |G-5 01 40 ...|C-5 01 30 ...|G-2 02 40 ...|..........| R12: |C-6 01 40 ...|E-5 01 30 ...|... .. .. ...|..........| R16: |... .. .. ...|... .. .. ...|F-2 02 40 ...|..........| R20: |... .. .. ...|... .. .. ...|... .. .. ...|..........| R24: |G-5 01 40 ...|C-5 01 30 ...|G-2 02 40 ...|..........| R28: |^^^ .. .. ...|^^^ .. .. ...|^^^ .. .. ...|..........|
- Plays pattern 0 (verse), then pattern 1 (chorus), then pattern 0 again
- Pattern 0 has piano on channel 0 and bass on channel 2
- Pattern 1 adds piano harmony on channel 1 and uses an explicit
C40effect on the first beat (set volume to 64 – redundant since the volume column already says 40, but illustrative)
Round-trip workflow
The .stt format workflow is: load, edit, save, (then) load produces the same song (although empty rows might change format, this can be added as a configuration option later).
Typical workflow
1. Compose by hand: write .stt directly in a text editor. Useful for short songs and learning the format.
2. Compose in OpenMPT/Schism: use the tracker software's editor, then export as text. The export format may need light translation to .stt syntax (column widths, comment characters); a simple converter could handles this.
3. Edit existing: load an .stt file, modify cells in any editor, save. Diffs are readable in version control.
Option B? Generate programmatically: write code that emits .stt text. Useful for procedural music or pattern variations. Can possibly convert MIDI or actual tracker files (basically an export-to-ST function).
Pro Tip: The parser is forgiving about whitespace and comments but strict about column widths within pattern rows. If a pattern doesn't parse, the most common cause is a misaligned cell.
V2.1 roadmap
The format as described here covers the basics. In a future V2.1 we can have:
- Instrument metadata in the file. Currently loaded in separately from a
.sfzcompanion file.
- Multi-effect cells. A cell can have an L-note which links it to a channel (in instrument no.) tp allow for multiple effects at once.
- Inline sample data.
.instdirectives only references external files. Eventually, the file format may support encoded sample data inline, or maybe we can come up with a native format at that point.
- Per-channel default panning, volume, etc. These will likely be added as per-channel or per-pattern directives.
- Comments for rows and instruments. Some trackers show text when playing. Something like that.
Loading and playing .stt files
under construction – more to come!
