Sonic and Sega Retro Message Board: High-Quality Sonic 1 PCM Music - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Loading News Feed...
 

High-Quality Sonic 1 PCM Music Using WAV files as level music in Sonic 1

#1 User is offline Sonic 65 

Posted 19 August 2008 - 09:39 PM

  • Posts: 1155
  • Joined: 09-October 04
  • Gender:Male
  • Project:Dustin Wyatt's Epic Jailbreak
  • Wiki edits:13
You might remember the various PCM demos I've posted over the past year, which played WAV files as level music in a Sonic 1 ROM. However, the quality of these past demos wasn't that great, to say the least.

Over the past few weeks, I've been optimizing the Z80 driver (now it's 3x faster) and finding other various ways to improve the sound quality. The playback quality is pretty much perfect now, and the driver can also support a file up to 22050Hz now.

Here's a test demo of the new, improved driver:

Link to Test Demo
EDIT: Link fixed.
EDIT 2: Just found this out; sound doesn't work in Gens. Would someone be willing to test if this works on real hardware?

Music list for the demo, in a fancy code box that preserves formatting:

PCMDriverLoad: ; XREF: GameClrRAM; TitleScreen
		move.w #0,($A11200).l
		move.w #$100,($A11100).l
		move.w #$100,($A11200).l

WaitForZ80_2:
		btst #0,($A11100).l
		bne WaitForZ80_2

		lea (Z802),a0
		lea ($A00000).l,a1
		move.W #Z802End-Z802,d1

LoadDriver:
		move.b (a0)+,(a1)+
		dbf d1,LoadDriver
		move.b	#$01,($FFFFFFFC).w
		rts
		
Z802:
		incbin sound\PCMD.bin
Z802End:



This is the code that actually loads the new PCM driver. It also incbin's the PCM driver (I'm assuming here that you put it in the sound folder of the split disassembly, and didn't change the name), and sets a special driver byte at $FFFFFFFC (this will be needed later).





Step 3:


Find the SoundDriverLoad subroutine, and replace it with this:

SoundDriverLoad:			; XREF: GameClrRAM; TitleScreen
		nop	
		move.w	#$100,($A11100).l ; stop the Z80
		move.w	#$100,($A11200).l ; reset the Z80
		lea	(Kos_Z80).l,a0	; load sound driver
		lea	($A00000).l,a1
		bsr.w	KosDec		; decompress
		move.w	#0,($A11200).l
		nop	
		nop	
		nop	
		nop	
		move.w	#$100,($A11200).l ; reset the Z80
		move.w	#0,($A11100).l	; start	the Z80
		move.b	#$00,($FFFFFFFC).w
		rts	



The only new thing here is the line of code at the end that sets the driver flag to 0. So when the driver flag is 0, the regular S1 drum driver is in use, but when the driver flag is 1, the new PCM driver is in use.






Step 4:

Find the subroutine labeled "sub_71B4C", and replace it with this.

sub_71B4C:				; XREF: loc_B10; PalToCRAM
		cmpi.b	#$01,($FFFFFFFC).w
		beq.s	loc_71B82
		move.w	#$100,($A11100).l ; stop the Z80

loc_71B5A:
		btst	#0,($A11100).l
		bne.s	loc_71B5A

		move.b	($A01FFD).l,d0
		btst	#7,d0
		bra.s	loc_71B82
		move.w	#0,($A11100).l	; start	the Z80
		bra.s	sub_71B4C



This is what we needed the driver flag for. Without this subroutine, the regular S1 drum driver won't play, but it's unnecessary to the new PCM driver, and also decreases the quality of the new PCM driver without this modification (since it stops the Z80). However, it's changed so that if the new PCM driver is in use, it'll skip stopping the Z80, preserving the quality of the music.





Step 5:

Find the subroutine labeled "Sound_81to9F", and add this code to the beginning:

; ---------------------------------------------------------------------------
PlayMusic81:

		jsr Sound_E4
		
		jsr PCMDriverLoad
		
		move.w #$100,($A11100).l ;Stop the Z80
		
WaitZ80_81:
		btst #0,($A11100).l
		bne WaitZ80_81 ;Wait for z80 to stop

		move.b	#1,($a00039).l		;turn the driver on
		
		move.b #(((Music81+$34)&0xFF0000)>>16),($a0003c).l ;location - $__xxxx
		move.b #(((Music81+$34)&0xFF00)>>8),($a0003b).l ;location - $xx__xx
		move.b #((Music81+$34)&0xFF),($a0003a).l ;location - $xxxx__
			
		move.b	#(((Music82-Music81)&0xFF0000)>>16),($a0003f).l	;length - $__xxxx
		move.b	#(((Music82-Music81)&0xFF00)>>8),($a0003e).l		;length - $xx__xx
		move.b	#((Music82-Music81)&0xFF),($a0003d).l			;length - $xxxx__


		move.b	#$0C,($a00046).l	;sample rate (00=22050Hz, 05=16000Hz, 0C=11025Hz, 15=8000Hz)

		move.b	#$01,($a0004A).l	;looping flag ($00=no,$01=yes)


		move.w	#$0,($A11100).l		;Start the Z80

		rts

; ---------------------------------------------------------------------------



This is the code that would actually play song $81. From the comments, you should be able to pretty much tell what it does. (Just in case you can't figure out, (Music82-Music81) equals the length of Music81.) You need to do one final thing to get it to play:


Add this at the beginning of Sound_81to9F:

Sound_81to9F:				; XREF: Sound_ChkValue
		cmpi.b #$81,d7
		beq.l PlayMusic81
		jmp Continue8129F
		nop

; ---------------------------------------------------------------------------
PlayMusic81:

		jsr Sound_E4

		
		
		jsr PCMDriverLoad
		
		move.w #$100,($A11100).l ;Stop the Z80
		
WaitZ80_81:
		btst #0,($A11100).l
		bne WaitZ80_81 ;Wait for z80 to halt

		


		move.b	#1,($a00039).l		;turn the wav playing script on
		
		move.b #(((Music81+$34)&0xFF0000)>>16),($a0003c).l ;addr - $__xxxx
		move.b #(((Music81+$34)&0xFF00)>>8),($a0003b).l ;addr - $xx__xx
		move.b #((Music81+$34)&0xFF),($a0003a).l ;addr - $xxxx__
			
		move.b	#(((Music82-Music81)&0xFF0000)>>16),($a0003f).l	;addr - $__xxxx
		move.b	#(((Music82-Music81)&0xFF00)>>8),($a0003e).l		;addr - $xx__xx
		move.b	#((Music82-Music81)&0xFF),($a0003d).l			;addr - $xxxx__


		move.b	#$0C,($a00046).l	;sample rate (00=22050Hz, 05=16000Hz, 0C=11025Hz, 15=8000Hz)

		move.b	#$01,($a0004A).l	;looping flag ($00=no,$01=yes)


		move.w	#$0,($A11100).l		;Start the Z80

		rts

; ---------------------------------------------------------------------------


Continue8129F:
		jsr		SoundDriverLoad
		cmpi.b	#$88,d7		; is "extra life" music	played?
		bne.s	loc_72024	; if not, branch





Let's say that, in your split disassembly, music82.bin was also a wav file, and you wanted it to play too. Then the subroutine would look like this:

Sound_81to9F:				; XREF: Sound_ChkValue
		cmpi.b #$81,d7
		beq.l PlayMusic81
		cmpi.b #$82,d7
		beq.l PlayMusic82
		jmp Continue8129F
		nop

; ---------------------------------------------------------------------------
PlayMusic81:

		jsr Sound_E4

		
		
		jsr PCMDriverLoad
		
		move.w #$100,($A11100).l ;Stop the Z80
		
WaitZ80_81:
		btst #0,($A11100).l
		bne WaitZ80_81 ;Wait for z80 to halt

		


		move.b	#1,($a00039).l		;turn the wav playing script on
		
		move.b #(((Music81+$34)&0xFF0000)>>16),($a0003c).l ;addr - $__xxxx
		move.b #(((Music81+$34)&0xFF00)>>8),($a0003b).l ;addr - $xx__xx
		move.b #((Music81+$34)&0xFF),($a0003a).l ;addr - $xxxx__
			
		move.b	#(((Music82-Music81)&0xFF0000)>>16),($a0003f).l	;addr - $__xxxx
		move.b	#(((Music82-Music81)&0xFF00)>>8),($a0003e).l		;addr - $xx__xx
		move.b	#((Music82-Music81)&0xFF),($a0003d).l			;addr - $xxxx__


		move.b	#$0C,($a00046).l	;sample rate (00=22050Hz, 05=16000Hz, 0C=11025Hz, 15=8000Hz)

		move.b	#$01,($a0004A).l	;looping flag ($00=no,$01=yes)


		move.w	#$0,($A11100).l		;Start the Z80

		rts

; ---------------------------------------------------------------------------


; ---------------------------------------------------------------------------
PlayMusic82:

		jsr Sound_E4

		
		
		jsr PCMDriverLoad
		
		move.w #$100,($A11100).l ;Stop the Z80
		
WaitZ80_82:
		btst #0,($A11100).l
		bne WaitZ80_82 ;Wait for z80 to halt

		


		move.b	#1,($a00039).l		;turn the wav playing script on
		
		move.b #(((Music82+$34)&0xFF0000)>>16),($a0003c).l ;addr - $__xxxx
		move.b #(((Music82+$34)&0xFF00)>>8),($a0003b).l ;addr - $xx__xx
		move.b #((Music82+$34)&0xFF),($a0003a).l ;addr - $xxxx__
			
		move.b	#(((Music83-Music82)&0xFF0000)>>16),($a0003f).l	;addr - $__xxxx
		move.b	#(((Music83-Music82)&0xFF00)>>8),($a0003e).l		;addr - $xx__xx
		move.b	#((Music83-Music82)&0xFF),($a0003d).l			;addr - $xxxx__


		move.b	#$0C,($a00046).l	;sample rate (00=22050Hz, 05=16000Hz, 0C=11025Hz, 15=8000Hz)

		move.b	#$01,($a0004A).l	;looping flag ($00=no,$01=yes)


		move.w	#$0,($A11100).l		;Start the Z80

		rts

; ---------------------------------------------------------------------------





Continue8129F:
		jsr		SoundDriverLoad
		cmpi.b	#$88,d7		; is "extra life" music	played?
		bne.s	loc_72024	; if not, branch






Hopefully you understood all of that...as I've said many times, I'm not good at explaining things. If you have any questions about this, just ask. =P

====================

tl;dr: You can put WAVs in for your level music now. You'll have to read the whole post to see how.
This post has been edited by Sonic 65: 19 August 2008 - 09:53 PM

#2 User is offline Tweaker 

Posted 19 August 2008 - 09:54 PM

  • Posts: 12389
  • Joined: 27-June 04
  • Gender:Male
WOW, that is extremely well done! Like, the quality is actually decent now—I'm pretty surprised!

This is some awesome work. I mean, I don't really see such a prospect becoming popular due to obscene amount of ROM space required to shove all that music in, but I'm certainly impressed nonetheless. Great job! :v:

#3 User is offline muteKi 

Posted 19 August 2008 - 09:57 PM

  • HRC: Have Retro Controllers
  • Posts: 7094
  • Joined: 03-March 05
  • Gender:Male
  • Wiki edits:91
Nice work! I didn't look too closely since I'm bad at reading code, but will this still work with the standard music files in Sonic 1?

I think that just having some high-quality voice clips would be cool enough, let alone using the PCM channel for all level music.


The thought of including good string samples in Sonic 1 makes me very happy.

#4 User is offline Sonic 65 

Posted 19 August 2008 - 10:02 PM

  • Posts: 1155
  • Joined: 09-October 04
  • Gender:Male
  • Project:Dustin Wyatt's Epic Jailbreak
  • Wiki edits:13

View PostmuteKi, on Aug 19 2008, 10:57 PM, said:

Nice work! I didn't look too closely since I'm bad at reading code, but will this still work with the standard music files in Sonic 1?

I think that just having some high-quality voice clips would be cool enough, let alone using the PCM channel for all level music.


The thought of including good string samples in Sonic 1 makes me very happy.


1. Yes. I wouldn't have even released it if it didn't. =P

2. Given the size restrictions, you wouldn't be able to use the PCM channel for all level music anyway, unless you played it at 8000KhZ or some low sample rate. I've open-sourced the driver, so hopefully some Z80 god will be able to do what I can't and add some sort of compression/decompression into it.

3. This doesn't use samples at all; it just plays an entire song in one big chunk. So you wouldn't be able to use the driver as it currently is for strings unless you sacrificed drums. You would need a 2-channel mixer to have both. (TmEE has done some work in this area, I think.)

#5 User is offline muteKi 

Posted 19 August 2008 - 10:03 PM

  • HRC: Have Retro Controllers
  • Posts: 7094
  • Joined: 03-March 05
  • Gender:Male
  • Wiki edits:91
Well sure. If SSG-EG can be enabled properly, I actually know of some voices that might be good for FM synth drums.

#6 User is offline Moogle! 

Posted 19 August 2008 - 10:28 PM

  • Posts: 225
  • Joined: 24-April 08
  • Gender:Male
Not to derail the thread here, but is it possible to get the PSG to play PCM data, like they've done with the Commoder 64?

#7 User is offline Irixion 

Posted 19 August 2008 - 10:36 PM

  • Posts: 1320
  • Joined: 30-December 04
  • Gender:Male
  • Location:Ontario, Canada
  • Project:Life
  • Wiki edits:152
I officially love you. Outstanding work! I'll be sure to be using this (maybe =P )


Edit: This doesn't work on gens edit that records movies. Doesn't play the wavs just blank, works in gens plus fine though.
This post has been edited by Irixion: 19 August 2008 - 10:39 PM

#8 User is offline GasparXR 

Posted 19 August 2008 - 11:33 PM

  • I'm back!
  • Posts: 425
  • Joined: 12-April 08
  • Gender:Male
  • Location:Espanola, Ontario, Canada
  • Project:Super Mario XR
  • Wiki edits:29
Or, you could port Sonic 1 to the SNES and put Chrono Trigger's sound driver in it so it has better quality than the Genesis D=

Anyway, this is awesome. I doubt I'll be using though, since I find SMPS to be fine. But that's still great work there, this opens doors for more originality in Sonic 1 hacks.

#9 User is offline Bibin 

Posted 20 August 2008 - 12:03 AM

  • DON'T LET THE SUN LAUGH AT YOU.
  • Posts: 878
  • Joined: 05-January 07
  • Gender:Male
  • Location:New York City
  • Project:Ghost in the Machine
Perhaps you could have regular SMPS music play while in the background rages some great drumming on a bassy 11khz wave, which is fine for drums, and maybe a bit of bass too. That way we'd be able to fit in real chords with our melodies and still have channels for SFX and such.

#10 User is offline roxahris 

Posted 20 August 2008 - 01:38 AM

  • Everyone's a hypocrite. Take my word for it.
  • Posts: 1216
  • Joined: 24-January 07
  • Gender:Male
  • Project:Doing anything at all
  • Wiki edits:30
Speaking of strings on DAC, I'm pretty sure that you can do something like this if you edit the DAC samples...

#11 User is offline P.P.A. 

Posted 20 August 2008 - 07:06 AM

  • SONIC 2 SUCKS, SONIC CD FOREVER
  • Posts: 644
  • Joined: 09-February 08
  • Gender:Male
  • Location:Germany
  • Project:Sonic MD (Currently: Art for Zone 3)
  • Wiki edits:21
That's pretty awesome!
Hey, now I can use Love You "Sonic" for the credits music of my S1 hack if it ever gets that far.

#12 User is offline Peruant 

Posted 20 August 2008 - 07:28 AM

  • Just dropping in through gaps
  • Posts: 250
  • Joined: 02-September 07
  • Gender:Male
  • Location:Paterson , New Jersey
  • Project:College

Quote

Would someone be willing to test if this works on real hardware?

I just checked and confirmed that this works on the Wii Gens+ emulator. But I can only guess since it has the MAME sound part in the emulator, it's running at perfect speed.
This post has been edited by Peruant: 20 August 2008 - 07:29 AM

#13 User is offline MoDule 

Posted 20 August 2008 - 08:09 AM

  • Posts: 304
  • Joined: 03-October 07
  • Gender:Male
  • Project:Procrastinating from writing bug-fix guides
  • Wiki edits:52

View PostBibin, on Aug 20 2008, 07:03 AM, said:

Perhaps you could have regular SMPS music play while in the background rages some great drumming on a bassy 11khz wave, which is fine for drums, and maybe a bit of bass too. That way we'd be able to fit in real chords with our melodies and still have channels for SFX and such.

That would be totally awsome. Some gba games do something like this. There's the normal sequenced music and then there's a drumloop running on one channel. The samples wouldn't even have to be that big since they just loop the whole time.

#14 User is offline Shibunoa 

Posted 20 August 2008 - 08:09 AM

  • Posts: 329
  • Joined: 19-July 08
  • Gender:Male
  • Location:Italy
  • Wiki edits:28
Awesome work, indeed!
I seem to have found a bug, I don't know if it's already known, but I've noticed that the music also plays when the game is paused after a bit of time passes.

#15 User is offline Sonic 65 

Posted 20 August 2008 - 08:22 AM

  • Posts: 1155
  • Joined: 09-October 04
  • Gender:Male
  • Project:Dustin Wyatt's Epic Jailbreak
  • Wiki edits:13

View PostMoDule, on Aug 20 2008, 09:09 AM, said:

View PostBibin, on Aug 20 2008, 07:03 AM, said:

Perhaps you could have regular SMPS music play while in the background rages some great drumming on a bassy 11khz wave, which is fine for drums, and maybe a bit of bass too. That way we'd be able to fit in real chords with our melodies and still have channels for SFX and such.

That would be totally awsome. Some gba games do something like this. There's the normal sequenced music and then there's a drumloop running on one channel. The samples wouldn't even have to be that big since they just loop the whole time.


You can do something like this with the current driver:

Sound_81to9F: ; XREF: Sound_ChkValue
	cmpi.b #$81,d7
	beq.l PlayMusic81
	jmp Continue8129F
	nop

; ---------------------------------------------------------------------------
PlayMusic81:

	jsr Sound_E4



	jsr PCMDriverLoad

	move.w #$100,($A11100).l ;Stop the Z80

WaitZ80_81:
	btst #0,($A11100).l
	bne WaitZ80_81 ;Wait for z80 to stop




	move.b #1,($a00039).l ;turn the start flag on

	move.b #(((Music81Drums+$34)&0xFF0000)>>16),($a0003c).l ;location - $__xxxx
	move.b #(((Music81Drums+$34)&0xFF00)>>8),($a0003b).l ;location - $xx__xx
	move.b #((Music81Drums+$34)&0xFF),($a0003a).l ;location - $xxxx__

	move.b #(((Music81DrumsEnd-Music81Drums)&0xFF0000)>>16),($a0003f).l ;length - $__xxxx
	move.b #(((Music81DrumsEnd-Music81Drums)&0xFF00)>>8),($a0003e).l ;length - $xx__xx
	move.b #((Music81DrumsEnd-Music81Drums)&0xFF),($a0003d).l ;length - $xxxx__


	move.b #$00,($a00046).l ;sample rate (00=22050Hz, 05=16000Hz, 0C=11025Hz, 15=8000Hz)

	move.b #$01,($a0004A).l ;looping flag ($00=no,$01=yes)


	move.w #$0,($A11100).l ;Start the Z80
	jmp	Continue8129F ;Continue to the song


Music81Drums:
	incbin	"sound/m81drums.bin"
Music81DrumsEnd:

; ---------------------------------------------------------------------------


Continue8129F:
	jsr SoundDriverLoad
	cmpi.b #$88,d7 ; is "extra life" music played?
	bne.s loc_72024 ; if not, branch




Quote

Not to derail the thread here, but is it possible to get the PSG to play PCM data, like they've done with the Commoder 64?


You probably could; they've done something like this on the MSX too, which also uses the Z80, with outstanding quality. Link. It uses a Viterbi search to get the best quality. The encoder doesn't work for me, but I've wondered for a while if something like this could be done for the Genesis (and so have other people, according to Sprites-Mind's forums).


Quote

I just checked and confirmed that this works on the Wii Gens+ emulator. But I can only guess since it has the MAME sound part in the emulator, it's running at perfect speed.


I meant real Genesis hardware. :v:


Quote

Awesome work, indeed!
I seem to have found a bug, I don't know if it's already known, but I've noticed that the music also plays when the game is paused after a bit of time passes.


I'll release fixes for this and the other problems soon. For this bug, it'll probably be as simple as putting in code to stop the Z80 when the game is paused and start it again when it gets unpaused.

  • 3 Pages +
  • 1
  • 2
  • 3
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users