User Tools

Site Tools


music_file_format

Music File Format

How to do it?

Proposal 1: Text file

  • on a row: CWND CWND CWND CWND
  • “Channel, Waveform, Note, Duration” ex 12G4Q is channel 1, waveform 2, note G4, quarter note
  • Can have commands like TEMPO = 90 and ROW=HalfNote (meaning 180 rows/minute for Tempo=90)
    • This would require auto-shutoff of notes/a polling player (could be done using Int 11h music timers)

Proposal 2 (Data-File)

MUSIC FILE FORMAT v1.0

  • Header (16 bytes):
    • +0: [2] Magic: “SD” ($53 $44)
    • +2: [1] Version (1)
    • +3: [1] Flags
    • +4: [2] Tempo (ms per row)
    • +6: [1] Number of instruments
    • +7: [1] Number of patterns
    • +8: [1] Song length (orders)
    • +9: [7] Reserved
  • Instrument Table (10 bytes each):
    • +0: [1] Instrument ID
    • +1: [1] Instrument Type
  • Waveforms:
    • +2: [1] Waveform (WAVE_xx constant)
    • +3: [1] Pulse width / duty cycle
    • +4: [1] Attack
    • +5: [1] Decay
    • +6: [1] Sustain
    • +7: [1] Release
    • +8: [1] Default volume
    • +9: [1] Reserved
  • Samples:
    • +2: [1] address (bank)
    • +3: [1] address (low byte)
    • +4: [1] address (high byte)
    • +5: [1] Volume
    • +6: [1] Playback speed
    • +7: [1] reserved
    • +8: [1] reserved
    • +9: [1] reserved

NOTE: need to do more research on what data we should include with samples. How does SNES/etc. do it?

  • Order List (1 byte each):
    • Pattern numbers in playback order
    • Terminated by $FF ($FFFF or $0000?)
  • Patterns:
    • Each pattern is a sequence of rows
    • Each row is a sequence of channel commands
    • Row terminated by $00
    • Pattern terminated by $FF (see above)

Row Command Format

Command Byte:

  • Bits 7-6: Channel (0-3)
  • Bits 5-4: Command type
  • Bits 3-0: Depends on command type

OR

  • Command Byte
  • Channel Byte
  • Data Word + Data Word + Data Word (Reserved)

Command Types:

  • 00 = Note On (3 bytes total)
    • [Cmd] [Note] [Instrument]
  • 01 = Note Off (1 byte)
    • [Cmd]
  • 10 = Set Volume (2 bytes)
    • [Cmd] [Volume]
  • 11 = Effect (3 bytes)
    • [Cmd] [Effect Type] [Effect Param]

Note data

  • $00 = Rest (no change)
  • $01-$60 = Notes (C0 to B7)
  • $61 = Note off
  • $FF = End of pattern
  • Note calculation:
    • Note = (Octave * 12) + Semitone + 1
    • C4 = (4 * 12) + 0 + 1 = 49 = $31
    • A4 = (4 * 12) + 9 + 1 = 58 = $3A

Example Data File

; ============================================================================
; Simple test song: C-E-G-C chord progression
; ============================================================================

music_test_song:

; Header (16 bytes)
music_header:
    .bytes "SD"             ; Magic
    .byte 1                 ; Version
    .byte 0                 ; Flags
    .word 250               ; Tempo: 250ms per row (240 BPM)
    .byte 2                 ; 2 instruments
    .byte 2                 ; 2 patterns
    .byte 4                 ; 4 orders (play pattern 0, 1, 0, 1)
    .fill 7, 0              ; Reserved

; Instruments (8 bytes each)
music_instruments:
    ; Instrument 0: Lead (pulse wave)
    .byte WAVE_PULSE        ; Waveform
    .byte $40               ; 50% duty
    .byte $10               ; Attack
    .byte $20               ; Decay
    .byte $80               ; Sustain
    .byte $40               ; Release
    .byte $C0               ; Volume
    .byte 0                 ; Reserved

    ; Instrument 1: Bass (triangle)
    .byte WAVE_TRIANGLE     ; Waveform
    .byte 0                 ; Duty (ignored for triangle)
    .byte $08               ; Attack
    .byte $10               ; Decay
    .byte $A0               ; Sustain
    .byte $30               ; Release
    .byte $FF               ; Volume
    .byte 0                 ; Reserved

; Order list
music_orders:
    .byte 0                 ; Play pattern 0
    .byte 1                 ; Play pattern 1
    .byte 0                 ; Play pattern 0 again
    .byte 1                 ; Play pattern 1 again
    .byte $FF               ; End of song

; Patterns
music_patterns:

; Pattern 0 offset (for seeking)
music_pattern_0:
    ; Row 0: Channel 0 plays C4 with instrument 0
    .byte $00, $31, $00     ; Ch0, Note On, C4, Inst 0
    .byte $40, $19, $01     ; Ch1, Note On, C3, Inst 1 (bass)
    .byte $FF               ; End of row

    ; Row 1: Channel 0 plays E4
    .byte $00, $35, $00     ; Ch0, Note On, E4, Inst 0
    .byte $FF               ; End of row

    ; Row 2: Channel 0 plays G4
    .byte $00, $38, $00     ; Ch0, Note On, G4, Inst 0
    .byte $FF               ; End of row

    ; Row 3: Channel 0 plays C5
    .byte $00, $3D, $00     ; Ch0, Note On, C5, Inst 0
    .byte $FF               ; End of row

    .byte $FF               ; End of pattern

music_pattern_1:
    ; Row 0: Note off on channel 0, bass plays G2
    .byte $10               ; Ch0, Note Off
    .byte $40, $14, $01     ; Ch1, Note On, G2, Inst 1
    .byte $FF               ; End of row

    ; Row 1: Channel 0 plays G4
    .byte $00, $38, $00     ; Ch0, Note On, G4, Inst 0
    .byte $FF               ; End of row

    ; Row 2: Channel 0 plays B4
    .byte $00, $3C, $00     ; Ch0, Note On, B4, Inst 0
    .byte $FF               ; End of row

    ; Row 3: Channel 0 plays D5
    .byte $00, $3F, $00     ; Ch0, Note On, D5, Inst 0
    .byte $FF               ; End of row

    .byte $FF               ; End of pattern

music_end:

music_file_format.txt · Last modified: by appledog

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki