[stella] The Sound Machine V1.0

Subject: [stella] The Sound Machine V1.0
From: Manuel Polik <cybergoth@xxxxxxxx>
Date: Wed, 05 Sep 2001 19:24:40 +0200
Hi there!

As I said in the SONIC (R)EVOLUTION mail, I'm gonna offer & explain the
sound driver of Gunfight!
Well, here it is, more or less in 'manual' form.
For an easy use, just follow all 'Action' steps...

Theory first:

I guess most of you already have an idea how the driver works. You'll
also notice, that it's heavily based on Kurt Wolochs 'ship demo' sound
driver. There were three major points bugging me in the original
routine:

- It didn't play *silent* notes
- It was fixed to one distortion table per channel
- It was wasting lots of ROM

The evolved driver solves all of this.

- Adding the ability to choose the distortion per note automatically
always provides the (well - almost) silent note from Pitch 0 /
Distortion 4/5, so I got this for free :-)

- Next idea was to pack the two tables into one, using the high nibble
(4 bits) for one and the low nibble for the other channel. This is
possible through two series of equates. 

This'd play D3 on one and A4 on the other channel for example:

   .byte #D32   | #A41


To access the values I only need too unpack the notes like this:

Channel0:
	AND #$0F

Channel1:
	AND #$F0
	LSR
	LSR
	LSR
	LSR

- Now we'd need lockup tables to map all the packed values back to the
real values. (We're limited to 16 different notes per channel now!) this
is done in 2 frequency & 2 distortion tables. (If we have to look up the
note anyway, we could look up the distortion for it as well, or? :-))

- One example for the decoding:

The equation:

E61         = $02   ; note E6 

would make the driver select value 3 of the according frequency &
distortion table, which would be:

voice1freqtab
    .byte #00   ; Dummy    
    .byte #00   ; 
    .byte #11   ; 

pitch 11 on 

voice1disttab
    .byte #00   ; Dummy    
    .byte #04   ; 
    .byte #04   ; 

distortion 4!

- Well - all three problems solved. As for the ROM usage of Ring of
Fire: 256 notes + 32 channel1 decodings +22 channel2 decodings - 4 dummy
bytes = 306 bytes ROM!!!

Ok, here's the step-by-step manual to use TSM V1.0:

1. Action-> The necessary Framework

Copy all the following into your project:

-----------------------------------------------------
; Two bytes RAM needed!

soundCount          ds 1 ; current note to be played
decayCount          ds 1 ; note decay

; The Routine

PlayMusic
            DEC decayCount
            DEC decayCount
            BNE DecayNotZero
            LDX soundCount
            LDA soundfreq,X
            AND #$0F
            BEQ NoNote0
            TAY
            LDA voice1disttab,Y
            STA AUDC0
            LDA voice1freqtab,Y
            STA AUDF0
NoNote0
            LDX soundCount
            LDA soundfreq,X
            AND #$F0
            BEQ NoNote1
            LSR
            LSR
            LSR
            LSR
            TAY
            LDA voice2disttab,Y
            STA AUDC1
            LDA voice2freqtab,Y
            STA AUDF1
NoNote1
            LDA #14
            STA AUDV0
            LDA #6
            STA AUDV1
            LDA #16
            STA decayCount
            INC soundCount
            RTS

DecayNotZero
            LDX soundCount
            LDA soundfreq,X
            AND #$0F
            BEQ NoDecay0
            LDA decayCount
            STA AUDV0
NoDecay0
            LDX soundCount
            LDA soundfreq,X
            AND #$F0
            BEQ NoDecay1
            LDA decayCount
            LSR
            STA AUDV1
NoDecay1
            RTS

;Sound equates for 16 different states/notes voice 1

HOLD1       = $00   ; Hold last note
SIL1        = $01   ; Silencium please

E61         = $02   ; note E6 
D61         = $03   ; note D6 
C61         = $04   ; note C6 
                            
H51         = $05   ; note H5 
A51         = $06   ; note A5 
G51         = $07   ; note G5 
F551        = $08   ; note F#5
E51         = $09   ; note E5 
D51         = $0A   ; note D5 
C51         = $0B   ; note C5 

H41         = $0C   ; note H4 
A41         = $0D   ; note A4 
G41         = $0E   ; note G4 
F451        = $0F   ; note F#4

;Sound equates for 10 different states/notes voice 2

HOLD2       = $00   ; Hold last note
DRM2        = $10   ; Base Drum :-)

A32         = $20   ; note A3
G32         = $30   ; note G3 
F352        = $40   ; note F#3
E32         = $50   ; note E3
D32         = $60   ; note D3 
C32         = $70   ; note C3 

H22         = $80   ; note H2
A22         = $90   ; note A2
G22         = $A0   ; note G2

; frequency & distortion tabs - notes see above!

voice1freqtab
    .byte #00   ; Dummy    
    .byte #00   ; 
    .byte #11   ; 
    .byte #12   ; 
    .byte #14   ; 
    .byte #15   ; 
    .byte #17   ; 
    .byte #19   ; 
    .byte #20   ; 
    .byte #23   ; 
    .byte #26   ; 
    .byte #29   ; 
    .byte #31   ; 
    .byte #11   ; 
    .byte #12   ; 
    .byte #13   ; 

voice1disttab
    .byte #00   ; Dummy    
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #04   ; 
    .byte #12   ; 
    .byte #12   ; 
    .byte #12   ; 

voice2freqtab
    .byte #00   ; Dummy    
    .byte #07   ; 
    .byte #18   ; 
    .byte #20   ; 
    .byte #10   ; 
    .byte #24   ; 
    .byte #13   ; 
    .byte #31   ; 
    .byte #15   ; 
    .byte #17   ; 
    .byte #20   ; 

voice2disttab
    .byte #00   ; Dummy    
    .byte #$08  ; 
    .byte #01   ; 
    .byte #01   ; 
    .byte #07   ; 
    .byte #01   ; 
    .byte #07   ; 
    .byte #01   ; 
    .byte #07   ; 
    .byte #07   ; 
    .byte #07   ; 

; the song data

soundfreq

   .byte #G32   | #D61
   .byte #HOLD2 | #SIL1
   .byte #DRM2  | #D61
   .byte #HOLD2 | #D61
   .byte #G32   | #SIL1
   .byte #HOLD2 | #D61
   .byte #DRM2  | #D61
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #E61
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #C61
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #D61
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #H51
   .byte #HOLD2 | #SIL1
   .byte #DRM2  | #H51
   .byte #HOLD2 | #H51
   .byte #D32   | #SIL1
   .byte #HOLD2 | #H51
   .byte #DRM2  | #H51
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #C61
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #A51
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #H51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #E32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #SIL1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #E32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #F352  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #D51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #SIL1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #D51
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #E51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #C51
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #D51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #D61
   .byte #HOLD2 | #D61
   .byte #D32   | #SIL1
   .byte #HOLD2 | #D61
   .byte #DRM2  | #D61
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #E61
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #C61
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #D61
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #H41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #H41
   .byte #HOLD2 | #H41
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #DRM2  | #H41
   .byte #HOLD2 | #H41
   .byte #D32   | #A41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #F451
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #G41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #SIL1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #H22   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #D51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #A22   | #F551
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #D32   | #A51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #A22   | #A51
   .byte #HOLD2 | #A51
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #G51
   .byte #HOLD2 | #G51
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #G51
   .byte #HOLD2 | #HOLD1
   .byte #E32   | #G51
   .byte #HOLD2 | #HOLD1
   .byte #G22   | #E51
   .byte #HOLD2 | #D51
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #H22   | #SIL1
   .byte #HOLD2 | #H41
   .byte #C32   | #C51
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #D51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #A22   | #F551
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #D32   | #A51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #A22   | #HOLD1
   .byte #HOLD2 | #F551
   .byte #DRM2  | #F551
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #G51
   .byte #HOLD2 | #HOLD1
   .byte #A32   | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #G32   | #G51
   .byte #HOLD2 | #HOLD1
   .byte #E32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G22   | #E51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #D51
   .byte #HOLD2 | #HOLD1
   .byte #C32   | #SIL1
   .byte #HOLD2 | #H41
   .byte #D32   | #H41
   .byte #HOLD2 | #SIL1
   .byte #G32   | #G41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #D32   | #H41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #SIL1
   .byte #G32   | #D51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #SIL1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G22   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #H41
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #C51
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #A41
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #H41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #D51
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #SIL1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #G41
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #A41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #F451
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #G41
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #SIL1
   .byte #HOLD2 | #HOLD1
   .byte #DRM2  | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #G32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #D32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #E32   | #HOLD1
   .byte #HOLD2 | #HOLD1
   .byte #F352  | #HOLD1
   .byte #HOLD2 | #HOLD1

-----------------------------------------------------

2. Action-> 

Now, when you call (JSR) PlayMusic once per frame, you should hear 'Ring
Of Fire' as done in Gunfight 2600!

3. Action->Raw Data

That's the most difficult part. Maybe I'll tell you how I did it:

First I quickly found a 'Ring Of Fire' MIDI file, which was done
brilliant. I was shocked to see that it had some 37K and used 12 melody
voices plus extra 8 rhythm voices.

I then toyed around with some MIDI software, muting more & more
channels, until only the trumpets, the voice & the baseline was left.
Still sounded good & recognizable enough I thought.

Now I tried to transform the tablature in readable (for me :-)) form. I
tried to find some MIDI to MOD or similar converter, but - now way. When
I was about to give up, I posted some help request to
news://de.soc.subkultur.gothic (where else? :-)) when finally one of the
friendliest souls there (Marcell Bollmann) offered to help me!

Now I sent him this MIDI file, asking him to transcribe it into two
readable tables in (C#3,D4...) notation , matching the one I found in
Eckhard Stollbergs frequency guide. 
I additionally asked him to merge the trumpet & voice into one table and
to loop the song after second 52 :-)

He did all of this and sent me two tables looking like this:

d6	1/16	[trumpet start]
--	1/16
d6	1/16
d6	1/16
--	1/16
d6	1/16
d6	1/8
e6	1/8
c6	1/8
d6	1/1
....

Now this resulted in 21 * 16/16 notes, being 5 full notes too much. So I
asked him to discard these 5 full notes by skipping the first halve of
the verse and he did that and merged everything again. 

Voila the complete raw data!

4. Action->Tables, Tables & more tables

- Now that you hopefully have your Raw data, you can start typing it
into soundfreq!

For d6 1/16 you'd type 

   .byte #D61  | #SIL1

For d6 1/8 you'd type 

   .byte #D61  | #SIL1
   .byte #HOLD1| #SIL1

easy or?

- Next you'd set up the two sets of equates, just enter all the notes
you used!

- Now you can pick the notes and distortions out of Eckhards frequency
guide

5. Action->Compile & Enjoy!

Ok, that's it...

I didn't explain everything, but I'm sure you'll figure the rest... 

- for exmple I'm playing the rhythm channel on half the volume, since I
think that sounds better...
- for example I replaced all silent notes in the original bassline table
with the drumlike sound...
- ...

Feel free to comment and/or suggest improvements on the code or the data
organisation
Just ask when something is left to explain...

Greetings,
	Manuel

-
Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/

Current Thread