From afec9cfbfd0c3d026c765d5e23bf8125207f49ad Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Fri, 4 Aug 2023 11:46:49 +0200 Subject: [PATCH 01/21] Save audio settings to flash --- main.cpp | 181 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 100 insertions(+), 81 deletions(-) diff --git a/main.cpp b/main.cpp index 6d465d9..9720de0 100644 --- a/main.cpp +++ b/main.cpp @@ -63,6 +63,10 @@ int showSpeakerMode = 0; // When > 0 speaker mode is shown on screen const uint LED_PIN = PICO_DEFAULT_LED_PIN; #endif +bool saveSettingsAndReboot = false; +#define STATUSINDICATORSTRING "STA" +#define VOLUMEINDICATORSTRING "VOL" + namespace { static constexpr uintptr_t NES_FILE_ADDR = 0x10110000; // Location of .nes rom or tar archive with .nes roms @@ -146,17 +150,6 @@ const WORD __not_in_flash_func(NesPalette)[] = { 0x00f0, // 3e 0x00f0}; // 3f -// static queue_t call_queue; -// typedef struct -// { -// int scanline; -// int bufferindex; -// bool startframe; -// bool endframe; -// } queue_entry_t; - -// static queue_entry_t entry; - static auto frame = 0; static uint32_t start_tick_us = 0; static uint32_t fps = 0; @@ -182,6 +175,8 @@ uint32_t getCurrentNVRAMAddr() } printf("SRAM slot %d\n", slot); // Save Games are stored towards address stored roms. + // calculate address of save game slot + // slot 0 is reserved. (Some state variables are stored at this location) uint32_t saveLocation = NES_BATTERY_SAVE_ADDR + SRAM_SIZE * (slot + 1); if (saveLocation >= NES_FILE_ADDR) { @@ -191,59 +186,73 @@ uint32_t getCurrentNVRAMAddr() return saveLocation; } -void __not_in_flash_func(_saveNVRAM)(uint32_t offset, int8_t currentGameIndex, char advance) -{ - static_assert((SRAM_SIZE & (FLASH_SECTOR_SIZE - 1)) == 0); - - uint32_t state = NES_BATTERY_SAVE_ADDR - XIP_BASE; - uint32_t ints = save_and_disable_interrupts(); - // Save SRAM - flash_range_erase(offset, SRAM_SIZE); - flash_range_program(offset, SRAM, SRAM_SIZE); - // Save state - SRAM[0] = 'S'; - SRAM[1] = 'T'; - SRAM[2] = 'A'; - SRAM[3] = currentGameIndex; - SRAM[4] = advance; - flash_range_erase(state, SRAM_SIZE); - flash_range_program(state, SRAM, SRAM_SIZE); - - restore_interrupts(ints); -} +// Positions in SRAM for storing state variables +#define STATUSINDICATORPOS 0 +#define GAMEINDEXPOS 3 +#define ADVANCEPOS 4 +#define VOLUMEINDICATORPOS 5 +#define MODEPOS 8 +#define VOLUMEPOS 9 -/// about 58 Games exist with save battery +// Save NES Battery RAM (about 58 Games exist with save battery) // Problem: First call to saveNVRAM after power up is ok // Second call causes a crash in flash_range_erase() -// Because of this we reserve one flash block for saving state of current played game and selected action. -// Then the RP2040 will be rebooted +// Because of this we reserve one flash block for saving state of current played game, selected action and sound settings. +// Then the RP2040 will always be rebooted // After reboot, the state will be restored. void saveNVRAM(uint8_t statevar, char advance) { - if (!SRAMwritten) + static_assert((SRAM_SIZE & (FLASH_SECTOR_SIZE - 1)) == 0); + printf("save SRAM and/or settings\n"); + if (!SRAMwritten && saveSettingsAndReboot == false) { - printf("SRAM not updated.\n"); + printf(" SRAM not updated and no audio settings changed.\n"); return; } + + // Disable core 1 to prevent RP2040 from crashing while writing to flash. + printf(" resetting Core 1\n"); + multicore_reset_core1(); + uint32_t ints = save_and_disable_interrupts(); + + uint32_t addr = getCurrentNVRAMAddr(); + uint32_t ofs = addr - XIP_BASE; + if (addr) + { + printf(" write SRAM to flash %x --> %x\n", addr, ofs); + flash_range_erase(ofs, SRAM_SIZE); + flash_range_program(ofs, SRAM, SRAM_SIZE); + } + // Save state variables + // - Current game index + // - Advance (+ Next, - Previous, B Build-in game, R Reset) + // - Speaker mode + // - Volume + printf(" write state variables and sound settings to flash\n"); + + SRAM[STATUSINDICATORPOS] = STATUSINDICATORSTRING[0]; + SRAM[STATUSINDICATORPOS + 1] = STATUSINDICATORSTRING[1]; + SRAM[STATUSINDICATORPOS + 2] = STATUSINDICATORSTRING[2]; + SRAM[GAMEINDEXPOS] = statevar; + SRAM[ADVANCEPOS] = advance; + SRAM[VOLUMEINDICATORPOS] = VOLUMEINDICATORSTRING[0]; + SRAM[VOLUMEINDICATORPOS + 1] = VOLUMEINDICATORSTRING[1]; + SRAM[VOLUMEINDICATORPOS + 2] = VOLUMEINDICATORSTRING[2]; + SRAM[MODEPOS] = mode; + SRAM[VOLUMEPOS] = volume; + // first block of flash is reserved for storing state variables + uint32_t state = NES_BATTERY_SAVE_ADDR - XIP_BASE; + flash_range_erase(state, SRAM_SIZE); + flash_range_program(state, SRAM, SRAM_SIZE); - if (auto addr = getCurrentNVRAMAddr()) - { - printf("save SRAM\n"); - printf(" resetting Core 1\n"); - multicore_reset_core1(); - auto ofs = addr - XIP_BASE; - - printf(" write flash %x --> %x\n", addr, ofs); - _saveNVRAM(ofs, statevar, advance); - - printf(" done\n"); - printf(" Rebooting...\n"); + printf(" done\n"); + printf(" Rebooting...\n"); + restore_interrupts(ints); + // Reboot after SRAM is flashed + watchdog_enable(100, 1); + while (1) + ; - // Reboot after SRAM is flashed - watchdog_enable(100, 1); - while (1) - ; - } SRAMwritten = false; // reboot } @@ -351,6 +360,7 @@ void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) mode = (mode + 1) % 4; showSpeakerMode = SPEAKERMODEFRAMES; + saveSettingsAndReboot = true; #endif } if (pushed & GPX) @@ -364,6 +374,7 @@ void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) volume = (volume + volume_increment >= FW_VOL_MAX) ? FW_VOL_MAX : volume + volume_increment; showVolume = VOLUMEFRAMES; volumeOperator = '+'; + saveSettingsAndReboot = true; // set_fw_vol(volume); // rapidFireMask[i] ^= io::GamePadState::Button::A; } @@ -374,6 +385,7 @@ void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) volume = 0; showVolume = VOLUMEFRAMES; volumeOperator = '-'; + saveSettingsAndReboot = true; // set_fw_vol(volume); // rapidFireMask[i] ^= io::GamePadState::Button::B; } @@ -466,10 +478,10 @@ void InfoNES_SoundOutput(int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYT for (i = 0; i < samples; i++) { -#ifndef NO_OVERCLOCK +#ifndef NO_OVERCLOCK final_wave[fw_wr][i] = ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) * 4096 / 1280; -#else +#else final_wave[fw_wr][i] = ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) * 2048 / 1280; #endif @@ -724,29 +736,29 @@ void fw_callback() // int scaler = 600; #endif #ifdef SPEAKER_ENABLED - - uint16_t freq = (final_wave[fw_rd][i] * volume / 100); - switch (mode) - { - case 0: // piezo only - pwm_set_gpio_level(11, freq * 8); - pwm_set_gpio_level(1, 0); - break; - case 1: // speaker only - pwm_set_gpio_level(11, 0); - pwm_set_gpio_level(1, freq); - break; - case 2: // both only - pwm_set_gpio_level(11, freq * 8); - pwm_set_gpio_level(1, freq); - break; - case 3: // mute all - pwm_set_gpio_level(11, 0); - pwm_set_gpio_level(1, 0); - break; - } + + uint16_t freq = (final_wave[fw_rd][i] * volume / 100); + switch (mode) + { + case 0: // piezo only + pwm_set_gpio_level(11, freq * 8); + pwm_set_gpio_level(1, 0); + break; + case 1: // speaker only + pwm_set_gpio_level(11, 0); + pwm_set_gpio_level(1, freq); + break; + case 2: // both only + pwm_set_gpio_level(11, freq * 8); + pwm_set_gpio_level(1, freq); + break; + case 3: // mute all + pwm_set_gpio_level(11, 0); + pwm_set_gpio_level(1, 0); + break; + } #else - picosystem::psg_vol((scaler * final_wave[fw_rd][i] * volume) / (255 + scaler / volume)); + picosystem::psg_vol((scaler * final_wave[fw_rd][i] * volume) / (255 + scaler / volume)); #endif #if 0 } @@ -767,6 +779,7 @@ void fw_callback() int main() { char errorMessage[30]; + saveSettingsAndReboot = false; strcpy(errorMessage, ""); _init_hardware(); // _start_audio(); @@ -830,21 +843,21 @@ int main() } #endif - // When system is rebooted after dlashing SRAM, load the saved state from flash and proceed. + // When system is rebooted after flashing SRAM, load the saved state and volume from flash and proceed. loadState(); - if (watchdog_caused_reboot() && strncmp((char *)SRAM, "STA", 3) == 0) + if (watchdog_caused_reboot() && strncmp((char *)SRAM, STATUSINDICATORSTRING, 3) == 0) { // Game which caused the reboot // When reboot is caused by built-in game, startingGame will be -1 - int8_t startingGame = (int8_t)SRAM[3]; + int8_t startingGame = (int8_t)SRAM[GAMEINDEXPOS]; printf("Game caused reboot: %d\n", startingGame); // + start next Game // - start previous game // R reset to menu // B Start built-in Game - char advance = (char)SRAM[4]; + char advance = (char)SRAM[ADVANCEPOS]; int tmpGame = startingGame; // When coming from built-in game, just start the first game. if (tmpGame == -1 && advance != 'R') @@ -864,6 +877,12 @@ int main() romSelector_.setRomIndex(menu(NES_FILE_ADDR, errorMessage, true)); } prevButtons = -1; + // Restore speaker and volume settings + if (strncmp((char *)&SRAM[VOLUMEINDICATORPOS], VOLUMEINDICATORSTRING, 3) == 0) + { + mode = SRAM[MODEPOS]; + volume = SRAM[VOLUMEPOS]; + } } else { From ae0db0a65cbcde418afa5e3f36e140dd59c3633d Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sat, 5 Aug 2023 17:28:10 +0200 Subject: [PATCH 02/21] Restore audio settings fix --- main.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/main.cpp b/main.cpp index 9720de0..2b3ed90 100644 --- a/main.cpp +++ b/main.cpp @@ -736,8 +736,11 @@ void fw_callback() // int scaler = 600; #endif #ifdef SPEAKER_ENABLED - - uint16_t freq = (final_wave[fw_rd][i] * volume / 100); + // Layer812 + int scaler = 20; + uint16_t freq = (scaler * final_wave[fw_rd][i] * volume) / (255 + scaler / (volume + 1)); + // NewSchool + // uint16_t freq = (final_wave[fw_rd][i] * volume / 100); switch (mode) { case 0: // piezo only @@ -853,6 +856,12 @@ int main() // When reboot is caused by built-in game, startingGame will be -1 int8_t startingGame = (int8_t)SRAM[GAMEINDEXPOS]; printf("Game caused reboot: %d\n", startingGame); + // Restore speaker and volume settings + if (strncmp((char *)&SRAM[VOLUMEINDICATORPOS], VOLUMEINDICATORSTRING, 3) == 0) + { + mode = SRAM[MODEPOS]; + volume = SRAM[VOLUMEPOS]; + } // + start next Game // - start previous game // R reset to menu @@ -870,19 +879,15 @@ int main() if (advance == '-') romSelector_.prev(); } - if (advance == 'B') + if (advance == 'B') { romSelector_.selectcustomrom(); + } if (advance == 'R') { romSelector_.setRomIndex(menu(NES_FILE_ADDR, errorMessage, true)); } prevButtons = -1; - // Restore speaker and volume settings - if (strncmp((char *)&SRAM[VOLUMEINDICATORPOS], VOLUMEINDICATORSTRING, 3) == 0) - { - mode = SRAM[MODEPOS]; - volume = SRAM[VOLUMEPOS]; - } + } else { From aed8bc54908ec35a41707bab1bd5f4bed5b6d7a8 Mon Sep 17 00:00:00 2001 From: newschooldev Date: Sat, 5 Aug 2023 22:52:25 -0700 Subject: [PATCH 03/21] Trying to max audio loudness with this method settled on just over 14bit wrap, and just under 65k on the level ratio. Explained all changes with known math. Higher wrap = higher volume, but a buzz is also introduced if you go to high. This method does not make use of play note set freq, and curve for volume. I might try that next. Merges save changes. --- main.cpp | 36 ++++++++++++------------------------ picosystem/hardware.cpp | 11 +++++------ 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/main.cpp b/main.cpp index 2b3ed90..75ff0e3 100644 --- a/main.cpp +++ b/main.cpp @@ -478,13 +478,10 @@ void InfoNES_SoundOutput(int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYT for (i = 0; i < samples; i++) { -#ifndef NO_OVERCLOCK + //based on infones linux, 5 channels come in 1 Byte at a time per channel, which is averaged to a single byte. + //in fw_callback we deal with byte conversion to 16 bit for the pwm level. line 738 final_wave[fw_wr][i] = - ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) * 4096 / 1280; -#else - final_wave[fw_wr][i] = - ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) * 2048 / 1280; -#endif + ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) / 5; } final_wave[fw_wr][i] = -1; fw_wr = 1 - fw_wr; @@ -715,7 +712,7 @@ int InfoNES_Menu() } using namespace picosystem; - +#define levelmax 61535 void fw_callback() { uint64_t et, nt; @@ -730,21 +727,16 @@ void fw_callback() { et = to_us_since_boot(get_absolute_time()); nt = et + SAMPLE_INTERVAL; -#if 0 - if (volume > 0) - { - // int scaler = 600; -#endif + #ifdef SPEAKER_ENABLED - // Layer812 - int scaler = 20; - uint16_t freq = (scaler * final_wave[fw_rd][i] * volume) / (255 + scaler / (volume + 1)); + // NewSchool - // uint16_t freq = (final_wave[fw_rd][i] * volume / 100); + uint16_t freq_prep = (final_wave[fw_rd][i] * levelmax / 256); //byte incoming * levelmax(65535) / byte max + uint16_t freq = (freq_prep * volume / FW_VOL_MAX); //Percentage of max freq switch (mode) { case 0: // piezo only - pwm_set_gpio_level(11, freq * 8); + pwm_set_gpio_level(11, freq ); pwm_set_gpio_level(1, 0); break; case 1: // speaker only @@ -752,7 +744,7 @@ void fw_callback() pwm_set_gpio_level(1, freq); break; case 2: // both only - pwm_set_gpio_level(11, freq * 8); + pwm_set_gpio_level(11, freq ); pwm_set_gpio_level(1, freq); break; case 3: // mute all @@ -761,13 +753,9 @@ void fw_callback() break; } #else - picosystem::psg_vol((scaler * final_wave[fw_rd][i] * volume) / (255 + scaler / volume)); -#endif -#if 0 - } - else - picosystem::psg_vol(0); + picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / 256) * volume / FW_VOL_MAX); #endif + while (et < nt) { et = to_us_since_boot(get_absolute_time()); diff --git a/picosystem/hardware.cpp b/picosystem/hardware.cpp index 4fe326e..c917c63 100644 --- a/picosystem/hardware.cpp +++ b/picosystem/hardware.cpp @@ -423,9 +423,8 @@ namespace picosystem { irq_set_exclusive_handler(DMA_IRQ_0, dma_complete); irq_set_enabled(DMA_IRQ_0, true); -// limit sound frequency below 10khz to protect piezo. - #define PWM_RANGE_BITS (14) // dirty hack , also defined in hardware.hpp. - #define PWM_RANGE (1< Date: Sun, 6 Aug 2023 16:03:46 -0700 Subject: [PATCH 04/21] Applied click fix. This build uses a tweaked wrap setting - and volume adjusted to max level to account for better volume. -applied click fix, volume fix was already applied and further adjusted to account for 16bit. -buffer change where we divide by 5 to average the 5 channels, then do the level conversion during the audio playback in the fw_callback() to account for byte 256 to 16bit 65535 volume level. -tested higher wrap and levelmax with poor results, also tested lower wraps from 1,256, 5k like picosystem has as a default, and 8k-65k to find the loudest volume. I play from 20-100 volume in both mode depending on game with this build. --- main.cpp | 56 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/main.cpp b/main.cpp index 75ff0e3..d5a672c 100644 --- a/main.cpp +++ b/main.cpp @@ -37,7 +37,7 @@ bool fps_enabled = false; // final wave buffer int fw_wr, fw_rd; -unsigned int final_wave[2][735 + 1]; /* 44100 (just in case)/ 60 = 735 samples per sync */ +int final_wave[2][735 + 1]; /* 44100 (just in case)/ 60 = 735 samples per sync */ // change volume #define FW_VOL_MAX 100 @@ -730,30 +730,36 @@ void fw_callback() #ifdef SPEAKER_ENABLED - // NewSchool - uint16_t freq_prep = (final_wave[fw_rd][i] * levelmax / 256); //byte incoming * levelmax(65535) / byte max - uint16_t freq = (freq_prep * volume / FW_VOL_MAX); //Percentage of max freq - switch (mode) - { - case 0: // piezo only - pwm_set_gpio_level(11, freq ); - pwm_set_gpio_level(1, 0); - break; - case 1: // speaker only - pwm_set_gpio_level(11, 0); - pwm_set_gpio_level(1, freq); - break; - case 2: // both only - pwm_set_gpio_level(11, freq ); - pwm_set_gpio_level(1, freq); - break; - case 3: // mute all - pwm_set_gpio_level(11, 0); - pwm_set_gpio_level(1, 0); - break; + + // NewSchool from byte to 16, while maintaining ratio + uint16_t pwm_level_16 = (final_wave[fw_rd][i] * levelmax / 256); //byte incoming * levelmax(65535) / byte max + uint16_t pwm_level_volume = (pwm_level_16 * volume / FW_VOL_MAX); //Percentage of max freq + switch (mode) + { + case 0: // piezo only + pwm_set_gpio_level(11, pwm_level_volume); + pwm_set_gpio_level(1, 0); + break; + case 1: // speaker only + pwm_set_gpio_level(11, 0); + pwm_set_gpio_level(1, pwm_level_volume); + break; + case 2: // both only + pwm_set_gpio_level(11, pwm_level_volume); + pwm_set_gpio_level(1, pwm_level_volume); + break; + case 3: // mute all + pwm_set_gpio_level(11, 0); + pwm_set_gpio_level(1, 0); + break; + } } #else - picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / 256) * volume / FW_VOL_MAX); + + + // NewSchool from byte to 16, while maintaining ratio + volume ratio + picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / 256) * volume / FW_VOL_MAX); + #endif while (et < nt) @@ -764,7 +770,7 @@ void fw_callback() } final_wave[fw_rd][0] = -1; fw_rd = fw_wr; - } + } int main() @@ -776,7 +782,7 @@ int main() // _start_audio(); // set_fw_vol(50); // set_fw_vol(0); // for mute - + final_wave[0][0] = final_wave[1][0] = -1; //click fix fw_wr = fw_rd = 0; multicore_launch_core1(fw_callback); From 22d49b9f7db4f2bd34adcf91103d9158a20d1a42 Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Mon, 7 Aug 2023 17:04:44 +0200 Subject: [PATCH 05/21] Speaker and volume settings not always restored --- main.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/main.cpp b/main.cpp index d5a672c..68542e8 100644 --- a/main.cpp +++ b/main.cpp @@ -842,7 +842,13 @@ int main() // When system is rebooted after flashing SRAM, load the saved state and volume from flash and proceed. loadState(); - + // Restore speaker and volume settings + if (strncmp((char *)&SRAM[VOLUMEINDICATORPOS], VOLUMEINDICATORSTRING, 3) == 0) + { + mode = SRAM[MODEPOS]; + volume = SRAM[VOLUMEPOS]; + printf("Restored mode %d, volume %d\n", mode, volume); + } if (watchdog_caused_reboot() && strncmp((char *)SRAM, STATUSINDICATORSTRING, 3) == 0) { @@ -850,12 +856,7 @@ int main() // When reboot is caused by built-in game, startingGame will be -1 int8_t startingGame = (int8_t)SRAM[GAMEINDEXPOS]; printf("Game caused reboot: %d\n", startingGame); - // Restore speaker and volume settings - if (strncmp((char *)&SRAM[VOLUMEINDICATORPOS], VOLUMEINDICATORSTRING, 3) == 0) - { - mode = SRAM[MODEPOS]; - volume = SRAM[VOLUMEPOS]; - } + // + start next Game // - start previous game // R reset to menu From ea68dc41eb8b4194d8e0be33ab2cbe43c59e5799 Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Mon, 7 Aug 2023 17:25:39 +0200 Subject: [PATCH 06/21] Show program version in flash and menu --- menu.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/menu.cpp b/menu.cpp index eb38653..e1e4771 100644 --- a/menu.cpp +++ b/menu.cpp @@ -188,10 +188,11 @@ void displayRoms(Frens::RomLister romlister, int startIndex) { char buffer[ROMLISTER_MAXPATH + 4]; auto y = STARTROW; + auto entries = romlister.GetEntries(); ClearScreen(screenBuffer, bgcolor); putText(1, 0, "Choose a rom to play:", fgcolor, bgcolor); - putText(1, SCREEN_ROWS - 1, "A: Select, B: Back", fgcolor, bgcolor); + putText(1, SCREEN_ROWS - 1, "A:Select, B:Back " PICO_PROGRAM_VERSION_STRING, fgcolor, bgcolor); for (auto index = startIndex; index < romlister.Count(); index++) { if (y <= ENDROW) @@ -282,6 +283,9 @@ void showSplashScreen() strcpy(s, "@Layer812"); putText(SCREEN_COLS / 2 - strlen(s) / 2, 20, s, CLIGHTBLUE, bgcolor); + strcpy(s, PICO_PROGRAM_VERSION_STRING); + putText(SCREEN_COLS / 2 - strlen(s) / 2, 23, s, fgcolor, bgcolor); + strcpy(s, "https://github.com/"); putText(SCREEN_COLS / 2 - strlen(s) / 2, 25, s, CLIGHTBLUE, bgcolor); strcpy(s, "fhoedemakers/"); @@ -298,7 +302,7 @@ void showSplashScreen() } DrawScreen(-1); RomSelect_PadState(&PAD1_Latch); - if (PAD1_Latch > 0 || (frameCount - startFrame) > 250) + if (PAD1_Latch > 0 || (frameCount - startFrame) > 500) { return; } From 78beadbbd9b90d564910c5a572963ffdccc5c8ce Mon Sep 17 00:00:00 2001 From: newschooldev Date: Tue, 8 Aug 2023 00:26:38 -0700 Subject: [PATCH 07/21] overclock update adjusting top (levelmax) With these settings I can hear the warning sound just before overheat on excitebike with both piezo and speaker. -adjusted sample rate for overclock --- infones/InfoNES_pAPU.h | 3 ++- main.cpp | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/infones/InfoNES_pAPU.h b/infones/InfoNES_pAPU.h index e57a1b3..a327e29 100644 --- a/infones/InfoNES_pAPU.h +++ b/infones/InfoNES_pAPU.h @@ -169,7 +169,8 @@ void InfoNES_pAPUHsync(bool enabled); /*-------------------------------------------------------------------*/ extern int ApuQuality; #define pAPU_QUALITY 3 // 44,100 Hz -#define SAMPLE_INTERVAL 22 // 1,000,000 us / 44,100 Hz +#define SAMPLE_INTERVAL 57 // 1,000,000 us / 44,100 Hz +//2,500,000 us 250mhz overclock / 44,100 = 56.6 /*-------------------------------------------------------------------*/ /* Rectangle Wave #1 resources */ diff --git a/main.cpp b/main.cpp index 68542e8..f2d5380 100644 --- a/main.cpp +++ b/main.cpp @@ -481,7 +481,7 @@ void InfoNES_SoundOutput(int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYT //based on infones linux, 5 channels come in 1 Byte at a time per channel, which is averaged to a single byte. //in fw_callback we deal with byte conversion to 16 bit for the pwm level. line 738 final_wave[fw_wr][i] = - ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) / 5; + ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) /5; } final_wave[fw_wr][i] = -1; fw_wr = 1 - fw_wr; @@ -712,7 +712,7 @@ int InfoNES_Menu() } using namespace picosystem; -#define levelmax 61535 +#define levelmax 53535 //palindrome void fw_callback() { uint64_t et, nt; @@ -732,8 +732,8 @@ void fw_callback() // NewSchool from byte to 16, while maintaining ratio - uint16_t pwm_level_16 = (final_wave[fw_rd][i] * levelmax / 256); //byte incoming * levelmax(65535) / byte max - uint16_t pwm_level_volume = (pwm_level_16 * volume / FW_VOL_MAX); //Percentage of max freq + uint16_t pwm_level_16 = final_wave[fw_rd][i] *levelmax / 256; //byte incoming * levelmax(< 65535) / byte max + uint16_t pwm_level_volume = pwm_level_16 * volume / FW_VOL_MAX; //Percentage of max freq switch (mode) { case 0: // piezo only @@ -898,6 +898,10 @@ int main() InfoNES_Main(); if (jumptomenu) { + pwm_set_gpio_level(11, 0); +#ifdef SPEAKER_ENABLED + pwm_set_gpio_level(1, 0); +#endif //fix sound continue from exit to menu while playing a game. romSelector_.setRomIndex(menu(NES_FILE_ADDR, errorMessage)); } } From 763d1189c881007db66954018e2950fbb6c533db Mon Sep 17 00:00:00 2001 From: newschooldev Date: Tue, 8 Aug 2023 02:31:47 -0700 Subject: [PATCH 08/21] 1280 fix --- main.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/main.cpp b/main.cpp index f2d5380..e396ca3 100644 --- a/main.cpp +++ b/main.cpp @@ -478,10 +478,9 @@ void InfoNES_SoundOutput(int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYT for (i = 0; i < samples; i++) { - //based on infones linux, 5 channels come in 1 Byte at a time per channel, which is averaged to a single byte. - //in fw_callback we deal with byte conversion to 16 bit for the pwm level. line 738 + final_wave[fw_wr][i] = - ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]) /5; + ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]); } final_wave[fw_wr][i] = -1; fw_wr = 1 - fw_wr; @@ -713,6 +712,7 @@ int InfoNES_Menu() using namespace picosystem; #define levelmax 53535 //palindrome +#define buffermax 1280 void fw_callback() { uint64_t et, nt; @@ -732,8 +732,12 @@ void fw_callback() // NewSchool from byte to 16, while maintaining ratio - uint16_t pwm_level_16 = final_wave[fw_rd][i] *levelmax / 256; //byte incoming * levelmax(< 65535) / byte max + uint16_t pwm_level_16 = final_wave[fw_rd][i] *levelmax / buffermax; //byte incoming * levelmax(< 65535) / byte max uint16_t pwm_level_volume = pwm_level_16 * volume / FW_VOL_MAX; //Percentage of max freq + + // the change in volume isn't linear - we correct for this here + // float curve = 2.4f; + // uint32_t pwm_level_volume = (pow((float)(volume) / (float)FW_VOL_MAX, curve) * pwm_level_16); switch (mode) { case 0: // piezo only @@ -758,7 +762,7 @@ void fw_callback() // NewSchool from byte to 16, while maintaining ratio + volume ratio - picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / 256) * volume / FW_VOL_MAX); + picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / buffermax) * volume / FW_VOL_MAX); #endif From 295f0fe883db22dc5c74c597511018114d96100d Mon Sep 17 00:00:00 2001 From: newschooldev Date: Tue, 8 Aug 2023 19:22:19 -0700 Subject: [PATCH 09/21] audio update -moved volume mode up so volume and mode can show at same time. -found example of 44100 hz pwm and applied the math from it. -piezo still too quiet, I did a *3 boost to get max volume due to piezo volume drop over frequency range. now okay --- infones/InfoNES_pAPU.h | 3 +- main.cpp | 97 +++++++++++++++++++++++------------------ picosystem/hardware.cpp | 33 ++++++++++---- 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/infones/InfoNES_pAPU.h b/infones/InfoNES_pAPU.h index a327e29..f1aca89 100644 --- a/infones/InfoNES_pAPU.h +++ b/infones/InfoNES_pAPU.h @@ -169,8 +169,7 @@ void InfoNES_pAPUHsync(bool enabled); /*-------------------------------------------------------------------*/ extern int ApuQuality; #define pAPU_QUALITY 3 // 44,100 Hz -#define SAMPLE_INTERVAL 57 // 1,000,000 us / 44,100 Hz -//2,500,000 us 250mhz overclock / 44,100 = 56.6 +#define SAMPLE_INTERVAL 22 /*-------------------------------------------------------------------*/ /* Rectangle Wave #1 resources */ diff --git a/main.cpp b/main.cpp index e396ca3..bf0c9af 100644 --- a/main.cpp +++ b/main.cpp @@ -478,9 +478,7 @@ void InfoNES_SoundOutput(int samples, BYTE *wave1, BYTE *wave2, BYTE *wave3, BYT for (i = 0; i < samples; i++) { - - final_wave[fw_wr][i] = - ((unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]); + final_wave[fw_wr][i] = (unsigned char)wave1[i] + (unsigned char)wave2[i] + (unsigned char)wave3[i] + (unsigned char)wave4[i] + (unsigned char)wave5[i]; } final_wave[fw_wr][i] = -1; fw_wr = 1 - fw_wr; @@ -611,6 +609,21 @@ void __not_in_flash_func(InfoNES_PostDrawLine)(int line, bool frommenu) fpsBuffer += 8; } } + +#ifdef SPEAKER_ENABLED + if (showSpeakerMode > 0 && line >= 96 && line < 104) + { + int l = (strlen(modeStrings[mode]) * 8) / 2; + fpsBuffer = lb + 104 - l; + int rowInChar = line % 8; + for (auto i = 0; i < strlen(modeStrings[mode]); i++) + { + char aChar = modeStrings[mode][i]; + DisplayChar(fpsBuffer, rowInChar, aChar, fgc, bgc); + fpsBuffer += 8; + } + } +#endif if (showVolume > 0 && line >= 120 && line < 128) { fpsBuffer = lb + 120; @@ -629,20 +642,6 @@ void __not_in_flash_func(InfoNES_PostDrawLine)(int line, bool frommenu) fpsBuffer += 8; } } -#ifdef SPEAKER_ENABLED - if (showSpeakerMode > 0 && line >= 120 && line < 128) - { - int l = (strlen(modeStrings[mode]) * 8) / 2; - fpsBuffer = lb + 120 - l; - int rowInChar = line % 8; - for (auto i = 0; i < strlen(modeStrings[mode]); i++) - { - char aChar = modeStrings[mode][i]; - DisplayChar(fpsBuffer, rowInChar, aChar, fgc, bgc); - fpsBuffer += 8; - } - } -#endif bufferIndex = hw_divider_s32_quotient_inlined(line, SCANLINEBUFFERLINES) & 1; lineInBuffer = hw_divider_s32_remainder_inlined(line, SCANLINEBUFFERLINES); @@ -711,7 +710,12 @@ int InfoNES_Menu() } using namespace picosystem; -#define levelmax 53535 //palindrome +#define speakerlevelmax 5669 //pwm wrap + 1 + +//piezo has a volume drop over a short range of audible sound, this boosts the sound. +//*3 is the most I can get with out the top losing resolution. +#define piezolevelmax 5669 * 3 + #define buffermax 1280 void fw_callback() { @@ -729,28 +733,29 @@ void fw_callback() nt = et + SAMPLE_INTERVAL; #ifdef SPEAKER_ENABLED - - - // NewSchool from byte to 16, while maintaining ratio - uint16_t pwm_level_16 = final_wave[fw_rd][i] *levelmax / buffermax; //byte incoming * levelmax(< 65535) / byte max - uint16_t pwm_level_volume = pwm_level_16 * volume / FW_VOL_MAX; //Percentage of max freq - - // the change in volume isn't linear - we correct for this here - // float curve = 2.4f; - // uint32_t pwm_level_volume = (pow((float)(volume) / (float)FW_VOL_MAX, curve) * pwm_level_16); + + + if (final_wave[fw_rd][i] > 0) + { + uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax / (float)buffermax; + uint16_t pwm_piezo_level_volume = pwm_piezo_level_16 * volume / FW_VOL_MAX; + + uint16_t pwm_speaker_level_16 = final_wave[fw_rd][i] * speakerlevelmax / (float)buffermax; + uint16_t pwm_speaker_level_volume = pwm_speaker_level_16 * volume / FW_VOL_MAX; //Percentage of max freq + switch (mode) { case 0: // piezo only - pwm_set_gpio_level(11, pwm_level_volume); + pwm_set_gpio_level(11, pwm_piezo_level_volume); pwm_set_gpio_level(1, 0); break; case 1: // speaker only pwm_set_gpio_level(11, 0); - pwm_set_gpio_level(1, pwm_level_volume); + pwm_set_gpio_level(1, pwm_speaker_level_volume); break; case 2: // both only - pwm_set_gpio_level(11, pwm_level_volume); - pwm_set_gpio_level(1, pwm_level_volume); + pwm_set_gpio_level(11, pwm_piezo_level_volume); + pwm_set_gpio_level(1, pwm_speaker_level_volume); break; case 3: // mute all pwm_set_gpio_level(11, 0); @@ -758,22 +763,28 @@ void fw_callback() break; } } + else + { + pwm_set_gpio_level(11, 0); + pwm_set_gpio_level(1, 0); + } #else - - - // NewSchool from byte to 16, while maintaining ratio + volume ratio - picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / buffermax) * volume / FW_VOL_MAX); - + + + // NewSchool from byte to 16, while maintaining ratio + volume ratio + picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / buffermax) * volume / FW_VOL_MAX); + #endif - while (et < nt) - { - et = to_us_since_boot(get_absolute_time()); - sleep_us(1); - } + while (et < nt) + { + et = to_us_since_boot(get_absolute_time()); + sleep_us(1); } - final_wave[fw_rd][0] = -1; - fw_rd = fw_wr; + } + } + final_wave[fw_rd][0] = -1; + fw_rd = fw_wr; } diff --git a/picosystem/hardware.cpp b/picosystem/hardware.cpp index c917c63..09cdc02 100644 --- a/picosystem/hardware.cpp +++ b/picosystem/hardware.cpp @@ -423,9 +423,23 @@ namespace picosystem { irq_set_exclusive_handler(DMA_IRQ_0, dma_complete); irq_set_enabled(DMA_IRQ_0, true); -#define PWM_RANGE_BITS (14) -#define PWM_RANGE ((1 << PWM_RANGE_BITS)+4096) //highest I can get it with out causing a ringing in high pitch. - + //audio example at 44,100 using wrap + 1 as level max. + // https://raspberrypi.stackexchange.com/questions/137671/cant-generate-pwm-output-on-rp2040-other-than-square-waves + // 3,015 * 1.00029 * 44,100 = 133,000,000 + //pwm_config_set_clkdiv(&config, 1.00029f); + //pwm_config_set_wrap(&config, 3015); + + // x * yf * 44100 = 250,000,000 = 5668.93424 + // x = 5668.93424 / 5668 = 1.00016f; + // 5668 * 1.00016f * 44100 = 250,000,000 + + // a wrap of 1280 @ 44100hz needs div of 4.428854f = 250,000,000 + // a wrap of 12800 @ 44100hz needs a div of 0.442885f which is lower then the 1.0f min. + // + // if your trying t get 12800hz from the pmw div or wrap must be changed + // a wrap of 19,531 * 1.00001f * 12800hz = 250000000 + // the default pwm config sets div to 1.0f + // // initialise audio pwm pin int audio_pwm_slice_number = pwm_gpio_to_slice_num(AUDIO); pwm_config audio_pwm_cfg = pwm_get_default_config(); @@ -433,21 +447,22 @@ namespace picosystem { gpio_set_function(AUDIO, GPIO_FUNC_PWM); pwm_set_gpio_level(AUDIO, 0); - pwm_config_set_wrap(&audio_pwm_cfg, PWM_RANGE); + pwm_config_set_clkdiv(&audio_pwm_cfg, 1.00016f); + pwm_config_set_wrap(&audio_pwm_cfg, 5668); + // init extra speaker. #ifdef SPEAKER_ENABLED - #define PWM_RANGE_BITS_S (14) //seems good enough. - #define PWM_RANGE_S ((1 << PWM_RANGE_BITS_S) +4096) - int audio_pwm_slice_numberS = pwm_gpio_to_slice_num(RX); pwm_config audio_pwm_cfgS = pwm_get_default_config(); gpio_set_function(RX, GPIO_FUNC_PWM); pwm_set_gpio_level(RX, 0); - pwm_config_set_wrap(&audio_pwm_cfgS, PWM_RANGE_S); + pwm_config_set_clkdiv(&audio_pwm_cfgS, 1.00016f); + pwm_config_set_wrap(&audio_pwm_cfgS, 5668); //5669 maxlevel + - pwm_init(audio_pwm_slice_numberS, &audio_pwm_cfgS, true);//sharing config for now + pwm_init(audio_pwm_slice_numberS, &audio_pwm_cfgS, true); #endif pwm_init(audio_pwm_slice_number, &audio_pwm_cfg, true); From 7c286931f8d577b262fefe782485d258fb7b267f Mon Sep 17 00:00:00 2001 From: newschooldev Date: Wed, 9 Aug 2023 18:41:17 -0700 Subject: [PATCH 10/21] Audio fix Thanks Layer812 I now understand the relationships. I was able to set your preferred settings with the wrap, and still get the volume boost on the piezo. I have it set to * 2.8f, 2-4 seems to be a decent range. however playing at 100 volume on some games can be too much. like blade buster hb is a bit much at 100, but like smb 100 is great. --- main.cpp | 8 ++------ picosystem/hardware.cpp | 27 +++------------------------ 2 files changed, 5 insertions(+), 30 deletions(-) diff --git a/main.cpp b/main.cpp index bf0c9af..298017e 100644 --- a/main.cpp +++ b/main.cpp @@ -710,11 +710,8 @@ int InfoNES_Menu() } using namespace picosystem; -#define speakerlevelmax 5669 //pwm wrap + 1 -//piezo has a volume drop over a short range of audible sound, this boosts the sound. -//*3 is the most I can get with out the top losing resolution. -#define piezolevelmax 5669 * 3 +#define piezolevelmax 12800 * 2.8f #define buffermax 1280 void fw_callback() @@ -740,8 +737,7 @@ void fw_callback() uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax / (float)buffermax; uint16_t pwm_piezo_level_volume = pwm_piezo_level_16 * volume / FW_VOL_MAX; - uint16_t pwm_speaker_level_16 = final_wave[fw_rd][i] * speakerlevelmax / (float)buffermax; - uint16_t pwm_speaker_level_volume = pwm_speaker_level_16 * volume / FW_VOL_MAX; //Percentage of max freq + uint16_t pwm_speaker_level_volume = final_wave[fw_rd][i] * volume / FW_VOL_MAX; //Percentage of max freq switch (mode) { diff --git a/picosystem/hardware.cpp b/picosystem/hardware.cpp index 09cdc02..9280363 100644 --- a/picosystem/hardware.cpp +++ b/picosystem/hardware.cpp @@ -423,33 +423,14 @@ namespace picosystem { irq_set_exclusive_handler(DMA_IRQ_0, dma_complete); irq_set_enabled(DMA_IRQ_0, true); - //audio example at 44,100 using wrap + 1 as level max. - // https://raspberrypi.stackexchange.com/questions/137671/cant-generate-pwm-output-on-rp2040-other-than-square-waves - // 3,015 * 1.00029 * 44,100 = 133,000,000 - //pwm_config_set_clkdiv(&config, 1.00029f); - //pwm_config_set_wrap(&config, 3015); - - // x * yf * 44100 = 250,000,000 = 5668.93424 - // x = 5668.93424 / 5668 = 1.00016f; - // 5668 * 1.00016f * 44100 = 250,000,000 - - // a wrap of 1280 @ 44100hz needs div of 4.428854f = 250,000,000 - // a wrap of 12800 @ 44100hz needs a div of 0.442885f which is lower then the 1.0f min. - // - // if your trying t get 12800hz from the pmw div or wrap must be changed - // a wrap of 19,531 * 1.00001f * 12800hz = 250000000 - // the default pwm config sets div to 1.0f - // // initialise audio pwm pin int audio_pwm_slice_number = pwm_gpio_to_slice_num(AUDIO); pwm_config audio_pwm_cfg = pwm_get_default_config(); gpio_set_function(AUDIO, GPIO_FUNC_PWM); pwm_set_gpio_level(AUDIO, 0); + pwm_config_set_wrap(&audio_pwm_cfg, 12799); - pwm_config_set_clkdiv(&audio_pwm_cfg, 1.00016f); - pwm_config_set_wrap(&audio_pwm_cfg, 5668); - // init extra speaker. #ifdef SPEAKER_ENABLED @@ -458,11 +439,9 @@ namespace picosystem { gpio_set_function(RX, GPIO_FUNC_PWM); pwm_set_gpio_level(RX, 0); - pwm_config_set_clkdiv(&audio_pwm_cfgS, 1.00016f); - pwm_config_set_wrap(&audio_pwm_cfgS, 5668); //5669 maxlevel - - + pwm_config_set_wrap(&audio_pwm_cfgS, 1279);//one less then level max. pwm_init(audio_pwm_slice_numberS, &audio_pwm_cfgS, true); + #endif pwm_init(audio_pwm_slice_number, &audio_pwm_cfg, true); From c4d2312bb0311a6bde0a28fd161c97ef7a953aa3 Mon Sep 17 00:00:00 2001 From: newschooldev Date: Wed, 9 Aug 2023 19:15:33 -0700 Subject: [PATCH 11/21] Clipping fix clips the excess volume. --- main.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/main.cpp b/main.cpp index 298017e..274d902 100644 --- a/main.cpp +++ b/main.cpp @@ -711,7 +711,7 @@ int InfoNES_Menu() using namespace picosystem; -#define piezolevelmax 12800 * 2.8f +#define piezolevelmax 12800 #define buffermax 1280 void fw_callback() @@ -734,7 +734,12 @@ void fw_callback() if (final_wave[fw_rd][i] > 0) { - uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax / (float)buffermax; + uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax * 2.8f / (float)buffermax; + //cut off clipping + if (pwm_piezo_level_16 > 12800) { + pwm_piezo_level_16 = 12800; + } + uint16_t pwm_piezo_level_volume = pwm_piezo_level_16 * volume / FW_VOL_MAX; uint16_t pwm_speaker_level_volume = final_wave[fw_rd][i] * volume / FW_VOL_MAX; //Percentage of max freq From 2ce439c3206713d1c384fad6e2d0782f7176f0a3 Mon Sep 17 00:00:00 2001 From: newschooldev Date: Thu, 10 Aug 2023 21:49:11 -0700 Subject: [PATCH 12/21] volume issues solved Secret Menu added with new setting -Overdrive multiplier, default 2.8, and is now used for both with clip protection. Y+Down multiple time to get to-> mute mode (3) then Y+A + Y + B - to adjust over drive setting. Todo- set min max, and save restore. --- main.cpp | 92 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/main.cpp b/main.cpp index 274d902..ee006c4 100644 --- a/main.cpp +++ b/main.cpp @@ -41,13 +41,13 @@ int final_wave[2][735 + 1]; /* 44100 (just in case)/ 60 = 735 samples per sync * // change volume #define FW_VOL_MAX 100 -int volume = 50; +int volume = 100; unsigned int volume_increment = 10; #define VOLUMEFRAMES 120 // number of frames the volume is shown int showVolume = 0; // When > 0 volume is shown on screen char volumeOperator = '+'; // '+' or '-' to indicate if volume is increased or decreased #include "font_8x8.h" - +float overdrive = 2.8f; // speaker #ifdef SPEAKER_ENABLED int mode = 0; // 0= piezo only 1= speaker only 2= both 3= mute all @@ -286,12 +286,12 @@ int getbuttons() (picosystem::button(picosystem::B) ? GPB : 0) | 0; } -static DWORD prevButtons = 0; -static int rapidFireMask = 0; -static int rapidFireCounter = 0; -static bool jumptomenu = false; + static DWORD prevButtons = 0; + static int rapidFireMask = 0; + static int rapidFireCounter = 0; + static bool jumptomenu = false; -void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) + void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) { // moved variables outside function body because prevButtons gets initialized to 0 everytime the function is called. @@ -302,6 +302,8 @@ void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) // static int rapidFireMask = 0; // static int rapidFireCounter = 0; + + ++rapidFireCounter; bool reset = jumptomenu = false; @@ -369,25 +371,50 @@ void InfoNES_PadState(DWORD *pdwPad1, DWORD *pdwPad2, DWORD *pdwSystem) reset = true; jumptomenu = true; } - if (pushed & GPA) + if (mode != 3) { - volume = (volume + volume_increment >= FW_VOL_MAX) ? FW_VOL_MAX : volume + volume_increment; - showVolume = VOLUMEFRAMES; - volumeOperator = '+'; - saveSettingsAndReboot = true; - // set_fw_vol(volume); - // rapidFireMask[i] ^= io::GamePadState::Button::A; + if (pushed & GPA) + { + volume = (volume + volume_increment >= FW_VOL_MAX) ? FW_VOL_MAX : volume + volume_increment; + showVolume = VOLUMEFRAMES; + volumeOperator = '+'; + saveSettingsAndReboot = true; + // set_fw_vol(volume); + // rapidFireMask[i] ^= io::GamePadState::Button::A; + } + if (pushed & GPB) + { + volume = volume - volume_increment; + if (volume < 0) + volume = 0; + showVolume = VOLUMEFRAMES; + volumeOperator = '-'; + saveSettingsAndReboot = true; + // set_fw_vol(volume); + // rapidFireMask[i] ^= io::GamePadState::Button::B; + } } - if (pushed & GPB) + else { - volume = volume - volume_increment; - if (volume < 0) - volume = 0; - showVolume = VOLUMEFRAMES; - volumeOperator = '-'; - saveSettingsAndReboot = true; - // set_fw_vol(volume); - // rapidFireMask[i] ^= io::GamePadState::Button::B; + if (pushed & GPA) + { + overdrive += 0.1f; + showVolume = VOLUMEFRAMES; + volumeOperator = '+'; + //saveSettingsAndReboot = true; + // set_fw_vol(volume); + // rapidFireMask[i] ^= io::GamePadState::Button::A; + } + if (pushed & GPB) + { + overdrive -= 0.1f; + + showVolume = VOLUMEFRAMES; + volumeOperator = '-'; + //saveSettingsAndReboot = true; + // set_fw_vol(volume); + // rapidFireMask[i] ^= io::GamePadState::Button::B; + } } } @@ -588,7 +615,7 @@ void __not_in_flash_func(InfoNES_PostDrawLine)(int line, bool frommenu) drawWorkMeter(line); #endif - char charBuffer[5]; + char charBuffer[9]; WORD *fpsBuffer = nullptr; WORD fgc = NesPalette[48]; WORD bgc = NesPalette[15]; @@ -627,12 +654,16 @@ void __not_in_flash_func(InfoNES_PostDrawLine)(int line, bool frommenu) if (showVolume > 0 && line >= 120 && line < 128) { fpsBuffer = lb + 120; - // fill charbuffer with 3 digits from volume + // fill charbuffer with volume and overdrive. charBuffer[0] = volumeOperator; charBuffer[1] = '0' + (volume / 100); charBuffer[2] = '0' + ((volume % 100) / 10); charBuffer[3] = '0' + (volume % 10); - charBuffer[4] = 0; + charBuffer[4] = '*'; + charBuffer[5] = '0' + ((short)overdrive % 10); + charBuffer[6] = '.'; + charBuffer[7] = '0' + ((short)(overdrive * 10) % 10); + charBuffer[8] = 0; int rowInChar = line % 8; for (auto i = 0; i < strlen(charBuffer); i++) @@ -712,7 +743,6 @@ int InfoNES_Menu() using namespace picosystem; #define piezolevelmax 12800 - #define buffermax 1280 void fw_callback() { @@ -734,7 +764,7 @@ void fw_callback() if (final_wave[fw_rd][i] > 0) { - uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax * 2.8f / (float)buffermax; + uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax * overdrive / (float)buffermax; //cut off clipping if (pwm_piezo_level_16 > 12800) { pwm_piezo_level_16 = 12800; @@ -742,8 +772,10 @@ void fw_callback() uint16_t pwm_piezo_level_volume = pwm_piezo_level_16 * volume / FW_VOL_MAX; - uint16_t pwm_speaker_level_volume = final_wave[fw_rd][i] * volume / FW_VOL_MAX; //Percentage of max freq - + uint16_t pwm_speaker_level_volume = final_wave[fw_rd][i] * overdrive * volume / FW_VOL_MAX; //Percentage of max freq + if (pwm_speaker_level_volume > 1280) { + pwm_speaker_level_volume = 1280; + } switch (mode) { case 0: // piezo only From d15ae1aafbad96af93b5f0f131c7b9745937d6ac Mon Sep 17 00:00:00 2001 From: newschooldev Date: Fri, 11 Aug 2023 20:53:32 -0700 Subject: [PATCH 13/21] removed secrect menu replaced overdrive menu with suggested scale from Layer8 onto the normal volume up down. -volume @ 1-50 act like 1-100 -volume @ 51-100 increment the overdrive factor from 1.3-4 ish. -changed increment to +-5 -left the display of factor for debugging, but it could be removed, or left either way. --- main.cpp | 109 ++++++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/main.cpp b/main.cpp index ee006c4..4672b43 100644 --- a/main.cpp +++ b/main.cpp @@ -41,13 +41,13 @@ int final_wave[2][735 + 1]; /* 44100 (just in case)/ 60 = 735 samples per sync * // change volume #define FW_VOL_MAX 100 -int volume = 100; -unsigned int volume_increment = 10; +int volume = 40; +unsigned int volume_increment = 5; #define VOLUMEFRAMES 120 // number of frames the volume is shown int showVolume = 0; // When > 0 volume is shown on screen char volumeOperator = '+'; // '+' or '-' to indicate if volume is increased or decreased #include "font_8x8.h" -float overdrive = 2.8f; +float overdrive = 1.0f; // speaker #ifdef SPEAKER_ENABLED int mode = 0; // 0= piezo only 1= speaker only 2= both 3= mute all @@ -371,51 +371,28 @@ int getbuttons() reset = true; jumptomenu = true; } - if (mode != 3) + + if (pushed & GPA) { - if (pushed & GPA) - { - volume = (volume + volume_increment >= FW_VOL_MAX) ? FW_VOL_MAX : volume + volume_increment; - showVolume = VOLUMEFRAMES; - volumeOperator = '+'; - saveSettingsAndReboot = true; - // set_fw_vol(volume); - // rapidFireMask[i] ^= io::GamePadState::Button::A; - } - if (pushed & GPB) - { - volume = volume - volume_increment; - if (volume < 0) - volume = 0; - showVolume = VOLUMEFRAMES; - volumeOperator = '-'; - saveSettingsAndReboot = true; - // set_fw_vol(volume); - // rapidFireMask[i] ^= io::GamePadState::Button::B; - } + volume = (volume + volume_increment >= FW_VOL_MAX) ? FW_VOL_MAX : volume + volume_increment; + showVolume = VOLUMEFRAMES; + volumeOperator = '+'; + saveSettingsAndReboot = true; + // set_fw_vol(volume); + // rapidFireMask[i] ^= io::GamePadState::Button::A; } - else + if (pushed & GPB) { - if (pushed & GPA) - { - overdrive += 0.1f; - showVolume = VOLUMEFRAMES; - volumeOperator = '+'; - //saveSettingsAndReboot = true; - // set_fw_vol(volume); - // rapidFireMask[i] ^= io::GamePadState::Button::A; - } - if (pushed & GPB) - { - overdrive -= 0.1f; - - showVolume = VOLUMEFRAMES; - volumeOperator = '-'; - //saveSettingsAndReboot = true; - // set_fw_vol(volume); - // rapidFireMask[i] ^= io::GamePadState::Button::B; - } + volume = volume - volume_increment; + if (volume < 0) + volume = 0; + showVolume = VOLUMEFRAMES; + volumeOperator = '-'; + saveSettingsAndReboot = true; + // set_fw_vol(volume); + // rapidFireMask[i] ^= io::GamePadState::Button::B; } + } prevButtons = v; @@ -742,7 +719,7 @@ int InfoNES_Menu() using namespace picosystem; -#define piezolevelmax 12800 +#define piezolevelmax 12800 #define buffermax 1280 void fw_callback() { @@ -764,17 +741,35 @@ void fw_callback() if (final_wave[fw_rd][i] > 0) { - uint16_t pwm_piezo_level_16 = final_wave[fw_rd][i] * piezolevelmax * overdrive / (float)buffermax; - //cut off clipping - if (pwm_piezo_level_16 > 12800) { - pwm_piezo_level_16 = 12800; - } - - uint16_t pwm_piezo_level_volume = pwm_piezo_level_16 * volume / FW_VOL_MAX; + //volume setting 0-50 : 0-100 volume output + //volume 51-100 : 1.1 - 4.0 overdrive multiplyer. + uint16_t volumelevel = final_wave[fw_rd][i]; + uint16_t pwm_piezo_level_volume, pwm_speaker_level_volume; - uint16_t pwm_speaker_level_volume = final_wave[fw_rd][i] * overdrive * volume / FW_VOL_MAX; //Percentage of max freq - if (pwm_speaker_level_volume > 1280) { - pwm_speaker_level_volume = 1280; + if (volume > 0 && volume < 51) + { + //0-50 + pwm_piezo_level_volume = (volumelevel * piezolevelmax / (float)buffermax) * (volume * 2) / FW_VOL_MAX; + pwm_speaker_level_volume = volumelevel * (volume * 2) / FW_VOL_MAX; + overdrive = 1.0f;//for display + } + else if (volume > 50) + { + overdrive =(((volume-50) * 2.92f) / (FW_VOL_MAX * 0.5f)) + 1.08f; //0.02 - 1 * 2.92f + 1.08f = 1.1-4.0f + //100 volume so no reduction. * overdrive + pwm_piezo_level_volume =ceil(volumelevel * overdrive * piezolevelmax / (float)buffermax); + pwm_speaker_level_volume =ceil( volumelevel * overdrive); + //clipping + if (pwm_piezo_level_volume > piezolevelmax) { + pwm_piezo_level_volume = piezolevelmax; + } + if (pwm_speaker_level_volume > buffermax) { + pwm_speaker_level_volume = buffermax; + } + } + else { + pwm_piezo_level_volume = 0; + pwm_speaker_level_volume = 0; } switch (mode) { @@ -804,8 +799,8 @@ void fw_callback() #else - // NewSchool from byte to 16, while maintaining ratio + volume ratio - picosystem::psg_vol((final_wave[fw_rd][i] * levelmax / buffermax) * volume / FW_VOL_MAX); + // needs update. + picosystem::psg_vol((final_wave[fw_rd][i] * piezolevelmax / (float)buffermax) * volume / FW_VOL_MAX); #endif From f4bd59d9380cb695b84be2c9f3d4763f17603be2 Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sat, 12 Aug 2023 13:45:09 +0200 Subject: [PATCH 14/21] Update CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdd8403..63d2f19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,16 @@ See [Readme](https://github.com/fhoedemakers/PicoSystem_InfoNes/blob/master/READ ## Release History +### 1.0.0 (2023-08-13) + +Fixes: + +- improved audio for second speaker. + +Features + +- Speaker selection and volume settings are saved now. You must reset to menu (Y + X) or toggle game (Y + Left, Y + Right or Y + UP) for this to work. + ### 0.9-alpha (2023-08-03) Fixes: From 2f382490925d03834e7ed3101bfe9713560efaef Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sat, 12 Aug 2023 13:45:41 +0200 Subject: [PATCH 15/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d2f19..ade41cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ Fixes: Features -- Speaker selection and volume settings are saved now. You must reset to menu (Y + X) or toggle game (Y + Left, Y + Right or Y + UP) for this to work. +- Speaker selection and volume settings are saved now. You must reset to menu (Y + X) or toggle game (Y + Left, Y + Right or Y + Up) for this to work. ### 0.9-alpha (2023-08-03) From 617b48003b85db01770cdd03f2cb586979cf0291 Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sat, 12 Aug 2023 13:51:16 +0200 Subject: [PATCH 16/21] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 19e500e..6c9926e 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,8 @@ picotool load games.tar -t bin -o 0x10110000 - Y + A: Volume up - Y + B: Volume down +> Speaker selection and volume level will be saved, but only when you reset to menu ( X + Y ) or toggle between games (Y + Left, Y + Right, Y + Up). Powering-off the device will not save these settings. + ### In-Menu - Up/DOWN: Scroll through list - A : Start selected game From 202cafcb5e391baba9848554374095b836d4b192 Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sat, 12 Aug 2023 13:52:23 +0200 Subject: [PATCH 17/21] Updated CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ade41cd..395695f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ See [Readme](https://github.com/fhoedemakers/PicoSystem_InfoNes/blob/master/READ Fixes: -- improved audio for second speaker. +- improved audio. Features From 5e3a3984c6f77db9bcead366cbe8887271258148 Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sun, 13 Aug 2023 18:24:03 +0200 Subject: [PATCH 18/21] Updated readme.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c9926e..60976a3 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ The original Nintendo Entertainment System has a resolution of 256x240 pixels. T ## Credits InfoNes is programmed by [Jay Kumogata](https://github.com/jay-kumogata/InfoNES) and ported for DVI output to the Raspberry PI Pico by [Shuichi Takano](https://github.com/shuichitakano/pico-infones). I used the port of Shuichi Takano as a starting point for this project. -Sound programmming by @newschooldev and @Layer812 +Sound programmming by [newschooldev](https://github.com/newschooldev) and [Layer812](https://github.com/Layer812) ## Things to do From 8fb85b9c5c5fae174fc3a9b5bddb24b98e477c8e Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sun, 13 Aug 2023 18:27:27 +0200 Subject: [PATCH 19/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 395695f..35efc5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ See [Readme](https://github.com/fhoedemakers/PicoSystem_InfoNes/blob/master/READ Fixes: -- improved audio. +- improved audio. [@newschooldev}(https://github.com/newschooldev) and [@Layer812](https://github.com/Layer812) Features From 12ac02a4fb1a3ce39dc882fb2fad93bfb8980a0c Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sun, 13 Aug 2023 18:27:49 +0200 Subject: [PATCH 20/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35efc5a..5b2af35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ See [Readme](https://github.com/fhoedemakers/PicoSystem_InfoNes/blob/master/READ Fixes: -- improved audio. [@newschooldev}(https://github.com/newschooldev) and [@Layer812](https://github.com/Layer812) +- improved audio. [@newschooldev](https://github.com/newschooldev) and [@Layer812](https://github.com/Layer812) Features From 00876e4ab83cd321313205c4623afea84c16a56c Mon Sep 17 00:00:00 2001 From: Frank Hoedemakers Date: Sun, 13 Aug 2023 18:31:41 +0200 Subject: [PATCH 21/21] Comment removals --- main.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main.cpp b/main.cpp index 4672b43..bc97359 100644 --- a/main.cpp +++ b/main.cpp @@ -822,9 +822,7 @@ int main() saveSettingsAndReboot = false; strcpy(errorMessage, ""); _init_hardware(); - // _start_audio(); - // set_fw_vol(50); - // set_fw_vol(0); // for mute + final_wave[0][0] = final_wave[1][0] = -1; //click fix fw_wr = fw_rd = 0; multicore_launch_core1(fw_callback); @@ -834,7 +832,7 @@ int main() memset(scanlinebuffer1, 0, sizeof(scanlinebuffer1)); stdio_init_all(); - // printf("Start program, flash size = %d\n", PICO_FLASH_SIZE_BYTES); + printf("Start program\n"); #ifdef LED_ENABLED @@ -842,7 +840,7 @@ int main() gpio_set_dir(LED_PIN, GPIO_OUT); gpio_put(LED_PIN, 1); #endif - // romSelector_.init(NES_FILE_ADDR); + // util::dumpMemory((void *)NES_FILE_ADDR, 1024);