don't click here

Adding >$1F songs (Sonic 2)

Discussion in 'Engineering & Reverse Engineering' started by Tamkis, Jun 27, 2011.

  1. Tamkis

    Tamkis

    Banned
    116
    0
    0
    Pennsylvania
    Megaman 2: The Robotnik Wars, Unnamed S3&K hack
    For the past 2 months, I have been struggling to add even more music into my sonic 2 hack, Sonic Loco 2. I need this featuer implemented into my hack before I submit it into the hacking contest. I plan on using different songs per boss (like in Megamix), and having a music monitor like in S1Nineko for a hidden song per zone. These new songs will total more than the original limit of Sonic 2 of $1F songs.

    Below is the code for my attempt of adding more than $1F songs. FYI, I am using the Sonic 2 clone driver, which is based upon the simpler Sonic 1 Sound driver, and one of the latest .svn disasms for Sonic 2. What am I doing wrong, and could anybody help me fix it?

    s2.constants.asm:

    Code (ASM):
    1.  
    2. ; Music IDs
    3. offset :=   zMasterPlaylist
    4. ptrsize :=  1
    5. idstart :=  $68
    6. ; $80 is reserved for silence, so if you make idstart $80 or less,
    7. ; you may need to insert a dummy zMusIDPtr in the $80 slot
    8.  
    9. MusID__First = idstart
    10. MUsID_EHZH =        id(zMusIDPtr_EHZH)  ; 68** "H" stands for "hidden"
    11. MUsID_CPZH =        id(zMusIDPtr_CPZH)  ; 69
    12. MUsID_ARZH =        id(zMusIDPtr_ARZH)  ; 70
    13. MUsID_CNZH =        id(zMusIDPtr_CNZH)  ; 71
    14. MUsID_HTZH =        id(zMusIDPtr_HTZH)  ; 72
    15. MusID_MCZH =        id(zMusIDPtr_MCZH)  ; 73
    16. MusID_OOZH =        id(zMusIDPtr_OOZH)  ; 74
    17. MusID_MTZH =        id(zMusIDPtr_MTZH)  ; 75
    18. MusID_Boss1 =       id(zMusIDPtr_Boss1) ; 76
    19. MusID_Boss2 =       id(zMusIDPtr_Boss2) ; 77
    20. MusID_Boss3 =       id(zMusIDPtr_Boss3) ; 78
    21. MusID_Boss4 =       id(zMusIDPtr_Boss4) ; 79
    22. MusID_Boss5 =       id(zMusIDPtr_Boss5) ; 7a
    23. MusID_Boss6 =       id(zMusIDPtr_Boss6) ; 7b
    24. MusID_Boss7 =       id(zMusIDPtr_Boss7) ; 7c
    25. MusID_Boss8 =       id(zMusIDPtr_Boss8) ; 7d
    26. MusID_Boss9 =       id(zMusIDPtr_Boss9) ; 7e
    27. MusID_Boss10 =      id(zMusIDPtr_Boss10)    ; 7f
    28. MusID_Dum =     id(zMusIDPtr_Dum)   ; 80
    29.  
    30. MusID_2PResult =    id(zMusIDPtr_2PResult)  ; 81
    31. MusID_EHZ =     id(zMusIDPtr_EHZ)   ; 82
    32. MusID_MCZ_2P =      id(zMusIDPtr_MCZ_2P)    ; 83
    33. MusID_OOZ =     id(zMusIDPtr_OOZ)   ; 84
    34. MusID_MTZ =     id(zMusIDPtr_MTZ)   ; 85
    35. MusID_HTZ =     id(zMusIDPtr_HTZ)   ; 86
    36. MusID_ARZ =     id(zMusIDPtr_ARZ)   ; 87
    37. MusID_CNZ_2P =      id(zMusIDPtr_CNZ_2P)    ; 88
    38. MusID_CNZ =     id(zMusIDPtr_CNZ)   ; 89
    39. MusID_DEZ =     id(zMusIDPtr_DEZ)   ; 8A
    40. MusID_MCZ =     id(zMusIDPtr_MCZ)   ; 8B
    41. MusID_EHZ_2P =      id(zMusIDPtr_EHZ_2P)    ; 8C
    42. MusID_SCZ =     id(zMusIDPtr_SCZ)   ; 8D
    43. MusID_CPZ =     id(zMusIDPtr_CPZ)   ; 8E
    44. MusID_WFZ =     id(zMusIDPtr_WFZ)   ; 8F
    45. MusID_HPZ =     id(zMusIDPtr_HPZ)   ; 90
    46. MusID_Options =     id(zMusIDPtr_Options)   ; 91
    47. MusID_SpecStage =       id(zMusIDPtr_SpecStage) ; 92
    48. MusID_Boss =        id(zMusIDPtr_Boss)  ; 93
    49. MusID_EndBoss =     id(zMusIDPtr_EndBoss)   ; 94
    50. MusID_Ending =      id(zMusIDPtr_Ending)    ; 95
    51. MusID_SuperSonic =                  id(zMusIDPtr_SuperSonic); 96
    52. MusID_Invincible =    id(zMusIDPtr_Invincible); 97
    53. MusID_ExtraLife =   id(zMusIDPtr_ExtraLife) ; 98
    54. MusID_Title =       id(zMusIDPtr_Title) ; 99
    55. MusID_EndLevel =    id(zMusIDPtr_EndLevel)  ; 9A
    56. MusID_GameOver =    id(zMusIDPtr_GameOver)  ; 9B
    57. MusID_Continue =    id(zMusIDPtr_Continue)  ; 9C
    58. MusID_Emerald =     id(zMusIDPtr_Emerald)   ; 9D
    59. MusID_Credits =     id(zMusIDPtr_Credits)   ; 9E
    60. MusID_Countdown =   id(zMusIDPtr_Countdown) ; 9F
    61. MusID__End =        id(zMusIDPtr__End)  ; a0
    62.  
    After I tried to compile that, I got errors such as "zMusIDPtr_EHZH, symbol undefined". So, after more searching, in the s2.sounddriver.asm, I changed this:

    Code (ASM):
    1.  
    2. ; Music IDs
    3. offset :=   MusicPoint2
    4. ptrsize :=  2
    5. idstart :=  68h                   ;Is this correct?
    6. ; note: +20h means uncompressed, here
    7.  
    8.  
    9. ZMusIDPtr_EHZH: db  id(MusPtr_EHZH) ;??
    10. ZMusIDPtr_cPZH: db  id(MusPtr_CPZH) ;??
    11. ZMusIDPtr_ARZH: db  id(MusPtr_ARZH) ;??
    12. ZMusIDPtr_CNZH: db  id(MusPtr_CNZH) ;??
    13. ZMusIDPtr_HTZH: db  id(MusPtr_HTZH) ;
    14. ZMusIDPtr_MCZH: db  id(MusPtr_MCZH) ;
    15. ZMusIDPtr_OOZH: db  id(MusPtr_OOZH) ;
    16. ZMusIDPtr_MTZH: db  id(MusPtr_MTZH) ;
    17. ZMusIDPtr_Boss1:    db  id(MusPtr_Boss1)    ;
    18. ZMusIDPtr_Boss2:    db  id(MusPtr_Boss2)    ;
    19. ZMusIDPtr_Boss3:    db  id(MusPtr_Boss3)    ;
    20. ZMusIDPtr_Boss4:    db  id(MusPtr_Boss4)    ;
    21. ZMusIDPtr_Boss5:    db  id(MusPtr_Boss5)    ;
    22. ZMusIDPtr_Boss6:    db  id(MusPtr_Boss6)    ;
    23. ZMusIDPtr_Boss7:    db  id(MusPtr_Boss7)    ;
    24. ZMusIDPtr_Boss8:    db  id(MusPtr_Boss8)    ;
    25. ZMusIDPtr_Boss9:    db  id(MusPtr_Boss9)    ;
    26. ZMusIDPtr_Boss10:   db  id(MusPtr_Boss10)   ;
    27. ZMusIDPtr_Dum:      db  id(MusPtr_Dum)      ;
    28.  
    29. ;WTF is with these psuedo-random music IDs??
    30.  
    31. zMusIDPtr_2PResult: db  id(MusPtr_2PResult) ; 92
    32. zMusIDPtr_EHZ:      db  id(MusPtr_EHZ)      ; 81
    33. zMusIDPtr_MCZ_2P:   db  id(MusPtr_MCZ_2P)   ; 85
    34. zMusIDPtr_OOZ:      db  id(MusPtr_OOZ)      ; 8F
    35. zMusIDPtr_MTZ:      db  id(MusPtr_MTZ)      ; 82
    36. zMusIDPtr_HTZ:      db  id(MusPtr_HTZ)      ; 94
    37. zMusIDPtr_ARZ:      db  id(MusPtr_ARZ)      ; 86
    38. zMusIDPtr_CNZ_2P:   db  id(MusPtr_CNZ_2P)   ; 80
    39. zMusIDPtr_CNZ:      db  id(MusPtr_CNZ)      ; 83
    40. zMusIDPtr_DEZ:      db  id(MusPtr_DEZ)      ; 87
    41. zMusIDPtr_MCZ:      db  id(MusPtr_MCZ)      ; 84
    42. zMusIDPtr_EHZ_2P:   db  id(MusPtr_EHZ_2P)   ; 91
    43. zMusIDPtr_SCZ:      db  id(MusPtr_SCZ)      ; 8E
    44. zMusIDPtr_CPZ:      db  id(MusPtr_CPZ)      ; 8C
    45. zMusIDPtr_WFZ:      db  id(MusPtr_WFZ)      ; 90
    46. zMusIDPtr_HPZ:      db  id(MusPtr_HPZ)      ; 9B
    47. zMusIDPtr_Options:  db  id(MusPtr_Options)  ; 89
    48. zMusIDPtr_SpecStage:    db  id(MusPtr_SpecStage)    ; 88
    49. zMusIDPtr_Boss:     db  id(MusPtr_Boss)     ; 8D
    50. zMusIDPtr_EndBoss:  db  id(MusPtr_EndBoss)  ; 8B
    51. zMusIDPtr_Ending:   db  id(MusPtr_Ending)   ; 8A
    52. zMusIDPtr_SuperSonic:   db  id(MusPtr_SuperSonic)   ; 93
    53. zMusIDPtr_Invincible:   db  id(MusPtr_Invincible)   ; 99
    54. zMusIDPtr_ExtraLife:    db  id(MusPtr_ExtraLife)+20h; B5
    55. zMusIDPtr_Title:    db  id(MusPtr_Title)    ; 96
    56. zMusIDPtr_EndLevel: db  id(MusPtr_EndLevel) ; 97
    57. zMusIDPtr_GameOver: db  id(MusPtr_GameOver)+20h ; B8
    58. zMusIDPtr_Continue: db  (MusPtr_Continue-MusicPoint1)/ptrsize   ; 0
    59. zMusIDPtr_Emerald:  db  id(MusPtr_Emerald)+20h  ; BA
    60. zMusIDPtr_Credits:  db  id(MusPtr_Credits)+20h  ; BD
    61. zMusIDPtr_Countdown:    db  id(MusPtr_Drowning)+40h ; DC
    62. zMusIDPtr__End:
    63.  
    Even after this, some symbols were still "undefined". After more searching, I changed this in s2.asm:

    Code (ASM):
    1.  
    2. ; ------------------------------------------------------------------------------
    3. ; Music pointers
    4. ; ------------------------------------------------------------------------------
    5.     align $8000
    6. soundBankStart  := *
    7.  
    8. ; loc_F8000:
    9. MusicPoint2:
    10. ;**
    11. MusPtr_EHZH:        rom_ptr_z80 Mus_EHZH
    12. MusPtr_CPZH:        rom_ptr_z80 Mus_CPZH
    13. MusPtr_ARZH:        rom_ptr_z80 Mus_ARZH
    14. MusPtr_CNZH:        rom_ptr_z80 Mus_CNZH
    15. MusPtr_HTZH:        rom_ptr_z80 Mus_HTZH
    16. MusPtr_MCZH:        rom_ptr_z80 Mus_MCZH
    17. MusPtr_OOZH:        rom_ptr_z80 Mus_OOZH
    18. MusPtr_MTZH:        rom_ptr_z80 Mus_MTZH
    19. MusPtr_Boss1:       rom_ptr_z80 Mus_Boss1
    20. MusPtr_Boss2:       rom_ptr_z80 Mus_Boss2
    21. MusPtr_Boss3:       rom_ptr_z80 Mus_Boss3
    22. MusPtr_Boss4:       rom_ptr_z80 Mus_Boss4
    23. MusPtr_Boss5:       rom_ptr_z80 Mus_Boss5
    24. MusPtr_Boss6:       rom_ptr_z80 Mus_Boss6
    25. MusPtr_Boss7:       rom_ptr_z80 Mus_Boss7
    26. MusPtr_Boss8:       rom_ptr_z80 Mus_Boss8
    27. MusPtr_Boss9:       rom_ptr_z80 Mus_Boss9
    28. MusPtr_Boss10:      rom_ptr_z80 Mus_Boss10
    29. MusPtr_Dum:     rom_ptr_z80 Mus_Dum
    30.  
    31. MusPtr_CNZ_2P:      rom_ptr_z80 Mus_CNZ_2P
    32. MusPtr_EHZ:     rom_ptr_z80 Mus_EHZ
    33. MusPtr_MTZ:     rom_ptr_z80 Mus_MTZ
    34. MusPtr_CNZ:     rom_ptr_z80 Mus_CNZ
    35. MusPtr_MCZ:     rom_ptr_z80 Mus_MCZ
    36. MusPtr_MCZ_2P:      rom_ptr_z80 Mus_MCZ_2P
    37. MusPtr_ARZ:     rom_ptr_z80 Mus_ARZ
    38. MusPtr_DEZ:     rom_ptr_z80 Mus_DEZ
    39. MusPtr_SpecStage:   rom_ptr_z80 Mus_SpecStage
    40. MusPtr_Options:     rom_ptr_z80 Mus_Options
    41. MusPtr_Ending:      rom_ptr_z80 Mus_Ending
    42. MusPtr_EndBoss:     rom_ptr_z80 Mus_EndBoss
    43. MusPtr_CPZ:     rom_ptr_z80 Mus_CPZ
    44. MusPtr_Boss:        rom_ptr_z80 Mus_Boss
    45. MusPtr_SCZ:     rom_ptr_z80 Mus_SCZ
    46. MusPtr_OOZ:     rom_ptr_z80 Mus_OOZ
    47. MusPtr_WFZ:     rom_ptr_z80 Mus_WFZ
    48. MusPtr_EHZ_2P:      rom_ptr_z80 Mus_EHZ_2P
    49. MusPtr_2PResult:    rom_ptr_z80 Mus_2PResult
    50. MusPtr_SuperSonic:  rom_ptr_z80 Mus_SuperSonic
    51. MusPtr_HTZ:     rom_ptr_z80 Mus_HTZ
    52. MusPtr_ExtraLife:   rom_ptr_z80 Mus_ExtraLife
    53. MusPtr_Title:       rom_ptr_z80 Mus_Title
    54. MusPtr_EndLevel:    rom_ptr_z80 Mus_EndLevel
    55. MusPtr_GameOver:    rom_ptr_z80 Mus_GameOver
    56. MusPtr_Invincible:  rom_ptr_z80 Mus_Invincible
    57. MusPtr_Emerald:     rom_ptr_z80 Mus_Emerald
    58. MusPtr_HPZ:     rom_ptr_z80 Mus_HPZ
    59. MusPtr_Drowning:    rom_ptr_z80 Mus_Drowning
    60. MusPtr_Credits:     rom_ptr_z80 Mus_Credits
    61.  
    Even after that, I got a new error:

    "> > >s2.asm(88541): error: soundBank must fit in $8000 bytes but was $8012. Try moving something to the other bank.
    > > > fatal "soundBank must fit in $8000 bytes but was $\{*-soundBankStart}. Try moving something to the other bank."
    fatal error, assembly terminated"

    As suggested in the Q&A thread, I commented out this fatal error to see what would happen. What happened was that the new songs were inserted, BUT any of the old songs that were shifted past sound test ID $1F were omitted! Any value >=$20 in the sound test was still sfx. How can I add more songs? I believe that the game still thinks that the music is banked, even though the S1Snd driver was ported...


    Below are some useful resources, including my hack disasm, which you can use to try to fix the problem. It isn't the latest version of my disasm, so you will need to give me steps to implement the fix into the latest version of my hack. Also below is my OST, complete with the new songs (boss songs and hidden songs) for testing.

    S2 z80 sound driver info (if you want to fix this problem in z80)
    lMy hack disasm for testing purposes (password is "Loco")
    Sonic 2 Loco OST
     
  2. Spanner

    Spanner

    The Tool Member
  3. Tamkis

    Tamkis

    Banned
    116
    0
    0
    Pennsylvania
    Megaman 2: The Robotnik Wars, Unnamed S3&K hack
    I knew about this guide, haven't tried it yet, but doesn't all this guide does is enumerate the pointers? I will try it in a bit and get back if I have problems. Hope it works
     
  4. SegaLoco

    SegaLoco

    W)(at did you say? Banned
    Sonic Loco......shouldn't that be a name I would be expected to use for a hack?
     
  5. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    There is a whole lot that needs to be changed to be able to add more than 1F songs to the S2 sound driver, or more than 120 songs+SFX. There is also the work that needs to be done to get bank switching working right to deal with bank size issues correctly -- in your case, for example, the $12 bytes past the end of the bank will never be reachable by the z80 and hence will be "lost".

    Here is the full guide on how to extend the S2 sound driver to have better bank switching for music, more space for SFX, easier maintenance of song lists and more than $1F songs (or more than 120 songs + SFX). I do not, however, explain how to fix sound test; you will have to do that yourself.

    Lets start by moving SFX to a sound bank of their own:
    in s2.sounddriver.asm, look for zsub_600 and replace the following 'bankswitch MusicPoint2' by 'bankswitch SoundIndex'
    in s2.sounddriver.asm, look for zloc_F1D and do the same replacement
    In s2.asm, just above label 'SoundIndex', add code as needed to make it look like this:

    Code (Text):
    1.    if * > soundBankStart + $8000
    2.        fatal soundBank must fit in $8000 bytes but was ${*-soundBankStart}. Try moving something to the other bank."
    3.    elseif MOMPASS= 2
    4.        message soundBank has ${$8000+soundBankStart-*} bytes free at end."
    5.    endif
    6.  
    7. ; ------------------------------------------------------------------------------------------
    8. ; Sound effect pointers
    9. ; ------------------------------------------------------------------------------------------
    10.    align   $8000
    11. soundBankStart := *
    12. ; WARNING the sound driver treats certain sounds specially
    13. ; going by the ID of the sound.
    14. ; SndID_Ring, SndID_RingLeft, SndID_BlockPush, SndID_Gloop, SndID_SpindashRev
    15. ; are referenced by the sound driver directly.
    16. ; If needed you can change this in s2.sounddriver.asm
    17.  
    18. ; NOTE: the exact order of this list determines the priority of each sound, since it determines the sound's SndID.
    19. ;       a sound can get dropped if a higher-priority sound is already playing.
    20. ;   see zSFXPriority for the priority allocation itself.
    21.  
    22. ; loc_FEE91: SoundPoint:
    23.  
    24. SoundIndex:

    Doing that will give you some space for the songs and SFX. And please, after you do these, restore the warning you deleted at the end of the file. BTW, I just applied items 1 and 2 to the SVN version because it makes no difference for it without also doing item 3.

    From now on, I will be assuming the SVN version of s2.sounddriver.asm due to the much better labels and comments. You can use it as reference, as it keeps the old labels. At this point, I will be improving the workings of the master playlist in the S2 sound driver so that it behaves more like the S&K sound driver (I.e., better) with regards to song banks. This will essentially allow you to add as many songs as you can without worrying about bank sizes.

    First, scroll down to zMasterPlaylist definition on s2.sounddriver.asm. Before it, define the following macros:

    Code (Text):
    1. zmake68kBank function addr,(((addr&3F8000h)/zROMWindow))
    2. zmakePlaylistEntry macro addr,val
    3.    db   zmake68kBank(addr),val
    4.    dw   zmake68kPtr(addr)
    5.    endm
    You will have to edit the master playlist; here are 3 examples of how to do it: edit this:

    Code (Text):
    1. zMusIDPtr_EndLevel: db id(MusPtr_EndLevel); 97
    2. zMusIDPtr_GameOver: db id(MusPtr_GameOver)+20h ; B8
    3. zMusIDPtr_Continue: db (MusPtr_Continue-MusicPoint1)/ptrsize   ; 0
    into this:
    Code (Text):
    1. zMusIDPtr_EndLevel: zmakePlaylistEntry Mus_EndLevel,0
    2. zMusIDPtr_GameOver: zmakePlaylistEntry Mus_GameOver,20h
    3. zMusIDPtr_Continue: zmakePlaylistEntry Mus_Continue,0
    Basically, the +20h (or +40h) gets shunted to after the comma, while a zero is there if neither is present, also removing the 'Ptr' from 'MusPtr'. You can also delete the comments at the end of the line, as they are misleading now. The continue music was an exception, so I fixed it in the example. You can also delete these lines:

    Code (Text):
    1. ; Music IDs
    2. offset :=   MusicPoint2
    3. ptrsize :=   2
    4. idstart :=   80h
    We now have a table that has, as entries: bank ID (byte); song flags (1 byte); song pointer, relative to bank start (2 bytes). We must now make the game use this. So now find the line after label zBGMLoad that refers to zMasterPlaylist. You can just search for zMasterPlaylist, it is the only line other than the definition that has it. Modify it so that this:


    Code (Text):
    1.    ld   hl,zMasterPlaylist       ; Get address of the zMasterPlaylist
    2.  
    3.    add   hl,de               ; Add the 16-bit offset here
    4.    ld   a,(hl)               ; Get "fixed" index
    5.    ld   b,a               ; 'a' -> 'b'
    6.    ; The following instructions enable a bankswitch routine
    7.    and   80h               ; Get only 'bank' bit
    8.    ld   (zAbsVar.MusicBankNumber),a   ; Store this (use to enable alternate bank)
    9.    ld   a,b               ; Restore 'a'
    10.    add   a,a               ; Adding a+a causes a possible overflow and a multiplication by 2
    11.    add   a,a               ; Now multiplied by 4 and another possible overflow
    12.    ld   c,a               ; Result -> 'c'
    13.    ccf                   ; Invert carry flag...
    14.    sbc   a,a               ; ... so that this sets a to FFh if bit 6 of original a was clear (allow PAL double-update), zero otherwise (do not allow PAL double-update)
    15.    ld   (zAbsVar.IsPalFlag),a       ; Set IsPalFlag
    16.    ld   a,c               ; Put prior multiply result back in
    17.    add   a,a               ; Now multiplied by 8!
    18.    sbc   a,a               ; This is FFh if bit 5 of original a was set (uncompressed song), zero otherwise (compressed song)
    19.    push   af               ; Backing up result...?
    20.    ld   a,b               ; Put 80h based index -> 'a'
    21.    and   1Fh               ; Strip the flag bits
    22.    add   a,a               ; multiply by 2; now 'a' is offset into music table, save for the $8000
    23.    ld   e,a
    24.    ld   d,0               ; de = a
    25.    ld   hl,zROMWindow
    26.    add   hl,de               ; "hl" now contains 2-byte offset for music address table lookup
    27.    push   hl               ; Save 'hl' (will be damaged by bank switch)
    28.    call   zBankSwitchToMusic       ; Bank switch to start of music in ROM!
    29.    pop   hl               ; Restore 'hl'
    30.    ld   e,(hl)
    31.    inc   hl
    32.    ld   d,(hl)               ; Getting offset within bank to music -> de
    becomes this:


    Code (Text):
    1.   ld   hl,zMasterPlaylist; Get address of the zMasterPlaylist
    2.    add   hl,de           ; Add the 16-bit offset here
    3.    add   hl,de           ; Add the 16-bit offset here
    4.    add   hl,de           ; Add the 16-bit offset here
    5.    add   hl,de           ; Add the 16-bit offset here
    6.    ld   a,(hl)           ; Get bank index
    7.    inc   hl               ; Advance pointer
    8.    ld   (zAbsVar.MusicBankNumber),a; Store bank index
    9.    ld   a,(hl)           ; Get song flags
    10.    inc   hl               ; Advance pointer
    11.    add   a,a               ; Adding a+a causes an overflow and a multiplication by 2
    12.    add   a,a               ; Now multiplied by 4
    13.    ld   c,a               ; Result -> 'c'
    14.    ccf                   ; Clear carry flag...
    15.    sbc   a,a               ; ... reverse subtract with carry that was set to zero ... umm.. a=0 in a funny way?
    16.    ld   (zAbsVar.IsPalFlag),a   ; Clear zIsPalFlag?
    17.    ld   a,c               ; Put prior multiply result back in
    18.    add   a,a               ; Now multiplied by 8!
    19.    sbc   a,a               ; This is nonzero if bit 5 of original a is set, zero otherwise (uncompressed song flag)
    20.    push   af           ; Backing up result...?
    21.    ld   e, (hl)           ; Read low byte of pointer into e
    22.    inc   hl               ; Advance pointer
    23.    ld   d, (hl)           ; Read high byte of pointer into d
    24.    push   hl; Save 'hl' (will be damaged by bank switch)
    25.    call   zBankSwitchToMusic; Bank switch to start of music in ROM!
    26.    pop   hl ; Restore 'hl'
    This is because we went from 1 byte per entry to 4 bytes per entry. We also skipped several steps due to the new organization, including one that caps the number of songs to $1F (the limit is still there, in another place, though). We now have to fix the zBankSwitchToMusic routine to work with the new index. So go to it, and replace this:

    Code (Text):
    1.    ld   a,(zAbsVar.MusicBankNumber)
    2.    or   a
    3.    jr   nz,+
    4.  
    5.    bankswitch MusicPoint1
    6.    ret
    7. +
    8.    bankswitch MusicPoint2
    9.    ret
    with this:
    Code (Text):
    1.    ld   a,(zAbsVar.MusicBankNumber)
    2.    ld   hl, zBankRegister
    3.    ld   (hl), a
    4.    rept 7
    5.        rra
    6.        ld   (hl), a
    7.    endm
    8.    xor   a
    9.    ld   (hl), a
    10.    ret
    Now go to s2.constants.asm and search for zMasterPlaylist. Right under it, change ptrsize to 4.
    Now go to s2.asm. Find MusicPoint1 and delete the line starting as 'MusPtr_Continue:' then go to MusicPoint2 and delete all lines starting as 'MusPtr_'; none of that is needed now. You are now free to move songs to different banks as you please, and can create new banks at will.

    To create a new bank, go anywhere you want (except the middle of another bank) and add the following lines:

    Code (Text):
    1.    align  $8000
    2. soundBankStart := *
    3.    ; songs go here
    4.  
    5.  
    6.    if  * > soundBankStart + $ 8000
    7.    fatal "soundBank must fit in $8000 bytes but was $\{*-soundBankStart}. Try moving something to the other bank."
    8.    elseif  MOMPASS=2
    9.    message "soundBank has $\{$8000+soundBankStart-*} bytes free at end."
    10.    endif

    Add the songs in the indicated location on the new bank.

    If you build the ROM right now and test, everything should be working correctly.

    To add songs now is rather simple:
    add the music in any bank you want, creating one if needed
    add the entry for the song in zMasterPlaylist
    add an entry to zSpedUpTempoTable for the new song, in the same order as it is found on the master playlist (it is right below the master playlist)
    add the entry in the music ID list in s2.constants.asm.
    It is so easy now to get space for songs that you can, if you want, decompress all songs and split them into banks as you see fit (as long as you change the second parameter to have bit 5 (20h) set in the second entry on the master playlist).

    All we need to do now is lift the song + SFX limit. We already took care of one problem. Starting here, things are minimally tested; I moved song IDs around to test and it worked, but I would love to know if it works in a more extreme case.
    If you are using the SVN disassembly, this is done already, so skip to step 2; otherwise, go to s2.sounddriver.asm, find sub zPlaySoundByIndex and replace the first line 'ret p' by this:
    Code (Text):
    1.  cp MusID__First
    2.  ret   c
    in s2.constants.asm, find the line containing zMasterPlaylist; you will edit idstart to be the value you want.
    back to s2.sounddriver.asm, go to the master playlist and add a dummy entry for music ID $80 (you will have to find where it goes on your own). You should also not use a music ID of $00 (you won't be able to, anyway). Here is a suitable dummy entry:

    Code (Text):
    1.    dw  0 , 0
    To have more SFX ids allowed, go to line 'offset := SoundIndex' in s2.constants.asm and change the value of idstart below to what you want. A good value is 'idstart := MusID__End', as this will always allow you to add SFX and songs as you please. You must also watch for SFX ID of $80 depending on when exactly music ends (you will have to add a dummy entry to SoundIndex table in s2.asm instead of in zMasterPlaylist if ID $80 falls on SFX range).

    That sums it all, I think.

    Edit: Fixed mistake in master playlist format.

    Edit 2: code->asm,z80 tags.

    Edit 3: fixed formatting for new forum, provided by Caverns.
     
    Last edited: Jul 18, 2019
  6. Tamkis

    Tamkis

    Banned
    116
    0
    0
    Pennsylvania
    Megaman 2: The Robotnik Wars, Unnamed S3&K hack
    Wow, you are right, there is a lot that needs to be changed for >$1F songs. How much research did you have to do to code this? This is amazing; no wonder why you are a tech member! I've followed most of the steps at this point, but am having some minor problems:

    Even though I added this macro above zmasterplaylist, the assembler is ignoring it and generating errors like (in the s2.log)

    Code (Text):
    1. > > >s2.sounddriver.asm(3118): error: unknown opcode
    2. > > > ZMAKEPLAYLISTENTRY(MUS_2PRESULT,0)
    3. > > > zMusIDPtr_2PResult:    zmakePlaylistEntry(Mus_2PResult,0)
    4. > > >s2.sounddriver.asm(3119): error: unknown opcode
    5. > > > ZMAKEPLAYLISTENTRY(MUS_EHZ,0)
    6. > > > zMusIDPtr_EHZ:        zmakePlaylistEntry(Mus_EHZ,0)
    Dumb question, but what is the new format of the songs in the bank under "songs go here"? Could you give me some examples? This is as far as I have gotten so far, but other than those few errors, everything is working.
     
  7. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Quite a bit. Things got a bit faster since I found out Rob Jinnai had done a lot of research on the S2 sound driver; his work (which I merged to SVN recently) gave me quite a head start for figuring out the S&K sound driver (still going on); both of these combined led to the changes I wrote about on my previous post.

    Ah, sorry; that is my fault: macros like that do not use parenthesis. So instead of what I said earlier, use this format for the master playlist instead:
    Code (ASM):
    1. zMusIDPtr_EndLevel: zmakePlaylistEntry Mus_EndLevel,0
    2. zMusIDPtr_GameOver: zmakePlaylistEntry Mus_GameOver,20h
    3. zMusIDPtr_Continue: zmakePlaylistEntry Mus_Continue,0
    (basically, remove the parenthesis) I fixed it in my previous post.

    If you mean the format of the entries, then it is one of the following:
    Code (ASM):
    1. Mus_DoomsdayZone:   BINCLUDE    "sound/music/DoomsdayZone.bin"
    2. Mus_FinalZone:      include "sound/music/FinalZone.asm"
    3. ; Since following is uncompressed, master playlist entry must have a 20h
    4. Mus_GameOver:   dc.w z80_ptr(MusGO_Voices),$0603,$02F2
    5.         dc.w z80_ptr(MusGOver_DAC),$0000
    6.         dc.w z80_ptr(MusGOver_FM1),$E80A
    7.         dc.w z80_ptr(MusGOver_FM2),$F40F
    8.         dc.w z80_ptr(MusGOver_FM3),$F40F
    9.         dc.w z80_ptr(MusGOver_FM4),$F40D
    10.         dc.w z80_ptr(MusGOver_FM5),$DC16
    11.         dc.w z80_ptr(MusGOver_PSG),$D003,$0005
    12.         dc.w z80_ptr(MusGOver_PSG),$DC06,$0005
    13.         dc.w z80_ptr(MusGOver_PSG),$DC00,$0004
    14. MusGOver_FM1:   dc.b $EF,$00
    15.         dc.b $F0,$20,$01,$04,$05
    16.         dc.b $80,$0C,$CA,$12,$80,$06,$CA,$80,$CB,$12,$C8,$1E
    17.         dc.b $CA,$06,$80,$CA,$80,$CA,$80,$C6,$80,$C4,$12,$C8
    18.         dc.b $0C,$80,$12,$C9,$04,$80,$C9,$C8,$06,$80,$C7,$80
    19.         dc.b $C6,$80
    20.         dc.b $F0,$28,$01,$18,$05
    21.         dc.b $C5,$60,$F2
    22. MusGOver_FM2:   dc.b $EF,$01,$80,$01,$D9,$06,$80,$D9,$80,$D6,$80,$D6
    23.         dc.b $80,$D7,$15,$D7,$1B,$D9,$06,$80,$D9,$80,$D6,$80
    24.         dc.b $D6,$80,$DC,$15,$DC,$1B,$F2
    25. MusGOver_FM3:   dc.b $EF,$01,$D6,$0C,$D6,$D2,$D2,$D4,$15,$D4,$1B,$D6
    26.         dc.b $0C,$D6,$D2,$D2,$D7,$15,$D7,$1B,$F2
    27. MusGOver_FM4:   dc.b $EF,$02,$E2,$01,$AE,$06,$80,$AE,$80,$A9,$80,$A9
    28.         dc.b $80,$AC,$15,$AB,$0C,$AC,$03,$AB,$0C,$AE,$06,$80
    29.         dc.b $AE,$80,$A9,$80,$A9,$80,$B3,$15,$B2,$0C,$B3,$03
    30.         dc.b $B2,$0C,$AE,$04,$80,$AE,$AD,$06,$80,$AC,$80,$AB
    31.         dc.b $80,$AB,$60,$E2,$01,$F2
    32. MusGOver_FM5:   dc.b $EF,$03,$80,$30,$D7,$12,$80,$03,$D7,$1B,$80,$30
    33.         dc.b $DC,$12,$80,$03,$DC,$1B
    34. MusGOver_PSG:   dc.b $F2
    35. MusGOver_DAC:   dc.b $80,$18,$81
    36.         dc.b $F7,$00,$04
    37.         dc.w z80_ptr(MusGOver_DAC)
    38.         dc.b $F2
    39. MusGO_Voices:   dc.b $3A,$51,$51,$08,$02,$1E,$1E,$1E,$10,$1F,$1F,$1F
    40.         dc.b $0F,$00,$00,$00,$02,$0F,$0F,$0F,$1F,$18,$22,$24,$81
    41.         dc.b $3C,$33,$73,$30,$70,$94,$96,$9F,$9F,$12,$14,$00
    42.         dc.b $0F,$04,$04,$0A,$0D,$2F,$4F,$0F,$2F,$33,$1A,$80,$80
    43.         dc.b $3A,$01,$01,$07,$01,$8E,$8D,$8E,$53,$0E,$0E,$0E
    44.         dc.b $03,$00,$00,$00,$07,$1F,$1F,$FF,$0F,$1C,$27,$28,$80
    45.         dc.b $1F,$66,$53,$31,$22,$1C,$1F,$98,$1F,$12,$0F,$0F
    46.         dc.b $0F,$00,$00,$00,$00,$FF,$0F,$0F,$0F,$8C,$8A,$8D,$8B
    If you mean the format of the songs: these would be normal S2 SMPS format. You can put the song compressed or uncompressed, it is your choice -- if uncompressed, the song's entry in the master playlist must have a 20h instead of a 0, if compressed, it must be Kosinskisaxman-compressed, with all pointers assuming that the song starts at offset $1380.

    Edit: fixed stupid mistake. What was I thinking, 'Kosinski'?