SonaStream is the format for sound tracks in Sona. Each track is a sequence of
"events" (commands) which consist of an "opcode" byte and possibly extra bytes
as arguments (see below for the format of each event). The recommended file
extension is ".sona".

The documentation below is for Sona 0.50.


*** Load commands ***

$00 ... Load FM ch1 instrument
$01 ... Load FM ch2 instrument
$02 ... Load FM ch3 instrument
$03 ... Load FM ch3 instrument
$04 ... Load FM ch4 instrument
$05 ... Load FM ch5 instrument
$06 ... Load FM ch6 instrument

   Loads a new instrument into the given FM channel. The following byte is
   the instrument ID. There isn't any difference between $02 and $03.

$08 ... Load square ch1 instrument
$09 ... Load square ch2 instrument
$0A ... Load square ch3 instrument

   Loads a new instrument into the given square channel. The following byte
   is the instrument ID.

$0B ... Load noise instrument

   Loads a new instrument into the noise channel. The following byte is the
   instrument ID.


*** Key-on commands ***

$10 ... FM ch1 key-on
$11 ... FM ch2 key-on
$12 ... FM ch3 key-on (normal)
$13 ... FM ch3 key-on (special)
$14 ... FM ch4 key-on
$15 ... FM ch5 key-on
$16 ... FM ch6 key-on

   Starts a new note in the given FM channel. This is followed by one pitch
   value (except $13, which is followed by four pitch values in S1, S2, S3,
   S4 order).

$18 ... square ch1 key-on
$19 ... square ch2 key-on
$1A ... square ch3 key-on

   Starts a new note in the given square wave channel. This is followed by
   one pitch value.

$1B ... noise key-on

   Starts a new note in the noise channel. This is followed by one byte:
   
      $00 = periodic noise, high pitch
      $01 = periodic noise, medium pitch
      $02 = periodic noise, low pitch
      $03 = periodic noise, square ch3 pitch
      $04 = white noise, high pitch
      $05 = white noise, medium pitch
      $06 = white noise, low pitch
      $07 = white noise, square ch3 pitch

$1E ... PCM ch1 key-on
$1F ... PCM ch2 key-on

   Plays a sample in the given PCM channel. This is followed by one byte,
   which is the instrument ID.


*** Key-off commands ***

$20 ... FM ch1 key-off
$21 ... FM ch2 key-off
$22 ... FM ch3 key-off
$23 ... FM ch3 key-off
$24 ... FM ch4 key-off
$25 ... FM ch5 key-off
$26 ... FM ch6 key-off

   Stops the current note in the given FM channel (starts release). There
   isn't any difference between $22 and $23.

$28 ... square ch1 key-off
$29 ... square ch2 key-off
$2A ... square ch3 key-off

   Stops the current note in the given square channel (starts release).

$2B ... noise key-off

   Stops the current note in the noise channel (starts release).

$2E ... PCM ch1 key-off
$2F ... PCM ch2 key-off

   Stops playback on the given PCM channel.


*** Set pitch commands ***

$30 ... FM ch1 set pitch
$31 ... FM ch2 set pitch
$32 ... FM ch3 set pitch (normal)
$33 ... FM ch3 set pitch (special)
$34 ... FM ch4 set pitch
$35 ... FM ch5 set pitch
$36 ... FM ch6 set pitch

   Changes the pitch of the given FM channel (without starting a new note).
   This is followed by one pitch value (except $33, which is followed by four
   pitch values in S1, S2, S3, S4 order).

$38 ... square ch1 set pitch
$39 ... square ch2 set pitch
$3A ... square ch3 set pitch

   Changes the pitch of the given square channel (without starting a new
   note). This is followed by one pitch value.

$3B ... noise set pitch

   Changes the pitch of the noise channel (without starting a new note). This
   is followed by one byte, in the same format as for $1B.


*** Volume commands ***

$40 ... FM ch1 set volume
$41 ... FM ch2 set volume
$42 ... FM ch3 set volume
$43 ... FM ch3 set volume
$44 ... FM ch4 set volume
$45 ... FM ch5 set volume
$46 ... FM ch6 set volume

   Changes the volume of the given FM channel. There isn't any difference
   between $42 and $43. This is followed by a volume value.

$48 ... square ch1 set volume
$49 ... square ch2 set volume
$4A ... square ch3 set volume

   Changes the volume of the given square channel. This is followed by a
   volume value.

$4B ... noise set volume

   Changes the volume of the noise channel. This is followed by a
   volume value.


*** Panning commands ***

$50 ... FM ch1 set panning
$51 ... FM ch2 set panning
$52 ... FM ch3 set panning
$53 ... FM ch3 set panning
$54 ... FM ch4 set panning
$55 ... FM ch5 set panning
$56 ... FM ch6 set panning

   Changes the panning of the given FM channel. There isn't any difference
   between $52 and $53. The following byte is the new panning:
   
      $00 = mute
      $40 = right speaker only
      $80 = left speaker only
      $C0 = both speakers
   
   Note: FM ch6's panning also affects PCM output (since it's the same
   hardware channel).


*** LFO commands ***

$FB ... Set LFO

   Changes the LFO setting. The following byte is the new setting (same
   format as YM2612 register $22):
   
      $00 = LFO off
      
      $08 = 3.82Hz   $0C = 6.60Hz
      $09 = 5.33Hz   $0D = 9.23Hz
      $0A = 5.77Hz   $0E = 46.11Hz
      $0B = 6.11Hz   $0F = 69.22Hz

$58 ... FM ch1 set PMS/AMS value
$59 ... FM ch2 set PMS/AMS value
$5A ... FM ch3 set PMS/AMS value
$5B ... FM ch3 set PMS/AMS value
$5C ... FM ch4 set PMS/AMS value
$5D ... FM ch5 set PMS/AMS value
$5E ... FM ch6 set PMS/AMS value

   Changes the PMS and AMS values for the given FM channel. There isn't any
   difference between $5A and $5B. The following byte is the PMS/AMS value,
   in this format:
   
      00aa0ppp
      
      aa = AMS      00 = off
                    01 = 1.4 dB
                    10 = 5.9 dB
                    11 = 11.8 dB
      
      ppp = PMS     000 = off
                    001 = ±3.4 cent
                    010 = ±6.7 cent
                    011 = ±10.0 cent
                    100 = ±14.0 cent
                    101 = ±20.0 cent
                    110 = ±40.0 cent
                    111 = ±80.0 cent
   
   You can use PMS to do vibrato and AMS to do tremolo. Only operators with
   their AMON bit set will be affected.


*** Control commands ***

$F6 ... Replace instrument

   Replaces an instrument in the instrument list with an instrument embedded
   in the stream data itself. The format is as follows:
   
      3 bytes: size of instrument (in bytes)
      1 bytes: instrument ID
      ?? bytes: instrument data

$F8 ... Write YM2612 register (bank 1)
$F9 ... Write YM2612 register (bank 2)

   Writes directly to a YM2612 register. Two bytes follow: the register
   number and the value to write.

$FA ... Set BGM speed

   Changes the BGM speed. One byte follows, which specifies the speed
   multiplier divided by 32:
   
      60Hz × (value ÷ 32)
   
   *60Hz if you didn't change Timer B's value.

$FC ... Set loop point

   Sets this stream's loop point here.

$FD ... Go to loop point

   Jumps to this stream's loop point.

$FE ... Wait

   Waits ("rest"). The following byte is the number of ticks to wait (0 is
   interpreted as waiting for 256 ticks).

$FF ... Stop

   End of stream data.


*** VM commands ***

$C0 ... Move immediate (src) into variable (dest)
$C1 ... Move variable (src) into variable (dest)

   dest ← src
   
   Copies a value into a VM variable.
   
   Two bytes follow: the first byte is the destination (dest), the second
   byte is the source (src). The destination is always a variable number.
   For $C0 the source is the value to copy, for $C1 the source is another
   variable number.

$C2 ... Add immediate (src) to variable (dest)
$C3 ... Add variable (src) to variable (dest)

   dest ← dest + src
   
   Adds a value to a VM variable.
   Two bytes follow, in the same format as for $C0/$C1.

$C4 ... Substract immediate (src) from variable (dest)
$C5 ... Substract variable (src) from variable (dest)

   dest ← dest - src
   
   Substracts a value from a VM variable.
   Two bytes follow, in the same format as for $C0/$C1.

$C6 ... AND immediate (src) with variable (dest)
$C7 ... AND variable (src) with variable (dest)

   dest ← dest & src
   
   Does a binary AND between a value and a VM variable.
   Two bytes follow, in the same format as for $C0/$C1.

$C8 ... OR immediate (src) with variable (dest)
$C9 ... OR variable (src) with variable (dest)

   dest ← dest | src
   
   Does a binary OR between a value and a VM variable.
   Two bytes follow, in the same format as for $C0/$C1.

$CA ... XOR immediate (src) with variable (dest)
$CB ... XOR variable (src) with variable (dest)

   dest ← dest ^ src
   
   Does a binary XOR between a value and a VM variable.
   Two bytes follow, in the same format as for $C0/$C1.

$CC ... Negate variable

   dest ← -dest
   
   Flips the sign of a VM variable (two's complement). One byte follows,
   which is the variable number. This is the same as doing $CD nn $CE nn
   (nn = variable number).

$CD ... NOT variable

   dest ← ~dest
   
   Flips all the bits of a VM variable. One byte follows, which is the
   variable number. This is the same as doing $CA nn $FF (nn = variable
   number).

$CE ... Increment variable by 1

   dest ← dest + 1
   
   Increments a VM variable by 1. One byte follows, which is the variable
   number. This is the same as doing $C2 nn $01 (nn = variable number).

$CF ... Decrement variable by 1

   dest ← dest - 1
   
   Decrements a VM variable by 1. One byte follows, which is the variable
   number. This is the same as doing $C4 nn $01 (nn = variable number).


*** Pitch argument format ***

   Pitch value format is one or two bytes as follows:
   
      $00~$5F = 0yyyyxxx            Absolute pitch (coarse)
      $70~$7F = 0111zzzz 0yyyyxxx   Absolute pitch (fine)
      $80~$DF = 1yyyy0xx            Relative pitch (coarse, up)
                1yyyy1xx            Relative pitch (coarse, down)
      $F0~$FF = 1111zzzz 0yyyyxxx   Relative pitch (fine, up)
                1111zzzz 1yyyyxxx   Relative pitch (fine, down)
      
      xxx     = octave (0~*)
      yyyy    = semitone (0~11)
      zzzz    = semitone fraction (0~15)
   
   * Octaves for FM are 0~7, for square are 0~5.
   * Fraction is measured in 1/16th semitone units (6.25 cents).
   * $80 can be used for key-on and set pitch with FM3 special to avoid
     changing the pitch for some operators.


*** Volume argument format ***

   Volume value format is one byte as follows:
   
      $00~$7F = 0vvvvvvv   Absolute volume
      $80~$BF = 10vvvvvv   Relative volume (increment attenuation)
      $C0~$FF = 11vvvvvv   Relative volume (decrement attenuation)
      
      vvvvvvv = attenuation
   
   Attenuation is always in -0.75dB steps, even for PSG channels.
