Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 136 lines (110 sloc) 3.69 KB
#!/usr/bin/env python
# Author: Bryan Cain
# Date: December 31, 2010
# Description: Attempts to restore the original sound samples to SNES ROMs in
# Virtual Console games, which use uncompressed PCM data separate from the ROM.
import os
import sys
import struct
from brrencode3 import BRREncoder
from cStringIO import StringIO
# vcrom: file-like object for the original VC ROM
# brr: file-like object containing the BRR-compressed audio samples
# Precondition: brr is the correct size
def restore_brr_samples(vcrom, pcm):
# read the samples from the input ROM into memory (TODO: check file size first)
vcrom.seek(0)
str = vcrom.read()
samplestart = str.find('PCMF') # samples start with first instance of the string "PCMF"
str = str[samplestart:]
# initialize output ROM in memory as a StringIO (pseudo-file)
rom = StringIO()
rom.write(str)
# read the input BRR samples
#brr.seek(0)
#brrdata = brr.read()
#lastbrroffset = None
enc = BRREncoder(pcm, None)
lastpcmoffset = None
# misc. variables
#goodrom = open('SNADNE1.667', 'rb')
wrong = 0
controlwrong = 0
indices = []
while str.find('PCMF') >= 0:
index = str.find('PCMF')
filepos = samplestart + index
# error checking to prevent infinite loops
#assert index not in indices
#indices.append(index)
pcmf, pcmoffset = struct.unpack('<4sI', str[index:index+8])
pcmoffset &= 0xffffff
if pcmoffset % 16 or pcmoffset < lastpcmoffset:
#print '%08x: unexpected offset %d' % (filepos, pcmoffset)
pcmoffset = lastpcmoffset + 16
#else:
# brroffset = 9 * (brroffset >> 4)
# read the BRR sample
#brr.seek(brroffset)
#brrsample = brr.read(9)
# read and encode the BRR block
brrsample = enc.encode_block(pcmoffset)
# error checking for invalid BRR offsets
if len(brrsample) != 9:
raise ValueError('Invalid BRR offset: %d' % brroffset)
# set the END bit in the BRR sample if it is set in the PCMF block
if ord(str[index+7]) & 1:
brrsample = chr(ord(brrsample[0]) | 1) + brrsample[1:]
# set the LOOP bit in the BRR sample if it is set in the PCMF block
if ord(str[index+7]) & 2:
brrsample = chr(ord(brrsample[0]) | 2) + brrsample[1:]
# checks whether sample matches the original ROM, when the original ROM is available (for debugging purposes)
'''goodrom.seek(samplestart + index)
grsample = goodrom.read(9)
if brrsample != grsample:
wrong += 1
sys.stdout.write('%08x: ' % filepos)
#if brrdata.find(grsample) >= 0:
# print 'wrong sample, correct BRR offset is %08x' % brrdata.find(grsample)
if brrsample[1:] == grsample[1:]:
if abs(ord(brrsample[0]) - ord(grsample[0])) <= 3:
controlwrong += 1
print 'SPC700 control bits differ'
else:
print 'flags are different'
else:
print 'sample encoded differently?' '''
rom.seek(index)
rom.write(brrsample)
str = rom.getvalue()
lastpcmoffset = pcmoffset
#print '%d wrong samples' % wrong
#print '%d differences in SPC700 control bits' % controlwrong
rom.close()
vcrom.seek(0)
return vcrom.read(samplestart) + str
if __name__ == '__main__':
import time
if len(sys.argv) != 4:
print 'Usage: snesrestore game.rom game.pcm output.smc'
sys.exit(1)
vcrom = open(sys.argv[1], 'rb')
pcm = open(sys.argv[2], 'rb')
'''# encode raw PCM in SNES BRR format
print 'Encoding audio as BRR'
brr = StringIO()
enc = BRREncoder(pcm, brr)
enc.encode()
pcm.close()'''
# encode and inject BRR sound data into the ROM
print 'Encoding and restoring BRR audio data to ROM'
start = time.clock()
string = restore_brr_samples(vcrom, pcm)
end = time.clock()
print 'Time: %.2f seconds' % (end - start)
# write to file
output = open(sys.argv[3], "wb")
output.write(string)
output.close()
pcm.close()
#print 'done'