Post subject: Galaxian (NES) music player disassembly and hackery
Banned User
Joined: 12/23/2004
Posts: 1850
(Crosspost from nesdev)
Galaxian (NES) has a hidden "sound test", which is very... convulted to access (it requires resetting the system over 45 times, and another 45 to change tracks) as well as holding the A+B button on P2 and all kinds of other shit. If you didn't know any better, you might assume it's just some glitch. Soon after I first discovered it, I fired up FCEUX and created a disassembly of it, changing things, removing dead code, and so on and so forth. That's been going on for a few days, on and off (mostly off). This is my first adventure into 6502 outside of changing INC to DEC (cough). ROM Everything Galaxian-related aside from a majority of the code and the music has been stripped out or changed, and the music isn't original anyway, so... I plan on working on this some more. Maybe turning it into some sort of beginner's music playtoy or something :P Use: Reset changes tracks. That's about it really. The numbers should be fairly self explanatory if look closely enough.
Programming in 6502 is a pain in the ass. But hey! CPU meter!
Perma-banned
Joined: 2/26/2007
Posts: 1365
Location: Minnesota
Heh, amazing what they could do with 32 different tones with a max of two at a time.
adelikat wrote:
I very much agree with this post.
Bobmario511 wrote:
Forget party hats, Christmas tree hats all the way man.
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Sticky wrote:
Heh, amazing what they could do with 32 different tones with a max of two at a time.
Yeah. Well, many modern instruments cannot even play that many different tones. A typical recorder for example, can only reach approximately one octave -- that is 12 tones, in student use. Even the best single-chambered ocarinas can produce a maximum of about 21 tones. With a maximum of one at a time.
Senior Moderator
Joined: 8/4/2005
Posts: 5777
Location: Away
One of the best examples of single-channel pseudo-polyphony is 1_channel_moog.it (explanatory video).
Warp wrote:
Edit: I think I understand now: It's my avatar, isn't it? It makes me look angry.
Joined: 4/3/2005
Posts: 575
Location: Spain
Khöömei ('throat singing') is an even more amazing example of vocal polyphony (singing two notes at once) that is practiced in Mongolia. http://www.youtube.com/watch?v=l1HL1kpwPUI&feature=related
No.
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
moozooh wrote:
One of the best examples of single-channel pseudo-polyphony is 1_channel_moog.it (explanatory video).
Neat tricks, though that's not real single-channel sound and consequently not "pseudo" polyphony. It uses the Instrument Mode, in which the sample played on the channel can sustain and continue playing on the background while a new one is started.* In Instrument Mode, the relationship between module channels and sound ("virtual") channels is relaxed. In traditional, MOD-style Sample Mode, the relationship is rigid: each module channel corresponds to a single sound channel. If this module used the "Note Cut" as the New Note Action rather than "Note Off", things would be different. *) That's roughly equivalent to holding down the sustain pedal and playing the piano single-fingered, and putting a little robot called Pitch Envelope inside the piano to stretch the released strings to produce different tones while the piano operator plays new keys. In olden times, "pseudo" polyphony was usually achieved with two methods: 1. Arpeggio, in which the pitch on the same channel is varied in rapid succession, e.g. between C,E,G,C,E,G 10 times in a second. For a profound example, listen to The Micro Machines title screen on NES. On even more restricted platforms such as the C64 or the Spectrum ZX, the arpeggio is interrupted by different instruments such as drumming. The listener won't easily realize that the chord and the percussion are played alternatingly on the very same channel. 2. Chord samples, i.e. samples in which several different sounds are recorded together as one sample to be played on one channel. Minor and major string chord samples were very common in MODs. For a NES example, see Gremlins or Journey to Silius. The effect is used in the DPCM sample. This is naturally only possible on platforms supporting recorded samples beyond basic waveforms.
Player (206)
Joined: 5/29/2004
Posts: 5712
Oh, so that's how Sunsoft did it!
put yourself in my rocketpack if that poochie is one outrageous dude
Banned User
Joined: 12/23/2004
Posts: 1850
Bisqwit wrote:
Sticky wrote:
Heh, amazing what they could do with 32 different tones with a max of two at a time.
Yeah. Well, many modern instruments cannot even play that many different tones. A typical recorder for example, can only reach approximately one octave -- that is 12 tones, in student use. Even the best single-chambered ocarinas can produce a maximum of about 21 tones. With a maximum of one at a time.
Yes, but at the same time you are trapped in a single tempo with the same length for every note. While tempo and note length are not big factors, they limit the options significantly when compared to real instruments. Also, I am grateful that this thread is at least on a related topic (dual-channel musicisms). Better than this stupid bullshit... By the way, you can edit in your own music if you care to experiment with the format. Open the ROM in a hex editor and add $4010 to the address displayed when playing music to get its location in the ROM (specifically, CHR-ROM). Ignore the message at the top, though :)
Perma-banned
Banned User
Joined: 12/23/2004
Posts: 1850
I've been working on it here and there. I wanted to learn PPU drawing, but had no real idea how; then I decided to just use the frame timer and the note value and go from there. Er... that isn't quite right. ROM available here (warning: contents volatile!) Assembly code available too (on request or snooping) It's really nothing too new. I do want to get in a slightly more advanced music engine, maybe with a wider range of frequencies than just 15. 64 would be a great place to start if I knew which to use.
Perma-banned
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
You could always use the Capcom music engine from Rockman / Rockman 2. It is pretty much plug and play. You can find it at http://bisqwit.iki.fi/jutut/megamansource/ . If you want it in binary format, it's located in rockman2.nes or megaman2.nes at file position $30010. It ends at $30A60, which is immediately followed by a table of song pointers. You'll want to place it so it runs at the address $8000 in your ROM. Each song pointer is 2 bytes. At the address pointed, is the song data. The song data is in this format:
  0000 byte $0F   ; this identifies as a song (as opposed to SFX)
  0001 word Channel1Pointer ; points to the data for channel 1
  0003 word Channel2Pointer ; points to the data for channel 2
  0005 word Channel3Pointer ; points to the data for channel 3
  0007 word Channel4Pointer ; points to the data for channel 4
  0009 word MetaPointer ; points to the list of vibrato specifications
Each channel is a stream of commands. The following are the most important commands:
  $00 $xx
    Sets playback speed to xx (each note plays for xx frames)
  $02 $xx
    Sets the duty-cycle values to xx. Accepted values: $00,$80,$40,$C0.
    This controls the type of sound produced by the NES hardware.
  $03 $xy
    Sets the volume and envelope of the sound. I think y is the volume and x is the envelope decay rate, or vice versa.
  $04 $nn $addr
    Declares a loop-end. The commands in between of the address $addr and this loop command are repeated nn times. If nn=0, loops infinitely.
    Loop nesting is not allowed, unless the outer nn=0 and inner nn>0.
  $05 $xx
    Sets the base note to xx. The value xx (in semitones) is added to each note played.
    Multiples of 12 give a difference of an octave.
  $06
    The following note will be played 50% longer (i.e. if the length is otherwise indicated 8 units, this makes it 12).
  $30
    The following note will be played 1/3 shorter (i.e. if the length is otherwise indicated 8 units, this makes it 8*2/3). This can be used to play triplets.
  $40..$5F
    Plays a note with length=2. The note played is (bytevalue-$40 + basenotevalue), except $40 means silence instead.
    The actual duration for the note is 2*playbackspeed frames,
    except if prefixed with the $06 byte or with the $30 byte.
  $60..$7F
    Plays a note with length=4. The note played is (bytevalue-$60 + basenotevalue), except $60 means silence instead.
  $80..$9F
    Plays a note with length=8. The note played is (bytevalue-$80 + basenotevalue), except $80 means silence instead.
  $A0..$BF
    Plays a note with length=16. The note played is (bytevalue-$A0 + basenotevalue), except $A0 means silence instead.
  $C0..$DF
    Plays a note with length=32. The note played is (bytevalue-$C0 + basenotevalue), except $C0 means silence instead.
  $E0..$FF
    Plays a note with length=64. The note played is (bytevalue-$E0 + basenotevalue), except $E0 means silence instead.
If you don't use vibrato, the vibrato specification pointer can be specified as 0. To use the sound engine, the following interface is available:
  jsr $8000  ; Call this once every NMI.
 
  lda #1
  jsr $8003 ; Call this when you want to start song number 1

  lda #$FC
  jsr $8003 ; Call this when you want to speed up music

  lda #$FD
  ldy 1  ; fade power
  jsr $8003 ; Call this when you want to initialize a volume fade

  lda #$FE
  jsr $8003 ; Call this when you want to stop all sfx and music

  lda #$FE
  jsr $8003 ; Call this when you want to stop all music