diff --git a/.gitmodules b/.gitmodules index c11b35c9..511e9de6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "retro-go-stm32"] path = retro-go-stm32 - url = https://github.com/kbeckmann/retro-go-stm32 + url = https://github.com/Nibelheims/retro-go-stm32 [submodule "LCD-Game-Emulator"] path = LCD-Game-Emulator url = https://github.com/bzhxx/LCD-Game-Emulator.git diff --git a/Core/Inc/gw_lcd.h b/Core/Inc/gw_lcd.h index c5aabd6d..eee9ac1c 100644 --- a/Core/Inc/gw_lcd.h +++ b/Core/Inc/gw_lcd.h @@ -6,6 +6,10 @@ #define GW_LCD_WIDTH 320 #define GW_LCD_HEIGHT 240 +#define GW_LCD_ORIG_WIDTH 160 +#define GW_LCD_ORIG_HEIGHT 144 +#define GW_LCD_FIT_WIDTH 266 +#define GW_LCD_FIT_HEIGHT 240 #ifdef GW_LCD_MODE_LUT8 extern uint8_t framebuffer1[GW_LCD_WIDTH * GW_LCD_HEIGHT] __attribute__((section (".lcd1"))) __attribute__ ((aligned (16))); diff --git a/Core/Inc/porting/common.h b/Core/Inc/porting/common.h index 04e94e47..ec94d4bd 100644 --- a/Core/Inc/porting/common.h +++ b/Core/Inc/porting/common.h @@ -32,7 +32,10 @@ extern int16_t pendingSamples; extern int16_t audiobuffer_emulator[AUDIO_BUFFER_LENGTH] __attribute__((section (".audio"))); extern int16_t audiobuffer_dma[AUDIO_BUFFER_LENGTH * 2] __attribute__((section (".audio"))); -extern const uint8_t volume_tbl[ODROID_AUDIO_VOLUME_MAX + 1]; +extern const uint8_t *volume_tbl; +extern const uint8_t volume_tbl_normal[ODROID_AUDIO_VOLUME_MAX + 1]; +extern const uint8_t volume_tbl_low[ODROID_AUDIO_VOLUME_MAX + 1]; +extern const uint8_t volume_tbl_very_low[ODROID_AUDIO_VOLUME_MAX + 1]; bool common_emu_frame_loop(void); void common_emu_input_loop(odroid_gamepad_state_t *joystick, odroid_dialog_choice_t *game_options); diff --git a/Core/Src/porting/common.c b/Core/Src/porting/common.c index 1ca16bde..aed48a04 100644 --- a/Core/Src/porting/common.c +++ b/Core/Src/porting/common.c @@ -33,7 +33,7 @@ int16_t audiobuffer_dma[AUDIO_BUFFER_LENGTH * 2] __attribute__((section (".audio dma_transfer_state_t dma_state; uint32_t dma_counter; -const uint8_t volume_tbl[ODROID_AUDIO_VOLUME_MAX + 1] = { +const uint8_t volume_tbl_normal[ODROID_AUDIO_VOLUME_MAX + 1] = { (uint8_t)(UINT8_MAX * 0.00f), (uint8_t)(UINT8_MAX * 0.06f), (uint8_t)(UINT8_MAX * 0.125f), @@ -46,6 +46,34 @@ const uint8_t volume_tbl[ODROID_AUDIO_VOLUME_MAX + 1] = { (uint8_t)(UINT8_MAX * 1.00f), }; +const uint8_t volume_tbl_low[ODROID_AUDIO_VOLUME_MAX + 1] = { + (uint8_t)(UINT8_MAX * 0.00f), + (uint8_t)(UINT8_MAX * 0.015f), + (uint8_t)(UINT8_MAX * 0.031f), + (uint8_t)(UINT8_MAX * 0.140f), + (uint8_t)(UINT8_MAX * 0.25f), + (uint8_t)(UINT8_MAX * 0.35f), + (uint8_t)(UINT8_MAX * 0.42f), + (uint8_t)(UINT8_MAX * 0.60f), + (uint8_t)(UINT8_MAX * 0.80f), + (uint8_t)(UINT8_MAX * 1.00f), +}; + +const uint8_t volume_tbl_very_low[ODROID_AUDIO_VOLUME_MAX + 1] = { + (uint8_t)(UINT8_MAX * 0.00f), + (uint8_t)(UINT8_MAX * 0.004f), + (uint8_t)(UINT8_MAX * 0.008f), + (uint8_t)(UINT8_MAX * 0.015f), + (uint8_t)(UINT8_MAX * 0.031f), + (uint8_t)(UINT8_MAX * 0.140f), + (uint8_t)(UINT8_MAX * 0.25f), + (uint8_t)(UINT8_MAX * 0.35f), + (uint8_t)(UINT8_MAX * 0.42f), + (uint8_t)(UINT8_MAX * 0.60f), +}; + +const uint8_t *volume_tbl = volume_tbl_normal; + void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) { dma_counter++; @@ -501,6 +529,15 @@ static void draw_darken_rectangle(pixel_t *fb, uint16_t x1, uint16_t y1, uint16_ } } +__attribute__((optimize("unroll-loops"))) +static void draw_black_rectangle(pixel_t *fb, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2){ + for(uint16_t i=y1; i < y2; i++){ + for(uint16_t j=x1; j < x2; j++){ + fb[j + GW_LCD_WIDTH * i] = 0; + } + } +} + __attribute__((optimize("unroll-loops"))) static void draw_darken_rounded_rectangle(pixel_t *fb, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2){ // *1 is inclusive, *2 is exclusive @@ -594,6 +631,7 @@ static void draw_clear_rounded_rectangle(pixel_t *fb, uint16_t x1, uint16_t y1, clear_pixel(&fb[ i + GW_LCD_WIDTH * (y2 - j - 1)]); } +// TODO make those macros calling function which return proper dimensions #define INGAME_OVERLAY_X 265 #define INGAME_OVERLAY_Y 10 #define INGAME_OVERLAY_BARS_H 128 @@ -657,7 +695,7 @@ void common_ingame_overlay(void) { INGAME_OVERLAY_BOX_X + INGAME_OVERLAY_BOX_W, by + bh); else - draw_darken_rectangle(fb, + draw_black_rectangle(fb, INGAME_OVERLAY_BOX_X, by, INGAME_OVERLAY_BOX_X + INGAME_OVERLAY_BOX_W, @@ -685,7 +723,7 @@ void common_ingame_overlay(void) { INGAME_OVERLAY_BOX_X + INGAME_OVERLAY_BOX_W, by + bh); else - draw_darken_rectangle(fb, + draw_black_rectangle(fb, INGAME_OVERLAY_BOX_X, by, INGAME_OVERLAY_BOX_X + INGAME_OVERLAY_BOX_W, diff --git a/Core/Src/porting/gb/main_gb.c b/Core/Src/porting/gb/main_gb.c index 6b29c604..3bc5daa7 100644 --- a/Core/Src/porting/gb/main_gb.c +++ b/Core/Src/porting/gb/main_gb.c @@ -97,6 +97,7 @@ static inline void screen_blit_nn(int32_t dest_width, int32_t dest_height) printf("Blit: %d us\n", (1000000 * PROFILING_DIFF(t_blit)) / t_blit_t0.SecondFraction); #endif + common_ingame_overlay(); lcd_swap(); } @@ -160,6 +161,7 @@ static void screen_blit_bilinear(int32_t dest_width) printf("Blit: %d us\n", (1000000 * PROFILING_DIFF(t_blit)) / t_blit_t0.SecondFraction); #endif + common_ingame_overlay(); lcd_swap(); } @@ -304,6 +306,7 @@ static inline void screen_blit_jth(void) { printf("Blit: %d us\n", (1000000 * PROFILING_DIFF(t_blit)) / t_blit_t0.SecondFraction); #endif + common_ingame_overlay(); lcd_swap(); } @@ -316,7 +319,7 @@ static void blit(void) switch (scaling) { case ODROID_DISPLAY_SCALING_OFF: // Original Resolution - screen_blit_nn(160, 144); + screen_blit_nn(GW_LCD_ORIG_WIDTH, GW_LCD_ORIG_HEIGHT); break; case ODROID_DISPLAY_SCALING_FIT: // Full height, borders on the side @@ -325,11 +328,11 @@ static void blit(void) /* fall-through */ case ODROID_DISPLAY_FILTER_SHARP: // crisp nearest neighbor scaling - screen_blit_nn(266, 240); + screen_blit_nn(GW_LCD_FIT_WIDTH, GW_LCD_FIT_HEIGHT); break; case ODROID_DISPLAY_FILTER_SOFT: // soft bilinear scaling - screen_blit_bilinear(266); + screen_blit_bilinear(GW_LCD_FIT_WIDTH); break; default: printf("Unknown filtering mode %d\n", filtering); @@ -342,7 +345,7 @@ static void blit(void) switch (filtering) { case ODROID_DISPLAY_FILTER_OFF: // crisp nearest neighbor scaling - screen_blit_nn(320, 240); + screen_blit_nn(GW_LCD_WIDTH, GW_LCD_HEIGHT); break; case ODROID_DISPLAY_FILTER_SHARP: // sharp bilinear-ish scaling @@ -350,7 +353,7 @@ static void blit(void) break; case ODROID_DISPLAY_FILTER_SOFT: // soft bilinear scaling - screen_blit_bilinear(320); + screen_blit_bilinear(GW_LCD_WIDTH); break; default: printf("Unknown filtering mode %d\n", filtering); diff --git a/Core/Src/porting/odroid_overlay.c b/Core/Src/porting/odroid_overlay.c index 75edb3e6..c4948405 100644 --- a/Core/Src/porting/odroid_overlay.c +++ b/Core/Src/porting/odroid_overlay.c @@ -485,9 +485,9 @@ static bool filter_update_cb(odroid_dialog_choice_t *option, odroid_dialog_event odroid_display_set_filter_mode(mode); } - if (mode == ODROID_DISPLAY_FILTER_OFF) strcpy(option->value, "Off"); + if (mode == ODROID_DISPLAY_FILTER_OFF) strcpy(option->value, "Off "); if (mode == ODROID_DISPLAY_FILTER_SHARP) strcpy(option->value, "Sharp"); - if (mode == ODROID_DISPLAY_FILTER_SOFT) strcpy(option->value, "Soft"); + if (mode == ODROID_DISPLAY_FILTER_SOFT) strcpy(option->value, "Soft "); return event == ODROID_DIALOG_ENTER; } @@ -505,9 +505,9 @@ static bool scaling_update_cb(odroid_dialog_choice_t *option, odroid_dialog_even odroid_display_set_scaling_mode(mode); } - if (mode == ODROID_DISPLAY_SCALING_OFF) strcpy(option->value, "Off"); - if (mode == ODROID_DISPLAY_SCALING_FIT) strcpy(option->value, "Fit"); - if (mode == ODROID_DISPLAY_SCALING_FULL) strcpy(option->value, "Full"); + if (mode == ODROID_DISPLAY_SCALING_OFF) strcpy(option->value, "Off "); + if (mode == ODROID_DISPLAY_SCALING_FIT) strcpy(option->value, "Fit "); + if (mode == ODROID_DISPLAY_SCALING_FULL) strcpy(option->value, "Full "); if (mode == ODROID_DISPLAY_SCALING_CUSTOM) strcpy(option->value, "Custom"); return event == ODROID_DIALOG_ENTER; diff --git a/Core/Src/porting/odroid_settings.c b/Core/Src/porting/odroid_settings.c index 605e6646..acd269a3 100644 --- a/Core/Src/porting/odroid_settings.c +++ b/Core/Src/porting/odroid_settings.c @@ -32,6 +32,7 @@ typedef struct persistent_config { uint8_t backlight; uint8_t start_action; uint8_t volume; + uint8_t sound_profile; // actually a value in ODROID_SOUND_PROFILE uint8_t font_size; uint8_t startup_app; void *startup_file; @@ -47,11 +48,12 @@ typedef struct persistent_config { static const persistent_config_t persistent_config_default = { .magic = CONFIG_MAGIC, - .version = 4, + .version = 5, .backlight = ODROID_BACKLIGHT_LEVEL6, .start_action = ODROID_START_ACTION_RESUME, .volume = ODROID_AUDIO_VOLUME_MAX / 2, // Too high volume can cause brown out if the battery isn't connected. + .sound_profile = ODROID_SOUND_PROFILE_NORMAL, .font_size = 8, .startup_app = 0, .main_menu_timeout_s = 60 * 10, // Turn off after 10 minutes of idle time in the main menu @@ -184,6 +186,14 @@ void odroid_settings_Volume_set(int32_t value) persistent_config_ram.volume = value; } +int32_t odroid_settings_SoundProfile_get() +{ + return persistent_config_ram.sound_profile; +} +void odroid_settings_SoundProfile_set(int32_t value) +{ + persistent_config_ram.sound_profile = value; +} int32_t odroid_settings_AudioSink_get() { diff --git a/Core/Src/retro-go/rg_emulators.c b/Core/Src/retro-go/rg_emulators.c index cd85f0f4..fef52fce 100644 --- a/Core/Src/retro-go/rg_emulators.c +++ b/Core/Src/retro-go/rg_emulators.c @@ -334,11 +334,9 @@ void emulator_show_file_menu(retro_emulator_file_t *file) // char *sram_path = odroid_system_get_path(ODROID_PATH_SAVE_SRAM, emu_get_file_path(file)); // bool has_save = odroid_sdcard_get_filesize(save_path) > 0; // bool has_sram = odroid_sdcard_get_filesize(sram_path) > 0; - // bool is_fav = favorite_find(file) != NULL; bool has_save = 1; bool has_sram = 0; - bool is_fav = 0; odroid_dialog_choice_t choices[] = { #if STATE_SAVING == 1 @@ -346,7 +344,6 @@ void emulator_show_file_menu(retro_emulator_file_t *file) #endif {1, "New game ", "", 1, NULL}, {0, "------------", "", -1, NULL}, - {3, is_fav ? "Del favorite" : "Add favorite", "", 1, NULL}, #if STATE_SAVING == 1 {2, "Delete save ", "", has_save || has_sram, NULL}, #endif @@ -363,12 +360,6 @@ void emulator_show_file_menu(retro_emulator_file_t *file) store_erase(file->save_address, file->save_size); } } - else if (sel == 3) { - // if (is_fav) - // favorite_remove(file); - // else - // favorite_add(file); - } // free(save_path); // free(sram_path); diff --git a/Core/Src/retro-go/rg_main.c b/Core/Src/retro-go/rg_main.c index b44e701f..a4b5b15a 100644 --- a/Core/Src/retro-go/rg_main.c +++ b/Core/Src/retro-go/rg_main.c @@ -6,6 +6,7 @@ #include #include +#include "common.h" #include "appid.h" #include "rg_emulators.h" #include "rg_favorites.h" @@ -126,7 +127,7 @@ static bool main_menu_timeout_cb(odroid_dialog_choice_t *option, odroid_dialog_e else if (timeout == 0xffff) { return false; } - + if (timeout > (0xffff - step)) { step = 0xffff - timeout; } @@ -138,6 +139,52 @@ static bool main_menu_timeout_cb(odroid_dialog_choice_t *option, odroid_dialog_e return event == ODROID_DIALOG_ENTER; } +static bool main_menu_sound_profile_cb(odroid_dialog_choice_t *option, odroid_dialog_event_t event, uint32_t repeat) +{ + int32_t sp = odroid_settings_SoundProfile_get(); + + if (event == ODROID_DIALOG_PREV) { + if (sp == 0) { + // do not cycle, limited amount of choices + // also avoid problems if the key is hold pressed + // Lower than 10 seconds doesn't make sense. set to 0 = disabled + odroid_settings_SoundProfile_set(0); + return false; // no change + } + + odroid_settings_SoundProfile_set(sp - 1); + gui_redraw(); + } + if (event == ODROID_DIALOG_NEXT) { + if (sp == ODROID_SOUND_PROFILE_NORMAL) { + odroid_settings_SoundProfile_set(ODROID_SOUND_PROFILE_NORMAL); + return false; // no change + } + + odroid_settings_SoundProfile_set(sp + 1); + gui_redraw(); + } + switch (sp) { + case ODROID_SOUND_PROFILE_VERY_LOW: + volume_tbl = volume_tbl_very_low; + sprintf(option->value, "very low "); + break; + case ODROID_SOUND_PROFILE_LOW: + volume_tbl = volume_tbl_low; + sprintf(option->value, "low "); + break; + case ODROID_SOUND_PROFILE_NORMAL: + volume_tbl = volume_tbl_normal; + sprintf(option->value, "normal "); + break; + default: + volume_tbl = volume_tbl_normal; + sprintf(option->value, "*INVALID*"); + break; + } + return event == ODROID_DIALOG_ENTER; +} + static inline bool tab_enabled(tab_t *tab) { int disabled_tabs = 0; @@ -234,8 +281,8 @@ void retro_loop() {0, "By", "ducalex", 1, NULL}, {0, "", "kbeckmann", 1, NULL}, {0, "", "stacksmashing", 1, NULL}, + {0, "", "niflheims", 1, NULL}, {0, "", "", -1, NULL}, - {2, "Debug menu", "", 1, NULL}, {1, "Reset settings", "", 1, NULL}, {0, "Close", "", 1, NULL}, ODROID_DIALOG_CHOICE_LAST @@ -248,81 +295,17 @@ void retro_loop() odroid_settings_reset(); odroid_system_switch_app(0); // reset } - } else if (sel == 2) { - // Debug menu - uint8_t jedec_id[3]; - char jedec_id_str[16]; - uint8_t status; - char status_str[8]; - uint8_t config; - char config_str[8]; - char erase_size_str[32]; - char dbgmcu_id_str[16]; - char dbgmcu_cr_str[16]; - - // Read jedec id and status register from the external flash - OSPI_DisableMemoryMappedMode(); - OSPI_ReadJedecId(&jedec_id[0]); - OSPI_ReadSR(&status); - OSPI_ReadCR(&config); - OSPI_EnableMemoryMappedMode(); - - snprintf(jedec_id_str, sizeof(jedec_id_str), "%02X %02X %02X", jedec_id[0], jedec_id[1], jedec_id[2]); - snprintf(status_str, sizeof(status_str), "0x%02X", status); - snprintf(config_str, sizeof(config_str), "0x%02X", config); - snprintf(erase_size_str, sizeof(erase_size_str), "%ld kB", OSPI_GetSmallestEraseSize() / 1024); - snprintf(dbgmcu_id_str, sizeof(dbgmcu_id_str), "0x%08lX", DBGMCU->IDCODE); - snprintf(dbgmcu_cr_str, sizeof(dbgmcu_cr_str), "0x%08lX", DBGMCU->CR); - - odroid_dialog_choice_t debuginfo[] = { - {0, "Flash JEDEC ID", (char *) jedec_id_str, 1, NULL}, - {0, "Flash Name", (char*) OSPI_GetFlashName(), 1, NULL}, - {0, "Flash SR", (char *) status_str, 1, NULL}, - {0, "Flash CR", (char *) config_str, 1, NULL}, - {0, "Smallest erase", erase_size_str, 1, NULL}, - {0, "------------------", "", 1, NULL}, - {0, "DBGMCU IDCODE", dbgmcu_id_str, 1, NULL}, - {1, "Enable DBGMCU CK", dbgmcu_cr_str, 1, NULL}, - {2, "Disable DBGMCU CK", "", 1, NULL}, - {0, "Close", "", 1, NULL}, - ODROID_DIALOG_CHOICE_LAST - }; - - int sel = odroid_overlay_dialog("Debug", debuginfo, -1); - switch (sel) { - case 1: - // Enable debug clocks explicitly - SET_BIT(DBGMCU->CR, - DBGMCU_CR_DBG_SLEEPCD | - DBGMCU_CR_DBG_STOPCD | - DBGMCU_CR_DBG_STANDBYCD | - DBGMCU_CR_DBG_TRACECKEN | - DBGMCU_CR_DBG_CKCDEN | - DBGMCU_CR_DBG_CKSRDEN - ); - case 2: - // Disable debug clocks explicitly - CLEAR_BIT(DBGMCU->CR, - DBGMCU_CR_DBG_SLEEPCD | - DBGMCU_CR_DBG_STOPCD | - DBGMCU_CR_DBG_STANDBYCD | - DBGMCU_CR_DBG_TRACECKEN | - DBGMCU_CR_DBG_CKCDEN | - DBGMCU_CR_DBG_CKSRDEN - ); - break; - default: - break; - } } gui_redraw(); } else if (last_key == ODROID_INPUT_VOLUME) { char timeout_value[32]; + char sp_value[32]; odroid_dialog_choice_t choices[] = { {0, "---", "", -1, NULL}, {0, "Idle power off", timeout_value, 1, &main_menu_timeout_cb}, + {0, "Sound profile", sp_value, 1, &main_menu_sound_profile_cb}, // {0, "Color theme", "1/10", 1, &color_shift_cb}, // {0, "Font size", "Small", 1, &font_size_cb}, // {0, "Show cover", "Yes", 1, &show_cover_cb}, diff --git a/retro-go-stm32 b/retro-go-stm32 index c3d9d49a..7e18bfc3 160000 --- a/retro-go-stm32 +++ b/retro-go-stm32 @@ -1 +1 @@ -Subproject commit c3d9d49a0acd1e7f0101e4fa1a3552239ab6964f +Subproject commit 7e18bfc35fba9a5c128857cbaa8c4251282bff58