What's new

l_oliveira

Professional
Joined
Jun 26, 2015
Messages
546
Reaction score
605
Location
Brazil
As the title says, I spent a while thinking of how making this work.

CPS1Q and CPS2 use a 16 byte array to send sound codes and Q-SOUND through the first 16 bytes of the shared RAM area.

example:

code 0x0ff0 => 0f ff 00 00 00 ff 00 xx 00 00 00 00 00 ff ff ff
xx let 68k side know if anything is playing. on this 00 when mute. On this particular case 0x10 is put there during playback and 0x00 when no sound is being played.
0xC00F is used as an acknowledge flag. 68k doesn't send commands if it doesn toggle.
Probably is used to stop the game from trying to send commands if the Z80 ceases responding.

CAPCOM ZN1 and ZN2 games (ZN is actually the name SONY gave to the board, not CAPCOM) use a single byte I/O port on the Z80,
sending four bytes of data (/NMI is fired once each byte is sent).

code 0x0ff0 => 0xff 0x00 0x0f 0xf0

So, once I figured out why it was sending four bytes, making a breakthrough was trivial.

I came up with this solution: (FYI, this is Star Gladiator 2 Q-SOUND rom)
Code:
0000: F3            di
0001: ED 56         im   1
0003: 31 FF FF      ld   sp,$FFFF
0006: 21 00 F0      ld   hl,$F000
0009: 11 01 F0      ld   de,$F001
000C: 01 FF 0F      ld   bc,$0FFF
000F: 36 00         ld   (hl),$00
0011: ED B0         ldir
0013: 3E 77         ld   a,$77			; flags "z80 alive"
0015: 32 FF CF      ld   ($CFFF),a		; for the 68k
0018: C3 9A 00      jp   $009A                  ; jump to original init

<snip>

0038: F3            di					; standard Q-SOUND interrupt routine
0039: 08            ex   af,af'
003A: D9            exx
003B: 21 00 F0      ld   hl,$F000
003E: 34            inc  (hl)
003F: 7E            ld   a,(hl)
0040: E6 03         and  $03
0042: 28 0F         jr   z,$0053
0044: 0F            rrca
0045: 30 06         jr   nc,$004D
0047: 21 01 F0      ld   hl,$F001
004A: 34            inc  (hl)
004B: 18 0A         jr   $0057
004D: 21 03 F0      ld   hl,$F003
0050: 34            inc  (hl)
0051: 18 04         jr   $0057
0053: 21 02 F0      ld   hl,$F002
0056: 34            inc  (hl)
0057: C3 00 3A      jp   $3A00		; this replaces "ex   af,af'/exx/ei/ret" with a jump to the added code 

<snip>

3A00: 3A FD CF      ld   a,($CFFD)	; 68k writes 0x88 here (shared RAM)
3A03: FE 88         cp   $88
3A05: C2 3C 3A      jp   nz,$3A3C	; if not 0x88 don't check for sound codes
3A08: 3A 0F C0      ld   a,($C00F)	; now playing flag
3A0B: 3C            inc  a
3A0C: CA 31 3A      jp   z,$3A31
3A0F: 3E FF         ld   a,$FF		; first sound code byte (fixed)
3A11: 32 30 F0      ld   ($F030),a
3A14: CD 40 3A      call $3A40		; send it
3A17: 3E 00         ld   a,$00		; second sound code byte (fixed)
3A19: 32 30 F0      ld   ($F030),a
3A1C: CD 40 3A      call $3A40		; send it
3A1F: 3A 00 C0      ld   a,($C000)	; third sound code byte (from 68K)
3A22: 32 30 F0      ld   ($F030),a
3A25: CD 40 3A      call $3A40		; send it
3A28: 3A 01 C0      ld   a,($C001)	; fourth sound code byte (from 68k)
3A2B: 32 30 F0      ld   ($F030),a
3A2E: CD 40 3A      call $3A40		; send it
3A31: 3E FF         ld   a,$FF
3A33: 32 0F C0      ld   ($C00F),a	
3A36: 3A FE CF      ld   a,($CFFE)
3A39: 32 04 F0      ld   ($F004),a
3A3C: 08            ex   af,af'
3A3D: D9            exx
3A3E: FB            ei
3A3F: C9            ret
3A40: 21 15 F0      ld   hl,$F015	; original NMI routine refactored for this purpose
3A43: 3A 17 F0      ld   a,($F017)	; push/pop and retn removed
3A46: 86            add  a,(hl)
3A47: 26 00         ld   h,$00
3A49: 6F            ld   l,a
3A4A: 01 00 F1      ld   bc,$F100
3A4D: 09            add  hl,bc
3A4E: 3A 30 F0      ld   a,($F030)	; original instruction here 'ld a,(c)' changed to this.  original was I/O port 0
3A51: 77            ld   (hl),a
3A52: 21 17 F0      ld   hl,$F017
3A55: 34            inc  (hl)
3A56: 7E            ld   a,(hl)
3A57: FE 02         cp   $02
3A59: 38 12         jr   c,$3A6D
3A5B: 36 00         ld   (hl),$00
3A5D: 3A 15 F0      ld   a,($F015)
3A60: C6 02         add  a,$02
3A62: 47            ld   b,a
3A63: C6 02         add  a,$02
3A65: 30 02         jr   nc,$3A69
3A67: 06 00         ld   b,$00
3A69: 78            ld   a,b
3A6A: 32 15 F0      ld   ($F015),a
3A6D: C9            ret
 
It means I can take some CPS2 game and put the ZN/ZN2 games music to play on the sound test of the said CPS2 game.

The CPS2 is cool but it's certainly not capable of running PlayStation software... ;)

I did this mostly to exercise some hacking, since I've been working a lot with these sound drivers recently (CPS1 to CPS2 conversion).
 
It means CPS2 hardware has just become a jukebox for any Qsound-playing games other than CPS1Q and CPS2 games :)

/me waits patiently for Leo's video to demonstrate music playing :)
 
I won't post videos but

https://mega.co.nz/#!T5lhGarB!RlZEDyY7Lyb2kjd5EgvBUFDqRoV8vOuQnkGMZOb7HVk

try it yourself. I was using pocket fighter/super gem fighter sound test to play the sounds when I tested. Any other game could be used.

Just rename the files in the zip accordingly (it's on CPS2 multi format already) and flash. (it's not a game, just the files which need to be replaced on a game)
 
I can comment only on Punisher which i did some hacking on, using Leo's routine to put the sprites in the right place and Jedpossums rom re-merging steps with (another) tool from Leo.
Leo has done extensive work on the Qsound rom decryption, maybe he will share some details on that as well ;)

Punisher:
What is needed, is a lot of free time to do more reverse-engineering on how Punisher (and cps1 in general) decides on sprite priority.
Right now, all cps1-qsound games can be 'made to work', but the sprite priority is still a partly solved puzzle.

In CPS2, there are several option bits for priority. 00, 01, 10, 11 (In CPS1, these bits are not set, so no sprites appear when you put the same data in the cps2 RAM area.)
On CPS2 the game draws a frame with sprites, from a list in memory (0x708000-0x709000 for example). The list ends with '8000' as a marker.
On CPS2, the order of overlap is decided by those bits. 10 has higher priority than 01.
So, example, if you have a game like Three wonders, all of the sprites are in one 'layer' (they mostly do not overlap each other on the screen.)
You can add the two bits 11 to the sprite value in the list, and get a decently playable Three Wonders game.

The prio problems start with a belt scroller like Punisher, where enemies can stand above and below the main sprite.
Let's assume the legs of the top sprite, and head of the bottom sprite 'overlap' with the main Punisher sprite.
On CPS1: The game seems to do this prioritizing in software. It simply draws the first enemy at the start of the list, then the Punisher, then the other enemy.
This way the punisher (sprite #2) overlaps the bottom of sprite #1(enemy), and the 3rd sprite is drawn on top of that, so sprite #3's head overlaps punisher's legs.

From what i've been looking at, this seems to be done in reverse on CPS2 but i'm not 100% sure about it yet. The current hack just adds 0x8000 to the prio parts, and then the list is drawn on screen. You can see an example below how it currently looks:

prio.png


We should have (from BACK to front)
Chair
Enemy
Punisher and his hand
Guy who's held by punisher (punisher hand should not be visible)

Instead we have it exactly the other way around.
So yeah, i'm pretty sure the list should be drawn backwards to solve this.

Note i'm also missing the plant pots there for some reason, but this is a heavy modded 'work' rom so i might have mistakes there from an earlier hack haha.

For 'vanilla' cps1 there is the hardware hurdle: the main board has no YM2151 and OKI ADPCM so there will need to be a hardware add-on board to have sound on those games.
Some of the Street Fighter games can 'remixed' to have qsound, with samples from the many SF games on the platform, and music from say, SFZ3. But again, time..
 
Last edited:
Those tracks are quite hilarious with pocket fighter. Nice work.
 
Reminds me of the one idea I had few years ago for SFA2 of porting the sfex songs into it, but it probably is easier to just port sfex z80 code to cps2 and redoing the samples in on sfex engine.
 
There's a problem with that though:

ZN boards do have the PlayStation SPU in them so besides playing the music, QSOUND is mostly used to things like coin sound effects or for announcer voices which say names of the characters.

So QSOUND ZN sound programs only have the game musics in them because ZN games will do sound effects using the PlayStation SPU.
 
For SFEX you have to put your code at 38E0 instead of 3A00. So five commands had to be changed.

I guess I should start opening up SSF2 Z80 since I already know the format of the samples on it (8 Bit Macintosh AIFF no header).
 
I didn't try SFEX neither Rival Schools but that was because I ended doing other things.

Tetris for example had a very weird sound driver. I didn't share it because it's prone to crashing when unexpected codes are sent.
 
SFEX2 and TGM are similar drivers if iirc. Also the 68000 sending it to fade can crash it as well.
 
It was me finally switching the sample/instrument. I know the where 3 more settings and pitch bend is in the instrument tracks just didn't put it in since room.
 
It was me finally switching the sample/instrument. I know the where 3 more settings and pitch bend is in the instrument tracks just didn't put it in since room.
I have a loose DSP-16 chip I took from a broken A-Board ... I plan on making a board with it and connect it to some computer to make experiments with.

Maybe eventually make something funny like a General Midi synthesizer box with it.
 
The ST's Z80 program doesn't have modulation but it is an effect in Alpha 3's Z80 program unused or rarely used.

With a custom z80 program it might be possible to expand the amount tracks since 16 sound effect tracks as well.
 
Back
Top