#!/usr/bin/env python import os.path import gzip import spidev import time import RPi.GPIO as GPIO commandPosition = 0 commandOffset = 0 pcmPosition = 0 pcmOffset = 0 spi = spidev.SpiDev() GPIO.setmode(GPIO.BCM) spi.open(0,0) spi.max_speed_hz=125000000 SN_RDY = 17; GPIO.setup( SN_RDY, GPIO.IN ) state = 0xCF YM_CS = ( 1 << 0 ) YM_IC = ( 1 << 1 ) YM_RD = ( 1 << 2 ) YM_WR = ( 1 << 3 ) YM_A0 = ( 1 << 4 ) YM_A1 = ( 1 << 5 ) SN_CS = ( 1 << 6 ) SN_WE = ( 1 << 7 ) def get_uncompressed_size( file ): fileobj = open( file, 'r' ) fileobj.seek( -8, 2 ) crc32 = gzip.read32( fileobj ) isize = gzip.read32( fileobj ) # may exceed 2GB fileobj.close() return isize def pushOut( var, data ): spi.xfer2( [ var, data ] ) #spi.xfer2( [ 0x55, 0xAA ] ) #spi.xfer2( [ 0xAA, 0x55 ] ) def writeSN76489( data ): pushOut((( state & ~( SN_CS )) & ~( SN_WE )), data ) #time.sleep( 0.00000007 ) #channel = GPIO.wait_for_edge( SN_RDY, GPIO.RISING, timeout = 1 ) pushOut( state, data ) def writeYM2612( port, addr, data ): newState = state; if port == 0: newState = ((newState & ~( YM_CS )) & ~( YM_A0 )) & ~( YM_A1 ) else: newState = ((newState & ~( YM_CS )) & ~( YM_A0 )) | ( YM_A1 ) newState &= ~( YM_WR ) pushOut( newState, addr ) #time.sleep( 0.00000001 ) newState |= YM_WR pushOut( newState, addr ) #time.sleep( 0.00000001 ) newState = ( newState | YM_A0 ) pushOut( newState, data ) #time.sleep( 0.00000001 ) newState &= ~( YM_WR ) pushOut( newState, data ) #time.sleep( 0.00000001 ) newState = newState | YM_WR pushOut( newState, data ) #time.sleep( 0.00000001 ) pushOut( state, data ) def main(): vgmSize = get_uncompressed_size( 'Sonic the Hedgehog - Staff Roll.vgz' ) print "VGM Size:", vgmSize vgmFile = gzip.open( 'Sonic the Hedgehog - Staff Roll.vgz' ) vgmBuf = bytearray( vgmSize ) vgmBuf = vgmFile.read() print "Ident:", "".join( n for n in vgmBuf[ 0 : 4 ] ) eofOffset = 0 for i in range( 0, 4 ): eofOffset += ord( vgmBuf[ i + 4 ]) << ( 8 * i ) print "EOF Offset:", eofOffset print "Version:", "".join( format( ord( n ), 'x' ) for n in reversed( vgmBuf[ 8 : 12 ])) snClock = 0 for i in range( 0, 4 ): snClock += ord(vgmBuf[ i + 12 ]) << ( 8 * i ) print "SN76489 Clock:", snClock loopOffset = 0 for i in range( 0, 4 ): loopOffset += ord(vgmBuf[ i + 0x1c ]) << ( 8 * i ) print "Loop Offset:", loopOffset loopNumber = 0 for i in range( 0, 4 ): loopNumber += ord(vgmBuf[ i + 0x20 ]) << ( 8 * i ) print "Loop Number:", loopNumber snClock = 0 for i in range( 0, 4 ): snClock += ord(vgmBuf[ i + 12 ]) << ( 8 * i ) print "SN76489 Clock:", snClock vgmDataOffset = 0 for i in range( 0, 4 ): vgmDataOffset += ord( vgmBuf[ i + 0x34 ]) << ( 8 * i ) if vgmDataOffset == 0 or vgmDataOffset == 0x0C: vgmDataOffset = 0x40; print "VGM Data Offset:", hex( vgmDataOffset ) commandPosition = vgmDataOffset pause = 0 data = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 done = 0 while ( done != 1 ) or ( loopNumber > 0 ): #print hex( data ) if data == 0x4f: writeSN76489( ord( vgmBuf[ commandPosition ] ) ) commandPosition += 1 elif data == 0x50: writeSN76489( ord( vgmBuf[ commandPosition ] ) ) commandPosition += 1 elif data == 0x52: addr = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 data = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 writeYM2612( 0, addr, data ); elif data == 0x53: addr = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 data = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 writeYM2612( 1, addr, data ); elif data == 0x61: pause = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 pause += ord( vgmBuf[ commandPosition ] ) << 8 commandPosition += 1 time.sleep( pause * 0.000022675737 ) elif data == 0x62: pause = 735; time.sleep( pause * 0.000022675737 ) elif data == 0x63: pause = 882; time.sleep( pause * 0.000022675737 ) elif data == 0x66: if loopOffset > 0: commandPointer = loopOffset + vgmDataOffset loopOffset = 0 done = 1; return 0 elif data == 0x67: temp = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 dataBlockType = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 if dataBlockType < 0x40 : size = 0 for i in range( 0, 4 ): size += ord( vgmBuf[ commandPosition ] ) << ( 8 * i ) commandPosition += 1 print size pcmOffset = commandPosition; commandPosition += size else: print "wrong pcm type", dataBlockType done = 1; elif ( data >> 4 ) == 0x07: time.sleep(( data & 0x0F ) * 0.000022675737 ) addr = 0x2A elif ( data >> 4 ) == 0x08: pause = data & 0x0F addr = 0x2A data = ord( vgmBuf[ pcmPosition ] ) pcmPosition += 1 writeYM2612( 0, addr, data ) time.sleep( pause * 0.000022675737 ) elif data == 0xE0: s = 0 for i in range( 0, 4 ): s += ord( vgmBuf[ commandPosition ] ) << ( 8 * i ) commandPosition += 1 pcmPosition = s + pcmOffset; else: print "unknown command", data if ( loopOffset == 0 ) and ( loopNumber > 0 ): loopNumber -= 1 data = ord( vgmBuf[ commandPosition ] ) commandPosition += 1 return 0 if __name__ == '__main__': main()