-
Better Sounding Example
02/15/2017 at 06:54 • 0 commentsPiped the output into my sound card's Line-In, take a listen!
-
Final Prototype Dump
02/11/2017 at 05:35 • 0 commentsI swear I'll organize these soon.
#include <SPI.h> #include <SdFat.h> #include <SPIFlash.h> #include <Wire.h> #include <Fatlib/FatFile.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SPI_SPEED SD_SCK_MHZ(50) //#define DEBUG //EEPROM COMMANDS #define MANID 0x90 #define PAGEPROG 0x02 #define READDATA 0x03 #define READSTAT1 0x05 #define WRITEENABLE 0x06 #define GLOBALUNLOCK 0x98 #define SUSPEND 0x75 #define RESUME 0x7A #define JEDECID 0x9f #define RELEASE 0xAB #define BLOCK64ERASE 0xD8 //PORTA #define CARD_CS ( 1 << 11 ) // 0 #define MISO ( 1 << 12 ) // 0 #define SN_WE ( 1 << 13 ) // 1 #define YM_IC ( 1 << 14 ) // 1 #define YM_A0 ( 1 << 15 ) // 0 #define YM_A1 ( 1 << 16 ) // 0 #define YM_RD ( 1 << 17 ) // 1 #define YM_WR ( 1 << 18 ) // 1 #define SN_CS ( 1 << 19 ) // 1 #define YM_CS ( 1 << 20 ) // 1 #define MEM_CS ( 1 << 21 ) // 1 #define SDA ( 1 << 22 ) // 1 #define SCL ( 1 << 23 ) // 1 #define SN_RDY ( 1 << 27 ) // 1 #define YM_IRQ ( 1 << 28 ) // 1 //PORTB #define BACKBUTTON ( 1 << 2 ) // 1 #define BACKARDUINO 19 #define PLAYBUTTON ( 1 << 3 ) // 1 #define PLAYARDUINO 25 #define HOLD ( 1 << 8 ) // 0 #define NEXTBUTTON ( 1 << 9 ) // 1 #define NEXTARDUINO 16 #define MOSI ( 1 << 10 ) // 0 #define SCK ( 1 << 11 ) // 0 #define MEM_WP ( 1 << 22 ) // 1 #define MIDI_IN ( 1 << 23 ) // 1 //DEBUG #ifdef DEBUG #define DEBUG_PRINT(...) Serial.print(__VA_ARGS__) #define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__) #else #define DEBUG_PRINT(...) #define DEBUG_PRINTLN(...) #endif SdFat SD; FatFile vgmDir; FatFile vgmFile; StdioStream vgmStream; Adafruit_SSD1306 display; volatile uint32_t pause; volatile uint8_t backButtonFlag; volatile uint8_t playButtonFlag; volatile uint8_t nextButtonFlag; uint8_t nextSongFlag = 0; uint32_t numFiles; uint32_t vgmStreamPosition = 0; uint32_t pcmPosition = 0; uint32_t pcmPositionOffset = 0; uint32_t ident = 0; uint32_t eof = 0; uint32_t vers = 0; uint32_t snclk = 0; uint32_t ymclk = 0; uint32_t gd3Offset = 0; uint32_t totalSamples = 0; uint32_t loopOffset = 0; uint32_t loopSamples = 0; uint32_t rateHz = 0; uint32_t snFeedback = 0; uint32_t snShiftReg = 0; uint32_t snFlags = 0; uint32_t ym2612Clock = 0; uint32_t ym2151Clock = 0; uint32_t vgmDataOffset = 0; void TC3_Handler(void) { TcCount16* TC = (TcCount16*) TC3; if ( TC->INTFLAG.bit.MC0 == 1 ) { if ( pause ) pause--; TC->INTFLAG.bit.MC0 = 1; } } void backButtonTrigger() { backButtonFlag = 1; } void playButtonTrigger() { playButtonFlag = 1; } void nextButtonTrigger() { nextButtonFlag = 1; } void writeEnable() { PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( WRITEENABLE ); PORT->Group[PORTA].OUTSET.reg = MEM_CS; } void waitForFlashReady() { PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( READSTAT1 ); byte s = SPI.transfer( 0x00 ); while ( s & 0x01 ) { s = SPI.transfer( 0x00 ); DEBUG_PRINT( "." ); } PORT->Group[PORTA].OUTSET.reg = MEM_CS; } void dumpPcmToFlash( uint32_t bytes ) { uint8_t buf[ 280 ]; uint32_t i = 0; uint32_t y = 0; while ( i < bytes ) { writeEnable(); waitForFlashReady(); DEBUG_PRINTLN( "Erasing 64K Block Starting At " + String( i, HEX )); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( BLOCK64ERASE ); SPI.transfer( i >> 16 ); SPI.transfer( i >> 8 ); SPI.transfer( 0 ); PORT->Group[PORTA].OUTSET.reg = MEM_CS; waitForFlashReady(); for ( int page = 0; page < 256; page++ ) { for ( int j = 0; j < 256; j++ ) { if ( y < bytes ) buf[ j ] = vgmStream.getc(); else buf[ j ] = 0xFF; y++; } writeEnable(); waitForFlashReady(); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( PAGEPROG ); SPI.transfer( i >> 16 ); SPI.transfer( i >> 8 ); SPI.transfer( i ); for ( int k = 0; k < 256; k++ ) { SPI.transfer( buf[ k ] ); i++; } PORT->Group[PORTA].OUTSET.reg = MEM_CS; waitForFlashReady(); DEBUG_PRINTLN( "Wrote to flash page " + String( i, HEX )); } } DEBUG_PRINTLN( "Verifying:" ); //for ( uint32_t k = 0; k < bytes; k++ ) { DEBUG_PRINT( readFromFlash( k ), HEX ); } PORT->Group[PORTB].OUTSET.reg = HOLD; PORT->Group[PORTA].OUTSET.reg = MEM_CS; DEBUG_PRINTLN( "" ); } byte readFromFlash( uint32_t addr ) { byte data; static uint32_t lastAddr = 0xFFFFFFF0; PORT->Group[PORTB].OUTSET.reg = HOLD; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; if ( addr != ( lastAddr + 1 )) { DEBUG_PRINT( "Last Address was " + String( lastAddr, HEX ) + " Changing Address to " + String( addr, HEX ) + " | "); PORT->Group[PORTA].OUTSET.reg = MEM_CS; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( READDATA ); SPI.transfer( addr >> 16 ); SPI.transfer( addr >> 8 ); SPI.transfer( addr ); } data = SPI.transfer( 0 ); PORT->Group[PORTB].OUTCLR.reg = HOLD; lastAddr = addr; return data; } void playSNdata( uint32_t data ) { DEBUG_PRINTLN( "SN 0x" + String( data, HEX )); PORT->Group[PORTA].OUTCLR.reg = SN_CS | (( ~( data ) & 0xFF ) << 3 ); PORT->Group[PORTA].OUTSET.reg = ( data << 3 ); while ( pause > 0 ); PORT->Group[PORTA].OUTCLR.reg = SN_WE; //delayMicroseconds( 1 ); while ( !(PORT->Group[PORTA].IN.reg & SN_RDY )); // this way is proper, but waiting 1us makes the sounds much tighter PORT->Group[PORTA].OUTSET.reg = SN_CS | SN_WE; } void playYMdata( uint8_t port, uint32_t addr, uint32_t data ) { DEBUG_PRINTLN( "YM" + String( port ) + " 0x" + String( addr, HEX ) + " 0x" + String( data, HEX ) ); PORT->Group[PORTA].OUTCLR.reg = YM_CS | YM_A0 | (( ~( addr ) & 0xFF ) << 3 ); PORT->Group[PORTA].OUTSET.reg = ( addr << 3 ); if ( port ) PORT->Group[PORTA].OUTSET.reg = YM_A1; else PORT->Group[PORTA].OUTCLR.reg = YM_A1; while ( pause > 0 ); PORT->Group[PORTA].OUTCLR.reg = YM_WR; delayMicroseconds( 1 ); PORT->Group[PORTA].OUTSET.reg = YM_WR; PORT->Group[PORTA].OUTSET.reg = YM_A0 | ( data << 3 ); PORT->Group[PORTA].OUTCLR.reg = ( ~( data ) & 0xFF ) << 3; PORT->Group[PORTA].OUTCLR.reg = YM_WR; delayMicroseconds( 1 ); PORT->Group[PORTA].OUTSET.reg = YM_CS | YM_WR; } typedef void ( *jumpTable )( void ); void nogo( void ) {} void playSN() { uint8_t data = vgmStream.getc(); playSNdata( data ); } void playYM( uint8_t port ) { uint8_t addr = vgmStream.getc(); uint8_t data = vgmStream.getc(); playYMdata( port, addr, data ); } void playYM1() { playYM( 1 ); } void playYM0() { playYM( 0 ); } void waitNSamples( uint32_t n ) { pause = n; DEBUG_PRINTLN( "DL " + String( n )); } void waitSamples() { uint32_t n = vgmStream.getc(); n += uint16_t( vgmStream.getc() ) << 8; waitNSamples( n ); } void endOfFile() { if ( loopOffset ) { vgmStream.fseek( loopOffset + 0x1C, SEEK_SET ); loopOffset = 0; } else nextSongFlag = 1; DEBUG_PRINTLN( "EOL 0x66" ); } void pcmStream() { uint8_t addr = vgmStream.getc(); //0x66 uint8_t data = vgmStream.getc(); //Data Block Type uint32_t s; if ( data < 0x40 ) { s += uint32_t( vgmStream.getc() ) << ( 8 * 0 ); s += uint32_t( vgmStream.getc() ) << ( 8 * 1 ); s += uint32_t( vgmStream.getc() ) << ( 8 * 2 ); s += uint32_t( vgmStream.getc() ) << ( 8 * 3 ); DEBUG_PRINTLN( "Data Block Type " + String( data, HEX ) + " Space Needed: " + s + " Set Command Pointer to " + String( s + vgmStream.ftell(), HEX ) ); pcmPositionOffset = vgmStream.ftell(); dumpPcmToFlash( s ); } else { Serial.println( "Error: Unsupported PCM Type " + String( data, HEX ) ); nextSongFlag = 1; } } void playSample( uint32_t n ) { pause = n; uint8_t addr = 0x2A; uint8_t data = readFromFlash( pcmPosition ); DEBUG_PRINT( "YM PCM 0x" + String( pcmPosition, HEX ) + " -> 0x" + String( pcmPosition + pcmPositionOffset, HEX) + " 0x" + String( data, HEX ) + " DL " + String( n ) + " | "); pcmPosition++; playYMdata( 0, addr, data ); } void play0Sample() { playSample( 0 ); } void play1Sample() { playSample( 1 ); } void play2Sample() { playSample( 2 ); } void play3Sample() { playSample( 3 ); } void play4Sample() { playSample( 4 ); } void play5Sample() { playSample( 5 ); } void play6Sample() { playSample( 6 ); } void play7Sample() { playSample( 7 ); } void play8Sample() { playSample( 8 ); } void play9Sample() { playSample( 9 ); } void play10Sample() { playSample( 10 ); } void play11Sample() { playSample( 11 ); } void play12Sample() { playSample( 12 ); } void play13Sample() { playSample( 13 ); } void play14Sample() { playSample( 14 ); } void play15Sample() { playSample( 15 ); } void wait1Samples() { waitNSamples( 1 ); } void wait2Samples() { waitNSamples( 2 ); } void wait3Samples() { waitNSamples( 3 ); } void wait4Samples() { waitNSamples( 4 ); } void wait5Samples() { waitNSamples( 5 ); } void wait6Samples() { waitNSamples( 6 ); } void wait7Samples() { waitNSamples( 7 ); } void wait8Samples() { waitNSamples( 8 ); } void wait9Samples() { waitNSamples( 9 ); } void wait10Samples() { waitNSamples( 10 ); } void wait11Samples() { waitNSamples( 11 ); } void wait12Samples() { waitNSamples( 12 ); } void wait13Samples() { waitNSamples( 13 ); } void wait14Samples() { waitNSamples( 14 ); } void wait15Samples() { waitNSamples( 15 ); } void wait16Samples() { waitNSamples( 16 ); } void wait735Samples() { waitNSamples( 735 ); } void wait882Samples() { waitNSamples( 882 ); } void seekPCM() { uint32_t s; s += uint32_t( vgmStream.getc() ) << ( 8 * 0 ); s += uint32_t( vgmStream.getc() ) << ( 8 * 1 ); s += uint32_t( vgmStream.getc() ) << ( 8 * 2 ); s += uint32_t( vgmStream.getc() ) << ( 8 * 3 ); pcmPosition = s; DEBUG_PRINTLN( "Seeking PCM Pointer to Offset " + String( pcmPosition, HEX )); } void badCommand( uint8_t command, uint32_t debugAddress ) { Serial.println( "Error: Unknown Command 0x" + String( command, HEX ) + " @ 0X" + String( debugAddress, HEX )); nextSongFlag = 1; } void silence() { playSNdata( 0x9F ); //4 byte silence sn sequence playSNdata( 0xBF ); playSNdata( 0xDF ); playSNdata( 0xFF ); playYMdata( 0, 0x22, 0x00 ); // LFO off playYMdata( 0, 0x27, 0x00 ); // Note off (channel 0) playYMdata( 0, 0x28, 0x01 ); // Note off (channel 1) playYMdata( 0, 0x28, 0x02 ); // Note off (channel 2) playYMdata( 0, 0x28, 0x04 ); // Note off (channel 3) playYMdata( 0, 0x28, 0x05 ); // Note off (channel 4) playYMdata( 0, 0x28, 0x06 ); // Note off (channel 5) playYMdata( 0, 0x2B, 0x00 ); // DAC off playYMdata( 0, 0x30, 0x71 ); // playYMdata( 0, 0x34, 0x0D ); // playYMdata( 0, 0x38, 0x33 ); // playYMdata( 0, 0x3C, 0x01 ); // DT1/MUL playYMdata( 0, 0x40, 0x23 ); // playYMdata( 0, 0x44, 0x2D ); // playYMdata( 0, 0x48, 0x26 ); // playYMdata( 0, 0x4C, 0x00 ); // Total level playYMdata( 0, 0x50, 0x5F ); // playYMdata( 0, 0x54, 0x99 ); // playYMdata( 0, 0x58, 0x5F ); // playYMdata( 0, 0x5C, 0x94 ); // RS/AR playYMdata( 0, 0x60, 0x05 ); // playYMdata( 0, 0x64, 0x05 ); // playYMdata( 0, 0x68, 0x05 ); // playYMdata( 0, 0x6C, 0x07 ); // AM/D1R playYMdata( 0, 0x70, 0x02 ); // playYMdata( 0, 0x74, 0x02 ); // playYMdata( 0, 0x78, 0x02 ); // playYMdata( 0, 0x7C, 0x02 ); // D2R playYMdata( 0, 0x80, 0x11 ); // playYMdata( 0, 0x84, 0x11 ); // playYMdata( 0, 0x88, 0x11 ); // playYMdata( 0, 0x8C, 0xA6 ); // D1L/RR playYMdata( 0, 0x90, 0x00 ); // playYMdata( 0, 0x94, 0x00 ); // playYMdata( 0, 0x98, 0x00 ); // playYMdata( 0, 0x9C, 0x00 ); // Proprietary playYMdata( 0, 0xB0, 0x32 ); // Feedback/algorithm playYMdata( 0, 0xB4, 0xC0 ); // Both speakers on playYMdata( 0, 0x28, 0x00 ); // Key off } jumpTable vgmFunctions[ 256 ] = { nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, playSN, playSN, playYM0, playYM1, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, waitSamples, wait735Samples, wait882Samples, nogo, nogo, endOfFile, pcmStream, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, wait1Samples, wait2Samples, wait3Samples, wait4Samples, wait5Samples, wait6Samples, wait7Samples, wait8Samples, wait9Samples, wait10Samples, wait11Samples, wait12Samples, wait13Samples, wait14Samples, wait15Samples, wait16Samples, play0Sample, play1Sample, play2Sample, play3Sample, play4Sample, play5Sample, play6Sample, play7Sample, play8Sample, play9Sample, play10Sample, play11Sample, play12Sample, play13Sample, play14Sample, play15Sample, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, seekPCM, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo, nogo }; void setup() { delay( 2000 ); Serial.begin( 115200 ); Serial.println( "Serial Online" ); display.begin( SSD1306_SWITCHCAPVCC, 0x3C ); display.clearDisplay(); display.setTextSize( 1 ); display.setTextColor( WHITE ); display.setCursor( 0, 0 ); display.println( "ChipTuneForever" ); display.println( "Sega Genesis Model" ); display.display(); Serial.println( "OLED Online" ); SPI.begin(); SPI.beginTransaction(SPISettings( 50000000, MSBFIRST, SPI_MODE0 )); REG_GCLK_CLKCTRL = ( uint16_t ) ( GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID ( GCM_TCC2_TC3 )) ; while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); TcCount16* TC = (TcCount16*) TC3; TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16;// Use the 16-bit timer while ( TC->STATUS.bit.SYNCBUSY == 1 ); TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;// Use match mode so that the timer counter resets when the count matches the compare register while ( TC->STATUS.bit.SYNCBUSY == 1 ); TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16; // Set prescaler to 16 while ( TC->STATUS.bit.SYNCBUSY == 1 ); int compareValue = ( 48000000 / ( 16 * 44100 )) - 1; TC->COUNT.reg = map( TC->COUNT.reg, 0, TC->CC[ 0 ].reg, 0, compareValue ); // Make sure the count is in a proportional position to where it was to prevent any jitter or disconnect when changing the compare value. TC->CC[ 0 ].reg = compareValue; while ( TC->STATUS.bit.SYNCBUSY == 1 ); TC->INTENSET.reg = 0; // Enable the compare interrupt TC->INTENSET.bit.MC0 = 1; NVIC_EnableIRQ( TC3_IRQn ); TC->CTRLA.reg |= TC_CTRLA_ENABLE; while ( TC->STATUS.bit.SYNCBUSY == 1 ); PORT->Group[PORTA].DIRSET.reg = ( 0xFF << 3 ) | CARD_CS | SN_WE | YM_IC | YM_A0 | YM_A1 | YM_RD | YM_WR | SN_CS | YM_CS | MEM_CS | SDA | SCL; PORT->Group[PORTA].DIRCLR.reg = SN_RDY | YM_IRQ | MISO; PORT->Group[PORTB].DIRSET.reg = MOSI | SCK | HOLD | MEM_WP; PORT->Group[PORTB].DIRCLR.reg = BACKBUTTON | PLAYBUTTON | NEXTBUTTON | MIDI_IN; PORT->Group[PORTA].OUTSET.reg = YM_IC | YM_RD | YM_WR | YM_CS | MEM_CS | SN_WE | SN_CS | CARD_CS; PORT->Group[PORTB].OUTSET.reg = BACKBUTTON | PLAYBUTTON | NEXTBUTTON | MEM_WP | HOLD; delay( 10 ); PORT->Group[PORTA].OUTCLR.reg = YM_IC | MEM_CS; delay( 10 ); PORT->Group[PORTA].OUTSET.reg = YM_IC | MEM_CS; delay( 10 ); silence(); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( RELEASE ); //release PORT->Group[PORTA].OUTSET.reg = MEM_CS; delayMicroseconds( 5 ); DEBUG_PRINTLN( "Flash Chip Released" ); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( JEDECID ); //read jedec SPI.transfer( 0x00 ); //manuf SPI.transfer( 0x00 ); //id high SPI.transfer( 0x00 ); //id low PORT->Group[PORTA].OUTSET.reg = MEM_CS; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( WRITEENABLE ); // write enable PORT->Group[PORTA].OUTSET.reg = MEM_CS; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( GLOBALUNLOCK ); // write enable PORT->Group[PORTA].OUTSET.reg = MEM_CS; DEBUG_PRINTLN( "Starting SD Card" ); char fileNameBuf[256]; SD.begin( 0, SD_SCK_MHZ(50) ); SD.vwd()->rewind(); DEBUG_PRINTLN( "Looking for files" ); while ( vgmFile.openNext( SD.vwd(), O_READ )) { vgmFile.close(); numFiles++; } if ( numFiles == 0 ) { Serial.println( "No Files Found" ); delay( 500 ); } pinMode( BACKARDUINO, INPUT_PULLUP ); pinMode( PLAYARDUINO, INPUT_PULLUP ); pinMode( NEXTARDUINO, INPUT_PULLUP ); attachInterrupt( digitalPinToInterrupt( BACKARDUINO ), backButtonTrigger, FALLING ); attachInterrupt( digitalPinToInterrupt( NEXTARDUINO ), nextButtonTrigger, FALLING ); DEBUG_PRINTLN( "Setup Done" ); } void loop() { char fileNameBuf[ 256 ]; randomSeed( micros() ); uint16_t randomFile = random( numFiles - 1 ); DEBUG_PRINTLN( "Opening File Number: " + String( randomFile )); SD.vwd()->rewind(); String fileNameString; vgmFile.openNext( SD.vwd(), O_READ ); for ( int i = 0; i < randomFile; i++ ) { vgmFile.close(); vgmFile.openNext( SD.vwd(), O_READ ); } fileNameString = vgmFile.getName( fileNameBuf, sizeof( fileNameBuf )); vgmFile.close(); // fileNameString = "Sonic the Hedgehog 2 - 09 - Hill Top Zone"; fileNameString.toCharArray( fileNameBuf, 256 ); Serial.println( "Opening VGM File " + String( fileNameBuf )); display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0, 0); display.println("Now Playing"); display.println(String( fileNameBuf )); display.display(); if ( vgmStream.fopen( fileNameBuf , "r" )) { vgmStreamPosition = 0; pcmPosition = 0; pcmPositionOffset = 0; ident = 0; eof = 0; vers = 0; snclk = 0; ymclk = 0; gd3Offset = 0; totalSamples = 0; loopOffset = 0; loopSamples = 0; rateHz = 0; snFeedback = 0; snShiftReg = 0; snFlags = 0; ym2612Clock = 0; ym2151Clock = 0; vgmDataOffset = 0; for ( int i = 0; i < 4; i++ ) ident += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) eof += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) vers += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) snclk += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) ymclk += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) gd3Offset += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) totalSamples += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) loopOffset += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) loopSamples += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) rateHz += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) snFeedback += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) snShiftReg += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) snFlags += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) ym2612Clock += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) ym2151Clock += uint32_t(vgmStream.getc()) << ( 8 * i ); for ( int i = 0; i < 4; i++ ) vgmDataOffset += uint32_t(vgmStream.getc()) << ( 8 * i ); if ( ident != 0x206d6756 ) { Serial.println( "Ident Match Failed! " + String( ident, HEX ) ); return; } if (( vgmDataOffset == 0x40 ) || ( vgmDataOffset == 0x00 )) vgmStream.fseek( 0x40, SEEK_SET ); else vgmStream.fseek( vgmDataOffset, SEEK_SET ); DEBUG_PRINTLN( "--------------VGM File Data Start--------------" ); nextButtonFlag = 0; nextSongFlag = 0; while (( nextSongFlag == 0 ) && ( nextButtonFlag == 0 )) { if ( !digitalRead( 25 ) ) { display.clearDisplay(); display.setCursor(0, 0); display.println("Paused"); display.println(String( fileNameBuf )); display.display(); delay( 100 ); while ( digitalRead( 25 ) ); display.clearDisplay(); display.setCursor(0, 0); display.println("Now Playing"); display.println(""); display.println(String( fileNameBuf )); display.display(); delay( 100 ); } int32_t debugAddress = 0; // vgmStream.ftell(); uint8_t command = vgmStream.getc(); DEBUG_PRINT( "Addr:0x" + String( debugAddress, HEX ) + " Cmd:0x" + String( command, HEX ) + " | " ); vgmFunctions[ command ](); } PORT->Group[PORTB].OUTSET.reg = MEM_CS; PORT->Group[PORTB].OUTSET.reg = HOLD; DEBUG_PRINTLN( "Done" ); } else Serial.println( "Cannot open " + String( fileNameBuf ) + ": File read error" ); vgmStream.fclose(); silence(); DEBUG_PRINTLN( "Next" ); } /* switch ( command ) { case 0x4F: playSN(); break; case 0x50: playSN(); break; case 0x52: playYM0(); break; case 0x53: playYM1(); break; case 0x61: waitSamples(); break; case 0x62: wait735Samples(); break; case 0x63: wait882Samples(); break; case 0x66: endOfFile(); break; case 0x67: pcmStream(); break; case 0x70: wait1Samples(); break; case 0x71: wait2Samples(); break; case 0x72: wait3Samples(); break; case 0x73: wait4Samples(); break; case 0x74: wait5Samples(); break; case 0x75: wait6Samples(); break; case 0x76: wait7Samples(); break; case 0x77: wait8Samples(); break; case 0x78: wait9Samples(); break; case 0x79: wait10Samples(); break; case 0x7A: wait11Samples(); break; case 0x7B: wait12Samples(); break; case 0x7C: wait13Samples(); break; case 0x7D: wait14Samples(); break; case 0x7E: wait15Samples(); break; case 0x7F: wait16Samples(); break; case 0x80: play0Sample(); break; case 0x81: play1Sample(); break; case 0x82: play2Sample(); break; case 0x83: play3Sample(); break; case 0x84: play4Sample(); break; case 0x85: play5Sample(); break; case 0x86: play6Sample(); break; case 0x87: play7Sample(); break; case 0x88: play8Sample(); break; case 0x89: play9Sample(); break; case 0x8A: play10Sample(); break; case 0x8B: play11Sample(); break; case 0x8C: play12Sample(); break; case 0x8D: play13Sample(); break; case 0x8E: play14Sample(); break; case 0x8F: play15Sample(); break; case 0xE0: seekPCM(); break; default: break; } */
-
Very Accurate Reproduction, Ironing Out Glitches now
10/02/2016 at 18:56 • 0 comments#include <SPI.h> #include <SdFat.h> #include <SPIFlash.h> #include "wiring_private.h" // pinPeripheral() function #define ENABLE_EXTENDED_TRANSFER_CLASS 1 #define CPU_HZ 48000000 #define TIMER_PRESCALER_DIV 16 #define MANID 0x90 #define PAGEPROG 0x02 #define READDATA 0x03 #define FASTREAD 0x0B #define WRITEDISABLE 0x04 #define READSTAT1 0x05 #define READSTAT2 0x35 #define WRITEENABLE 0x06 #define SECTORERASE 0x20 #define BLOCK32ERASE 0x52 #define CHIPERASE 0x60 #define SUSPEND 0x75 #define ID 0x90 #define RESUME 0x7A #define JEDECID 0x9f #define RELEASE 0xAB #define POWERDOWN 0xB9 #define BLOCK64ERASE 0xD8 //PORTA #define CARD_CS ( 1 << 11 ) // 0 #define MISO ( 1 << 12 ) // 0 #define SN_WE ( 1 << 13 ) // 1 #define YM_IC ( 1 << 14 ) // 1 #define YM_A0 ( 1 << 15 ) // 0 #define YM_A1 ( 1 << 16 ) // 0 #define YM_RD ( 1 << 17 ) // 1 #define YM_WR ( 1 << 18 ) // 1 #define SN_CS ( 1 << 19 ) // 1 #define YM_CS ( 1 << 20 ) // 1 #define MEM_CS ( 1 << 21 ) // 1 #define SDA ( 1 << 22 ) // 1 #define SCL ( 1 << 23 ) // 1 #define SN_RDY ( 1 << 27 ) // 1 #define YM_IRQ ( 1 << 28 ) // 1 //PORTB #define BACKBUTTON ( 1 << 2 ) // 1 #define PLAYBUTTON ( 1 << 3 ) // 1 #define OSC_IN ( 1 << 8 ) // 0 #define NEXTBUTTON ( 1 << 9 ) // 1 #define MOSI ( 1 << 10 ) // 0 #define SCK ( 1 << 11 ) // 0 #define MIDI_IN ( 1 << 23 ) // 1 //#define DEBUG #ifdef DEBUG #define DEBUG_PRINT(...) Serial.print(__VA_ARGS__) #define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__) #else #define DEBUG_PRINT(...) #define DEBUG_PRINTLN(...) #endif #define PCMSIZE 20000 byte pcmData[ PCMSIZE ]; int numFiles = 0; SdFat SD; File vgmFile; StdioStream vgmStream; SPIClass mySPI ( &sercom1, 12, 13, 11, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_3 ); volatile byte done = 0; uint32_t fileSize; byte readPcmFromFlash = 0; volatile uint32_t commandPosition; volatile uint32_t pcmPosition; void waitForFlashReady() { PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( READSTAT1 ); byte s = SPI.transfer( 0x00 ); while ( s & 0x01 ) { s = SPI.transfer( 0x00 ); DEBUG_PRINT( "." ); } PORT->Group[PORTA].OUTSET.reg = MEM_CS; } void getNumFiles() { SD.vwd()->rewind(); Serial.println( "Looking for files"); while (vgmFile.openNext(SD.vwd(), O_READ)) { numFiles++; vgmFile.close(); } } void writeEnable() { PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( WRITEENABLE ); PORT->Group[PORTA].OUTSET.reg = MEM_CS; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( READSTAT1 ); byte s = SPI.transfer( 0x00 ); while ( s & 0x01 ) { s = SPI.transfer( 0x00 ); DEBUG_PRINT( "." ); } PORT->Group[PORTA].OUTSET.reg = MEM_CS; } void dumpToPcm() { for ( uint32_t addr = 0; addr < fileSize; addr++ ) { byte data = readFromFlash( addr ); uint32_t s = 0; if ( data == 0x67 ) { addr++; data = readFromFlash( addr ); //0x66 if ( data == 0x66 ) { addr++; data = readFromFlash( addr++ ); //Data Block Type for ( uint32_t j = 0; j < 4; j++ ) s += ( uint32_t( readFromFlash( addr++ ) ) << ( 8 * j )); if ( s > PCMSIZE ) { Serial.println( "PCM Data too large!" ); readPcmFromFlash = 1; return; } readPcmFromFlash = 0; for ( uint32_t j = 0; j < s; j++ ) { pcmData[ j ] = readFromFlash( addr++ ); DEBUG_PRINTLN( "Writing PCM Data to " + String( j, HEX )); } } } } } void dumpToFlash() { uint8_t buf[ 256 ]; uint32_t addr = 0; while ( !vgmStream.feof() ) { writeEnable(); DEBUG_PRINTLN( "Erasing 64K Block Starting At " + String( addr, HEX )); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( BLOCK64ERASE ); SPI.transfer( addr >> 16 ); SPI.transfer( addr >> 8 ); SPI.transfer( 0 ); PORT->Group[PORTA].OUTSET.reg = MEM_CS; waitForFlashReady(); for ( int page = 0; page < 256; page++ ) { for ( int i = 0; i < 256; i++ ) { byte data = 0; if ( !vgmStream.feof() ) data = vgmStream.getc(); buf[ i ] = data; } writeEnable(); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( 0x02 ); // Pageprog SPI.transfer( addr >> 16 ); SPI.transfer( addr >> 8 ); SPI.transfer( addr ); for (int i = 0; i < 256; i++) { SPI.transfer( buf[i] ); addr++; } PORT->Group[PORTA].OUTSET.reg = MEM_CS; waitForFlashReady(); DEBUG_PRINTLN( "Wrote to flash page " + String( addr, HEX )); } } } void dumpFlash() { PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( 0x03 ); // read SPI.transfer( 0x00 ); SPI.transfer( 0x00 ); SPI.transfer( 0x00 ); byte dat = 0; for ( long i = 0; i < 0xFFFFFF; i++ ) { dat = SPI.transfer( 0x00 ); DEBUG_PRINTLN( "Reading from flash " + String( SPI.transfer( 0x00 ), HEX )); } PORT->Group[PORTA].OUTSET.reg = MEM_CS; } byte readFromFlash( uint32_t addr ) { static uint32_t lastAddr = 0xFFFFFFF0; if ( addr != ( lastAddr + 1 )) { DEBUG_PRINTLN( "Last Address was " + String( lastAddr, HEX ) + " Changing Address to " + String( addr, HEX )); PORT->Group[PORTA].OUTSET.reg = MEM_CS; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer16(( 0x03 << 8 ) | (addr >> 16)); // read SPI.transfer16( addr ); } lastAddr = addr; byte data = SPI.transfer( 0x00 ); return data; } void playSN( uint8_t data ) { PORT->Group[PORTA].OUTCLR.reg = SN_CS | ((uint32_t)~(data) << 3 ) & 0x7F8; PORT->Group[PORTA].OUTSET.reg = ((uint32_t)data << 3 ) & 0x7F8; PORT->Group[PORTA].OUTCLR.reg = SN_WE; delayMicroseconds( 7 ); while ( !(PORT->Group[PORTA].IN.reg & SN_RDY )); PORT->Group[PORTA].OUTSET.reg = SN_CS | SN_WE; } void playYM( uint8_t port, uint8_t addr, uint8_t data ) { PORT->Group[PORTA].OUTCLR.reg = YM_CS | YM_A0 | ((uint32_t)~(addr) << 3 ) & 0x7F8; PORT->Group[PORTA].OUTSET.reg = ((uint32_t)addr << 3 ) & 0x7F8; if ( port ) PORT->Group[PORTA].OUTSET.reg = YM_A1; else PORT->Group[PORTA].OUTCLR.reg = YM_A1; PORT->Group[PORTA].OUTCLR.reg = YM_WR; delayMicroseconds( 1 ); PORT->Group[PORTA].OUTSET.reg = YM_WR; PORT->Group[PORTA].OUTSET.reg = YM_A0 | ((uint32_t)data << 3 ) & 0x7F8; PORT->Group[PORTA].OUTCLR.reg = ((uint32_t)~(data) << 3 ) & 0x7F8; PORT->Group[PORTA].OUTCLR.reg = YM_WR; PORT->Group[PORTA].OUTSET.reg = YM_CS | YM_WR; } void silence() { playSN( 0x9F ); //4 byte silence sn sequence playSN( 0xBF ); playSN( 0xDF ); playSN( 0xFF ); playYM(0, 0x22, 0x00); // LFO off playYM(0, 0x27, 0x00); // Note off (channel 0) playYM(0, 0x28, 0x01); // Note off (channel 1) playYM(0, 0x28, 0x02); // Note off (channel 2) playYM(0, 0x28, 0x04); // Note off (channel 3) playYM(0, 0x28, 0x05); // Note off (channel 4) playYM(0, 0x28, 0x06); // Note off (channel 5) playYM(0, 0x2B, 0x00); // DAC off } void TC3_Handler(void) { TcCount16* TC = (TcCount16*) TC3; if (( TC->INTFLAG.bit.MC0 == 1 ) && ( done == 0 )) { TC->INTFLAG.bit.MC0 = 1; static uint32_t pause = 0; uint8_t bufferByte; if ( pause > 0 ) { pause--; DEBUG_PRINTLN( "Pausing for " + String( pause )); } else { byte command = readFromFlash( commandPosition ); DEBUG_PRINT( "Addr:0x" + String( ( commandPosition ), HEX ) + " Cmd:0x" + String( command, HEX ) + " | " ); commandPosition++; uint32_t addr; uint32_t data; uint32_t temp; uint32_t s = 0; switch ( command ) { case 0x4F: // should I just write this straight to the SN? data = readFromFlash( commandPosition++ ); DEBUG_PRINTLN( "W - SN? Data 0x" + String( data, HEX )); playSN( data ); break; case 0x50: data = readFromFlash( commandPosition++ ); DEBUG_PRINTLN( "W - SN Data 0x" + String( data, HEX )); playSN( data ); break; case 0x52: addr = readFromFlash( commandPosition++ ); data = readFromFlash( commandPosition++ ); DEBUG_PRINTLN( "W - YM 0 Address 0x" + String( addr, HEX ) + " Data 0x" + String( data, HEX ) ); playYM( 0, addr, data ); break; case 0x53: addr = readFromFlash( commandPosition++ ); data = readFromFlash( commandPosition++ ); DEBUG_PRINTLN( "W - YM 1 Address 0x" + String( addr, HEX ) + " Data 0x" + String( data, HEX ) ); playYM( 1, addr, data ); break; case 0x61: pause = readFromFlash( commandPosition++ ); pause += (((uint16_t)readFromFlash( commandPosition++ )) << 8 ); DEBUG_PRINTLN( "W - Delay " + String( pause )); break; case 0x62: DEBUG_PRINTLN( "W - Delay 735" ); pause = 735; break; case 0x63: DEBUG_PRINTLN( "W - Delay 882" ); pause = 882; break; case 0x66: done = 1; DEBUG_PRINTLN( "End of Sound Data" ); break; case 0x67: temp = readFromFlash( commandPosition++ ); //0x66 temp = readFromFlash( commandPosition++ ); //Data Block Type for ( uint32_t j = 0; j < 4; j++ ) s += ( uint32_t( readFromFlash( commandPosition++ ) ) << ( 8 * j )); pcmPosition = commandPosition; commandPosition += s; DEBUG_PRINTLN( "Data Block Type " + String( temp, HEX ) + " Space Needed: " + s + " Set Command Pointer to " + commandPosition ); break; case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: DEBUG_PRINTLN( "W - Delaying " + String( ( command & 0x0F ) + 1 )); pause = ( command & 0x0F ) + 1; break; case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: addr = 0x2A; if ( readPcmFromFlash ) data = readFromFlash( pcmPosition++ ); else data = pcmData[ pcmPosition ]; DEBUG_PRINTLN( "W - YM Play 0x" + String( pcmPosition, HEX ) + " > 0x" + String ( data, HEX )); playYM( 0, addr, data ); pause = (command & 0x0F); if ( pause > 0 ) pause--; break; case 0xE0: for ( int j = 0; j < 4; j++ ) s += ( readFromFlash( commandPosition++ ) << ( 8 * ( j ))); pcmPosition = s; // are these addresses offset relative to the data block's position in memory, or relative to the data block's 0th index? DEBUG_PRINTLN( "Seeking PCM Pointer to Offset " + String( pcmPosition, HEX )); break; default: DEBUG_PRINTLN( "Unknown File Command: 0x" + String( command, HEX )); //while ( 1 ); break; } } } } void startTimer(int frequencyHz) { REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (GCM_TCC2_TC3)) ; while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); TcCount16* TC = (TcCount16*) TC3; TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16;// Use the 16-bit timer while (TC->STATUS.bit.SYNCBUSY == 1); TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;// Use match mode so that the timer counter resets when the count matches the compare register while (TC->STATUS.bit.SYNCBUSY == 1); TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16; // Set prescaler to 16 while (TC->STATUS.bit.SYNCBUSY == 1); int compareValue = ( CPU_HZ / ( TIMER_PRESCALER_DIV * frequencyHz )) - 1; TC->COUNT.reg = map( TC->COUNT.reg, 0, TC->CC[ 0 ].reg, 0, compareValue ); // Make sure the count is in a proportional position to where it was to prevent any jitter or disconnect when changing the compare value. TC->CC[ 0 ].reg = compareValue; while ( TC->STATUS.bit.SYNCBUSY == 1 ); TC->INTENSET.reg = 0; // Enable the compare interrupt TC->INTENSET.bit.MC0 = 1; NVIC_EnableIRQ(TC3_IRQn); TC->CTRLA.reg |= TC_CTRLA_ENABLE; while (TC->STATUS.bit.SYNCBUSY == 1); } void setTimerFrequency(int frequencyHz) { int compareValue = ( CPU_HZ / ( TIMER_PRESCALER_DIV * frequencyHz )) - 1; TcCount16* TC = ( TcCount16* ) TC3; TC->COUNT.reg = map( TC->COUNT.reg, 0, TC->CC[ 0 ].reg, 0, compareValue ); // Make sure the count is in a proportional position to where it was to prevent any jitter or disconnect when changing the compare value. TC->CC[ 0 ].reg = compareValue; while ( TC->STATUS.bit.SYNCBUSY == 1 ); } void setup() { Serial.begin( 115200 ); Serial.println( "Serial Online" ); randomSeed( micros() / millis() ); PORT->Group[PORTA].DIRSET.reg = ( 0xFF << 3 ) | CARD_CS | SN_WE | YM_IC | YM_A0 | YM_A1 | YM_RD | YM_WR | SN_CS | YM_CS | MEM_CS | SDA | SCL; PORT->Group[PORTA].DIRCLR.reg = SN_RDY | YM_IRQ; PORT->Group[PORTA].OUTSET.reg = YM_IC | YM_RD | YM_WR | YM_CS | MEM_CS | SN_WE | SN_CS; PORT->Group[PORTB].DIRSET.reg = MOSI | SCK; PORT->Group[PORTB].DIRCLR.reg = OSC_IN | BACKBUTTON | PLAYBUTTON | NEXTBUTTON | MIDI_IN; PORT->Group[PORTB].OUTSET.reg = BACKBUTTON | PLAYBUTTON | NEXTBUTTON; delay( 10 ); PORT->Group[PORTA].OUTCLR.reg = YM_IC; delay( 10 ); PORT->Group[PORTA].OUTSET.reg = YM_IC; delay( 10 ); silence(); SPI.begin(); SPI.beginTransaction(SPISettings(50000000, MSBFIRST, SPI_MODE0)); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( 0xab ); //release PORT->Group[PORTA].OUTSET.reg = MEM_CS; delayMicroseconds( 5 ); DEBUG_PRINTLN( "Flash Chip Released" ); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( 0x9f ); //read jedec uint8_t manuf = SPI.transfer(0x00); uint16_t id = ((uint16_t)SPI.transfer(0x00)) << 8; id |= SPI.transfer(0x00); PORT->Group[PORTA].OUTSET.reg = MEM_CS; DEBUG_PRINTLN("MANUF=0x" + String(manuf, HEX) + ",ID=0x" + String(id, HEX)); PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( 0x06 ); // write enable PORT->Group[PORTA].OUTSET.reg = MEM_CS; PORT->Group[PORTA].OUTCLR.reg = MEM_CS; SPI.transfer( 0x98 ); // write enable PORT->Group[PORTA].OUTSET.reg = MEM_CS; SD.begin( 0, SPI_FULL_SPEED ); DEBUG_PRINTLN( "Setup Done" ); delay( 5000 ); } void loop() { getNumFiles(); static int fileCount = 0; SD.vwd()->rewind(); int randomFile = fileCount; fileCount++; char buf[256]; for ( int i = 0; i < randomFile; i++ ) { vgmFile.openNext(SD.vwd(), O_READ); vgmFile.getName( buf, sizeof( buf ) ); Serial.println( String( buf )); vgmFile.close(); } Serial.println("try"); if ( vgmStream.fopen( buf , "r" ) ) { Serial.println("fileopen"); DEBUG_PRINTLN( "VGM File Open" ); uint32_t ident = 0; for ( int i = 0; i < 4; i++ ) ident += uint32_t( vgmStream.getc() ) << ( 8 * i ); if ( ident != 0x206d6756 ) { DEBUG_PRINTLN( "Ident Match Failed!" ); return; } fileSize = 0; for ( int i = 0; i < 4; i++ ) fileSize += uint32_t( vgmStream.getc() ) << ( 8 * i ); DEBUG_PRINTLN( "EOF:" + String( fileSize ) ); vgmStream.fseek( 0x40, SEEK_SET );// cheat for now, need to read real VGM offset in header DEBUG_PRINTLN( "--------------VGM File Data Start--------------" ); Serial.println("dumping"); dumpToFlash(); dumpToPcm(); Serial.println("done"); vgmStream.fclose(); } else Serial.println(" File read error" ); DEBUG_PRINTLN( "Closing VGM File" ); done = 0; startTimer(44100); interrupts(); while ( done == 0 ) DEBUG_PRINTLN( "Doing" ); noInterrupts(); DEBUG_PRINTLN( "Done" ); PORT->Group[PORTA].OUTSET.reg = MEM_CS; silence(); fileSize = 0; commandPosition = 0; pcmPosition = 0; Serial.println("redo"); }
-
A little bit faster now!
09/06/2016 at 02:26 • 0 comments -
Need To Upgrade To A Speedier Micro
09/03/2016 at 03:51 • 0 comments