From 57c4d9d7709c1e183b08e07912ce298df54d7415 Mon Sep 17 00:00:00 2001 From: kikugrave Date: Sun, 15 Feb 2026 10:47:41 -0800 Subject: [PATCH 01/51] Add PSP port with shared fast software renderer --- .gitignore | 5 + Makefile | 42 +- README.md | 1 + asm/macros/portable.inc | 3 + include/config.h | 14 +- include/gba/defines.h | 6 + .../shared/rendering/sw_renderer_common.h | 56 + libagbsyscall/Makefile | 4 + src/background.c | 4 +- src/core.c | 4 +- src/lib/m4a/m4a.c | 9 +- src/platform/pret_sdl/sdl2.c | 554 ++++---- src/platform/psp/psp_module.c | 41 + src/platform/shared/audio/m4a_sound_mixer.c | 20 +- src/platform/shared/dma.c | 22 +- .../shared/rendering/sw_renderer_fast.c | 1167 +++++++++++++++++ 16 files changed, 1708 insertions(+), 244 deletions(-) create mode 100644 include/platform/shared/rendering/sw_renderer_common.h create mode 100644 src/platform/psp/psp_module.c create mode 100644 src/platform/shared/rendering/sw_renderer_fast.c diff --git a/.gitignore b/.gitignore index 60cc4e932c..8d9dfac692 100644 --- a/.gitignore +++ b/.gitignore @@ -86,5 +86,10 @@ libagbsyscall/*.s *.dll *.sdl +# PSP build outputs +EBOOT.PBP +PARAM.SFO +sa2_debug.log + # third party deps /ext diff --git a/Makefile b/Makefile index b972750e00..16f0014742 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,12 @@ else ifeq ($(CPU_ARCH),i386) TOOLCHAIN := /usr/x86_64-w64-mingw32/ PREFIX := x86_64-w64-mingw32- endif +# PSP +else ifeq ($(PLATFORM),psp) + PSPDEV ?= $(HOME)/pspdev + PSPSDK := $(PSPDEV)/psp/sdk + export PATH := $(PSPDEV)/bin:$(PATH) + PREFIX := psp- else # Native ifneq ($(PLATFORM),sdl) @@ -120,6 +126,10 @@ else ifeq ($(PLATFORM),sdl) ROM := $(BUILD_NAME).sdl ELF := $(ROM).elf MAP := $(ROM).map +else ifeq ($(PLATFORM),psp) +ROM := EBOOT.PBP +ELF := $(BUILD_NAME).psp.elf +MAP := $(BUILD_NAME).psp.map else ROM := $(BUILD_NAME).$(PLATFORM).exe ELF := $(ROM:.exe=.elf) @@ -156,11 +166,13 @@ TILESETS_SUBDIR = graphics/tilesets/ ifeq ($(PLATFORM),gba) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") +else ifeq ($(PLATFORM),psp) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") else ifeq ($(PLATFORM),sdl_win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") else ifeq ($(PLATFORM),win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/psp/*") else C_SRCS := $(shell find $(C_SUBDIR) -name "*.c") endif @@ -225,6 +237,9 @@ else ifeq ($(PLATFORM),sdl) CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags) + else ifeq ($(PLATFORM),psp) + CC1FLAGS += -G0 + CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600 else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) else ifeq ($(PLATFORM),win32) @@ -249,6 +264,8 @@ else # for modern we are using a modern compiler # so instead of CPP we can use gcc -E to "preprocess only" CPP := $(CC1) -E + else ifeq ($(PLATFORM), psp) + CPP := $(CC1) -E endif # Allow file input through stdin on modern GCC and set it to "compile only" CC1FLAGS += -x c -S @@ -258,7 +275,12 @@ ifeq ($(DEBUG),1) CC1FLAGS += -g3 -O0 CPPFLAGS += -D DEBUG=1 else - CC1FLAGS += -O2 + ifeq ($(PLATFORM),psp) + # -O3 for PSP (Allegrex MIPS, small D-cache) + CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer + else + CC1FLAGS += -O2 + endif CPPFLAGS += -D DEBUG=0 endif @@ -297,6 +319,9 @@ else ifeq ($(PLATFORM),sdl) else MAP_FLAG := -Xlinker -Map= endif +# PSP +else ifeq ($(PLATFORM),psp) + MAP_FLAG := -Xlinker -Map= # Win32 else MAP_FLAG := -Xlinker -Map= @@ -307,6 +332,8 @@ ifeq ($(PLATFORM),gba) LIBS := $(ROOT_DIR)/tools/agbcc/lib/libgcc.a $(ROOT_DIR)/tools/agbcc/lib/libc.a $(LIBABGSYSCALL_LIBS) else ifeq ($(PLATFORM),sdl) LIBS := $(shell sdl2-config --cflags --libs) +else ifeq ($(PLATFORM),psp) + LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),sdl_win32) LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS) else ifeq ($(PLATFORM), win32) @@ -398,6 +425,7 @@ tidy: $(RM) -r build/* $(RM) SDL2.dll $(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba + $(RM) EBOOT.PBP PARAM.SFO usa_beta: ; @$(MAKE) GAME_REGION=USA GAME_VARIANT=BETA @@ -409,6 +437,8 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE sdl: ; @$(MAKE) PLATFORM=sdl +psp: ; @$(MAKE) PLATFORM=psp + tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 sdl_win32: @@ -476,6 +506,12 @@ ifeq ($(PLATFORM),gba) $(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent else ifeq ($(PLATFORM),sdl) cp $< $@ +else ifeq ($(PLATFORM),psp) + psp-fixup-imports $< + mksfoex 'Sonic Advance 2' PARAM.SFO + psp-strip $< -o $(BUILD_NAME).psp_strip.elf + pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL + -rm -f $(BUILD_NAME).psp_strip.elf else $(OBJCOPY) -O pei-x86-64 $< $@ endif diff --git a/README.md b/README.md index 382027ade6..1dd07df9fa 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ It can also build: * **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port) * **sa2.sdl_win32.exe** `make sdl_win32` (Windows SDL 64bit port) * :construction: **sa2.win32.exe** `make win32` (Win32 native port, not functional) +* **EBOOT.PBP** `make psp` (PlayStation Portable homebrew port, requires [PSPDEV](https://github.com/pspdev/pspdev)) ## Current state diff --git a/asm/macros/portable.inc b/asm/macros/portable.inc index b389fb26a0..e3f80ed9d6 100644 --- a/asm/macros/portable.inc +++ b/asm/macros/portable.inc @@ -10,6 +10,9 @@ .macro mPtr value #if defined(__aarch64__) || defined(__x86_64__) .quad \value +#elif defined(__mips__) + .balign 4 + .int \value #else .int \value #endif diff --git a/include/config.h b/include/config.h index 15b9df4ec4..845e611046 100644 --- a/include/config.h +++ b/include/config.h @@ -39,14 +39,20 @@ #define TAS_TESTING_WIDESCREEN_HACK 1 -#define RENDERER_SOFTWARE 0 -#define RENDERER_OPENGL 1 -#define RENDERER_COUNT 2 -#if PLATFORM_WIN32 && !PLATFORM_SDL +#define RENDERER_SOFTWARE 0 +#define RENDERER_OPENGL 1 +#define RENDERER_SOFTWARE_FAST 2 +#define RENDERER_COUNT 3 + +#ifndef RENDERER +#if defined(__PSP__) || defined(__PS2__) +#define RENDERER RENDERER_SOFTWARE_FAST +#elif PLATFORM_WIN32 && !PLATFORM_SDL // TODO: Only win32 for now #define RENDERER RENDERER_OPENGL #else #define RENDERER RENDERER_SOFTWARE #endif +#endif #endif // GUARD_SA2_CONFIG_H diff --git a/include/gba/defines.h b/include/gba/defines.h index b904ee74d0..1902845103 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -39,8 +39,14 @@ #define OAM_ENTRY_COUNT 128 #if PORTABLE // NOTE: Used in gba/types.h, so they have to be defined before the #include +#ifdef __PSP__ +// PSP: Use GBA-native resolution, SDL scales to 480x272 +#define DISPLAY_WIDTH 240 +#define DISPLAY_HEIGHT 160 +#else #define DISPLAY_WIDTH 426 #define DISPLAY_HEIGHT 240 +#endif // NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing. // This hack should best be removed once there's a "native" platform layer. diff --git a/include/platform/shared/rendering/sw_renderer_common.h b/include/platform/shared/rendering/sw_renderer_common.h new file mode 100644 index 0000000000..1e1a626d91 --- /dev/null +++ b/include/platform/shared/rendering/sw_renderer_common.h @@ -0,0 +1,56 @@ +#ifndef GUARD_SW_RENDERER_COMMON_H +#define GUARD_SW_RENDERER_COMMON_H + +// shared color math for the gba ppu blend unit +// used by both the normal (multi-pass) and fast (single-pass) software renderers + +#include + +// bgr555 channel extraction +#define getAlphaBit(x) (((x) >> 15) & 1) +#define getRedChannel(x) (((x) >> 0) & 0x1F) +#define getGreenChannel(x) (((x) >> 5) & 0x1F) +#define getBlueChannel(x) (((x) >> 10) & 0x1F) +#define COLOR_OPAQUE 0x8000 + +static inline uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB, + unsigned int eva, unsigned int evb) +{ + unsigned int r = ((getRedChannel(targetA) * eva) + (getRedChannel(targetB) * evb)) >> 4; + unsigned int g = ((getGreenChannel(targetA) * eva) + (getGreenChannel(targetB) * evb)) >> 4; + unsigned int b = ((getBlueChannel(targetA) * eva) + (getBlueChannel(targetB) * evb)) >> 4; + + if (r > 31) r = 31; + if (g > 31) g = 31; + if (b > 31) b = 31; + + return r | (g << 5) | (b << 10) | COLOR_OPAQUE; +} + +static inline uint16_t alphaBrightnessIncrease(uint16_t targetA, unsigned int evy) +{ + unsigned int r = getRedChannel(targetA) + (31 - getRedChannel(targetA)) * evy / 16; + unsigned int g = getGreenChannel(targetA) + (31 - getGreenChannel(targetA)) * evy / 16; + unsigned int b = getBlueChannel(targetA) + (31 - getBlueChannel(targetA)) * evy / 16; + + if (r > 31) r = 31; + if (g > 31) g = 31; + if (b > 31) b = 31; + + return r | (g << 5) | (b << 10) | COLOR_OPAQUE; +} + +static inline uint16_t alphaBrightnessDecrease(uint16_t targetA, unsigned int evy) +{ + unsigned int r = getRedChannel(targetA) - getRedChannel(targetA) * evy / 16; + unsigned int g = getGreenChannel(targetA) - getGreenChannel(targetA) * evy / 16; + unsigned int b = getBlueChannel(targetA) - getBlueChannel(targetA) * evy / 16; + + if (r > 31) r = 31; + if (g > 31) g = 31; + if (b > 31) b = 31; + + return r | (g << 5) | (b << 10) | COLOR_OPAQUE; +} + +#endif // GUARD_SW_RENDERER_COMMON_H diff --git a/libagbsyscall/Makefile b/libagbsyscall/Makefile index 654a44e4bf..7f6c55693a 100644 --- a/libagbsyscall/Makefile +++ b/libagbsyscall/Makefile @@ -34,6 +34,10 @@ else ifeq ($(CPU_ARCH),i386) TOOLCHAIN := /usr/x86_64-w64-mingw32/ PREFIX := x86_64-w64-mingw32- endif +else ifeq ($(PLATFORM),psp) + PSPDEV ?= $(HOME)/pspdev + export PATH := $(PSPDEV)/bin:$(PATH) + PREFIX := psp- else ifneq ($(PLATFORM),sdl) $(error Unknown CPU architecture $(CPU_ARCH)) endif # (PLATFORM == gba) diff --git a/src/background.c b/src/background.c index 7fba666262..190160224b 100644 --- a/src/background.c +++ b/src/background.c @@ -650,7 +650,7 @@ END_NONMATCH void UpdateBgAnimationTiles(Background *bg) { -#if (RENDERER == RENDERER_SOFTWARE) +#if (RENDERER != RENDERER_OPENGL) Tilemap *tilemap = gTilemapsRef[bg->tilemapId]; if (tilemap->animFrameCount > 0) { if (tilemap->animDelay <= ++bg->animDelayCounter) { @@ -872,7 +872,7 @@ NONMATCH("asm/non_matching/engine/sub_80039E4.inc", bool32 sub_80039E4(void)) return TRUE; #endif -#if (RENDERER == RENDERER_SOFTWARE) +#if (RENDERER != RENDERER_OPENGL) if (gBgSpritesCount != 0) { OamDataShort oam; s32 r5; diff --git a/src/core.c b/src/core.c index ea52547b73..a5ffe374df 100644 --- a/src/core.c +++ b/src/core.c @@ -924,7 +924,7 @@ bool32 ProcessVramGraphicsCopyQueue(void) if ((graphics->src != 0) && (graphics->dest != 0)) #endif { -#if (RENDERER == RENDERER_SOFTWARE) +#if (RENDERER != RENDERER_OPENGL) DmaCopy16(3, (void *)(graphics->src + offset), (void *)(graphics->dest + offset), COPY_CHUNK_SIZE); #endif graphics->size -= COPY_CHUNK_SIZE; @@ -939,7 +939,7 @@ bool32 ProcessVramGraphicsCopyQueue(void) if ((graphics->src != 0) && (graphics->dest != 0)) #endif { -#if (RENDERER == RENDERER_SOFTWARE) +#if (RENDERER != RENDERER_OPENGL) DmaCopy16(3, (void *)(graphics->src + offset), (void *)(graphics->dest + offset), graphics->size); #endif } diff --git a/src/lib/m4a/m4a.c b/src/lib/m4a/m4a.c index db161254bf..a7119e5a36 100644 --- a/src/lib/m4a/m4a.c +++ b/src/lib/m4a/m4a.c @@ -1377,8 +1377,15 @@ cond_true : { return; } -cond_false: +cond_false: { +#ifdef __mips__ + // Align to 4 bytes (mPtr adds .balign 4 on MIPS) + u8 *ptrStart = (u8 *)(((uintptr_t)track->cmdPtr + 3) & ~(uintptr_t)3); + track->cmdPtr = ptrStart + 4; +#else track->cmdPtr += 4; +#endif +} } void MP2K_event_xcmd(struct MP2KPlayerState *mplayInfo, struct MP2KTrack *track) diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index f4ceaf79ad..f93af8ed5a 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -10,6 +10,11 @@ #include #endif +#ifdef __PSP__ +#include +extern int setupPspCallbacks(void); +#endif + #include #include "global.h" @@ -21,6 +26,7 @@ #include "lib/agb_flash/flash_internal.h" #include "platform/shared/dma.h" #include "platform/shared/input.h" +#include "platform/shared/rendering/sw_renderer_common.h" #if ENABLE_AUDIO #include "platform/shared/audio/cgb_audio.h" @@ -92,6 +98,13 @@ bool paused = false; bool stepOneFrame = false; bool headless = false; +#ifdef __PSP__ +static SDL_Joystick *pspJoystick = NULL; +#define PSP_SCREEN_W 480 +#define PSP_SCREEN_H 272 +static SDL_Rect pspDestRect; +#endif + double lastGameTime = 0; double curGameTime = 0; double fixedTimestep = 1.0 / 60.0; // 16.666667ms @@ -122,6 +135,10 @@ void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } int main(int argc, char **argv) { +#ifdef __PSP__ + setupPspCallbacks(); +#endif + const char *headlessEnv = getenv("HEADLESS"); if (headlessEnv && strcmp(headlessEnv, "true") == 0) { @@ -162,14 +179,24 @@ int main(int argc, char **argv) return 1; } +#ifdef __PSP__ + if (SDL_NumJoysticks() > 0) { + pspJoystick = SDL_JoystickOpen(0); + } +#endif + #ifdef TITLE_BAR const char *title = STR(TITLE_BAR); #else const char *title = "SAT-R sa2"; #endif +#ifdef __PSP__ + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 272, SDL_WINDOW_SHOWN); +#else sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); +#endif if (sdlWindow == NULL) { fprintf(stderr, "Window could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -191,7 +218,15 @@ int main(int argc, char **argv) } #endif +#ifdef __PSP__ + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (sdlRenderer == NULL) + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); + if (sdlRenderer == NULL) + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); +#else sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); +#endif if (sdlRenderer == NULL) { fprintf(stderr, "Renderer could not be created! SDL_Error: %s\n", SDL_GetError()); return 1; @@ -208,7 +243,12 @@ int main(int argc, char **argv) SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); SDL_RenderClear(sdlRenderer); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); +#ifdef __PSP__ + // SDL_RenderSetLogicalSize is broken on PSP, stretch to fill manually + pspDestRect = (SDL_Rect){ 0, 0, PSP_SCREEN_W, PSP_SCREEN_H }; +#else SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); +#endif #if ENABLE_VRAM_VIEW SDL_SetRenderDrawColor(vramRenderer, 0, 0, 0, 255); SDL_RenderClear(vramRenderer); @@ -239,9 +279,9 @@ int main(int argc, char **argv) want.samples = (want.freq / 60); cgb_audio_init(want.freq); - if (SDL_OpenAudio(&want, 0) < 0) + if (SDL_OpenAudio(&want, 0) < 0) { SDL_Log("Failed to open audio: %s", SDL_GetError()); - else { + } else { if (want.format != AUDIO_F32) /* we let this one thing change. */ SDL_Log("We didn't get Float32 audio format."); SDL_PauseAudio(0); @@ -259,12 +299,10 @@ int main(int argc, char **argv) bool newFrameRequested = FALSE; -// Every GBA frame we process the SDL events and render the number of times -// SDL requires us to for vsync. When we need another frame we break out of -// the loop via a return +// called every gba frame. we process sdl events and render as many times +// as vsync needs, then return when a new game frame is needed. void VBlankIntrWait(void) { - // ((struct MultiSioPacket *)gMultiSioArea.nextSendBufp) #define HANDLE_VBLANK_INTRS() \ ({ \ REG_DISPSTAT |= INTR_FLAG_VBLANK; \ @@ -281,6 +319,11 @@ void VBlankIntrWait(void) } bool frameAvailable = TRUE; + bool frameDrawn = false; +#ifdef __PSP__ + static int psp_frames_skipped = 0; +#define PSP_MAX_FRAME_SKIP 2 +#endif while (isRunning) { ProcessSDLEvents(); @@ -288,9 +331,8 @@ void VBlankIntrWait(void) if (!paused || stepOneFrame) { double dt = fixedTimestep / timeScale; // TODO: Fix speedup - // Hack to emulate the behaviour of threaded sdl - // it will not add any new values to the accumulator - // when a new frame was requested within a frame cycle + // don't accumulate time if we already requested a new frame + // this frame cycle (emulates threaded sdl behavior) if (!newFrameRequested) { double deltaTime = 0; @@ -312,8 +354,21 @@ void VBlankIntrWait(void) while (accumulator >= dt) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); if (frameAvailable) { +#ifdef __PSP__ + // frame skip: let game logic catch up when behind + if (accumulator >= dt * 2.0 && psp_frames_skipped < PSP_MAX_FRAME_SKIP) { + psp_frames_skipped++; + frameAvailable = FALSE; + HANDLE_VBLANK_INTRS(); + accumulator -= dt; + newFrameRequested = TRUE; + return; + } + psp_frames_skipped = 0; +#endif VDraw(sdlTexture); frameAvailable = FALSE; + frameDrawn = true; HANDLE_VBLANK_INTRS(); @@ -329,6 +384,17 @@ void VBlankIntrWait(void) } } + // present +#ifdef __PSP__ + // manual blit since SDL_RenderSetLogicalSize doesn't work on psp + if (frameDrawn) { + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &pspDestRect); + SDL_RenderPresent(sdlRenderer); + frameDrawn = false; + } else { + SDL_Delay(1); + } +#else SDL_RenderClear(sdlRenderer); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); @@ -345,6 +411,7 @@ void VBlankIntrWait(void) SDL_RenderPresent(sdlRenderer); #if ENABLE_VRAM_VIEW SDL_RenderPresent(vramRenderer); +#endif #endif } @@ -352,8 +419,11 @@ void VBlankIntrWait(void) SDL_DestroyWindow(sdlWindow); SDL_Quit(); +#ifdef __PSP__ + sceKernelExitGame(); +#endif exit(0); -#undef RUN_VBLANK_INTRS +#undef HANDLE_VBLANK_INTRS } static void ReadSaveFile(char *path) @@ -421,6 +491,55 @@ static void CloseSaveFile() static u16 keys; +#ifdef __PSP__ +#define PSP_BTN_TRIANGLE 0 +#define PSP_BTN_CIRCLE 1 +#define PSP_BTN_CROSS 2 +#define PSP_BTN_SQUARE 3 +#define PSP_BTN_LTRIGGER 4 +#define PSP_BTN_RTRIGGER 5 +#define PSP_BTN_DOWN 6 +#define PSP_BTN_LEFT 7 +#define PSP_BTN_UP 8 +#define PSP_BTN_RIGHT 9 +#define PSP_BTN_SELECT 10 +#define PSP_BTN_START 11 + +static u16 PollPSPButtons(void) +{ + u16 pspKeys = 0; + if (pspJoystick == NULL) + return pspKeys; + + SDL_JoystickUpdate(); + + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_CROSS)) + pspKeys |= A_BUTTON; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_CIRCLE)) + pspKeys |= B_BUTTON; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_SQUARE)) + pspKeys |= B_BUTTON; // Square also B + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_START)) + pspKeys |= START_BUTTON; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_SELECT)) + pspKeys |= SELECT_BUTTON; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_LTRIGGER)) + pspKeys |= L_BUTTON; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_RTRIGGER)) + pspKeys |= R_BUTTON; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_UP)) + pspKeys |= DPAD_UP; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_DOWN)) + pspKeys |= DPAD_DOWN; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_LEFT)) + pspKeys |= DPAD_LEFT; + if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_RIGHT)) + pspKeys |= DPAD_RIGHT; + + return pspKeys; +} +#endif + u32 fullScreenFlags = 0; static SDL_DisplayMode sdlDispMode = { 0 }; @@ -561,18 +680,33 @@ u16 Platform_GetKeyInput(void) return (gamepadKeys != 0) ? gamepadKeys : keys; #endif +#ifdef __PSP__ + return keys | PollPSPButtons(); +#endif + return keys; } // BIOS function implementations are based on the VBA-M source code. -static uint32_t CPUReadMemory(const void *src) { return *(uint32_t *)src; } +// safe unaligned access for MIPS +static uint32_t CPUReadMemory(const void *src) +{ + uint32_t val; + memcpy(&val, src, sizeof(val)); + return val; +} -static void CPUWriteMemory(void *dest, uint32_t val) { *(uint32_t *)dest = val; } +static void CPUWriteMemory(void *dest, uint32_t val) { memcpy(dest, &val, sizeof(val)); } -static uint16_t CPUReadHalfWord(const void *src) { return *(uint16_t *)src; } +static uint16_t CPUReadHalfWord(const void *src) +{ + uint16_t val; + memcpy(&val, src, sizeof(val)); + return val; +} -static void CPUWriteHalfWord(void *dest, uint16_t val) { *(uint16_t *)dest = val; } +static void CPUWriteHalfWord(void *dest, uint16_t val) { memcpy(dest, &val, sizeof(val)); } static uint8_t CPUReadByte(const void *src) { return *(uint8_t *)src; } @@ -968,25 +1102,26 @@ static const uint16_t bgMapSizes[][2] = { #define applySpriteHorizontalMosaicEffect(x) (x - (x % (mosaicSpriteEffectX + 1))) #define applySpriteVerticalMosaicEffect(y) (y - (y % (mosaicSpriteEffectY + 1))) -// NOTE: This is the corrected function. static void RenderBGScanline(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *line) { unsigned int charBaseBlock = (control >> 2) & 3; unsigned int screenBaseBlock = (control & BGCNT_SCREENBASE_MASK) >> 8; - unsigned int bitsPerPixel = ((control >> 7) & 1) ? 8 : 4; + unsigned int is8bpp = (control >> 7) & 1; // Determine background dimensions from the control register unsigned int mapWidth = bgMapSizes[control >> 14][0]; // in tiles - unsigned int mapHeight = bgMapSizes[control >> 14][1]; // in tiles - unsigned int mapPixelWidth = mapWidth * TILE_WIDTH; - unsigned int mapPixelHeight = mapHeight * TILE_WIDTH; + unsigned int mapPixelWidth = mapWidth << 3; + unsigned int mapPixelHeight = bgMapSizes[control >> 14][1] << 3; + unsigned int pixelWidthMask = mapPixelWidth - 1; + unsigned int pixelHeightMask = mapPixelHeight - 1; uint8_t *bgtiles = (uint8_t *)BG_CHAR_ADDR(charBaseBlock); uint16_t *bgmap = (uint16_t *)BG_SCREEN_ADDR(screenBaseBlock); uint16_t *pal = (uint16_t *)PLTT; // Apply vertical mosaic effect to the entire scanline if enabled - if (control & BGCNT_MOSAIC) { + bool hasMosaic = control & BGCNT_MOSAIC; + if (hasMosaic) { lineNum = applyBGVerticalMosaicEffect(lineNum); } @@ -994,29 +1129,22 @@ static void RenderBGScanline(int bgNum, uint16_t control, uint16_t hoffs, uint16 hoffs &= 0x1FF; voffs &= 0x1FF; + unsigned int yy = (lineNum + voffs) & pixelHeightMask; + unsigned int mapY = yy >> 3; + unsigned int tileY = yy & 7; + unsigned int mapRowBase = mapY * mapWidth; + for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - unsigned int xx, yy; + unsigned int xx; - // Calculate the source coordinate in the background map, applying scroll and mosaic - if (control & BGCNT_MOSAIC) { - xx = applyBGHorizontalMosaicEffect(x) + hoffs; + if (hasMosaic) { + xx = (applyBGHorizontalMosaicEffect(x) + hoffs) & pixelWidthMask; } else { - xx = x + hoffs; + xx = (x + hoffs) & pixelWidthMask; } - yy = lineNum + voffs; - // Wrap the coordinates based on the background's actual pixel dimensions. - // This fixes issues with backgrounds that are not 256x256. - xx &= (mapPixelWidth - 1); - yy &= (mapPixelHeight - 1); - - // Convert pixel coordinates to tile coordinates - unsigned int mapX = xx / TILE_WIDTH; - unsigned int mapY = yy / TILE_WIDTH; - - // Calculate the 1D index into the tilemap. This was the primary source of bugs, - // as the original code used a hardcoded map width of 32 tiles. - unsigned int mapIndex = mapY * mapWidth + mapX; + unsigned int mapX = xx >> 3; + unsigned int mapIndex = mapRowBase + mapX; uint16_t entry = bgmap[mapIndex]; unsigned int tileNum = entry & 0x3FF; @@ -1026,40 +1154,30 @@ static void RenderBGScanline(int bgNum, uint16_t control, uint16_t hoffs, uint16 vramPalIdBuffer[tileNum] = paletteNum; #endif - // Get the coordinate within the specific tile - unsigned int tileX = xx % TILE_WIDTH; - unsigned int tileY = yy % TILE_WIDTH; + unsigned int tx = xx & 7; + unsigned int ty = tileY; - // Handle horizontal and vertical tile flipping if (entry & (1 << 10)) - tileX = (TILE_WIDTH - 1) - tileX; // H-flip + tx = 7 - tx; if (entry & (1 << 11)) - tileY = (TILE_WIDTH - 1) - tileY; // V-flip + ty = 7 - ty; - // Calculate address of the pixel data and extract the color - if (bitsPerPixel == 4) { - uint32_t tileDataOffset = tileNum * TILE_SIZE_4BPP; - uint32_t pixelByteOffset = (tileY * TILE_WIDTH + tileX) / 2; + if (!is8bpp) { + uint32_t tileDataOffset = tileNum << 5; + uint32_t pixelByteOffset = (ty << 2) + (tx >> 1); uint8_t pixelPair = bgtiles[tileDataOffset + pixelByteOffset]; - uint8_t pixel; - if (tileX & 1) { - pixel = pixelPair >> 4; - } else { - pixel = pixelPair & 0xF; - } + uint8_t pixel = (tx & 1) ? (pixelPair >> 4) : (pixelPair & 0xF); if (pixel != 0) { - line[x] = pal[16 * paletteNum + pixel] | 0x8000; + line[x] = pal[(paletteNum << 4) + pixel] | 0x8000; } } else { // 8 bits per pixel - uint32_t tileDataOffset = tileNum * TILE_SIZE_8BPP; - uint32_t pixelByteOffset = tileY * TILE_WIDTH + tileX; + uint32_t tileDataOffset = tileNum << 6; + uint32_t pixelByteOffset = (ty << 3) + tx; uint8_t pixel = bgtiles[tileDataOffset + pixelByteOffset]; if (pixel != 0) { - // For 8bpp tiles, the palette number in the tile entry is ignored. - // The pixel value is a direct index into the 256-color palette. line[x] = pal[pixel] | 0x8000; } } @@ -1257,65 +1375,8 @@ const u8 spriteSizes[][2] = { { 32, 64 }, }; -#define getAlphaBit(x) ((x >> 15) & 1) -#define getRedChannel(x) ((x >> 0) & 0x1F) -#define getGreenChannel(x) ((x >> 5) & 0x1F) -#define getBlueChannel(x) ((x >> 10) & 0x1F) #define isbgEnabled(x) ((REG_DISPCNT >> 8) & 0xF) & (1 << x) -static uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB) -{ - unsigned int eva = REG_BLDALPHA & 0x1F; - unsigned int evb = (REG_BLDALPHA >> 8) & 0x1F; - // shift right by 4 = division by 16 - unsigned int r = ((getRedChannel(targetA) * eva) + (getRedChannel(targetB) * evb)) >> 4; - unsigned int g = ((getGreenChannel(targetA) * eva) + (getGreenChannel(targetB) * evb)) >> 4; - unsigned int b = ((getBlueChannel(targetA) * eva) + (getBlueChannel(targetB) * evb)) >> 4; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | (1 << 15); -} - -static uint16_t alphaBrightnessIncrease(uint16_t targetA) -{ - unsigned int evy = (REG_BLDY & 0x1F); - unsigned int r = getRedChannel(targetA) + (31 - getRedChannel(targetA)) * evy / 16; - unsigned int g = getGreenChannel(targetA) + (31 - getGreenChannel(targetA)) * evy / 16; - unsigned int b = getBlueChannel(targetA) + (31 - getBlueChannel(targetA)) * evy / 16; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | (1 << 15); -} - -static uint16_t alphaBrightnessDecrease(uint16_t targetA) -{ - unsigned int evy = (REG_BLDY & 0x1F); - unsigned int r = getRedChannel(targetA) - getRedChannel(targetA) * evy / 16; - unsigned int g = getGreenChannel(targetA) - getGreenChannel(targetA) * evy / 16; - unsigned int b = getBlueChannel(targetA) - getBlueChannel(targetA) * evy / 16; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | (1 << 15); -} - // outputs the blended pixel in colorOutput, the prxxx are the bg priority and // subpriority, pixelpos is pixel offset in scanline static bool alphaBlendSelectTargetB(struct scanlineData *scanline, uint16_t *colorOutput, char prnum, char prsub, int pixelpos, @@ -1396,8 +1457,6 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool bool isAffine = oam->split.affineMode & 1; bool doubleSizeOrDisabled = (oam->split.affineMode >> 1) & 1; - bool isSemiTransparent = (oam->split.objMode == 1); - bool isObjWin = (oam->split.objMode == 2); if (!(isAffine) && doubleSizeOrDisabled) // disable for non-affine { @@ -1408,31 +1467,41 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool width = gOamShapesSizes[index][0]; height = gOamShapesSizes[index][1]; - int rect_width = width; - int rect_height = height; - int half_width = width / 2; int half_height = height / 2; - pixels = scanline->spriteLayers[oam->split.priority]; - int32_t x = oam->split.x; int32_t y = oam->split.y; #if !EXTENDED_OAM - // The regular, unextended values are 9 and 8 unsigned bits for x and y respectively. - // Once they have exceeded the screen's right or bottom, they get treated as signed values on original hardware. - // This is done so that, for example, a sprite at 0 on either axis that moves left or up will not suddenly disappear. - // - // With EXTENDED_OAM we are using signed 16 bit values, so we don't want to change the raw value. if (x >= DISPLAY_WIDTH) x -= 512; if (y >= DISPLAY_HEIGHT) y -= 256; #endif + if (isAffine && doubleSizeOrDisabled) { + half_width *= 2; + half_height *= 2; + } + + int spriteTop = y; + int spriteBottom = y + (half_height * 2); + if ((int)vcount < spriteTop || (int)vcount >= spriteBottom) + continue; + + int spriteLeft = x; + int spriteRight = x + (half_width * 2); + if (spriteRight < 0 || spriteLeft >= DISPLAY_WIDTH) + continue; + + bool isSemiTransparent = (oam->split.objMode == 1); + bool isObjWin = (oam->split.objMode == 2); + + int rect_width = width; + int rect_height = height; + if (isAffine) { - // TODO: there is probably a better way to do this u8 matrixNum = oam->split.matrixNum * 4; OamData *oam1 = &((OamData *)OAM)[matrixNum]; @@ -1445,26 +1514,22 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool matrix[1][0] = oam3->all.affineParam; matrix[1][1] = oam4->all.affineParam; - if (doubleSizeOrDisabled) // double size for affine - { + if (doubleSizeOrDisabled) { rect_width *= 2; rect_height *= 2; - half_width *= 2; - half_height *= 2; } } else { - // Identity matrix[0][0] = 0x100; matrix[0][1] = 0; matrix[1][0] = 0; matrix[1][1] = 0x100; } + pixels = scanline->spriteLayers[oam->split.priority]; x += half_width; y += half_height; - // Does this sprite actually draw on this scanline? - if (vcount >= (y - half_height) && vcount < (y + half_height)) { + { int local_y = (oam->split.mosaic == 1) ? applySpriteVerticalMosaicEffect(vcount) - y : vcount - y; int number = oam->split.tileNum; int palette = oam->split.paletteNum; @@ -1472,9 +1537,10 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); bool is8BPP = oam->split.bpp & 1; + { + uint8_t *tiledata = (uint8_t *)objtiles; + uint16_t *sprpal = (uint16_t *)(PLTT + (0x200 / 2)); for (int local_x = -half_width; local_x <= half_width; local_x++) { - uint8_t *tiledata = (uint8_t *)objtiles; - uint16_t *palette = (uint16_t *)(PLTT + (0x200 / 2)); int local_mosaicX; int tex_x; int tex_y; @@ -1505,30 +1571,32 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool if (flipY) tex_y = height - tex_y - 1; - int tile_x = tex_x % 8; - int tile_y = tex_y % 8; - int block_x = tex_x / 8; - int block_y = tex_y / 8; - int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width / 8) : 16)) + block_x); + int tile_x = tex_x & 7; + int tile_y = tex_y & 7; + int block_x = tex_x >> 3; + int block_y = tex_y >> 3; + int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width >> 3) : 16)) + block_x); uint16_t pixel = 0; + uint16_t *pixpal; if (!is8BPP) { - int tileDataIndex = (block_offset + oam->split.tileNum) * 32 + (tile_y * 4) + (tile_x / 2); + int tileDataIndex = ((block_offset + oam->split.tileNum) << 5) + (tile_y << 2) + (tile_x >> 1); pixel = tiledata[tileDataIndex]; if (tile_x & 1) pixel >>= 4; else pixel &= 0xF; - palette += oam->split.paletteNum * 16; + pixpal = sprpal + (oam->split.paletteNum << 4); #if ENABLE_VRAM_VIEW - vramPalIdBuffer[0x800 + (tileDataIndex / 32)] = 16 + oam->split.paletteNum; + vramPalIdBuffer[0x800 + (tileDataIndex >> 5)] = 16 + oam->split.paletteNum; #endif } else { - pixel = tiledata[(block_offset * 2 + oam->split.tileNum) * 32 + (tile_y * 8) + tile_x]; + pixel = tiledata[((block_offset * 2 + oam->split.tileNum) << 5) + (tile_y << 3) + tile_x]; + pixpal = sprpal; } if (pixel != 0) { - uint16_t color = palette[pixel]; + uint16_t color = pixpal[pixel]; // if sprite mode is 2 then write to the window mask instead if (isObjWin) { @@ -1547,15 +1615,15 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool uint16_t targetA = color; uint16_t targetB = 0; if (alphaBlendSelectTargetB(scanline, &targetB, oam->split.priority, 0, global_x, false)) { - color = alphaBlendColor(targetA, targetB); + color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); } } else if (REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) { switch (blendMode) { case 2: - color = alphaBrightnessIncrease(color); + color = alphaBrightnessIncrease(color, REG_BLDY & 0x1F); break; case 3: - color = alphaBrightnessDecrease(color); + color = alphaBrightnessDecrease(color, REG_BLDY & 0x1F); break; } } @@ -1565,6 +1633,7 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool } } } + } } } } @@ -1574,14 +1643,19 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) unsigned int mode = REG_DISPCNT & 3; unsigned char numOfBgs = (mode == 0 ? 4 : 3); int bgnum, prnum; - struct scanlineData scanline; + static struct scanlineData scanline; unsigned int blendMode = (REG_BLDCNT >> 6) & 3; unsigned int xpos; + unsigned int enabledBgs = (REG_DISPCNT >> 8) & 0xF; - // initialize all priority bookkeeping data - memset(scanline.layers, 0, sizeof(scanline.layers)); - memset(scanline.winMask, 0, sizeof(scanline.winMask)); - memset(scanline.spriteLayers, 0, sizeof(scanline.spriteLayers)); + // Only zero the layers that are actually enabled, + // instead of blindly zeroing all 4+4 layers (~8KB total) every scanline. + for (bgnum = 0; bgnum < numOfBgs; bgnum++) { + if (enabledBgs & (1 << bgnum)) + memset(scanline.layers[bgnum], 0, sizeof(scanline.layers[bgnum])); + } + if (REG_DISPCNT & DISPCNT_OBJ_ON) + memset(scanline.spriteLayers, 0, sizeof(scanline.spriteLayers)); memset(scanline.prioritySortedBgsCount, 0, sizeof(scanline.prioritySortedBgsCount)); for (bgnum = 0; bgnum < numOfBgs; bgnum++) { @@ -1696,63 +1770,89 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) if (REG_DISPCNT & DISPCNT_OBJ_ON) DrawOamSprites(&scanline, vcount, windowsEnabled); - // iterate trough every priority in order - for (prnum = 3; prnum >= 0; prnum--) { - for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { - char bgnum = scanline.prioritySortedBgs[prnum][prsub]; - // if background is enabled then draw it - if (isbgEnabled(bgnum)) { - uint16_t *src = scanline.layers[bgnum]; - // copy all pixels to framebuffer + // iterate through every priority in order + if (blendMode == 0 && !windowsEnabled) { + for (prnum = 3; prnum >= 0; prnum--) { + for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { + char bgnum = scanline.prioritySortedBgs[prnum][prsub]; + if (isbgEnabled(bgnum)) { + uint16_t *src = scanline.layers[bgnum]; + for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + uint16_t color = src[xpos]; + if (color & 0x8000) // alpha bit set = opaque + pixels[xpos] = color; + } + } + } + // draw sprites on current priority + if (REG_DISPCNT & DISPCNT_OBJ_ON) { + uint16_t *src = scanline.spriteLayers[prnum]; for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - uint16_t color = src[xpos]; - bool winEffectEnable = true; - - if (!getAlphaBit(color)) - continue; // do nothing if alpha bit is not set + if (src[xpos] & 0x8000) + pixels[xpos] = src[xpos]; + } + } + } + } else { + // FULL PATH: blending and/or windows are active + for (prnum = 3; prnum >= 0; prnum--) { + for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { + char bgnum = scanline.prioritySortedBgs[prnum][prsub]; + // if background is enabled then draw it + if (isbgEnabled(bgnum)) { + uint16_t *src = scanline.layers[bgnum]; + // copy all pixels to framebuffer + for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + uint16_t color = src[xpos]; + bool winEffectEnable = true; + + if (!getAlphaBit(color)) + continue; // do nothing if alpha bit is not set + + if (windowsEnabled) { + winEffectEnable = ((scanline.winMask[xpos] & WINMASK_CLR) >> 5); + // if bg is disabled inside the window then do not draw the pixel + if (!(scanline.winMask[xpos] & 1 << bgnum)) + continue; + } - if (windowsEnabled) { - winEffectEnable = ((scanline.winMask[xpos] & WINMASK_CLR) >> 5); - // if bg is disabled inside the window then do not draw the pixel - if (!(scanline.winMask[xpos] & 1 << bgnum)) - continue; - } + // blending code + if (blendMode != 0 && REG_BLDCNT & (1 << bgnum) && winEffectEnable) { + uint16_t targetA = color; + uint16_t targetB = 0; - // blending code - if (blendMode != 0 && REG_BLDCNT & (1 << bgnum) && winEffectEnable) { - uint16_t targetA = color; - uint16_t targetB = 0; - - switch (blendMode) { - case 1: { - char isSpriteBlendingEnabled = REG_BLDCNT & BLDCNT_TGT2_OBJ ? 1 : 0; - // find targetB and blend it - if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, isSpriteBlendingEnabled)) { - color = alphaBlendColor(targetA, targetB); - } - } break; - case 2: - color = alphaBrightnessIncrease(targetA); - break; - case 3: - color = alphaBrightnessDecrease(targetA); - break; + switch (blendMode) { + case 1: { + char isSpriteBlendingEnabled = REG_BLDCNT & BLDCNT_TGT2_OBJ ? 1 : 0; + // find targetB and blend it + if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, + isSpriteBlendingEnabled)) { + color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); + } + } break; + case 2: + color = alphaBrightnessIncrease(targetA, REG_BLDY & 0x1F); + break; + case 3: + color = alphaBrightnessDecrease(targetA, REG_BLDY & 0x1F); + break; + } } + // write the pixel to scanline buffer output + pixels[xpos] = color; } - // write the pixel to scanline buffer output - pixels[xpos] = color; } } - } - // draw sprites on current priority - uint16_t *src = scanline.spriteLayers[prnum]; - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - if (getAlphaBit(src[xpos])) { - // check if sprite pixel draws inside window - if (windowsEnabled && !(scanline.winMask[xpos] & WINMASK_OBJ)) - continue; - // draw the pixel - pixels[xpos] = src[xpos]; + // draw sprites on current priority + uint16_t *src = scanline.spriteLayers[prnum]; + for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + if (getAlphaBit(src[xpos])) { + // check if sprite pixel draws inside window + if (windowsEnabled && !(scanline.winMask[xpos] & WINMASK_OBJ)) + continue; + // draw the pixel + pixels[xpos] = src[xpos]; + } } } } @@ -1760,21 +1860,25 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) uint16_t *memsetu16(uint16_t *dst, uint16_t fill, size_t count) { - for (int i = 0; i < count; i++) { - *dst++ = fill; + uint32_t fill32 = ((uint32_t)fill << 16) | fill; + uint32_t *dst32 = (uint32_t *)dst; + size_t pairs = count >> 1; + for (size_t i = 0; i < pairs; i++) { + dst32[i] = fill32; } - - return 0; + if (count & 1) { + dst[count - 1] = fill; + } + return dst; } static void DrawFrame(uint16_t *pixels) { int i; - int j; - static uint16_t scanlines[DISPLAY_HEIGHT][DISPLAY_WIDTH]; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; for (i = 0; i < DISPLAY_HEIGHT; i++) { + uint16_t *scanline = &pixels[i * DISPLAY_WIDTH]; + REG_VCOUNT = i; if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { REG_DISPSTAT |= INTR_FLAG_VCOUNT; @@ -1782,10 +1886,10 @@ static void DrawFrame(uint16_t *pixels) gIntrTable[INTR_INDEX_VCOUNT](); } - // Render the backdrop color before the each individual scanline. - // HBlank interrupt code could have changed it inbetween lines. - memsetu16(scanlines[i], *(uint16_t *)PLTT, DISPLAY_WIDTH); - DrawScanline(scanlines[i], i); + // Render the backdrop color before each individual scanline. + // HBlank interrupt code could have changed it in between lines. + memsetu16(scanline, *(uint16_t *)PLTT, DISPLAY_WIDTH); + DrawScanline(scanline, i); REG_DISPSTAT |= INTR_FLAG_HBLANK; @@ -1797,14 +1901,6 @@ static void DrawFrame(uint16_t *pixels) REG_DISPSTAT &= ~INTR_FLAG_HBLANK; REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; } - - // Copy to screen - for (i = 0; i < DISPLAY_HEIGHT; i++) { - uint16_t *src = scanlines[i]; - for (j = 0; j < DISPLAY_WIDTH; j++) { - pixels[i * DISPLAY_WIDTH + j] = src[j]; - } - } } #if ENABLE_VRAM_VIEW @@ -1845,8 +1941,14 @@ void VramDraw(SDL_Texture *texture) void VDraw(SDL_Texture *texture) { - memset(gameImage, 0, sizeof(gameImage)); +#if RENDERER == RENDERER_SOFTWARE_FAST + { + extern void DrawFrame_Fast(uint16_t *pixels); + DrawFrame_Fast(gameImage); + } +#else DrawFrame(gameImage); +#endif SDL_UpdateTexture(texture, NULL, gameImage, DISPLAY_WIDTH * sizeof(Uint16)); REG_VCOUNT = DISPLAY_HEIGHT + 1; // prep for being in VBlank period } diff --git a/src/platform/psp/psp_module.c b/src/platform/psp/psp_module.c new file mode 100644 index 0000000000..a070da463c --- /dev/null +++ b/src/platform/psp/psp_module.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +PSP_MODULE_INFO("SonicAdvance2", 0, 1, 0); +PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU); +PSP_HEAP_SIZE_KB(-1024); + +unsigned int sce_newlib_stack_size = 512 * 1024; + +extern bool isRunning; + +int exitCallback(int arg1, int arg2, void *common) +{ + (void)arg1; + (void)arg2; + (void)common; + isRunning = false; + return 0; +} + +int callbackThread(SceSize args, void *argp) +{ + (void)args; + (void)argp; + int cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL); + sceKernelRegisterExitCallback(cbid); + sceKernelSleepThreadCB(); + return 0; +} + +int setupPspCallbacks(void) +{ + int thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0); + if (thid >= 0) + { + sceKernelStartThread(thid, 0, 0); + } + return thid; +} diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index 49b0d65bc1..b9236e9841 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -368,10 +368,20 @@ void MP2K_event_fine(struct MP2KPlayerState *unused, struct MP2KTrack *track) track->status = 0; } +// mPtr aligns to 4 bytes on MIPS; match that here before reading pointer data +#ifdef __mips__ +static inline u8 *alignCmdPtr4(u8 *p) +{ + return (u8 *)(((uintptr_t)p + 3) & ~(uintptr_t)3); +} +#else +#define alignCmdPtr4(p) (p) +#endif + // Sets the track's cmdPtr to the specified address. void MP2K_event_goto(struct MP2KPlayerState *unused, struct MP2KTrack *track) { - u8 *cmdPtr = track->cmdPtr; + u8 *cmdPtr = alignCmdPtr4(track->cmdPtr); uintptr_t addr = 0; for (size_t i = sizeof(uintptr_t) - 1; i > 0; i--) { addr |= cmdPtr[i]; @@ -386,7 +396,9 @@ void MP2K_event_patt(struct MP2KPlayerState *unused, struct MP2KTrack *track) { u8 level = track->patternLevel; if (level < 3) { - track->patternStack[level] = track->cmdPtr + sizeof(u8 *); + // Return address is past the aligned pointer data + u8 *ptrStart = alignCmdPtr4(track->cmdPtr); + track->patternStack[level] = ptrStart + sizeof(u8 *); track->patternLevel++; MP2K_event_goto(unused, track); } else { @@ -419,7 +431,9 @@ void MP2K_event_rept(struct MP2KPlayerState *unused, struct MP2KTrack *track) MP2K_event_goto(unused, track); } else { track->repeatCount = 0; - track->cmdPtr += sizeof(u8) + sizeof(u8 *); + // Skip past the aligned pointer data + u8 *ptrStart = alignCmdPtr4(track->cmdPtr); + track->cmdPtr = ptrStart + sizeof(u8 *); } } } diff --git a/src/platform/shared/dma.c b/src/platform/shared/dma.c index 60ad6144ff..d2f55e045f 100644 --- a/src/platform/shared/dma.c +++ b/src/platform/shared/dma.c @@ -1,10 +1,26 @@ #include +#include #include "global.h" #include "platform/shared/dma.h" +// safe unaligned access for MIPS +static inline void dma_copy32(void *dst, const void *src) +{ + u32 tmp; + memcpy(&tmp, src, 4); + memcpy(dst, &tmp, 4); +} + +static inline void dma_copy16(void *dst, const void *src) +{ + u16 tmp; + memcpy(&tmp, src, 2); + memcpy(dst, &tmp, 2); +} + struct DMATransfer DMAList[DMA_COUNT] = { 0 }; -void RunDMAs(u32 type) +void RunDMAs(DmaStartTypes type) { for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { struct DMATransfer *dma = &DMAList[dmaNum]; @@ -23,9 +39,9 @@ void RunDMAs(u32 type) // printf("DMA%d src=%p, dest=%p, control=%d\n", dmaNum, dma->src, dma->dst, dma->control); for (int i = 0; i < dma->size; i++) { if ((dma->control) & DMA_32BIT) - *dma->dst32 = *dma->src32; + dma_copy32(dma->dst, dma->src); else - *dma->dst16 = *dma->src16; + dma_copy16(dma->dst, dma->src); // process destination pointer changes if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_INC) { diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c new file mode 100644 index 0000000000..72327a2de9 --- /dev/null +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -0,0 +1,1167 @@ +// sw_renderer_fast.c -- single-pass back-to-front gba ppu renderer +// +// the default renderer does multiple passes per scanline which thrashes +// the data cache on older platforms with tiny L1 and no L2 + +// this one composites everything in one pass per scanline, painting +// layers directly into the output buffer from back to front. a +// layerIds[] side-buffer tracks what wrote each pixel so alpha +// blending can find its target-b inline. +// +// 4bpp text bgs get a batched path that reads one u32 per 8 pixels. +// 8bpp and mosaic bgs fall back to per-pixel. sprites are pre-filtered +// per scanline so we only touch the ones that actually matter. + +#include "config.h" + +#if RENDERER == RENDERER_SOFTWARE_FAST + +#include +#include +#include +#include + +#include "global.h" +#include "core.h" +#include "gba/defines.h" +#include "gba/io_reg.h" +#include "gba/types.h" +#include "platform/shared/dma.h" +#include "platform/shared/rendering/sw_renderer_common.h" + +extern IntrFunc gIntrTable[16]; +extern uint8_t REG_BASE[IO_SIZE]; +extern uint16_t PLTT[PLTT_SIZE / sizeof(uint16_t)]; +extern uint8_t VRAM[VRAM_SIZE]; +extern uint8_t OAM[OAM_SIZE]; +extern const u8 gOamShapesSizes[12][2]; + +#ifndef TILE_WIDTH +#define TILE_WIDTH 8 +#endif + +#define IsBGEnabled(n) (((REG_DISPCNT >> 8) & 0xF) & (1 << (n))) + +// mosaic +#define MOSAIC_BG_X (REG_MOSAIC & 0xF) +#define MOSAIC_BG_Y ((REG_MOSAIC >> 4) & 0xF) +#define MOSAIC_SPR_X ((REG_MOSAIC >> 8) & 0xF) +#define MOSAIC_SPR_Y ((REG_MOSAIC >> 12) & 0xF) +#define ApplyMosaicBGX(x) ((x) - ((x) % (MOSAIC_BG_X + 1))) +#define ApplyMosaicBGY(y) ((y) - ((y) % (MOSAIC_BG_Y + 1))) +#define ApplyMosaicSprX(x) ((x) - ((x) % (MOSAIC_SPR_X + 1))) +#define ApplyMosaicSprY(y) ((y) - ((y) % (MOSAIC_SPR_Y + 1))) + +// tilemap entry fields +#define TILE_NUM(e) ((e) & 0x3FF) +#define TILE_PALETTE(e) (((e) >> 12) & 0xF) +#define TILE_HFLIP(e) ((e) & (1 << 10)) +#define TILE_VFLIP(e) ((e) & (1 << 11)) + +// window mask bits +#define WINMASK_BG0 (1 << 0) +#define WINMASK_BG1 (1 << 1) +#define WINMASK_BG2 (1 << 2) +#define WINMASK_BG3 (1 << 3) +#define WINMASK_OBJ (1 << 4) +#define WINMASK_CLR (1 << 5) +#define WINMASK_WINOUT (1 << 6) + +// layer ids for blend target tracking +#define LAYER_BG0 0 +#define LAYER_BG1 1 +#define LAYER_BG2 2 +#define LAYER_BG3 3 +#define LAYER_OBJ 4 +#define LAYER_BACKDROP 5 + +static const uint16_t bgMapSizes[][2] = { + { 32, 32 }, { 64, 32 }, { 32, 64 }, { 64, 64 }, +}; + + +// 16-bit fill using 32-bit writes +static inline void Memset16(uint16_t *dst, uint16_t fill, unsigned int count) +{ + uint32_t fill32 = ((uint32_t)fill << 16) | fill; + uint32_t *dst32 = (uint32_t *)dst; + unsigned int pairs = count >> 1; + for (unsigned int i = 0; i < pairs; i++) + dst32[i] = fill32; + if (count & 1) + dst[count - 1] = fill; +} + +static inline uint32_t GetBgRefX(int bg) { return (bg == 2) ? REG_BG2X : (bg == 3) ? REG_BG3X : 0; } +static inline uint32_t GetBgRefY(int bg) { return (bg == 2) ? REG_BG2Y : (bg == 3) ? REG_BG3Y : 0; } +static inline uint16_t GetBgPA(int bg) { return (bg == 2) ? REG_BG2PA : (bg == 3) ? REG_BG3PA : 0; } +static inline uint16_t GetBgPB(int bg) { return (bg == 2) ? REG_BG2PB : (bg == 3) ? REG_BG3PB : 0; } +static inline uint16_t GetBgPC(int bg) { return (bg == 2) ? REG_BG2PC : (bg == 3) ? REG_BG3PC : 0; } +static inline uint16_t GetBgPD(int bg) { return (bg == 2) ? REG_BG2PD : (bg == 3) ? REG_BG3PD : 0; } + +// handles the wraparound case where left > right +static inline bool WindowContainsX(u16 left, u16 right, u16 x) +{ + if (left > right) + return (x >= left || x < right); + return (x >= left && x < right); +} + +// check if a layer can be the target-b for alpha blending +static inline bool IsBlendTargetB(uint8_t layerId, unsigned int bldcnt) +{ + if (layerId <= 3) + return (bldcnt & (1 << (8 + layerId))) != 0; + if (layerId == LAYER_OBJ) + return (bldcnt & BLDCNT_TGT2_OBJ) != 0; + if (layerId == LAYER_BACKDROP) + return (bldcnt & BLDCNT_TGT2_BD) != 0; + return false; +} + +// sprites with oam mode 1 always try alpha blending regardless of bldcnt +static inline uint16_t BlendSpritePixel( + uint16_t color, unsigned int x, + uint16_t *output, uint8_t *layerIds, + bool isSemiTransparent, + unsigned int blendMode, unsigned int bldcnt, + bool windowsEnabled, uint16_t *winMask, + unsigned int eva, unsigned int evb, unsigned int evy) +{ + bool winAllowsBlend = !windowsEnabled + || (winMask && (winMask[x] & WINMASK_CLR)); + + bool doAlpha = (blendMode == 1 && (bldcnt & BLDCNT_TGT1_OBJ) && winAllowsBlend) + || isSemiTransparent; + + if (doAlpha) { + if (IsBlendTargetB(layerIds[x], bldcnt)) + return alphaBlendColor(color, output[x], eva, evb); + } else if ((bldcnt & BLDCNT_TGT1_OBJ) && winAllowsBlend) { + if (blendMode == 2) + return alphaBrightnessIncrease(color, evy); + if (blendMode == 3) + return alphaBrightnessDecrease(color, evy); + } + + return color; +} + +// write a bg pixel with inline blend resolution +static inline void WriteBGPixelBlended( + unsigned int x, uint8_t pixel, + const uint16_t *palBase, int bgNum, + uint16_t *output, uint8_t *layerIds, + unsigned int blendMode, bool bgIsTargetA, + bool useWindows, unsigned int winBgBit, uint16_t *winMask, + unsigned int bldcnt, + unsigned int eva, unsigned int evb, unsigned int evy) +{ + uint16_t color = palBase[pixel] | COLOR_OPAQUE; + + if (useWindows && !(winMask[x] & winBgBit)) + return; + + if (bgIsTargetA && (!useWindows || (winMask[x] & WINMASK_CLR))) { + uint16_t src = color; + switch (blendMode) { + case 1: + if (IsBlendTargetB(layerIds[x], bldcnt)) + color = alphaBlendColor(src, output[x], eva, evb); + break; + case 2: color = alphaBrightnessIncrease(src, evy); break; + case 3: color = alphaBrightnessDecrease(src, evy); break; + } + } + + output[x] = color; + layerIds[x] = bgNum; +} + +static void RenderTextBG(int bgNum, uint16_t control, + uint16_t hoffs, uint16_t voffs, + int lineNum, uint16_t *output) +{ + unsigned int charBase = (control >> 2) & 3; + unsigned int screenBase = (control & BGCNT_SCREENBASE_MASK) >> 8; + unsigned int is8bpp = (control >> 7) & 1; + + unsigned int mapW = bgMapSizes[control >> 14][0]; + unsigned int mapPxW = mapW << 3; + unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; + unsigned int wMask = mapPxW - 1; + unsigned int hMask = mapPxH - 1; + + uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); + uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); + uint16_t *pal = (uint16_t *)PLTT; + + bool hasMosaic = control & BGCNT_MOSAIC; + if (hasMosaic) + lineNum = ApplyMosaicBGY(lineNum); + + hoffs &= 0x1FF; + voffs &= 0x1FF; + + unsigned int yy = (lineNum + voffs) & hMask; + unsigned int mapY = yy >> 3; + unsigned int tileY = yy & 7; + unsigned int rowBase = mapY * mapW; + + // slow path: 8bpp or mosaic, one pixel at a time + if (hasMosaic || is8bpp) { + for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { + unsigned int xx = hasMosaic + ? (ApplyMosaicBGX(x) + hoffs) & wMask + : (x + hoffs) & wMask; + + uint16_t entry = map[rowBase + (xx >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int tx = xx & 7; + unsigned int ty = tileY; + if (TILE_HFLIP(entry)) tx = 7 - tx; + if (TILE_VFLIP(entry)) ty = 7 - ty; + + if (!is8bpp) { + uint8_t pair = tiles[(tileNum << 5) + (ty << 2) + (tx >> 1)]; + uint8_t pixel = (tx & 1) ? (pair >> 4) : (pair & 0xF); + if (pixel) + output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; + } else { + uint8_t pixel = tiles[(tileNum << 6) + (ty << 3) + tx]; + if (pixel) + output[x] = pal[pixel] | COLOR_OPAQUE; + } + } + return; + } + + // fast path: 4bpp, read one u32 per tile row, unroll 8 pixels + unsigned int x = 0; + + // left edge: partial tile if scroll isn't tile-aligned + { + unsigned int startX = hoffs & wMask; + unsigned int startOff = startX & 7; + + if (startOff != 0) { + uint16_t entry = map[rowBase + (startX >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) ty = 7 - ty; + bool hflip = TILE_HFLIP(entry); + + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + + unsigned int partial = 8 - startOff; + if (partial > DISPLAY_WIDTH) partial = DISPLAY_WIDTH; + + for (unsigned int t = 0; t < partial && x < DISPLAY_WIDTH; t++, x++) { + unsigned int tx = startOff + t; + if (hflip) tx = 7 - tx; + uint8_t pixel = (row >> (tx << 2)) & 0xF; + if (pixel) + output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; + } + } + } + + // middle: full tiles, 8 pixels at a time + while (x + 8 <= DISPLAY_WIDTH) { + unsigned int srcX = (x + hoffs) & wMask; + uint16_t entry = map[rowBase + (srcX >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) ty = 7 - ty; + + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint16_t *palBase = pal + (palNum << 4); + + if (!TILE_HFLIP(entry)) { + uint8_t p; + p = row & 0xF; if (p) output[x ] = palBase[p] | COLOR_OPAQUE; + p = (row >> 4) & 0xF; if (p) output[x+1] = palBase[p] | COLOR_OPAQUE; + p = (row >> 8) & 0xF; if (p) output[x+2] = palBase[p] | COLOR_OPAQUE; + p = (row >> 12) & 0xF; if (p) output[x+3] = palBase[p] | COLOR_OPAQUE; + p = (row >> 16) & 0xF; if (p) output[x+4] = palBase[p] | COLOR_OPAQUE; + p = (row >> 20) & 0xF; if (p) output[x+5] = palBase[p] | COLOR_OPAQUE; + p = (row >> 24) & 0xF; if (p) output[x+6] = palBase[p] | COLOR_OPAQUE; + p = (row >> 28) & 0xF; if (p) output[x+7] = palBase[p] | COLOR_OPAQUE; + } else { + uint8_t p; + p = (row >> 28) & 0xF; if (p) output[x ] = palBase[p] | COLOR_OPAQUE; + p = (row >> 24) & 0xF; if (p) output[x+1] = palBase[p] | COLOR_OPAQUE; + p = (row >> 20) & 0xF; if (p) output[x+2] = palBase[p] | COLOR_OPAQUE; + p = (row >> 16) & 0xF; if (p) output[x+3] = palBase[p] | COLOR_OPAQUE; + p = (row >> 12) & 0xF; if (p) output[x+4] = palBase[p] | COLOR_OPAQUE; + p = (row >> 8) & 0xF; if (p) output[x+5] = palBase[p] | COLOR_OPAQUE; + p = (row >> 4) & 0xF; if (p) output[x+6] = palBase[p] | COLOR_OPAQUE; + p = row & 0xF; if (p) output[x+7] = palBase[p] | COLOR_OPAQUE; + } + x += 8; + } + + // right edge: leftover partial tile + if (x < DISPLAY_WIDTH) { + unsigned int srcX = (x + hoffs) & wMask; + uint16_t entry = map[rowBase + (srcX >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) ty = 7 - ty; + bool hflip = TILE_HFLIP(entry); + + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + + for (unsigned int t = 0; x < DISPLAY_WIDTH; t++, x++) { + unsigned int tx = hflip ? (7 - t) : t; + uint8_t pixel = (row >> (tx << 2)) & 0xF; + if (pixel) + output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; + } + } +} + +// same thing but with blend/window tracking baked in +static void RenderTextBGBlend(int bgNum, uint16_t control, + uint16_t hoffs, uint16_t voffs, + int lineNum, uint16_t *output, + uint8_t *layerIds, + unsigned int blendMode, + bool windowsEnabled, + uint16_t *winMask, + unsigned int bldcnt, + unsigned int eva, unsigned int evb, + unsigned int evy) +{ + unsigned int charBase = (control >> 2) & 3; + unsigned int screenBase = (control & BGCNT_SCREENBASE_MASK) >> 8; + unsigned int is8bpp = (control >> 7) & 1; + + unsigned int mapW = bgMapSizes[control >> 14][0]; + unsigned int mapPxW = mapW << 3; + unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; + unsigned int wMask = mapPxW - 1; + unsigned int hMask = mapPxH - 1; + + uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); + uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); + uint16_t *pal = (uint16_t *)PLTT; + + bool hasMosaic = control & BGCNT_MOSAIC; + if (hasMosaic) + lineNum = ApplyMosaicBGY(lineNum); + + hoffs &= 0x1FF; + voffs &= 0x1FF; + + unsigned int yy = (lineNum + voffs) & hMask; + unsigned int mapY = yy >> 3; + unsigned int tileY = yy & 7; + unsigned int rowBase = mapY * mapW; + + bool bgIsTargetA = (blendMode != 0) && (bldcnt & (1 << bgNum)); + bool useWindows = windowsEnabled && (winMask != NULL); + unsigned int winBgBit = 1 << bgNum; + + // slow path: 8bpp or mosaic + if (hasMosaic || is8bpp) { + for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { + unsigned int xx = hasMosaic + ? (ApplyMosaicBGX(x) + hoffs) & wMask + : (x + hoffs) & wMask; + + uint16_t entry = map[rowBase + (xx >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int tx = xx & 7; + unsigned int ty = tileY; + if (TILE_HFLIP(entry)) tx = 7 - tx; + if (TILE_VFLIP(entry)) ty = 7 - ty; + + uint8_t pixel; + if (!is8bpp) { + uint8_t pair = tiles[(tileNum << 5) + (ty << 2) + (tx >> 1)]; + pixel = (tx & 1) ? (pair >> 4) : (pair & 0xF); + } else { + pixel = tiles[(tileNum << 6) + (ty << 3) + tx]; + } + + if (pixel == 0) + continue; + + uint16_t color = !is8bpp + ? pal[(palNum << 4) + pixel] | COLOR_OPAQUE + : pal[pixel] | COLOR_OPAQUE; + + if (useWindows && !(winMask[x] & winBgBit)) + continue; + + if (bgIsTargetA && (!useWindows || (winMask[x] & WINMASK_CLR))) { + uint16_t src = color; + switch (blendMode) { + case 1: + if (IsBlendTargetB(layerIds[x], bldcnt)) + color = alphaBlendColor(src, output[x], eva, evb); + break; + case 2: color = alphaBrightnessIncrease(src, evy); break; + case 3: color = alphaBrightnessDecrease(src, evy); break; + } + } + + output[x] = color; + layerIds[x] = bgNum; + } + return; + } + + // fast path: 4bpp batched with inline blend + unsigned int x = 0; + + // left edge partial tile + { + unsigned int startX = hoffs & wMask; + unsigned int startOff = startX & 7; + + if (startOff != 0) { + uint16_t entry = map[rowBase + (startX >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) ty = 7 - ty; + bool hflip = TILE_HFLIP(entry); + + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint16_t *palBase = pal + (palNum << 4); + + unsigned int partial = 8 - startOff; + if (partial > DISPLAY_WIDTH) partial = DISPLAY_WIDTH; + + for (unsigned int t = 0; t < partial && x < DISPLAY_WIDTH; t++, x++) { + unsigned int tx = startOff + t; + if (hflip) tx = 7 - tx; + uint8_t pixel = (row >> (tx << 2)) & 0xF; + if (pixel) + WriteBGPixelBlended(x, pixel, palBase, bgNum, output, + layerIds, blendMode, bgIsTargetA, + useWindows, winBgBit, winMask, + bldcnt, eva, evb, evy); + } + } + } + + // middle: full tiles + while (x + 8 <= DISPLAY_WIDTH) { + unsigned int srcX = (x + hoffs) & wMask; + uint16_t entry = map[rowBase + (srcX >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) ty = 7 - ty; + + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint16_t *palBase = pal + (palNum << 4); + + #define BLEND_PX(off, shift) do { \ + uint8_t p = (row >> (shift)) & 0xF; \ + if (p) WriteBGPixelBlended(x+(off), p, palBase, bgNum, \ + output, layerIds, blendMode, bgIsTargetA, \ + useWindows, winBgBit, winMask, \ + bldcnt, eva, evb, evy); \ + } while (0) + + if (!TILE_HFLIP(entry)) { + BLEND_PX(0, 0); BLEND_PX(1, 4); + BLEND_PX(2, 8); BLEND_PX(3, 12); + BLEND_PX(4, 16); BLEND_PX(5, 20); + BLEND_PX(6, 24); BLEND_PX(7, 28); + } else { + BLEND_PX(0, 28); BLEND_PX(1, 24); + BLEND_PX(2, 20); BLEND_PX(3, 16); + BLEND_PX(4, 12); BLEND_PX(5, 8); + BLEND_PX(6, 4); BLEND_PX(7, 0); + } + + #undef BLEND_PX + + x += 8; + } + + // right edge partial tile + if (x < DISPLAY_WIDTH) { + unsigned int srcX = (x + hoffs) & wMask; + uint16_t entry = map[rowBase + (srcX >> 3)]; + unsigned int tileNum = TILE_NUM(entry); + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) ty = 7 - ty; + bool hflip = TILE_HFLIP(entry); + + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint16_t *palBase = pal + (palNum << 4); + + for (unsigned int t = 0; x < DISPLAY_WIDTH; t++, x++) { + unsigned int tx = hflip ? (7 - t) : t; + uint8_t pixel = (row >> (tx << 2)) & 0xF; + if (pixel) + WriteBGPixelBlended(x, pixel, palBase, bgNum, output, + layerIds, blendMode, bgIsTargetA, + useWindows, winBgBit, winMask, + bldcnt, eva, evb, evy); + } + } +} + +static void RenderAffineBG(int bgNum, uint16_t control, + int lineNum, uint16_t *output) +{ + vBgCnt *bgcnt = (vBgCnt *)&control; + + uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); + uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); + uint16_t *pal = (uint16_t *)PLTT; + + if (control & BGCNT_MOSAIC) + lineNum = ApplyMosaicBGY(lineNum); + + s16 pa = GetBgPA(bgNum); + s16 pb = GetBgPB(bgNum); + s16 pc = GetBgPC(bgNum); + s16 pd = GetBgPD(bgNum); + + // always square: 128/256/512/1024 + int size = 128; + switch (bgcnt->screenSize) { + case 1: size = 256; break; + case 2: size = 512; break; + case 3: size = 1024; break; + } + int mask = size - 1; + int yshift = ((control >> 14) & 3) + 4; + + // sign-extend 28-bit reference point, advance by scanline + s32 refX = GetBgRefX(bgNum); + s32 refY = GetBgRefY(bgNum); + refX = (refX & (1 << 27)) ? refX | 0xF0000000 : refX; + refY = (refY & (1 << 27)) ? refY | 0xF0000000 : refY; + refX += lineNum * pb; + refY += lineNum * pd; + + int curX = refX; + int curY = refY; + + if (bgcnt->areaOverflowMode) { + // wraparound + for (int x = 0; x < DISPLAY_WIDTH; x++) { + int tx = (curX >> 8) & mask; + int ty = (curY >> 8) & mask; + int tile = map[(tx >> 3) + ((ty >> 3) << yshift)]; + uint8_t pixel = tiles[(tile << 6) + ((ty & 7) << 3) + (tx & 7)]; + if (pixel) + output[x] = pal[pixel] | COLOR_OPAQUE; + curX += pa; + curY += pc; + } + } else { + // clamp: outside the map = transparent + for (int x = 0; x < DISPLAY_WIDTH; x++) { + int tx = curX >> 8; + int ty = curY >> 8; + if (tx >= 0 && ty >= 0 && tx < size && ty < size) { + int tile = map[(tx >> 3) + ((ty >> 3) << yshift)]; + uint8_t pixel = tiles[(tile << 6) + ((ty & 7) << 3) + (tx & 7)]; + if (pixel) + output[x] = pal[pixel] | COLOR_OPAQUE; + } + curX += pa; + curY += pc; + } + } + + // horizontal mosaic as a post-pass + if ((control & BGCNT_MOSAIC) && MOSAIC_BG_X > 0) { + for (int x = 0; x < DISPLAY_WIDTH; x++) + output[x] = output[ApplyMosaicBGX(x)]; + } +} + +// same deal with blend/window support +static void RenderAffineBGBlend(int bgNum, uint16_t control, + int lineNum, uint16_t *output, + uint8_t *layerIds, + unsigned int blendMode, + bool windowsEnabled, + uint16_t *winMask, + unsigned int bldcnt, + unsigned int eva, unsigned int evb, + unsigned int evy) +{ + vBgCnt *bgcnt = (vBgCnt *)&control; + + uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); + uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); + uint16_t *pal = (uint16_t *)PLTT; + + if (control & BGCNT_MOSAIC) + lineNum = ApplyMosaicBGY(lineNum); + + s16 pa = GetBgPA(bgNum); + s16 pb = GetBgPB(bgNum); + s16 pc = GetBgPC(bgNum); + s16 pd = GetBgPD(bgNum); + + int size = 128; + switch (bgcnt->screenSize) { + case 1: size = 256; break; + case 2: size = 512; break; + case 3: size = 1024; break; + } + int mask = size - 1; + int yshift = ((control >> 14) & 3) + 4; + + s32 refX = GetBgRefX(bgNum); + s32 refY = GetBgRefY(bgNum); + refX = (refX & (1 << 27)) ? refX | 0xF0000000 : refX; + refY = (refY & (1 << 27)) ? refY | 0xF0000000 : refY; + refX += lineNum * pb; + refY += lineNum * pd; + + int curX = refX; + int curY = refY; + + bool bgIsTargetA = (blendMode != 0) && (bldcnt & (1 << bgNum)); + + for (int x = 0; x < DISPLAY_WIDTH; x++) { + int tx, ty; + + if (bgcnt->areaOverflowMode) { + tx = (curX >> 8) & mask; + ty = (curY >> 8) & mask; + } else { + tx = curX >> 8; + ty = curY >> 8; + if (tx < 0 || ty < 0 || tx >= size || ty >= size) { + curX += pa; + curY += pc; + continue; + } + } + + int tile = map[(tx >> 3) + ((ty >> 3) << yshift)]; + uint8_t pixel = tiles[(tile << 6) + ((ty & 7) << 3) + (tx & 7)]; + + curX += pa; + curY += pc; + + if (pixel == 0) + continue; + + uint16_t color = pal[pixel] | COLOR_OPAQUE; + + if (windowsEnabled && winMask && !(winMask[x] & (1 << bgNum))) + continue; + + bool winAllowsBlend = true; + if (windowsEnabled && winMask) + winAllowsBlend = (winMask[x] & WINMASK_CLR) >> 5; + + if (bgIsTargetA && winAllowsBlend) { + uint16_t src = color; + switch (blendMode) { + case 1: + if (IsBlendTargetB(layerIds[x], bldcnt)) + color = alphaBlendColor(src, output[x], eva, evb); + break; + case 2: color = alphaBrightnessIncrease(src, evy); break; + case 3: color = alphaBrightnessDecrease(src, evy); break; + } + } + + output[x] = color; + layerIds[x] = bgNum; + } + + if ((control & BGCNT_MOSAIC) && MOSAIC_BG_X > 0) { + for (int x = 0; x < DISPLAY_WIDTH; x++) + output[x] = output[ApplyMosaicBGX(x)]; + } +} + +#define MAX_SPRITES_PER_PRIORITY 32 + +typedef struct { + uint8_t oamIndex; +} ActiveSprite; + +static ActiveSprite sActiveSprites[4][MAX_SPRITES_PER_PRIORITY]; +static int sActiveSpriteCount[4]; + +static void PrefilterSprites(uint16_t vcount) +{ + sActiveSpriteCount[0] = 0; + sActiveSpriteCount[1] = 0; + sActiveSpriteCount[2] = 0; + sActiveSpriteCount[3] = 0; + + if (!(REG_DISPCNT & DISPCNT_OBJ_ON)) + return; + + // back-to-front so lower oam indices (higher hw priority) draw last + for (int i = OAM_ENTRY_COUNT - 1; i >= 0; i--) { + OamData *oam = &((OamData *)OAM)[i]; + + bool isAffine = oam->split.affineMode & 1; + bool isDisabled = (oam->split.affineMode >> 1) & 1; + + if (!isAffine && isDisabled) + continue; + + s32 idx = (oam->split.shape << 2) | oam->split.size; + unsigned int width = gOamShapesSizes[idx][0]; + unsigned int height = gOamShapesSizes[idx][1]; + int halfW = width / 2; + int halfH = height / 2; + + int32_t sx = oam->split.x; + int32_t sy = oam->split.y; +#if !EXTENDED_OAM + if (sx >= DISPLAY_WIDTH) sx -= 512; + if (sy >= DISPLAY_HEIGHT) sy -= 256; +#endif + + // double-size affine sprites have 2x bounding box + if (isAffine && isDisabled) { + halfW *= 2; + halfH *= 2; + } + + if ((int)vcount < sy || (int)vcount >= sy + halfH * 2) + continue; + if (sx + halfW * 2 < 0 || sx >= DISPLAY_WIDTH) + continue; + + int pri = oam->split.priority; + if (sActiveSpriteCount[pri] < MAX_SPRITES_PER_PRIORITY) { + sActiveSprites[pri][sActiveSpriteCount[pri]].oamIndex = i; + sActiveSpriteCount[pri]++; + } + } +} + +static void DrawSpritesAtPriority(int priority, uint16_t vcount, + uint16_t *output, uint8_t *layerIds, + bool windowsEnabled, uint16_t *winMask, + unsigned int blendMode, bool objWinOnly, + unsigned int bldcnt, + unsigned int eva, unsigned int evb, + unsigned int evy) +{ + uint8_t *tiledata = (uint8_t *)OBJ_VRAM0; + uint16_t *sprpal = (uint16_t *)PLTT + (0x200 / 2); + int16_t matrix[2][2]; + + // only 1-D tile mapping supported + if (!(REG_DISPCNT & (1 << 6))) + return; + + for (int s = 0; s < sActiveSpriteCount[priority]; s++) { + int i = sActiveSprites[priority][s].oamIndex; + OamData *oam = &((OamData *)OAM)[i]; + + bool isAffine = oam->split.affineMode & 1; + bool doubleSize = (oam->split.affineMode >> 1) & 1; + + s32 idx = (oam->split.shape << 2) | oam->split.size; + unsigned int width = gOamShapesSizes[idx][0]; + unsigned int height = gOamShapesSizes[idx][1]; + int halfW = width / 2; + int halfH = height / 2; + + int32_t x = oam->split.x; + int32_t y = oam->split.y; +#if !EXTENDED_OAM + if (x >= DISPLAY_WIDTH) x -= 512; + if (y >= DISPLAY_HEIGHT) y -= 256; +#endif + if (isAffine && doubleSize) { + halfW *= 2; + halfH *= 2; + } + + bool isSemiTransparent = (oam->split.objMode == 1); + bool isObjWin = (oam->split.objMode == 2); + + if (objWinOnly && !isObjWin) continue; + if (!objWinOnly && isObjWin) continue; + + int rectWidth = width; + int rectHeight = height; + + if (isAffine) { + u8 matrixNum = oam->split.matrixNum * 4; + OamData *m0 = &((OamData *)OAM)[matrixNum]; + OamData *m1 = &((OamData *)OAM)[matrixNum + 1]; + OamData *m2 = &((OamData *)OAM)[matrixNum + 2]; + OamData *m3 = &((OamData *)OAM)[matrixNum + 3]; + matrix[0][0] = m0->all.affineParam; + matrix[0][1] = m1->all.affineParam; + matrix[1][0] = m2->all.affineParam; + matrix[1][1] = m3->all.affineParam; + if (doubleSize) { + rectWidth *= 2; + rectHeight *= 2; + } + } else { + matrix[0][0] = 0x100; // identity in 8.8 fixed point + matrix[0][1] = 0; + matrix[1][0] = 0; + matrix[1][1] = 0x100; + } + + x += halfW; + y += halfH; + + int localY = (oam->split.mosaic == 1) + ? ApplyMosaicSprY(vcount) - y + : vcount - y; + bool flipX = !isAffine && ((oam->split.matrixNum >> 3) & 1); + bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); + bool is8bpp = oam->split.bpp & 1; + + int startLX = -halfW; + int endLX = halfW; + if (startLX + x < 0) startLX = -x; + if (endLX + x >= DISPLAY_WIDTH) endLX = DISPLAY_WIDTH - 1 - x; + + // fast path: non-affine 4bpp, no mosaic -- batched tile row reads + if (!isAffine && !is8bpp && !oam->split.mosaic) { + int texY = localY + halfH; + if (flipY) texY = height - texY - 1; + if (texY < 0 || texY >= (int)height) + continue; + + int tileRowY = texY & 7; + int blockY = texY >> 3; + int tilesPerRow = (REG_DISPCNT & 0x40) ? ((int)width >> 3) : 16; + int tileBase = blockY * tilesPerRow + oam->split.tileNum; + int rowByteOff = tileRowY << 2; + uint16_t *pixpal = sprpal + (oam->split.paletteNum << 4); + + int lx = startLX; + while (lx <= endLX) { + int rawX = lx + halfW; + int texX = flipX ? ((int)width - 1 - rawX) : rawX; + + if (texX < 0 || texX >= (int)width) { + lx++; + continue; + } + + int blockX = texX >> 3; + int tileXStart = texX & 7; + + uint32_t rowData = *(uint32_t *)(tiledata + + ((tileBase + blockX) << 5) + rowByteOff); + + int pixelsInTile = !flipX ? (8 - tileXStart) : (tileXStart + 1); + int remain = endLX - lx + 1; + if (pixelsInTile > remain) pixelsInTile = remain; + + if (!flipX) { + int texRemain = (int)width - texX; + if (pixelsInTile > texRemain) pixelsInTile = texRemain; + } else { + int texRemain = texX + 1; + if (pixelsInTile > texRemain) pixelsInTile = texRemain; + } + + for (int p = 0; p < pixelsInTile; p++, lx++) { + int curTX = flipX ? (tileXStart - p) : (tileXStart + p); + uint8_t pixel = (rowData >> (curTX << 2)) & 0xF; + if (pixel == 0) + continue; + + int gx = lx + x; + uint16_t color = pixpal[pixel]; + + // obj window sprites modify the window mask, not the framebuffer + if (isObjWin) { + if (windowsEnabled && winMask && (winMask[gx] & WINMASK_WINOUT)) + winMask[gx] = (REG_WINOUT >> 8) & 0x3F; + continue; + } + + if (layerIds && blendMode != 0) + color = BlendSpritePixel(color, gx, output, layerIds, + isSemiTransparent, blendMode, + bldcnt, windowsEnabled, winMask, + eva, evb, evy); + + if (windowsEnabled && winMask && !(winMask[gx] & WINMASK_OBJ)) + continue; + + output[gx] = color | COLOR_OPAQUE; + if (layerIds) + layerIds[gx] = LAYER_OBJ; + } + } + continue; + } + + // generic path: affine, 8bpp, or mosaic -- per pixel + for (int localX = startLX; localX <= endLX; localX++) { + int gx = localX + x; + int texX, texY; + + if (!isAffine) { + int lmx = localX; + if (oam->split.mosaic == 1) + lmx = ApplyMosaicSprX(gx) - x; + texX = lmx + halfW; + texY = localY + halfH; + if (flipX) texX = width - texX - 1; + if (flipY) texY = height - texY - 1; + } else { + int lmx = localX; + int lmy = localY; + if (oam->split.mosaic == 1) { + lmx = ApplyMosaicSprX(gx) - x; + lmy = ApplyMosaicSprY(vcount) - y; + } + // apply 2x2 affine matrix (8.8 fixed point) + texX = ((matrix[0][0] * lmx + matrix[0][1] * lmy) >> 8) + (width / 2); + texY = ((matrix[1][0] * lmx + matrix[1][1] * lmy) >> 8) + (height / 2); + } + + if (texX < 0 || texY < 0 || texX >= (int)width || texY >= (int)height) + continue; + + int tileX = texX & 7; + int tileY = texY & 7; + int blockX = texX >> 3; + int blockY = texY >> 3; + int blockOffset = blockY * (REG_DISPCNT & 0x40 ? ((int)width >> 3) : 16) + blockX; + + uint16_t pixel = 0; + uint16_t *pixpal; + + if (!is8bpp) { + int tdi = ((blockOffset + oam->split.tileNum) << 5) + (tileY << 2) + (tileX >> 1); + pixel = tiledata[tdi]; + if (tileX & 1) pixel >>= 4; + else pixel &= 0xF; + pixpal = sprpal + (oam->split.paletteNum << 4); + } else { + pixel = tiledata[((blockOffset * 2 + oam->split.tileNum) << 5) + (tileY << 3) + tileX]; + pixpal = sprpal; + } + + if (pixel == 0) + continue; + + uint16_t color = pixpal[pixel]; + + if (isObjWin) { + if (windowsEnabled && winMask && (winMask[gx] & WINMASK_WINOUT)) + winMask[gx] = (REG_WINOUT >> 8) & 0x3F; + continue; + } + + if (layerIds && blendMode != 0) + color = BlendSpritePixel(color, gx, output, layerIds, + isSemiTransparent, blendMode, + bldcnt, windowsEnabled, winMask, + eva, evb, evy); + + if (windowsEnabled && winMask && !(winMask[gx] & WINMASK_OBJ)) + continue; + + output[gx] = color | COLOR_OPAQUE; + if (layerIds) + layerIds[gx] = LAYER_OBJ; + } + } +} + +static void DrawScanline(uint16_t *pixels, uint16_t vcount) +{ + unsigned int mode = REG_DISPCNT & 3; + unsigned int numBGs = (mode == 0) ? 4 : 3; + unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + unsigned int enabledBgs = (REG_DISPCNT >> 8) & 0xF; + + // sort bgs by priority + uint16_t bgcnts[4]; + char bgPriority[4]; + char bgsByPri[4][4]; + char bgsByPriCount[4] = {0, 0, 0, 0}; + + for (int bg = 0; bg < (int)numBGs; bg++) { + uint16_t cnt = *(uint16_t *)(REG_ADDR_BG0CNT + bg * 2); + bgcnts[bg] = cnt; + uint16_t pri = cnt & 3; + bgPriority[bg] = pri; + bgsByPri[pri][bgsByPriCount[pri]] = bg; + bgsByPriCount[pri]++; + } + + // window setup + bool windowsEnabled = false; + u16 win0Bot, win0Top, win0Right, win0Left; + u16 win1Bot, win1Top, win1Right, win1Left; + bool win0Active = false, win1Active = false; + static uint16_t winMask[DISPLAY_WIDTH]; + + if (REG_DISPCNT & DISPCNT_WIN0_ON) { + win0Bot = WIN_GET_HIGHER(REG_WIN0V); + win0Top = WIN_GET_LOWER(REG_WIN0V); + win0Right = WIN_GET_HIGHER(REG_WIN0H); + win0Left = WIN_GET_LOWER(REG_WIN0H); + if (win0Top > win0Bot) + win0Active = (vcount >= win0Top || vcount < win0Bot); + else + win0Active = (vcount >= win0Top && vcount < win0Bot); + windowsEnabled = true; + } + if (REG_DISPCNT & DISPCNT_WIN1_ON) { + win1Bot = WIN_GET_HIGHER(REG_WIN1V); + win1Top = WIN_GET_LOWER(REG_WIN1V); + win1Right = WIN_GET_HIGHER(REG_WIN1H); + win1Left = WIN_GET_LOWER(REG_WIN1H); + if (win1Top > win1Bot) + win1Active = (vcount >= win1Top || vcount < win1Bot); + else + win1Active = (vcount >= win1Top && vcount < win1Bot); + windowsEnabled = true; + } + if ((REG_DISPCNT & DISPCNT_OBJWIN_ON) && (REG_DISPCNT & DISPCNT_OBJ_ON)) + windowsEnabled = true; + + // build per-pixel window mask + if (windowsEnabled) { + for (unsigned int xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { + if (win0Active && WindowContainsX(win0Left, win0Right, xpos)) + winMask[xpos] = REG_WININ & 0x3F; + else if (win1Active && WindowContainsX(win1Left, win1Right, xpos)) + winMask[xpos] = (REG_WININ >> 8) & 0x3F; + else + winMask[xpos] = (REG_WINOUT & 0x3F) | WINMASK_WINOUT; + } + } + + PrefilterSprites(vcount); + + // layerIds tracks who wrote each pixel so alpha blend can find target-b + static uint8_t layerIds[DISPLAY_WIDTH]; + bool needLayerIds = (blendMode != 0 || windowsEnabled); + uint8_t *lids = needLayerIds ? layerIds : NULL; + uint16_t *wmask = windowsEnabled ? winMask : NULL; + + if (needLayerIds) + memset(layerIds, LAYER_BACKDROP, DISPLAY_WIDTH); + + // grab blend regs once per scanline + unsigned int bldcnt = REG_BLDCNT; + unsigned int bld_eva = REG_BLDALPHA & 0x1F; + unsigned int bld_evb = (REG_BLDALPHA >> 8) & 0x1F; + unsigned int bld_evy = REG_BLDY & 0x1F; + + // obj window pass -- these sprites modify the window mask, not the framebuffer + if (windowsEnabled && (REG_DISPCNT & DISPCNT_OBJWIN_ON) && (REG_DISPCNT & DISPCNT_OBJ_ON)) { + for (int pri = 0; pri < 4; pri++) + DrawSpritesAtPriority(pri, vcount, pixels, lids, + windowsEnabled, wmask, blendMode, + /*objWinOnly=*/true, + bldcnt, bld_eva, bld_evb, bld_evy); + } + + // back-to-front: priority 3 first, 0 last (0 is topmost) + for (int pri = 3; pri >= 0; pri--) { + for (int sub = bgsByPriCount[pri] - 1; sub >= 0; sub--) { + int bg = bgsByPri[pri][sub]; + if (!IsBGEnabled(bg)) + continue; + + if (!needLayerIds) { + switch (mode) { + case 0: + RenderTextBG(bg, bgcnts[bg], + *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), + *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), + vcount, pixels); + break; + case 1: + if (bg == 2) + RenderAffineBG(bg, bgcnts[bg], vcount, pixels); + else + RenderTextBG(bg, bgcnts[bg], + *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), + *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), + vcount, pixels); + break; + } + } else { + switch (mode) { + case 0: + RenderTextBGBlend(bg, bgcnts[bg], + *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), + *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), + vcount, pixels, lids, blendMode, + windowsEnabled, wmask, + bldcnt, bld_eva, bld_evb, bld_evy); + break; + case 1: + if (bg == 2) + RenderAffineBGBlend(bg, bgcnts[bg], + vcount, pixels, lids, blendMode, + windowsEnabled, wmask, + bldcnt, bld_eva, bld_evb, bld_evy); + else + RenderTextBGBlend(bg, bgcnts[bg], + *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), + *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), + vcount, pixels, lids, blendMode, + windowsEnabled, wmask, + bldcnt, bld_eva, bld_evb, bld_evy); + break; + } + } + } + + if (REG_DISPCNT & DISPCNT_OBJ_ON) + DrawSpritesAtPriority(pri, vcount, pixels, lids, + windowsEnabled, wmask, blendMode, + /*objWinOnly=*/false, + bldcnt, bld_eva, bld_evb, bld_evy); + } +} + +void DrawFrame_Fast(uint16_t *pixels) +{ + for (int i = 0; i < DISPLAY_HEIGHT; i++) { + uint16_t *scanline = &pixels[i * DISPLAY_WIDTH]; + + REG_VCOUNT = i; + if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { + REG_DISPSTAT |= INTR_FLAG_VCOUNT; + if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) + gIntrTable[INTR_INDEX_VCOUNT](); + } + + Memset16(scanline, *(uint16_t *)PLTT, DISPLAY_WIDTH); + DrawScanline(scanline, i); + + REG_DISPSTAT |= INTR_FLAG_HBLANK; + RunDMAs(DMA_HBLANK); + if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) + gIntrTable[INTR_INDEX_HBLANK](); + + REG_DISPSTAT &= ~INTR_FLAG_HBLANK; + REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; + } +} + +#endif From 347875845cd077530464de5c9c985a43b57f193e Mon Sep 17 00:00:00 2001 From: kikugrave Date: Sun, 15 Feb 2026 10:54:56 -0800 Subject: [PATCH 02/51] Fix lint --- .../shared/rendering/sw_renderer_common.h | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/include/platform/shared/rendering/sw_renderer_common.h b/include/platform/shared/rendering/sw_renderer_common.h index 1e1a626d91..ddb85d7ff2 100644 --- a/include/platform/shared/rendering/sw_renderer_common.h +++ b/include/platform/shared/rendering/sw_renderer_common.h @@ -8,21 +8,23 @@ // bgr555 channel extraction #define getAlphaBit(x) (((x) >> 15) & 1) -#define getRedChannel(x) (((x) >> 0) & 0x1F) -#define getGreenChannel(x) (((x) >> 5) & 0x1F) +#define getRedChannel(x) (((x) >> 0) & 0x1F) +#define getGreenChannel(x) (((x) >> 5) & 0x1F) #define getBlueChannel(x) (((x) >> 10) & 0x1F) -#define COLOR_OPAQUE 0x8000 +#define COLOR_OPAQUE 0x8000 -static inline uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB, - unsigned int eva, unsigned int evb) +static inline uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB, unsigned int eva, unsigned int evb) { unsigned int r = ((getRedChannel(targetA) * eva) + (getRedChannel(targetB) * evb)) >> 4; unsigned int g = ((getGreenChannel(targetA) * eva) + (getGreenChannel(targetB) * evb)) >> 4; unsigned int b = ((getBlueChannel(targetA) * eva) + (getBlueChannel(targetB) * evb)) >> 4; - if (r > 31) r = 31; - if (g > 31) g = 31; - if (b > 31) b = 31; + if (r > 31) + r = 31; + if (g > 31) + g = 31; + if (b > 31) + b = 31; return r | (g << 5) | (b << 10) | COLOR_OPAQUE; } @@ -33,9 +35,12 @@ static inline uint16_t alphaBrightnessIncrease(uint16_t targetA, unsigned int ev unsigned int g = getGreenChannel(targetA) + (31 - getGreenChannel(targetA)) * evy / 16; unsigned int b = getBlueChannel(targetA) + (31 - getBlueChannel(targetA)) * evy / 16; - if (r > 31) r = 31; - if (g > 31) g = 31; - if (b > 31) b = 31; + if (r > 31) + r = 31; + if (g > 31) + g = 31; + if (b > 31) + b = 31; return r | (g << 5) | (b << 10) | COLOR_OPAQUE; } @@ -46,9 +51,12 @@ static inline uint16_t alphaBrightnessDecrease(uint16_t targetA, unsigned int ev unsigned int g = getGreenChannel(targetA) - getGreenChannel(targetA) * evy / 16; unsigned int b = getBlueChannel(targetA) - getBlueChannel(targetA) * evy / 16; - if (r > 31) r = 31; - if (g > 31) g = 31; - if (b > 31) b = 31; + if (r > 31) + r = 31; + if (g > 31) + g = 31; + if (b > 31) + b = 31; return r | (g << 5) | (b << 10) | COLOR_OPAQUE; } From f881e7c588345506471599312bb374e6a3ec7603 Mon Sep 17 00:00:00 2001 From: kikugrave Date: Sun, 15 Feb 2026 10:57:27 -0800 Subject: [PATCH 03/51] Fix lint 2 --- src/lib/m4a/m4a.c | 2 +- src/platform/pret_sdl/sdl2.c | 181 +++-- src/platform/psp/psp_module.c | 3 +- src/platform/shared/audio/m4a_sound_mixer.c | 5 +- .../shared/rendering/sw_renderer_fast.c | 648 +++++++++--------- 5 files changed, 433 insertions(+), 406 deletions(-) diff --git a/src/lib/m4a/m4a.c b/src/lib/m4a/m4a.c index a7119e5a36..108dae8978 100644 --- a/src/lib/m4a/m4a.c +++ b/src/lib/m4a/m4a.c @@ -1369,7 +1369,7 @@ void MP2K_event_memacc(struct MP2KPlayerState *mplayInfo, struct MP2KTrack *trac return; } -cond_true : { +cond_true: { { void (*func)(struct MP2KPlayerState *, struct MP2KTrack *) = *(&gMPlayJumpTable[1]); func(mplayInfo, track); diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index f93af8ed5a..044d2ab4cf 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -114,7 +114,7 @@ double accumulator = 0.0; static FILE *sSaveFile = NULL; extern void AgbMain(void); -void DoSoftReset(void) {}; +void DoSoftReset(void) { }; void ProcessSDLEvents(void); void VDraw(SDL_Texture *texture); @@ -245,7 +245,7 @@ int main(int argc, char **argv) SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); #ifdef __PSP__ // SDL_RenderSetLogicalSize is broken on PSP, stretch to fill manually - pspDestRect = (SDL_Rect){ 0, 0, PSP_SCREEN_W, PSP_SCREEN_H }; + pspDestRect = (SDL_Rect) { 0, 0, PSP_SCREEN_W, PSP_SCREEN_H }; #else SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); #endif @@ -1375,7 +1375,7 @@ const u8 spriteSizes[][2] = { { 32, 64 }, }; -#define isbgEnabled(x) ((REG_DISPCNT >> 8) & 0xF) & (1 << x) +#define isbgEnabled(x) ((REG_DISPCNT >> 8) & 0xF) & (1 << x) // outputs the blended pixel in colorOutput, the prxxx are the bg priority and // subpriority, pixelpos is pixel offset in scanline @@ -1538,102 +1538,102 @@ static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool bool is8BPP = oam->split.bpp & 1; { - uint8_t *tiledata = (uint8_t *)objtiles; - uint16_t *sprpal = (uint16_t *)(PLTT + (0x200 / 2)); - for (int local_x = -half_width; local_x <= half_width; local_x++) { - int local_mosaicX; - int tex_x; - int tex_y; - - unsigned int global_x = local_x + x; - - if (global_x < 0 || global_x >= DISPLAY_WIDTH) - continue; - - if (oam->split.mosaic == 1) { - // mosaic effect has to be applied to global coordinates otherwise - // the mosaic will scroll - local_mosaicX = applySpriteHorizontalMosaicEffect(global_x) - x; - tex_x = ((matrix[0][0] * local_mosaicX + matrix[0][1] * local_y) >> 8) + (width / 2); - tex_y = ((matrix[1][0] * local_mosaicX + matrix[1][1] * local_y) >> 8) + (height / 2); - } else { - tex_x = ((matrix[0][0] * local_x + matrix[0][1] * local_y) >> 8) + (width / 2); - tex_y = ((matrix[1][0] * local_x + matrix[1][1] * local_y) >> 8) + (height / 2); - } + uint8_t *tiledata = (uint8_t *)objtiles; + uint16_t *sprpal = (uint16_t *)(PLTT + (0x200 / 2)); + for (int local_x = -half_width; local_x <= half_width; local_x++) { + int local_mosaicX; + int tex_x; + int tex_y; - /* Check if transformed coordinates are inside bounds. */ - - if (tex_x >= width || tex_y >= height || tex_x < 0 || tex_y < 0) - continue; - - if (flipX) - tex_x = width - tex_x - 1; - if (flipY) - tex_y = height - tex_y - 1; - - int tile_x = tex_x & 7; - int tile_y = tex_y & 7; - int block_x = tex_x >> 3; - int block_y = tex_y >> 3; - int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width >> 3) : 16)) + block_x); - uint16_t pixel = 0; - - uint16_t *pixpal; - if (!is8BPP) { - int tileDataIndex = ((block_offset + oam->split.tileNum) << 5) + (tile_y << 2) + (tile_x >> 1); - pixel = tiledata[tileDataIndex]; - if (tile_x & 1) - pixel >>= 4; - else - pixel &= 0xF; - pixpal = sprpal + (oam->split.paletteNum << 4); -#if ENABLE_VRAM_VIEW - vramPalIdBuffer[0x800 + (tileDataIndex >> 5)] = 16 + oam->split.paletteNum; -#endif - } else { - pixel = tiledata[((block_offset * 2 + oam->split.tileNum) << 5) + (tile_y << 3) + tile_x]; - pixpal = sprpal; - } + unsigned int global_x = local_x + x; - if (pixel != 0) { - uint16_t color = pixpal[pixel]; + if (global_x < 0 || global_x >= DISPLAY_WIDTH) + continue; - // if sprite mode is 2 then write to the window mask instead - if (isObjWin) { - if (scanline->winMask[global_x] & WINMASK_WINOUT) - scanline->winMask[global_x] = (REG_WINOUT >> 8) & 0x3F; + if (oam->split.mosaic == 1) { + // mosaic effect has to be applied to global coordinates otherwise + // the mosaic will scroll + local_mosaicX = applySpriteHorizontalMosaicEffect(global_x) - x; + tex_x = ((matrix[0][0] * local_mosaicX + matrix[0][1] * local_y) >> 8) + (width / 2); + tex_y = ((matrix[1][0] * local_mosaicX + matrix[1][1] * local_y) >> 8) + (height / 2); + } else { + tex_x = ((matrix[0][0] * local_x + matrix[0][1] * local_y) >> 8) + (width / 2); + tex_y = ((matrix[1][0] * local_x + matrix[1][1] * local_y) >> 8) + (height / 2); + } + + /* Check if transformed coordinates are inside bounds. */ + + if (tex_x >= width || tex_y >= height || tex_x < 0 || tex_y < 0) continue; + + if (flipX) + tex_x = width - tex_x - 1; + if (flipY) + tex_y = height - tex_y - 1; + + int tile_x = tex_x & 7; + int tile_y = tex_y & 7; + int block_x = tex_x >> 3; + int block_y = tex_y >> 3; + int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width >> 3) : 16)) + block_x); + uint16_t pixel = 0; + + uint16_t *pixpal; + if (!is8BPP) { + int tileDataIndex = ((block_offset + oam->split.tileNum) << 5) + (tile_y << 2) + (tile_x >> 1); + pixel = tiledata[tileDataIndex]; + if (tile_x & 1) + pixel >>= 4; + else + pixel &= 0xF; + pixpal = sprpal + (oam->split.paletteNum << 4); +#if ENABLE_VRAM_VIEW + vramPalIdBuffer[0x800 + (tileDataIndex >> 5)] = 16 + oam->split.paletteNum; +#endif + } else { + pixel = tiledata[((block_offset * 2 + oam->split.tileNum) << 5) + (tile_y << 3) + tile_x]; + pixpal = sprpal; } - // this code runs if pixel is to be drawn - if (global_x < DISPLAY_WIDTH && global_x >= 0) { - // check if its enabled in the window (if window is enabled) - winShouldBlendPixel = (windowsEnabled == false || scanline->winMask[global_x] & WINMASK_CLR); - - // has to be separated from the blend mode switch statement - // because of OBJ semi transparancy feature - if ((blendMode == 1 && REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) || isSemiTransparent) { - uint16_t targetA = color; - uint16_t targetB = 0; - if (alphaBlendSelectTargetB(scanline, &targetB, oam->split.priority, 0, global_x, false)) { - color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); - } - } else if (REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) { - switch (blendMode) { - case 2: - color = alphaBrightnessIncrease(color, REG_BLDY & 0x1F); - break; - case 3: - color = alphaBrightnessDecrease(color, REG_BLDY & 0x1F); - break; - } + + if (pixel != 0) { + uint16_t color = pixpal[pixel]; + + // if sprite mode is 2 then write to the window mask instead + if (isObjWin) { + if (scanline->winMask[global_x] & WINMASK_WINOUT) + scanline->winMask[global_x] = (REG_WINOUT >> 8) & 0x3F; + continue; } + // this code runs if pixel is to be drawn + if (global_x < DISPLAY_WIDTH && global_x >= 0) { + // check if its enabled in the window (if window is enabled) + winShouldBlendPixel = (windowsEnabled == false || scanline->winMask[global_x] & WINMASK_CLR); + + // has to be separated from the blend mode switch statement + // because of OBJ semi transparancy feature + if ((blendMode == 1 && REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) || isSemiTransparent) { + uint16_t targetA = color; + uint16_t targetB = 0; + if (alphaBlendSelectTargetB(scanline, &targetB, oam->split.priority, 0, global_x, false)) { + color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); + } + } else if (REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) { + switch (blendMode) { + case 2: + color = alphaBrightnessIncrease(color, REG_BLDY & 0x1F); + break; + case 3: + color = alphaBrightnessDecrease(color, REG_BLDY & 0x1F); + break; + } + } - // write pixel to pixel framebuffer - pixels[global_x] = color | (1 << 15); + // write pixel to pixel framebuffer + pixels[global_x] = color | (1 << 15); + } } } } - } } } } @@ -1825,8 +1825,7 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) case 1: { char isSpriteBlendingEnabled = REG_BLDCNT & BLDCNT_TGT2_OBJ ? 1 : 0; // find targetB and blend it - if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, - isSpriteBlendingEnabled)) { + if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, isSpriteBlendingEnabled)) { color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); } } break; diff --git a/src/platform/psp/psp_module.c b/src/platform/psp/psp_module.c index a070da463c..18040b1e17 100644 --- a/src/platform/psp/psp_module.c +++ b/src/platform/psp/psp_module.c @@ -33,8 +33,7 @@ int callbackThread(SceSize args, void *argp) int setupPspCallbacks(void) { int thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0); - if (thid >= 0) - { + if (thid >= 0) { sceKernelStartThread(thid, 0, 0); } return thid; diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index b9236e9841..f7a8927b3f 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -370,10 +370,7 @@ void MP2K_event_fine(struct MP2KPlayerState *unused, struct MP2KTrack *track) // mPtr aligns to 4 bytes on MIPS; match that here before reading pointer data #ifdef __mips__ -static inline u8 *alignCmdPtr4(u8 *p) -{ - return (u8 *)(((uintptr_t)p + 3) & ~(uintptr_t)3); -} +static inline u8 *alignCmdPtr4(u8 *p) { return (u8 *)(((uintptr_t)p + 3) & ~(uintptr_t)3); } #else #define alignCmdPtr4(p) (p) #endif diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c index 72327a2de9..484ddf042c 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -30,33 +30,33 @@ #include "platform/shared/rendering/sw_renderer_common.h" extern IntrFunc gIntrTable[16]; -extern uint8_t REG_BASE[IO_SIZE]; +extern uint8_t REG_BASE[IO_SIZE]; extern uint16_t PLTT[PLTT_SIZE / sizeof(uint16_t)]; -extern uint8_t VRAM[VRAM_SIZE]; -extern uint8_t OAM[OAM_SIZE]; +extern uint8_t VRAM[VRAM_SIZE]; +extern uint8_t OAM[OAM_SIZE]; extern const u8 gOamShapesSizes[12][2]; #ifndef TILE_WIDTH #define TILE_WIDTH 8 #endif -#define IsBGEnabled(n) (((REG_DISPCNT >> 8) & 0xF) & (1 << (n))) +#define IsBGEnabled(n) (((REG_DISPCNT >> 8) & 0xF) & (1 << (n))) // mosaic -#define MOSAIC_BG_X (REG_MOSAIC & 0xF) -#define MOSAIC_BG_Y ((REG_MOSAIC >> 4) & 0xF) -#define MOSAIC_SPR_X ((REG_MOSAIC >> 8) & 0xF) -#define MOSAIC_SPR_Y ((REG_MOSAIC >> 12) & 0xF) -#define ApplyMosaicBGX(x) ((x) - ((x) % (MOSAIC_BG_X + 1))) -#define ApplyMosaicBGY(y) ((y) - ((y) % (MOSAIC_BG_Y + 1))) -#define ApplyMosaicSprX(x) ((x) - ((x) % (MOSAIC_SPR_X + 1))) -#define ApplyMosaicSprY(y) ((y) - ((y) % (MOSAIC_SPR_Y + 1))) +#define MOSAIC_BG_X (REG_MOSAIC & 0xF) +#define MOSAIC_BG_Y ((REG_MOSAIC >> 4) & 0xF) +#define MOSAIC_SPR_X ((REG_MOSAIC >> 8) & 0xF) +#define MOSAIC_SPR_Y ((REG_MOSAIC >> 12) & 0xF) +#define ApplyMosaicBGX(x) ((x) - ((x) % (MOSAIC_BG_X + 1))) +#define ApplyMosaicBGY(y) ((y) - ((y) % (MOSAIC_BG_Y + 1))) +#define ApplyMosaicSprX(x) ((x) - ((x) % (MOSAIC_SPR_X + 1))) +#define ApplyMosaicSprY(y) ((y) - ((y) % (MOSAIC_SPR_Y + 1))) // tilemap entry fields -#define TILE_NUM(e) ((e) & 0x3FF) -#define TILE_PALETTE(e) (((e) >> 12) & 0xF) -#define TILE_HFLIP(e) ((e) & (1 << 10)) -#define TILE_VFLIP(e) ((e) & (1 << 11)) +#define TILE_NUM(e) ((e) & 0x3FF) +#define TILE_PALETTE(e) (((e) >> 12) & 0xF) +#define TILE_HFLIP(e) ((e) & (1 << 10)) +#define TILE_VFLIP(e) ((e) & (1 << 11)) // window mask bits #define WINMASK_BG0 (1 << 0) @@ -68,18 +68,20 @@ extern const u8 gOamShapesSizes[12][2]; #define WINMASK_WINOUT (1 << 6) // layer ids for blend target tracking -#define LAYER_BG0 0 -#define LAYER_BG1 1 -#define LAYER_BG2 2 -#define LAYER_BG3 3 -#define LAYER_OBJ 4 -#define LAYER_BACKDROP 5 +#define LAYER_BG0 0 +#define LAYER_BG1 1 +#define LAYER_BG2 2 +#define LAYER_BG3 3 +#define LAYER_OBJ 4 +#define LAYER_BACKDROP 5 static const uint16_t bgMapSizes[][2] = { - { 32, 32 }, { 64, 32 }, { 32, 64 }, { 64, 64 }, + { 32, 32 }, + { 64, 32 }, + { 32, 64 }, + { 64, 64 }, }; - // 16-bit fill using 32-bit writes static inline void Memset16(uint16_t *dst, uint16_t fill, unsigned int count) { @@ -94,10 +96,10 @@ static inline void Memset16(uint16_t *dst, uint16_t fill, unsigned int count) static inline uint32_t GetBgRefX(int bg) { return (bg == 2) ? REG_BG2X : (bg == 3) ? REG_BG3X : 0; } static inline uint32_t GetBgRefY(int bg) { return (bg == 2) ? REG_BG2Y : (bg == 3) ? REG_BG3Y : 0; } -static inline uint16_t GetBgPA(int bg) { return (bg == 2) ? REG_BG2PA : (bg == 3) ? REG_BG3PA : 0; } -static inline uint16_t GetBgPB(int bg) { return (bg == 2) ? REG_BG2PB : (bg == 3) ? REG_BG3PB : 0; } -static inline uint16_t GetBgPC(int bg) { return (bg == 2) ? REG_BG2PC : (bg == 3) ? REG_BG3PC : 0; } -static inline uint16_t GetBgPD(int bg) { return (bg == 2) ? REG_BG2PD : (bg == 3) ? REG_BG3PD : 0; } +static inline uint16_t GetBgPA(int bg) { return (bg == 2) ? REG_BG2PA : (bg == 3) ? REG_BG3PA : 0; } +static inline uint16_t GetBgPB(int bg) { return (bg == 2) ? REG_BG2PB : (bg == 3) ? REG_BG3PB : 0; } +static inline uint16_t GetBgPC(int bg) { return (bg == 2) ? REG_BG2PC : (bg == 3) ? REG_BG3PC : 0; } +static inline uint16_t GetBgPD(int bg) { return (bg == 2) ? REG_BG2PD : (bg == 3) ? REG_BG3PD : 0; } // handles the wraparound case where left > right static inline bool WindowContainsX(u16 left, u16 right, u16 x) @@ -120,19 +122,13 @@ static inline bool IsBlendTargetB(uint8_t layerId, unsigned int bldcnt) } // sprites with oam mode 1 always try alpha blending regardless of bldcnt -static inline uint16_t BlendSpritePixel( - uint16_t color, unsigned int x, - uint16_t *output, uint8_t *layerIds, - bool isSemiTransparent, - unsigned int blendMode, unsigned int bldcnt, - bool windowsEnabled, uint16_t *winMask, - unsigned int eva, unsigned int evb, unsigned int evy) +static inline uint16_t BlendSpritePixel(uint16_t color, unsigned int x, uint16_t *output, uint8_t *layerIds, bool isSemiTransparent, + unsigned int blendMode, unsigned int bldcnt, bool windowsEnabled, uint16_t *winMask, + unsigned int eva, unsigned int evb, unsigned int evy) { - bool winAllowsBlend = !windowsEnabled - || (winMask && (winMask[x] & WINMASK_CLR)); + bool winAllowsBlend = !windowsEnabled || (winMask && (winMask[x] & WINMASK_CLR)); - bool doAlpha = (blendMode == 1 && (bldcnt & BLDCNT_TGT1_OBJ) && winAllowsBlend) - || isSemiTransparent; + bool doAlpha = (blendMode == 1 && (bldcnt & BLDCNT_TGT1_OBJ) && winAllowsBlend) || isSemiTransparent; if (doAlpha) { if (IsBlendTargetB(layerIds[x], bldcnt)) @@ -148,14 +144,9 @@ static inline uint16_t BlendSpritePixel( } // write a bg pixel with inline blend resolution -static inline void WriteBGPixelBlended( - unsigned int x, uint8_t pixel, - const uint16_t *palBase, int bgNum, - uint16_t *output, uint8_t *layerIds, - unsigned int blendMode, bool bgIsTargetA, - bool useWindows, unsigned int winBgBit, uint16_t *winMask, - unsigned int bldcnt, - unsigned int eva, unsigned int evb, unsigned int evy) +static inline void WriteBGPixelBlended(unsigned int x, uint8_t pixel, const uint16_t *palBase, int bgNum, uint16_t *output, + uint8_t *layerIds, unsigned int blendMode, bool bgIsTargetA, bool useWindows, unsigned int winBgBit, + uint16_t *winMask, unsigned int bldcnt, unsigned int eva, unsigned int evb, unsigned int evy) { uint16_t color = palBase[pixel] | COLOR_OPAQUE; @@ -169,8 +160,12 @@ static inline void WriteBGPixelBlended( if (IsBlendTargetB(layerIds[x], bldcnt)) color = alphaBlendColor(src, output[x], eva, evb); break; - case 2: color = alphaBrightnessIncrease(src, evy); break; - case 3: color = alphaBrightnessDecrease(src, evy); break; + case 2: + color = alphaBrightnessIncrease(src, evy); + break; + case 3: + color = alphaBrightnessDecrease(src, evy); + break; } } @@ -178,23 +173,21 @@ static inline void WriteBGPixelBlended( layerIds[x] = bgNum; } -static void RenderTextBG(int bgNum, uint16_t control, - uint16_t hoffs, uint16_t voffs, - int lineNum, uint16_t *output) +static void RenderTextBG(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *output) { - unsigned int charBase = (control >> 2) & 3; + unsigned int charBase = (control >> 2) & 3; unsigned int screenBase = (control & BGCNT_SCREENBASE_MASK) >> 8; - unsigned int is8bpp = (control >> 7) & 1; + unsigned int is8bpp = (control >> 7) & 1; - unsigned int mapW = bgMapSizes[control >> 14][0]; - unsigned int mapPxW = mapW << 3; - unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; - unsigned int wMask = mapPxW - 1; - unsigned int hMask = mapPxH - 1; + unsigned int mapW = bgMapSizes[control >> 14][0]; + unsigned int mapPxW = mapW << 3; + unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; + unsigned int wMask = mapPxW - 1; + unsigned int hMask = mapPxH - 1; - uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); - uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); - uint16_t *pal = (uint16_t *)PLTT; + uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); + uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); + uint16_t *pal = (uint16_t *)PLTT; bool hasMosaic = control & BGCNT_MOSAIC; if (hasMosaic) @@ -203,25 +196,25 @@ static void RenderTextBG(int bgNum, uint16_t control, hoffs &= 0x1FF; voffs &= 0x1FF; - unsigned int yy = (lineNum + voffs) & hMask; - unsigned int mapY = yy >> 3; - unsigned int tileY = yy & 7; + unsigned int yy = (lineNum + voffs) & hMask; + unsigned int mapY = yy >> 3; + unsigned int tileY = yy & 7; unsigned int rowBase = mapY * mapW; // slow path: 8bpp or mosaic, one pixel at a time if (hasMosaic || is8bpp) { for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - unsigned int xx = hasMosaic - ? (ApplyMosaicBGX(x) + hoffs) & wMask - : (x + hoffs) & wMask; + unsigned int xx = hasMosaic ? (ApplyMosaicBGX(x) + hoffs) & wMask : (x + hoffs) & wMask; uint16_t entry = map[rowBase + (xx >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); + unsigned int palNum = TILE_PALETTE(entry); unsigned int tx = xx & 7; unsigned int ty = tileY; - if (TILE_HFLIP(entry)) tx = 7 - tx; - if (TILE_VFLIP(entry)) ty = 7 - ty; + if (TILE_HFLIP(entry)) + tx = 7 - tx; + if (TILE_VFLIP(entry)) + ty = 7 - ty; if (!is8bpp) { uint8_t pair = tiles[(tileNum << 5) + (ty << 2) + (tx >> 1)]; @@ -242,25 +235,28 @@ static void RenderTextBG(int bgNum, uint16_t control, // left edge: partial tile if scroll isn't tile-aligned { - unsigned int startX = hoffs & wMask; + unsigned int startX = hoffs & wMask; unsigned int startOff = startX & 7; if (startOff != 0) { uint16_t entry = map[rowBase + (startX >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) ty = 7 - ty; + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) + ty = 7 - ty; bool hflip = TILE_HFLIP(entry); uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); unsigned int partial = 8 - startOff; - if (partial > DISPLAY_WIDTH) partial = DISPLAY_WIDTH; + if (partial > DISPLAY_WIDTH) + partial = DISPLAY_WIDTH; for (unsigned int t = 0; t < partial && x < DISPLAY_WIDTH; t++, x++) { unsigned int tx = startOff + t; - if (hflip) tx = 7 - tx; + if (hflip) + tx = 7 - tx; uint8_t pixel = (row >> (tx << 2)) & 0xF; if (pixel) output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; @@ -271,35 +267,68 @@ static void RenderTextBG(int bgNum, uint16_t control, // middle: full tiles, 8 pixels at a time while (x + 8 <= DISPLAY_WIDTH) { unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; + uint16_t entry = map[rowBase + (srcX >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) ty = 7 - ty; + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) + ty = 7 - ty; - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); uint16_t *palBase = pal + (palNum << 4); if (!TILE_HFLIP(entry)) { uint8_t p; - p = row & 0xF; if (p) output[x ] = palBase[p] | COLOR_OPAQUE; - p = (row >> 4) & 0xF; if (p) output[x+1] = palBase[p] | COLOR_OPAQUE; - p = (row >> 8) & 0xF; if (p) output[x+2] = palBase[p] | COLOR_OPAQUE; - p = (row >> 12) & 0xF; if (p) output[x+3] = palBase[p] | COLOR_OPAQUE; - p = (row >> 16) & 0xF; if (p) output[x+4] = palBase[p] | COLOR_OPAQUE; - p = (row >> 20) & 0xF; if (p) output[x+5] = palBase[p] | COLOR_OPAQUE; - p = (row >> 24) & 0xF; if (p) output[x+6] = palBase[p] | COLOR_OPAQUE; - p = (row >> 28) & 0xF; if (p) output[x+7] = palBase[p] | COLOR_OPAQUE; + p = row & 0xF; + if (p) + output[x] = palBase[p] | COLOR_OPAQUE; + p = (row >> 4) & 0xF; + if (p) + output[x + 1] = palBase[p] | COLOR_OPAQUE; + p = (row >> 8) & 0xF; + if (p) + output[x + 2] = palBase[p] | COLOR_OPAQUE; + p = (row >> 12) & 0xF; + if (p) + output[x + 3] = palBase[p] | COLOR_OPAQUE; + p = (row >> 16) & 0xF; + if (p) + output[x + 4] = palBase[p] | COLOR_OPAQUE; + p = (row >> 20) & 0xF; + if (p) + output[x + 5] = palBase[p] | COLOR_OPAQUE; + p = (row >> 24) & 0xF; + if (p) + output[x + 6] = palBase[p] | COLOR_OPAQUE; + p = (row >> 28) & 0xF; + if (p) + output[x + 7] = palBase[p] | COLOR_OPAQUE; } else { uint8_t p; - p = (row >> 28) & 0xF; if (p) output[x ] = palBase[p] | COLOR_OPAQUE; - p = (row >> 24) & 0xF; if (p) output[x+1] = palBase[p] | COLOR_OPAQUE; - p = (row >> 20) & 0xF; if (p) output[x+2] = palBase[p] | COLOR_OPAQUE; - p = (row >> 16) & 0xF; if (p) output[x+3] = palBase[p] | COLOR_OPAQUE; - p = (row >> 12) & 0xF; if (p) output[x+4] = palBase[p] | COLOR_OPAQUE; - p = (row >> 8) & 0xF; if (p) output[x+5] = palBase[p] | COLOR_OPAQUE; - p = (row >> 4) & 0xF; if (p) output[x+6] = palBase[p] | COLOR_OPAQUE; - p = row & 0xF; if (p) output[x+7] = palBase[p] | COLOR_OPAQUE; + p = (row >> 28) & 0xF; + if (p) + output[x] = palBase[p] | COLOR_OPAQUE; + p = (row >> 24) & 0xF; + if (p) + output[x + 1] = palBase[p] | COLOR_OPAQUE; + p = (row >> 20) & 0xF; + if (p) + output[x + 2] = palBase[p] | COLOR_OPAQUE; + p = (row >> 16) & 0xF; + if (p) + output[x + 3] = palBase[p] | COLOR_OPAQUE; + p = (row >> 12) & 0xF; + if (p) + output[x + 4] = palBase[p] | COLOR_OPAQUE; + p = (row >> 8) & 0xF; + if (p) + output[x + 5] = palBase[p] | COLOR_OPAQUE; + p = (row >> 4) & 0xF; + if (p) + output[x + 6] = palBase[p] | COLOR_OPAQUE; + p = row & 0xF; + if (p) + output[x + 7] = palBase[p] | COLOR_OPAQUE; } x += 8; } @@ -307,11 +336,12 @@ static void RenderTextBG(int bgNum, uint16_t control, // right edge: leftover partial tile if (x < DISPLAY_WIDTH) { unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; + uint16_t entry = map[rowBase + (srcX >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) ty = 7 - ty; + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) + ty = 7 - ty; bool hflip = TILE_HFLIP(entry); uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); @@ -326,30 +356,23 @@ static void RenderTextBG(int bgNum, uint16_t control, } // same thing but with blend/window tracking baked in -static void RenderTextBGBlend(int bgNum, uint16_t control, - uint16_t hoffs, uint16_t voffs, - int lineNum, uint16_t *output, - uint8_t *layerIds, - unsigned int blendMode, - bool windowsEnabled, - uint16_t *winMask, - unsigned int bldcnt, - unsigned int eva, unsigned int evb, - unsigned int evy) +static void RenderTextBGBlend(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *output, uint8_t *layerIds, + unsigned int blendMode, bool windowsEnabled, uint16_t *winMask, unsigned int bldcnt, unsigned int eva, + unsigned int evb, unsigned int evy) { - unsigned int charBase = (control >> 2) & 3; + unsigned int charBase = (control >> 2) & 3; unsigned int screenBase = (control & BGCNT_SCREENBASE_MASK) >> 8; - unsigned int is8bpp = (control >> 7) & 1; + unsigned int is8bpp = (control >> 7) & 1; - unsigned int mapW = bgMapSizes[control >> 14][0]; - unsigned int mapPxW = mapW << 3; - unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; - unsigned int wMask = mapPxW - 1; - unsigned int hMask = mapPxH - 1; + unsigned int mapW = bgMapSizes[control >> 14][0]; + unsigned int mapPxW = mapW << 3; + unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; + unsigned int wMask = mapPxW - 1; + unsigned int hMask = mapPxH - 1; - uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); - uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); - uint16_t *pal = (uint16_t *)PLTT; + uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); + uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); + uint16_t *pal = (uint16_t *)PLTT; bool hasMosaic = control & BGCNT_MOSAIC; if (hasMosaic) @@ -358,29 +381,29 @@ static void RenderTextBGBlend(int bgNum, uint16_t control, hoffs &= 0x1FF; voffs &= 0x1FF; - unsigned int yy = (lineNum + voffs) & hMask; - unsigned int mapY = yy >> 3; - unsigned int tileY = yy & 7; + unsigned int yy = (lineNum + voffs) & hMask; + unsigned int mapY = yy >> 3; + unsigned int tileY = yy & 7; unsigned int rowBase = mapY * mapW; - bool bgIsTargetA = (blendMode != 0) && (bldcnt & (1 << bgNum)); - bool useWindows = windowsEnabled && (winMask != NULL); + bool bgIsTargetA = (blendMode != 0) && (bldcnt & (1 << bgNum)); + bool useWindows = windowsEnabled && (winMask != NULL); unsigned int winBgBit = 1 << bgNum; // slow path: 8bpp or mosaic if (hasMosaic || is8bpp) { for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - unsigned int xx = hasMosaic - ? (ApplyMosaicBGX(x) + hoffs) & wMask - : (x + hoffs) & wMask; + unsigned int xx = hasMosaic ? (ApplyMosaicBGX(x) + hoffs) & wMask : (x + hoffs) & wMask; uint16_t entry = map[rowBase + (xx >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); + unsigned int palNum = TILE_PALETTE(entry); unsigned int tx = xx & 7; unsigned int ty = tileY; - if (TILE_HFLIP(entry)) tx = 7 - tx; - if (TILE_VFLIP(entry)) ty = 7 - ty; + if (TILE_HFLIP(entry)) + tx = 7 - tx; + if (TILE_VFLIP(entry)) + ty = 7 - ty; uint8_t pixel; if (!is8bpp) { @@ -393,9 +416,7 @@ static void RenderTextBGBlend(int bgNum, uint16_t control, if (pixel == 0) continue; - uint16_t color = !is8bpp - ? pal[(palNum << 4) + pixel] | COLOR_OPAQUE - : pal[pixel] | COLOR_OPAQUE; + uint16_t color = !is8bpp ? pal[(palNum << 4) + pixel] | COLOR_OPAQUE : pal[pixel] | COLOR_OPAQUE; if (useWindows && !(winMask[x] & winBgBit)) continue; @@ -407,8 +428,12 @@ static void RenderTextBGBlend(int bgNum, uint16_t control, if (IsBlendTargetB(layerIds[x], bldcnt)) color = alphaBlendColor(src, output[x], eva, evb); break; - case 2: color = alphaBrightnessIncrease(src, evy); break; - case 3: color = alphaBrightnessDecrease(src, evy); break; + case 2: + color = alphaBrightnessIncrease(src, evy); + break; + case 3: + color = alphaBrightnessDecrease(src, evy); + break; } } @@ -423,31 +448,32 @@ static void RenderTextBGBlend(int bgNum, uint16_t control, // left edge partial tile { - unsigned int startX = hoffs & wMask; + unsigned int startX = hoffs & wMask; unsigned int startOff = startX & 7; if (startOff != 0) { uint16_t entry = map[rowBase + (startX >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) ty = 7 - ty; + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) + ty = 7 - ty; bool hflip = TILE_HFLIP(entry); - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); uint16_t *palBase = pal + (palNum << 4); unsigned int partial = 8 - startOff; - if (partial > DISPLAY_WIDTH) partial = DISPLAY_WIDTH; + if (partial > DISPLAY_WIDTH) + partial = DISPLAY_WIDTH; for (unsigned int t = 0; t < partial && x < DISPLAY_WIDTH; t++, x++) { unsigned int tx = startOff + t; - if (hflip) tx = 7 - tx; + if (hflip) + tx = 7 - tx; uint8_t pixel = (row >> (tx << 2)) & 0xF; if (pixel) - WriteBGPixelBlended(x, pixel, palBase, bgNum, output, - layerIds, blendMode, bgIsTargetA, - useWindows, winBgBit, winMask, + WriteBGPixelBlended(x, pixel, palBase, bgNum, output, layerIds, blendMode, bgIsTargetA, useWindows, winBgBit, winMask, bldcnt, eva, evb, evy); } } @@ -456,36 +482,45 @@ static void RenderTextBGBlend(int bgNum, uint16_t control, // middle: full tiles while (x + 8 <= DISPLAY_WIDTH) { unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; + uint16_t entry = map[rowBase + (srcX >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) ty = 7 - ty; + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) + ty = 7 - ty; - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); uint16_t *palBase = pal + (palNum << 4); - #define BLEND_PX(off, shift) do { \ - uint8_t p = (row >> (shift)) & 0xF; \ - if (p) WriteBGPixelBlended(x+(off), p, palBase, bgNum, \ - output, layerIds, blendMode, bgIsTargetA, \ - useWindows, winBgBit, winMask, \ - bldcnt, eva, evb, evy); \ - } while (0) +#define BLEND_PX(off, shift) \ + do { \ + uint8_t p = (row >> (shift)) & 0xF; \ + if (p) \ + WriteBGPixelBlended(x + (off), p, palBase, bgNum, output, layerIds, blendMode, bgIsTargetA, useWindows, winBgBit, winMask, \ + bldcnt, eva, evb, evy); \ + } while (0) if (!TILE_HFLIP(entry)) { - BLEND_PX(0, 0); BLEND_PX(1, 4); - BLEND_PX(2, 8); BLEND_PX(3, 12); - BLEND_PX(4, 16); BLEND_PX(5, 20); - BLEND_PX(6, 24); BLEND_PX(7, 28); + BLEND_PX(0, 0); + BLEND_PX(1, 4); + BLEND_PX(2, 8); + BLEND_PX(3, 12); + BLEND_PX(4, 16); + BLEND_PX(5, 20); + BLEND_PX(6, 24); + BLEND_PX(7, 28); } else { - BLEND_PX(0, 28); BLEND_PX(1, 24); - BLEND_PX(2, 20); BLEND_PX(3, 16); - BLEND_PX(4, 12); BLEND_PX(5, 8); - BLEND_PX(6, 4); BLEND_PX(7, 0); + BLEND_PX(0, 28); + BLEND_PX(1, 24); + BLEND_PX(2, 20); + BLEND_PX(3, 16); + BLEND_PX(4, 12); + BLEND_PX(5, 8); + BLEND_PX(6, 4); + BLEND_PX(7, 0); } - #undef BLEND_PX +#undef BLEND_PX x += 8; } @@ -493,36 +528,34 @@ static void RenderTextBGBlend(int bgNum, uint16_t control, // right edge partial tile if (x < DISPLAY_WIDTH) { unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; + uint16_t entry = map[rowBase + (srcX >> 3)]; unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) ty = 7 - ty; + unsigned int palNum = TILE_PALETTE(entry); + unsigned int ty = tileY; + if (TILE_VFLIP(entry)) + ty = 7 - ty; bool hflip = TILE_HFLIP(entry); - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); + uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); uint16_t *palBase = pal + (palNum << 4); for (unsigned int t = 0; x < DISPLAY_WIDTH; t++, x++) { unsigned int tx = hflip ? (7 - t) : t; uint8_t pixel = (row >> (tx << 2)) & 0xF; if (pixel) - WriteBGPixelBlended(x, pixel, palBase, bgNum, output, - layerIds, blendMode, bgIsTargetA, - useWindows, winBgBit, winMask, + WriteBGPixelBlended(x, pixel, palBase, bgNum, output, layerIds, blendMode, bgIsTargetA, useWindows, winBgBit, winMask, bldcnt, eva, evb, evy); } } } -static void RenderAffineBG(int bgNum, uint16_t control, - int lineNum, uint16_t *output) +static void RenderAffineBG(int bgNum, uint16_t control, int lineNum, uint16_t *output) { vBgCnt *bgcnt = (vBgCnt *)&control; - uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); - uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); - uint16_t *pal = (uint16_t *)PLTT; + uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); + uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); + uint16_t *pal = (uint16_t *)PLTT; if (control & BGCNT_MOSAIC) lineNum = ApplyMosaicBGY(lineNum); @@ -535,11 +568,17 @@ static void RenderAffineBG(int bgNum, uint16_t control, // always square: 128/256/512/1024 int size = 128; switch (bgcnt->screenSize) { - case 1: size = 256; break; - case 2: size = 512; break; - case 3: size = 1024; break; + case 1: + size = 256; + break; + case 2: + size = 512; + break; + case 3: + size = 1024; + break; } - int mask = size - 1; + int mask = size - 1; int yshift = ((control >> 14) & 3) + 4; // sign-extend 28-bit reference point, advance by scanline @@ -589,21 +628,15 @@ static void RenderAffineBG(int bgNum, uint16_t control, } // same deal with blend/window support -static void RenderAffineBGBlend(int bgNum, uint16_t control, - int lineNum, uint16_t *output, - uint8_t *layerIds, - unsigned int blendMode, - bool windowsEnabled, - uint16_t *winMask, - unsigned int bldcnt, - unsigned int eva, unsigned int evb, +static void RenderAffineBGBlend(int bgNum, uint16_t control, int lineNum, uint16_t *output, uint8_t *layerIds, unsigned int blendMode, + bool windowsEnabled, uint16_t *winMask, unsigned int bldcnt, unsigned int eva, unsigned int evb, unsigned int evy) { vBgCnt *bgcnt = (vBgCnt *)&control; - uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); - uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); - uint16_t *pal = (uint16_t *)PLTT; + uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); + uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); + uint16_t *pal = (uint16_t *)PLTT; if (control & BGCNT_MOSAIC) lineNum = ApplyMosaicBGY(lineNum); @@ -615,11 +648,17 @@ static void RenderAffineBGBlend(int bgNum, uint16_t control, int size = 128; switch (bgcnt->screenSize) { - case 1: size = 256; break; - case 2: size = 512; break; - case 3: size = 1024; break; + case 1: + size = 256; + break; + case 2: + size = 512; + break; + case 3: + size = 1024; + break; } - int mask = size - 1; + int mask = size - 1; int yshift = ((control >> 14) & 3) + 4; s32 refX = GetBgRefX(bgNum); @@ -675,8 +714,12 @@ static void RenderAffineBGBlend(int bgNum, uint16_t control, if (IsBlendTargetB(layerIds[x], bldcnt)) color = alphaBlendColor(src, output[x], eva, evb); break; - case 2: color = alphaBrightnessIncrease(src, evy); break; - case 3: color = alphaBrightnessDecrease(src, evy); break; + case 2: + color = alphaBrightnessIncrease(src, evy); + break; + case 3: + color = alphaBrightnessDecrease(src, evy); + break; } } @@ -697,7 +740,7 @@ typedef struct { } ActiveSprite; static ActiveSprite sActiveSprites[4][MAX_SPRITES_PER_PRIORITY]; -static int sActiveSpriteCount[4]; +static int sActiveSpriteCount[4]; static void PrefilterSprites(uint16_t vcount) { @@ -713,14 +756,14 @@ static void PrefilterSprites(uint16_t vcount) for (int i = OAM_ENTRY_COUNT - 1; i >= 0; i--) { OamData *oam = &((OamData *)OAM)[i]; - bool isAffine = oam->split.affineMode & 1; + bool isAffine = oam->split.affineMode & 1; bool isDisabled = (oam->split.affineMode >> 1) & 1; if (!isAffine && isDisabled) continue; s32 idx = (oam->split.shape << 2) | oam->split.size; - unsigned int width = gOamShapesSizes[idx][0]; + unsigned int width = gOamShapesSizes[idx][0]; unsigned int height = gOamShapesSizes[idx][1]; int halfW = width / 2; int halfH = height / 2; @@ -728,8 +771,10 @@ static void PrefilterSprites(uint16_t vcount) int32_t sx = oam->split.x; int32_t sy = oam->split.y; #if !EXTENDED_OAM - if (sx >= DISPLAY_WIDTH) sx -= 512; - if (sy >= DISPLAY_HEIGHT) sy -= 256; + if (sx >= DISPLAY_WIDTH) + sx -= 512; + if (sy >= DISPLAY_HEIGHT) + sy -= 256; #endif // double-size affine sprites have 2x bounding box @@ -751,16 +796,12 @@ static void PrefilterSprites(uint16_t vcount) } } -static void DrawSpritesAtPriority(int priority, uint16_t vcount, - uint16_t *output, uint8_t *layerIds, - bool windowsEnabled, uint16_t *winMask, - unsigned int blendMode, bool objWinOnly, - unsigned int bldcnt, - unsigned int eva, unsigned int evb, - unsigned int evy) +static void DrawSpritesAtPriority(int priority, uint16_t vcount, uint16_t *output, uint8_t *layerIds, bool windowsEnabled, + uint16_t *winMask, unsigned int blendMode, bool objWinOnly, unsigned int bldcnt, unsigned int eva, + unsigned int evb, unsigned int evy) { - uint8_t *tiledata = (uint8_t *)OBJ_VRAM0; - uint16_t *sprpal = (uint16_t *)PLTT + (0x200 / 2); + uint8_t *tiledata = (uint8_t *)OBJ_VRAM0; + uint16_t *sprpal = (uint16_t *)PLTT + (0x200 / 2); int16_t matrix[2][2]; // only 1-D tile mapping supported @@ -771,11 +812,11 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, int i = sActiveSprites[priority][s].oamIndex; OamData *oam = &((OamData *)OAM)[i]; - bool isAffine = oam->split.affineMode & 1; + bool isAffine = oam->split.affineMode & 1; bool doubleSize = (oam->split.affineMode >> 1) & 1; s32 idx = (oam->split.shape << 2) | oam->split.size; - unsigned int width = gOamShapesSizes[idx][0]; + unsigned int width = gOamShapesSizes[idx][0]; unsigned int height = gOamShapesSizes[idx][1]; int halfW = width / 2; int halfH = height / 2; @@ -783,8 +824,10 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, int32_t x = oam->split.x; int32_t y = oam->split.y; #if !EXTENDED_OAM - if (x >= DISPLAY_WIDTH) x -= 512; - if (y >= DISPLAY_HEIGHT) y -= 256; + if (x >= DISPLAY_WIDTH) + x -= 512; + if (y >= DISPLAY_HEIGHT) + y -= 256; #endif if (isAffine && doubleSize) { halfW *= 2; @@ -792,12 +835,14 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, } bool isSemiTransparent = (oam->split.objMode == 1); - bool isObjWin = (oam->split.objMode == 2); + bool isObjWin = (oam->split.objMode == 2); - if (objWinOnly && !isObjWin) continue; - if (!objWinOnly && isObjWin) continue; + if (objWinOnly && !isObjWin) + continue; + if (!objWinOnly && isObjWin) + continue; - int rectWidth = width; + int rectWidth = width; int rectHeight = height; if (isAffine) { @@ -811,7 +856,7 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, matrix[1][0] = m2->all.affineParam; matrix[1][1] = m3->all.affineParam; if (doubleSize) { - rectWidth *= 2; + rectWidth *= 2; rectHeight *= 2; } } else { @@ -824,30 +869,31 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, x += halfW; y += halfH; - int localY = (oam->split.mosaic == 1) - ? ApplyMosaicSprY(vcount) - y - : vcount - y; + int localY = (oam->split.mosaic == 1) ? ApplyMosaicSprY(vcount) - y : vcount - y; bool flipX = !isAffine && ((oam->split.matrixNum >> 3) & 1); bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); bool is8bpp = oam->split.bpp & 1; int startLX = -halfW; - int endLX = halfW; - if (startLX + x < 0) startLX = -x; - if (endLX + x >= DISPLAY_WIDTH) endLX = DISPLAY_WIDTH - 1 - x; + int endLX = halfW; + if (startLX + x < 0) + startLX = -x; + if (endLX + x >= DISPLAY_WIDTH) + endLX = DISPLAY_WIDTH - 1 - x; // fast path: non-affine 4bpp, no mosaic -- batched tile row reads if (!isAffine && !is8bpp && !oam->split.mosaic) { int texY = localY + halfH; - if (flipY) texY = height - texY - 1; + if (flipY) + texY = height - texY - 1; if (texY < 0 || texY >= (int)height) continue; - int tileRowY = texY & 7; - int blockY = texY >> 3; + int tileRowY = texY & 7; + int blockY = texY >> 3; int tilesPerRow = (REG_DISPCNT & 0x40) ? ((int)width >> 3) : 16; - int tileBase = blockY * tilesPerRow + oam->split.tileNum; - int rowByteOff = tileRowY << 2; + int tileBase = blockY * tilesPerRow + oam->split.tileNum; + int rowByteOff = tileRowY << 2; uint16_t *pixpal = sprpal + (oam->split.paletteNum << 4); int lx = startLX; @@ -860,22 +906,24 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, continue; } - int blockX = texX >> 3; + int blockX = texX >> 3; int tileXStart = texX & 7; - uint32_t rowData = *(uint32_t *)(tiledata - + ((tileBase + blockX) << 5) + rowByteOff); + uint32_t rowData = *(uint32_t *)(tiledata + ((tileBase + blockX) << 5) + rowByteOff); int pixelsInTile = !flipX ? (8 - tileXStart) : (tileXStart + 1); int remain = endLX - lx + 1; - if (pixelsInTile > remain) pixelsInTile = remain; + if (pixelsInTile > remain) + pixelsInTile = remain; if (!flipX) { int texRemain = (int)width - texX; - if (pixelsInTile > texRemain) pixelsInTile = texRemain; + if (pixelsInTile > texRemain) + pixelsInTile = texRemain; } else { int texRemain = texX + 1; - if (pixelsInTile > texRemain) pixelsInTile = texRemain; + if (pixelsInTile > texRemain) + pixelsInTile = texRemain; } for (int p = 0; p < pixelsInTile; p++, lx++) { @@ -895,9 +943,7 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, } if (layerIds && blendMode != 0) - color = BlendSpritePixel(color, gx, output, layerIds, - isSemiTransparent, blendMode, - bldcnt, windowsEnabled, winMask, + color = BlendSpritePixel(color, gx, output, layerIds, isSemiTransparent, blendMode, bldcnt, windowsEnabled, winMask, eva, evb, evy); if (windowsEnabled && winMask && !(winMask[gx] & WINMASK_OBJ)) @@ -922,8 +968,10 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, lmx = ApplyMosaicSprX(gx) - x; texX = lmx + halfW; texY = localY + halfH; - if (flipX) texX = width - texX - 1; - if (flipY) texY = height - texY - 1; + if (flipX) + texX = width - texX - 1; + if (flipY) + texY = height - texY - 1; } else { int lmx = localX; int lmy = localY; @@ -932,17 +980,17 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, lmy = ApplyMosaicSprY(vcount) - y; } // apply 2x2 affine matrix (8.8 fixed point) - texX = ((matrix[0][0] * lmx + matrix[0][1] * lmy) >> 8) + (width / 2); + texX = ((matrix[0][0] * lmx + matrix[0][1] * lmy) >> 8) + (width / 2); texY = ((matrix[1][0] * lmx + matrix[1][1] * lmy) >> 8) + (height / 2); } if (texX < 0 || texY < 0 || texX >= (int)width || texY >= (int)height) continue; - int tileX = texX & 7; - int tileY = texY & 7; - int blockX = texX >> 3; - int blockY = texY >> 3; + int tileX = texX & 7; + int tileY = texY & 7; + int blockX = texX >> 3; + int blockY = texY >> 3; int blockOffset = blockY * (REG_DISPCNT & 0x40 ? ((int)width >> 3) : 16) + blockX; uint16_t pixel = 0; @@ -951,8 +999,10 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, if (!is8bpp) { int tdi = ((blockOffset + oam->split.tileNum) << 5) + (tileY << 2) + (tileX >> 1); pixel = tiledata[tdi]; - if (tileX & 1) pixel >>= 4; - else pixel &= 0xF; + if (tileX & 1) + pixel >>= 4; + else + pixel &= 0xF; pixpal = sprpal + (oam->split.paletteNum << 4); } else { pixel = tiledata[((blockOffset * 2 + oam->split.tileNum) << 5) + (tileY << 3) + tileX]; @@ -971,10 +1021,8 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, } if (layerIds && blendMode != 0) - color = BlendSpritePixel(color, gx, output, layerIds, - isSemiTransparent, blendMode, - bldcnt, windowsEnabled, winMask, - eva, evb, evy); + color = BlendSpritePixel(color, gx, output, layerIds, isSemiTransparent, blendMode, bldcnt, windowsEnabled, winMask, eva, + evb, evy); if (windowsEnabled && winMask && !(winMask[gx] & WINMASK_OBJ)) continue; @@ -988,21 +1036,21 @@ static void DrawSpritesAtPriority(int priority, uint16_t vcount, static void DrawScanline(uint16_t *pixels, uint16_t vcount) { - unsigned int mode = REG_DISPCNT & 3; - unsigned int numBGs = (mode == 0) ? 4 : 3; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; + unsigned int mode = REG_DISPCNT & 3; + unsigned int numBGs = (mode == 0) ? 4 : 3; + unsigned int blendMode = (REG_BLDCNT >> 6) & 3; unsigned int enabledBgs = (REG_DISPCNT >> 8) & 0xF; // sort bgs by priority uint16_t bgcnts[4]; - char bgPriority[4]; - char bgsByPri[4][4]; - char bgsByPriCount[4] = {0, 0, 0, 0}; + char bgPriority[4]; + char bgsByPri[4][4]; + char bgsByPriCount[4] = { 0, 0, 0, 0 }; for (int bg = 0; bg < (int)numBGs; bg++) { uint16_t cnt = *(uint16_t *)(REG_ADDR_BG0CNT + bg * 2); - bgcnts[bg] = cnt; - uint16_t pri = cnt & 3; + bgcnts[bg] = cnt; + uint16_t pri = cnt & 3; bgPriority[bg] = pri; bgsByPri[pri][bgsByPriCount[pri]] = bg; bgsByPriCount[pri]++; @@ -1016,10 +1064,10 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) static uint16_t winMask[DISPLAY_WIDTH]; if (REG_DISPCNT & DISPCNT_WIN0_ON) { - win0Bot = WIN_GET_HIGHER(REG_WIN0V); - win0Top = WIN_GET_LOWER(REG_WIN0V); + win0Bot = WIN_GET_HIGHER(REG_WIN0V); + win0Top = WIN_GET_LOWER(REG_WIN0V); win0Right = WIN_GET_HIGHER(REG_WIN0H); - win0Left = WIN_GET_LOWER(REG_WIN0H); + win0Left = WIN_GET_LOWER(REG_WIN0H); if (win0Top > win0Bot) win0Active = (vcount >= win0Top || vcount < win0Bot); else @@ -1027,10 +1075,10 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) windowsEnabled = true; } if (REG_DISPCNT & DISPCNT_WIN1_ON) { - win1Bot = WIN_GET_HIGHER(REG_WIN1V); - win1Top = WIN_GET_LOWER(REG_WIN1V); + win1Bot = WIN_GET_HIGHER(REG_WIN1V); + win1Top = WIN_GET_LOWER(REG_WIN1V); win1Right = WIN_GET_HIGHER(REG_WIN1H); - win1Left = WIN_GET_LOWER(REG_WIN1H); + win1Left = WIN_GET_LOWER(REG_WIN1H); if (win1Top > win1Bot) win1Active = (vcount >= win1Top || vcount < win1Bot); else @@ -1057,14 +1105,14 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) // layerIds tracks who wrote each pixel so alpha blend can find target-b static uint8_t layerIds[DISPLAY_WIDTH]; bool needLayerIds = (blendMode != 0 || windowsEnabled); - uint8_t *lids = needLayerIds ? layerIds : NULL; + uint8_t *lids = needLayerIds ? layerIds : NULL; uint16_t *wmask = windowsEnabled ? winMask : NULL; if (needLayerIds) memset(layerIds, LAYER_BACKDROP, DISPLAY_WIDTH); // grab blend regs once per scanline - unsigned int bldcnt = REG_BLDCNT; + unsigned int bldcnt = REG_BLDCNT; unsigned int bld_eva = REG_BLDALPHA & 0x1F; unsigned int bld_evb = (REG_BLDALPHA >> 8) & 0x1F; unsigned int bld_evy = REG_BLDY & 0x1F; @@ -1072,10 +1120,8 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) // obj window pass -- these sprites modify the window mask, not the framebuffer if (windowsEnabled && (REG_DISPCNT & DISPCNT_OBJWIN_ON) && (REG_DISPCNT & DISPCNT_OBJ_ON)) { for (int pri = 0; pri < 4; pri++) - DrawSpritesAtPriority(pri, vcount, pixels, lids, - windowsEnabled, wmask, blendMode, - /*objWinOnly=*/true, - bldcnt, bld_eva, bld_evb, bld_evy); + DrawSpritesAtPriority(pri, vcount, pixels, lids, windowsEnabled, wmask, blendMode, + /*objWinOnly=*/true, bldcnt, bld_eva, bld_evb, bld_evy); } // back-to-front: priority 3 first, 0 last (0 is topmost) @@ -1088,54 +1134,40 @@ static void DrawScanline(uint16_t *pixels, uint16_t vcount) if (!needLayerIds) { switch (mode) { case 0: - RenderTextBG(bg, bgcnts[bg], - *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), - *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), - vcount, pixels); + RenderTextBG(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), + vcount, pixels); break; case 1: if (bg == 2) RenderAffineBG(bg, bgcnts[bg], vcount, pixels); else - RenderTextBG(bg, bgcnts[bg], - *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), - *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), - vcount, pixels); + RenderTextBG(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), + vcount, pixels); break; } } else { switch (mode) { case 0: - RenderTextBGBlend(bg, bgcnts[bg], - *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), - *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), - vcount, pixels, lids, blendMode, - windowsEnabled, wmask, - bldcnt, bld_eva, bld_evb, bld_evy); + RenderTextBGBlend(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), + *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), vcount, pixels, lids, blendMode, windowsEnabled, wmask, + bldcnt, bld_eva, bld_evb, bld_evy); break; case 1: if (bg == 2) - RenderAffineBGBlend(bg, bgcnts[bg], - vcount, pixels, lids, blendMode, - windowsEnabled, wmask, - bldcnt, bld_eva, bld_evb, bld_evy); + RenderAffineBGBlend(bg, bgcnts[bg], vcount, pixels, lids, blendMode, windowsEnabled, wmask, bldcnt, bld_eva, + bld_evb, bld_evy); else - RenderTextBGBlend(bg, bgcnts[bg], - *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), - *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), - vcount, pixels, lids, blendMode, - windowsEnabled, wmask, - bldcnt, bld_eva, bld_evb, bld_evy); + RenderTextBGBlend(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), + *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), vcount, pixels, lids, blendMode, windowsEnabled, + wmask, bldcnt, bld_eva, bld_evb, bld_evy); break; } } } if (REG_DISPCNT & DISPCNT_OBJ_ON) - DrawSpritesAtPriority(pri, vcount, pixels, lids, - windowsEnabled, wmask, blendMode, - /*objWinOnly=*/false, - bldcnt, bld_eva, bld_evb, bld_evy); + DrawSpritesAtPriority(pri, vcount, pixels, lids, windowsEnabled, wmask, blendMode, + /*objWinOnly=*/false, bldcnt, bld_eva, bld_evb, bld_evy); } } @@ -1164,4 +1196,4 @@ void DrawFrame_Fast(uint16_t *pixels) } } -#endif +#endif From 6b3bca250e892c61d0c52ac4e35b9b1d8211214f Mon Sep 17 00:00:00 2001 From: kikugrave Date: Sun, 15 Feb 2026 11:17:47 -0800 Subject: [PATCH 04/51] Fix lint 3 --- src/lib/m4a/m4a.c | 4 ++-- src/platform/pret_sdl/sdl2.c | 4 ++-- src/platform/shared/rendering/sw_renderer_fast.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/m4a/m4a.c b/src/lib/m4a/m4a.c index 108dae8978..329741bf3c 100644 --- a/src/lib/m4a/m4a.c +++ b/src/lib/m4a/m4a.c @@ -1369,7 +1369,7 @@ void MP2K_event_memacc(struct MP2KPlayerState *mplayInfo, struct MP2KTrack *trac return; } -cond_true: { +cond_true : { { void (*func)(struct MP2KPlayerState *, struct MP2KTrack *) = *(&gMPlayJumpTable[1]); func(mplayInfo, track); @@ -1377,7 +1377,7 @@ cond_true: { return; } -cond_false: { +cond_false : { #ifdef __mips__ // Align to 4 bytes (mPtr adds .balign 4 on MIPS) u8 *ptrStart = (u8 *)(((uintptr_t)track->cmdPtr + 3) & ~(uintptr_t)3); diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 044d2ab4cf..d253bd4186 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -114,7 +114,7 @@ double accumulator = 0.0; static FILE *sSaveFile = NULL; extern void AgbMain(void); -void DoSoftReset(void) { }; +void DoSoftReset(void) {}; void ProcessSDLEvents(void); void VDraw(SDL_Texture *texture); @@ -1942,7 +1942,7 @@ void VDraw(SDL_Texture *texture) { #if RENDERER == RENDERER_SOFTWARE_FAST { - extern void DrawFrame_Fast(uint16_t *pixels); + extern void DrawFrame_Fast(uint16_t * pixels); DrawFrame_Fast(gameImage); } #else diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c index 484ddf042c..9a1283d2e0 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -53,7 +53,7 @@ extern const u8 gOamShapesSizes[12][2]; #define ApplyMosaicSprY(y) ((y) - ((y) % (MOSAIC_SPR_Y + 1))) // tilemap entry fields -#define TILE_NUM(e) ((e) & 0x3FF) +#define TILE_NUM(e) ((e)&0x3FF) #define TILE_PALETTE(e) (((e) >> 12) & 0xF) #define TILE_HFLIP(e) ((e) & (1 << 10)) #define TILE_VFLIP(e) ((e) & (1 << 11)) From efeebe0df70196a3127e63a5db3e52a7b84031d7 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 16 Feb 2026 00:40:34 +0000 Subject: [PATCH 05/51] fixes, add ps2 build --- .gitignore | 1 + Makefile | 32 +++- asm/macros/portable.inc | 3 +- config.mk | 1 + include/gba/defines.h | 2 +- include/gba/types.h | 4 + ps2/ntsc/SYSTEM.CNF | 3 + src/lib/m4a/m4a.c | 6 - src/platform/pret_sdl/sdl2.c | 190 ++++++++++++++------ src/platform/shared/audio/m4a_sound_mixer.c | 17 +- 10 files changed, 179 insertions(+), 80 deletions(-) create mode 100644 ps2/ntsc/SYSTEM.CNF diff --git a/.gitignore b/.gitignore index 8d9dfac692..cf418a7462 100644 --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,7 @@ libagbsyscall/*.s *.exe *.dll *.sdl +*.iso # PSP build outputs EBOOT.PBP diff --git a/Makefile b/Makefile index 16f0014742..c7979cd8f8 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,8 @@ else ifeq ($(PLATFORM),psp) PSPSDK := $(PSPDEV)/psp/sdk export PATH := $(PSPDEV)/bin:$(PATH) PREFIX := psp- +else ifeq ($(PLATFORM),ps2) + PREFIX := mips64r5900el-ps2-elf- else # Native ifneq ($(PLATFORM),sdl) @@ -130,6 +132,10 @@ else ifeq ($(PLATFORM),psp) ROM := EBOOT.PBP ELF := $(BUILD_NAME).psp.elf MAP := $(BUILD_NAME).psp.map +else ifeq ($(PLATFORM),ps2) +ROM := $(BUILD_NAME).$(PLATFORM).iso +ELF := $(ROM:.iso=.elf) +MAP := $(ROM:.iso=.map) else ROM := $(BUILD_NAME).$(PLATFORM).exe ELF := $(ROM:.exe=.elf) @@ -169,6 +175,8 @@ else ifeq ($(PLATFORM),sdl) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") else ifeq ($(PLATFORM),psp) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") +else ifeq ($(PLATFORM),ps2) +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") else ifeq ($(PLATFORM),sdl_win32) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") else ifeq ($(PLATFORM),win32) @@ -240,6 +248,9 @@ else else ifeq ($(PLATFORM),psp) CC1FLAGS += -G0 CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600 + else ifeq ($(PLATFORM),ps2) + CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math + CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(PS2SDK)/ports/bin/sdl2-config --cflags) else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) else ifeq ($(PLATFORM),win32) @@ -266,6 +277,8 @@ else CPP := $(CC1) -E else ifeq ($(PLATFORM), psp) CPP := $(CC1) -E + else ifeq ($(PLATFORM), ps2) + ASFLAGS += -msingle-float endif # Allow file input through stdin on modern GCC and set it to "compile only" CC1FLAGS += -x c -S @@ -278,6 +291,8 @@ else ifeq ($(PLATFORM),psp) # -O3 for PSP (Allegrex MIPS, small D-cache) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer + else ifeq ($(PLATFORM),ps2) + CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else CC1FLAGS += -O2 endif @@ -322,6 +337,8 @@ else ifeq ($(PLATFORM),sdl) # PSP else ifeq ($(PLATFORM),psp) MAP_FLAG := -Xlinker -Map= +else ifeq ($(PLATFORM),ps2) + MAP_FLAG := -Xlinker -Map= # Win32 else MAP_FLAG := -Xlinker -Map= @@ -334,6 +351,8 @@ else ifeq ($(PLATFORM),sdl) LIBS := $(shell sdl2-config --cflags --libs) else ifeq ($(PLATFORM),psp) LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128 +else ifeq ($(PLATFORM),ps2) + LIBS := -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),sdl_win32) LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS) else ifeq ($(PLATFORM), win32) @@ -343,7 +362,7 @@ endif #### MAIN TARGETS #### # these commands will run regardless of deps being completed -.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall +.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall ps2 # Ensure required directories exist $(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR)) @@ -424,7 +443,7 @@ clean-tools: tidy: $(RM) -r build/* $(RM) SDL2.dll - $(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba + $(RM) $(BUILD_NAME)*.exe $(BUILD_NAME)*.elf $(BUILD_NAME)*.map $(BUILD_NAME)*.sdl $(BUILD_NAME)*.gba $(BUILD_NAME)*.iso $(RM) EBOOT.PBP PARAM.SFO usa_beta: ; @$(MAKE) GAME_REGION=USA GAME_VARIANT=BETA @@ -439,6 +458,8 @@ sdl: ; @$(MAKE) PLATFORM=sdl psp: ; @$(MAKE) PLATFORM=psp +ps2: ; @$(MAKE) PLATFORM=ps2 + tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 sdl_win32: @@ -489,7 +510,7 @@ data/mb_chao_garden_japan.gba.lz: data/mb_chao_garden_japan.gba %.bin: %.aif ; $(AIF) $< $@ -$(ELF): $(OBJS) libagbsyscall +$(ELF): $(OBJS) ifeq ($(PLATFORM),gba) @echo "$(LD) -T $(LDSCRIPT) $(MAP_FLAG) $(MAP) -o $@" @$(CPP) -P $(CPPFLAGS) $(LDSCRIPT) > $(OBJ_DIR)/$(LDSCRIPT) @@ -512,6 +533,11 @@ else ifeq ($(PLATFORM),psp) psp-strip $< -o $(BUILD_NAME).psp_strip.elf pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL -rm -f $(BUILD_NAME).psp_strip.elf +else ifeq ($(PLATFORM),ps2) + @echo Creating $(ROM) from $(ELF) + @cp -r ps2/ntsc $(OBJ_DIR)/iso + @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) + @mkisofs -o $(ROM) $(OBJ_DIR)/iso/ else $(OBJCOPY) -O pei-x86-64 $< $@ endif diff --git a/asm/macros/portable.inc b/asm/macros/portable.inc index e3f80ed9d6..fd66638b8a 100644 --- a/asm/macros/portable.inc +++ b/asm/macros/portable.inc @@ -11,8 +11,7 @@ #if defined(__aarch64__) || defined(__x86_64__) .quad \value #elif defined(__mips__) - .balign 4 - .int \value + .4byte \value #else .int \value #endif diff --git a/config.mk b/config.mk index 5f687443a8..15affde184 100644 --- a/config.mk +++ b/config.mk @@ -63,6 +63,7 @@ MAKER_CODE := 78 BUILD_NAME := sa2 TITLE := SONICADVANC2 GAME_CODE := A2N +PS2_GAME_CODE := SLUS_054.02 # Revision diff --git a/include/gba/defines.h b/include/gba/defines.h index 1902845103..6b9d09afcf 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -39,7 +39,7 @@ #define OAM_ENTRY_COUNT 128 #if PORTABLE // NOTE: Used in gba/types.h, so they have to be defined before the #include -#ifdef __PSP__ +#if defined(__PSP__) // PSP: Use GBA-native resolution, SDL scales to 480x272 #define DISPLAY_WIDTH 240 #define DISPLAY_HEIGHT 160 diff --git a/include/gba/types.h b/include/gba/types.h index 72e721ad7b..fa32343578 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -20,6 +20,9 @@ typedef struct __attribute__((packed)) name struct_body name; #endif +#ifdef __PS2__ +#include +#else typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; @@ -28,6 +31,7 @@ typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; +#endif #if (GAME == GAME_SA1) typedef u8 MetatileIndexType; diff --git a/ps2/ntsc/SYSTEM.CNF b/ps2/ntsc/SYSTEM.CNF new file mode 100644 index 0000000000..9c440527d2 --- /dev/null +++ b/ps2/ntsc/SYSTEM.CNF @@ -0,0 +1,3 @@ +BOOT2 = cdrom0:\SLUS_054.02;1 +VER = 1.00 +VMODE = NTSC \ No newline at end of file diff --git a/src/lib/m4a/m4a.c b/src/lib/m4a/m4a.c index 329741bf3c..7b90fe3a99 100644 --- a/src/lib/m4a/m4a.c +++ b/src/lib/m4a/m4a.c @@ -1378,13 +1378,7 @@ cond_true : { } cond_false : { -#ifdef __mips__ - // Align to 4 bytes (mPtr adds .balign 4 on MIPS) - u8 *ptrStart = (u8 *)(((uintptr_t)track->cmdPtr + 3) & ~(uintptr_t)3); - track->cmdPtr = ptrStart + 4; -#else track->cmdPtr += 4; -#endif } } diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index d253bd4186..1a77546ea0 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -98,8 +98,11 @@ bool paused = false; bool stepOneFrame = false; bool headless = false; +#if defined(__PSP__) || defined(__PS2__) +static SDL_Joystick *joystick = NULL; +#endif + #ifdef __PSP__ -static SDL_Joystick *pspJoystick = NULL; #define PSP_SCREEN_W 480 #define PSP_SCREEN_H 272 static SDL_Rect pspDestRect; @@ -133,12 +136,57 @@ void *Platform_malloc(size_t numBytes) { return HeapAlloc(GetProcessHeap(), HEAP void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #endif +#ifdef __PS2__ +// TODO: clean these for what is needed +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void reset_IOP() +{ + SifInitRpc(0); + while (!SifIopReset(NULL, 0)) { } // Comment this line if you want to "debug" through ps2link + while (!SifIopSync()) { } +} + +static void prepare_IOP() +{ + reset_IOP(); + SifInitRpc(0); + sbv_patch_enable_lmb(); + sbv_patch_disable_prefix_check(); +} + +static void init_drivers() +{ + init_only_boot_ps2_filesystem_driver(); + init_memcard_driver(true); +} + +static void deinit_drivers() +{ + deinit_memcard_driver(true); + deinit_only_boot_ps2_filesystem_driver(); +} +#endif + int main(int argc, char **argv) { #ifdef __PSP__ setupPspCallbacks(); #endif +#ifdef __PS2__ + prepare_IOP(); +#endif + const char *headlessEnv = getenv("HEADLESS"); if (headlessEnv && strcmp(headlessEnv, "true") == 0) { @@ -161,7 +209,9 @@ int main(int argc, char **argv) freopen("CON", "w", stdout); #endif +#ifndef __PS2__ ReadSaveFile("sa2.sav"); +#endif // Prevent the multiplayer screen from being drawn ( see core.c:EngineInit() ) REG_RCNT = 0x8000; @@ -179,9 +229,9 @@ int main(int argc, char **argv) return 1; } -#ifdef __PSP__ +#if defined(__PSP__) || defined(__PS2__) if (SDL_NumJoysticks() > 0) { - pspJoystick = SDL_JoystickOpen(0); + joystick = SDL_JoystickOpen(0); } #endif @@ -193,6 +243,8 @@ int main(int argc, char **argv) #ifdef __PSP__ sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 272, SDL_WINDOW_SHOWN); +#elif defined(__PS2__) + sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 448, SDL_WINDOW_SHOWN); #else sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); @@ -224,6 +276,8 @@ int main(int argc, char **argv) sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); if (sdlRenderer == NULL) sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); +#elif defined(__PS2__) + sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); #else sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); #endif @@ -269,6 +323,12 @@ int main(int argc, char **argv) } #endif +#ifdef __PS2__ + SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); + // For some reason we are WAY blown out on the PS2 + SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); +#endif + #if ENABLE_AUDIO SDL_AudioSpec want; @@ -320,13 +380,15 @@ void VBlankIntrWait(void) bool frameAvailable = TRUE; bool frameDrawn = false; -#ifdef __PSP__ - static int psp_frames_skipped = 0; -#define PSP_MAX_FRAME_SKIP 2 +#if defined(__PSP__) || defined(__PS2__) + static int frames_skipped = 0; +#define MAX_FRAME_SKIP 2 #endif while (isRunning) { +#if !defined(__PS2__) && !defined(__PSP__) ProcessSDLEvents(); +#endif if (!paused || stepOneFrame) { double dt = fixedTimestep / timeScale; // TODO: Fix speedup @@ -354,17 +416,17 @@ void VBlankIntrWait(void) while (accumulator >= dt) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); if (frameAvailable) { -#ifdef __PSP__ +#if defined(__PSP__) || defined(__PS2__) // frame skip: let game logic catch up when behind - if (accumulator >= dt * 2.0 && psp_frames_skipped < PSP_MAX_FRAME_SKIP) { - psp_frames_skipped++; + if (accumulator >= dt * 2.0 && frames_skipped < MAX_FRAME_SKIP) { + frames_skipped++; frameAvailable = FALSE; HANDLE_VBLANK_INTRS(); accumulator -= dt; newFrameRequested = TRUE; return; } - psp_frames_skipped = 0; + frames_skipped = 0; #endif VDraw(sdlTexture); frameAvailable = FALSE; @@ -395,6 +457,10 @@ void VBlankIntrWait(void) SDL_Delay(1); } #else +#ifdef __PS2__ + // Allow audio to play + DelayThread(800); +#endif SDL_RenderClear(sdlRenderer); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); @@ -491,52 +557,68 @@ static void CloseSaveFile() static u16 keys; -#ifdef __PSP__ -#define PSP_BTN_TRIANGLE 0 -#define PSP_BTN_CIRCLE 1 -#define PSP_BTN_CROSS 2 -#define PSP_BTN_SQUARE 3 -#define PSP_BTN_LTRIGGER 4 -#define PSP_BTN_RTRIGGER 5 -#define PSP_BTN_DOWN 6 -#define PSP_BTN_LEFT 7 -#define PSP_BTN_UP 8 -#define PSP_BTN_RIGHT 9 -#define PSP_BTN_SELECT 10 -#define PSP_BTN_START 11 - -static u16 PollPSPButtons(void) +#if defined(__PSP__) || defined(__PS2__) + +#ifdef __PS2__ +#define BTN_TRIANGLE 12 +#define BTN_CIRCLE 13 +#define BTN_CROSS 14 +#define BTN_SQUARE 15 +#define BTN_LTRIGGER 10 +#define BTN_RTRIGGER 11 +#define BTN_DOWN 6 +#define BTN_LEFT 7 +#define BTN_UP 4 +#define BTN_RIGHT 5 +#define BTN_SELECT 0 +#define BTN_START 3 +#else +#define BTN_TRIANGLE 0 +#define BTN_CIRCLE 1 +#define BTN_CROSS 2 +#define BTN_SQUARE 3 +#define BTN_LTRIGGER 4 +#define BTN_RTRIGGER 5 +#define BTN_DOWN 6 +#define BTN_LEFT 7 +#define BTN_UP 8 +#define BTN_RIGHT 9 +#define BTN_SELECT 10 +#define BTN_START 11 +#endif + +static u16 PollJoystickButtons(void) { - u16 pspKeys = 0; - if (pspJoystick == NULL) - return pspKeys; + u16 keys = 0; + if (joystick == NULL) + return keys; SDL_JoystickUpdate(); - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_CROSS)) - pspKeys |= A_BUTTON; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_CIRCLE)) - pspKeys |= B_BUTTON; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_SQUARE)) - pspKeys |= B_BUTTON; // Square also B - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_START)) - pspKeys |= START_BUTTON; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_SELECT)) - pspKeys |= SELECT_BUTTON; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_LTRIGGER)) - pspKeys |= L_BUTTON; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_RTRIGGER)) - pspKeys |= R_BUTTON; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_UP)) - pspKeys |= DPAD_UP; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_DOWN)) - pspKeys |= DPAD_DOWN; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_LEFT)) - pspKeys |= DPAD_LEFT; - if (SDL_JoystickGetButton(pspJoystick, PSP_BTN_RIGHT)) - pspKeys |= DPAD_RIGHT; - - return pspKeys; + if (SDL_JoystickGetButton(joystick, BTN_CROSS)) + keys |= A_BUTTON; + if (SDL_JoystickGetButton(joystick, BTN_CIRCLE)) + keys |= B_BUTTON; + if (SDL_JoystickGetButton(joystick, BTN_SQUARE)) + keys |= B_BUTTON; // Square also B + if (SDL_JoystickGetButton(joystick, BTN_START)) + keys |= START_BUTTON; + if (SDL_JoystickGetButton(joystick, BTN_SELECT)) + keys |= SELECT_BUTTON; + if (SDL_JoystickGetButton(joystick, BTN_LTRIGGER)) + keys |= L_BUTTON; + if (SDL_JoystickGetButton(joystick, BTN_RTRIGGER)) + keys |= R_BUTTON; + if (SDL_JoystickGetButton(joystick, BTN_UP)) + keys |= DPAD_UP; + if (SDL_JoystickGetButton(joystick, BTN_DOWN)) + keys |= DPAD_DOWN; + if (SDL_JoystickGetButton(joystick, BTN_LEFT)) + keys |= DPAD_LEFT; + if (SDL_JoystickGetButton(joystick, BTN_RIGHT)) + keys |= DPAD_RIGHT; + + return keys; } #endif @@ -680,8 +762,8 @@ u16 Platform_GetKeyInput(void) return (gamepadKeys != 0) ? gamepadKeys : keys; #endif -#ifdef __PSP__ - return keys | PollPSPButtons(); +#if defined(__PSP__) || defined(__PS2__) + return keys | PollJoystickButtons(); #endif return keys; diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index f7a8927b3f..67e276fb10 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -368,17 +368,10 @@ void MP2K_event_fine(struct MP2KPlayerState *unused, struct MP2KTrack *track) track->status = 0; } -// mPtr aligns to 4 bytes on MIPS; match that here before reading pointer data -#ifdef __mips__ -static inline u8 *alignCmdPtr4(u8 *p) { return (u8 *)(((uintptr_t)p + 3) & ~(uintptr_t)3); } -#else -#define alignCmdPtr4(p) (p) -#endif - // Sets the track's cmdPtr to the specified address. void MP2K_event_goto(struct MP2KPlayerState *unused, struct MP2KTrack *track) { - u8 *cmdPtr = alignCmdPtr4(track->cmdPtr); + u8 *cmdPtr = track->cmdPtr; uintptr_t addr = 0; for (size_t i = sizeof(uintptr_t) - 1; i > 0; i--) { addr |= cmdPtr[i]; @@ -393,9 +386,7 @@ void MP2K_event_patt(struct MP2KPlayerState *unused, struct MP2KTrack *track) { u8 level = track->patternLevel; if (level < 3) { - // Return address is past the aligned pointer data - u8 *ptrStart = alignCmdPtr4(track->cmdPtr); - track->patternStack[level] = ptrStart + sizeof(u8 *); + track->patternStack[level] = track->cmdPtr + sizeof(u8 *); track->patternLevel++; MP2K_event_goto(unused, track); } else { @@ -428,9 +419,7 @@ void MP2K_event_rept(struct MP2KPlayerState *unused, struct MP2KTrack *track) MP2K_event_goto(unused, track); } else { track->repeatCount = 0; - // Skip past the aligned pointer data - u8 *ptrStart = alignCmdPtr4(track->cmdPtr); - track->cmdPtr = ptrStart + sizeof(u8 *); + track->cmdPtr = track->cmdPtr + sizeof(u8 *); } } } From 12e9621e6ef64162d55aea1987e6af7b8ac47ac5 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 16 Feb 2026 19:33:01 +0000 Subject: [PATCH 06/51] convert to sdl_ps2 --- Makefile | 30 +++++++++++++++++------------- src/lib/m4a/m4a.c | 3 +-- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index c7979cd8f8..3af4ea8311 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ else ifeq ($(PLATFORM),psp) PSPSDK := $(PSPDEV)/psp/sdk export PATH := $(PSPDEV)/bin:$(PATH) PREFIX := psp- -else ifeq ($(PLATFORM),ps2) +else ifeq ($(PLATFORM),sdl_ps2) PREFIX := mips64r5900el-ps2-elf- else # Native @@ -132,7 +132,7 @@ else ifeq ($(PLATFORM),psp) ROM := EBOOT.PBP ELF := $(BUILD_NAME).psp.elf MAP := $(BUILD_NAME).psp.map -else ifeq ($(PLATFORM),ps2) +else ifeq ($(PLATFORM),sdl_ps2) ROM := $(BUILD_NAME).$(PLATFORM).iso ELF := $(ROM:.iso=.elf) MAP := $(ROM:.iso=.map) @@ -175,7 +175,7 @@ else ifeq ($(PLATFORM),sdl) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") else ifeq ($(PLATFORM),psp) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") -else ifeq ($(PLATFORM),ps2) +else ifeq ($(PLATFORM),sdl_ps2) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") else ifeq ($(PLATFORM),sdl_win32) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") @@ -248,7 +248,7 @@ else else ifeq ($(PLATFORM),psp) CC1FLAGS += -G0 CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600 - else ifeq ($(PLATFORM),ps2) + else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(PS2SDK)/ports/bin/sdl2-config --cflags) else ifeq ($(PLATFORM),sdl_win32) @@ -277,7 +277,7 @@ else CPP := $(CC1) -E else ifeq ($(PLATFORM), psp) CPP := $(CC1) -E - else ifeq ($(PLATFORM), ps2) + else ifeq ($(PLATFORM), sdl_ps2) ASFLAGS += -msingle-float endif # Allow file input through stdin on modern GCC and set it to "compile only" @@ -291,7 +291,7 @@ else ifeq ($(PLATFORM),psp) # -O3 for PSP (Allegrex MIPS, small D-cache) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer - else ifeq ($(PLATFORM),ps2) + else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else CC1FLAGS += -O2 @@ -337,7 +337,7 @@ else ifeq ($(PLATFORM),sdl) # PSP else ifeq ($(PLATFORM),psp) MAP_FLAG := -Xlinker -Map= -else ifeq ($(PLATFORM),ps2) +else ifeq ($(PLATFORM),sdl_ps2) MAP_FLAG := -Xlinker -Map= # Win32 else @@ -351,7 +351,7 @@ else ifeq ($(PLATFORM),sdl) LIBS := $(shell sdl2-config --cflags --libs) else ifeq ($(PLATFORM),psp) LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128 -else ifeq ($(PLATFORM),ps2) +else ifeq ($(PLATFORM),sdl_ps2) LIBS := -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),sdl_win32) LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS) @@ -362,7 +362,7 @@ endif #### MAIN TARGETS #### # these commands will run regardless of deps being completed -.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall ps2 +.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall # Ensure required directories exist $(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR)) @@ -458,7 +458,7 @@ sdl: ; @$(MAKE) PLATFORM=sdl psp: ; @$(MAKE) PLATFORM=psp -ps2: ; @$(MAKE) PLATFORM=ps2 +sdl_ps2: ; @$(MAKE) PLATFORM=sdl_ps2 tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 @@ -521,11 +521,14 @@ else @cd $(OBJ_DIR) && $(CC1) $(MAP_FLAG)$(ROOT_DIR)/$(MAP) $(OBJS_REL) $(LIBS) -o $(ROOT_DIR)/$@ endif -$(ROM): $(ELF) + ifeq ($(PLATFORM),gba) +$(ROM): $(ELF) libagbsyscall $(OBJCOPY) -O binary --pad-to 0x8400000 $< $@ $(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent -else ifeq ($(PLATFORM),sdl) +else +$(ROM): $(ELF) +ifeq ($(PLATFORM),sdl) cp $< $@ else ifeq ($(PLATFORM),psp) psp-fixup-imports $< @@ -533,7 +536,7 @@ else ifeq ($(PLATFORM),psp) psp-strip $< -o $(BUILD_NAME).psp_strip.elf pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL -rm -f $(BUILD_NAME).psp_strip.elf -else ifeq ($(PLATFORM),ps2) +else ifeq ($(PLATFORM),sdl_ps2) @echo Creating $(ROM) from $(ELF) @cp -r ps2/ntsc $(OBJ_DIR)/iso @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) @@ -541,6 +544,7 @@ else ifeq ($(PLATFORM),ps2) else $(OBJCOPY) -O pei-x86-64 $< $@ endif +endif # Build c sources, and ensure alignment $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.c diff --git a/src/lib/m4a/m4a.c b/src/lib/m4a/m4a.c index 7b90fe3a99..db161254bf 100644 --- a/src/lib/m4a/m4a.c +++ b/src/lib/m4a/m4a.c @@ -1377,10 +1377,9 @@ cond_true : { return; } -cond_false : { +cond_false: track->cmdPtr += 4; } -} void MP2K_event_xcmd(struct MP2KPlayerState *mplayInfo, struct MP2KTrack *track) { From 31419cafde30bc46589855880cdc0583eccb8db6 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 17 Feb 2026 01:49:25 +0000 Subject: [PATCH 07/51] add ps2 non sdl --- Makefile | 45 +- include/lib/m4a/m4a_internal.h | 2 + include/platform/platform.h | 2 +- src/game/special_stage/world.c | 4 +- src/platform/pret_sdl/sdl2.c | 2 +- src/platform/ps2/ps2.c | 949 ++++++++++++++++++++ src/platform/shared/audio/m4a_sound_mixer.c | 13 +- src/platform/win32/win32.c | 2 +- src/sprite.c | 4 +- 9 files changed, 999 insertions(+), 24 deletions(-) create mode 100644 src/platform/ps2/ps2.c diff --git a/Makefile b/Makefile index 3af4ea8311..e17045f1ff 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,8 @@ else ifeq ($(PLATFORM),psp) PREFIX := psp- else ifeq ($(PLATFORM),sdl_ps2) PREFIX := mips64r5900el-ps2-elf- +else ifeq ($(PLATFORM),ps2) + PREFIX := mips64r5900el-ps2-elf- else # Native ifneq ($(PLATFORM),sdl) @@ -136,6 +138,10 @@ else ifeq ($(PLATFORM),sdl_ps2) ROM := $(BUILD_NAME).$(PLATFORM).iso ELF := $(ROM:.iso=.elf) MAP := $(ROM:.iso=.map) +else ifeq ($(PLATFORM),ps2) +ROM := $(BUILD_NAME).$(PLATFORM).iso +ELF := $(ROM:.iso=.elf) +MAP := $(ROM:.iso=.map) else ROM := $(BUILD_NAME).$(PLATFORM).exe ELF := $(ROM:.exe=.elf) @@ -172,15 +178,17 @@ TILESETS_SUBDIR = graphics/tilesets/ ifeq ($(PLATFORM),gba) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),psp) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),sdl_ps2) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") +else ifeq ($(PLATFORM),ps2) +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/pret_sdl/*") else ifeq ($(PLATFORM),sdl_win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/psp/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") else C_SRCS := $(shell find $(C_SUBDIR) -name "*.c") endif @@ -251,6 +259,9 @@ else else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(PS2SDK)/ports/bin/sdl2-config --cflags) + else ifeq ($(PLATFORM),ps2) + CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math + CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=0 -D PLATFORM_WIN32=0 -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include else ifeq ($(PLATFORM),sdl_win32) CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(SDL_MINGW_FLAGS) else ifeq ($(PLATFORM),win32) @@ -279,6 +290,8 @@ else CPP := $(CC1) -E else ifeq ($(PLATFORM), sdl_ps2) ASFLAGS += -msingle-float + else ifeq ($(PLATFORM), ps2) + ASFLAGS += -msingle-float endif # Allow file input through stdin on modern GCC and set it to "compile only" CC1FLAGS += -x c -S @@ -293,6 +306,8 @@ else CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer + else ifeq ($(PLATFORM),ps2) + CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else CC1FLAGS += -O2 endif @@ -339,6 +354,8 @@ else ifeq ($(PLATFORM),psp) MAP_FLAG := -Xlinker -Map= else ifeq ($(PLATFORM),sdl_ps2) MAP_FLAG := -Xlinker -Map= +else ifeq ($(PLATFORM),ps2) + MAP_FLAG := -Xlinker -Map= # Win32 else MAP_FLAG := -Xlinker -Map= @@ -353,6 +370,8 @@ else ifeq ($(PLATFORM),psp) LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),sdl_ps2) LIBS := -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 +else ifeq ($(PLATFORM),ps2) + LIBS := -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -lgskit -ldmakit -lps2_drivers -lmc -lpatches -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),sdl_win32) LIBS := -mwin32 -lkernel32 -lwinmm -lmingw32 -lxinput $(SDL_MINGW_LIBS) else ifeq ($(PLATFORM), win32) @@ -362,7 +381,7 @@ endif #### MAIN TARGETS #### # these commands will run regardless of deps being completed -.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall +.PHONY: clean tools tidy clean-tools $(TOOLDIRS) libagbsyscall ps2 # Ensure required directories exist $(shell mkdir -p $(C_BUILDDIR) $(ASM_BUILDDIR) $(DATA_ASM_BUILDDIR) $(SOUND_ASM_BUILDDIR) $(SONG_BUILDDIR) $(MID_BUILDDIR)) @@ -460,6 +479,8 @@ psp: ; @$(MAKE) PLATFORM=psp sdl_ps2: ; @$(MAKE) PLATFORM=sdl_ps2 +ps2: ; @$(MAKE) PLATFORM=ps2 + tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 sdl_win32: @@ -526,8 +547,11 @@ ifeq ($(PLATFORM),gba) $(ROM): $(ELF) libagbsyscall $(OBJCOPY) -O binary --pad-to 0x8400000 $< $@ $(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent +else ifeq ($(PLATFORM),win32) +$(ROM): $(ELF) libagbsyscall + $(OBJCOPY) -O pei-x86-64 $< $@ else -$(ROM): $(ELF) +$(ROM): $(ELF) ifeq ($(PLATFORM),sdl) cp $< $@ else ifeq ($(PLATFORM),psp) @@ -541,8 +565,11 @@ else ifeq ($(PLATFORM),sdl_ps2) @cp -r ps2/ntsc $(OBJ_DIR)/iso @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) @mkisofs -o $(ROM) $(OBJ_DIR)/iso/ -else - $(OBJCOPY) -O pei-x86-64 $< $@ +else ifeq ($(PLATFORM),ps2) + @echo Creating $(ROM) from $(ELF) + @cp -r ps2/ntsc $(OBJ_DIR)/iso + @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) + @mkisofs -o $(ROM) $(OBJ_DIR)/iso/ endif endif diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 7755591c67..0ae01ef882 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -243,6 +243,8 @@ struct SoundMixerState { #if PLATFORM_GBA s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; #else + // TODO: let's not make this float, they are slow + // on older systems float pcmBuffer[PCM_DMA_BUF_SIZE * 2]; #endif }; diff --git a/include/platform/platform.h b/include/platform/platform.h index 0a44b8f1ff..504c23586d 100644 --- a/include/platform/platform.h +++ b/include/platform/platform.h @@ -21,6 +21,6 @@ extern void Platform_RLFree(unsigned char *dest); extern void Platform_LZDecompressUnsafe(unsigned char *src, unsigned char *dest); extern void Platform_RLDecompressUnsafe(unsigned char *src, unsigned char *dest); -extern void Platform_QueueAudio(const void *data, u32 numBytes); +extern void Platform_QueueAudio(const float *data, u32 numBytes); #endif // GUARD_SA2_PLATFORM_H diff --git a/src/game/special_stage/world.c b/src/game/special_stage/world.c index eb293bf744..a41ac6d5c3 100644 --- a/src/game/special_stage/world.c +++ b/src/game/special_stage/world.c @@ -239,14 +239,14 @@ void sub_806EA04(void) *unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PA // HACK: in SDL we don't handle these PB and PD values properly -#if PLATFORM_SDL +#if !PLATFORM_GBA && (RENDERER == RENDERER_SOFTWARE_FAST || RENDERER == RENDERER_SOFTWARE) *unk1884++ = 0; #else *unk1884++ = (Q_16_16_TO_INT(temp) * sin) >> 0x10; // BG2PB #endif *unk1884++ = (Q_16_16_TO_INT(temp) * -sin) >> 0x10; // BG2PC -#if PLATFORM_SDL +#if !PLATFORM_GBA && (RENDERER == RENDERER_SOFTWARE_FAST || RENDERER == RENDERER_SOFTWARE) *unk1884++ = 0; #else *unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PD diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 1a77546ea0..4e4086ca93 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -625,7 +625,7 @@ static u16 PollJoystickButtons(void) u32 fullScreenFlags = 0; static SDL_DisplayMode sdlDispMode = { 0 }; -void Platform_QueueAudio(const void *data, uint32_t bytesCount) +void Platform_QueueAudio(const float *data, uint32_t bytesCount) { if (headless) { return; diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c new file mode 100644 index 0000000000..b4c09442e5 --- /dev/null +++ b/src/platform/ps2/ps2.c @@ -0,0 +1,949 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "audsrv.h" + +#include "global.h" +#include "core.h" +#include "multi_sio.h" +#include "gba/defines.h" +#include "gba/io_reg.h" +#include "gba/types.h" +#include "lib/agb_flash/flash_internal.h" +#include "platform/shared/dma.h" + +static GSGLOBAL *gsGlobal; +static GSTEXTURE screen; + +#include "platform/shared/audio/cgb_audio.h" + +#ifndef TILE_WIDTH +#define TILE_WIDTH 8 +#endif + +extern IntrFunc gIntrTable[16]; + +ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * DISPLAY_HEIGHT]; + +struct VidMode { + const char *name; + s16 mode; + s16 interlace; + s16 field; + int max_width; + int max_height; + int width; + int height; + int vck; + int iPassCount; + int x_off; + int y_off; +}; + +static const struct VidMode vid_modes[] = { + { "240p", GS_MODE_NTSC, GS_NONINTERLACED, GS_FRAME, 652, 224, 320, 224, 2, 1, 0, 0 }, +#if !defined(VERSION_EU) + // NTSC + { "480i", GS_MODE_NTSC, GS_INTERLACED, GS_FIELD, 704, 480, 704, 452, 4, 1, 0, 0 }, + { "480p", GS_MODE_DTV_480P, GS_NONINTERLACED, GS_FRAME, 704, 480, 704, 452, 2, 1, 0, 0 }, +#else + // PAL + { "576i", GS_MODE_PAL, GS_INTERLACED, GS_FIELD, 704, 576, 704, 536, 4, 1, 0, 0 }, + { "576p", GS_MODE_DTV_576P, GS_NONINTERLACED, GS_FRAME, 704, 576, 704, 536, 2, 1, 0, 0 }, +#endif + // HDTV + { "720p", GS_MODE_DTV_720P, GS_NONINTERLACED, GS_FRAME, 1280, 720, 1280, 720, 1, 2, 0, 0 }, + { "1080i", GS_MODE_DTV_1080I, GS_INTERLACED, GS_FRAME, 1920, 1080, 1920, 1080, 1, 2, 0, 0 }, +}; + +static int vsync_sema_1st_id; +static int vsync_sema_2nd_id; +static int vsync_sema_id = -1; +static int vsync_id = -1; + +static const struct VidMode *vid_mode; +static bool use_hires = false; + +bool speedUp = false; +bool isRunning = true; +bool paused = false; +bool stepOneFrame = false; +bool headless = false; + +double lastGameTime = 0; +double curGameTime = 0; +double fixedTimestep = 1.0 / 60.0; // 16.666667ms +double timeScale = 1.0; +double accumulator = 0.0; + +static FILE *sSaveFile = NULL; + +extern void AgbMain(void); +void DoSoftReset(void) {}; + +void VDraw(void); +void UpdateTexture(void); + +static void ReadSaveFile(char *path); +static void StoreSaveFile(void); +static void CloseSaveFile(void); + +u16 Platform_GetKeyInput(void); + +#define SAMPLES_HIGH 544 +#define SAMPLES_LOW 528 + +static bool audio_ps2_init(void) +{ + if (init_audio_driver() != 0) + return false; + audsrv_set_volume(MAX_VOLUME); + + audsrv_fmt_t fmt; + + fmt.freq = 48000; + fmt.bits = 16; + fmt.channels = 2; + + if (audsrv_set_format(&fmt)) { + printf("audio_ps2: unsupported sound format\n"); + audsrv_quit(); + return false; + } + + return true; +} + +static int audio_ps2_buffered(void) { return audsrv_queued() / 4; } + +static void audio_ps2_play(const uint8_t *buf, size_t len) +{ + if (audio_ps2_buffered() < 6000) { + audsrv_play_audio(buf, len); + } +} + +void reset_IOP() +{ + SifInitRpc(0); + while (!SifIopReset(NULL, 0)) { } // Comment this line if you want to "debug" through ps2link + while (!SifIopSync()) { } +} + +static void prepare_IOP() +{ + reset_IOP(); + SifInitRpc(0); + sbv_patch_enable_lmb(); + sbv_patch_disable_prefix_check(); +} + +static void init_drivers() +{ + init_only_boot_ps2_filesystem_driver(); + init_memcard_driver(true); +} + +static void deinit_drivers() +{ + deinit_memcard_driver(true); + deinit_only_boot_ps2_filesystem_driver(); +} + +void platform_video_init(void) +{ + if (vid_mode == NULL) { + vid_mode = &vid_modes[2]; // Standard def 480p + } else { + if (use_hires) { + gsKit_hires_deinit_global(gsGlobal); + } else { + gsKit_deinit_global(gsGlobal); + if (vsync_id != -1) { + gsKit_remove_vsync_handler(vsync_id); + } + vsync_sema_id = -1; + } + } + use_hires = (vid_mode->mode == GS_MODE_DTV_720P || vid_mode->mode == GS_MODE_DTV_1080I); + + if (use_hires) { + gsGlobal = gsKit_hires_init_global(); + } else { + gsGlobal = gsKit_init_global(); + } + + dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); + + dmaKit_chan_init(DMA_CHANNEL_GIF); + + gsGlobal->Mode = vid_mode->mode; + gsGlobal->Width = vid_mode->width; + gsGlobal->Height = vid_mode->height; + if (gsGlobal->Mode == GS_MODE_DTV_1080I) { + gsGlobal->Height /= 2; + } + + gsGlobal->Interlace = vid_mode->interlace; + gsGlobal->Field = vid_mode->field; + gsGlobal->ZBuffering = GS_SETTING_ON; + gsGlobal->DoubleBuffering = GS_SETTING_ON; + gsGlobal->PrimAAEnable = GS_SETTING_OFF; + gsGlobal->Dithering = GS_SETTING_OFF; + gsGlobal->PSM = GS_PSM_CT16; + gsGlobal->PSMZ = GS_PSMZ_16; + + if (use_hires) { + gsKit_hires_init_screen(gsGlobal, vid_mode->iPassCount); + } else { + gsKit_init_screen(gsGlobal); + } + // hires sets the texture pointer to the wrong location. Ensure it's correct. + gsGlobal->TexturePointer = gsGlobal->CurrentPointer; + gsKit_TexManager_init(gsGlobal); + + screen.Width = DISPLAY_WIDTH; + screen.Height = DISPLAY_HEIGHT; + screen.PSM = GS_PSM_CT16; + screen.Mem = (void *)gameImage; +} + +int main(int argc, char **argv) +{ + prepare_IOP(); + + // ReadSaveFile("sa2.sav"); + + // Prevent the multiplayer screen from being drawn ( see core.c:EngineInit() ) + REG_RCNT = 0x8000; + REG_KEYINPUT = 0x3FF; + + audio_ps2_init(); + platform_video_init(); + // controller init + + cgb_audio_init(48000); + + VDraw(); + AgbMain(); + + return 0; +} + +bool newFrameRequested = FALSE; +int skipFrame = 0; + +// called every gba frame. we process sdl events and render as many times +// as vsync needs, then return when a new game frame is needed. +void VBlankIntrWait(void) +{ +#define HANDLE_VBLANK_INTRS() \ + ({ \ + REG_DISPSTAT |= INTR_FLAG_VBLANK; \ + RunDMAs(DMA_VBLANK); \ + if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) \ + gIntrTable[INTR_INDEX_VBLANK](); \ + REG_DISPSTAT &= ~INTR_FLAG_VBLANK; \ + }) + + bool frameAvailable = TRUE; + bool frameDrawn = false; + static int frames_skipped = 0; + if (isRunning) { + REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + +// Only render 30fps when in widescreen as the draw func is too slow for the ps2 +#if DISPLAY_WIDTH > 240 + skipFrame++; + skipFrame %= 2; +#endif + if (skipFrame == 0) { + VDraw(); + } else { + UpdateTexture(); + } + HANDLE_VBLANK_INTRS(); + if (skipFrame != 0) { + return; + } + + if (use_hires) { + gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1); + } else { + gsKit_sync_flip(gsGlobal); + gsKit_queue_exec(gsGlobal); + } + gsKit_TexManager_nextFrame(gsGlobal); + return; + } + // #define MAX_FRAME_SKIP 2 + + // while (isRunning) { + // if (!paused || stepOneFrame) { + // double dt = fixedTimestep / timeScale; // TODO: Fix speedup + + // // don't accumulate time if we already requested a new frame + // // this frame cycle (emulates threaded sdl behavior) + // if (!newFrameRequested) { + // double deltaTime = 0; + + // // TODO: fix + // curGameTime += dt; + // if (stepOneFrame) { + // deltaTime = dt; + // } else { + // // TODO: divide by expected frequency + // deltaTime = (double)((curGameTime - lastGameTime) / 1); + // if (deltaTime > (dt * 5)) + // deltaTime = dt * 5; + // } + // lastGameTime = curGameTime; + + // accumulator += deltaTime; + // } else { + // newFrameRequested = FALSE; + // } + + // while (accumulator >= dt) { + // REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); + // if (frameAvailable) { + // // frame skip: let game logic catch up when behind + // if (accumulator >= dt * 2.0 && frames_skipped < MAX_FRAME_SKIP) { + // frames_skipped++; + // frameAvailable = FALSE; + // HANDLE_VBLANK_INTRS(); + // accumulator -= dt; + // newFrameRequested = TRUE; + // return; + // } + // frames_skipped = 0; + // VDraw(); + // frameAvailable = FALSE; + // frameDrawn = true; + + // HANDLE_VBLANK_INTRS(); + + // accumulator -= dt; + // } else { + // newFrameRequested = TRUE; + // return; + // } + // } + + // if (paused && stepOneFrame) { + // stepOneFrame = false; + // } + // } + + // if (use_hires) { + // gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1); + // } else { + // // gsKit_flip(gs_global); + // gsKit_sync_flip(gsGlobal); + // gsKit_queue_exec(gsGlobal); + // } + // gsKit_TexManager_nextFrame(gsGlobal); + // } + + CloseSaveFile(); + + deinit_drivers(); + exit(0); +#undef HANDLE_VBLANK_INTRS +} + +static void ReadSaveFile(char *path) +{ + // Check whether the saveFile exists, and create it if not + sSaveFile = fopen(path, "r+b"); + if (sSaveFile == NULL) { + sSaveFile = fopen(path, "w+b"); + } + + fseek(sSaveFile, 0, SEEK_END); + int fileSize = ftell(sSaveFile); + fseek(sSaveFile, 0, SEEK_SET); + + // Only read as many bytes as fit inside the buffer + // or as many bytes as are in the file + int bytesToRead = (fileSize < sizeof(FLASH_BASE)) ? fileSize : sizeof(FLASH_BASE); + + int bytesRead = fread(FLASH_BASE, 1, bytesToRead, sSaveFile); + + // Fill the buffer if the savefile was just created or smaller than the buffer itself + for (int i = bytesRead; i < sizeof(FLASH_BASE); i++) { + FLASH_BASE[i] = 0xFF; + } +} + +static void StoreSaveFile() +{ + if (sSaveFile != NULL) { + fseek(sSaveFile, 0, SEEK_SET); + fwrite(FLASH_BASE, 1, sizeof(FLASH_BASE), sSaveFile); + } +} + +void Platform_StoreSaveFile(void) { StoreSaveFile(); } + +static void CloseSaveFile() +{ + if (sSaveFile != NULL) { + fclose(sSaveFile); + } +} + +s16 converted_audio[4096]; + +void float_audio_to_s16(const float *input, int16_t *output, size_t length) +{ + if (!input || !output) + return; + + for (size_t i = 0; i < length; i++) { + float sample = input[i]; + + if (sample > 1.0f) + sample = 1.0f; + else if (sample < -1.0f) + sample = -1.0f; + + output[i] = (int16_t)(sample * 32767.0f + (sample >= 0 ? 0.5f : -0.5f)); + } +} + +void Platform_QueueAudio(const float *data, uint32_t bytesCount) +{ + float_audio_to_s16(data, converted_audio, bytesCount / sizeof(float)); + audio_ps2_play((void *)converted_audio, bytesCount / sizeof(float) * sizeof(u16)); +} + +// TODO: handle input +u16 Platform_GetKeyInput(void) { return 0; } + +// BIOS function implementations are based on the VBA-M source code. + +// safe unaligned access for MIPS +static uint32_t CPUReadMemory(const void *src) +{ + uint32_t val; + memcpy(&val, src, sizeof(val)); + return val; +} + +static void CPUWriteMemory(void *dest, uint32_t val) { memcpy(dest, &val, sizeof(val)); } + +static uint16_t CPUReadHalfWord(const void *src) +{ + uint16_t val; + memcpy(&val, src, sizeof(val)); + return val; +} + +static void CPUWriteHalfWord(void *dest, uint16_t val) { memcpy(dest, &val, sizeof(val)); } + +static uint8_t CPUReadByte(const void *src) { return *(uint8_t *)src; } + +static void CPUWriteByte(void *dest, uint8_t val) { *(uint8_t *)dest = val; } + +void CpuSet(const void *src, void *dst, u32 cnt) +{ + if (dst == NULL) { + puts("Attempted to CpuSet to NULL\n"); + return; + } + + int count = cnt & 0x1FFFFF; + + const u8 *source = src; + u8 *dest = dst; + + // 32-bit ? + if ((cnt >> 26) & 1) { + // assert(((uintptr_t)src & ~3) == (uintptr_t)src); + // assert(((uintptr_t)dst & ~3) == (uintptr_t)dst); + + // needed for 32-bit mode! + // source = (u8 *)((uint32_t )source & ~3); + // dest = (u8 *)((uint32_t )dest & ~3); + + // fill ? + if ((cnt >> 24) & 1) { + uint32_t value = CPUReadMemory(source); + while (count) { + CPUWriteMemory(dest, value); + dest += 4; + count--; + } + } else { + // copy + while (count) { + CPUWriteMemory(dest, CPUReadMemory(source)); + source += 4; + dest += 4; + count--; + } + } + } else { + // No align on 16-bit fill? + // assert(((uintptr_t)src & ~1) == (uintptr_t)src); + // assert(((uintptr_t)dst & ~1) == (uintptr_t)dst); + + // 16-bit fill? + if ((cnt >> 24) & 1) { + uint16_t value = CPUReadHalfWord(source); + while (count) { + CPUWriteHalfWord(dest, value); + dest += 2; + count--; + } + } else { + // copy + while (count) { + CPUWriteHalfWord(dest, CPUReadHalfWord(source)); + source += 2; + dest += 2; + count--; + } + } + } +} + +void CpuFastSet(const void *src, void *dst, u32 cnt) +{ + if (dst == NULL) { + puts("Attempted to CpuFastSet to NULL\n"); + return; + } + + int count = cnt & 0x1FFFFF; + + const u8 *source = src; + u8 *dest = dst; + + // source = (u8 *)((uint32_t )source & ~3); + // dest = (u8 *)((uint32_t )dest & ~3); + + // fill? + if ((cnt >> 24) & 1) { + uint32_t value = CPUReadMemory(source); + while (count > 0) { + // BIOS always transfers 32 bytes at a time + for (int i = 0; i < 8; i++) { + CPUWriteMemory(dest, value); + dest += 4; + } + count -= 8; + } + } else { + // copy + while (count > 0) { + // BIOS always transfers 32 bytes at a time + for (int i = 0; i < 8; i++) { + uint32_t value = CPUReadMemory(source); + CPUWriteMemory(dest, value); + source += 4; + dest += 4; + } + count -= 8; + } + } +} + +void LZ77UnCompVram(const void *src_, void *dest_) +{ + const u8 *src = (const u8 *)src_; + u8 *dest = dest_; + int destSize = (src[3] << 16) | (src[2] << 8) | src[1]; + int srcPos = 4; + int destPos = 0; + + for (;;) { + unsigned char flags = src[srcPos++]; + + for (int i = 0; i < 8; i++) { + if (flags & 0x80) { + int blockSize = (src[srcPos] >> 4) + 3; + int blockDistance = (((src[srcPos] & 0xF) << 8) | src[srcPos + 1]) + 1; + + srcPos += 2; + + int blockPos = destPos - blockDistance; + + // Some Ruby/Sapphire tilesets overflow. + if (destPos + blockSize > destSize) { + blockSize = destSize - destPos; + // fprintf(stderr, "Destination buffer overflow.\n"); + puts("Destination buffer overflow.\n"); + } + + if (blockPos < 0) + goto fail; + + for (int j = 0; j < blockSize; j++) + dest[destPos++] = dest[blockPos + j]; + } else { + if (destPos >= destSize) + goto fail; + + dest[destPos++] = src[srcPos++]; + } + + if (destPos == destSize) { + return; + } + + flags <<= 1; + } + } + +fail: + puts("Fatal error while decompressing LZ file.\n"); +} + +void LZ77UnCompWram(const void *src, void *dst) +{ + const uint8_t *source = src; + uint8_t *dest = dst; + + uint32_t header = CPUReadMemory(source); + source += 4; + + int len = header >> 8; + + while (len > 0) { + uint8_t d = CPUReadByte(source++); + + if (d) { + for (int i = 0; i < 8; i++) { + if (d & 0x80) { + uint16_t data = CPUReadByte(source++) << 8; + data |= CPUReadByte(source++); + int length = (data >> 12) + 3; + int offset = (data & 0x0FFF); + uint8_t *windowOffset = dest - offset - 1; + for (int i2 = 0; i2 < length; i2++) { + CPUWriteByte(dest++, CPUReadByte(windowOffset++)); + len--; + if (len == 0) + return; + } + } else { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if (len == 0) + return; + } + d <<= 1; + } + } else { + for (int i = 0; i < 8; i++) { + CPUWriteByte(dest++, CPUReadByte(source++)); + len--; + if (len == 0) + return; + } + } + } +} + +void RLUnCompWram(const void *src, void *dest) +{ + int remaining = CPUReadMemory(src) >> 8; + int blockHeader; + int block; + src += 4; + while (remaining > 0) { + blockHeader = CPUReadByte(src); + src++; + if (blockHeader & 0x80) // Compressed? + { + blockHeader &= 0x7F; + blockHeader += 3; + block = CPUReadByte(src); + src++; + while (blockHeader-- && remaining) { + remaining--; + CPUWriteByte(dest, block); + dest++; + } + } else // Uncompressed + { + blockHeader++; + while (blockHeader-- && remaining) { + remaining--; + u8 byte = CPUReadByte(src); + src++; + CPUWriteByte(dest, byte); + dest++; + } + } + } +} + +void RLUnCompVram(const void *src, void *dest) +{ + int remaining = CPUReadMemory(src) >> 8; + int padding = (4 - remaining) & 0x3; + int blockHeader; + int block; + int halfWord = 0; + src += 4; + while (remaining > 0) { + blockHeader = CPUReadByte(src); + src++; + if (blockHeader & 0x80) // Compressed? + { + blockHeader &= 0x7F; + blockHeader += 3; + block = CPUReadByte(src); + src++; + while (blockHeader-- && remaining) { + remaining--; + if ((uintptr_t)dest & 1) { + halfWord |= block << 8; + CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord); + } else + halfWord = block; + dest++; + } + } else // Uncompressed + { + blockHeader++; + while (blockHeader-- && remaining) { + remaining--; + u8 byte = CPUReadByte(src); + src++; + if ((uintptr_t)dest & 1) { + halfWord |= byte << 8; + CPUWriteHalfWord((void *)((uintptr_t)dest ^ 1), halfWord); + } else + halfWord = byte; + dest++; + } + } + } + if ((uintptr_t)dest & 1) { + padding--; + dest++; + } + for (; padding > 0; padding -= 2, dest += 2) + CPUWriteHalfWord(dest, 0); +} + +const s16 sineTable[256] + = { (s16)0x0000, (s16)0x0192, (s16)0x0323, (s16)0x04B5, (s16)0x0645, (s16)0x07D5, (s16)0x0964, (s16)0x0AF1, (s16)0x0C7C, (s16)0x0E05, + (s16)0x0F8C, (s16)0x1111, (s16)0x1294, (s16)0x1413, (s16)0x158F, (s16)0x1708, (s16)0x187D, (s16)0x19EF, (s16)0x1B5D, (s16)0x1CC6, + (s16)0x1E2B, (s16)0x1F8B, (s16)0x20E7, (s16)0x223D, (s16)0x238E, (s16)0x24DA, (s16)0x261F, (s16)0x275F, (s16)0x2899, (s16)0x29CD, + (s16)0x2AFA, (s16)0x2C21, (s16)0x2D41, (s16)0x2E5A, (s16)0x2F6B, (s16)0x3076, (s16)0x3179, (s16)0x3274, (s16)0x3367, (s16)0x3453, + (s16)0x3536, (s16)0x3612, (s16)0x36E5, (s16)0x37AF, (s16)0x3871, (s16)0x392A, (s16)0x39DA, (s16)0x3A82, (s16)0x3B20, (s16)0x3BB6, + (s16)0x3C42, (s16)0x3CC5, (s16)0x3D3E, (s16)0x3DAE, (s16)0x3E14, (s16)0x3E71, (s16)0x3EC5, (s16)0x3F0E, (s16)0x3F4E, (s16)0x3F84, + (s16)0x3FB1, (s16)0x3FD3, (s16)0x3FEC, (s16)0x3FFB, (s16)0x4000, (s16)0x3FFB, (s16)0x3FEC, (s16)0x3FD3, (s16)0x3FB1, (s16)0x3F84, + (s16)0x3F4E, (s16)0x3F0E, (s16)0x3EC5, (s16)0x3E71, (s16)0x3E14, (s16)0x3DAE, (s16)0x3D3E, (s16)0x3CC5, (s16)0x3C42, (s16)0x3BB6, + (s16)0x3B20, (s16)0x3A82, (s16)0x39DA, (s16)0x392A, (s16)0x3871, (s16)0x37AF, (s16)0x36E5, (s16)0x3612, (s16)0x3536, (s16)0x3453, + (s16)0x3367, (s16)0x3274, (s16)0x3179, (s16)0x3076, (s16)0x2F6B, (s16)0x2E5A, (s16)0x2D41, (s16)0x2C21, (s16)0x2AFA, (s16)0x29CD, + (s16)0x2899, (s16)0x275F, (s16)0x261F, (s16)0x24DA, (s16)0x238E, (s16)0x223D, (s16)0x20E7, (s16)0x1F8B, (s16)0x1E2B, (s16)0x1CC6, + (s16)0x1B5D, (s16)0x19EF, (s16)0x187D, (s16)0x1708, (s16)0x158F, (s16)0x1413, (s16)0x1294, (s16)0x1111, (s16)0x0F8C, (s16)0x0E05, + (s16)0x0C7C, (s16)0x0AF1, (s16)0x0964, (s16)0x07D5, (s16)0x0645, (s16)0x04B5, (s16)0x0323, (s16)0x0192, (s16)0x0000, (s16)0xFE6E, + (s16)0xFCDD, (s16)0xFB4B, (s16)0xF9BB, (s16)0xF82B, (s16)0xF69C, (s16)0xF50F, (s16)0xF384, (s16)0xF1FB, (s16)0xF074, (s16)0xEEEF, + (s16)0xED6C, (s16)0xEBED, (s16)0xEA71, (s16)0xE8F8, (s16)0xE783, (s16)0xE611, (s16)0xE4A3, (s16)0xE33A, (s16)0xE1D5, (s16)0xE075, + (s16)0xDF19, (s16)0xDDC3, (s16)0xDC72, (s16)0xDB26, (s16)0xD9E1, (s16)0xD8A1, (s16)0xD767, (s16)0xD633, (s16)0xD506, (s16)0xD3DF, + (s16)0xD2BF, (s16)0xD1A6, (s16)0xD095, (s16)0xCF8A, (s16)0xCE87, (s16)0xCD8C, (s16)0xCC99, (s16)0xCBAD, (s16)0xCACA, (s16)0xC9EE, + (s16)0xC91B, (s16)0xC851, (s16)0xC78F, (s16)0xC6D6, (s16)0xC626, (s16)0xC57E, (s16)0xC4E0, (s16)0xC44A, (s16)0xC3BE, (s16)0xC33B, + (s16)0xC2C2, (s16)0xC252, (s16)0xC1EC, (s16)0xC18F, (s16)0xC13B, (s16)0xC0F2, (s16)0xC0B2, (s16)0xC07C, (s16)0xC04F, (s16)0xC02D, + (s16)0xC014, (s16)0xC005, (s16)0xC000, (s16)0xC005, (s16)0xC014, (s16)0xC02D, (s16)0xC04F, (s16)0xC07C, (s16)0xC0B2, (s16)0xC0F2, + (s16)0xC13B, (s16)0xC18F, (s16)0xC1EC, (s16)0xC252, (s16)0xC2C2, (s16)0xC33B, (s16)0xC3BE, (s16)0xC44A, (s16)0xC4E0, (s16)0xC57E, + (s16)0xC626, (s16)0xC6D6, (s16)0xC78F, (s16)0xC851, (s16)0xC91B, (s16)0xC9EE, (s16)0xCACA, (s16)0xCBAD, (s16)0xCC99, (s16)0xCD8C, + (s16)0xCE87, (s16)0xCF8A, (s16)0xD095, (s16)0xD1A6, (s16)0xD2BF, (s16)0xD3DF, (s16)0xD506, (s16)0xD633, (s16)0xD767, (s16)0xD8A1, + (s16)0xD9E1, (s16)0xDB26, (s16)0xDC72, (s16)0xDDC3, (s16)0xDF19, (s16)0xE075, (s16)0xE1D5, (s16)0xE33A, (s16)0xE4A3, (s16)0xE611, + (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, (s16)0xF384, (s16)0xF50F, + (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E }; + +void BgAffineSet(struct BgAffineSrcData *src, struct BgAffineDstData *dest, s32 count) +{ + for (s32 i = 0; i < count; i++) { + s32 cx = src[i].texX; + s32 cy = src[i].texY; + s16 dispx = src[i].scrX; + s16 dispy = src[i].scrY; + s16 rx = src[i].sx; + s16 ry = src[i].sy; + u16 theta = src[i].alpha >> 8; + s32 a = sineTable[(theta + 0x40) & 255]; + s32 b = sineTable[theta]; + + s16 dx = (rx * a) >> 14; + s16 dmx = (rx * b) >> 14; + s16 dy = (ry * b) >> 14; + s16 dmy = (ry * a) >> 14; + + dest[i].pa = dx; + dest[i].pb = -dmx; + dest[i].pc = dy; + dest[i].pd = dmy; + + s32 startx = cx - dx * dispx + dmx * dispy; + s32 starty = cy - dy * dispx - dmy * dispy; + + dest[i].dx = startx; + dest[i].dy = starty; + } +} + +void ObjAffineSet(struct ObjAffineSrcData *src, void *dest, s32 count, s32 offset) +{ + for (s32 i = 0; i < count; i++) { + s16 rx = src[i].xScale; + s16 ry = src[i].yScale; + u16 theta = src[i].rotation >> 8; + + s32 a = (s32)sineTable[(theta + 64) & 255]; + s32 b = (s32)sineTable[theta]; + + s16 dx = ((s32)rx * a) >> 14; + s16 dmx = ((s32)rx * b) >> 14; + s16 dy = ((s32)ry * b) >> 14; + s16 dmy = ((s32)ry * a) >> 14; + + CPUWriteHalfWord(dest, dx); + dest += offset; + CPUWriteHalfWord(dest, -dmx); + dest += offset; + CPUWriteHalfWord(dest, dy); + dest += offset; + CPUWriteHalfWord(dest, dmy); + dest += offset; + } +} + +void SoftReset(u32 resetFlags) { } + +void SoftResetExram(u32 resetFlags) { } + +// Following functions taken from mGBA's source +u16 ArcTan(s16 i) +{ + s32 a = -((i * i) >> 14); + s32 b = ((0xA9 * a) >> 14) + 0x390; + b = ((b * a) >> 14) + 0x91C; + b = ((b * a) >> 14) + 0xFB6; + b = ((b * a) >> 14) + 0x16AA; + b = ((b * a) >> 14) + 0x2081; + b = ((b * a) >> 14) + 0x3651; + b = ((b * a) >> 14) + 0xA2F9; + + return (i * b) >> 16; +} + +u16 ArcTan2(s16 x, s16 y) +{ + if (!y) { + if (x >= 0) + return 0; + return 0x8000; + } + if (!x) { + if (y >= 0) + return 0x4000; + return 0xC000; + } + if (y >= 0) { + if (x >= 0) { + if (x >= y) + return ArcTan((y << 14) / x); + } else if (-x >= y) + return ArcTan((y << 14) / x) + 0x8000; + return 0x4000 - ArcTan((x << 14) / y); + } else { + if (x <= 0) { + if (-x > -y) + return ArcTan((y << 14) / x) + 0x8000; + } else if (x >= -y) + return ArcTan((y << 14) / x) + 0x10000; + return 0xC000 - ArcTan((x << 14) / y); + } +} + +u16 Sqrt(u32 num) +{ + if (!num) + return 0; + u32 lower; + u32 upper = num; + u32 bound = 1; + while (bound < upper) { + upper >>= 1; + bound <<= 1; + } + while (1) { + upper = num; + u32 accum = 0; + lower = bound; + while (1) { + u32 oldLower = lower; + if (lower <= upper >> 1) + lower <<= 1; + if (oldLower >= upper >> 1) + break; + } + while (1) { + accum <<= 1; + if (upper >= lower) { + ++accum; + upper -= lower; + } + if (lower == bound) + break; + lower >>= 1; + } + u32 oldBound = bound; + bound += accum; + bound >>= 1; + if (bound >= oldBound) { + bound = oldBound; + break; + } + } + return bound; +} + +int MultiBoot(struct MultiBootParam *mp) { return 0; } + +void VDraw(void) +{ + extern void DrawFrame_Fast(uint16_t * pixels); + DrawFrame_Fast(gameImage); + UpdateTexture(); + REG_VCOUNT = DISPLAY_HEIGHT + 1; // prep for being in VBlank period +} + +void UpdateTexture(void) +{ + gsKit_TexManager_invalidate(gsGlobal, &screen); + gsKit_TexManager_bind(gsGlobal, &screen); + + int startX = (gsGlobal->Width); + int startY = (gsGlobal->Height); + + gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0, 0, 0, 0, 0)); + + // Table + gsKit_prim_sprite_texture(gsGlobal, &screen, + 0.0f, // X1 + 0.0f, // Y2 + 0.0f, // U1 + 0.0f, // V1 + startX, // X2 + startY, // Y2 + gsGlobal->Width, // U2 + gsGlobal->Height, // V2 + 0, GS_SETREG_RGBAQ(128, 128, 128, 0, 0)); +} diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index 67e276fb10..6482d6382f 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -31,6 +31,9 @@ struct SoundMixerState *SOUND_INFO_PTR = &sSoundInfo; void SoundMain(void) { +#if !ENABLE_AUDIO + return; +#endif struct SoundMixerState *mixer = SOUND_INFO_PTR; if (mixer->lockStatus != ID_NUMBER) { @@ -419,7 +422,7 @@ void MP2K_event_rept(struct MP2KPlayerState *unused, struct MP2KTrack *track) MP2K_event_goto(unused, track); } else { track->repeatCount = 0; - track->cmdPtr = track->cmdPtr + sizeof(u8 *); + track->cmdPtr += sizeof(u8) + sizeof(u8 *); } } } @@ -908,7 +911,6 @@ void m4aSoundVSync(void) float *m4aBuffer = mixer->pcmBuffer; float *cgbBuffer = cgb_get_buffer(); s32 dmaCounter = mixer->dmaCounter; - bool8 shouldQueue = FALSE; if (dmaCounter > 1) { m4aBuffer += samplesPerFrame * (mixer->framesPerDmaCycle - (dmaCounter - 1)); @@ -916,14 +918,9 @@ void m4aSoundVSync(void) for (u32 i = 0; i < samplesPerFrame; i++) { audioBuffer[i] = m4aBuffer[i] + cgbBuffer[i]; - if (audioBuffer[i] != 0) { - shouldQueue = TRUE; - } } - if (shouldQueue) { - Platform_QueueAudio(audioBuffer, samplesPerFrame * 4); - } + Platform_QueueAudio(audioBuffer, samplesPerFrame * sizeof(float)); if ((s8)(--mixer->dmaCounter) <= 0) mixer->dmaCounter = mixer->framesPerDmaCycle; } diff --git a/src/platform/win32/win32.c b/src/platform/win32/win32.c index 261a18e60d..60d375dfb8 100644 --- a/src/platform/win32/win32.c +++ b/src/platform/win32/win32.c @@ -449,4 +449,4 @@ void *Platform_malloc(size_t numBytes) { return HeapAlloc(GetProcessHeap(), HEAP void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } -void Platform_QueueAudio(const u8 *data, u32 numBytes) { } +void Platform_QueueAudio(const float *data, u32 numBytes) { } diff --git a/src/sprite.c b/src/sprite.c index 94f677da09..234ae233e5 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -9,7 +9,7 @@ #include "animation_commands.h" #include "platform/platform.h" -#if !PLATFORM_GBA && !PLATFORM_SDL +#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE_FAST && RENDERER != RENDERER_SOFTWARE extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); #endif @@ -722,7 +722,7 @@ void DisplaySprite(Sprite *sprite) oam->split.paletteNum += sprite->palId; #endif -#if !PLATFORM_GBA && !PLATFORM_SDL +#if !PLATFORM_GBA && (RENDERER != RENDERER_SOFTWARE_FAST && RENDERER != RENDERER_SOFTWARE) // TEMP // Quick hack for getting output in OpenGL test // The whole function call should be replaced by this! From d194ef36b1c9bf0158b6a00c953002c24a0049a7 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 18 Feb 2026 02:09:08 +0000 Subject: [PATCH 08/51] replace fast renderer with gpsp renderer --- include/config.h | 2 +- include/gba/defines.h | 11 +- src/platform/ps2/ps2.c | 19 +- src/platform/shared/rendering/common.h | 143 + .../shared/rendering/sw_renderer_fast.c | 4643 +++++++++++++---- 5 files changed, 3756 insertions(+), 1062 deletions(-) create mode 100644 src/platform/shared/rendering/common.h diff --git a/include/config.h b/include/config.h index 845e611046..dd1e301d21 100644 --- a/include/config.h +++ b/include/config.h @@ -51,7 +51,7 @@ // TODO: Only win32 for now #define RENDERER RENDERER_OPENGL #else -#define RENDERER RENDERER_SOFTWARE +#define RENDERER RENDERER_SOFTWARE_FAST #endif #endif diff --git a/include/gba/defines.h b/include/gba/defines.h index 6b9d09afcf..5ec55588ca 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -43,9 +43,13 @@ // PSP: Use GBA-native resolution, SDL scales to 480x272 #define DISPLAY_WIDTH 240 #define DISPLAY_HEIGHT 160 +#elif defined(__PS2__) +// Runs at 60fps with the "fast draw" +#define DISPLAY_WIDTH 240 +#define DISPLAY_HEIGHT 160 #else -#define DISPLAY_WIDTH 426 -#define DISPLAY_HEIGHT 240 +#define DISPLAY_WIDTH 240 +#define DISPLAY_HEIGHT 160 #endif // NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing. @@ -54,7 +58,8 @@ #undef VRAM_SIZE #define VRAM_SIZE (0x18000 + (0x800 * (12))) #define WIDESCREEN_HACK TRUE -#define EXTENDED_OAM TRUE +// TODO: extend oam again once fast renderer supports +#define EXTENDED_OAM FALSE #else #define WIDESCREEN_HACK FALSE #define EXTENDED_OAM !TRUE diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index b4c09442e5..a822b3753d 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -161,7 +161,7 @@ static void deinit_drivers() void platform_video_init(void) { if (vid_mode == NULL) { - vid_mode = &vid_modes[2]; // Standard def 480p + vid_mode = &vid_modes[1]; // Standard def 480p } else { if (use_hires) { gsKit_hires_deinit_global(gsGlobal); @@ -219,6 +219,7 @@ void platform_video_init(void) int main(int argc, char **argv) { prepare_IOP(); + init_drivers(); // ReadSaveFile("sa2.sav"); @@ -233,6 +234,11 @@ int main(int argc, char **argv) cgb_audio_init(48000); VDraw(); + // while (true) { + // UpdateTexture(); + // gsKit_sync_flip(gsGlobal); + // gsKit_queue_exec(gsGlobal); + // } AgbMain(); return 0; @@ -260,11 +266,11 @@ void VBlankIntrWait(void) if (isRunning) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); -// Only render 30fps when in widescreen as the draw func is too slow for the ps2 -#if DISPLAY_WIDTH > 240 - skipFrame++; - skipFrame %= 2; -#endif + // Only render 30fps when in widescreen as the draw func is too slow for the ps2 + // #if DISPLAY_WIDTH > 240 + // skipFrame++; + // skipFrame %= 2; + // #endif if (skipFrame == 0) { VDraw(); } else { @@ -935,7 +941,6 @@ void UpdateTexture(void) gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0, 0, 0, 0, 0)); - // Table gsKit_prim_sprite_texture(gsGlobal, &screen, 0.0f, // X1 0.0f, // Y2 diff --git a/src/platform/shared/rendering/common.h b/src/platform/shared/rendering/common.h new file mode 100644 index 0000000000..7592b4218c --- /dev/null +++ b/src/platform/shared/rendering/common.h @@ -0,0 +1,143 @@ +/* gameplaySP + * + * Copyright (C) 2006 Exophase + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef COMMON_H +#define COMMON_H + +#define ror(dest, value, shift) dest = ((value) >> (shift)) | ((value) << (32 - (shift))) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#if defined(_WIN32) +#define PATH_SEPARATOR "\\" +#define PATH_SEPARATOR_CHAR '\\' +#else +#define PATH_SEPARATOR "/" +#define PATH_SEPARATOR_CHAR '/' +#endif + +/* On x86 we pass arguments via registers instead of stack */ +#ifdef X86_ARCH +#define function_cc __attribute__((regparm(2))) +#else +#define function_cc +#endif + +#ifdef ARM_ARCH + +#define _BSD_SOURCE // sync +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* ARM_ARCH */ + +// Huge thanks to pollux for the heads up on using native file I/O +// functions on PSP for vastly improved memstick performance. + +#ifdef PSP +#include +#include +#include +#include +#include +#include +#include +#include +#else +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short int u16; +typedef signed short int s16; +typedef unsigned int u32; +typedef signed int s32; +typedef unsigned long long int u64; +typedef signed long long int s64; +#endif + +#ifdef USE_BGR_FORMAT +#define convert_palette(value) (((value & 0x7FE0) << 1) | (value & 0x1F)) +#elif defined(USE_XBGR1555_FORMAT) +#define convert_palette(value) (value & 0x7FFF) +#else +#define convert_palette(value) (((value & 0x1F) << 11) | ((value & 0x03E0) << 1) | ((value >> 10) & 0x1F)) +#endif + +#define GBA_SCREEN_WIDTH (240) +#define GBA_SCREEN_HEIGHT (160) +#define GBA_SCREEN_PITCH (240) + +typedef u32 fixed16_16; +typedef u32 fixed8_24; + +#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) + +#define fp16_16_to_float(value) (float)((value) / 65536.0) + +#define u32_to_fp16_16(value) ((value) << 16) + +#define fp16_16_to_u32(value) ((value) >> 16) + +#define fp16_16_fractional_part(value) ((value)&0xFFFF) + +#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) + +#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) + +#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) + +#define address8(base, offset) *((u8 *)((u8 *)base + (offset))) + +#define address16(base, offset) *((u16 *)((u8 *)base + (offset))) + +#define address32(base, offset) *((u32 *)((u8 *)base + (offset))) + +#define eswap8(value) (value) +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define eswap16(value) __builtin_bswap16(value) +#define eswap32(value) __builtin_bswap32(value) +#else +#define eswap16(value) (value) +#define eswap32(value) (value) +#endif + +#define readaddress8(base, offset) eswap8(address8(base, offset)) +#define readaddress16(base, offset) eswap16(address16(base, offset)) +#define readaddress32(base, offset) eswap32(address32(base, offset)) + +#define read_ioreg(regnum) (eswap16(io_registers[(regnum)])) +#define write_ioreg(regnum, val) io_registers[(regnum)] = eswap16(val) +#define read_ioreg32(regnum) (read_ioreg(regnum) | (read_ioreg((regnum) + 1) << 16)) + +#define read_dmareg(regnum, dmachan) (eswap16(io_registers[(regnum) + (dmachan)*6])) +#define write_dmareg(regnum, dmachan, val) io_registers[(regnum) + (dmachan)*6] = eswap16(val) + +#include +#include +#include +#include +#include + +#endif \ No newline at end of file diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c index 9a1283d2e0..c2a839f0a9 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -1,24 +1,27 @@ -// sw_renderer_fast.c -- single-pass back-to-front gba ppu renderer -// -// the default renderer does multiple passes per scanline which thrashes -// the data cache on older platforms with tiny L1 and no L2 - -// this one composites everything in one pass per scanline, painting -// layers directly into the output buffer from back to front. a -// layerIds[] side-buffer tracks what wrote each pixel so alpha -// blending can find its target-b inline. -// -// 4bpp text bgs get a batched path that reads one u32 per 8 pixels. -// 8bpp and mosaic bgs fall back to per-pixel. sprites are pre-filtered -// per scanline so we only touch the ones that actually matter. +/* gameplaySP + * + * Copyright (C) 2006 Exophase + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "config.h" - #if RENDERER == RENDERER_SOFTWARE_FAST +#include "global.h" #include -#include -#include #include #include "global.h" @@ -26,1155 +29,3690 @@ #include "gba/defines.h" #include "gba/io_reg.h" #include "gba/types.h" + #include "platform/shared/dma.h" -#include "platform/shared/rendering/sw_renderer_common.h" -extern IntrFunc gIntrTable[16]; -extern uint8_t REG_BASE[IO_SIZE]; -extern uint16_t PLTT[PLTT_SIZE / sizeof(uint16_t)]; -extern uint8_t VRAM[VRAM_SIZE]; -extern uint8_t OAM[OAM_SIZE]; -extern const u8 gOamShapesSizes[12][2]; +#define eswap16(value) (value) +#define eswap32(value) (value) -#ifndef TILE_WIDTH -#define TILE_WIDTH 8 -#endif +#define GBA_SCREEN_PITCH DISPLAY_WIDTH + +typedef u32 fixed16_16; +typedef u32 fixed8_24; + +#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) + +#define fp16_16_to_float(value) (float)((value) / 65536.0) + +#define u32_to_fp16_16(value) ((value) << 16) + +#define fp16_16_to_u32(value) ((value) >> 16) + +#define fp16_16_fractional_part(value) ((value)&0xFFFF) + +#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) + +#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) + +#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) + +#define read_ioreg(regaddr) (eswap16(*(u16 *)(regaddr))) +#define read_ioreg32(regaddr) (read_ioreg(regaddr) | (read_ioreg((regaddr) + sizeof(u16)) << 16)) + +#define REG_ADDR_BGxCNT(n) (REG_ADDR_BG0CNT + ((n) * sizeof(u16))) + +#define convert_palette(value) (value & 0x7FFF) + +u16 *gba_screen_pixels = NULL; + +#define get_screen_pixels() gba_screen_pixels +#define get_screen_pitch() GBA_SCREEN_PITCH + +typedef struct { + u16 attr0, attr1, attr2, attr3; +} t_oam; + +void update_scanline(void); +void video_reload_counters(void); + +extern s32 affine_reference_x[2]; +extern s32 affine_reference_y[2]; + +typedef void (*tile_render_function)(u32 layer_number, u32 start, u32 end, void *dest_ptr); +typedef void (*bitmap_render_function)(u32 start, u32 end, void *dest_ptr); + +typedef struct { + tile_render_function normal_render_base; + tile_render_function normal_render_transparent; + tile_render_function alpha_render_base; + tile_render_function alpha_render_transparent; + tile_render_function color16_render_base; + tile_render_function color16_render_transparent; + tile_render_function color32_render_base; + tile_render_function color32_render_transparent; +} tile_layer_render_struct; + +typedef struct { + bitmap_render_function normal_render; +} bitmap_layer_render_struct; + +typedef enum { filter_nearest, filter_bilinear } video_filter_type; + +static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, + const tile_layer_render_struct *layer_renderers); +static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, + const bitmap_layer_render_struct *layer_renderers); + +#define tile_expand_base_normal(index) \ + current_pixel = palette[current_pixel]; \ + dest_ptr[index] = current_pixel + +#define tile_expand_base_normal_mode4(index) \ + if (current_pixel != 0) { \ + current_pixel = palette[current_pixel]; \ + dest_ptr[index] = current_pixel; \ + } + +#define tile_expand_transparent_normal(index) tile_expand_base_normal(index) + +#define tile_expand_copy(index) dest_ptr[index] = copy_ptr[index] + +#define advance_dest_ptr_base(delta) dest_ptr += delta + +#define advance_dest_ptr_transparent(delta) advance_dest_ptr_base(delta) + +#define advance_dest_ptr_copy(delta) \ + advance_dest_ptr_base(delta); \ + copy_ptr += delta + +#define color_combine_mask_a(layer) ((read_ioreg(REG_ADDR_BLDCNT) >> layer) & 0x01) + +// For color blending operations, will create a mask that has in bit +// 10 if the layer is target B, and bit 9 if the layer is target A. + +#define color_combine_mask(layer) (color_combine_mask_a(layer) | ((read_ioreg(REG_ADDR_BLDCNT) >> (layer + 7)) & 0x02)) << 9 + +// For alpha blending renderers, draw the palette index (9bpp) and +// layer bits rather than the raw RGB. For the base this should write to +// the 32bit location directly. + +#define tile_expand_base_alpha(index) dest_ptr[index] = current_pixel | pixel_combine + +#define tile_expand_base_bg(index) dest_ptr[index] = bg_combine + +// For layered (transparent) writes this should shift the "stack" and write +// to the bottom. This will preserve the topmost pixel and the most recent +// one. + +#define tile_expand_transparent_alpha(index) dest_ptr[index] = (dest_ptr[index] << 16) | current_pixel | pixel_combine + +// OBJ should only shift if the top isn't already OBJ +#define tile_expand_transparent_alpha_obj(index) \ + dest = dest_ptr[index]; \ + if (dest & 0x00000100) \ + dest_ptr[index] = (dest & 0xFFFF0000) | current_pixel | pixel_combine; \ + else \ + dest_ptr[index] = (dest << 16) | current_pixel | pixel_combine; + +// For color effects that don't need to preserve the previous layer. +// The color32 version should be used with 32bit wide dest_ptr so as to be +// compatible with alpha combine on top of it. + +#define tile_expand_base_color16(index) dest_ptr[index] = current_pixel | pixel_combine + +#define tile_expand_transparent_color16(index) tile_expand_base_color16(index) + +#define tile_expand_base_color32(index) tile_expand_base_color16(index) + +#define tile_expand_transparent_color32(index) tile_expand_base_color16(index) + +// Operations for isolation 8bpp pixels within 32bpp pixel blocks. + +#define tile_8bpp_pixel_op_mask(op_param) current_pixel = current_pixels & 0xFF + +#define tile_8bpp_pixel_op_shift_mask(shift) current_pixel = (current_pixels >> shift) & 0xFF + +#define tile_8bpp_pixel_op_shift(shift) current_pixel = current_pixels >> shift + +#define tile_8bpp_pixel_op_none(shift) + +// Base should always draw raw in 8bpp mode; color 0 will be drawn where +// color 0 is. + +#define tile_8bpp_draw_base_normal(index) tile_expand_base_normal(index) + +#define tile_8bpp_draw_base_alpha(index) \ + if (current_pixel) { \ + tile_expand_base_alpha(index); \ + } else { \ + tile_expand_base_bg(index); \ + } + +#define tile_8bpp_draw_base_color16(index) tile_8bpp_draw_base_alpha(index) + +#define tile_8bpp_draw_base_color32(index) tile_8bpp_draw_base_alpha(index) + +#define tile_8bpp_draw_base(index, op, op_param, alpha_op) \ + tile_8bpp_pixel_op_##op(op_param); \ + tile_8bpp_draw_base_##alpha_op(index) + +// Transparent (layered) writes should only replace what is there if the +// pixel is not transparent (zero) + +#define tile_8bpp_draw_transparent(index, op, op_param, alpha_op) \ + tile_8bpp_pixel_op_##op(op_param); \ + if (current_pixel) { \ + tile_expand_transparent_##alpha_op(index); \ + } + +#define tile_8bpp_draw_copy(index, op, op_param, alpha_op) \ + tile_8bpp_pixel_op_##op(op_param); \ + if (current_pixel) { \ + tile_expand_copy(index); \ + } + +// Get the current tile from the map in 8bpp mode + +#define get_tile_8bpp() \ + current_tile = eswap16(*map_ptr); \ + tile_ptr = tile_base + ((current_tile & 0x3FF) * 64) + +// Draw half of a tile in 8bpp mode, for base renderer + +#define tile_8bpp_draw_four_noflip(index, combine_op, alpha_op) \ + tile_8bpp_draw_##combine_op(index + 0, mask, 0, alpha_op); \ + tile_8bpp_draw_##combine_op(index + 1, shift_mask, 8, alpha_op); \ + tile_8bpp_draw_##combine_op(index + 2, shift_mask, 16, alpha_op); \ + tile_8bpp_draw_##combine_op(index + 3, shift, 24, alpha_op) + +// Like the above, but draws the half-tile horizontally flipped + +#define tile_8bpp_draw_four_flip(index, combine_op, alpha_op) \ + tile_8bpp_draw_##combine_op(index + 3, mask, 0, alpha_op); \ + tile_8bpp_draw_##combine_op(index + 2, shift_mask, 8, alpha_op); \ + tile_8bpp_draw_##combine_op(index + 1, shift_mask, 16, alpha_op); \ + tile_8bpp_draw_##combine_op(index + 0, shift, 24, alpha_op) + +#define tile_8bpp_draw_four_base(index, alpha_op, flip_op) tile_8bpp_draw_four_##flip_op(index, base, alpha_op) + +// Draw half of a tile in 8bpp mode, for transparent renderer; as an +// optimization the entire thing is checked against zero (in transparent +// capable renders it is more likely for the pixels to be transparent than +// opaque) + +#define tile_8bpp_draw_four_transparent(index, alpha_op, flip_op) \ + if (current_pixels != 0) { \ + tile_8bpp_draw_four_##flip_op(index, transparent, alpha_op); \ + } + +#define tile_8bpp_draw_four_copy(index, alpha_op, flip_op) \ + if (current_pixels != 0) { \ + tile_8bpp_draw_four_##flip_op(index, copy, alpha_op); \ + } + +// Helper macro for drawing 8bpp tiles clipped against the edge of the screen + +#define partial_tile_8bpp(combine_op, alpha_op) \ + for (i = 0; i < partial_tile_run; i++) { \ + tile_8bpp_draw_##combine_op(0, mask, 0, alpha_op); \ + current_pixels >>= 8; \ + advance_dest_ptr_##combine_op(1); \ + } + +// Draws 8bpp tiles clipped against the left side of the screen, +// partial_tile_offset indicates how much clipped in it is, partial_tile_run +// indicates how much it should draw. + +#define partial_tile_right_noflip_8bpp(combine_op, alpha_op) \ + if (partial_tile_offset >= 4) { \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) >> ((partial_tile_offset - 4) * 8); \ + partial_tile_8bpp(combine_op, alpha_op); \ + } else { \ + partial_tile_run -= 4; \ + current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 8); \ + partial_tile_8bpp(combine_op, alpha_op); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ + tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ + advance_dest_ptr_##combine_op(4); \ + } + +// Draws 8bpp tiles clipped against both the left and right side of the +// screen, IE, runs of less than 8 - partial_tile_offset. + +#define partial_tile_mid_noflip_8bpp(combine_op, alpha_op) \ + if (partial_tile_offset >= 4) { \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) >> ((partial_tile_offset - 4) * 8); \ + } else { \ + current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 8); \ + if ((partial_tile_offset + partial_tile_run) > 4) { \ + u32 old_run = partial_tile_run; \ + partial_tile_run = 4 - partial_tile_offset; \ + partial_tile_8bpp(combine_op, alpha_op); \ + partial_tile_run = old_run - partial_tile_run; \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ + } \ + } \ + partial_tile_8bpp(combine_op, alpha_op); + +// Draws 8bpp tiles clipped against the right side of the screen, +// partial_tile_run indicates how much there is to draw. + +#define partial_tile_left_noflip_8bpp(combine_op, alpha_op) \ + if (partial_tile_run >= 4) { \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ + advance_dest_ptr_##combine_op(4); \ + tile_ptr += 4; \ + partial_tile_run -= 4; \ + } \ + \ + current_pixels = eswap32(*((u32 *)(tile_ptr))); \ + partial_tile_8bpp(combine_op, alpha_op) + +// Draws a non-clipped (complete) 8bpp tile. + +#define tile_noflip_8bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ + tile_8bpp_draw_four_##combine_op(4, alpha_op, noflip) + +// Like the above versions but draws flipped tiles. + +#define partial_tile_flip_8bpp(combine_op, alpha_op) \ + for (i = 0; i < partial_tile_run; i++) { \ + tile_8bpp_draw_##combine_op(0, shift, 24, alpha_op); \ + current_pixels <<= 8; \ + advance_dest_ptr_##combine_op(1); \ + } + +#define partial_tile_right_flip_8bpp(combine_op, alpha_op) \ + if (partial_tile_offset >= 4) { \ + current_pixels = eswap32(*((u32 *)tile_ptr)) << ((partial_tile_offset - 4) * 8); \ + partial_tile_flip_8bpp(combine_op, alpha_op); \ + } else { \ + partial_tile_run -= 4; \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) << ((partial_tile_offset - 4) * 8); \ + partial_tile_flip_8bpp(combine_op, alpha_op); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ + advance_dest_ptr_##combine_op(4); \ + } + +#define partial_tile_mid_flip_8bpp(combine_op, alpha_op) \ + if (partial_tile_offset >= 4) \ + current_pixels = eswap32(*((u32 *)tile_ptr)) << ((partial_tile_offset - 4) * 8); \ + else { \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) << ((partial_tile_offset - 4) * 8); \ + \ + if ((partial_tile_offset + partial_tile_run) > 4) { \ + u32 old_run = partial_tile_run; \ + partial_tile_run = 4 - partial_tile_offset; \ + partial_tile_flip_8bpp(combine_op, alpha_op); \ + partial_tile_run = old_run - partial_tile_run; \ + current_pixels = eswap32(*((u32 *)(tile_ptr))); \ + } \ + } \ + partial_tile_flip_8bpp(combine_op, alpha_op); + +#define partial_tile_left_flip_8bpp(combine_op, alpha_op) \ + if (partial_tile_run >= 4) { \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ + tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ + advance_dest_ptr_##combine_op(4); \ + tile_ptr -= 4; \ + partial_tile_run -= 4; \ + } \ + \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ + partial_tile_flip_8bpp(combine_op, alpha_op) + +#define tile_flip_8bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ + tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + tile_8bpp_draw_four_##combine_op(4, alpha_op, flip) + +// Operations for isolating 4bpp tiles in a 32bit block + +#define tile_4bpp_pixel_op_mask(op_param) current_pixel = current_pixels & 0x0F + +#define tile_4bpp_pixel_op_shift_mask(shift) current_pixel = (current_pixels >> shift) & 0x0F + +#define tile_4bpp_pixel_op_shift(shift) current_pixel = current_pixels >> shift + +#define tile_4bpp_pixel_op_none(op_param) + +// Draws a single 4bpp pixel as base, normal renderer; checks to see if the +// pixel is zero because if so the current palette should not be applied. +// These ifs can be replaced with a lookup table, may or may not be superior +// this way, should be benchmarked. The lookup table would be from 0-255 +// identity map except for multiples of 16, which would map to 0. + +#define tile_4bpp_draw_base_normal(index) \ + if (current_pixel) \ + current_pixel |= current_palette; \ + tile_expand_base_normal(index); + +#define tile_4bpp_draw_base_alpha(index) \ + if (current_pixel) { \ + current_pixel |= current_palette; \ + tile_expand_base_alpha(index); \ + } else { \ + tile_expand_base_bg(index); \ + } + +#define tile_4bpp_draw_base_color16(index) tile_4bpp_draw_base_alpha(index) + +#define tile_4bpp_draw_base_color32(index) tile_4bpp_draw_base_alpha(index) + +#define tile_4bpp_draw_base(index, op, op_param, alpha_op) \ + tile_4bpp_pixel_op_##op(op_param); \ + tile_4bpp_draw_base_##alpha_op(index) + +// Draws a single 4bpp pixel as layered, if not transparent. + +#define tile_4bpp_draw_transparent(index, op, op_param, alpha_op) \ + tile_4bpp_pixel_op_##op(op_param); \ + if (current_pixel) { \ + current_pixel |= current_palette; \ + tile_expand_transparent_##alpha_op(index); \ + } + +#define tile_4bpp_draw_copy(index, op, op_param, alpha_op) \ + tile_4bpp_pixel_op_##op(op_param); \ + if (current_pixel) { \ + current_pixel |= current_palette; \ + tile_expand_copy(index); \ + } + +// Draws eight background pixels in transparent mode, for alpha or normal +// renderers. + +#define tile_4bpp_draw_eight_base_zero(value) \ + dest_ptr[0] = value; \ + dest_ptr[1] = value; \ + dest_ptr[2] = value; \ + dest_ptr[3] = value; \ + dest_ptr[4] = value; \ + dest_ptr[5] = value; \ + dest_ptr[6] = value; \ + dest_ptr[7] = value + +// Draws eight background pixels for the alpha renderer, basically color zero +// with the background flag high. + +#define tile_4bpp_draw_eight_base_zero_alpha() tile_4bpp_draw_eight_base_zero(bg_combine) + +#define tile_4bpp_draw_eight_base_zero_color16() tile_4bpp_draw_eight_base_zero_alpha() + +#define tile_4bpp_draw_eight_base_zero_color32() tile_4bpp_draw_eight_base_zero_alpha() + +// Draws eight background pixels for the normal renderer, just a bunch of +// zeros. + +#define tile_4bpp_draw_eight_base_zero_normal() \ + current_pixel = palette[0]; \ + tile_4bpp_draw_eight_base_zero(current_pixel) + +// Draws eight 4bpp pixels. + +#define tile_4bpp_draw_eight_noflip(combine_op, alpha_op) \ + tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \ + tile_4bpp_draw_##combine_op(1, shift_mask, 4, alpha_op); \ + tile_4bpp_draw_##combine_op(2, shift_mask, 8, alpha_op); \ + tile_4bpp_draw_##combine_op(3, shift_mask, 12, alpha_op); \ + tile_4bpp_draw_##combine_op(4, shift_mask, 16, alpha_op); \ + tile_4bpp_draw_##combine_op(5, shift_mask, 20, alpha_op); \ + tile_4bpp_draw_##combine_op(6, shift_mask, 24, alpha_op); \ + tile_4bpp_draw_##combine_op(7, shift, 28, alpha_op) + +// Draws eight 4bpp pixels in reverse order (for hflip). + +#define tile_4bpp_draw_eight_flip(combine_op, alpha_op) \ + tile_4bpp_draw_##combine_op(7, mask, 0, alpha_op); \ + tile_4bpp_draw_##combine_op(6, shift_mask, 4, alpha_op); \ + tile_4bpp_draw_##combine_op(5, shift_mask, 8, alpha_op); \ + tile_4bpp_draw_##combine_op(4, shift_mask, 12, alpha_op); \ + tile_4bpp_draw_##combine_op(3, shift_mask, 16, alpha_op); \ + tile_4bpp_draw_##combine_op(2, shift_mask, 20, alpha_op); \ + tile_4bpp_draw_##combine_op(1, shift_mask, 24, alpha_op); \ + tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op) + +// Draws eight 4bpp pixels in base mode, checks if all are zero, if so draws +// the appropriate background pixels. + +#define tile_4bpp_draw_eight_base(alpha_op, flip_op) \ + if (current_pixels != 0) { \ + tile_4bpp_draw_eight_##flip_op(base, alpha_op); \ + } else { \ + tile_4bpp_draw_eight_base_zero_##alpha_op(); \ + } + +// Draws eight 4bpp pixels in transparent (layered) mode, checks if all are +// zero and if so draws nothing. + +#define tile_4bpp_draw_eight_transparent(alpha_op, flip_op) \ + if (current_pixels != 0) { \ + tile_4bpp_draw_eight_##flip_op(transparent, alpha_op); \ + } + +#define tile_4bpp_draw_eight_copy(alpha_op, flip_op) \ + if (current_pixels != 0) { \ + tile_4bpp_draw_eight_##flip_op(copy, alpha_op); \ + } + +// Gets the current tile in 4bpp mode, also getting the current palette and +// the pixel block. + +#define get_tile_4bpp() \ + current_tile = eswap16(*map_ptr); \ + current_palette = (current_tile >> 12) << 4; \ + tile_ptr = tile_base + ((current_tile & 0x3FF) * 32); + +// Helper macro for drawing clipped 4bpp tiles. + +#define partial_tile_4bpp(combine_op, alpha_op) \ + for (i = 0; i < partial_tile_run; i++) { \ + tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \ + current_pixels >>= 4; \ + advance_dest_ptr_##combine_op(1); \ + } + +// Draws a 4bpp tile clipped against the left edge of the screen. +// partial_tile_offset is how far in it's clipped, partial_tile_run is +// how many to draw. + +#define partial_tile_right_noflip_4bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 4); \ + partial_tile_4bpp(combine_op, alpha_op) + +// Draws a 4bpp tile clipped against both edges of the screen, same as right. + +#define partial_tile_mid_noflip_4bpp(combine_op, alpha_op) partial_tile_right_noflip_4bpp(combine_op, alpha_op) + +// Draws a 4bpp tile clipped against the right edge of the screen. +// partial_tile_offset is how many to draw. + +#define partial_tile_left_noflip_4bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + partial_tile_4bpp(combine_op, alpha_op) + +// Draws a complete 4bpp tile row (not clipped) +#define tile_noflip_4bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + tile_4bpp_draw_eight_##combine_op(alpha_op, noflip) + +// Like the above, but draws flipped tiles. + +#define partial_tile_flip_4bpp(combine_op, alpha_op) \ + for (i = 0; i < partial_tile_run; i++) { \ + tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op); \ + current_pixels <<= 4; \ + advance_dest_ptr_##combine_op(1); \ + } + +#define partial_tile_right_flip_4bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)) << (partial_tile_offset * 4); \ + partial_tile_flip_4bpp(combine_op, alpha_op) + +#define partial_tile_mid_flip_4bpp(combine_op, alpha_op) partial_tile_right_flip_4bpp(combine_op, alpha_op) + +#define partial_tile_left_flip_4bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + partial_tile_flip_4bpp(combine_op, alpha_op) + +#define tile_flip_4bpp(combine_op, alpha_op) \ + current_pixels = eswap32(*((u32 *)tile_ptr)); \ + tile_4bpp_draw_eight_##combine_op(alpha_op, flip) + +// Draws a single (partial or complete) tile from the tilemap, flipping +// as necessary. + +#define single_tile_map(tile_type, combine_op, color_depth, alpha_op) \ + get_tile_##color_depth(); \ + if (current_tile & 0x800) \ + tile_ptr += vertical_pixel_flip; \ + \ + if (current_tile & 0x400) { \ + tile_type##_flip_##color_depth(combine_op, alpha_op); \ + } else { \ + tile_type##_noflip_##color_depth(combine_op, alpha_op); \ + } + +#define single_tile_map_base_4bpp_color16(tile_type) \ + get_tile_4bpp(); \ + if (current_tile & 0x800) \ + tile_ptr += vertical_pixel_flip; \ + \ + if (current_tile & 0x400) { \ + tile_type##_flip_4bpp(base, color16); \ + } else { \ + tile_type##_noflip_4bpp(base, color16); \ + } + +// Draws multiple sequential tiles from the tilemap, hflips and vflips as +// necessary. + +#define multiple_tile_map(combine_op, color_depth, alpha_op) \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, combine_op, color_depth, alpha_op); \ + advance_dest_ptr_##combine_op(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_transparent_8bpp_color16() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, transparent, 8bpp, color16); \ + advance_dest_ptr_transparent(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_transparent_4bpp_color16() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, transparent, 4bpp, color16); \ + advance_dest_ptr_transparent(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_base_8bpp_color16() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, base, 8bpp, color16); \ + advance_dest_ptr_base(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_base_4bpp_color16() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map_base_4bpp_color16(tile); \ + advance_dest_ptr_base(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_transparent_8bpp_normal() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, transparent, 8bpp, normal); \ + advance_dest_ptr_transparent(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_transparent_4bpp_normal() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, transparent, 4bpp, normal); \ + advance_dest_ptr_transparent(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_base_8bpp_normal() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, base, 8bpp, normal); \ + advance_dest_ptr_base(8); \ + map_ptr++; \ + } + +#define multiple_tile_map_base_4bpp_normal() \ + for (i = 0; i < tile_run; i++) { \ + single_tile_map(tile, base, 4bpp, normal); \ + advance_dest_ptr_base(8); \ + map_ptr++; \ + } + +// Draws a partial tile from a tilemap clipped against the left edge of the +// screen. + +#define partial_tile_right_map(combine_op, color_depth, alpha_op) \ + single_tile_map(partial_tile_right, combine_op, color_depth, alpha_op); \ + map_ptr++ + +// Draws a partial tile from a tilemap clipped against both edges of the +// screen. + +#define partial_tile_mid_map(combine_op, color_depth, alpha_op) single_tile_map(partial_tile_mid, combine_op, color_depth, alpha_op) + +// Draws a partial tile from a tilemap clipped against the right edge of the +// screen. + +#define partial_tile_left_map(combine_op, color_depth, alpha_op) single_tile_map(partial_tile_left, combine_op, color_depth, alpha_op) + +// Advances a non-flipped 4bpp obj to the next tile. + +#define obj_advance_noflip_4bpp() tile_ptr += 32 + +// Advances a non-flipped 8bpp obj to the next tile. + +#define obj_advance_noflip_8bpp() tile_ptr += 64 + +// Advances a flipped 4bpp obj to the next tile. + +#define obj_advance_flip_4bpp() tile_ptr -= 32 + +// Advances a flipped 8bpp obj to the next tile. + +#define obj_advance_flip_8bpp() tile_ptr -= 64 + +// Draws multiple sequential tiles from an obj, flip_op determines if it should +// be flipped or not (set to flip or noflip) + +#define multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op) \ + for (i = 0; i < tile_run; i++) { \ + tile_##flip_op##_##color_depth(combine_op, alpha_op); \ + obj_advance_##flip_op##_##color_depth(); \ + advance_dest_ptr_##combine_op(8); \ + } + +// Draws an obj's tile clipped against the left side of the screen + +#define partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op) \ + partial_tile_right_##flip_op##_##color_depth(combine_op, alpha_op); \ + obj_advance_##flip_op##_##color_depth() + +// Draws an obj's tile clipped against both sides of the screen + +#define partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op) partial_tile_mid_##flip_op##_##color_depth(combine_op, alpha_op) + +// Draws an obj's tile clipped against the right side of the screen + +#define partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op) partial_tile_left_##flip_op##_##color_depth(combine_op, alpha_op) + +// Extra variables specific for 8bpp/4bpp tile renderers. + +#define tile_extra_variables_8bpp() + +#define tile_extra_variables_4bpp() u32 current_palette + +// Byte lengths of complete tiles and tile rows in 4bpp and 8bpp. + +#define tile_width_4bpp 4 +#define tile_size_4bpp 32 +#define tile_width_8bpp 8 +#define tile_size_8bpp 64 + +#define render_scanline_dest_normal u16 +#define render_scanline_dest_alpha u32 +#define render_scanline_dest_alpha_obj u32 +#define render_scanline_dest_color16 u16 +#define render_scanline_dest_color32 u32 +#define render_scanline_dest_partial_alpha u32 +#define render_scanline_dest_copy_tile u16 +#define render_scanline_dest_copy_bitmap u16 + +// If rendering a scanline that is not a target A then there's no point in +// keeping what's underneath it because it can't blend with it. + +#define render_scanline_skip_alpha(bg_type, combine_op) \ + if ((pixel_combine & 0x00000200) == 0) { \ + render_scanline_##bg_type##_##combine_op##_color32(layer, start, end, scanline); \ + return; \ + } + +#define render_scanline_extra_variables_base_normal(bg_type) u16 *palette = PLTT + +#define render_scanline_extra_variables_base_alpha(bg_type) \ + u32 bg_combine = color_combine_mask(5); \ + u32 pixel_combine = color_combine_mask(layer) | (bg_combine << 16); \ + render_scanline_skip_alpha(bg_type, base) + +#define render_scanline_extra_variables_base_color() \ + u32 bg_combine = color_combine_mask(5); \ + u32 pixel_combine = color_combine_mask(layer) + +#define render_scanline_extra_variables_base_color16(bg_type) render_scanline_extra_variables_base_color() + +#define render_scanline_extra_variables_base_color32(bg_type) render_scanline_extra_variables_base_color() + +#define render_scanline_extra_variables_transparent_normal(bg_type) render_scanline_extra_variables_base_normal(bg_type) + +#define render_scanline_extra_variables_transparent_alpha(bg_type) \ + u32 pixel_combine = color_combine_mask(layer); \ + render_scanline_skip_alpha(bg_type, transparent) + +#define render_scanline_extra_variables_transparent_color() u32 pixel_combine = color_combine_mask(layer) + +#define render_scanline_extra_variables_transparent_color16(bg_type) render_scanline_extra_variables_transparent_color() + +#define render_scanline_extra_variables_transparent_color32(bg_type) render_scanline_extra_variables_transparent_color() + +static const u32 map_widths[] = { 256, 512, 256, 512 }; + +static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void *scanline) +{ + render_scanline_extra_variables_base_normal(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_normal *dest_ptr = ((render_scanline_dest_normal *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } + + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: base + * alpha : normal + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + + tile_extra_variables_8bpp(); + + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 8bpp, normal); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 8bpp, normal); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 8bpp, normal); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_base_8bpp_normal(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_base_8bpp_normal(); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(base, 8bpp, normal); + } + } else { + /* color depth: 4bpp + * combine: base + * alpha : normal + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + + tile_extra_variables_4bpp(); + + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 4bpp, normal); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 4bpp, normal); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 4bpp, normal); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_base_4bpp_normal(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_base_4bpp_normal(); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(base, 4bpp, normal); + } + } +} + +static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 end, void *scanline) +{ + render_scanline_extra_variables_transparent_normal(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_normal *dest_ptr = ((render_scanline_dest_normal *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } + + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: transparent + * alpha : normal + */ + + /* Render a single scanline of text tiles */ + + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 8bpp, normal); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 8bpp, normal); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 8bpp, normal); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_transparent_8bpp_normal(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_transparent_8bpp_normal(); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(transparent, 8bpp, normal); + } + } else { + /* color depth: 4bpp + * combine: transparent + * alpha : normal + */ + + /* Render a single scanline of text tiles */ + + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 4bpp, normal); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 4bpp, normal); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 4bpp, normal); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_transparent_4bpp_normal(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_transparent_4bpp_normal(); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(transparent, 4bpp, normal); + } + } +} + +static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, void *scanline) +{ + render_scanline_extra_variables_base_color16(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_color16 *dest_ptr = ((render_scanline_dest_color16 *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } + + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: base + * alpha :color16 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 8bpp, color16); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 8bpp, color16); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 8bpp, color16); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_base_8bpp_color16(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_base_8bpp_color16(); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(base, 8bpp, color16); + } + } else { + /* color depth: 4bpp + * combine: base + * alpha :color16 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 4bpp, color16); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 4bpp, color16); + } + } + + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 4bpp, color16); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_base_4bpp_color16(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_base_4bpp_color16(); + + partial_tile_run = end % 8; + + if (partial_tile_run) { + partial_tile_left_map(base, 4bpp, color16); + } + } +} + +static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 end, void *scanline) +{ + render_scanline_extra_variables_transparent_color16(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_color16 *dest_ptr = ((render_scanline_dest_color16 *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } + + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: transparent + * alpha :color16 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 8bpp, color16); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 8bpp, color16); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 8bpp, color16); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_transparent_8bpp_color16(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_transparent_8bpp_color16(); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(transparent, 8bpp, color16); + } + } else { + /* color depth: 4bpp + * combine: transparent + * alpha :color16 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 4bpp, color16); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 4bpp, color16); + } + } + + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 4bpp, color16); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map_transparent_4bpp_color16(); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map_transparent_4bpp_color16(); + + partial_tile_run = end % 8; + + if (partial_tile_run) { + partial_tile_left_map(transparent, 4bpp, color16); + } + } +} + +static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, void *scanline) +{ + render_scanline_extra_variables_base_color32(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_color32 *dest_ptr = ((render_scanline_dest_color32 *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } + + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: base + * alpha :color32 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 8bpp, color32); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 8bpp, color32); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 8bpp, color32); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(base, 8bpp, color32); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map(base, 8bpp, color32); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(base, 8bpp, color32); + } + } else { + /* color depth: 4bpp + * combine: base + * alpha :color32 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 4bpp, color32); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 4bpp, color32); + } + } + + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 4bpp, color32); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(base, 4bpp, color32); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map(base, 4bpp, color32); + + partial_tile_run = end % 8; + + if (partial_tile_run) { + partial_tile_left_map(base, 4bpp, color32); + } + } +} + +static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 end, void *scanline) +{ + render_scanline_extra_variables_transparent_color32(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_color32 *dest_ptr = ((render_scanline_dest_color32 *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } + + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: transparent + * alpha :color32 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 8bpp, color32); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 8bpp, color32); + } + } -#define IsBGEnabled(n) (((REG_DISPCNT >> 8) & 0xF) & (1 << (n))) - -// mosaic -#define MOSAIC_BG_X (REG_MOSAIC & 0xF) -#define MOSAIC_BG_Y ((REG_MOSAIC >> 4) & 0xF) -#define MOSAIC_SPR_X ((REG_MOSAIC >> 8) & 0xF) -#define MOSAIC_SPR_Y ((REG_MOSAIC >> 12) & 0xF) -#define ApplyMosaicBGX(x) ((x) - ((x) % (MOSAIC_BG_X + 1))) -#define ApplyMosaicBGY(y) ((y) - ((y) % (MOSAIC_BG_Y + 1))) -#define ApplyMosaicSprX(x) ((x) - ((x) % (MOSAIC_SPR_X + 1))) -#define ApplyMosaicSprY(y) ((y) - ((y) % (MOSAIC_SPR_Y + 1))) - -// tilemap entry fields -#define TILE_NUM(e) ((e)&0x3FF) -#define TILE_PALETTE(e) (((e) >> 12) & 0xF) -#define TILE_HFLIP(e) ((e) & (1 << 10)) -#define TILE_VFLIP(e) ((e) & (1 << 11)) - -// window mask bits -#define WINMASK_BG0 (1 << 0) -#define WINMASK_BG1 (1 << 1) -#define WINMASK_BG2 (1 << 2) -#define WINMASK_BG3 (1 << 3) -#define WINMASK_OBJ (1 << 4) -#define WINMASK_CLR (1 << 5) -#define WINMASK_WINOUT (1 << 6) - -// layer ids for blend target tracking -#define LAYER_BG0 0 -#define LAYER_BG1 1 -#define LAYER_BG2 2 -#define LAYER_BG3 3 -#define LAYER_OBJ 4 -#define LAYER_BACKDROP 5 - -static const uint16_t bgMapSizes[][2] = { - { 32, 32 }, - { 64, 32 }, - { 32, 64 }, - { 64, 64 }, -}; + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 8bpp, color32); + } -// 16-bit fill using 32-bit writes -static inline void Memset16(uint16_t *dst, uint16_t fill, unsigned int count) -{ - uint32_t fill32 = ((uint32_t)fill << 16) | fill; - uint32_t *dst32 = (uint32_t *)dst; - unsigned int pairs = count >> 1; - for (unsigned int i = 0; i < pairs; i++) - dst32[i] = fill32; - if (count & 1) - dst[count - 1] = fill; -} + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(transparent, 8bpp, color32); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map(transparent, 8bpp, color32); -static inline uint32_t GetBgRefX(int bg) { return (bg == 2) ? REG_BG2X : (bg == 3) ? REG_BG3X : 0; } -static inline uint32_t GetBgRefY(int bg) { return (bg == 2) ? REG_BG2Y : (bg == 3) ? REG_BG3Y : 0; } -static inline uint16_t GetBgPA(int bg) { return (bg == 2) ? REG_BG2PA : (bg == 3) ? REG_BG3PA : 0; } -static inline uint16_t GetBgPB(int bg) { return (bg == 2) ? REG_BG2PB : (bg == 3) ? REG_BG3PB : 0; } -static inline uint16_t GetBgPC(int bg) { return (bg == 2) ? REG_BG2PC : (bg == 3) ? REG_BG3PC : 0; } -static inline uint16_t GetBgPD(int bg) { return (bg == 2) ? REG_BG2PD : (bg == 3) ? REG_BG3PD : 0; } + partial_tile_run = end % 8; -// handles the wraparound case where left > right -static inline bool WindowContainsX(u16 left, u16 right, u16 x) -{ - if (left > right) - return (x >= left || x < right); - return (x >= left && x < right); -} + if (partial_tile_run) { + partial_tile_left_map(transparent, 8bpp, color32); + } + } else { + /* color depth: 4bpp + * combine: transparent + * alpha :color32 + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 4bpp, color32); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 4bpp, color32); + } + } -// check if a layer can be the target-b for alpha blending -static inline bool IsBlendTargetB(uint8_t layerId, unsigned int bldcnt) -{ - if (layerId <= 3) - return (bldcnt & (1 << (8 + layerId))) != 0; - if (layerId == LAYER_OBJ) - return (bldcnt & BLDCNT_TGT2_OBJ) != 0; - if (layerId == LAYER_BACKDROP) - return (bldcnt & BLDCNT_TGT2_BD) != 0; - return false; -} + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 4bpp, color32); + } -// sprites with oam mode 1 always try alpha blending regardless of bldcnt -static inline uint16_t BlendSpritePixel(uint16_t color, unsigned int x, uint16_t *output, uint8_t *layerIds, bool isSemiTransparent, - unsigned int blendMode, unsigned int bldcnt, bool windowsEnabled, uint16_t *winMask, - unsigned int eva, unsigned int evb, unsigned int evy) -{ - bool winAllowsBlend = !windowsEnabled || (winMask && (winMask[x] & WINMASK_CLR)); + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(transparent, 4bpp, color32); + map_ptr = second_ptr; + end -= pixel_run; + } + tile_run = end / 8; + multiple_tile_map(transparent, 4bpp, color32); - bool doAlpha = (blendMode == 1 && (bldcnt & BLDCNT_TGT1_OBJ) && winAllowsBlend) || isSemiTransparent; + partial_tile_run = end % 8; - if (doAlpha) { - if (IsBlendTargetB(layerIds[x], bldcnt)) - return alphaBlendColor(color, output[x], eva, evb); - } else if ((bldcnt & BLDCNT_TGT1_OBJ) && winAllowsBlend) { - if (blendMode == 2) - return alphaBrightnessIncrease(color, evy); - if (blendMode == 3) - return alphaBrightnessDecrease(color, evy); + if (partial_tile_run) { + partial_tile_left_map(transparent, 4bpp, color32); + } } - - return color; } -// write a bg pixel with inline blend resolution -static inline void WriteBGPixelBlended(unsigned int x, uint8_t pixel, const uint16_t *palBase, int bgNum, uint16_t *output, - uint8_t *layerIds, unsigned int blendMode, bool bgIsTargetA, bool useWindows, unsigned int winBgBit, - uint16_t *winMask, unsigned int bldcnt, unsigned int eva, unsigned int evb, unsigned int evy) +static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void *scanline) { - uint16_t color = palBase[pixel] | COLOR_OPAQUE; - - if (useWindows && !(winMask[x] & winBgBit)) - return; - - if (bgIsTargetA && (!useWindows || (winMask[x] & WINMASK_CLR))) { - uint16_t src = color; - switch (blendMode) { - case 1: - if (IsBlendTargetB(layerIds[x], bldcnt)) - color = alphaBlendColor(src, output[x], eva, evb); - break; - case 2: - color = alphaBrightnessIncrease(src, evy); - break; - case 3: - color = alphaBrightnessDecrease(src, evy); - break; - } + render_scanline_extra_variables_base_alpha(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_alpha *dest_ptr = ((render_scanline_dest_alpha *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); } - output[x] = color; - layerIds[x] = bgNum; -} + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } -static void RenderTextBG(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *output) -{ - unsigned int charBase = (control >> 2) & 3; - unsigned int screenBase = (control & BGCNT_SCREENBASE_MASK) >> 8; - unsigned int is8bpp = (control >> 7) & 1; - - unsigned int mapW = bgMapSizes[control >> 14][0]; - unsigned int mapPxW = mapW << 3; - unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; - unsigned int wMask = mapPxW - 1; - unsigned int hMask = mapPxH - 1; - - uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); - uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); - uint16_t *pal = (uint16_t *)PLTT; - - bool hasMosaic = control & BGCNT_MOSAIC; - if (hasMosaic) - lineNum = ApplyMosaicBGY(lineNum); - - hoffs &= 0x1FF; - voffs &= 0x1FF; - - unsigned int yy = (lineNum + voffs) & hMask; - unsigned int mapY = yy >> 3; - unsigned int tileY = yy & 7; - unsigned int rowBase = mapY * mapW; - - // slow path: 8bpp or mosaic, one pixel at a time - if (hasMosaic || is8bpp) { - for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - unsigned int xx = hasMosaic ? (ApplyMosaicBGX(x) + hoffs) & wMask : (x + hoffs) & wMask; - - uint16_t entry = map[rowBase + (xx >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int tx = xx & 7; - unsigned int ty = tileY; - if (TILE_HFLIP(entry)) - tx = 7 - tx; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - - if (!is8bpp) { - uint8_t pair = tiles[(tileNum << 5) + (ty << 2) + (tx >> 1)]; - uint8_t pixel = (tx & 1) ? (pair >> 4) : (pair & 0xF); - if (pixel) - output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; - } else { - uint8_t pixel = tiles[(tileNum << 6) + (ty << 3) + tx]; - if (pixel) - output[x] = pal[pixel] | COLOR_OPAQUE; + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: base + * alpha : alpha + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 8bpp, alpha); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 8bpp, alpha); + } } - } - return; - } - - // fast path: 4bpp, read one u32 per tile row, unroll 8 pixels - unsigned int x = 0; - - // left edge: partial tile if scroll isn't tile-aligned - { - unsigned int startX = hoffs & wMask; - unsigned int startOff = startX & 7; - - if (startOff != 0) { - uint16_t entry = map[rowBase + (startX >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - bool hflip = TILE_HFLIP(entry); - - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); - - unsigned int partial = 8 - startOff; - if (partial > DISPLAY_WIDTH) - partial = DISPLAY_WIDTH; - - for (unsigned int t = 0; t < partial && x < DISPLAY_WIDTH; t++, x++) { - unsigned int tx = startOff + t; - if (hflip) - tx = 7 - tx; - uint8_t pixel = (row >> (tx << 2)) & 0xF; - if (pixel) - output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 8bpp, alpha); } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(base, 8bpp, alpha); + map_ptr = second_ptr; + end -= pixel_run; } - } + tile_run = end / 8; + multiple_tile_map(base, 8bpp, alpha); - // middle: full tiles, 8 pixels at a time - while (x + 8 <= DISPLAY_WIDTH) { - unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); - uint16_t *palBase = pal + (palNum << 4); - - if (!TILE_HFLIP(entry)) { - uint8_t p; - p = row & 0xF; - if (p) - output[x] = palBase[p] | COLOR_OPAQUE; - p = (row >> 4) & 0xF; - if (p) - output[x + 1] = palBase[p] | COLOR_OPAQUE; - p = (row >> 8) & 0xF; - if (p) - output[x + 2] = palBase[p] | COLOR_OPAQUE; - p = (row >> 12) & 0xF; - if (p) - output[x + 3] = palBase[p] | COLOR_OPAQUE; - p = (row >> 16) & 0xF; - if (p) - output[x + 4] = palBase[p] | COLOR_OPAQUE; - p = (row >> 20) & 0xF; - if (p) - output[x + 5] = palBase[p] | COLOR_OPAQUE; - p = (row >> 24) & 0xF; - if (p) - output[x + 6] = palBase[p] | COLOR_OPAQUE; - p = (row >> 28) & 0xF; - if (p) - output[x + 7] = palBase[p] | COLOR_OPAQUE; + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(base, 8bpp, alpha); + } + } else { + /* color depth: 4bpp + * combine: base + * alpha : alpha + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(base, 4bpp, alpha); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(base, 4bpp, alpha); + } + } } else { - uint8_t p; - p = (row >> 28) & 0xF; - if (p) - output[x] = palBase[p] | COLOR_OPAQUE; - p = (row >> 24) & 0xF; - if (p) - output[x + 1] = palBase[p] | COLOR_OPAQUE; - p = (row >> 20) & 0xF; - if (p) - output[x + 2] = palBase[p] | COLOR_OPAQUE; - p = (row >> 16) & 0xF; - if (p) - output[x + 3] = palBase[p] | COLOR_OPAQUE; - p = (row >> 12) & 0xF; - if (p) - output[x + 4] = palBase[p] | COLOR_OPAQUE; - p = (row >> 8) & 0xF; - if (p) - output[x + 5] = palBase[p] | COLOR_OPAQUE; - p = (row >> 4) & 0xF; - if (p) - output[x + 6] = palBase[p] | COLOR_OPAQUE; - p = row & 0xF; - if (p) - output[x + 7] = palBase[p] | COLOR_OPAQUE; + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(base, 4bpp, alpha); + } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(base, 4bpp, alpha); + map_ptr = second_ptr; + end -= pixel_run; } - x += 8; - } - - // right edge: leftover partial tile - if (x < DISPLAY_WIDTH) { - unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - bool hflip = TILE_HFLIP(entry); - - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); - - for (unsigned int t = 0; x < DISPLAY_WIDTH; t++, x++) { - unsigned int tx = hflip ? (7 - t) : t; - uint8_t pixel = (row >> (tx << 2)) & 0xF; - if (pixel) - output[x] = pal[(palNum << 4) + pixel] | COLOR_OPAQUE; + tile_run = end / 8; + multiple_tile_map(base, 4bpp, alpha); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(base, 4bpp, alpha); } } } -// same thing but with blend/window tracking baked in -static void RenderTextBGBlend(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *output, uint8_t *layerIds, - unsigned int blendMode, bool windowsEnabled, uint16_t *winMask, unsigned int bldcnt, unsigned int eva, - unsigned int evb, unsigned int evy) +static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end, void *scanline) { - unsigned int charBase = (control >> 2) & 3; - unsigned int screenBase = (control & BGCNT_SCREENBASE_MASK) >> 8; - unsigned int is8bpp = (control >> 7) & 1; - - unsigned int mapW = bgMapSizes[control >> 14][0]; - unsigned int mapPxW = mapW << 3; - unsigned int mapPxH = bgMapSizes[control >> 14][1] << 3; - unsigned int wMask = mapPxW - 1; - unsigned int hMask = mapPxH - 1; - - uint8_t *tiles = (uint8_t *)BG_CHAR_ADDR(charBase); - uint16_t *map = (uint16_t *)BG_SCREEN_ADDR(screenBase); - uint16_t *pal = (uint16_t *)PLTT; - - bool hasMosaic = control & BGCNT_MOSAIC; - if (hasMosaic) - lineNum = ApplyMosaicBGY(lineNum); - - hoffs &= 0x1FF; - voffs &= 0x1FF; - - unsigned int yy = (lineNum + voffs) & hMask; - unsigned int mapY = yy >> 3; - unsigned int tileY = yy & 7; - unsigned int rowBase = mapY * mapW; - - bool bgIsTargetA = (blendMode != 0) && (bldcnt & (1 << bgNum)); - bool useWindows = windowsEnabled && (winMask != NULL); - unsigned int winBgBit = 1 << bgNum; - - // slow path: 8bpp or mosaic - if (hasMosaic || is8bpp) { - for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - unsigned int xx = hasMosaic ? (ApplyMosaicBGX(x) + hoffs) & wMask : (x + hoffs) & wMask; - - uint16_t entry = map[rowBase + (xx >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int tx = xx & 7; - unsigned int ty = tileY; - if (TILE_HFLIP(entry)) - tx = 7 - tx; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - - uint8_t pixel; - if (!is8bpp) { - uint8_t pair = tiles[(tileNum << 5) + (ty << 2) + (tx >> 1)]; - pixel = (tx & 1) ? (pair >> 4) : (pair & 0xF); - } else { - pixel = tiles[(tileNum << 6) + (ty << 3) + tx]; - } + render_scanline_extra_variables_transparent_alpha(text); + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; + u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; + u32 current_pixel; + u32 current_pixels; + u32 partial_tile_run = 0; + u32 partial_tile_offset; + u32 tile_run; + u32 i; + render_scanline_dest_alpha *dest_ptr = ((render_scanline_dest_alpha *)scanline) + start; + + u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_ptr, *second_ptr; + u8 *tile_ptr; + + end -= start; + + if ((map_size & 0x02) && (vertical_offset >= 256)) { + map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); + } else { + map_base += (((vertical_offset % 256) / 8) * 32); + } - if (pixel == 0) - continue; - - uint16_t color = !is8bpp ? pal[(palNum << 4) + pixel] | COLOR_OPAQUE : pal[pixel] | COLOR_OPAQUE; - - if (useWindows && !(winMask[x] & winBgBit)) - continue; - - if (bgIsTargetA && (!useWindows || (winMask[x] & WINMASK_CLR))) { - uint16_t src = color; - switch (blendMode) { - case 1: - if (IsBlendTargetB(layerIds[x], bldcnt)) - color = alphaBlendColor(src, output[x], eva, evb); - break; - case 2: - color = alphaBrightnessIncrease(src, evy); - break; - case 3: - color = alphaBrightnessDecrease(src, evy); - break; + if (map_size & 0x01) { + if (horizontal_offset >= 256) { + horizontal_offset -= 256; + map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + second_ptr = map_base; + } else { + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base + (32 * 32); + } + } else { + horizontal_offset %= 256; + map_ptr = map_base + (horizontal_offset / 8); + second_ptr = map_base; + } + + if (bg_control & 0x80) { + /* color depth: 8bpp + * combine: transparent + * alpha : alpha + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; + s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_8bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 8bpp, alpha); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 8bpp, alpha); } } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 8bpp, alpha); + } - output[x] = color; - layerIds[x] = bgNum; + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(transparent, 8bpp, alpha); + map_ptr = second_ptr; + end -= pixel_run; } - return; - } - - // fast path: 4bpp batched with inline blend - unsigned int x = 0; - - // left edge partial tile - { - unsigned int startX = hoffs & wMask; - unsigned int startOff = startX & 7; - - if (startOff != 0) { - uint16_t entry = map[rowBase + (startX >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - bool hflip = TILE_HFLIP(entry); - - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); - uint16_t *palBase = pal + (palNum << 4); - - unsigned int partial = 8 - startOff; - if (partial > DISPLAY_WIDTH) - partial = DISPLAY_WIDTH; - - for (unsigned int t = 0; t < partial && x < DISPLAY_WIDTH; t++, x++) { - unsigned int tx = startOff + t; - if (hflip) - tx = 7 - tx; - uint8_t pixel = (row >> (tx << 2)) & 0xF; - if (pixel) - WriteBGPixelBlended(x, pixel, palBase, bgNum, output, layerIds, blendMode, bgIsTargetA, useWindows, winBgBit, winMask, - bldcnt, eva, evb, evy); + tile_run = end / 8; + multiple_tile_map(transparent, 8bpp, alpha); + + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(transparent, 8bpp, alpha); + } + } else { + /* color depth: 4bpp + * combine: transparent + * alpha : alpha + */ + + /* Render a single scanline of text tiles */ + u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; + s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; + tile_extra_variables_4bpp(); + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); + u32 current_tile; + + map_base += ((vertical_offset % 256) / 8) * 32; + partial_tile_offset = (horizontal_offset % 8); + + if (pixel_run >= end) { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + if (end < partial_tile_run) { + partial_tile_run = end; + partial_tile_mid_map(transparent, 4bpp, alpha); + return; + } else { + end -= partial_tile_run; + partial_tile_right_map(transparent, 4bpp, alpha); + } + } + } else { + if (partial_tile_offset) { + partial_tile_run = 8 - partial_tile_offset; + partial_tile_right_map(transparent, 4bpp, alpha); } + + tile_run = (pixel_run - partial_tile_run) / 8; + multiple_tile_map(transparent, 4bpp, alpha); + map_ptr = second_ptr; + end -= pixel_run; } - } + tile_run = end / 8; + multiple_tile_map(transparent, 4bpp, alpha); - // middle: full tiles - while (x + 8 <= DISPLAY_WIDTH) { - unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); - uint16_t *palBase = pal + (palNum << 4); - -#define BLEND_PX(off, shift) \ - do { \ - uint8_t p = (row >> (shift)) & 0xF; \ - if (p) \ - WriteBGPixelBlended(x + (off), p, palBase, bgNum, output, layerIds, blendMode, bgIsTargetA, useWindows, winBgBit, winMask, \ - bldcnt, eva, evb, evy); \ - } while (0) - - if (!TILE_HFLIP(entry)) { - BLEND_PX(0, 0); - BLEND_PX(1, 4); - BLEND_PX(2, 8); - BLEND_PX(3, 12); - BLEND_PX(4, 16); - BLEND_PX(5, 20); - BLEND_PX(6, 24); - BLEND_PX(7, 28); - } else { - BLEND_PX(0, 28); - BLEND_PX(1, 24); - BLEND_PX(2, 20); - BLEND_PX(3, 16); - BLEND_PX(4, 12); - BLEND_PX(5, 8); - BLEND_PX(6, 4); - BLEND_PX(7, 0); + partial_tile_run = end % 8; + if (partial_tile_run) { + partial_tile_left_map(transparent, 4bpp, alpha); } + } +} + +s32 affine_reference_x[2]; +s32 affine_reference_y[2]; + +static inline s32 signext28(u32 value) +{ + s32 ret = (s32)(value << 4); + return ret >> 4; +} + +void video_reload_counters() +{ + /* This happens every Vblank */ + affine_reference_x[0] = signext28(read_ioreg32(REG_ADDR_BG2X_L)); + affine_reference_y[0] = signext28(read_ioreg32(REG_ADDR_BG2Y_L)); + affine_reference_x[1] = signext28(read_ioreg32(REG_ADDR_BG3X_L)); + affine_reference_y[1] = signext28(read_ioreg32(REG_ADDR_BG3Y_L)); +} + +#define affine_render_bg_pixel_normal() current_pixel = PLTT[0] + +#define affine_render_bg_pixel_alpha() current_pixel = bg_combine + +#define affine_render_bg_pixel_color16() affine_render_bg_pixel_alpha() + +#define affine_render_bg_pixel_color32() affine_render_bg_pixel_alpha() + +#define affine_render_bg_pixel_base(alpha_op) affine_render_bg_pixel_##alpha_op() -#undef BLEND_PX +#define affine_render_bg_pixel_transparent(alpha_op) - x += 8; +#define affine_render_bg_pixel_copy(alpha_op) + +#define affine_render_bg_base(alpha_op) dest_ptr[0] = current_pixel + +#define affine_render_bg_transparent(alpha_op) + +#define affine_render_bg_copy(alpha_op) + +#define affine_render_bg_remainder_base(alpha_op) \ + affine_render_bg_pixel_##alpha_op(); \ + for (; i < end; i++) { \ + affine_render_bg_base(alpha_op); \ + advance_dest_ptr_base(1); \ } - // right edge partial tile - if (x < DISPLAY_WIDTH) { - unsigned int srcX = (x + hoffs) & wMask; - uint16_t entry = map[rowBase + (srcX >> 3)]; - unsigned int tileNum = TILE_NUM(entry); - unsigned int palNum = TILE_PALETTE(entry); - unsigned int ty = tileY; - if (TILE_VFLIP(entry)) - ty = 7 - ty; - bool hflip = TILE_HFLIP(entry); +#define affine_render_bg_remainder_transparent(alpha_op) + +#define affine_render_bg_remainder_copy(alpha_op) + +#define affine_render_next(combine_op) \ + source_x += dx; \ + source_y += dy; \ + advance_dest_ptr_##combine_op(1) + +#define affine_render_scale_offset() \ + tile_base += ((pixel_y % 8) * 8); \ + map_base += (pixel_y / 8) << map_pitch + +#define affine_render_scale_pixel(combine_op, alpha_op) \ + map_offset = (pixel_x / 8); \ + if (map_offset != last_map_offset) { \ + tile_ptr = tile_base + (map_base[map_offset] * 64); \ + last_map_offset = map_offset; \ + } \ + tile_ptr = tile_base + (map_base[(pixel_x / 8)] * 64); \ + current_pixel = tile_ptr[(pixel_x % 8)]; \ + tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \ + affine_render_next(combine_op) + +#define affine_render_scale(combine_op, alpha_op) \ + { \ + pixel_y = source_y >> 8; \ + u32 i = 0; \ + affine_render_bg_pixel_##combine_op(alpha_op); \ + if ((u32)pixel_y < (u32)width_height) { \ + affine_render_scale_offset(); \ + for (; i < end; i++) { \ + pixel_x = source_x >> 8; \ + \ + if ((u32)pixel_x < (u32)width_height) { \ + break; \ + } \ + \ + affine_render_bg_##combine_op(alpha_op); \ + affine_render_next(combine_op); \ + } \ + \ + for (; i < end; i++) { \ + pixel_x = source_x >> 8; \ + \ + if ((u32)pixel_x >= (u32)width_height) \ + break; \ + \ + affine_render_scale_pixel(combine_op, alpha_op); \ + } \ + } \ + affine_render_bg_remainder_##combine_op(alpha_op); \ + } - uint32_t row = *(uint32_t *)(tiles + (tileNum << 5) + (ty << 2)); - uint16_t *palBase = pal + (palNum << 4); +#define affine_render_scale_wrap(combine_op, alpha_op) \ + { \ + u32 wrap_mask = width_height - 1; \ + pixel_y = (source_y >> 8) & wrap_mask; \ + if ((u32)pixel_y < (u32)width_height) { \ + affine_render_scale_offset(); \ + for (i = 0; i < end; i++) { \ + pixel_x = (source_x >> 8) & wrap_mask; \ + affine_render_scale_pixel(combine_op, alpha_op); \ + } \ + } \ + } - for (unsigned int t = 0; x < DISPLAY_WIDTH; t++, x++) { - unsigned int tx = hflip ? (7 - t) : t; - uint8_t pixel = (row >> (tx << 2)) & 0xF; - if (pixel) - WriteBGPixelBlended(x, pixel, palBase, bgNum, output, layerIds, blendMode, bgIsTargetA, useWindows, winBgBit, winMask, - bldcnt, eva, evb, evy); - } +#define affine_render_rotate_pixel(combine_op, alpha_op) \ + map_offset = (pixel_x / 8) + ((pixel_y / 8) << map_pitch); \ + if (map_offset != last_map_offset) { \ + tile_ptr = tile_base + (map_base[map_offset] * 64); \ + last_map_offset = map_offset; \ + } \ + \ + current_pixel = tile_ptr[(pixel_x % 8) + ((pixel_y % 8) * 8)]; \ + tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \ + affine_render_next(combine_op) + +#define affine_render_rotate(combine_op, alpha_op) \ + { \ + affine_render_bg_pixel_##combine_op(alpha_op); \ + for (i = 0; i < end; i++) { \ + pixel_x = source_x >> 8; \ + pixel_y = source_y >> 8; \ + \ + if (((u32)pixel_x < (u32)width_height) && ((u32)pixel_y < (u32)width_height)) { \ + break; \ + } \ + affine_render_bg_##combine_op(alpha_op); \ + affine_render_next(combine_op); \ + } \ + \ + for (; i < end; i++) { \ + pixel_x = source_x >> 8; \ + pixel_y = source_y >> 8; \ + \ + if (((u32)pixel_x >= (u32)width_height) || ((u32)pixel_y >= (u32)width_height)) { \ + affine_render_bg_remainder_##combine_op(alpha_op); \ + break; \ + } \ + \ + affine_render_rotate_pixel(combine_op, alpha_op); \ + } \ } -} -static void RenderAffineBG(int bgNum, uint16_t control, int lineNum, uint16_t *output) -{ - vBgCnt *bgcnt = (vBgCnt *)&control; - - uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); - uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); - uint16_t *pal = (uint16_t *)PLTT; - - if (control & BGCNT_MOSAIC) - lineNum = ApplyMosaicBGY(lineNum); - - s16 pa = GetBgPA(bgNum); - s16 pb = GetBgPB(bgNum); - s16 pc = GetBgPC(bgNum); - s16 pd = GetBgPD(bgNum); - - // always square: 128/256/512/1024 - int size = 128; - switch (bgcnt->screenSize) { - case 1: - size = 256; - break; - case 2: - size = 512; - break; - case 3: - size = 1024; - break; - } - int mask = size - 1; - int yshift = ((control >> 14) & 3) + 4; - - // sign-extend 28-bit reference point, advance by scanline - s32 refX = GetBgRefX(bgNum); - s32 refY = GetBgRefY(bgNum); - refX = (refX & (1 << 27)) ? refX | 0xF0000000 : refX; - refY = (refY & (1 << 27)) ? refY | 0xF0000000 : refY; - refX += lineNum * pb; - refY += lineNum * pd; - - int curX = refX; - int curY = refY; - - if (bgcnt->areaOverflowMode) { - // wraparound - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int tx = (curX >> 8) & mask; - int ty = (curY >> 8) & mask; - int tile = map[(tx >> 3) + ((ty >> 3) << yshift)]; - uint8_t pixel = tiles[(tile << 6) + ((ty & 7) << 3) + (tx & 7)]; - if (pixel) - output[x] = pal[pixel] | COLOR_OPAQUE; - curX += pa; - curY += pc; - } - } else { - // clamp: outside the map = transparent - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int tx = curX >> 8; - int ty = curY >> 8; - if (tx >= 0 && ty >= 0 && tx < size && ty < size) { - int tile = map[(tx >> 3) + ((ty >> 3) << yshift)]; - uint8_t pixel = tiles[(tile << 6) + ((ty & 7) << 3) + (tx & 7)]; - if (pixel) - output[x] = pal[pixel] | COLOR_OPAQUE; - } - curX += pa; - curY += pc; - } +#define affine_render_rotate_wrap(combine_op, alpha_op) \ + { \ + u32 wrap_mask = width_height - 1; \ + for (i = 0; i < end; i++) { \ + pixel_x = (source_x >> 8) & wrap_mask; \ + pixel_y = (source_y >> 8) & wrap_mask; \ + \ + affine_render_rotate_pixel(combine_op, alpha_op); \ + } \ } - // horizontal mosaic as a post-pass - if ((control & BGCNT_MOSAIC) && MOSAIC_BG_X > 0) { - for (int x = 0; x < DISPLAY_WIDTH; x++) - output[x] = output[ApplyMosaicBGX(x)]; +// Build affine background renderers. + +#define render_scanline_affine_builder(combine_op, alpha_op) \ + void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, u32 start, u32 end, void *scanline) \ + { \ + render_scanline_extra_variables_##combine_op##_##alpha_op(affine); \ + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); \ + u32 current_pixel; \ + s32 source_x, source_y; \ + u32 pixel_x, pixel_y; \ + u32 layer_offset = (layer - 2) * 8; \ + s32 dx, dy; \ + u32 map_size = (bg_control >> 14) & 0x03; \ + u32 width_height = 1 << (7 + map_size); \ + u32 map_pitch = map_size + 4; \ + u8 *map_base = VRAM + (((bg_control >> 8) & 0x1F) * (1024 * 2)); \ + u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)); \ + u8 *tile_ptr = NULL; \ + u32 map_offset, last_map_offset = (u32)-1; \ + u32 i; \ + render_scanline_dest_##alpha_op *dest_ptr = ((render_scanline_dest_##alpha_op *)scanline) + start; \ + \ + dx = (s16)read_ioreg(REG_ADDR_BG2PA + (layer_offset * sizeof(u16))); \ + dy = (s16)read_ioreg(REG_ADDR_BG2PC + (layer_offset * sizeof(u16))); \ + source_x = affine_reference_x[layer - 2] + (start * dx); \ + source_y = affine_reference_y[layer - 2] + (start * dy); \ + \ + end -= start; \ + \ + switch (((bg_control >> 12) & 0x02) | (dy != 0)) { \ + case 0x00: \ + affine_render_scale(combine_op, alpha_op); \ + break; \ + \ + case 0x01: \ + affine_render_rotate(combine_op, alpha_op); \ + break; \ + \ + case 0x02: \ + affine_render_scale_wrap(combine_op, alpha_op); \ + break; \ + \ + case 0x03: \ + affine_render_rotate_wrap(combine_op, alpha_op); \ + break; \ + } \ } -} -// same deal with blend/window support -static void RenderAffineBGBlend(int bgNum, uint16_t control, int lineNum, uint16_t *output, uint8_t *layerIds, unsigned int blendMode, - bool windowsEnabled, uint16_t *winMask, unsigned int bldcnt, unsigned int eva, unsigned int evb, - unsigned int evy) -{ - vBgCnt *bgcnt = (vBgCnt *)&control; - - uint8_t *tiles = (uint8_t *)(VRAM + bgcnt->charBaseBlock * 0x4000); - uint8_t *map = (uint8_t *)(VRAM + bgcnt->screenBaseBlock * 0x800); - uint16_t *pal = (uint16_t *)PLTT; - - if (control & BGCNT_MOSAIC) - lineNum = ApplyMosaicBGY(lineNum); - - s16 pa = GetBgPA(bgNum); - s16 pb = GetBgPB(bgNum); - s16 pc = GetBgPC(bgNum); - s16 pd = GetBgPD(bgNum); - - int size = 128; - switch (bgcnt->screenSize) { - case 1: - size = 256; - break; - case 2: - size = 512; - break; - case 3: - size = 1024; - break; - } - int mask = size - 1; - int yshift = ((control >> 14) & 3) + 4; - - s32 refX = GetBgRefX(bgNum); - s32 refY = GetBgRefY(bgNum); - refX = (refX & (1 << 27)) ? refX | 0xF0000000 : refX; - refY = (refY & (1 << 27)) ? refY | 0xF0000000 : refY; - refX += lineNum * pb; - refY += lineNum * pd; - - int curX = refX; - int curY = refY; - - bool bgIsTargetA = (blendMode != 0) && (bldcnt & (1 << bgNum)); - - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int tx, ty; - - if (bgcnt->areaOverflowMode) { - tx = (curX >> 8) & mask; - ty = (curY >> 8) & mask; - } else { - tx = curX >> 8; - ty = curY >> 8; - if (tx < 0 || ty < 0 || tx >= size || ty >= size) { - curX += pa; - curY += pc; - continue; - } - } +render_scanline_affine_builder(base, normal); +render_scanline_affine_builder(transparent, normal); +render_scanline_affine_builder(base, color16); +render_scanline_affine_builder(transparent, color16); +render_scanline_affine_builder(base, color32); +render_scanline_affine_builder(transparent, color32); +render_scanline_affine_builder(base, alpha); +render_scanline_affine_builder(transparent, alpha); + +#define bitmap_render_pixel_mode3(alpha_op) \ + current_pixel = convert_palette(current_pixel); \ + *dest_ptr = current_pixel + +#define bitmap_render_pixel_mode4(alpha_op) tile_expand_base_##alpha_op##_mode4(0) + +#define bitmap_render_pixel_mode5(alpha_op) bitmap_render_pixel_mode3(alpha_op) + +#define bitmap_render_scale(type, alpha_op, width, height) \ + pixel_y = (source_y >> 8); \ + if ((u32)pixel_y < (u32)height) { \ + pixel_x = (source_x >> 8); \ + src_ptr += (pixel_y * width); \ + if (dx == 0x100) { \ + if (pixel_x < 0) { \ + end += pixel_x; \ + dest_ptr -= pixel_x; \ + pixel_x = 0; \ + } else if (pixel_x > 0) \ + src_ptr += pixel_x; \ + \ + if ((pixel_x + end) >= width) \ + end = (width - pixel_x); \ + \ + for (i = 0; (s32)i < (s32)end; i++) { \ + current_pixel = srcread_##type(*src_ptr); \ + bitmap_render_pixel_##type(alpha_op); \ + src_ptr++; \ + dest_ptr++; \ + } \ + } else { \ + if ((u32)(source_y >> 8) < (u32)height) { \ + for (i = 0; i < end; i++) { \ + pixel_x = (source_x >> 8); \ + \ + if ((u32)pixel_x < (u32)width) \ + break; \ + \ + source_x += dx; \ + dest_ptr++; \ + } \ + \ + for (; i < end; i++) { \ + pixel_x = (source_x >> 8); \ + \ + if ((u32)pixel_x >= (u32)width) \ + break; \ + \ + current_pixel = srcread_##type(src_ptr[pixel_x]); \ + bitmap_render_pixel_##type(alpha_op); \ + \ + source_x += dx; \ + dest_ptr++; \ + } \ + } \ + } \ + } - int tile = map[(tx >> 3) + ((ty >> 3) << yshift)]; - uint8_t pixel = tiles[(tile << 6) + ((ty & 7) << 3) + (tx & 7)]; - - curX += pa; - curY += pc; - - if (pixel == 0) - continue; - - uint16_t color = pal[pixel] | COLOR_OPAQUE; - - if (windowsEnabled && winMask && !(winMask[x] & (1 << bgNum))) - continue; - - bool winAllowsBlend = true; - if (windowsEnabled && winMask) - winAllowsBlend = (winMask[x] & WINMASK_CLR) >> 5; - - if (bgIsTargetA && winAllowsBlend) { - uint16_t src = color; - switch (blendMode) { - case 1: - if (IsBlendTargetB(layerIds[x], bldcnt)) - color = alphaBlendColor(src, output[x], eva, evb); - break; - case 2: - color = alphaBrightnessIncrease(src, evy); - break; - case 3: - color = alphaBrightnessDecrease(src, evy); - break; - } - } +#define bitmap_render_rotate(type, alpha_op, width, height) \ + for (i = 0; i < end; i++) { \ + pixel_x = source_x >> 8; \ + pixel_y = source_y >> 8; \ + \ + if (((u32)pixel_x < (u32)width) && ((u32)pixel_y < (u32)height)) \ + break; \ + \ + source_x += dx; \ + source_y += dy; \ + dest_ptr++; \ + } \ + \ + for (; i < end; i++) { \ + pixel_x = (source_x >> 8); \ + pixel_y = (source_y >> 8); \ + \ + if (((u32)pixel_x >= (u32)width) || ((u32)pixel_y >= (u32)height)) \ + break; \ + \ + current_pixel = srcread_##type(src_ptr[pixel_x + (pixel_y * width)]); \ + bitmap_render_pixel_##type(alpha_op); \ + \ + source_x += dx; \ + source_y += dy; \ + dest_ptr++; \ + } - output[x] = color; - layerIds[x] = bgNum; +#define render_scanline_vram_setup_mode3() u16 *src_ptr = (u16 *)VRAM + +#define render_scanline_vram_setup_mode5() \ + u16 *src_ptr = (u16 *)VRAM; \ + if (read_ioreg(REG_ADDR_DISPCNT) & 0x10) \ + src_ptr = (u16 *)(VRAM + 0xA000); + +#define render_scanline_vram_setup_mode4() \ + u16 *palette = PLTT; \ + u8 *src_ptr = VRAM; \ + if (read_ioreg(REG_ADDR_DISPCNT) & 0x10) \ + src_ptr = VRAM + 0xA000; + +#define srcread_mode3(v) eswap16(v) +#define srcread_mode5(v) eswap16(v) +#define srcread_mode4(v) (v) + +// Build bitmap scanline rendering functions. + +#define render_scanline_bitmap_builder(type, alpha_op, width, height) \ + static void render_scanline_bitmap_##type##_##alpha_op(u32 start, u32 end, void *scanline) \ + { \ + u32 current_pixel; \ + s32 source_x, source_y; \ + s32 pixel_x, pixel_y; \ + \ + s32 dx = (s16)read_ioreg(REG_ADDR_BG2PA); \ + s32 dy = (s16)read_ioreg(REG_ADDR_BG2PC); \ + \ + u32 i; \ + \ + render_scanline_dest_##alpha_op *dest_ptr = ((render_scanline_dest_##alpha_op *)scanline) + start; \ + render_scanline_vram_setup_##type(); \ + \ + end -= start; \ + \ + source_x = affine_reference_x[0] + (start * dx); \ + source_y = affine_reference_y[0] + (start * dy); \ + \ + if (dy == 0) { \ + bitmap_render_scale(type, alpha_op, width, height); \ + } else { \ + bitmap_render_rotate(type, alpha_op, width, height); \ + } \ } - if ((control & BGCNT_MOSAIC) && MOSAIC_BG_X > 0) { - for (int x = 0; x < DISPLAY_WIDTH; x++) - output[x] = output[ApplyMosaicBGX(x)]; +render_scanline_bitmap_builder(mode3, normal, DISPLAY_WIDTH, DISPLAY_HEIGHT); +render_scanline_bitmap_builder(mode4, normal, DISPLAY_WIDTH, DISPLAY_WIDTH); +render_scanline_bitmap_builder(mode5, normal, 160, 128); + +// Fill in the renderers for a layer based on the mode type, + +#define tile_layer_render_functions(type) \ + { \ + render_scanline_##type##_base_normal, render_scanline_##type##_transparent_normal, render_scanline_##type##_base_alpha, \ + render_scanline_##type##_transparent_alpha, render_scanline_##type##_base_color16, \ + render_scanline_##type##_transparent_color16, render_scanline_##type##_base_color32, \ + render_scanline_##type##_transparent_color32 \ } -} -#define MAX_SPRITES_PER_PRIORITY 32 +// Use if a layer is unsupported for that mode. -typedef struct { - uint8_t oamIndex; -} ActiveSprite; +#define tile_layer_render_null() \ + { \ + NULL, NULL, NULL, NULL \ + } + +#define bitmap_layer_render_functions(type) \ + { \ + render_scanline_bitmap_##type##_normal \ + } -static ActiveSprite sActiveSprites[4][MAX_SPRITES_PER_PRIORITY]; -static int sActiveSpriteCount[4]; +// Structs containing functions to render the layers for each mode, for +// each render type. +static const tile_layer_render_struct tile_mode_renderers[3][4] + = { { tile_layer_render_functions(text), tile_layer_render_functions(text), tile_layer_render_functions(text), + tile_layer_render_functions(text) }, + { tile_layer_render_functions(text), tile_layer_render_functions(text), tile_layer_render_functions(affine), + tile_layer_render_functions(text) }, + { tile_layer_render_functions(text), tile_layer_render_functions(text), tile_layer_render_functions(affine), + tile_layer_render_functions(affine) } }; + +static const bitmap_layer_render_struct bitmap_mode_renderers[3] + = { bitmap_layer_render_functions(mode3), bitmap_layer_render_functions(mode4), bitmap_layer_render_functions(mode5) }; + +#define render_scanline_layer_functions_tile() const tile_layer_render_struct *layer_renderers = tile_mode_renderers[dispcnt & 0x07] + +#define render_scanline_layer_functions_bitmap() \ + const bitmap_layer_render_struct *layer_renderers = bitmap_mode_renderers + ((dispcnt & 0x07) - 3) + +// Adjust a flipped obj's starting position + +#define obj_tile_offset_noflip(color_depth) + +#define obj_tile_offset_flip(color_depth) +(tile_size_##color_depth * ((obj_width - 8) / 8)) + +// Adjust the obj's starting point if it goes too far off the left edge of +// the screen. + +#define obj_tile_right_offset_noflip(color_depth) tile_ptr += (partial_tile_offset / 8) * tile_size_##color_depth + +#define obj_tile_right_offset_flip(color_depth) tile_ptr -= (partial_tile_offset / 8) * tile_size_##color_depth + +// Get the current row offset into an obj in 1D map space + +#define obj_tile_offset_1D(color_depth, flip_op) \ + tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth) \ + + ((vertical_offset % 8) * tile_width_##color_depth) obj_tile_offset_##flip_op(color_depth) + +// Get the current row offset into an obj in 2D map space + +#define obj_tile_offset_2D(color_depth, flip_op) \ + tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * 1024) \ + + ((vertical_offset % 8) * tile_width_##color_depth) obj_tile_offset_##flip_op(color_depth) + +// Get the palette for 4bpp obj. + +#define obj_get_palette_4bpp() current_palette = (obj_attribute_2 >> 8) & 0xF0 + +#define obj_get_palette_8bpp() + +// Render the current row of an obj. + +#define obj_render(combine_op, color_depth, alpha_op, map_space, flip_op) \ + { \ + obj_get_palette_##color_depth(); \ + obj_tile_offset_##map_space(color_depth, flip_op); \ + \ + if (obj_x < (s32)start) { \ + dest_ptr = scanline + start; \ + pixel_run = obj_width - (start - obj_x); \ + if ((s32)pixel_run > 0) { \ + if ((obj_x + obj_width) >= end) { \ + pixel_run = end - start; \ + partial_tile_offset = start - obj_x; \ + obj_tile_right_offset_##flip_op(color_depth); \ + partial_tile_offset %= 8; \ + \ + if (partial_tile_offset) { \ + partial_tile_run = 8 - partial_tile_offset; \ + if ((s32)pixel_run < (s32)partial_tile_run) { \ + if ((s32)pixel_run > 0) { \ + partial_tile_run = pixel_run; \ + partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + continue; \ + } else { \ + pixel_run -= partial_tile_run; \ + partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + } \ + tile_run = pixel_run / 8; \ + multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ + partial_tile_run = pixel_run % 8; \ + if (partial_tile_run) { \ + partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + } else { \ + partial_tile_offset = start - obj_x; \ + obj_tile_right_offset_##flip_op(color_depth); \ + partial_tile_offset %= 8; \ + if (partial_tile_offset) { \ + partial_tile_run = 8 - partial_tile_offset; \ + partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + tile_run = pixel_run / 8; \ + multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + } \ + } else \ + \ + if ((obj_x + obj_width) >= end) { \ + pixel_run = end - obj_x; \ + if ((s32)pixel_run > 0) { \ + dest_ptr = scanline + obj_x; \ + tile_run = pixel_run / 8; \ + multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ + partial_tile_run = pixel_run % 8; \ + if (partial_tile_run) { \ + partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + } \ + } else { \ + dest_ptr = scanline + obj_x; \ + tile_run = obj_width / 8; \ + multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ + } \ + } -static void PrefilterSprites(uint16_t vcount) -{ - sActiveSpriteCount[0] = 0; - sActiveSpriteCount[1] = 0; - sActiveSpriteCount[2] = 0; - sActiveSpriteCount[3] = 0; +#define obj_scale_offset_1D(color_depth) \ + tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth) \ + + ((vertical_offset % 8) * tile_width_##color_depth) + +// Get the current row offset into an obj in 2D map space + +#define obj_scale_offset_2D(color_depth) \ + tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * 1024) \ + + ((vertical_offset % 8) * tile_width_##color_depth) + +#define obj_render_scale_pixel_4bpp(combine_op, alpha_op) \ + current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)]; \ + if (tile_x & 0x01) \ + current_pixel >>= 4; \ + else \ + current_pixel &= 0x0F; \ + \ + tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) + +#define obj_render_scale_pixel_8bpp(combine_op, alpha_op) \ + current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07)]; \ + tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); + +#define obj_render_scale(combine_op, color_depth, alpha_op, map_space) \ + { \ + u32 vertical_offset; \ + source_y += (y_delta * dmy); \ + vertical_offset = (source_y >> 8); \ + if ((u32)vertical_offset < (u32)max_y) { \ + obj_scale_offset_##map_space(color_depth); \ + source_x += (y_delta * dmx) - (middle_x * dx); \ + \ + for (i = 0; i < obj_width; i++) { \ + tile_x = (source_x >> 8); \ + \ + if ((u32)tile_x < (u32)max_x) \ + break; \ + \ + source_x += dx; \ + advance_dest_ptr_##combine_op(1); \ + } \ + \ + for (; i < obj_width; i++) { \ + tile_x = (source_x >> 8); \ + \ + if ((u32)tile_x >= (u32)max_x) \ + break; \ + \ + tile_map_offset = (tile_x >> 3) * tile_size_##color_depth; \ + obj_render_scale_pixel_##color_depth(combine_op, alpha_op); \ + \ + source_x += dx; \ + advance_dest_ptr_##combine_op(1); \ + } \ + } \ + } + +#define obj_rotate_offset_1D(color_depth) obj_tile_pitch = (max_x / 8) * tile_size_##color_depth + +#define obj_rotate_offset_2D(color_depth) obj_tile_pitch = 1024 + +#define obj_render_rotate_pixel_4bpp(combine_op, alpha_op) \ + current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)]; \ + if (tile_x & 0x01) \ + current_pixel >>= 4; \ + else \ + current_pixel &= 0x0F; \ + \ + tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) + +#define obj_render_rotate_pixel_8bpp(combine_op, alpha_op) \ + current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07) + ((tile_y & 0x07) * obj_pitch)]; \ + \ + tile_8bpp_draw_##combine_op(0, none, 0, alpha_op) + +#define obj_render_rotate(combine_op, color_depth, alpha_op, map_space) \ + { \ + tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32); \ + obj_rotate_offset_##map_space(color_depth); \ + \ + source_x += (y_delta * dmx) - (middle_x * dx); \ + source_y += (y_delta * dmy) - (middle_x * dy); \ + \ + for (i = 0; i < obj_width; i++) { \ + tile_x = (source_x >> 8); \ + tile_y = (source_y >> 8); \ + \ + if (((u32)tile_x < (u32)max_x) && ((u32)tile_y < (u32)max_y)) \ + break; \ + \ + source_x += dx; \ + source_y += dy; \ + advance_dest_ptr_##combine_op(1); \ + } \ + \ + for (; i < obj_width; i++) { \ + tile_x = (source_x >> 8); \ + tile_y = (source_y >> 8); \ + \ + if (((u32)tile_x >= (u32)max_x) || ((u32)tile_y >= (u32)max_y)) \ + break; \ + \ + tile_map_offset = ((tile_x >> 3) * tile_size_##color_depth) + ((tile_y >> 3) * obj_tile_pitch); \ + obj_render_rotate_pixel_##color_depth(combine_op, alpha_op); \ + \ + source_x += dx; \ + source_y += dy; \ + advance_dest_ptr_##combine_op(1); \ + } \ + } + +// Render the current row of an affine transformed OBJ. + +#define obj_render_affine(combine_op, color_depth, alpha_op, map_space) \ + { \ + u16 *params = (u16 *)OAM + (((obj_attribute_1 >> 9) & 0x1F) * 16); \ + s32 dx = (s16)eswap16(params[3]); \ + s32 dmx = (s16)eswap16(params[7]); \ + s32 dy = (s16)eswap16(params[11]); \ + s32 dmy = (s16)eswap16(params[15]); \ + s32 source_x, source_y; \ + s32 tile_x, tile_y; \ + u32 tile_map_offset; \ + s32 middle_x; \ + s32 middle_y; \ + s32 max_x = obj_width; \ + s32 max_y = obj_height; \ + s32 y_delta; \ + u32 obj_pitch = tile_width_##color_depth; \ + u32 obj_tile_pitch; \ + \ + middle_x = (obj_width / 2); \ + middle_y = (obj_height / 2); \ + \ + source_x = (middle_x << 8); \ + source_y = (middle_y << 8); \ + \ + if (obj_attribute_0 & 0x200) { \ + obj_width *= 2; \ + obj_height *= 2; \ + middle_x *= 2; \ + middle_y *= 2; \ + } \ + \ + if ((s32)obj_x < (s32)start) { \ + u32 x_delta = start - obj_x; \ + middle_x -= x_delta; \ + obj_width -= x_delta; \ + obj_x = start; \ + \ + if ((s32)obj_width <= 0) \ + continue; \ + } \ + \ + if ((s32)(obj_x + obj_width) >= (s32)end) { \ + obj_width = end - obj_x; \ + \ + if ((s32)obj_width <= 0) \ + continue; \ + } \ + dest_ptr = scanline + obj_x; \ + \ + y_delta = vcount - (obj_y + middle_y); \ + \ + obj_get_palette_##color_depth(); \ + \ + if (dy == 0) { \ + obj_render_scale(combine_op, color_depth, alpha_op, map_space); \ + } else { \ + obj_render_rotate(combine_op, color_depth, alpha_op, map_space); \ + } \ + } + +static const u32 obj_width_table[] = { 8, 16, 32, 64, 16, 32, 32, 64, 8, 8, 16, 32 }; +static const u32 obj_height_table[] = { 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64 }; + +static const u8 obj_dim_table[3][4][2] = { { { 8, 8 }, { 16, 16 }, { 32, 32 }, { 64, 64 } }, + { { 16, 8 }, { 32, 8 }, { 32, 16 }, { 64, 32 } }, + { { 8, 16 }, { 8, 32 }, { 16, 32 }, { 32, 64 } } }; + +static u8 obj_priority_list[5][DISPLAY_HEIGHT][128]; +static u8 obj_priority_count[5][DISPLAY_HEIGHT]; +static u8 obj_alpha_count[DISPLAY_HEIGHT]; + +// Build obj rendering functions + +#define render_scanline_obj_extra_variables_normal(bg_type) u16 *palette = PLTT + 256 + +#define render_scanline_obj_extra_variables_color() u32 pixel_combine = color_combine_mask(4) | (1 << 8) + +#define render_scanline_obj_extra_variables_alpha_obj(map_space) \ + render_scanline_obj_extra_variables_color(); \ + u32 dest; \ + if ((pixel_combine & 0x00000200) == 0) { \ + render_scanline_obj_color32_##map_space(priority, start, end, scanline); \ + return; \ + } + +#define render_scanline_obj_extra_variables_color16(map_space) render_scanline_obj_extra_variables_color() + +#define render_scanline_obj_extra_variables_color32(map_space) render_scanline_obj_extra_variables_color() + +#define render_scanline_obj_extra_variables_partial_alpha(map_space) \ + render_scanline_obj_extra_variables_color(); \ + u32 base_pixel_combine = pixel_combine; \ + u32 dest + +#define render_scanline_obj_extra_variables_copy(type) \ + u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); \ + u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); \ + u32 obj_enable = read_ioreg(REG_ADDR_WINOUT) >> 8; \ + render_scanline_layer_functions_##type(); \ + u32 copy_start, copy_end; \ + u16 copy_buffer[DISPLAY_WIDTH]; \ + u16 *copy_ptr + +#define render_scanline_obj_extra_variables_copy_tile(map_space) render_scanline_obj_extra_variables_copy(tile) + +#define render_scanline_obj_extra_variables_copy_bitmap(map_space) render_scanline_obj_extra_variables_copy(bitmap) + +#define render_scanline_obj_main(combine_op, alpha_op, map_space) \ + if (obj_attribute_0 & 0x100) { \ + if ((obj_attribute_0 >> 13) & 0x01) { \ + obj_render_affine(combine_op, 8bpp, alpha_op, map_space); \ + } else { \ + obj_render_affine(combine_op, 4bpp, alpha_op, map_space); \ + } \ + } else { \ + vertical_offset = vcount - obj_y; \ + \ + if ((obj_attribute_1 >> 13) & 0x01) \ + vertical_offset = obj_height - vertical_offset - 1; \ + \ + switch (((obj_attribute_0 >> 12) & 0x02) | ((obj_attribute_1 >> 12) & 0x01)) { \ + case 0x0: \ + obj_render(combine_op, 4bpp, alpha_op, map_space, noflip); \ + break; \ + \ + case 0x1: \ + obj_render(combine_op, 4bpp, alpha_op, map_space, flip); \ + break; \ + \ + case 0x2: \ + obj_render(combine_op, 8bpp, alpha_op, map_space, noflip); \ + break; \ + \ + case 0x3: \ + obj_render(combine_op, 8bpp, alpha_op, map_space, flip); \ + break; \ + } \ + } + +#define render_scanline_obj_no_partial_alpha(combine_op, alpha_op, map_space) render_scanline_obj_main(combine_op, alpha_op, map_space) + +#define render_scanline_obj_partial_alpha(combine_op, alpha_op, map_space) \ + if ((obj_attribute_0 >> 10) & 0x03) { \ + pixel_combine = 0x00000300; \ + render_scanline_obj_main(combine_op, alpha_obj, map_space); \ + } else { \ + pixel_combine = base_pixel_combine; \ + render_scanline_obj_main(combine_op, color32, map_space); \ + } - if (!(REG_DISPCNT & DISPCNT_OBJ_ON)) - return; +#define render_scanline_obj_prologue_transparent(alpha_op) + +#define render_scanline_obj_prologue_copy_body(type) \ + copy_start = obj_x; \ + copy_end = obj_x + obj_width; \ + if (obj_attribute_0 & 0x200) \ + copy_end += obj_width; \ + \ + if (copy_start < start) \ + copy_start = start; \ + if (copy_end > end) \ + copy_end = end; \ + \ + if ((copy_start < end) && (copy_end > start)) { \ + render_scanline_conditional_##type(copy_start, copy_end, copy_buffer, obj_enable, dispcnt, bldcnt, layer_renderers); \ + copy_ptr = copy_buffer + copy_start; \ + } else { \ + continue; \ + } - // back-to-front so lower oam indices (higher hw priority) draw last - for (int i = OAM_ENTRY_COUNT - 1; i >= 0; i--) { - OamData *oam = &((OamData *)OAM)[i]; +#define render_scanline_obj_prologue_copy_tile() render_scanline_obj_prologue_copy_body(tile) + +#define render_scanline_obj_prologue_copy_bitmap() render_scanline_obj_prologue_copy_body(bitmap) + +#define render_scanline_obj_prologue_copy(alpha_op) render_scanline_obj_prologue_##alpha_op() + +#define render_scanline_obj_builder(combine_op, alpha_op, map_space, partial_alpha_op) \ + static void render_scanline_obj_##alpha_op##_##map_space(u32 priority, u32 start, u32 end, render_scanline_dest_##alpha_op *scanline) \ + { \ + render_scanline_obj_extra_variables_##alpha_op(map_space); \ + u32 obj_num, i; \ + s32 obj_x, obj_y; \ + u32 obj_size; \ + u32 obj_width, obj_height; \ + u32 obj_attribute_0, obj_attribute_1, obj_attribute_2; \ + s32 vcount = read_ioreg(REG_ADDR_VCOUNT); \ + u32 tile_run; \ + u32 current_pixels; \ + u32 current_pixel; \ + u32 current_palette; \ + u32 vertical_offset; \ + u32 partial_tile_run, partial_tile_offset; \ + u32 pixel_run; \ + u16 *oam_ptr; \ + OamData *oam_data; \ + render_scanline_dest_##alpha_op *dest_ptr; \ + u8 *tile_base = VRAM + 0x10000; \ + u8 *tile_ptr; \ + u32 obj_count = obj_priority_count[priority][vcount]; \ + u8 *obj_list = obj_priority_list[priority][vcount]; \ + \ + for (obj_num = 0; obj_num < obj_count; obj_num++) { \ + oam_data = (OamData *)&OAM[obj_list[obj_num] * OAM_DATA_SIZE_AFFINE]; \ + oam_ptr = (u16 *)OAM + (obj_list[obj_num] * 4); \ + obj_attribute_0 = eswap16(oam_ptr[0]); \ + obj_attribute_1 = eswap16(oam_ptr[1]); \ + obj_attribute_2 = eswap16(oam_ptr[2]); \ + obj_size = ((obj_attribute_0 >> 12) & 0x0C) | (obj_attribute_1 >> 14); \ + \ + obj_x = oam_data->split.x; \ + obj_width = obj_width_table[obj_size]; \ + \ + render_scanline_obj_prologue_##combine_op(alpha_op); \ + \ + obj_y = obj_attribute_0 & 0xFF; \ + \ + if (!EXTENDED_OAM) { \ + if (obj_x > DISPLAY_WIDTH) \ + obj_x -= 512; \ + if (obj_y > DISPLAY_HEIGHT) \ + obj_y -= 256; \ + } \ + \ + obj_height = obj_height_table[obj_size]; \ + render_scanline_obj_##partial_alpha_op(combine_op, alpha_op, map_space); \ + } \ + } - bool isAffine = oam->split.affineMode & 1; - bool isDisabled = (oam->split.affineMode >> 1) & 1; +render_scanline_obj_builder(transparent, normal, 1D, no_partial_alpha); +render_scanline_obj_builder(transparent, normal, 2D, no_partial_alpha); +render_scanline_obj_builder(transparent, color16, 1D, no_partial_alpha); +render_scanline_obj_builder(transparent, color16, 2D, no_partial_alpha); +render_scanline_obj_builder(transparent, color32, 1D, no_partial_alpha); +render_scanline_obj_builder(transparent, color32, 2D, no_partial_alpha); +render_scanline_obj_builder(transparent, alpha_obj, 1D, no_partial_alpha); +render_scanline_obj_builder(transparent, alpha_obj, 2D, no_partial_alpha); +render_scanline_obj_builder(transparent, partial_alpha, 1D, partial_alpha); +render_scanline_obj_builder(transparent, partial_alpha, 2D, partial_alpha); +render_scanline_obj_builder(copy, copy_tile, 1D, no_partial_alpha); +render_scanline_obj_builder(copy, copy_tile, 2D, no_partial_alpha); +render_scanline_obj_builder(copy, copy_bitmap, 1D, no_partial_alpha); +render_scanline_obj_builder(copy, copy_bitmap, 2D, no_partial_alpha); + +#define OBJ_MOD_NORMAL 0 +#define OBJ_MOD_SEMITRAN 1 +#define OBJ_MOD_WINDOW 2 +#define OBJ_MOD_INVALID 3 + +// Goes through the object list in the OAM (from #127 to #0) and adds objects +// into a sorted list by priority for the current row. +// Invisible objects are discarded. +static void order_obj(u32 video_mode) +{ + s32 obj_num; + u32 row; + t_oam *oam_base = (t_oam *)OAM; + + memset(obj_priority_count, 0, sizeof(obj_priority_count)); + memset(obj_alpha_count, 0, sizeof(obj_alpha_count)); + + for (obj_num = 127; obj_num >= 0; obj_num--) { + OamData *oam_data = (OamData *)&OAM[obj_num * OAM_DATA_SIZE_AFFINE]; + t_oam *oam_ptr = &oam_base[obj_num]; + u16 obj_attr0 = eswap16(oam_ptr->attr0); + // Bit 9 disables regular sprites. Used as double bit for affine ones. + bool visible = oam_data->split.affineMode != 2; + if (visible) { + u16 obj_shape = obj_attr0 >> 14; + u32 obj_mode = (obj_attr0 >> 10) & 0x03; + + // Prohibited shape and mode + bool invalid = (obj_shape == 0x3) || (obj_mode == OBJ_MOD_INVALID); + if (!invalid) { + u16 obj_attr1 = eswap16(oam_ptr->attr1); + u16 obj_attr2 = eswap16(oam_ptr->attr2); + u32 obj_priority = (obj_attr2 >> 10) & 0x03; + + if (((video_mode < 3) || ((obj_attr2 & 0x3FF) >= 512))) { + // Calculate object size (from size and shape attr bits) + u16 obj_size = (obj_attr1 >> 14); + s32 obj_height = obj_dim_table[obj_shape][obj_size][1]; + s32 obj_width = obj_dim_table[obj_shape][obj_size][0]; + s32 obj_y = obj_attr0 & 0xFF; - if (!isAffine && isDisabled) - continue; +#if !EXTENDED_OAM + if (obj_y > DISPLAY_HEIGHT) + obj_y -= 512; +#endif - s32 idx = (oam->split.shape << 2) | oam->split.size; - unsigned int width = gOamShapesSizes[idx][0]; - unsigned int height = gOamShapesSizes[idx][1]; - int halfW = width / 2; - int halfH = height / 2; + // Double size for affine sprites with double bit set + if (obj_attr0 & 0x200) { + obj_height *= 2; + obj_width *= 2; + } - int32_t sx = oam->split.x; - int32_t sy = oam->split.y; + if (((obj_y + obj_height) > 0) && (obj_y < DISPLAY_HEIGHT)) { + s32 obj_x = oam_data->split.x; #if !EXTENDED_OAM - if (sx >= DISPLAY_WIDTH) - sx -= 512; - if (sy >= DISPLAY_HEIGHT) - sy -= 256; + if (obj_x > DISPLAY_WIDTH) + obj_x -= 512; #endif - // double-size affine sprites have 2x bounding box - if (isAffine && isDisabled) { - halfW *= 2; - halfH *= 2; + if (((obj_x + obj_width) > 0) && (obj_x < DISPLAY_WIDTH)) { + // Clip Y coord and height to the 0..159 interval + u32 starty = MAX(obj_y, 0); + u32 endy = MIN(obj_y + obj_height, DISPLAY_HEIGHT); + + switch (obj_mode) { + case OBJ_MOD_SEMITRAN: + for (row = starty; row < endy; row++) { + u32 cur_cnt = obj_priority_count[obj_priority][row]; + obj_priority_list[obj_priority][row][cur_cnt] = obj_num; + obj_priority_count[obj_priority][row] = cur_cnt + 1; + // Mark the row as having semi-transparent objects + obj_alpha_count[row] = 1; + } + break; + case OBJ_MOD_WINDOW: + obj_priority = 4; + /* fallthrough */ + case OBJ_MOD_NORMAL: + // Add the object to the list. + for (row = starty; row < endy; row++) { + u32 cur_cnt = obj_priority_count[obj_priority][row]; + obj_priority_list[obj_priority][row][cur_cnt] = obj_num; + obj_priority_count[obj_priority][row] = cur_cnt + 1; + } + break; + }; + } + } + } + } } + } +} + +u32 layer_order[16]; +u32 layer_count; + +// Sorts active BG/OBJ layers and generates an ordered list of layers. +// Things are drawn back to front, so lowest priority goes first. +static void order_layers(u32 layer_flags, u32 vcnt) +{ + bool obj_enabled = (layer_flags & 0x10); + s32 priority; + + layer_count = 0; - if ((int)vcount < sy || (int)vcount >= sy + halfH * 2) - continue; - if (sx + halfW * 2 < 0 || sx >= DISPLAY_WIDTH) - continue; + for (priority = 3; priority >= 0; priority--) { + bool anyobj = obj_priority_count[priority][vcnt] > 0; + s32 lnum; - int pri = oam->split.priority; - if (sActiveSpriteCount[pri] < MAX_SPRITES_PER_PRIORITY) { - sActiveSprites[pri][sActiveSpriteCount[pri]].oamIndex = i; - sActiveSpriteCount[pri]++; + for (lnum = 3; lnum >= 0; lnum--) { + if (((layer_flags >> lnum) & 1) && ((read_ioreg(REG_ADDR_BGxCNT(lnum)) & 0x03) == priority)) { + layer_order[layer_count++] = lnum; + } } + + if (obj_enabled && anyobj) + layer_order[layer_count++] = priority | 0x04; } } -static void DrawSpritesAtPriority(int priority, uint16_t vcount, uint16_t *output, uint8_t *layerIds, bool windowsEnabled, - uint16_t *winMask, unsigned int blendMode, bool objWinOnly, unsigned int bldcnt, unsigned int eva, - unsigned int evb, unsigned int evy) -{ - uint8_t *tiledata = (uint8_t *)OBJ_VRAM0; - uint16_t *sprpal = (uint16_t *)PLTT + (0x200 / 2); - int16_t matrix[2][2]; +#define fill_line(_start, _end) \ + u32 i; \ + \ + for (i = _start; i < _end; i++) \ + dest_ptr[i] = color; - // only 1-D tile mapping supported - if (!(REG_DISPCNT & (1 << 6))) - return; +#define fill_line_color_normal() color = PLTT[color] - for (int s = 0; s < sActiveSpriteCount[priority]; s++) { - int i = sActiveSprites[priority][s].oamIndex; - OamData *oam = &((OamData *)OAM)[i]; +#define fill_line_color_alpha() - bool isAffine = oam->split.affineMode & 1; - bool doubleSize = (oam->split.affineMode >> 1) & 1; +#define fill_line_color_color16() - s32 idx = (oam->split.shape << 2) | oam->split.size; - unsigned int width = gOamShapesSizes[idx][0]; - unsigned int height = gOamShapesSizes[idx][1]; - int halfW = width / 2; - int halfH = height / 2; +#define fill_line_color_color32() + +#define fill_line_builder(type) \ + static void fill_line_##type(u16 color, render_scanline_dest_##type *dest_ptr, u32 start, u32 end) \ + { \ + fill_line_color_##type(); \ + fill_line(start, end); \ + } + +fill_line_builder(normal); +fill_line_builder(alpha); +fill_line_builder(color16); +fill_line_builder(color32); + +// Blending is performed by separating an RGB value into 0G0R0B (32 bit) +// Since blending factors are at most 16, mult/add operations do not overflow +// to the neighbouring color and can be performed much faster than separatedly + +// Here follow the mask value to separate/expand the color to 32 bit, +// the mask to detect overflows in the blend operation and + +#define BLND_MSK (SATR_MSK | SATG_MSK | SATB_MSK) + +#define OVFG_MSK 0x04000000 +#define OVFR_MSK 0x00008000 +#define OVFB_MSK 0x00000020 +#define SATG_MSK 0x03E00000 +#define SATR_MSK 0x00007C00 +#define SATB_MSK 0x0000001F + +// Alpha blend two pixels (pixel_top and pixel_bottom). + +#define blend_pixel() \ + pixel_bottom = PLTT[(pixel_pair >> 16) & 0x1FF]; \ + pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & BLND_MSK; \ + pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4 + +// Alpha blend two pixels, allowing for saturation (individual channels > 31). +// The operation is optimized towards saturation not occuring. + +#define blend_saturate_pixel() \ + pixel_bottom = PLTT[(pixel_pair >> 16) & 0x1FF]; \ + pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & BLND_MSK; \ + pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4; \ + if (pixel_top & (OVFR_MSK | OVFG_MSK | OVFB_MSK)) { \ + if (pixel_top & OVFG_MSK) \ + pixel_top |= SATG_MSK; \ + \ + if (pixel_top & OVFR_MSK) \ + pixel_top |= SATR_MSK; \ + \ + if (pixel_top & OVFB_MSK) \ + pixel_top |= SATB_MSK; \ + } + +#define brighten_pixel() pixel_top = upper + ((pixel_top * blend) >> 4); + +#define darken_pixel() pixel_top = (pixel_top * blend) >> 4; + +#define effect_condition_alpha ((pixel_pair & 0x04000200) == 0x04000200) + +#define effect_condition_fade(pixel_source) ((pixel_source & 0x00000200) == 0x00000200) + +#define expand_pixel_no_dest(expand_type, pixel_source) \ + pixel_top = (pixel_top | (pixel_top << 16)) & BLND_MSK; \ + expand_type##_pixel(); \ + pixel_top &= BLND_MSK; \ + pixel_top = (pixel_top >> 16) | pixel_top + +#define expand_pixel(expand_type, pixel_source) \ + pixel_top = PLTT[pixel_source & 0x1FF]; \ + expand_pixel_no_dest(expand_type, pixel_source); \ + *screen_dest_ptr = pixel_top + +#define expand_loop(expand_type, effect_condition, pixel_source) \ + screen_src_ptr += start; \ + screen_dest_ptr += start; \ + \ + end -= start; \ + \ + for (i = 0; i < end; i++) { \ + pixel_source = *screen_src_ptr; \ + if (effect_condition) { \ + expand_pixel(expand_type, pixel_source); \ + } else { \ + *screen_dest_ptr = PLTT[pixel_source & 0x1FF]; \ + } \ + \ + screen_src_ptr++; \ + screen_dest_ptr++; \ + } + +#define expand_loop_partial_alpha(alpha_expand, expand_type) \ + screen_src_ptr += start; \ + screen_dest_ptr += start; \ + \ + end -= start; \ + \ + for (i = 0; i < end; i++) { \ + pixel_pair = *screen_src_ptr; \ + if (effect_condition_fade(pixel_pair)) { \ + if (effect_condition_alpha) { \ + expand_pixel(alpha_expand, pixel_pair); \ + } else { \ + expand_pixel(expand_type, pixel_pair); \ + } \ + } else { \ + *screen_dest_ptr = PLTT[pixel_pair & 0x1FF]; \ + } \ + \ + screen_src_ptr++; \ + screen_dest_ptr++; \ + } + +#define expand_partial_alpha(expand_type) \ + if ((blend_a + blend_b) > 16) { \ + expand_loop_partial_alpha(blend_saturate, expand_type); \ + } else { \ + expand_loop_partial_alpha(blend, expand_type); \ + } + +// Blend top two pixels of scanline with each other. + +#define expand_normal(screen_ptr, start, end) + +void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end); + +#ifndef ARM_ARCH_BLENDING_OPTS + +void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) +{ + u32 pixel_pair; + u32 pixel_top, pixel_bottom; + u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); + u32 blend_a = bldalpha & 0x1F; + u32 blend_b = (bldalpha >> 8) & 0x1F; + u32 i; + + if (blend_a > 16) + blend_a = 16; + + if (blend_b > 16) + blend_b = 16; + + // The individual colors can saturate over 31, this should be taken + // care of in an alternate pass as it incurs a huge additional speedhit. + if ((blend_a + blend_b) > 16) { + expand_loop(blend_saturate, effect_condition_alpha, pixel_pair); + } else { + expand_loop(blend, effect_condition_alpha, pixel_pair); + } +} - int32_t x = oam->split.x; - int32_t y = oam->split.y; -#if !EXTENDED_OAM - if (x >= DISPLAY_WIDTH) - x -= 512; - if (y >= DISPLAY_HEIGHT) - y -= 256; #endif - if (isAffine && doubleSize) { - halfW *= 2; - halfH *= 2; - } - bool isSemiTransparent = (oam->split.objMode == 1); - bool isObjWin = (oam->split.objMode == 2); - - if (objWinOnly && !isObjWin) - continue; - if (!objWinOnly && isObjWin) - continue; - - int rectWidth = width; - int rectHeight = height; - - if (isAffine) { - u8 matrixNum = oam->split.matrixNum * 4; - OamData *m0 = &((OamData *)OAM)[matrixNum]; - OamData *m1 = &((OamData *)OAM)[matrixNum + 1]; - OamData *m2 = &((OamData *)OAM)[matrixNum + 2]; - OamData *m3 = &((OamData *)OAM)[matrixNum + 3]; - matrix[0][0] = m0->all.affineParam; - matrix[0][1] = m1->all.affineParam; - matrix[1][0] = m2->all.affineParam; - matrix[1][1] = m3->all.affineParam; - if (doubleSize) { - rectWidth *= 2; - rectHeight *= 2; - } - } else { - matrix[0][0] = 0x100; // identity in 8.8 fixed point - matrix[0][1] = 0; - matrix[1][0] = 0; - matrix[1][1] = 0x100; - } +// Blend scanline with white. - x += halfW; - y += halfH; - - int localY = (oam->split.mosaic == 1) ? ApplyMosaicSprY(vcount) - y : vcount - y; - bool flipX = !isAffine && ((oam->split.matrixNum >> 3) & 1); - bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); - bool is8bpp = oam->split.bpp & 1; - - int startLX = -halfW; - int endLX = halfW; - if (startLX + x < 0) - startLX = -x; - if (endLX + x >= DISPLAY_WIDTH) - endLX = DISPLAY_WIDTH - 1 - x; - - // fast path: non-affine 4bpp, no mosaic -- batched tile row reads - if (!isAffine && !is8bpp && !oam->split.mosaic) { - int texY = localY + halfH; - if (flipY) - texY = height - texY - 1; - if (texY < 0 || texY >= (int)height) - continue; - - int tileRowY = texY & 7; - int blockY = texY >> 3; - int tilesPerRow = (REG_DISPCNT & 0x40) ? ((int)width >> 3) : 16; - int tileBase = blockY * tilesPerRow + oam->split.tileNum; - int rowByteOff = tileRowY << 2; - uint16_t *pixpal = sprpal + (oam->split.paletteNum << 4); - - int lx = startLX; - while (lx <= endLX) { - int rawX = lx + halfW; - int texX = flipX ? ((int)width - 1 - rawX) : rawX; - - if (texX < 0 || texX >= (int)width) { - lx++; - continue; - } +static void expand_darken(u16 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) +{ + u32 pixel_top; + s32 blend = 16 - (read_ioreg(REG_ADDR_BLDY) & 0x1F); + u32 i; - int blockX = texX >> 3; - int tileXStart = texX & 7; + if (blend < 0) + blend = 0; - uint32_t rowData = *(uint32_t *)(tiledata + ((tileBase + blockX) << 5) + rowByteOff); + expand_loop(darken, effect_condition_fade(pixel_top), pixel_top); +} - int pixelsInTile = !flipX ? (8 - tileXStart) : (tileXStart + 1); - int remain = endLX - lx + 1; - if (pixelsInTile > remain) - pixelsInTile = remain; +// Blend scanline with black. - if (!flipX) { - int texRemain = (int)width - texX; - if (pixelsInTile > texRemain) - pixelsInTile = texRemain; - } else { - int texRemain = texX + 1; - if (pixelsInTile > texRemain) - pixelsInTile = texRemain; - } +static void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) +{ + u32 pixel_top; + u32 blend = read_ioreg(REG_ADDR_BLDY) & 0x1F; + u32 upper; + u32 i; - for (int p = 0; p < pixelsInTile; p++, lx++) { - int curTX = flipX ? (tileXStart - p) : (tileXStart + p); - uint8_t pixel = (rowData >> (curTX << 2)) & 0xF; - if (pixel == 0) - continue; + if (blend > 16) + blend = 16; - int gx = lx + x; - uint16_t color = pixpal[pixel]; + upper = ((BLND_MSK * blend) >> 4) & BLND_MSK; + blend = 16 - blend; - // obj window sprites modify the window mask, not the framebuffer - if (isObjWin) { - if (windowsEnabled && winMask && (winMask[gx] & WINMASK_WINOUT)) - winMask[gx] = (REG_WINOUT >> 8) & 0x3F; - continue; - } + expand_loop(brighten, effect_condition_fade(pixel_top), pixel_top); +} - if (layerIds && blendMode != 0) - color = BlendSpritePixel(color, gx, output, layerIds, isSemiTransparent, blendMode, bldcnt, windowsEnabled, winMask, - eva, evb, evy); +// Expand scanline such that if both top and bottom pass it's alpha, +// if only top passes it's as specified, and if neither pass it's normal. - if (windowsEnabled && winMask && !(winMask[gx] & WINMASK_OBJ)) - continue; +static void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) +{ + s32 blend = 16 - (read_ioreg(REG_ADDR_BLDY) & 0x1F); + u32 pixel_pair; + u32 pixel_top, pixel_bottom; + u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); + u32 blend_a = bldalpha & 0x1F; + u32 blend_b = (bldalpha >> 8) & 0x1F; + u32 i; - output[gx] = color | COLOR_OPAQUE; - if (layerIds) - layerIds[gx] = LAYER_OBJ; - } - } - continue; - } + if (blend < 0) + blend = 0; - // generic path: affine, 8bpp, or mosaic -- per pixel - for (int localX = startLX; localX <= endLX; localX++) { - int gx = localX + x; - int texX, texY; - - if (!isAffine) { - int lmx = localX; - if (oam->split.mosaic == 1) - lmx = ApplyMosaicSprX(gx) - x; - texX = lmx + halfW; - texY = localY + halfH; - if (flipX) - texX = width - texX - 1; - if (flipY) - texY = height - texY - 1; - } else { - int lmx = localX; - int lmy = localY; - if (oam->split.mosaic == 1) { - lmx = ApplyMosaicSprX(gx) - x; - lmy = ApplyMosaicSprY(vcount) - y; - } - // apply 2x2 affine matrix (8.8 fixed point) - texX = ((matrix[0][0] * lmx + matrix[0][1] * lmy) >> 8) + (width / 2); - texY = ((matrix[1][0] * lmx + matrix[1][1] * lmy) >> 8) + (height / 2); - } + if (blend_a > 16) + blend_a = 16; - if (texX < 0 || texY < 0 || texX >= (int)width || texY >= (int)height) - continue; - - int tileX = texX & 7; - int tileY = texY & 7; - int blockX = texX >> 3; - int blockY = texY >> 3; - int blockOffset = blockY * (REG_DISPCNT & 0x40 ? ((int)width >> 3) : 16) + blockX; - - uint16_t pixel = 0; - uint16_t *pixpal; - - if (!is8bpp) { - int tdi = ((blockOffset + oam->split.tileNum) << 5) + (tileY << 2) + (tileX >> 1); - pixel = tiledata[tdi]; - if (tileX & 1) - pixel >>= 4; - else - pixel &= 0xF; - pixpal = sprpal + (oam->split.paletteNum << 4); - } else { - pixel = tiledata[((blockOffset * 2 + oam->split.tileNum) << 5) + (tileY << 3) + tileX]; - pixpal = sprpal; - } + if (blend_b > 16) + blend_b = 16; - if (pixel == 0) - continue; + expand_partial_alpha(darken); +} + +static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) +{ + s32 blend = read_ioreg(REG_ADDR_BLDY) & 0x1F; + u32 pixel_pair; + u32 pixel_top, pixel_bottom; + u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); + u32 blend_a = bldalpha & 0x1F; + u32 blend_b = (bldalpha >> 8) & 0x1F; + u32 upper; + u32 i; - uint16_t color = pixpal[pixel]; + if (blend > 16) + blend = 16; - if (isObjWin) { - if (windowsEnabled && winMask && (winMask[gx] & WINMASK_WINOUT)) - winMask[gx] = (REG_WINOUT >> 8) & 0x3F; - continue; - } + upper = ((BLND_MSK * blend) >> 4) & BLND_MSK; + blend = 16 - blend; - if (layerIds && blendMode != 0) - color = BlendSpritePixel(color, gx, output, layerIds, isSemiTransparent, blendMode, bldcnt, windowsEnabled, winMask, eva, - evb, evy); + if (blend_a > 16) + blend_a = 16; - if (windowsEnabled && winMask && !(winMask[gx] & WINMASK_OBJ)) - continue; + if (blend_b > 16) + blend_b = 16; - output[gx] = color | COLOR_OPAQUE; - if (layerIds) - layerIds[gx] = LAYER_OBJ; + expand_partial_alpha(brighten); +} + +// Render an OBJ layer from start to end, depending on the type (1D or 2D) +// stored in dispcnt. + +#define render_obj_layer(type, dest, _start, _end) \ + current_layer &= ~0x04; \ + if (dispcnt & 0x40) \ + render_scanline_obj_##type##_1D(current_layer, _start, _end, dest); \ + else \ + render_scanline_obj_##type##_2D(current_layer, _start, _end, dest) + +// Render a target all the way with the background color as taken from the +// palette. + +#define fill_line_bg(type, dest, _start, _end) fill_line_##type(0, dest, _start, _end) + +// Render all layers as they appear in the layer order. + +#define render_layers(tile_alpha, obj_alpha, dest) \ + { \ + current_layer = layer_order[0]; \ + if (current_layer & 0x04) { \ + /* If the first one is OBJ render the background then render it. */ \ + fill_line_bg(tile_alpha, dest, 0, DISPLAY_WIDTH); \ + render_obj_layer(obj_alpha, dest, 0, DISPLAY_WIDTH); \ + } else { \ + /* Otherwise render a base layer. */ \ + layer_renderers[current_layer].tile_alpha##_render_base(current_layer, 0, DISPLAY_WIDTH, dest); \ + } \ + \ + /* Render the rest of the layers. */ \ + for (layer_order_pos = 1; layer_order_pos < layer_count; layer_order_pos++) { \ + current_layer = layer_order[layer_order_pos]; \ + if (current_layer & 0x04) { \ + render_obj_layer(obj_alpha, dest, 0, DISPLAY_WIDTH); \ + } else { \ + layer_renderers[current_layer].tile_alpha##_render_transparent(current_layer, 0, DISPLAY_WIDTH, dest); \ + } \ + } \ + } + +#define render_condition_alpha \ + (((read_ioreg(REG_ADDR_BLDALPHA) & 0x1F1F) != 0x001F) && ((read_ioreg(REG_ADDR_BLDCNT) & 0x3F) != 0) \ + && ((read_ioreg(REG_ADDR_BLDCNT) & 0x3F00) != 0)) + +#define render_condition_fade (((read_ioreg(REG_ADDR_BLDY) & 0x1F) != 0) && ((read_ioreg(REG_ADDR_BLDCNT) & 0x3F) != 0)) + +#define render_layers_color_effect(renderer, layer_condition, alpha_condition, fade_condition, _start, _end) \ + { \ + if (layer_condition) { \ + if (obj_alpha_count[read_ioreg(REG_ADDR_VCOUNT)]) { \ + /* Render based on special effects mode. */ \ + u32 screen_buffer[DISPLAY_WIDTH]; \ + switch ((bldcnt >> 6) & 0x03) { \ + /* Alpha blend */ \ + case 0x01: { \ + if (alpha_condition) { \ + renderer(alpha, alpha_obj, screen_buffer); \ + expand_blend(screen_buffer, scanline, _start, _end); \ + return; \ + } \ + break; \ + } \ + \ + /* Fade to white */ \ + case 0x02: { \ + if (fade_condition) { \ + renderer(color32, partial_alpha, screen_buffer); \ + expand_brighten_partial_alpha(screen_buffer, scanline, _start, _end); \ + return; \ + } \ + break; \ + } \ + \ + /* Fade to black */ \ + case 0x03: { \ + if (fade_condition) { \ + renderer(color32, partial_alpha, screen_buffer); \ + expand_darken_partial_alpha(screen_buffer, scanline, _start, _end); \ + return; \ + } \ + break; \ + } \ + } \ + \ + renderer(color32, partial_alpha, screen_buffer); \ + expand_blend(screen_buffer, scanline, _start, _end); \ + } else { \ + /* Render based on special effects mode. */ \ + switch ((bldcnt >> 6) & 0x03) { \ + /* Alpha blend */ \ + case 0x01: { \ + if (alpha_condition) { \ + u32 screen_buffer[DISPLAY_WIDTH]; \ + renderer(alpha, alpha_obj, screen_buffer); \ + expand_blend(screen_buffer, scanline, _start, _end); \ + return; \ + } \ + break; \ + } \ + \ + /* Fade to white */ \ + case 0x02: { \ + if (fade_condition) { \ + renderer(color16, color16, scanline); \ + expand_brighten(scanline, scanline, _start, _end); \ + return; \ + } \ + break; \ + } \ + \ + /* Fade to black */ \ + case 0x03: { \ + if (fade_condition) { \ + renderer(color16, color16, scanline); \ + expand_darken(scanline, scanline, _start, _end); \ + return; \ + } \ + break; \ + } \ + } \ + \ + renderer(normal, normal, scanline); \ + expand_normal(scanline, _start, _end); \ + } \ + } else { \ + u32 pixel_top = PLTT[0]; \ + switch ((bldcnt >> 6) & 0x03) { \ + /* Fade to white */ \ + case 0x02: { \ + if (color_combine_mask_a(5)) { \ + u32 blend = read_ioreg(REG_ADDR_BLDY) & 0x1F; \ + u32 upper; \ + \ + if (blend > 16) \ + blend = 16; \ + \ + upper = ((BLND_MSK * blend) >> 4) & BLND_MSK; \ + blend = 16 - blend; \ + \ + expand_pixel_no_dest(brighten, pixel_top); \ + } \ + break; \ + } \ + \ + /* Fade to black */ \ + case 0x03: { \ + if (color_combine_mask_a(5)) { \ + s32 blend = 16 - (read_ioreg(REG_ADDR_BLDY) & 0x1F); \ + \ + if (blend < 0) \ + blend = 0; \ + \ + expand_pixel_no_dest(darken, pixel_top); \ + } \ + break; \ + } \ + } \ + fill_line_color16(pixel_top, scanline, _start, _end); \ + } \ + } + +// Renders an entire scanline from 0 to DISPLAY_WIDTH, based on current color mode. + +static void render_scanline_tile(u16 *scanline, u32 dispcnt) +{ + u32 current_layer; + u32 layer_order_pos; + u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); + render_scanline_layer_functions_tile(); + + render_layers_color_effect(render_layers, layer_count, render_condition_alpha, render_condition_fade, 0, DISPLAY_WIDTH); +} + +static void render_scanline_bitmap(u16 *scanline, u32 dispcnt) +{ + render_scanline_layer_functions_bitmap(); + u32 current_layer; + u32 layer_order_pos; + + fill_line_bg(normal, scanline, 0, DISPLAY_WIDTH); + + for (layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++) { + current_layer = layer_order[layer_order_pos]; + if (current_layer & 0x04) { + render_obj_layer(normal, scanline, 0, DISPLAY_WIDTH); + } else { + layer_renderers->normal_render(0, DISPLAY_WIDTH, scanline); } } } -static void DrawScanline(uint16_t *pixels, uint16_t vcount) +// Render layers from start to end based on if they're allowed in the +// enable flags. + +#define render_layers_conditional(tile_alpha, obj_alpha, dest) \ + { \ + __label__ skip; \ + current_layer = layer_order[layer_order_pos]; \ + /* If OBJ aren't enabled skip to the first non-OBJ layer */ \ + if (!(enable_flags & 0x10)) { \ + while ((current_layer & 0x04) || !((1 << current_layer) & enable_flags)) { \ + layer_order_pos++; \ + current_layer = layer_order[layer_order_pos]; \ + \ + /* Oops, ran out of layers, render the background. */ \ + if (layer_order_pos == layer_count) { \ + fill_line_bg(tile_alpha, dest, start, end); \ + goto skip; \ + } \ + } \ + \ + /* Render the first valid layer */ \ + layer_renderers[current_layer].tile_alpha##_render_base(current_layer, start, end, dest); \ + \ + layer_order_pos++; \ + \ + /* Render the rest of the layers if active, skipping OBJ ones. */ \ + for (; layer_order_pos < layer_count; layer_order_pos++) { \ + current_layer = layer_order[layer_order_pos]; \ + if (!(current_layer & 0x04) && ((1 << current_layer) & enable_flags)) { \ + layer_renderers[current_layer].tile_alpha##_render_transparent(current_layer, start, end, dest); \ + } \ + } \ + } else { \ + /* Find the first active layer, skip all of the inactive ones */ \ + while (!((current_layer & 0x04) || ((1 << current_layer) & enable_flags))) { \ + layer_order_pos++; \ + current_layer = layer_order[layer_order_pos]; \ + \ + /* Oops, ran out of layers, render the background. */ \ + if (layer_order_pos == layer_count) { \ + fill_line_bg(tile_alpha, dest, start, end); \ + goto skip; \ + } \ + } \ + \ + if (current_layer & 0x04) { \ + /* If the first one is OBJ render the background then render it. */ \ + fill_line_bg(tile_alpha, dest, start, end); \ + render_obj_layer(obj_alpha, dest, start, end); \ + } else { \ + /* Otherwise render a base layer. */ \ + layer_renderers[current_layer].tile_alpha##_render_base(current_layer, start, end, dest); \ + } \ + \ + layer_order_pos++; \ + \ + /* Render the rest of the layers. */ \ + for (; layer_order_pos < layer_count; layer_order_pos++) { \ + current_layer = layer_order[layer_order_pos]; \ + if (current_layer & 0x04) { \ + render_obj_layer(obj_alpha, dest, start, end); \ + } else { \ + if (enable_flags & (1 << current_layer)) { \ + layer_renderers[current_layer].tile_alpha##_render_transparent(current_layer, start, end, dest); \ + } \ + } \ + } \ + } \ + \ + skip:; \ + } + +// Render all of the BG and OBJ in a tiled scanline from start to end ONLY if +// enable_flag allows that layer/OBJ. Also conditionally render color effects. + +static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, + const tile_layer_render_struct *layer_renderers) +{ + u32 current_layer; + u32 layer_order_pos = 0; + + render_layers_color_effect(render_layers_conditional, (layer_count && (enable_flags & 0x1F)), + ((enable_flags & 0x20) && render_condition_alpha), ((enable_flags & 0x20) && render_condition_fade), start, + end); +} + +// Render the BG and OBJ in a bitmap scanline from start to end ONLY if +// enable_flag allows that layer/OBJ. Also conditionally render color effects. + +static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, + const bitmap_layer_render_struct *layer_renderers) { - unsigned int mode = REG_DISPCNT & 3; - unsigned int numBGs = (mode == 0) ? 4 : 3; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; - unsigned int enabledBgs = (REG_DISPCNT >> 8) & 0xF; - - // sort bgs by priority - uint16_t bgcnts[4]; - char bgPriority[4]; - char bgsByPri[4][4]; - char bgsByPriCount[4] = { 0, 0, 0, 0 }; - - for (int bg = 0; bg < (int)numBGs; bg++) { - uint16_t cnt = *(uint16_t *)(REG_ADDR_BG0CNT + bg * 2); - bgcnts[bg] = cnt; - uint16_t pri = cnt & 3; - bgPriority[bg] = pri; - bgsByPri[pri][bgsByPriCount[pri]] = bg; - bgsByPriCount[pri]++; - } - - // window setup - bool windowsEnabled = false; - u16 win0Bot, win0Top, win0Right, win0Left; - u16 win1Bot, win1Top, win1Right, win1Left; - bool win0Active = false, win1Active = false; - static uint16_t winMask[DISPLAY_WIDTH]; - - if (REG_DISPCNT & DISPCNT_WIN0_ON) { - win0Bot = WIN_GET_HIGHER(REG_WIN0V); - win0Top = WIN_GET_LOWER(REG_WIN0V); - win0Right = WIN_GET_HIGHER(REG_WIN0H); - win0Left = WIN_GET_LOWER(REG_WIN0H); - if (win0Top > win0Bot) - win0Active = (vcount >= win0Top || vcount < win0Bot); - else - win0Active = (vcount >= win0Top && vcount < win0Bot); - windowsEnabled = true; - } - if (REG_DISPCNT & DISPCNT_WIN1_ON) { - win1Bot = WIN_GET_HIGHER(REG_WIN1V); - win1Top = WIN_GET_LOWER(REG_WIN1V); - win1Right = WIN_GET_HIGHER(REG_WIN1H); - win1Left = WIN_GET_LOWER(REG_WIN1H); - if (win1Top > win1Bot) - win1Active = (vcount >= win1Top || vcount < win1Bot); - else - win1Active = (vcount >= win1Top && vcount < win1Bot); - windowsEnabled = true; - } - if ((REG_DISPCNT & DISPCNT_OBJWIN_ON) && (REG_DISPCNT & DISPCNT_OBJ_ON)) - windowsEnabled = true; - - // build per-pixel window mask - if (windowsEnabled) { - for (unsigned int xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - if (win0Active && WindowContainsX(win0Left, win0Right, xpos)) - winMask[xpos] = REG_WININ & 0x3F; - else if (win1Active && WindowContainsX(win1Left, win1Right, xpos)) - winMask[xpos] = (REG_WININ >> 8) & 0x3F; - else - winMask[xpos] = (REG_WINOUT & 0x3F) | WINMASK_WINOUT; + u32 current_layer; + u32 layer_order_pos; + + fill_line_bg(normal, scanline, start, end); + + for (layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++) { + current_layer = layer_order[layer_order_pos]; + if (current_layer & 0x04) { + if (enable_flags & 0x10) { + render_obj_layer(normal, scanline, start, end); + } + } else { + if (enable_flags & 0x04) + layer_renderers->normal_render(start, end, scanline); } } +} - PrefilterSprites(vcount); - - // layerIds tracks who wrote each pixel so alpha blend can find target-b - static uint8_t layerIds[DISPLAY_WIDTH]; - bool needLayerIds = (blendMode != 0 || windowsEnabled); - uint8_t *lids = needLayerIds ? layerIds : NULL; - uint16_t *wmask = windowsEnabled ? winMask : NULL; - - if (needLayerIds) - memset(layerIds, LAYER_BACKDROP, DISPLAY_WIDTH); - - // grab blend regs once per scanline - unsigned int bldcnt = REG_BLDCNT; - unsigned int bld_eva = REG_BLDALPHA & 0x1F; - unsigned int bld_evb = (REG_BLDALPHA >> 8) & 0x1F; - unsigned int bld_evy = REG_BLDY & 0x1F; - - // obj window pass -- these sprites modify the window mask, not the framebuffer - if (windowsEnabled && (REG_DISPCNT & DISPCNT_OBJWIN_ON) && (REG_DISPCNT & DISPCNT_OBJ_ON)) { - for (int pri = 0; pri < 4; pri++) - DrawSpritesAtPriority(pri, vcount, pixels, lids, windowsEnabled, wmask, blendMode, - /*objWinOnly=*/true, bldcnt, bld_eva, bld_evb, bld_evy); - } - - // back-to-front: priority 3 first, 0 last (0 is topmost) - for (int pri = 3; pri >= 0; pri--) { - for (int sub = bgsByPriCount[pri] - 1; sub >= 0; sub--) { - int bg = bgsByPri[pri][sub]; - if (!IsBGEnabled(bg)) - continue; - - if (!needLayerIds) { - switch (mode) { - case 0: - RenderTextBG(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), - vcount, pixels); - break; - case 1: - if (bg == 2) - RenderAffineBG(bg, bgcnts[bg], vcount, pixels); - else - RenderTextBG(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), - vcount, pixels); - break; - } +#define window_x_coords(window_number) \ + window_##window_number##_x1 = read_ioreg(REG_ADDR_WIN##window_number##H) >> 8; \ + window_##window_number##_x2 = read_ioreg(REG_ADDR_WIN##window_number##H) & 0xFF; \ + window_##window_number##_enable = (winin >> (window_number * 8)) & 0x3F; \ + \ + if (window_##window_number##_x1 > DISPLAY_WIDTH) \ + window_##window_number##_x1 = DISPLAY_WIDTH; \ + \ + if (window_##window_number##_x2 > DISPLAY_WIDTH) \ + window_##window_number##_x2 = DISPLAY_WIDTH + +#define window_coords(window_number) \ + u32 window_##window_number##_x1, window_##window_number##_x2; \ + u32 window_##window_number##_y1, window_##window_number##_y2; \ + u32 window_##window_number##_enable = 0; \ + window_##window_number##_y1 = read_ioreg(REG_ADDR_WIN##window_number##V) >> 8; \ + window_##window_number##_y2 = read_ioreg(REG_ADDR_WIN##window_number##V) & 0xFF; \ + \ + if (window_##window_number##_y1 > window_##window_number##_y2) { \ + if ((((vcount <= window_##window_number##_y2) || (vcount > window_##window_number##_y1)) \ + || (window_##window_number##_y2 > (DISPLAY_WIDTH - 13))) \ + && (window_##window_number##_y1 <= (DISPLAY_WIDTH - 13))) { \ + window_x_coords(window_number); \ + } else { \ + window_##window_number##_x1 = DISPLAY_WIDTH; \ + window_##window_number##_x2 = DISPLAY_WIDTH; \ + } \ + } else { \ + if ((((vcount >= window_##window_number##_y1) && (vcount < window_##window_number##_y2)) \ + || (window_##window_number##_y2 > (DISPLAY_WIDTH - 13))) \ + && (window_##window_number##_y1 <= (DISPLAY_WIDTH - 13))) { \ + window_x_coords(window_number); \ + } else { \ + window_##window_number##_x1 = DISPLAY_WIDTH; \ + window_##window_number##_x2 = DISPLAY_WIDTH; \ + } \ + } + +#define render_window_segment(type, start, end, window_type) \ + if (start != end) { \ + render_scanline_conditional_##type(start, end, scanline, window_##window_type##_enable, dispcnt, bldcnt, layer_renderers); \ + } + +#define render_window_segment_unequal(type, start, end, window_type) \ + render_scanline_conditional_##type(start, end, scanline, window_##window_type##_enable, dispcnt, bldcnt, layer_renderers) + +#define render_window_segment_clip(type, clip_start, clip_end, start, end, window_type) \ + { \ + if (start != end) { \ + if (start < clip_start) { \ + if (end > clip_start) { \ + if (end > clip_end) { \ + render_window_segment_unequal(type, clip_start, clip_end, window_type); \ + } else { \ + render_window_segment_unequal(type, clip_start, end, window_type); \ + } \ + } \ + } else \ + \ + if (end > clip_end) { \ + if (start < clip_end) \ + render_window_segment_unequal(type, start, clip_end, window_type); \ + } else { \ + render_window_segment_unequal(type, start, end, window_type); \ + } \ + } \ + } + +#define render_window_clip_1(type, start, end) \ + if (window_1_x1 != DISPLAY_WIDTH) { \ + if (window_1_x1 > window_1_x2) { \ + render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \ + render_window_segment_clip(type, start, end, window_1_x2, window_1_x1, out); \ + render_window_segment_clip(type, start, end, window_1_x1, DISPLAY_WIDTH, 1); \ + } else { \ + render_window_segment_clip(type, start, end, 0, window_1_x1, out); \ + render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, 1); \ + render_window_segment_clip(type, start, end, window_1_x2, DISPLAY_WIDTH, out); \ + } \ + } else { \ + render_window_segment(type, start, end, out); \ + } + +#define render_window_clip_obj(type, start, end) \ + ; \ + render_window_segment(type, start, end, out); \ + if (dispcnt & 0x40) \ + render_scanline_obj_copy_##type##_1D(4, start, end, scanline); \ + else \ + render_scanline_obj_copy_##type##_2D(4, start, end, scanline) + +#define render_window_segment_clip_obj(type, clip_start, clip_end, start, end) \ + { \ + if (start != end) { \ + if (start < clip_start) { \ + if (end > clip_start) { \ + if (end > clip_end) { \ + render_window_clip_obj(type, clip_start, clip_end); \ + } else { \ + render_window_clip_obj(type, clip_start, end); \ + } \ + } \ + } else \ + \ + if (end > clip_end) { \ + if (start < clip_end) { \ + render_window_clip_obj(type, start, clip_end); \ + } \ + } else { \ + render_window_clip_obj(type, start, end); \ + } \ + } \ + } + +#define render_window_clip_1_obj(type, start, end) \ + if (window_1_x1 != DISPLAY_WIDTH) { \ + if (window_1_x1 > window_1_x2) { \ + render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \ + render_window_segment_clip_obj(type, start, end, window_1_x2, window_1_x1); \ + render_window_segment_clip(type, start, end, window_1_x1, DISPLAY_WIDTH, 1); \ + } else { \ + render_window_segment_clip_obj(type, start, end, 0, window_1_x1); \ + render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, 1); \ + render_window_segment_clip_obj(type, start, end, window_1_x2, DISPLAY_WIDTH); \ + } \ + } else { \ + render_window_clip_obj(type, start, end); \ + } + +#define render_window_single(type, window_number) \ + u32 winin = read_ioreg(REG_ADDR_WININ); \ + window_coords(window_number); \ + if (window_##window_number##_x1 > window_##window_number##_x2) { \ + render_window_segment(type, 0, window_##window_number##_x2, window_number); \ + render_window_segment(type, window_##window_number##_x2, window_##window_number##_x1, out); \ + render_window_segment(type, window_##window_number##_x1, DISPLAY_WIDTH, window_number); \ + } else { \ + render_window_segment(type, 0, window_##window_number##_x1, out); \ + render_window_segment(type, window_##window_number##_x1, window_##window_number##_x2, window_number); \ + render_window_segment(type, window_##window_number##_x2, DISPLAY_WIDTH, out); \ + } + +#define render_window_multi(type, front, back) \ + if (window_##front##_x1 > window_##front##_x2) { \ + render_window_segment(type, 0, window_##front##_x2, front); \ + render_window_clip_##back(type, window_##front##_x2, window_##front##_x1); \ + render_window_segment(type, window_##front##_x1, DISPLAY_WIDTH, front); \ + } else { \ + render_window_clip_##back(type, 0, window_##front##_x1); \ + render_window_segment(type, window_##front##_x1, window_##front##_x2, front); \ + render_window_clip_##back(type, window_##front##_x2, DISPLAY_WIDTH); \ + } + +#define render_scanline_window_builder(type) \ + static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ + { \ + u32 vcount = read_ioreg(REG_ADDR_VCOUNT); \ + u32 winout = read_ioreg(REG_ADDR_WINOUT); \ + u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); \ + u32 window_out_enable = winout & 0x3F; \ + \ + render_scanline_layer_functions_##type(); \ + \ + switch (dispcnt >> 13) { \ + /* Just window 0 */ \ + case 0x01: { \ + render_window_single(type, 0); \ + break; \ + } \ + \ + /* Just window 1 */ \ + case 0x02: { \ + render_window_single(type, 1); \ + break; \ + } \ + \ + /* Windows 1 and 2 */ \ + case 0x03: { \ + u32 winin = read_ioreg(REG_ADDR_WININ); \ + window_coords(0); \ + window_coords(1); \ + render_window_multi(type, 0, 1); \ + break; \ + } \ + \ + /* Just OBJ windows */ \ + case 0x04: { \ + render_window_clip_obj(type, 0, DISPLAY_WIDTH); \ + break; \ + } \ + \ + /* Window 0 and OBJ window */ \ + case 0x05: { \ + u32 winin = read_ioreg(REG_ADDR_WININ); \ + window_coords(0); \ + render_window_multi(type, 0, obj); \ + break; \ + } \ + \ + /* Window 1 and OBJ window */ \ + case 0x06: { \ + u32 winin = read_ioreg(REG_ADDR_WININ); \ + window_coords(1); \ + render_window_multi(type, 1, obj); \ + break; \ + } \ + \ + /* Window 0, 1, and OBJ window */ \ + case 0x07: { \ + u32 winin = read_ioreg(REG_ADDR_WININ); \ + window_coords(0); \ + window_coords(1); \ + render_window_multi(type, 0, 1_obj); \ + break; \ + } \ + } \ + } + +render_scanline_window_builder(tile); +render_scanline_window_builder(bitmap); + +static const u8 active_layers[] = { + 0x1F, // Mode 0, Tile BG0-3 and OBJ + 0x17, // Mode 1, Tile BG0-2 and OBJ + 0x1C, // Mode 2, Tile BG2-3 and OBJ + 0x14, // Mode 3, BMP BG2 and OBJ + 0x14, // Mode 4, BMP BG2 and OBJ + 0x14, // Mode 5, BMP BG2 and OBJ + 0, // Unused + 0, +}; + +void update_scanline(void) +{ + u32 pitch = get_screen_pitch(); + u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u32 vcount = read_ioreg(REG_ADDR_VCOUNT); + u16 *screen_offset = get_screen_pixels() + (vcount * pitch); + u32 video_mode = dispcnt & 0x07; + + order_layers((dispcnt >> 8) & active_layers[video_mode], vcount); + + // If the screen is in in forced blank draw pure white. + if (dispcnt & 0x80) { + fill_line_color16(0xFFFF, screen_offset, 0, DISPLAY_WIDTH); + } else { + if (video_mode < 3) { + if (dispcnt >> 13) { + render_scanline_window_tile(screen_offset, dispcnt); } else { - switch (mode) { - case 0: - RenderTextBGBlend(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), - *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), vcount, pixels, lids, blendMode, windowsEnabled, wmask, - bldcnt, bld_eva, bld_evb, bld_evy); - break; - case 1: - if (bg == 2) - RenderAffineBGBlend(bg, bgcnts[bg], vcount, pixels, lids, blendMode, windowsEnabled, wmask, bldcnt, bld_eva, - bld_evb, bld_evy); - else - RenderTextBGBlend(bg, bgcnts[bg], *(uint16_t *)(REG_ADDR_BG0HOFS + bg * 4), - *(uint16_t *)(REG_ADDR_BG0VOFS + bg * 4), vcount, pixels, lids, blendMode, windowsEnabled, - wmask, bldcnt, bld_eva, bld_evb, bld_evy); - break; - } + render_scanline_tile(screen_offset, dispcnt); } + } else { + if (dispcnt >> 13) + render_scanline_window_bitmap(screen_offset, dispcnt); + else + render_scanline_bitmap(screen_offset, dispcnt); } - - if (REG_DISPCNT & DISPCNT_OBJ_ON) - DrawSpritesAtPriority(pri, vcount, pixels, lids, windowsEnabled, wmask, blendMode, - /*objWinOnly=*/false, bldcnt, bld_eva, bld_evb, bld_evy); } + + affine_reference_x[0] += (s16)read_ioreg(REG_ADDR_BG2PB); + affine_reference_y[0] += (s16)read_ioreg(REG_ADDR_BG2PD); + affine_reference_x[1] += (s16)read_ioreg(REG_ADDR_BG3PB); + affine_reference_y[1] += (s16)read_ioreg(REG_ADDR_BG3PD); } -void DrawFrame_Fast(uint16_t *pixels) +void DrawFrame_Fast(u16 *pixels) { - for (int i = 0; i < DISPLAY_HEIGHT; i++) { - uint16_t *scanline = &pixels[i * DISPLAY_WIDTH]; + int i; + + gba_screen_pixels = pixels; + video_reload_counters(); + // convert_whole_palette(); + + // assume that the oam is only updated once before the frame + // starts to be drawn + u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u32 video_mode = dispcnt & 0x07; + order_obj(video_mode); + + for (i = 0; i < DISPLAY_HEIGHT; i++) { REG_VCOUNT = i; if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { @@ -1183,11 +3721,14 @@ void DrawFrame_Fast(uint16_t *pixels) gIntrTable[INTR_INDEX_VCOUNT](); } - Memset16(scanline, *(uint16_t *)PLTT, DISPLAY_WIDTH); - DrawScanline(scanline, i); + // Render the backdrop color before each individual scanline. + // HBlank interrupt code could have changed it in between lines. + update_scanline(); REG_DISPSTAT |= INTR_FLAG_HBLANK; + RunDMAs(DMA_HBLANK); + if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) gIntrTable[INTR_INDEX_HBLANK](); From 84cbc3e14da547cc0669583d238e1c960fa54fba Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 18 Feb 2026 02:09:26 +0000 Subject: [PATCH 09/51] remove common --- src/platform/shared/rendering/common.h | 143 ------------------------- 1 file changed, 143 deletions(-) delete mode 100644 src/platform/shared/rendering/common.h diff --git a/src/platform/shared/rendering/common.h b/src/platform/shared/rendering/common.h deleted file mode 100644 index 7592b4218c..0000000000 --- a/src/platform/shared/rendering/common.h +++ /dev/null @@ -1,143 +0,0 @@ -/* gameplaySP - * - * Copyright (C) 2006 Exophase - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef COMMON_H -#define COMMON_H - -#define ror(dest, value, shift) dest = ((value) >> (shift)) | ((value) << (32 - (shift))) - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#if defined(_WIN32) -#define PATH_SEPARATOR "\\" -#define PATH_SEPARATOR_CHAR '\\' -#else -#define PATH_SEPARATOR "/" -#define PATH_SEPARATOR_CHAR '/' -#endif - -/* On x86 we pass arguments via registers instead of stack */ -#ifdef X86_ARCH -#define function_cc __attribute__((regparm(2))) -#else -#define function_cc -#endif - -#ifdef ARM_ARCH - -#define _BSD_SOURCE // sync -#include -#include -#include -#include -#include -#include -#include -#include - -#endif /* ARM_ARCH */ - -// Huge thanks to pollux for the heads up on using native file I/O -// functions on PSP for vastly improved memstick performance. - -#ifdef PSP -#include -#include -#include -#include -#include -#include -#include -#include -#else -typedef unsigned char u8; -typedef signed char s8; -typedef unsigned short int u16; -typedef signed short int s16; -typedef unsigned int u32; -typedef signed int s32; -typedef unsigned long long int u64; -typedef signed long long int s64; -#endif - -#ifdef USE_BGR_FORMAT -#define convert_palette(value) (((value & 0x7FE0) << 1) | (value & 0x1F)) -#elif defined(USE_XBGR1555_FORMAT) -#define convert_palette(value) (value & 0x7FFF) -#else -#define convert_palette(value) (((value & 0x1F) << 11) | ((value & 0x03E0) << 1) | ((value >> 10) & 0x1F)) -#endif - -#define GBA_SCREEN_WIDTH (240) -#define GBA_SCREEN_HEIGHT (160) -#define GBA_SCREEN_PITCH (240) - -typedef u32 fixed16_16; -typedef u32 fixed8_24; - -#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) - -#define fp16_16_to_float(value) (float)((value) / 65536.0) - -#define u32_to_fp16_16(value) ((value) << 16) - -#define fp16_16_to_u32(value) ((value) >> 16) - -#define fp16_16_fractional_part(value) ((value)&0xFFFF) - -#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) - -#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) - -#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) - -#define address8(base, offset) *((u8 *)((u8 *)base + (offset))) - -#define address16(base, offset) *((u16 *)((u8 *)base + (offset))) - -#define address32(base, offset) *((u32 *)((u8 *)base + (offset))) - -#define eswap8(value) (value) -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define eswap16(value) __builtin_bswap16(value) -#define eswap32(value) __builtin_bswap32(value) -#else -#define eswap16(value) (value) -#define eswap32(value) (value) -#endif - -#define readaddress8(base, offset) eswap8(address8(base, offset)) -#define readaddress16(base, offset) eswap16(address16(base, offset)) -#define readaddress32(base, offset) eswap32(address32(base, offset)) - -#define read_ioreg(regnum) (eswap16(io_registers[(regnum)])) -#define write_ioreg(regnum, val) io_registers[(regnum)] = eswap16(val) -#define read_ioreg32(regnum) (read_ioreg(regnum) | (read_ioreg((regnum) + 1) << 16)) - -#define read_dmareg(regnum, dmachan) (eswap16(io_registers[(regnum) + (dmachan)*6])) -#define write_dmareg(regnum, dmachan, val) io_registers[(regnum) + (dmachan)*6] = eswap16(val) - -#include -#include -#include -#include -#include - -#endif \ No newline at end of file From 45754d515b10fa5f186e141bad224c64073afd85 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 18 Feb 2026 21:32:54 +0000 Subject: [PATCH 10/51] fix oam and some extended backgrounds --- include/gba/defines.h | 7 +- include/global.h | 2 +- src/platform/pret_sdl/sdl2.c | 2 + .../shared/rendering/sw_renderer_fast.c | 151 +++++++++--------- 4 files changed, 78 insertions(+), 84 deletions(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index 5ec55588ca..7c3ccac2ed 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -48,8 +48,8 @@ #define DISPLAY_WIDTH 240 #define DISPLAY_HEIGHT 160 #else -#define DISPLAY_WIDTH 240 -#define DISPLAY_HEIGHT 160 +#define DISPLAY_WIDTH 426 +#define DISPLAY_HEIGHT 240 #endif // NOTE: We shouldn't consider WIDESCREEN_HACK a permanent thing. @@ -58,8 +58,7 @@ #undef VRAM_SIZE #define VRAM_SIZE (0x18000 + (0x800 * (12))) #define WIDESCREEN_HACK TRUE -// TODO: extend oam again once fast renderer supports -#define EXTENDED_OAM FALSE +#define EXTENDED_OAM TRUE #else #define WIDESCREEN_HACK FALSE #define EXTENDED_OAM !TRUE diff --git a/include/global.h b/include/global.h index 946528d0d3..777ebc3210 100644 --- a/include/global.h +++ b/include/global.h @@ -7,7 +7,7 @@ #if PLATFORM_GBA #define ENABLE_AUDIO TRUE #else -#define ENABLE_AUDIO TRUE +#define ENABLE_AUDIO FALSE #define ENABLE_VRAM_VIEW !TRUE #endif diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 4e4086ca93..f63b7ba7e6 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -218,8 +218,10 @@ int main(int argc, char **argv) REG_KEYINPUT = 0x3FF; if (headless) { +#if ENABLE_AUDIO // Required or it makes an infinite loop cgb_audio_init(48000); +#endif AgbMain(); return 1; } diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c index c2a839f0a9..a38af7d905 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -804,8 +804,8 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -813,7 +813,7 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -831,7 +831,7 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -880,7 +880,7 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -948,8 +948,8 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -957,7 +957,7 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -974,7 +974,7 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1022,7 +1022,7 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1090,8 +1090,8 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1099,7 +1099,7 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1115,7 +1115,7 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1162,7 +1162,7 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1232,8 +1232,8 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1241,7 +1241,7 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1257,7 +1257,7 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1304,7 +1304,7 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1374,8 +1374,8 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1383,7 +1383,7 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1399,7 +1399,7 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1446,7 +1446,7 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1516,8 +1516,8 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1525,7 +1525,7 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1541,7 +1541,7 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1590,7 +1590,7 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1660,8 +1660,8 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1669,7 +1669,7 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1685,7 +1685,7 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1732,7 +1732,7 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1800,8 +1800,8 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end } if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; + if (horizontal_offset >= 512) { + horizontal_offset -= 512; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1809,7 +1809,7 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 256; + horizontal_offset %= 512; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1825,7 +1825,7 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1872,7 +1872,7 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = 512 - (horizontal_offset % 512); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -2321,18 +2321,18 @@ static const bitmap_layer_render_struct bitmap_mode_renderers[3] // Get the current row offset into an obj in 1D map space #define obj_tile_offset_1D(color_depth, flip_op) \ - tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth) \ + tile_ptr = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth) \ + ((vertical_offset % 8) * tile_width_##color_depth) obj_tile_offset_##flip_op(color_depth) // Get the current row offset into an obj in 2D map space #define obj_tile_offset_2D(color_depth, flip_op) \ - tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * 1024) \ + tile_ptr = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * 1024) \ + ((vertical_offset % 8) * tile_width_##color_depth) obj_tile_offset_##flip_op(color_depth) // Get the palette for 4bpp obj. -#define obj_get_palette_4bpp() current_palette = (obj_attribute_2 >> 8) & 0xF0 +#define obj_get_palette_4bpp() current_palette = oam_data->split.paletteNum << 4 #define obj_get_palette_8bpp() @@ -2405,14 +2405,14 @@ static const bitmap_layer_render_struct bitmap_mode_renderers[3] } #define obj_scale_offset_1D(color_depth) \ - tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth) \ + tile_ptr = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth) \ + ((vertical_offset % 8) * tile_width_##color_depth) // Get the current row offset into an obj in 2D map space #define obj_scale_offset_2D(color_depth) \ - tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32) + ((vertical_offset / 8) * 1024) \ - + ((vertical_offset % 8) * tile_width_##color_depth) + tile_ptr \ + = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * 1024) + ((vertical_offset % 8) * tile_width_##color_depth) #define obj_render_scale_pixel_4bpp(combine_op, alpha_op) \ current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)]; \ @@ -2481,7 +2481,7 @@ static const bitmap_layer_render_struct bitmap_mode_renderers[3] #define obj_render_rotate(combine_op, color_depth, alpha_op, map_space) \ { \ - tile_ptr = tile_base + ((obj_attribute_2 & 0x3FF) * 32); \ + tile_ptr = tile_base + (oam_data->split.tileNum * 32); \ obj_rotate_offset_##map_space(color_depth); \ \ source_x += (y_delta * dmx) - (middle_x * dx); \ @@ -2519,11 +2519,15 @@ static const bitmap_layer_render_struct bitmap_mode_renderers[3] #define obj_render_affine(combine_op, color_depth, alpha_op, map_space) \ { \ - u16 *params = (u16 *)OAM + (((obj_attribute_1 >> 9) & 0x1F) * 16); \ - s32 dx = (s16)eswap16(params[3]); \ - s32 dmx = (s16)eswap16(params[7]); \ - s32 dy = (s16)eswap16(params[11]); \ - s32 dmy = (s16)eswap16(params[15]); \ + u8 matrix_num = oam_data->split.matrixNum * 4; \ + OamData *oam1 = &((OamData *)OAM)[matrix_num]; \ + OamData *oam2 = &((OamData *)OAM)[matrix_num + 1]; \ + OamData *oam3 = &((OamData *)OAM)[matrix_num + 2]; \ + OamData *oam4 = &((OamData *)OAM)[matrix_num + 3]; \ + s32 dx = (s16)oam1->all.affineParam; \ + s32 dmx = (s16)oam2->all.affineParam; \ + s32 dy = (s16)oam3->all.affineParam; \ + s32 dmy = (s16)oam4->all.affineParam; \ s32 source_x, source_y; \ s32 tile_x, tile_y; \ u32 tile_map_offset; \ @@ -2541,7 +2545,7 @@ static const bitmap_layer_render_struct bitmap_mode_renderers[3] source_x = (middle_x << 8); \ source_y = (middle_y << 8); \ \ - if (obj_attribute_0 & 0x200) { \ + if ((oam_data->split.affineMode >> 1) & 1) { \ obj_width *= 2; \ obj_height *= 2; \ middle_x *= 2; \ @@ -2625,8 +2629,8 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; #define render_scanline_obj_extra_variables_copy_bitmap(map_space) render_scanline_obj_extra_variables_copy(bitmap) #define render_scanline_obj_main(combine_op, alpha_op, map_space) \ - if (obj_attribute_0 & 0x100) { \ - if ((obj_attribute_0 >> 13) & 0x01) { \ + if (oam_data->split.affineMode & 1) { \ + if (oam_data->split.bpp & 1) { \ obj_render_affine(combine_op, 8bpp, alpha_op, map_space); \ } else { \ obj_render_affine(combine_op, 4bpp, alpha_op, map_space); \ @@ -2634,10 +2638,10 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; } else { \ vertical_offset = vcount - obj_y; \ \ - if ((obj_attribute_1 >> 13) & 0x01) \ + if ((oam_data->split.matrixNum >> 4) & 1) \ vertical_offset = obj_height - vertical_offset - 1; \ \ - switch (((obj_attribute_0 >> 12) & 0x02) | ((obj_attribute_1 >> 12) & 0x01)) { \ + switch ((oam_data->split.bpp << 1) | ((oam_data->split.matrixNum >> 3) & 1)) { \ case 0x0: \ obj_render(combine_op, 4bpp, alpha_op, map_space, noflip); \ break; \ @@ -2659,7 +2663,7 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; #define render_scanline_obj_no_partial_alpha(combine_op, alpha_op, map_space) render_scanline_obj_main(combine_op, alpha_op, map_space) #define render_scanline_obj_partial_alpha(combine_op, alpha_op, map_space) \ - if ((obj_attribute_0 >> 10) & 0x03) { \ + if (oam_data->split.objMode) { \ pixel_combine = 0x00000300; \ render_scanline_obj_main(combine_op, alpha_obj, map_space); \ } else { \ @@ -2672,7 +2676,7 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; #define render_scanline_obj_prologue_copy_body(type) \ copy_start = obj_x; \ copy_end = obj_x + obj_width; \ - if (obj_attribute_0 & 0x200) \ + if (oam_data->split.affineMode & 2) \ copy_end += obj_width; \ \ if (copy_start < start) \ @@ -2701,7 +2705,6 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; s32 obj_x, obj_y; \ u32 obj_size; \ u32 obj_width, obj_height; \ - u32 obj_attribute_0, obj_attribute_1, obj_attribute_2; \ s32 vcount = read_ioreg(REG_ADDR_VCOUNT); \ u32 tile_run; \ u32 current_pixels; \ @@ -2710,7 +2713,6 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; u32 vertical_offset; \ u32 partial_tile_run, partial_tile_offset; \ u32 pixel_run; \ - u16 *oam_ptr; \ OamData *oam_data; \ render_scanline_dest_##alpha_op *dest_ptr; \ u8 *tile_base = VRAM + 0x10000; \ @@ -2720,18 +2722,14 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; \ for (obj_num = 0; obj_num < obj_count; obj_num++) { \ oam_data = (OamData *)&OAM[obj_list[obj_num] * OAM_DATA_SIZE_AFFINE]; \ - oam_ptr = (u16 *)OAM + (obj_list[obj_num] * 4); \ - obj_attribute_0 = eswap16(oam_ptr[0]); \ - obj_attribute_1 = eswap16(oam_ptr[1]); \ - obj_attribute_2 = eswap16(oam_ptr[2]); \ - obj_size = ((obj_attribute_0 >> 12) & 0x0C) | (obj_attribute_1 >> 14); \ + obj_size = (oam_data->split.shape << 2) | oam_data->split.size; \ \ obj_x = oam_data->split.x; \ obj_width = obj_width_table[obj_size]; \ \ render_scanline_obj_prologue_##combine_op(alpha_op); \ \ - obj_y = obj_attribute_0 & 0xFF; \ + obj_y = oam_data->split.y; \ \ if (!EXTENDED_OAM) { \ if (obj_x > DISPLAY_WIDTH) \ @@ -2772,34 +2770,29 @@ static void order_obj(u32 video_mode) { s32 obj_num; u32 row; - t_oam *oam_base = (t_oam *)OAM; memset(obj_priority_count, 0, sizeof(obj_priority_count)); memset(obj_alpha_count, 0, sizeof(obj_alpha_count)); for (obj_num = 127; obj_num >= 0; obj_num--) { OamData *oam_data = (OamData *)&OAM[obj_num * OAM_DATA_SIZE_AFFINE]; - t_oam *oam_ptr = &oam_base[obj_num]; - u16 obj_attr0 = eswap16(oam_ptr->attr0); // Bit 9 disables regular sprites. Used as double bit for affine ones. bool visible = oam_data->split.affineMode != 2; if (visible) { - u16 obj_shape = obj_attr0 >> 14; - u32 obj_mode = (obj_attr0 >> 10) & 0x03; + u16 obj_shape = oam_data->split.shape; + u32 obj_mode = oam_data->split.objMode; // Prohibited shape and mode bool invalid = (obj_shape == 0x3) || (obj_mode == OBJ_MOD_INVALID); if (!invalid) { - u16 obj_attr1 = eswap16(oam_ptr->attr1); - u16 obj_attr2 = eswap16(oam_ptr->attr2); - u32 obj_priority = (obj_attr2 >> 10) & 0x03; + u32 obj_priority = oam_data->split.priority; - if (((video_mode < 3) || ((obj_attr2 & 0x3FF) >= 512))) { + if (((video_mode < 3) || (oam_data->split.tileNum >= 512))) { // Calculate object size (from size and shape attr bits) - u16 obj_size = (obj_attr1 >> 14); + u16 obj_size = oam_data->split.size; s32 obj_height = obj_dim_table[obj_shape][obj_size][1]; s32 obj_width = obj_dim_table[obj_shape][obj_size][0]; - s32 obj_y = obj_attr0 & 0xFF; + s32 obj_y = oam_data->split.y; #if !EXTENDED_OAM if (obj_y > DISPLAY_HEIGHT) @@ -2807,7 +2800,7 @@ static void order_obj(u32 video_mode) #endif // Double size for affine sprites with double bit set - if (obj_attr0 & 0x200) { + if ((oam_data->split.affineMode >> 1) & 1) { obj_height *= 2; obj_width *= 2; } From 66f9a093b8ad82ed10a850c2cf9103baaf4341f0 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Thu, 19 Feb 2026 02:54:25 +0000 Subject: [PATCH 11/51] fix bg rendering in widescreen hack, 512 rendering still not working --- include/gba/defines.h | 2 +- include/global.h | 2 +- src/platform/ps2/ps2.c | 2 +- .../shared/rendering/sw_renderer_fast.c | 156 +++++++++--------- 4 files changed, 83 insertions(+), 79 deletions(-) diff --git a/include/gba/defines.h b/include/gba/defines.h index 7c3ccac2ed..4ef57d98b7 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -60,7 +60,7 @@ #define WIDESCREEN_HACK TRUE #define EXTENDED_OAM TRUE #else -#define WIDESCREEN_HACK FALSE +#define WIDESCREEN_HACK TRUE #define EXTENDED_OAM !TRUE #endif extern uint8_t VRAM[VRAM_SIZE]; diff --git a/include/global.h b/include/global.h index 777ebc3210..946528d0d3 100644 --- a/include/global.h +++ b/include/global.h @@ -7,7 +7,7 @@ #if PLATFORM_GBA #define ENABLE_AUDIO TRUE #else -#define ENABLE_AUDIO FALSE +#define ENABLE_AUDIO TRUE #define ENABLE_VRAM_VIEW !TRUE #endif diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index a822b3753d..809c0a843b 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -161,7 +161,7 @@ static void deinit_drivers() void platform_video_init(void) { if (vid_mode == NULL) { - vid_mode = &vid_modes[1]; // Standard def 480p + vid_mode = &vid_modes[3]; // Standard def 480p } else { if (use_hires) { gsKit_hires_deinit_global(gsGlobal); diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c index a38af7d905..143b7cbb64 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -791,7 +791,7 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void u32 i; render_scanline_dest_normal *dest_ptr = ((render_scanline_dest_normal *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -804,8 +804,8 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -813,7 +813,7 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -830,8 +830,8 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -879,8 +879,8 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -909,6 +909,7 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void map_ptr = second_ptr; end -= pixel_run; } + tile_run = end / 8; multiple_tile_map_base_4bpp_normal(); @@ -935,7 +936,7 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en u32 i; render_scanline_dest_normal *dest_ptr = ((render_scanline_dest_normal *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -948,8 +949,9 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + printf("%d\n", vertical_offset); + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -957,7 +959,7 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -973,8 +975,8 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1021,8 +1023,8 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1077,7 +1079,7 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi u32 i; render_scanline_dest_color16 *dest_ptr = ((render_scanline_dest_color16 *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -1090,8 +1092,8 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1099,7 +1101,7 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1114,8 +1116,8 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1161,8 +1163,8 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1219,7 +1221,7 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e u32 i; render_scanline_dest_color16 *dest_ptr = ((render_scanline_dest_color16 *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -1232,8 +1234,8 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1241,7 +1243,7 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1256,8 +1258,8 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1303,8 +1305,8 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1361,7 +1363,7 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi u32 i; render_scanline_dest_color32 *dest_ptr = ((render_scanline_dest_color32 *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -1374,8 +1376,8 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1383,7 +1385,7 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1398,8 +1400,8 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1445,8 +1447,8 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1503,7 +1505,7 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e u32 i; render_scanline_dest_color32 *dest_ptr = ((render_scanline_dest_color32 *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -1516,8 +1518,8 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1525,7 +1527,7 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1540,8 +1542,8 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1589,8 +1591,8 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1647,7 +1649,7 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void u32 i; render_scanline_dest_alpha *dest_ptr = ((render_scanline_dest_alpha *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -1660,8 +1662,8 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1669,7 +1671,7 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1684,8 +1686,8 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1731,8 +1733,8 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1787,7 +1789,7 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end u32 i; render_scanline_dest_alpha *dest_ptr = ((render_scanline_dest_alpha *)scanline) + start; - u16 *map_base = (u16 *)(VRAM + ((bg_control >> 8) & 0x1F) * (1024 * 2)); + u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); u16 *map_ptr, *second_ptr; u8 *tile_ptr; @@ -1800,8 +1802,8 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end } if (map_size & 0x01) { - if (horizontal_offset >= 512) { - horizontal_offset -= 512; + if (horizontal_offset >= 256) { + horizontal_offset -= 256; map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { @@ -1809,7 +1811,7 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end second_ptr = map_base + (32 * 32); } } else { - horizontal_offset %= 512; + horizontal_offset %= 256; map_ptr = map_base + (horizontal_offset / 8); second_ptr = map_base; } @@ -1824,8 +1826,8 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -1871,8 +1873,8 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)) + vertical_pixel_offset; - u32 pixel_run = 512 - (horizontal_offset % 512); + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; + u32 pixel_run = 256 - (horizontal_offset % 256); u32 current_tile; map_base += ((vertical_offset % 256) / 8) * 32; @@ -2087,8 +2089,8 @@ void video_reload_counters() u32 map_size = (bg_control >> 14) & 0x03; \ u32 width_height = 1 << (7 + map_size); \ u32 map_pitch = map_size + 4; \ - u8 *map_base = VRAM + (((bg_control >> 8) & 0x1F) * (1024 * 2)); \ - u8 *tile_base = VRAM + (((bg_control >> 2) & 0x03) * (1024 * 16)); \ + u8 *map_base = BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); \ + u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03); \ u8 *tile_ptr = NULL; \ u32 map_offset, last_map_offset = (u32)-1; \ u32 i; \ @@ -2618,7 +2620,7 @@ static u8 obj_alpha_count[DISPLAY_HEIGHT]; #define render_scanline_obj_extra_variables_copy(type) \ u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); \ u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); \ - u32 obj_enable = read_ioreg(REG_ADDR_WINOUT) >> 8; \ + u32 obj_enable = WIN_GET_LOWER(read_ioreg(REG_ADDR_WINOUT)); \ render_scanline_layer_functions_##type(); \ u32 copy_start, copy_end; \ u16 copy_buffer[DISPLAY_WIDTH]; \ @@ -3426,8 +3428,8 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline } #define window_x_coords(window_number) \ - window_##window_number##_x1 = read_ioreg(REG_ADDR_WIN##window_number##H) >> 8; \ - window_##window_number##_x2 = read_ioreg(REG_ADDR_WIN##window_number##H) & 0xFF; \ + window_##window_number##_x1 = WIN_GET_LOWER(read_ioreg(REG_ADDR_WIN##window_number##H)); \ + window_##window_number##_x2 = WIN_GET_HIGHER(read_ioreg(REG_ADDR_WIN##window_number##H)); \ window_##window_number##_enable = (winin >> (window_number * 8)) & 0x3F; \ \ if (window_##window_number##_x1 > DISPLAY_WIDTH) \ @@ -3440,13 +3442,13 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline u32 window_##window_number##_x1, window_##window_number##_x2; \ u32 window_##window_number##_y1, window_##window_number##_y2; \ u32 window_##window_number##_enable = 0; \ - window_##window_number##_y1 = read_ioreg(REG_ADDR_WIN##window_number##V) >> 8; \ - window_##window_number##_y2 = read_ioreg(REG_ADDR_WIN##window_number##V) & 0xFF; \ + window_##window_number##_y1 = WIN_GET_LOWER(read_ioreg(REG_ADDR_WIN##window_number##V)); \ + window_##window_number##_y2 = WIN_GET_HIGHER(read_ioreg(REG_ADDR_WIN##window_number##V)); \ \ if (window_##window_number##_y1 > window_##window_number##_y2) { \ if ((((vcount <= window_##window_number##_y2) || (vcount > window_##window_number##_y1)) \ - || (window_##window_number##_y2 > (DISPLAY_WIDTH - 13))) \ - && (window_##window_number##_y1 <= (DISPLAY_WIDTH - 13))) { \ + || (window_##window_number##_y2 > (DISPLAY_HEIGHT + 67))) \ + && (window_##window_number##_y1 <= (DISPLAY_HEIGHT + 67))) { \ window_x_coords(window_number); \ } else { \ window_##window_number##_x1 = DISPLAY_WIDTH; \ @@ -3454,8 +3456,8 @@ static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline } \ } else { \ if ((((vcount >= window_##window_number##_y1) && (vcount < window_##window_number##_y2)) \ - || (window_##window_number##_y2 > (DISPLAY_WIDTH - 13))) \ - && (window_##window_number##_y1 <= (DISPLAY_WIDTH - 13))) { \ + || (window_##window_number##_y2 > (DISPLAY_HEIGHT + 67))) \ + && (window_##window_number##_y1 <= (DISPLAY_HEIGHT + 67))) { \ window_x_coords(window_number); \ } else { \ window_##window_number##_x1 = DISPLAY_WIDTH; \ @@ -3667,8 +3669,10 @@ void update_scanline(void) order_layers((dispcnt >> 8) & active_layers[video_mode], vcount); + // fill_line_color16(*(uint16_t *)PLTT, screen_offset, 0, DISPLAY_WIDTH); + // If the screen is in in forced blank draw pure white. - if (dispcnt & 0x80) { + if (dispcnt & DISPCNT_FORCED_BLANK) { fill_line_color16(0xFFFF, screen_offset, 0, DISPLAY_WIDTH); } else { if (video_mode < 3) { From 5891c7e3755067afb6e44ef03a07a537ff3bb4ce Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Thu, 19 Feb 2026 17:05:34 +0000 Subject: [PATCH 12/51] fix render for 512 backgrounds --- .../shared/rendering/sw_renderer_fast.c | 113 +++++++++--------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c index 143b7cbb64..814f64009e 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ b/src/platform/shared/rendering/sw_renderer_fast.c @@ -800,17 +800,17 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -831,10 +831,10 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -880,10 +880,10 @@ static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -945,18 +945,17 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { - printf("%d\n", vertical_offset); if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -976,10 +975,10 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1024,10 +1023,10 @@ static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 en s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1088,17 +1087,17 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -1117,10 +1116,10 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1164,10 +1163,10 @@ static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1230,17 +1229,17 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -1259,10 +1258,10 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1306,10 +1305,10 @@ static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1372,17 +1371,17 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -1401,10 +1400,10 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1448,10 +1447,10 @@ static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, voi s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1514,17 +1513,17 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -1543,10 +1542,10 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1592,10 +1591,10 @@ static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 e s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1658,17 +1657,17 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -1687,10 +1686,10 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1734,10 +1733,10 @@ static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1798,17 +1797,17 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end if ((map_size & 0x02) && (vertical_offset >= 256)) { map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); } else { - map_base += (((vertical_offset % 256) / 8) * 32); + map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); } if (map_size & 0x01) { if (horizontal_offset >= 256) { horizontal_offset -= 256; - map_ptr = map_base + (32 * 32) + (horizontal_offset / 8); + map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); second_ptr = map_base; } else { map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + (32 * 32); + second_ptr = map_base + ((map_width / 8) * 32); } } else { horizontal_offset %= 256; @@ -1827,10 +1826,10 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_8bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { @@ -1874,10 +1873,10 @@ static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; tile_extra_variables_4bpp(); u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = 256 - (horizontal_offset % 256); + u32 pixel_run = map_width - (horizontal_offset % map_width); u32 current_tile; - map_base += ((vertical_offset % 256) / 8) * 32; + map_base += ((vertical_offset % 256) / 8) * (map_width / 8); partial_tile_offset = (horizontal_offset % 8); if (pixel_run >= end) { From a849adc47109e3f16e37618a5e9c17755cea6c03 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Fri, 20 Feb 2026 02:42:59 +0000 Subject: [PATCH 13/51] switch to latest gpsp renderer, allow c++ compilation --- Makefile | 65 +- include/gba/defines.h | 6 +- include/gba/types.h | 6 +- src/platform/ps2/ps2.c | 57 - .../shared/rendering/sw_renderer_fast.c | 3736 ----------------- .../shared/rendering/sw_renderer_fast.cc | 2298 ++++++++++ tools/scaninc/source_file.cpp | 2 +- 7 files changed, 2349 insertions(+), 3821 deletions(-) delete mode 100644 src/platform/shared/rendering/sw_renderer_fast.c create mode 100644 src/platform/shared/rendering/sw_renderer_fast.cc diff --git a/Makefile b/Makefile index e17045f1ff..e07a3e3cca 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,7 @@ CC1 := tools/agbcc/bin/agbcc$(EXE) CC1_OLD := tools/agbcc/bin/old_agbcc$(EXE) else CC1 := $(PREFIX)gcc$(EXE) +CXX := $(PREFIX)g++$(EXE) CC1_OLD := $(CC1) endif @@ -194,6 +195,14 @@ C_SRCS := $(shell find $(C_SUBDIR) -name "*.c") endif C_OBJS := $(patsubst $(C_SUBDIR)/%.c,$(C_BUILDDIR)/%.o,$(C_SRCS)) +ifeq ($(PLATFORM),gba) +CXX_SRCS := $(shell find $(C_SUBDIR) -name "*.cc" -not -path "*/platform/*") +else +CXX_SRCS := $(shell find $(C_SUBDIR) -name "*.cc") +endif + +CXX_OBJS := $(patsubst $(C_SUBDIR)/%.cc,$(C_BUILDDIR)/%.o,$(CXX_SRCS)) + # Platform not included as we only need the headers for decomp scratches C_HEADERS := $(shell find $(INCLUDE_DIRS) -name "*.h" -not -path "*/platform/*") @@ -217,7 +226,7 @@ MID_OBJS := $(patsubst $(MID_SUBDIR)/%.mid,$(MID_BUILDDIR)/%.o,$(MID_SRCS)) SOUND_ASM_SRCS := $(wildcard $(SOUND_ASM_SUBDIR)/*.s) SOUND_ASM_OBJS := $(patsubst $(SOUND_ASM_SUBDIR)/%.s,$(SOUND_ASM_BUILDDIR)/%.o,$(SOUND_ASM_SRCS)) -OBJS := $(C_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) +OBJS := $(C_OBJS) $(CXX_OBJS) $(ASM_OBJS) $(C_ASM_OBJS) $(DATA_ASM_OBJS) $(SONG_OBJS) $(MID_OBJS) OBJS_REL := $(patsubst $(OBJ_DIR)/%,%,$(OBJS)) FORMAT_SRC_PATHS := $(shell find . -name "*.c" ! -path '*/src/data/*' ! -path '*/build/*' ! -path '*/ext/*') @@ -278,25 +287,6 @@ else endif endif -ifeq ($(PLATFORM),gba) - ASFLAGS += -mcpu=arm7tdmi -mthumb-interwork - CC1FLAGS += -mthumb-interwork -else - ifeq ($(PLATFORM), sdl) - # for modern we are using a modern compiler - # so instead of CPP we can use gcc -E to "preprocess only" - CPP := $(CC1) -E - else ifeq ($(PLATFORM), psp) - CPP := $(CC1) -E - else ifeq ($(PLATFORM), sdl_ps2) - ASFLAGS += -msingle-float - else ifeq ($(PLATFORM), ps2) - ASFLAGS += -msingle-float - endif - # Allow file input through stdin on modern GCC and set it to "compile only" - CC1FLAGS += -x c -S -endif - ifeq ($(DEBUG),1) CC1FLAGS += -g3 -O0 CPPFLAGS += -D DEBUG=1 @@ -307,7 +297,7 @@ else else ifeq ($(PLATFORM),sdl_ps2) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else ifeq ($(PLATFORM),ps2) - CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer + CC1FLAGS += -O3 -fomit-frame-pointer else CC1FLAGS += -O2 endif @@ -337,6 +327,28 @@ else CPPFLAGS += -D ENABLE_DECOMP_CREDITS=1 endif +CXXFLAGS := $(CC1FLAGS) $(CPPFLAGS) -fno-rtti -fno-exceptions -std=c++11 + +ifeq ($(PLATFORM),gba) + ASFLAGS += -mcpu=arm7tdmi -mthumb-interwork + CC1FLAGS += -mthumb-interwork +else + ifeq ($(PLATFORM), sdl) + # for modern we are using a modern compiler + # so instead of CPP we can use gcc -E to "preprocess only" + CPP := $(CC1) -E + else ifeq ($(PLATFORM), psp) + CPP := $(CC1) -E + else ifeq ($(PLATFORM), sdl_ps2) + ASFLAGS += -msingle-float + else ifeq ($(PLATFORM), ps2) + ASFLAGS += -msingle-float + endif + # Allow file input through stdin on modern gcc/g++ and set it to "compile only" + CC1FLAGS += -x c -S + CXXFLAGS += -x c++ -S +endif + ### LINKER FLAGS ### # GBA @@ -584,11 +596,21 @@ ifeq ($(PLATFORM), gba) endif @$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@ +$(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.cc + @echo "$(CXX) -o $@ $<" + @$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.o')) + @$(CXX) $(CXXFLAGS) -o $(C_BUILDDIR)/$*.s $< + @$(AS) $(ASFLAGS) $(C_BUILDDIR)/$*.s -o $@ + # Scan the src dependencies to determine if any dependent files have changed $(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.c @$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d')) $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $< +$(C_BUILDDIR)/%.d: $(C_SUBDIR)/%.cc + @$(shell mkdir -p $(shell dirname '$(C_BUILDDIR)/$*.d')) + $(SCANINC) -M $@ $(INCLUDE_SCANINC_ARGS) $< + # rule for sources from the src dir (parts of libraries) $(C_BUILDDIR)/%.o: $(C_SUBDIR)/%.s @echo "$(AS) -o $@ $<" @@ -608,6 +630,7 @@ $(DATA_ASM_BUILDDIR)/%.d: $(DATA_ASM_SUBDIR)/%.s ifneq ($(NODEP),1) -include $(addprefix $(OBJ_DIR)/,$(C_SRCS:.c=.d)) +-include $(addprefix $(OBJ_DIR)/,$(CXX_SRCS:.cc=.d)) -include $(addprefix $(OBJ_DIR)/,$(DATA_ASM_SRCS:.s=.d)) endif diff --git a/include/gba/defines.h b/include/gba/defines.h index 4ef57d98b7..45371a2e1e 100644 --- a/include/gba/defines.h +++ b/include/gba/defines.h @@ -45,8 +45,8 @@ #define DISPLAY_HEIGHT 160 #elif defined(__PS2__) // Runs at 60fps with the "fast draw" -#define DISPLAY_WIDTH 240 -#define DISPLAY_HEIGHT 160 +#define DISPLAY_WIDTH 320 +#define DISPLAY_HEIGHT 180 #else #define DISPLAY_WIDTH 426 #define DISPLAY_HEIGHT 240 @@ -60,7 +60,7 @@ #define WIDESCREEN_HACK TRUE #define EXTENDED_OAM TRUE #else -#define WIDESCREEN_HACK TRUE +#define WIDESCREEN_HACK FALSE #define EXTENDED_OAM !TRUE #endif extern uint8_t VRAM[VRAM_SIZE]; diff --git a/include/gba/types.h b/include/gba/types.h index fa32343578..419e1fdda4 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -42,12 +42,12 @@ typedef u16 MetatileIndexType; // If the DISPLAY_HEIGHT was >255, scanline effects would break, // so we have to make this variable bigger. // (u16 should be plenty for screen coordinates, right?) -#if !defined(DISPLAY_HEIGHT) -#error DISPLAY_HEIGHT not defined. +#if !defined(WIDESCREEN_HACK) +#error WIDESCREEN_HACK not defined. #endif /// TODO: Technically this should only be #if (DISPLAY_HEIGHT > 255), // we should probably replace uses of int_vcount with a different type where a high DISPLAY_WIDTH necessitates u16. -#if ((DISPLAY_WIDTH > 255) || (DISPLAY_HEIGHT > 255)) +#if WIDESCREEN_HACK typedef u16 int_vcount; #else typedef u8 int_vcount; diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 809c0a843b..b0541e2e62 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -773,63 +773,6 @@ const s16 sineTable[256] (s16)0xE783, (s16)0xE8F8, (s16)0xEA71, (s16)0xEBED, (s16)0xED6C, (s16)0xEEEF, (s16)0xF074, (s16)0xF1FB, (s16)0xF384, (s16)0xF50F, (s16)0xF69C, (s16)0xF82B, (s16)0xF9BB, (s16)0xFB4B, (s16)0xFCDD, (s16)0xFE6E }; -void BgAffineSet(struct BgAffineSrcData *src, struct BgAffineDstData *dest, s32 count) -{ - for (s32 i = 0; i < count; i++) { - s32 cx = src[i].texX; - s32 cy = src[i].texY; - s16 dispx = src[i].scrX; - s16 dispy = src[i].scrY; - s16 rx = src[i].sx; - s16 ry = src[i].sy; - u16 theta = src[i].alpha >> 8; - s32 a = sineTable[(theta + 0x40) & 255]; - s32 b = sineTable[theta]; - - s16 dx = (rx * a) >> 14; - s16 dmx = (rx * b) >> 14; - s16 dy = (ry * b) >> 14; - s16 dmy = (ry * a) >> 14; - - dest[i].pa = dx; - dest[i].pb = -dmx; - dest[i].pc = dy; - dest[i].pd = dmy; - - s32 startx = cx - dx * dispx + dmx * dispy; - s32 starty = cy - dy * dispx - dmy * dispy; - - dest[i].dx = startx; - dest[i].dy = starty; - } -} - -void ObjAffineSet(struct ObjAffineSrcData *src, void *dest, s32 count, s32 offset) -{ - for (s32 i = 0; i < count; i++) { - s16 rx = src[i].xScale; - s16 ry = src[i].yScale; - u16 theta = src[i].rotation >> 8; - - s32 a = (s32)sineTable[(theta + 64) & 255]; - s32 b = (s32)sineTable[theta]; - - s16 dx = ((s32)rx * a) >> 14; - s16 dmx = ((s32)rx * b) >> 14; - s16 dy = ((s32)ry * b) >> 14; - s16 dmy = ((s32)ry * a) >> 14; - - CPUWriteHalfWord(dest, dx); - dest += offset; - CPUWriteHalfWord(dest, -dmx); - dest += offset; - CPUWriteHalfWord(dest, dy); - dest += offset; - CPUWriteHalfWord(dest, dmy); - dest += offset; - } -} - void SoftReset(u32 resetFlags) { } void SoftResetExram(u32 resetFlags) { } diff --git a/src/platform/shared/rendering/sw_renderer_fast.c b/src/platform/shared/rendering/sw_renderer_fast.c deleted file mode 100644 index 814f64009e..0000000000 --- a/src/platform/shared/rendering/sw_renderer_fast.c +++ /dev/null @@ -1,3736 +0,0 @@ -/* gameplaySP - * - * Copyright (C) 2006 Exophase - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#if RENDERER == RENDERER_SOFTWARE_FAST - -#include "global.h" -#include -#include - -#include "global.h" -#include "core.h" -#include "gba/defines.h" -#include "gba/io_reg.h" -#include "gba/types.h" - -#include "platform/shared/dma.h" - -#define eswap16(value) (value) -#define eswap32(value) (value) - -#define GBA_SCREEN_PITCH DISPLAY_WIDTH - -typedef u32 fixed16_16; -typedef u32 fixed8_24; - -#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) - -#define fp16_16_to_float(value) (float)((value) / 65536.0) - -#define u32_to_fp16_16(value) ((value) << 16) - -#define fp16_16_to_u32(value) ((value) >> 16) - -#define fp16_16_fractional_part(value) ((value)&0xFFFF) - -#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) - -#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) - -#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) - -#define read_ioreg(regaddr) (eswap16(*(u16 *)(regaddr))) -#define read_ioreg32(regaddr) (read_ioreg(regaddr) | (read_ioreg((regaddr) + sizeof(u16)) << 16)) - -#define REG_ADDR_BGxCNT(n) (REG_ADDR_BG0CNT + ((n) * sizeof(u16))) - -#define convert_palette(value) (value & 0x7FFF) - -u16 *gba_screen_pixels = NULL; - -#define get_screen_pixels() gba_screen_pixels -#define get_screen_pitch() GBA_SCREEN_PITCH - -typedef struct { - u16 attr0, attr1, attr2, attr3; -} t_oam; - -void update_scanline(void); -void video_reload_counters(void); - -extern s32 affine_reference_x[2]; -extern s32 affine_reference_y[2]; - -typedef void (*tile_render_function)(u32 layer_number, u32 start, u32 end, void *dest_ptr); -typedef void (*bitmap_render_function)(u32 start, u32 end, void *dest_ptr); - -typedef struct { - tile_render_function normal_render_base; - tile_render_function normal_render_transparent; - tile_render_function alpha_render_base; - tile_render_function alpha_render_transparent; - tile_render_function color16_render_base; - tile_render_function color16_render_transparent; - tile_render_function color32_render_base; - tile_render_function color32_render_transparent; -} tile_layer_render_struct; - -typedef struct { - bitmap_render_function normal_render; -} bitmap_layer_render_struct; - -typedef enum { filter_nearest, filter_bilinear } video_filter_type; - -static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, - const tile_layer_render_struct *layer_renderers); -static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, - const bitmap_layer_render_struct *layer_renderers); - -#define tile_expand_base_normal(index) \ - current_pixel = palette[current_pixel]; \ - dest_ptr[index] = current_pixel - -#define tile_expand_base_normal_mode4(index) \ - if (current_pixel != 0) { \ - current_pixel = palette[current_pixel]; \ - dest_ptr[index] = current_pixel; \ - } - -#define tile_expand_transparent_normal(index) tile_expand_base_normal(index) - -#define tile_expand_copy(index) dest_ptr[index] = copy_ptr[index] - -#define advance_dest_ptr_base(delta) dest_ptr += delta - -#define advance_dest_ptr_transparent(delta) advance_dest_ptr_base(delta) - -#define advance_dest_ptr_copy(delta) \ - advance_dest_ptr_base(delta); \ - copy_ptr += delta - -#define color_combine_mask_a(layer) ((read_ioreg(REG_ADDR_BLDCNT) >> layer) & 0x01) - -// For color blending operations, will create a mask that has in bit -// 10 if the layer is target B, and bit 9 if the layer is target A. - -#define color_combine_mask(layer) (color_combine_mask_a(layer) | ((read_ioreg(REG_ADDR_BLDCNT) >> (layer + 7)) & 0x02)) << 9 - -// For alpha blending renderers, draw the palette index (9bpp) and -// layer bits rather than the raw RGB. For the base this should write to -// the 32bit location directly. - -#define tile_expand_base_alpha(index) dest_ptr[index] = current_pixel | pixel_combine - -#define tile_expand_base_bg(index) dest_ptr[index] = bg_combine - -// For layered (transparent) writes this should shift the "stack" and write -// to the bottom. This will preserve the topmost pixel and the most recent -// one. - -#define tile_expand_transparent_alpha(index) dest_ptr[index] = (dest_ptr[index] << 16) | current_pixel | pixel_combine - -// OBJ should only shift if the top isn't already OBJ -#define tile_expand_transparent_alpha_obj(index) \ - dest = dest_ptr[index]; \ - if (dest & 0x00000100) \ - dest_ptr[index] = (dest & 0xFFFF0000) | current_pixel | pixel_combine; \ - else \ - dest_ptr[index] = (dest << 16) | current_pixel | pixel_combine; - -// For color effects that don't need to preserve the previous layer. -// The color32 version should be used with 32bit wide dest_ptr so as to be -// compatible with alpha combine on top of it. - -#define tile_expand_base_color16(index) dest_ptr[index] = current_pixel | pixel_combine - -#define tile_expand_transparent_color16(index) tile_expand_base_color16(index) - -#define tile_expand_base_color32(index) tile_expand_base_color16(index) - -#define tile_expand_transparent_color32(index) tile_expand_base_color16(index) - -// Operations for isolation 8bpp pixels within 32bpp pixel blocks. - -#define tile_8bpp_pixel_op_mask(op_param) current_pixel = current_pixels & 0xFF - -#define tile_8bpp_pixel_op_shift_mask(shift) current_pixel = (current_pixels >> shift) & 0xFF - -#define tile_8bpp_pixel_op_shift(shift) current_pixel = current_pixels >> shift - -#define tile_8bpp_pixel_op_none(shift) - -// Base should always draw raw in 8bpp mode; color 0 will be drawn where -// color 0 is. - -#define tile_8bpp_draw_base_normal(index) tile_expand_base_normal(index) - -#define tile_8bpp_draw_base_alpha(index) \ - if (current_pixel) { \ - tile_expand_base_alpha(index); \ - } else { \ - tile_expand_base_bg(index); \ - } - -#define tile_8bpp_draw_base_color16(index) tile_8bpp_draw_base_alpha(index) - -#define tile_8bpp_draw_base_color32(index) tile_8bpp_draw_base_alpha(index) - -#define tile_8bpp_draw_base(index, op, op_param, alpha_op) \ - tile_8bpp_pixel_op_##op(op_param); \ - tile_8bpp_draw_base_##alpha_op(index) - -// Transparent (layered) writes should only replace what is there if the -// pixel is not transparent (zero) - -#define tile_8bpp_draw_transparent(index, op, op_param, alpha_op) \ - tile_8bpp_pixel_op_##op(op_param); \ - if (current_pixel) { \ - tile_expand_transparent_##alpha_op(index); \ - } - -#define tile_8bpp_draw_copy(index, op, op_param, alpha_op) \ - tile_8bpp_pixel_op_##op(op_param); \ - if (current_pixel) { \ - tile_expand_copy(index); \ - } - -// Get the current tile from the map in 8bpp mode - -#define get_tile_8bpp() \ - current_tile = eswap16(*map_ptr); \ - tile_ptr = tile_base + ((current_tile & 0x3FF) * 64) - -// Draw half of a tile in 8bpp mode, for base renderer - -#define tile_8bpp_draw_four_noflip(index, combine_op, alpha_op) \ - tile_8bpp_draw_##combine_op(index + 0, mask, 0, alpha_op); \ - tile_8bpp_draw_##combine_op(index + 1, shift_mask, 8, alpha_op); \ - tile_8bpp_draw_##combine_op(index + 2, shift_mask, 16, alpha_op); \ - tile_8bpp_draw_##combine_op(index + 3, shift, 24, alpha_op) - -// Like the above, but draws the half-tile horizontally flipped - -#define tile_8bpp_draw_four_flip(index, combine_op, alpha_op) \ - tile_8bpp_draw_##combine_op(index + 3, mask, 0, alpha_op); \ - tile_8bpp_draw_##combine_op(index + 2, shift_mask, 8, alpha_op); \ - tile_8bpp_draw_##combine_op(index + 1, shift_mask, 16, alpha_op); \ - tile_8bpp_draw_##combine_op(index + 0, shift, 24, alpha_op) - -#define tile_8bpp_draw_four_base(index, alpha_op, flip_op) tile_8bpp_draw_four_##flip_op(index, base, alpha_op) - -// Draw half of a tile in 8bpp mode, for transparent renderer; as an -// optimization the entire thing is checked against zero (in transparent -// capable renders it is more likely for the pixels to be transparent than -// opaque) - -#define tile_8bpp_draw_four_transparent(index, alpha_op, flip_op) \ - if (current_pixels != 0) { \ - tile_8bpp_draw_four_##flip_op(index, transparent, alpha_op); \ - } - -#define tile_8bpp_draw_four_copy(index, alpha_op, flip_op) \ - if (current_pixels != 0) { \ - tile_8bpp_draw_four_##flip_op(index, copy, alpha_op); \ - } - -// Helper macro for drawing 8bpp tiles clipped against the edge of the screen - -#define partial_tile_8bpp(combine_op, alpha_op) \ - for (i = 0; i < partial_tile_run; i++) { \ - tile_8bpp_draw_##combine_op(0, mask, 0, alpha_op); \ - current_pixels >>= 8; \ - advance_dest_ptr_##combine_op(1); \ - } - -// Draws 8bpp tiles clipped against the left side of the screen, -// partial_tile_offset indicates how much clipped in it is, partial_tile_run -// indicates how much it should draw. - -#define partial_tile_right_noflip_8bpp(combine_op, alpha_op) \ - if (partial_tile_offset >= 4) { \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) >> ((partial_tile_offset - 4) * 8); \ - partial_tile_8bpp(combine_op, alpha_op); \ - } else { \ - partial_tile_run -= 4; \ - current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 8); \ - partial_tile_8bpp(combine_op, alpha_op); \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ - tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ - advance_dest_ptr_##combine_op(4); \ - } - -// Draws 8bpp tiles clipped against both the left and right side of the -// screen, IE, runs of less than 8 - partial_tile_offset. - -#define partial_tile_mid_noflip_8bpp(combine_op, alpha_op) \ - if (partial_tile_offset >= 4) { \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) >> ((partial_tile_offset - 4) * 8); \ - } else { \ - current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 8); \ - if ((partial_tile_offset + partial_tile_run) > 4) { \ - u32 old_run = partial_tile_run; \ - partial_tile_run = 4 - partial_tile_offset; \ - partial_tile_8bpp(combine_op, alpha_op); \ - partial_tile_run = old_run - partial_tile_run; \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ - } \ - } \ - partial_tile_8bpp(combine_op, alpha_op); - -// Draws 8bpp tiles clipped against the right side of the screen, -// partial_tile_run indicates how much there is to draw. - -#define partial_tile_left_noflip_8bpp(combine_op, alpha_op) \ - if (partial_tile_run >= 4) { \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ - advance_dest_ptr_##combine_op(4); \ - tile_ptr += 4; \ - partial_tile_run -= 4; \ - } \ - \ - current_pixels = eswap32(*((u32 *)(tile_ptr))); \ - partial_tile_8bpp(combine_op, alpha_op) - -// Draws a non-clipped (complete) 8bpp tile. - -#define tile_noflip_8bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - tile_8bpp_draw_four_##combine_op(0, alpha_op, noflip); \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ - tile_8bpp_draw_four_##combine_op(4, alpha_op, noflip) - -// Like the above versions but draws flipped tiles. - -#define partial_tile_flip_8bpp(combine_op, alpha_op) \ - for (i = 0; i < partial_tile_run; i++) { \ - tile_8bpp_draw_##combine_op(0, shift, 24, alpha_op); \ - current_pixels <<= 8; \ - advance_dest_ptr_##combine_op(1); \ - } - -#define partial_tile_right_flip_8bpp(combine_op, alpha_op) \ - if (partial_tile_offset >= 4) { \ - current_pixels = eswap32(*((u32 *)tile_ptr)) << ((partial_tile_offset - 4) * 8); \ - partial_tile_flip_8bpp(combine_op, alpha_op); \ - } else { \ - partial_tile_run -= 4; \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) << ((partial_tile_offset - 4) * 8); \ - partial_tile_flip_8bpp(combine_op, alpha_op); \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ - advance_dest_ptr_##combine_op(4); \ - } - -#define partial_tile_mid_flip_8bpp(combine_op, alpha_op) \ - if (partial_tile_offset >= 4) \ - current_pixels = eswap32(*((u32 *)tile_ptr)) << ((partial_tile_offset - 4) * 8); \ - else { \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))) << ((partial_tile_offset - 4) * 8); \ - \ - if ((partial_tile_offset + partial_tile_run) > 4) { \ - u32 old_run = partial_tile_run; \ - partial_tile_run = 4 - partial_tile_offset; \ - partial_tile_flip_8bpp(combine_op, alpha_op); \ - partial_tile_run = old_run - partial_tile_run; \ - current_pixels = eswap32(*((u32 *)(tile_ptr))); \ - } \ - } \ - partial_tile_flip_8bpp(combine_op, alpha_op); - -#define partial_tile_left_flip_8bpp(combine_op, alpha_op) \ - if (partial_tile_run >= 4) { \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ - tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ - advance_dest_ptr_##combine_op(4); \ - tile_ptr -= 4; \ - partial_tile_run -= 4; \ - } \ - \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ - partial_tile_flip_8bpp(combine_op, alpha_op) - -#define tile_flip_8bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)(tile_ptr + 4))); \ - tile_8bpp_draw_four_##combine_op(0, alpha_op, flip); \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - tile_8bpp_draw_four_##combine_op(4, alpha_op, flip) - -// Operations for isolating 4bpp tiles in a 32bit block - -#define tile_4bpp_pixel_op_mask(op_param) current_pixel = current_pixels & 0x0F - -#define tile_4bpp_pixel_op_shift_mask(shift) current_pixel = (current_pixels >> shift) & 0x0F - -#define tile_4bpp_pixel_op_shift(shift) current_pixel = current_pixels >> shift - -#define tile_4bpp_pixel_op_none(op_param) - -// Draws a single 4bpp pixel as base, normal renderer; checks to see if the -// pixel is zero because if so the current palette should not be applied. -// These ifs can be replaced with a lookup table, may or may not be superior -// this way, should be benchmarked. The lookup table would be from 0-255 -// identity map except for multiples of 16, which would map to 0. - -#define tile_4bpp_draw_base_normal(index) \ - if (current_pixel) \ - current_pixel |= current_palette; \ - tile_expand_base_normal(index); - -#define tile_4bpp_draw_base_alpha(index) \ - if (current_pixel) { \ - current_pixel |= current_palette; \ - tile_expand_base_alpha(index); \ - } else { \ - tile_expand_base_bg(index); \ - } - -#define tile_4bpp_draw_base_color16(index) tile_4bpp_draw_base_alpha(index) - -#define tile_4bpp_draw_base_color32(index) tile_4bpp_draw_base_alpha(index) - -#define tile_4bpp_draw_base(index, op, op_param, alpha_op) \ - tile_4bpp_pixel_op_##op(op_param); \ - tile_4bpp_draw_base_##alpha_op(index) - -// Draws a single 4bpp pixel as layered, if not transparent. - -#define tile_4bpp_draw_transparent(index, op, op_param, alpha_op) \ - tile_4bpp_pixel_op_##op(op_param); \ - if (current_pixel) { \ - current_pixel |= current_palette; \ - tile_expand_transparent_##alpha_op(index); \ - } - -#define tile_4bpp_draw_copy(index, op, op_param, alpha_op) \ - tile_4bpp_pixel_op_##op(op_param); \ - if (current_pixel) { \ - current_pixel |= current_palette; \ - tile_expand_copy(index); \ - } - -// Draws eight background pixels in transparent mode, for alpha or normal -// renderers. - -#define tile_4bpp_draw_eight_base_zero(value) \ - dest_ptr[0] = value; \ - dest_ptr[1] = value; \ - dest_ptr[2] = value; \ - dest_ptr[3] = value; \ - dest_ptr[4] = value; \ - dest_ptr[5] = value; \ - dest_ptr[6] = value; \ - dest_ptr[7] = value - -// Draws eight background pixels for the alpha renderer, basically color zero -// with the background flag high. - -#define tile_4bpp_draw_eight_base_zero_alpha() tile_4bpp_draw_eight_base_zero(bg_combine) - -#define tile_4bpp_draw_eight_base_zero_color16() tile_4bpp_draw_eight_base_zero_alpha() - -#define tile_4bpp_draw_eight_base_zero_color32() tile_4bpp_draw_eight_base_zero_alpha() - -// Draws eight background pixels for the normal renderer, just a bunch of -// zeros. - -#define tile_4bpp_draw_eight_base_zero_normal() \ - current_pixel = palette[0]; \ - tile_4bpp_draw_eight_base_zero(current_pixel) - -// Draws eight 4bpp pixels. - -#define tile_4bpp_draw_eight_noflip(combine_op, alpha_op) \ - tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \ - tile_4bpp_draw_##combine_op(1, shift_mask, 4, alpha_op); \ - tile_4bpp_draw_##combine_op(2, shift_mask, 8, alpha_op); \ - tile_4bpp_draw_##combine_op(3, shift_mask, 12, alpha_op); \ - tile_4bpp_draw_##combine_op(4, shift_mask, 16, alpha_op); \ - tile_4bpp_draw_##combine_op(5, shift_mask, 20, alpha_op); \ - tile_4bpp_draw_##combine_op(6, shift_mask, 24, alpha_op); \ - tile_4bpp_draw_##combine_op(7, shift, 28, alpha_op) - -// Draws eight 4bpp pixels in reverse order (for hflip). - -#define tile_4bpp_draw_eight_flip(combine_op, alpha_op) \ - tile_4bpp_draw_##combine_op(7, mask, 0, alpha_op); \ - tile_4bpp_draw_##combine_op(6, shift_mask, 4, alpha_op); \ - tile_4bpp_draw_##combine_op(5, shift_mask, 8, alpha_op); \ - tile_4bpp_draw_##combine_op(4, shift_mask, 12, alpha_op); \ - tile_4bpp_draw_##combine_op(3, shift_mask, 16, alpha_op); \ - tile_4bpp_draw_##combine_op(2, shift_mask, 20, alpha_op); \ - tile_4bpp_draw_##combine_op(1, shift_mask, 24, alpha_op); \ - tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op) - -// Draws eight 4bpp pixels in base mode, checks if all are zero, if so draws -// the appropriate background pixels. - -#define tile_4bpp_draw_eight_base(alpha_op, flip_op) \ - if (current_pixels != 0) { \ - tile_4bpp_draw_eight_##flip_op(base, alpha_op); \ - } else { \ - tile_4bpp_draw_eight_base_zero_##alpha_op(); \ - } - -// Draws eight 4bpp pixels in transparent (layered) mode, checks if all are -// zero and if so draws nothing. - -#define tile_4bpp_draw_eight_transparent(alpha_op, flip_op) \ - if (current_pixels != 0) { \ - tile_4bpp_draw_eight_##flip_op(transparent, alpha_op); \ - } - -#define tile_4bpp_draw_eight_copy(alpha_op, flip_op) \ - if (current_pixels != 0) { \ - tile_4bpp_draw_eight_##flip_op(copy, alpha_op); \ - } - -// Gets the current tile in 4bpp mode, also getting the current palette and -// the pixel block. - -#define get_tile_4bpp() \ - current_tile = eswap16(*map_ptr); \ - current_palette = (current_tile >> 12) << 4; \ - tile_ptr = tile_base + ((current_tile & 0x3FF) * 32); - -// Helper macro for drawing clipped 4bpp tiles. - -#define partial_tile_4bpp(combine_op, alpha_op) \ - for (i = 0; i < partial_tile_run; i++) { \ - tile_4bpp_draw_##combine_op(0, mask, 0, alpha_op); \ - current_pixels >>= 4; \ - advance_dest_ptr_##combine_op(1); \ - } - -// Draws a 4bpp tile clipped against the left edge of the screen. -// partial_tile_offset is how far in it's clipped, partial_tile_run is -// how many to draw. - -#define partial_tile_right_noflip_4bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)) >> (partial_tile_offset * 4); \ - partial_tile_4bpp(combine_op, alpha_op) - -// Draws a 4bpp tile clipped against both edges of the screen, same as right. - -#define partial_tile_mid_noflip_4bpp(combine_op, alpha_op) partial_tile_right_noflip_4bpp(combine_op, alpha_op) - -// Draws a 4bpp tile clipped against the right edge of the screen. -// partial_tile_offset is how many to draw. - -#define partial_tile_left_noflip_4bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - partial_tile_4bpp(combine_op, alpha_op) - -// Draws a complete 4bpp tile row (not clipped) -#define tile_noflip_4bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - tile_4bpp_draw_eight_##combine_op(alpha_op, noflip) - -// Like the above, but draws flipped tiles. - -#define partial_tile_flip_4bpp(combine_op, alpha_op) \ - for (i = 0; i < partial_tile_run; i++) { \ - tile_4bpp_draw_##combine_op(0, shift, 28, alpha_op); \ - current_pixels <<= 4; \ - advance_dest_ptr_##combine_op(1); \ - } - -#define partial_tile_right_flip_4bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)) << (partial_tile_offset * 4); \ - partial_tile_flip_4bpp(combine_op, alpha_op) - -#define partial_tile_mid_flip_4bpp(combine_op, alpha_op) partial_tile_right_flip_4bpp(combine_op, alpha_op) - -#define partial_tile_left_flip_4bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - partial_tile_flip_4bpp(combine_op, alpha_op) - -#define tile_flip_4bpp(combine_op, alpha_op) \ - current_pixels = eswap32(*((u32 *)tile_ptr)); \ - tile_4bpp_draw_eight_##combine_op(alpha_op, flip) - -// Draws a single (partial or complete) tile from the tilemap, flipping -// as necessary. - -#define single_tile_map(tile_type, combine_op, color_depth, alpha_op) \ - get_tile_##color_depth(); \ - if (current_tile & 0x800) \ - tile_ptr += vertical_pixel_flip; \ - \ - if (current_tile & 0x400) { \ - tile_type##_flip_##color_depth(combine_op, alpha_op); \ - } else { \ - tile_type##_noflip_##color_depth(combine_op, alpha_op); \ - } - -#define single_tile_map_base_4bpp_color16(tile_type) \ - get_tile_4bpp(); \ - if (current_tile & 0x800) \ - tile_ptr += vertical_pixel_flip; \ - \ - if (current_tile & 0x400) { \ - tile_type##_flip_4bpp(base, color16); \ - } else { \ - tile_type##_noflip_4bpp(base, color16); \ - } - -// Draws multiple sequential tiles from the tilemap, hflips and vflips as -// necessary. - -#define multiple_tile_map(combine_op, color_depth, alpha_op) \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, combine_op, color_depth, alpha_op); \ - advance_dest_ptr_##combine_op(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_transparent_8bpp_color16() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, transparent, 8bpp, color16); \ - advance_dest_ptr_transparent(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_transparent_4bpp_color16() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, transparent, 4bpp, color16); \ - advance_dest_ptr_transparent(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_base_8bpp_color16() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, base, 8bpp, color16); \ - advance_dest_ptr_base(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_base_4bpp_color16() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map_base_4bpp_color16(tile); \ - advance_dest_ptr_base(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_transparent_8bpp_normal() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, transparent, 8bpp, normal); \ - advance_dest_ptr_transparent(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_transparent_4bpp_normal() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, transparent, 4bpp, normal); \ - advance_dest_ptr_transparent(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_base_8bpp_normal() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, base, 8bpp, normal); \ - advance_dest_ptr_base(8); \ - map_ptr++; \ - } - -#define multiple_tile_map_base_4bpp_normal() \ - for (i = 0; i < tile_run; i++) { \ - single_tile_map(tile, base, 4bpp, normal); \ - advance_dest_ptr_base(8); \ - map_ptr++; \ - } - -// Draws a partial tile from a tilemap clipped against the left edge of the -// screen. - -#define partial_tile_right_map(combine_op, color_depth, alpha_op) \ - single_tile_map(partial_tile_right, combine_op, color_depth, alpha_op); \ - map_ptr++ - -// Draws a partial tile from a tilemap clipped against both edges of the -// screen. - -#define partial_tile_mid_map(combine_op, color_depth, alpha_op) single_tile_map(partial_tile_mid, combine_op, color_depth, alpha_op) - -// Draws a partial tile from a tilemap clipped against the right edge of the -// screen. - -#define partial_tile_left_map(combine_op, color_depth, alpha_op) single_tile_map(partial_tile_left, combine_op, color_depth, alpha_op) - -// Advances a non-flipped 4bpp obj to the next tile. - -#define obj_advance_noflip_4bpp() tile_ptr += 32 - -// Advances a non-flipped 8bpp obj to the next tile. - -#define obj_advance_noflip_8bpp() tile_ptr += 64 - -// Advances a flipped 4bpp obj to the next tile. - -#define obj_advance_flip_4bpp() tile_ptr -= 32 - -// Advances a flipped 8bpp obj to the next tile. - -#define obj_advance_flip_8bpp() tile_ptr -= 64 - -// Draws multiple sequential tiles from an obj, flip_op determines if it should -// be flipped or not (set to flip or noflip) - -#define multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op) \ - for (i = 0; i < tile_run; i++) { \ - tile_##flip_op##_##color_depth(combine_op, alpha_op); \ - obj_advance_##flip_op##_##color_depth(); \ - advance_dest_ptr_##combine_op(8); \ - } - -// Draws an obj's tile clipped against the left side of the screen - -#define partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op) \ - partial_tile_right_##flip_op##_##color_depth(combine_op, alpha_op); \ - obj_advance_##flip_op##_##color_depth() - -// Draws an obj's tile clipped against both sides of the screen - -#define partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op) partial_tile_mid_##flip_op##_##color_depth(combine_op, alpha_op) - -// Draws an obj's tile clipped against the right side of the screen - -#define partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op) partial_tile_left_##flip_op##_##color_depth(combine_op, alpha_op) - -// Extra variables specific for 8bpp/4bpp tile renderers. - -#define tile_extra_variables_8bpp() - -#define tile_extra_variables_4bpp() u32 current_palette - -// Byte lengths of complete tiles and tile rows in 4bpp and 8bpp. - -#define tile_width_4bpp 4 -#define tile_size_4bpp 32 -#define tile_width_8bpp 8 -#define tile_size_8bpp 64 - -#define render_scanline_dest_normal u16 -#define render_scanline_dest_alpha u32 -#define render_scanline_dest_alpha_obj u32 -#define render_scanline_dest_color16 u16 -#define render_scanline_dest_color32 u32 -#define render_scanline_dest_partial_alpha u32 -#define render_scanline_dest_copy_tile u16 -#define render_scanline_dest_copy_bitmap u16 - -// If rendering a scanline that is not a target A then there's no point in -// keeping what's underneath it because it can't blend with it. - -#define render_scanline_skip_alpha(bg_type, combine_op) \ - if ((pixel_combine & 0x00000200) == 0) { \ - render_scanline_##bg_type##_##combine_op##_color32(layer, start, end, scanline); \ - return; \ - } - -#define render_scanline_extra_variables_base_normal(bg_type) u16 *palette = PLTT - -#define render_scanline_extra_variables_base_alpha(bg_type) \ - u32 bg_combine = color_combine_mask(5); \ - u32 pixel_combine = color_combine_mask(layer) | (bg_combine << 16); \ - render_scanline_skip_alpha(bg_type, base) - -#define render_scanline_extra_variables_base_color() \ - u32 bg_combine = color_combine_mask(5); \ - u32 pixel_combine = color_combine_mask(layer) - -#define render_scanline_extra_variables_base_color16(bg_type) render_scanline_extra_variables_base_color() - -#define render_scanline_extra_variables_base_color32(bg_type) render_scanline_extra_variables_base_color() - -#define render_scanline_extra_variables_transparent_normal(bg_type) render_scanline_extra_variables_base_normal(bg_type) - -#define render_scanline_extra_variables_transparent_alpha(bg_type) \ - u32 pixel_combine = color_combine_mask(layer); \ - render_scanline_skip_alpha(bg_type, transparent) - -#define render_scanline_extra_variables_transparent_color() u32 pixel_combine = color_combine_mask(layer) - -#define render_scanline_extra_variables_transparent_color16(bg_type) render_scanline_extra_variables_transparent_color() - -#define render_scanline_extra_variables_transparent_color32(bg_type) render_scanline_extra_variables_transparent_color() - -static const u32 map_widths[] = { 256, 512, 256, 512 }; - -static void render_scanline_text_base_normal(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_base_normal(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_normal *dest_ptr = ((render_scanline_dest_normal *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: base - * alpha : normal - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - - tile_extra_variables_8bpp(); - - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 8bpp, normal); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 8bpp, normal); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 8bpp, normal); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_base_8bpp_normal(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_base_8bpp_normal(); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(base, 8bpp, normal); - } - } else { - /* color depth: 4bpp - * combine: base - * alpha : normal - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - - tile_extra_variables_4bpp(); - - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 4bpp, normal); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 4bpp, normal); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 4bpp, normal); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_base_4bpp_normal(); - map_ptr = second_ptr; - end -= pixel_run; - } - - tile_run = end / 8; - multiple_tile_map_base_4bpp_normal(); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(base, 4bpp, normal); - } - } -} - -static void render_scanline_text_transparent_normal(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_transparent_normal(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_normal *dest_ptr = ((render_scanline_dest_normal *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: transparent - * alpha : normal - */ - - /* Render a single scanline of text tiles */ - - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 8bpp, normal); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 8bpp, normal); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 8bpp, normal); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_transparent_8bpp_normal(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_transparent_8bpp_normal(); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(transparent, 8bpp, normal); - } - } else { - /* color depth: 4bpp - * combine: transparent - * alpha : normal - */ - - /* Render a single scanline of text tiles */ - - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 4bpp, normal); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 4bpp, normal); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 4bpp, normal); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_transparent_4bpp_normal(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_transparent_4bpp_normal(); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(transparent, 4bpp, normal); - } - } -} - -static void render_scanline_text_base_color16(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_base_color16(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_color16 *dest_ptr = ((render_scanline_dest_color16 *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: base - * alpha :color16 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 8bpp, color16); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 8bpp, color16); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 8bpp, color16); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_base_8bpp_color16(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_base_8bpp_color16(); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(base, 8bpp, color16); - } - } else { - /* color depth: 4bpp - * combine: base - * alpha :color16 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 4bpp, color16); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 4bpp, color16); - } - } - - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 4bpp, color16); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_base_4bpp_color16(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_base_4bpp_color16(); - - partial_tile_run = end % 8; - - if (partial_tile_run) { - partial_tile_left_map(base, 4bpp, color16); - } - } -} - -static void render_scanline_text_transparent_color16(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_transparent_color16(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_color16 *dest_ptr = ((render_scanline_dest_color16 *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: transparent - * alpha :color16 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 8bpp, color16); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 8bpp, color16); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 8bpp, color16); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_transparent_8bpp_color16(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_transparent_8bpp_color16(); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(transparent, 8bpp, color16); - } - } else { - /* color depth: 4bpp - * combine: transparent - * alpha :color16 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 4bpp, color16); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 4bpp, color16); - } - } - - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 4bpp, color16); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map_transparent_4bpp_color16(); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map_transparent_4bpp_color16(); - - partial_tile_run = end % 8; - - if (partial_tile_run) { - partial_tile_left_map(transparent, 4bpp, color16); - } - } -} - -static void render_scanline_text_base_color32(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_base_color32(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_color32 *dest_ptr = ((render_scanline_dest_color32 *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: base - * alpha :color32 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 8bpp, color32); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 8bpp, color32); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 8bpp, color32); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(base, 8bpp, color32); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(base, 8bpp, color32); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(base, 8bpp, color32); - } - } else { - /* color depth: 4bpp - * combine: base - * alpha :color32 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 4bpp, color32); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 4bpp, color32); - } - } - - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 4bpp, color32); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(base, 4bpp, color32); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(base, 4bpp, color32); - - partial_tile_run = end % 8; - - if (partial_tile_run) { - partial_tile_left_map(base, 4bpp, color32); - } - } -} - -static void render_scanline_text_transparent_color32(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_transparent_color32(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_color32 *dest_ptr = ((render_scanline_dest_color32 *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: transparent - * alpha :color32 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 8bpp, color32); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 8bpp, color32); - } - } - - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 8bpp, color32); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(transparent, 8bpp, color32); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(transparent, 8bpp, color32); - - partial_tile_run = end % 8; - - if (partial_tile_run) { - partial_tile_left_map(transparent, 8bpp, color32); - } - } else { - /* color depth: 4bpp - * combine: transparent - * alpha :color32 - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 4bpp, color32); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 4bpp, color32); - } - } - - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 4bpp, color32); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(transparent, 4bpp, color32); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(transparent, 4bpp, color32); - - partial_tile_run = end % 8; - - if (partial_tile_run) { - partial_tile_left_map(transparent, 4bpp, color32); - } - } -} - -static void render_scanline_text_base_alpha(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_base_alpha(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_alpha *dest_ptr = ((render_scanline_dest_alpha *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: base - * alpha : alpha - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 8bpp, alpha); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 8bpp, alpha); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 8bpp, alpha); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(base, 8bpp, alpha); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(base, 8bpp, alpha); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(base, 8bpp, alpha); - } - } else { - /* color depth: 4bpp - * combine: base - * alpha : alpha - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(base, 4bpp, alpha); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(base, 4bpp, alpha); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(base, 4bpp, alpha); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(base, 4bpp, alpha); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(base, 4bpp, alpha); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(base, 4bpp, alpha); - } - } -} - -static void render_scanline_text_transparent_alpha(u32 layer, u32 start, u32 end, void *scanline) -{ - render_scanline_extra_variables_transparent_alpha(text); - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); - u32 map_size = (bg_control >> 14) & 0x03; - u32 map_width = map_widths[map_size]; - u32 horizontal_offset = (read_ioreg(REG_ADDR_BG0HOFS + (layer * 2) * sizeof(u16)) + start) % 512; - u32 vertical_offset = (read_ioreg(REG_ADDR_VCOUNT) + read_ioreg(REG_ADDR_BG0VOFS + (layer * 2) * sizeof(u16))) % 512; - u32 current_pixel; - u32 current_pixels; - u32 partial_tile_run = 0; - u32 partial_tile_offset; - u32 tile_run; - u32 i; - render_scanline_dest_alpha *dest_ptr = ((render_scanline_dest_alpha *)scanline) + start; - - u16 *map_base = (u16 *)BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); - u16 *map_ptr, *second_ptr; - u8 *tile_ptr; - - end -= start; - - if ((map_size & 0x02) && (vertical_offset >= 256)) { - map_base += ((map_width / 8) * 32) + (((vertical_offset - 256) / 8) * 32); - } else { - map_base += (((vertical_offset % 256) / 8) * (map_width / 8)); - } - - if (map_size & 0x01) { - if (horizontal_offset >= 256) { - horizontal_offset -= 256; - map_ptr = map_base + ((map_width / 8) * 32) + (horizontal_offset / 8); - second_ptr = map_base; - } else { - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base + ((map_width / 8) * 32); - } - } else { - horizontal_offset %= 256; - map_ptr = map_base + (horizontal_offset / 8); - second_ptr = map_base; - } - - if (bg_control & 0x80) { - /* color depth: 8bpp - * combine: transparent - * alpha : alpha - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_8bpp; - s32 vertical_pixel_flip = ((tile_size_8bpp - tile_width_8bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_8bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 8bpp, alpha); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 8bpp, alpha); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 8bpp, alpha); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(transparent, 8bpp, alpha); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(transparent, 8bpp, alpha); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(transparent, 8bpp, alpha); - } - } else { - /* color depth: 4bpp - * combine: transparent - * alpha : alpha - */ - - /* Render a single scanline of text tiles */ - u32 vertical_pixel_offset = (vertical_offset % 8) * tile_width_4bpp; - s32 vertical_pixel_flip = ((tile_size_4bpp - tile_width_4bpp) - vertical_pixel_offset) - vertical_pixel_offset; - tile_extra_variables_4bpp(); - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03) + vertical_pixel_offset; - u32 pixel_run = map_width - (horizontal_offset % map_width); - u32 current_tile; - - map_base += ((vertical_offset % 256) / 8) * (map_width / 8); - partial_tile_offset = (horizontal_offset % 8); - - if (pixel_run >= end) { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - if (end < partial_tile_run) { - partial_tile_run = end; - partial_tile_mid_map(transparent, 4bpp, alpha); - return; - } else { - end -= partial_tile_run; - partial_tile_right_map(transparent, 4bpp, alpha); - } - } - } else { - if (partial_tile_offset) { - partial_tile_run = 8 - partial_tile_offset; - partial_tile_right_map(transparent, 4bpp, alpha); - } - - tile_run = (pixel_run - partial_tile_run) / 8; - multiple_tile_map(transparent, 4bpp, alpha); - map_ptr = second_ptr; - end -= pixel_run; - } - tile_run = end / 8; - multiple_tile_map(transparent, 4bpp, alpha); - - partial_tile_run = end % 8; - if (partial_tile_run) { - partial_tile_left_map(transparent, 4bpp, alpha); - } - } -} - -s32 affine_reference_x[2]; -s32 affine_reference_y[2]; - -static inline s32 signext28(u32 value) -{ - s32 ret = (s32)(value << 4); - return ret >> 4; -} - -void video_reload_counters() -{ - /* This happens every Vblank */ - affine_reference_x[0] = signext28(read_ioreg32(REG_ADDR_BG2X_L)); - affine_reference_y[0] = signext28(read_ioreg32(REG_ADDR_BG2Y_L)); - affine_reference_x[1] = signext28(read_ioreg32(REG_ADDR_BG3X_L)); - affine_reference_y[1] = signext28(read_ioreg32(REG_ADDR_BG3Y_L)); -} - -#define affine_render_bg_pixel_normal() current_pixel = PLTT[0] - -#define affine_render_bg_pixel_alpha() current_pixel = bg_combine - -#define affine_render_bg_pixel_color16() affine_render_bg_pixel_alpha() - -#define affine_render_bg_pixel_color32() affine_render_bg_pixel_alpha() - -#define affine_render_bg_pixel_base(alpha_op) affine_render_bg_pixel_##alpha_op() - -#define affine_render_bg_pixel_transparent(alpha_op) - -#define affine_render_bg_pixel_copy(alpha_op) - -#define affine_render_bg_base(alpha_op) dest_ptr[0] = current_pixel - -#define affine_render_bg_transparent(alpha_op) - -#define affine_render_bg_copy(alpha_op) - -#define affine_render_bg_remainder_base(alpha_op) \ - affine_render_bg_pixel_##alpha_op(); \ - for (; i < end; i++) { \ - affine_render_bg_base(alpha_op); \ - advance_dest_ptr_base(1); \ - } - -#define affine_render_bg_remainder_transparent(alpha_op) - -#define affine_render_bg_remainder_copy(alpha_op) - -#define affine_render_next(combine_op) \ - source_x += dx; \ - source_y += dy; \ - advance_dest_ptr_##combine_op(1) - -#define affine_render_scale_offset() \ - tile_base += ((pixel_y % 8) * 8); \ - map_base += (pixel_y / 8) << map_pitch - -#define affine_render_scale_pixel(combine_op, alpha_op) \ - map_offset = (pixel_x / 8); \ - if (map_offset != last_map_offset) { \ - tile_ptr = tile_base + (map_base[map_offset] * 64); \ - last_map_offset = map_offset; \ - } \ - tile_ptr = tile_base + (map_base[(pixel_x / 8)] * 64); \ - current_pixel = tile_ptr[(pixel_x % 8)]; \ - tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \ - affine_render_next(combine_op) - -#define affine_render_scale(combine_op, alpha_op) \ - { \ - pixel_y = source_y >> 8; \ - u32 i = 0; \ - affine_render_bg_pixel_##combine_op(alpha_op); \ - if ((u32)pixel_y < (u32)width_height) { \ - affine_render_scale_offset(); \ - for (; i < end; i++) { \ - pixel_x = source_x >> 8; \ - \ - if ((u32)pixel_x < (u32)width_height) { \ - break; \ - } \ - \ - affine_render_bg_##combine_op(alpha_op); \ - affine_render_next(combine_op); \ - } \ - \ - for (; i < end; i++) { \ - pixel_x = source_x >> 8; \ - \ - if ((u32)pixel_x >= (u32)width_height) \ - break; \ - \ - affine_render_scale_pixel(combine_op, alpha_op); \ - } \ - } \ - affine_render_bg_remainder_##combine_op(alpha_op); \ - } - -#define affine_render_scale_wrap(combine_op, alpha_op) \ - { \ - u32 wrap_mask = width_height - 1; \ - pixel_y = (source_y >> 8) & wrap_mask; \ - if ((u32)pixel_y < (u32)width_height) { \ - affine_render_scale_offset(); \ - for (i = 0; i < end; i++) { \ - pixel_x = (source_x >> 8) & wrap_mask; \ - affine_render_scale_pixel(combine_op, alpha_op); \ - } \ - } \ - } - -#define affine_render_rotate_pixel(combine_op, alpha_op) \ - map_offset = (pixel_x / 8) + ((pixel_y / 8) << map_pitch); \ - if (map_offset != last_map_offset) { \ - tile_ptr = tile_base + (map_base[map_offset] * 64); \ - last_map_offset = map_offset; \ - } \ - \ - current_pixel = tile_ptr[(pixel_x % 8) + ((pixel_y % 8) * 8)]; \ - tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); \ - affine_render_next(combine_op) - -#define affine_render_rotate(combine_op, alpha_op) \ - { \ - affine_render_bg_pixel_##combine_op(alpha_op); \ - for (i = 0; i < end; i++) { \ - pixel_x = source_x >> 8; \ - pixel_y = source_y >> 8; \ - \ - if (((u32)pixel_x < (u32)width_height) && ((u32)pixel_y < (u32)width_height)) { \ - break; \ - } \ - affine_render_bg_##combine_op(alpha_op); \ - affine_render_next(combine_op); \ - } \ - \ - for (; i < end; i++) { \ - pixel_x = source_x >> 8; \ - pixel_y = source_y >> 8; \ - \ - if (((u32)pixel_x >= (u32)width_height) || ((u32)pixel_y >= (u32)width_height)) { \ - affine_render_bg_remainder_##combine_op(alpha_op); \ - break; \ - } \ - \ - affine_render_rotate_pixel(combine_op, alpha_op); \ - } \ - } - -#define affine_render_rotate_wrap(combine_op, alpha_op) \ - { \ - u32 wrap_mask = width_height - 1; \ - for (i = 0; i < end; i++) { \ - pixel_x = (source_x >> 8) & wrap_mask; \ - pixel_y = (source_y >> 8) & wrap_mask; \ - \ - affine_render_rotate_pixel(combine_op, alpha_op); \ - } \ - } - -// Build affine background renderers. - -#define render_scanline_affine_builder(combine_op, alpha_op) \ - void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, u32 start, u32 end, void *scanline) \ - { \ - render_scanline_extra_variables_##combine_op##_##alpha_op(affine); \ - u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); \ - u32 current_pixel; \ - s32 source_x, source_y; \ - u32 pixel_x, pixel_y; \ - u32 layer_offset = (layer - 2) * 8; \ - s32 dx, dy; \ - u32 map_size = (bg_control >> 14) & 0x03; \ - u32 width_height = 1 << (7 + map_size); \ - u32 map_pitch = map_size + 4; \ - u8 *map_base = BG_SCREEN_ADDR((bg_control & BGCNT_SCREENBASE_MASK) >> 8); \ - u8 *tile_base = BG_CHAR_ADDR((bg_control >> 2) & 0x03); \ - u8 *tile_ptr = NULL; \ - u32 map_offset, last_map_offset = (u32)-1; \ - u32 i; \ - render_scanline_dest_##alpha_op *dest_ptr = ((render_scanline_dest_##alpha_op *)scanline) + start; \ - \ - dx = (s16)read_ioreg(REG_ADDR_BG2PA + (layer_offset * sizeof(u16))); \ - dy = (s16)read_ioreg(REG_ADDR_BG2PC + (layer_offset * sizeof(u16))); \ - source_x = affine_reference_x[layer - 2] + (start * dx); \ - source_y = affine_reference_y[layer - 2] + (start * dy); \ - \ - end -= start; \ - \ - switch (((bg_control >> 12) & 0x02) | (dy != 0)) { \ - case 0x00: \ - affine_render_scale(combine_op, alpha_op); \ - break; \ - \ - case 0x01: \ - affine_render_rotate(combine_op, alpha_op); \ - break; \ - \ - case 0x02: \ - affine_render_scale_wrap(combine_op, alpha_op); \ - break; \ - \ - case 0x03: \ - affine_render_rotate_wrap(combine_op, alpha_op); \ - break; \ - } \ - } - -render_scanline_affine_builder(base, normal); -render_scanline_affine_builder(transparent, normal); -render_scanline_affine_builder(base, color16); -render_scanline_affine_builder(transparent, color16); -render_scanline_affine_builder(base, color32); -render_scanline_affine_builder(transparent, color32); -render_scanline_affine_builder(base, alpha); -render_scanline_affine_builder(transparent, alpha); - -#define bitmap_render_pixel_mode3(alpha_op) \ - current_pixel = convert_palette(current_pixel); \ - *dest_ptr = current_pixel - -#define bitmap_render_pixel_mode4(alpha_op) tile_expand_base_##alpha_op##_mode4(0) - -#define bitmap_render_pixel_mode5(alpha_op) bitmap_render_pixel_mode3(alpha_op) - -#define bitmap_render_scale(type, alpha_op, width, height) \ - pixel_y = (source_y >> 8); \ - if ((u32)pixel_y < (u32)height) { \ - pixel_x = (source_x >> 8); \ - src_ptr += (pixel_y * width); \ - if (dx == 0x100) { \ - if (pixel_x < 0) { \ - end += pixel_x; \ - dest_ptr -= pixel_x; \ - pixel_x = 0; \ - } else if (pixel_x > 0) \ - src_ptr += pixel_x; \ - \ - if ((pixel_x + end) >= width) \ - end = (width - pixel_x); \ - \ - for (i = 0; (s32)i < (s32)end; i++) { \ - current_pixel = srcread_##type(*src_ptr); \ - bitmap_render_pixel_##type(alpha_op); \ - src_ptr++; \ - dest_ptr++; \ - } \ - } else { \ - if ((u32)(source_y >> 8) < (u32)height) { \ - for (i = 0; i < end; i++) { \ - pixel_x = (source_x >> 8); \ - \ - if ((u32)pixel_x < (u32)width) \ - break; \ - \ - source_x += dx; \ - dest_ptr++; \ - } \ - \ - for (; i < end; i++) { \ - pixel_x = (source_x >> 8); \ - \ - if ((u32)pixel_x >= (u32)width) \ - break; \ - \ - current_pixel = srcread_##type(src_ptr[pixel_x]); \ - bitmap_render_pixel_##type(alpha_op); \ - \ - source_x += dx; \ - dest_ptr++; \ - } \ - } \ - } \ - } - -#define bitmap_render_rotate(type, alpha_op, width, height) \ - for (i = 0; i < end; i++) { \ - pixel_x = source_x >> 8; \ - pixel_y = source_y >> 8; \ - \ - if (((u32)pixel_x < (u32)width) && ((u32)pixel_y < (u32)height)) \ - break; \ - \ - source_x += dx; \ - source_y += dy; \ - dest_ptr++; \ - } \ - \ - for (; i < end; i++) { \ - pixel_x = (source_x >> 8); \ - pixel_y = (source_y >> 8); \ - \ - if (((u32)pixel_x >= (u32)width) || ((u32)pixel_y >= (u32)height)) \ - break; \ - \ - current_pixel = srcread_##type(src_ptr[pixel_x + (pixel_y * width)]); \ - bitmap_render_pixel_##type(alpha_op); \ - \ - source_x += dx; \ - source_y += dy; \ - dest_ptr++; \ - } - -#define render_scanline_vram_setup_mode3() u16 *src_ptr = (u16 *)VRAM - -#define render_scanline_vram_setup_mode5() \ - u16 *src_ptr = (u16 *)VRAM; \ - if (read_ioreg(REG_ADDR_DISPCNT) & 0x10) \ - src_ptr = (u16 *)(VRAM + 0xA000); - -#define render_scanline_vram_setup_mode4() \ - u16 *palette = PLTT; \ - u8 *src_ptr = VRAM; \ - if (read_ioreg(REG_ADDR_DISPCNT) & 0x10) \ - src_ptr = VRAM + 0xA000; - -#define srcread_mode3(v) eswap16(v) -#define srcread_mode5(v) eswap16(v) -#define srcread_mode4(v) (v) - -// Build bitmap scanline rendering functions. - -#define render_scanline_bitmap_builder(type, alpha_op, width, height) \ - static void render_scanline_bitmap_##type##_##alpha_op(u32 start, u32 end, void *scanline) \ - { \ - u32 current_pixel; \ - s32 source_x, source_y; \ - s32 pixel_x, pixel_y; \ - \ - s32 dx = (s16)read_ioreg(REG_ADDR_BG2PA); \ - s32 dy = (s16)read_ioreg(REG_ADDR_BG2PC); \ - \ - u32 i; \ - \ - render_scanline_dest_##alpha_op *dest_ptr = ((render_scanline_dest_##alpha_op *)scanline) + start; \ - render_scanline_vram_setup_##type(); \ - \ - end -= start; \ - \ - source_x = affine_reference_x[0] + (start * dx); \ - source_y = affine_reference_y[0] + (start * dy); \ - \ - if (dy == 0) { \ - bitmap_render_scale(type, alpha_op, width, height); \ - } else { \ - bitmap_render_rotate(type, alpha_op, width, height); \ - } \ - } - -render_scanline_bitmap_builder(mode3, normal, DISPLAY_WIDTH, DISPLAY_HEIGHT); -render_scanline_bitmap_builder(mode4, normal, DISPLAY_WIDTH, DISPLAY_WIDTH); -render_scanline_bitmap_builder(mode5, normal, 160, 128); - -// Fill in the renderers for a layer based on the mode type, - -#define tile_layer_render_functions(type) \ - { \ - render_scanline_##type##_base_normal, render_scanline_##type##_transparent_normal, render_scanline_##type##_base_alpha, \ - render_scanline_##type##_transparent_alpha, render_scanline_##type##_base_color16, \ - render_scanline_##type##_transparent_color16, render_scanline_##type##_base_color32, \ - render_scanline_##type##_transparent_color32 \ - } - -// Use if a layer is unsupported for that mode. - -#define tile_layer_render_null() \ - { \ - NULL, NULL, NULL, NULL \ - } - -#define bitmap_layer_render_functions(type) \ - { \ - render_scanline_bitmap_##type##_normal \ - } - -// Structs containing functions to render the layers for each mode, for -// each render type. -static const tile_layer_render_struct tile_mode_renderers[3][4] - = { { tile_layer_render_functions(text), tile_layer_render_functions(text), tile_layer_render_functions(text), - tile_layer_render_functions(text) }, - { tile_layer_render_functions(text), tile_layer_render_functions(text), tile_layer_render_functions(affine), - tile_layer_render_functions(text) }, - { tile_layer_render_functions(text), tile_layer_render_functions(text), tile_layer_render_functions(affine), - tile_layer_render_functions(affine) } }; - -static const bitmap_layer_render_struct bitmap_mode_renderers[3] - = { bitmap_layer_render_functions(mode3), bitmap_layer_render_functions(mode4), bitmap_layer_render_functions(mode5) }; - -#define render_scanline_layer_functions_tile() const tile_layer_render_struct *layer_renderers = tile_mode_renderers[dispcnt & 0x07] - -#define render_scanline_layer_functions_bitmap() \ - const bitmap_layer_render_struct *layer_renderers = bitmap_mode_renderers + ((dispcnt & 0x07) - 3) - -// Adjust a flipped obj's starting position - -#define obj_tile_offset_noflip(color_depth) - -#define obj_tile_offset_flip(color_depth) +(tile_size_##color_depth * ((obj_width - 8) / 8)) - -// Adjust the obj's starting point if it goes too far off the left edge of -// the screen. - -#define obj_tile_right_offset_noflip(color_depth) tile_ptr += (partial_tile_offset / 8) * tile_size_##color_depth - -#define obj_tile_right_offset_flip(color_depth) tile_ptr -= (partial_tile_offset / 8) * tile_size_##color_depth - -// Get the current row offset into an obj in 1D map space - -#define obj_tile_offset_1D(color_depth, flip_op) \ - tile_ptr = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * (obj_width / 8) * tile_size_##color_depth) \ - + ((vertical_offset % 8) * tile_width_##color_depth) obj_tile_offset_##flip_op(color_depth) - -// Get the current row offset into an obj in 2D map space - -#define obj_tile_offset_2D(color_depth, flip_op) \ - tile_ptr = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * 1024) \ - + ((vertical_offset % 8) * tile_width_##color_depth) obj_tile_offset_##flip_op(color_depth) - -// Get the palette for 4bpp obj. - -#define obj_get_palette_4bpp() current_palette = oam_data->split.paletteNum << 4 - -#define obj_get_palette_8bpp() - -// Render the current row of an obj. - -#define obj_render(combine_op, color_depth, alpha_op, map_space, flip_op) \ - { \ - obj_get_palette_##color_depth(); \ - obj_tile_offset_##map_space(color_depth, flip_op); \ - \ - if (obj_x < (s32)start) { \ - dest_ptr = scanline + start; \ - pixel_run = obj_width - (start - obj_x); \ - if ((s32)pixel_run > 0) { \ - if ((obj_x + obj_width) >= end) { \ - pixel_run = end - start; \ - partial_tile_offset = start - obj_x; \ - obj_tile_right_offset_##flip_op(color_depth); \ - partial_tile_offset %= 8; \ - \ - if (partial_tile_offset) { \ - partial_tile_run = 8 - partial_tile_offset; \ - if ((s32)pixel_run < (s32)partial_tile_run) { \ - if ((s32)pixel_run > 0) { \ - partial_tile_run = pixel_run; \ - partial_tile_mid_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - continue; \ - } else { \ - pixel_run -= partial_tile_run; \ - partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - } \ - tile_run = pixel_run / 8; \ - multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ - partial_tile_run = pixel_run % 8; \ - if (partial_tile_run) { \ - partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - } else { \ - partial_tile_offset = start - obj_x; \ - obj_tile_right_offset_##flip_op(color_depth); \ - partial_tile_offset %= 8; \ - if (partial_tile_offset) { \ - partial_tile_run = 8 - partial_tile_offset; \ - partial_tile_right_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - tile_run = pixel_run / 8; \ - multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - } \ - } else \ - \ - if ((obj_x + obj_width) >= end) { \ - pixel_run = end - obj_x; \ - if ((s32)pixel_run > 0) { \ - dest_ptr = scanline + obj_x; \ - tile_run = pixel_run / 8; \ - multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ - partial_tile_run = pixel_run % 8; \ - if (partial_tile_run) { \ - partial_tile_left_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - } \ - } else { \ - dest_ptr = scanline + obj_x; \ - tile_run = obj_width / 8; \ - multiple_tile_obj(combine_op, color_depth, alpha_op, flip_op); \ - } \ - } - -#define obj_scale_offset_1D(color_depth) \ - tile_ptr = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * (max_x / 8) * tile_size_##color_depth) \ - + ((vertical_offset % 8) * tile_width_##color_depth) - -// Get the current row offset into an obj in 2D map space - -#define obj_scale_offset_2D(color_depth) \ - tile_ptr \ - = tile_base + (oam_data->split.tileNum * 32) + ((vertical_offset / 8) * 1024) + ((vertical_offset % 8) * tile_width_##color_depth) - -#define obj_render_scale_pixel_4bpp(combine_op, alpha_op) \ - current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03)]; \ - if (tile_x & 0x01) \ - current_pixel >>= 4; \ - else \ - current_pixel &= 0x0F; \ - \ - tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) - -#define obj_render_scale_pixel_8bpp(combine_op, alpha_op) \ - current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07)]; \ - tile_8bpp_draw_##combine_op(0, none, 0, alpha_op); - -#define obj_render_scale(combine_op, color_depth, alpha_op, map_space) \ - { \ - u32 vertical_offset; \ - source_y += (y_delta * dmy); \ - vertical_offset = (source_y >> 8); \ - if ((u32)vertical_offset < (u32)max_y) { \ - obj_scale_offset_##map_space(color_depth); \ - source_x += (y_delta * dmx) - (middle_x * dx); \ - \ - for (i = 0; i < obj_width; i++) { \ - tile_x = (source_x >> 8); \ - \ - if ((u32)tile_x < (u32)max_x) \ - break; \ - \ - source_x += dx; \ - advance_dest_ptr_##combine_op(1); \ - } \ - \ - for (; i < obj_width; i++) { \ - tile_x = (source_x >> 8); \ - \ - if ((u32)tile_x >= (u32)max_x) \ - break; \ - \ - tile_map_offset = (tile_x >> 3) * tile_size_##color_depth; \ - obj_render_scale_pixel_##color_depth(combine_op, alpha_op); \ - \ - source_x += dx; \ - advance_dest_ptr_##combine_op(1); \ - } \ - } \ - } - -#define obj_rotate_offset_1D(color_depth) obj_tile_pitch = (max_x / 8) * tile_size_##color_depth - -#define obj_rotate_offset_2D(color_depth) obj_tile_pitch = 1024 - -#define obj_render_rotate_pixel_4bpp(combine_op, alpha_op) \ - current_pixel = tile_ptr[tile_map_offset + ((tile_x >> 1) & 0x03) + ((tile_y & 0x07) * obj_pitch)]; \ - if (tile_x & 0x01) \ - current_pixel >>= 4; \ - else \ - current_pixel &= 0x0F; \ - \ - tile_4bpp_draw_##combine_op(0, none, 0, alpha_op) - -#define obj_render_rotate_pixel_8bpp(combine_op, alpha_op) \ - current_pixel = tile_ptr[tile_map_offset + (tile_x & 0x07) + ((tile_y & 0x07) * obj_pitch)]; \ - \ - tile_8bpp_draw_##combine_op(0, none, 0, alpha_op) - -#define obj_render_rotate(combine_op, color_depth, alpha_op, map_space) \ - { \ - tile_ptr = tile_base + (oam_data->split.tileNum * 32); \ - obj_rotate_offset_##map_space(color_depth); \ - \ - source_x += (y_delta * dmx) - (middle_x * dx); \ - source_y += (y_delta * dmy) - (middle_x * dy); \ - \ - for (i = 0; i < obj_width; i++) { \ - tile_x = (source_x >> 8); \ - tile_y = (source_y >> 8); \ - \ - if (((u32)tile_x < (u32)max_x) && ((u32)tile_y < (u32)max_y)) \ - break; \ - \ - source_x += dx; \ - source_y += dy; \ - advance_dest_ptr_##combine_op(1); \ - } \ - \ - for (; i < obj_width; i++) { \ - tile_x = (source_x >> 8); \ - tile_y = (source_y >> 8); \ - \ - if (((u32)tile_x >= (u32)max_x) || ((u32)tile_y >= (u32)max_y)) \ - break; \ - \ - tile_map_offset = ((tile_x >> 3) * tile_size_##color_depth) + ((tile_y >> 3) * obj_tile_pitch); \ - obj_render_rotate_pixel_##color_depth(combine_op, alpha_op); \ - \ - source_x += dx; \ - source_y += dy; \ - advance_dest_ptr_##combine_op(1); \ - } \ - } - -// Render the current row of an affine transformed OBJ. - -#define obj_render_affine(combine_op, color_depth, alpha_op, map_space) \ - { \ - u8 matrix_num = oam_data->split.matrixNum * 4; \ - OamData *oam1 = &((OamData *)OAM)[matrix_num]; \ - OamData *oam2 = &((OamData *)OAM)[matrix_num + 1]; \ - OamData *oam3 = &((OamData *)OAM)[matrix_num + 2]; \ - OamData *oam4 = &((OamData *)OAM)[matrix_num + 3]; \ - s32 dx = (s16)oam1->all.affineParam; \ - s32 dmx = (s16)oam2->all.affineParam; \ - s32 dy = (s16)oam3->all.affineParam; \ - s32 dmy = (s16)oam4->all.affineParam; \ - s32 source_x, source_y; \ - s32 tile_x, tile_y; \ - u32 tile_map_offset; \ - s32 middle_x; \ - s32 middle_y; \ - s32 max_x = obj_width; \ - s32 max_y = obj_height; \ - s32 y_delta; \ - u32 obj_pitch = tile_width_##color_depth; \ - u32 obj_tile_pitch; \ - \ - middle_x = (obj_width / 2); \ - middle_y = (obj_height / 2); \ - \ - source_x = (middle_x << 8); \ - source_y = (middle_y << 8); \ - \ - if ((oam_data->split.affineMode >> 1) & 1) { \ - obj_width *= 2; \ - obj_height *= 2; \ - middle_x *= 2; \ - middle_y *= 2; \ - } \ - \ - if ((s32)obj_x < (s32)start) { \ - u32 x_delta = start - obj_x; \ - middle_x -= x_delta; \ - obj_width -= x_delta; \ - obj_x = start; \ - \ - if ((s32)obj_width <= 0) \ - continue; \ - } \ - \ - if ((s32)(obj_x + obj_width) >= (s32)end) { \ - obj_width = end - obj_x; \ - \ - if ((s32)obj_width <= 0) \ - continue; \ - } \ - dest_ptr = scanline + obj_x; \ - \ - y_delta = vcount - (obj_y + middle_y); \ - \ - obj_get_palette_##color_depth(); \ - \ - if (dy == 0) { \ - obj_render_scale(combine_op, color_depth, alpha_op, map_space); \ - } else { \ - obj_render_rotate(combine_op, color_depth, alpha_op, map_space); \ - } \ - } - -static const u32 obj_width_table[] = { 8, 16, 32, 64, 16, 32, 32, 64, 8, 8, 16, 32 }; -static const u32 obj_height_table[] = { 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64 }; - -static const u8 obj_dim_table[3][4][2] = { { { 8, 8 }, { 16, 16 }, { 32, 32 }, { 64, 64 } }, - { { 16, 8 }, { 32, 8 }, { 32, 16 }, { 64, 32 } }, - { { 8, 16 }, { 8, 32 }, { 16, 32 }, { 32, 64 } } }; - -static u8 obj_priority_list[5][DISPLAY_HEIGHT][128]; -static u8 obj_priority_count[5][DISPLAY_HEIGHT]; -static u8 obj_alpha_count[DISPLAY_HEIGHT]; - -// Build obj rendering functions - -#define render_scanline_obj_extra_variables_normal(bg_type) u16 *palette = PLTT + 256 - -#define render_scanline_obj_extra_variables_color() u32 pixel_combine = color_combine_mask(4) | (1 << 8) - -#define render_scanline_obj_extra_variables_alpha_obj(map_space) \ - render_scanline_obj_extra_variables_color(); \ - u32 dest; \ - if ((pixel_combine & 0x00000200) == 0) { \ - render_scanline_obj_color32_##map_space(priority, start, end, scanline); \ - return; \ - } - -#define render_scanline_obj_extra_variables_color16(map_space) render_scanline_obj_extra_variables_color() - -#define render_scanline_obj_extra_variables_color32(map_space) render_scanline_obj_extra_variables_color() - -#define render_scanline_obj_extra_variables_partial_alpha(map_space) \ - render_scanline_obj_extra_variables_color(); \ - u32 base_pixel_combine = pixel_combine; \ - u32 dest - -#define render_scanline_obj_extra_variables_copy(type) \ - u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); \ - u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); \ - u32 obj_enable = WIN_GET_LOWER(read_ioreg(REG_ADDR_WINOUT)); \ - render_scanline_layer_functions_##type(); \ - u32 copy_start, copy_end; \ - u16 copy_buffer[DISPLAY_WIDTH]; \ - u16 *copy_ptr - -#define render_scanline_obj_extra_variables_copy_tile(map_space) render_scanline_obj_extra_variables_copy(tile) - -#define render_scanline_obj_extra_variables_copy_bitmap(map_space) render_scanline_obj_extra_variables_copy(bitmap) - -#define render_scanline_obj_main(combine_op, alpha_op, map_space) \ - if (oam_data->split.affineMode & 1) { \ - if (oam_data->split.bpp & 1) { \ - obj_render_affine(combine_op, 8bpp, alpha_op, map_space); \ - } else { \ - obj_render_affine(combine_op, 4bpp, alpha_op, map_space); \ - } \ - } else { \ - vertical_offset = vcount - obj_y; \ - \ - if ((oam_data->split.matrixNum >> 4) & 1) \ - vertical_offset = obj_height - vertical_offset - 1; \ - \ - switch ((oam_data->split.bpp << 1) | ((oam_data->split.matrixNum >> 3) & 1)) { \ - case 0x0: \ - obj_render(combine_op, 4bpp, alpha_op, map_space, noflip); \ - break; \ - \ - case 0x1: \ - obj_render(combine_op, 4bpp, alpha_op, map_space, flip); \ - break; \ - \ - case 0x2: \ - obj_render(combine_op, 8bpp, alpha_op, map_space, noflip); \ - break; \ - \ - case 0x3: \ - obj_render(combine_op, 8bpp, alpha_op, map_space, flip); \ - break; \ - } \ - } - -#define render_scanline_obj_no_partial_alpha(combine_op, alpha_op, map_space) render_scanline_obj_main(combine_op, alpha_op, map_space) - -#define render_scanline_obj_partial_alpha(combine_op, alpha_op, map_space) \ - if (oam_data->split.objMode) { \ - pixel_combine = 0x00000300; \ - render_scanline_obj_main(combine_op, alpha_obj, map_space); \ - } else { \ - pixel_combine = base_pixel_combine; \ - render_scanline_obj_main(combine_op, color32, map_space); \ - } - -#define render_scanline_obj_prologue_transparent(alpha_op) - -#define render_scanline_obj_prologue_copy_body(type) \ - copy_start = obj_x; \ - copy_end = obj_x + obj_width; \ - if (oam_data->split.affineMode & 2) \ - copy_end += obj_width; \ - \ - if (copy_start < start) \ - copy_start = start; \ - if (copy_end > end) \ - copy_end = end; \ - \ - if ((copy_start < end) && (copy_end > start)) { \ - render_scanline_conditional_##type(copy_start, copy_end, copy_buffer, obj_enable, dispcnt, bldcnt, layer_renderers); \ - copy_ptr = copy_buffer + copy_start; \ - } else { \ - continue; \ - } - -#define render_scanline_obj_prologue_copy_tile() render_scanline_obj_prologue_copy_body(tile) - -#define render_scanline_obj_prologue_copy_bitmap() render_scanline_obj_prologue_copy_body(bitmap) - -#define render_scanline_obj_prologue_copy(alpha_op) render_scanline_obj_prologue_##alpha_op() - -#define render_scanline_obj_builder(combine_op, alpha_op, map_space, partial_alpha_op) \ - static void render_scanline_obj_##alpha_op##_##map_space(u32 priority, u32 start, u32 end, render_scanline_dest_##alpha_op *scanline) \ - { \ - render_scanline_obj_extra_variables_##alpha_op(map_space); \ - u32 obj_num, i; \ - s32 obj_x, obj_y; \ - u32 obj_size; \ - u32 obj_width, obj_height; \ - s32 vcount = read_ioreg(REG_ADDR_VCOUNT); \ - u32 tile_run; \ - u32 current_pixels; \ - u32 current_pixel; \ - u32 current_palette; \ - u32 vertical_offset; \ - u32 partial_tile_run, partial_tile_offset; \ - u32 pixel_run; \ - OamData *oam_data; \ - render_scanline_dest_##alpha_op *dest_ptr; \ - u8 *tile_base = VRAM + 0x10000; \ - u8 *tile_ptr; \ - u32 obj_count = obj_priority_count[priority][vcount]; \ - u8 *obj_list = obj_priority_list[priority][vcount]; \ - \ - for (obj_num = 0; obj_num < obj_count; obj_num++) { \ - oam_data = (OamData *)&OAM[obj_list[obj_num] * OAM_DATA_SIZE_AFFINE]; \ - obj_size = (oam_data->split.shape << 2) | oam_data->split.size; \ - \ - obj_x = oam_data->split.x; \ - obj_width = obj_width_table[obj_size]; \ - \ - render_scanline_obj_prologue_##combine_op(alpha_op); \ - \ - obj_y = oam_data->split.y; \ - \ - if (!EXTENDED_OAM) { \ - if (obj_x > DISPLAY_WIDTH) \ - obj_x -= 512; \ - if (obj_y > DISPLAY_HEIGHT) \ - obj_y -= 256; \ - } \ - \ - obj_height = obj_height_table[obj_size]; \ - render_scanline_obj_##partial_alpha_op(combine_op, alpha_op, map_space); \ - } \ - } - -render_scanline_obj_builder(transparent, normal, 1D, no_partial_alpha); -render_scanline_obj_builder(transparent, normal, 2D, no_partial_alpha); -render_scanline_obj_builder(transparent, color16, 1D, no_partial_alpha); -render_scanline_obj_builder(transparent, color16, 2D, no_partial_alpha); -render_scanline_obj_builder(transparent, color32, 1D, no_partial_alpha); -render_scanline_obj_builder(transparent, color32, 2D, no_partial_alpha); -render_scanline_obj_builder(transparent, alpha_obj, 1D, no_partial_alpha); -render_scanline_obj_builder(transparent, alpha_obj, 2D, no_partial_alpha); -render_scanline_obj_builder(transparent, partial_alpha, 1D, partial_alpha); -render_scanline_obj_builder(transparent, partial_alpha, 2D, partial_alpha); -render_scanline_obj_builder(copy, copy_tile, 1D, no_partial_alpha); -render_scanline_obj_builder(copy, copy_tile, 2D, no_partial_alpha); -render_scanline_obj_builder(copy, copy_bitmap, 1D, no_partial_alpha); -render_scanline_obj_builder(copy, copy_bitmap, 2D, no_partial_alpha); - -#define OBJ_MOD_NORMAL 0 -#define OBJ_MOD_SEMITRAN 1 -#define OBJ_MOD_WINDOW 2 -#define OBJ_MOD_INVALID 3 - -// Goes through the object list in the OAM (from #127 to #0) and adds objects -// into a sorted list by priority for the current row. -// Invisible objects are discarded. -static void order_obj(u32 video_mode) -{ - s32 obj_num; - u32 row; - - memset(obj_priority_count, 0, sizeof(obj_priority_count)); - memset(obj_alpha_count, 0, sizeof(obj_alpha_count)); - - for (obj_num = 127; obj_num >= 0; obj_num--) { - OamData *oam_data = (OamData *)&OAM[obj_num * OAM_DATA_SIZE_AFFINE]; - // Bit 9 disables regular sprites. Used as double bit for affine ones. - bool visible = oam_data->split.affineMode != 2; - if (visible) { - u16 obj_shape = oam_data->split.shape; - u32 obj_mode = oam_data->split.objMode; - - // Prohibited shape and mode - bool invalid = (obj_shape == 0x3) || (obj_mode == OBJ_MOD_INVALID); - if (!invalid) { - u32 obj_priority = oam_data->split.priority; - - if (((video_mode < 3) || (oam_data->split.tileNum >= 512))) { - // Calculate object size (from size and shape attr bits) - u16 obj_size = oam_data->split.size; - s32 obj_height = obj_dim_table[obj_shape][obj_size][1]; - s32 obj_width = obj_dim_table[obj_shape][obj_size][0]; - s32 obj_y = oam_data->split.y; - -#if !EXTENDED_OAM - if (obj_y > DISPLAY_HEIGHT) - obj_y -= 512; -#endif - - // Double size for affine sprites with double bit set - if ((oam_data->split.affineMode >> 1) & 1) { - obj_height *= 2; - obj_width *= 2; - } - - if (((obj_y + obj_height) > 0) && (obj_y < DISPLAY_HEIGHT)) { - s32 obj_x = oam_data->split.x; -#if !EXTENDED_OAM - if (obj_x > DISPLAY_WIDTH) - obj_x -= 512; -#endif - - if (((obj_x + obj_width) > 0) && (obj_x < DISPLAY_WIDTH)) { - // Clip Y coord and height to the 0..159 interval - u32 starty = MAX(obj_y, 0); - u32 endy = MIN(obj_y + obj_height, DISPLAY_HEIGHT); - - switch (obj_mode) { - case OBJ_MOD_SEMITRAN: - for (row = starty; row < endy; row++) { - u32 cur_cnt = obj_priority_count[obj_priority][row]; - obj_priority_list[obj_priority][row][cur_cnt] = obj_num; - obj_priority_count[obj_priority][row] = cur_cnt + 1; - // Mark the row as having semi-transparent objects - obj_alpha_count[row] = 1; - } - break; - case OBJ_MOD_WINDOW: - obj_priority = 4; - /* fallthrough */ - case OBJ_MOD_NORMAL: - // Add the object to the list. - for (row = starty; row < endy; row++) { - u32 cur_cnt = obj_priority_count[obj_priority][row]; - obj_priority_list[obj_priority][row][cur_cnt] = obj_num; - obj_priority_count[obj_priority][row] = cur_cnt + 1; - } - break; - }; - } - } - } - } - } - } -} - -u32 layer_order[16]; -u32 layer_count; - -// Sorts active BG/OBJ layers and generates an ordered list of layers. -// Things are drawn back to front, so lowest priority goes first. -static void order_layers(u32 layer_flags, u32 vcnt) -{ - bool obj_enabled = (layer_flags & 0x10); - s32 priority; - - layer_count = 0; - - for (priority = 3; priority >= 0; priority--) { - bool anyobj = obj_priority_count[priority][vcnt] > 0; - s32 lnum; - - for (lnum = 3; lnum >= 0; lnum--) { - if (((layer_flags >> lnum) & 1) && ((read_ioreg(REG_ADDR_BGxCNT(lnum)) & 0x03) == priority)) { - layer_order[layer_count++] = lnum; - } - } - - if (obj_enabled && anyobj) - layer_order[layer_count++] = priority | 0x04; - } -} - -#define fill_line(_start, _end) \ - u32 i; \ - \ - for (i = _start; i < _end; i++) \ - dest_ptr[i] = color; - -#define fill_line_color_normal() color = PLTT[color] - -#define fill_line_color_alpha() - -#define fill_line_color_color16() - -#define fill_line_color_color32() - -#define fill_line_builder(type) \ - static void fill_line_##type(u16 color, render_scanline_dest_##type *dest_ptr, u32 start, u32 end) \ - { \ - fill_line_color_##type(); \ - fill_line(start, end); \ - } - -fill_line_builder(normal); -fill_line_builder(alpha); -fill_line_builder(color16); -fill_line_builder(color32); - -// Blending is performed by separating an RGB value into 0G0R0B (32 bit) -// Since blending factors are at most 16, mult/add operations do not overflow -// to the neighbouring color and can be performed much faster than separatedly - -// Here follow the mask value to separate/expand the color to 32 bit, -// the mask to detect overflows in the blend operation and - -#define BLND_MSK (SATR_MSK | SATG_MSK | SATB_MSK) - -#define OVFG_MSK 0x04000000 -#define OVFR_MSK 0x00008000 -#define OVFB_MSK 0x00000020 -#define SATG_MSK 0x03E00000 -#define SATR_MSK 0x00007C00 -#define SATB_MSK 0x0000001F - -// Alpha blend two pixels (pixel_top and pixel_bottom). - -#define blend_pixel() \ - pixel_bottom = PLTT[(pixel_pair >> 16) & 0x1FF]; \ - pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & BLND_MSK; \ - pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4 - -// Alpha blend two pixels, allowing for saturation (individual channels > 31). -// The operation is optimized towards saturation not occuring. - -#define blend_saturate_pixel() \ - pixel_bottom = PLTT[(pixel_pair >> 16) & 0x1FF]; \ - pixel_bottom = (pixel_bottom | (pixel_bottom << 16)) & BLND_MSK; \ - pixel_top = ((pixel_top * blend_a) + (pixel_bottom * blend_b)) >> 4; \ - if (pixel_top & (OVFR_MSK | OVFG_MSK | OVFB_MSK)) { \ - if (pixel_top & OVFG_MSK) \ - pixel_top |= SATG_MSK; \ - \ - if (pixel_top & OVFR_MSK) \ - pixel_top |= SATR_MSK; \ - \ - if (pixel_top & OVFB_MSK) \ - pixel_top |= SATB_MSK; \ - } - -#define brighten_pixel() pixel_top = upper + ((pixel_top * blend) >> 4); - -#define darken_pixel() pixel_top = (pixel_top * blend) >> 4; - -#define effect_condition_alpha ((pixel_pair & 0x04000200) == 0x04000200) - -#define effect_condition_fade(pixel_source) ((pixel_source & 0x00000200) == 0x00000200) - -#define expand_pixel_no_dest(expand_type, pixel_source) \ - pixel_top = (pixel_top | (pixel_top << 16)) & BLND_MSK; \ - expand_type##_pixel(); \ - pixel_top &= BLND_MSK; \ - pixel_top = (pixel_top >> 16) | pixel_top - -#define expand_pixel(expand_type, pixel_source) \ - pixel_top = PLTT[pixel_source & 0x1FF]; \ - expand_pixel_no_dest(expand_type, pixel_source); \ - *screen_dest_ptr = pixel_top - -#define expand_loop(expand_type, effect_condition, pixel_source) \ - screen_src_ptr += start; \ - screen_dest_ptr += start; \ - \ - end -= start; \ - \ - for (i = 0; i < end; i++) { \ - pixel_source = *screen_src_ptr; \ - if (effect_condition) { \ - expand_pixel(expand_type, pixel_source); \ - } else { \ - *screen_dest_ptr = PLTT[pixel_source & 0x1FF]; \ - } \ - \ - screen_src_ptr++; \ - screen_dest_ptr++; \ - } - -#define expand_loop_partial_alpha(alpha_expand, expand_type) \ - screen_src_ptr += start; \ - screen_dest_ptr += start; \ - \ - end -= start; \ - \ - for (i = 0; i < end; i++) { \ - pixel_pair = *screen_src_ptr; \ - if (effect_condition_fade(pixel_pair)) { \ - if (effect_condition_alpha) { \ - expand_pixel(alpha_expand, pixel_pair); \ - } else { \ - expand_pixel(expand_type, pixel_pair); \ - } \ - } else { \ - *screen_dest_ptr = PLTT[pixel_pair & 0x1FF]; \ - } \ - \ - screen_src_ptr++; \ - screen_dest_ptr++; \ - } - -#define expand_partial_alpha(expand_type) \ - if ((blend_a + blend_b) > 16) { \ - expand_loop_partial_alpha(blend_saturate, expand_type); \ - } else { \ - expand_loop_partial_alpha(blend, expand_type); \ - } - -// Blend top two pixels of scanline with each other. - -#define expand_normal(screen_ptr, start, end) - -void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end); - -#ifndef ARM_ARCH_BLENDING_OPTS - -void expand_blend(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) -{ - u32 pixel_pair; - u32 pixel_top, pixel_bottom; - u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); - u32 blend_a = bldalpha & 0x1F; - u32 blend_b = (bldalpha >> 8) & 0x1F; - u32 i; - - if (blend_a > 16) - blend_a = 16; - - if (blend_b > 16) - blend_b = 16; - - // The individual colors can saturate over 31, this should be taken - // care of in an alternate pass as it incurs a huge additional speedhit. - if ((blend_a + blend_b) > 16) { - expand_loop(blend_saturate, effect_condition_alpha, pixel_pair); - } else { - expand_loop(blend, effect_condition_alpha, pixel_pair); - } -} - -#endif - -// Blend scanline with white. - -static void expand_darken(u16 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) -{ - u32 pixel_top; - s32 blend = 16 - (read_ioreg(REG_ADDR_BLDY) & 0x1F); - u32 i; - - if (blend < 0) - blend = 0; - - expand_loop(darken, effect_condition_fade(pixel_top), pixel_top); -} - -// Blend scanline with black. - -static void expand_brighten(u16 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) -{ - u32 pixel_top; - u32 blend = read_ioreg(REG_ADDR_BLDY) & 0x1F; - u32 upper; - u32 i; - - if (blend > 16) - blend = 16; - - upper = ((BLND_MSK * blend) >> 4) & BLND_MSK; - blend = 16 - blend; - - expand_loop(brighten, effect_condition_fade(pixel_top), pixel_top); -} - -// Expand scanline such that if both top and bottom pass it's alpha, -// if only top passes it's as specified, and if neither pass it's normal. - -static void expand_darken_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) -{ - s32 blend = 16 - (read_ioreg(REG_ADDR_BLDY) & 0x1F); - u32 pixel_pair; - u32 pixel_top, pixel_bottom; - u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); - u32 blend_a = bldalpha & 0x1F; - u32 blend_b = (bldalpha >> 8) & 0x1F; - u32 i; - - if (blend < 0) - blend = 0; - - if (blend_a > 16) - blend_a = 16; - - if (blend_b > 16) - blend_b = 16; - - expand_partial_alpha(darken); -} - -static void expand_brighten_partial_alpha(u32 *screen_src_ptr, u16 *screen_dest_ptr, u32 start, u32 end) -{ - s32 blend = read_ioreg(REG_ADDR_BLDY) & 0x1F; - u32 pixel_pair; - u32 pixel_top, pixel_bottom; - u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); - u32 blend_a = bldalpha & 0x1F; - u32 blend_b = (bldalpha >> 8) & 0x1F; - u32 upper; - u32 i; - - if (blend > 16) - blend = 16; - - upper = ((BLND_MSK * blend) >> 4) & BLND_MSK; - blend = 16 - blend; - - if (blend_a > 16) - blend_a = 16; - - if (blend_b > 16) - blend_b = 16; - - expand_partial_alpha(brighten); -} - -// Render an OBJ layer from start to end, depending on the type (1D or 2D) -// stored in dispcnt. - -#define render_obj_layer(type, dest, _start, _end) \ - current_layer &= ~0x04; \ - if (dispcnt & 0x40) \ - render_scanline_obj_##type##_1D(current_layer, _start, _end, dest); \ - else \ - render_scanline_obj_##type##_2D(current_layer, _start, _end, dest) - -// Render a target all the way with the background color as taken from the -// palette. - -#define fill_line_bg(type, dest, _start, _end) fill_line_##type(0, dest, _start, _end) - -// Render all layers as they appear in the layer order. - -#define render_layers(tile_alpha, obj_alpha, dest) \ - { \ - current_layer = layer_order[0]; \ - if (current_layer & 0x04) { \ - /* If the first one is OBJ render the background then render it. */ \ - fill_line_bg(tile_alpha, dest, 0, DISPLAY_WIDTH); \ - render_obj_layer(obj_alpha, dest, 0, DISPLAY_WIDTH); \ - } else { \ - /* Otherwise render a base layer. */ \ - layer_renderers[current_layer].tile_alpha##_render_base(current_layer, 0, DISPLAY_WIDTH, dest); \ - } \ - \ - /* Render the rest of the layers. */ \ - for (layer_order_pos = 1; layer_order_pos < layer_count; layer_order_pos++) { \ - current_layer = layer_order[layer_order_pos]; \ - if (current_layer & 0x04) { \ - render_obj_layer(obj_alpha, dest, 0, DISPLAY_WIDTH); \ - } else { \ - layer_renderers[current_layer].tile_alpha##_render_transparent(current_layer, 0, DISPLAY_WIDTH, dest); \ - } \ - } \ - } - -#define render_condition_alpha \ - (((read_ioreg(REG_ADDR_BLDALPHA) & 0x1F1F) != 0x001F) && ((read_ioreg(REG_ADDR_BLDCNT) & 0x3F) != 0) \ - && ((read_ioreg(REG_ADDR_BLDCNT) & 0x3F00) != 0)) - -#define render_condition_fade (((read_ioreg(REG_ADDR_BLDY) & 0x1F) != 0) && ((read_ioreg(REG_ADDR_BLDCNT) & 0x3F) != 0)) - -#define render_layers_color_effect(renderer, layer_condition, alpha_condition, fade_condition, _start, _end) \ - { \ - if (layer_condition) { \ - if (obj_alpha_count[read_ioreg(REG_ADDR_VCOUNT)]) { \ - /* Render based on special effects mode. */ \ - u32 screen_buffer[DISPLAY_WIDTH]; \ - switch ((bldcnt >> 6) & 0x03) { \ - /* Alpha blend */ \ - case 0x01: { \ - if (alpha_condition) { \ - renderer(alpha, alpha_obj, screen_buffer); \ - expand_blend(screen_buffer, scanline, _start, _end); \ - return; \ - } \ - break; \ - } \ - \ - /* Fade to white */ \ - case 0x02: { \ - if (fade_condition) { \ - renderer(color32, partial_alpha, screen_buffer); \ - expand_brighten_partial_alpha(screen_buffer, scanline, _start, _end); \ - return; \ - } \ - break; \ - } \ - \ - /* Fade to black */ \ - case 0x03: { \ - if (fade_condition) { \ - renderer(color32, partial_alpha, screen_buffer); \ - expand_darken_partial_alpha(screen_buffer, scanline, _start, _end); \ - return; \ - } \ - break; \ - } \ - } \ - \ - renderer(color32, partial_alpha, screen_buffer); \ - expand_blend(screen_buffer, scanline, _start, _end); \ - } else { \ - /* Render based on special effects mode. */ \ - switch ((bldcnt >> 6) & 0x03) { \ - /* Alpha blend */ \ - case 0x01: { \ - if (alpha_condition) { \ - u32 screen_buffer[DISPLAY_WIDTH]; \ - renderer(alpha, alpha_obj, screen_buffer); \ - expand_blend(screen_buffer, scanline, _start, _end); \ - return; \ - } \ - break; \ - } \ - \ - /* Fade to white */ \ - case 0x02: { \ - if (fade_condition) { \ - renderer(color16, color16, scanline); \ - expand_brighten(scanline, scanline, _start, _end); \ - return; \ - } \ - break; \ - } \ - \ - /* Fade to black */ \ - case 0x03: { \ - if (fade_condition) { \ - renderer(color16, color16, scanline); \ - expand_darken(scanline, scanline, _start, _end); \ - return; \ - } \ - break; \ - } \ - } \ - \ - renderer(normal, normal, scanline); \ - expand_normal(scanline, _start, _end); \ - } \ - } else { \ - u32 pixel_top = PLTT[0]; \ - switch ((bldcnt >> 6) & 0x03) { \ - /* Fade to white */ \ - case 0x02: { \ - if (color_combine_mask_a(5)) { \ - u32 blend = read_ioreg(REG_ADDR_BLDY) & 0x1F; \ - u32 upper; \ - \ - if (blend > 16) \ - blend = 16; \ - \ - upper = ((BLND_MSK * blend) >> 4) & BLND_MSK; \ - blend = 16 - blend; \ - \ - expand_pixel_no_dest(brighten, pixel_top); \ - } \ - break; \ - } \ - \ - /* Fade to black */ \ - case 0x03: { \ - if (color_combine_mask_a(5)) { \ - s32 blend = 16 - (read_ioreg(REG_ADDR_BLDY) & 0x1F); \ - \ - if (blend < 0) \ - blend = 0; \ - \ - expand_pixel_no_dest(darken, pixel_top); \ - } \ - break; \ - } \ - } \ - fill_line_color16(pixel_top, scanline, _start, _end); \ - } \ - } - -// Renders an entire scanline from 0 to DISPLAY_WIDTH, based on current color mode. - -static void render_scanline_tile(u16 *scanline, u32 dispcnt) -{ - u32 current_layer; - u32 layer_order_pos; - u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); - render_scanline_layer_functions_tile(); - - render_layers_color_effect(render_layers, layer_count, render_condition_alpha, render_condition_fade, 0, DISPLAY_WIDTH); -} - -static void render_scanline_bitmap(u16 *scanline, u32 dispcnt) -{ - render_scanline_layer_functions_bitmap(); - u32 current_layer; - u32 layer_order_pos; - - fill_line_bg(normal, scanline, 0, DISPLAY_WIDTH); - - for (layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++) { - current_layer = layer_order[layer_order_pos]; - if (current_layer & 0x04) { - render_obj_layer(normal, scanline, 0, DISPLAY_WIDTH); - } else { - layer_renderers->normal_render(0, DISPLAY_WIDTH, scanline); - } - } -} - -// Render layers from start to end based on if they're allowed in the -// enable flags. - -#define render_layers_conditional(tile_alpha, obj_alpha, dest) \ - { \ - __label__ skip; \ - current_layer = layer_order[layer_order_pos]; \ - /* If OBJ aren't enabled skip to the first non-OBJ layer */ \ - if (!(enable_flags & 0x10)) { \ - while ((current_layer & 0x04) || !((1 << current_layer) & enable_flags)) { \ - layer_order_pos++; \ - current_layer = layer_order[layer_order_pos]; \ - \ - /* Oops, ran out of layers, render the background. */ \ - if (layer_order_pos == layer_count) { \ - fill_line_bg(tile_alpha, dest, start, end); \ - goto skip; \ - } \ - } \ - \ - /* Render the first valid layer */ \ - layer_renderers[current_layer].tile_alpha##_render_base(current_layer, start, end, dest); \ - \ - layer_order_pos++; \ - \ - /* Render the rest of the layers if active, skipping OBJ ones. */ \ - for (; layer_order_pos < layer_count; layer_order_pos++) { \ - current_layer = layer_order[layer_order_pos]; \ - if (!(current_layer & 0x04) && ((1 << current_layer) & enable_flags)) { \ - layer_renderers[current_layer].tile_alpha##_render_transparent(current_layer, start, end, dest); \ - } \ - } \ - } else { \ - /* Find the first active layer, skip all of the inactive ones */ \ - while (!((current_layer & 0x04) || ((1 << current_layer) & enable_flags))) { \ - layer_order_pos++; \ - current_layer = layer_order[layer_order_pos]; \ - \ - /* Oops, ran out of layers, render the background. */ \ - if (layer_order_pos == layer_count) { \ - fill_line_bg(tile_alpha, dest, start, end); \ - goto skip; \ - } \ - } \ - \ - if (current_layer & 0x04) { \ - /* If the first one is OBJ render the background then render it. */ \ - fill_line_bg(tile_alpha, dest, start, end); \ - render_obj_layer(obj_alpha, dest, start, end); \ - } else { \ - /* Otherwise render a base layer. */ \ - layer_renderers[current_layer].tile_alpha##_render_base(current_layer, start, end, dest); \ - } \ - \ - layer_order_pos++; \ - \ - /* Render the rest of the layers. */ \ - for (; layer_order_pos < layer_count; layer_order_pos++) { \ - current_layer = layer_order[layer_order_pos]; \ - if (current_layer & 0x04) { \ - render_obj_layer(obj_alpha, dest, start, end); \ - } else { \ - if (enable_flags & (1 << current_layer)) { \ - layer_renderers[current_layer].tile_alpha##_render_transparent(current_layer, start, end, dest); \ - } \ - } \ - } \ - } \ - \ - skip:; \ - } - -// Render all of the BG and OBJ in a tiled scanline from start to end ONLY if -// enable_flag allows that layer/OBJ. Also conditionally render color effects. - -static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, - const tile_layer_render_struct *layer_renderers) -{ - u32 current_layer; - u32 layer_order_pos = 0; - - render_layers_color_effect(render_layers_conditional, (layer_count && (enable_flags & 0x1F)), - ((enable_flags & 0x20) && render_condition_alpha), ((enable_flags & 0x20) && render_condition_fade), start, - end); -} - -// Render the BG and OBJ in a bitmap scanline from start to end ONLY if -// enable_flag allows that layer/OBJ. Also conditionally render color effects. - -static void render_scanline_conditional_bitmap(u32 start, u32 end, u16 *scanline, u32 enable_flags, u32 dispcnt, u32 bldcnt, - const bitmap_layer_render_struct *layer_renderers) -{ - u32 current_layer; - u32 layer_order_pos; - - fill_line_bg(normal, scanline, start, end); - - for (layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++) { - current_layer = layer_order[layer_order_pos]; - if (current_layer & 0x04) { - if (enable_flags & 0x10) { - render_obj_layer(normal, scanline, start, end); - } - } else { - if (enable_flags & 0x04) - layer_renderers->normal_render(start, end, scanline); - } - } -} - -#define window_x_coords(window_number) \ - window_##window_number##_x1 = WIN_GET_LOWER(read_ioreg(REG_ADDR_WIN##window_number##H)); \ - window_##window_number##_x2 = WIN_GET_HIGHER(read_ioreg(REG_ADDR_WIN##window_number##H)); \ - window_##window_number##_enable = (winin >> (window_number * 8)) & 0x3F; \ - \ - if (window_##window_number##_x1 > DISPLAY_WIDTH) \ - window_##window_number##_x1 = DISPLAY_WIDTH; \ - \ - if (window_##window_number##_x2 > DISPLAY_WIDTH) \ - window_##window_number##_x2 = DISPLAY_WIDTH - -#define window_coords(window_number) \ - u32 window_##window_number##_x1, window_##window_number##_x2; \ - u32 window_##window_number##_y1, window_##window_number##_y2; \ - u32 window_##window_number##_enable = 0; \ - window_##window_number##_y1 = WIN_GET_LOWER(read_ioreg(REG_ADDR_WIN##window_number##V)); \ - window_##window_number##_y2 = WIN_GET_HIGHER(read_ioreg(REG_ADDR_WIN##window_number##V)); \ - \ - if (window_##window_number##_y1 > window_##window_number##_y2) { \ - if ((((vcount <= window_##window_number##_y2) || (vcount > window_##window_number##_y1)) \ - || (window_##window_number##_y2 > (DISPLAY_HEIGHT + 67))) \ - && (window_##window_number##_y1 <= (DISPLAY_HEIGHT + 67))) { \ - window_x_coords(window_number); \ - } else { \ - window_##window_number##_x1 = DISPLAY_WIDTH; \ - window_##window_number##_x2 = DISPLAY_WIDTH; \ - } \ - } else { \ - if ((((vcount >= window_##window_number##_y1) && (vcount < window_##window_number##_y2)) \ - || (window_##window_number##_y2 > (DISPLAY_HEIGHT + 67))) \ - && (window_##window_number##_y1 <= (DISPLAY_HEIGHT + 67))) { \ - window_x_coords(window_number); \ - } else { \ - window_##window_number##_x1 = DISPLAY_WIDTH; \ - window_##window_number##_x2 = DISPLAY_WIDTH; \ - } \ - } - -#define render_window_segment(type, start, end, window_type) \ - if (start != end) { \ - render_scanline_conditional_##type(start, end, scanline, window_##window_type##_enable, dispcnt, bldcnt, layer_renderers); \ - } - -#define render_window_segment_unequal(type, start, end, window_type) \ - render_scanline_conditional_##type(start, end, scanline, window_##window_type##_enable, dispcnt, bldcnt, layer_renderers) - -#define render_window_segment_clip(type, clip_start, clip_end, start, end, window_type) \ - { \ - if (start != end) { \ - if (start < clip_start) { \ - if (end > clip_start) { \ - if (end > clip_end) { \ - render_window_segment_unequal(type, clip_start, clip_end, window_type); \ - } else { \ - render_window_segment_unequal(type, clip_start, end, window_type); \ - } \ - } \ - } else \ - \ - if (end > clip_end) { \ - if (start < clip_end) \ - render_window_segment_unequal(type, start, clip_end, window_type); \ - } else { \ - render_window_segment_unequal(type, start, end, window_type); \ - } \ - } \ - } - -#define render_window_clip_1(type, start, end) \ - if (window_1_x1 != DISPLAY_WIDTH) { \ - if (window_1_x1 > window_1_x2) { \ - render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \ - render_window_segment_clip(type, start, end, window_1_x2, window_1_x1, out); \ - render_window_segment_clip(type, start, end, window_1_x1, DISPLAY_WIDTH, 1); \ - } else { \ - render_window_segment_clip(type, start, end, 0, window_1_x1, out); \ - render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, 1); \ - render_window_segment_clip(type, start, end, window_1_x2, DISPLAY_WIDTH, out); \ - } \ - } else { \ - render_window_segment(type, start, end, out); \ - } - -#define render_window_clip_obj(type, start, end) \ - ; \ - render_window_segment(type, start, end, out); \ - if (dispcnt & 0x40) \ - render_scanline_obj_copy_##type##_1D(4, start, end, scanline); \ - else \ - render_scanline_obj_copy_##type##_2D(4, start, end, scanline) - -#define render_window_segment_clip_obj(type, clip_start, clip_end, start, end) \ - { \ - if (start != end) { \ - if (start < clip_start) { \ - if (end > clip_start) { \ - if (end > clip_end) { \ - render_window_clip_obj(type, clip_start, clip_end); \ - } else { \ - render_window_clip_obj(type, clip_start, end); \ - } \ - } \ - } else \ - \ - if (end > clip_end) { \ - if (start < clip_end) { \ - render_window_clip_obj(type, start, clip_end); \ - } \ - } else { \ - render_window_clip_obj(type, start, end); \ - } \ - } \ - } - -#define render_window_clip_1_obj(type, start, end) \ - if (window_1_x1 != DISPLAY_WIDTH) { \ - if (window_1_x1 > window_1_x2) { \ - render_window_segment_clip(type, start, end, 0, window_1_x2, 1); \ - render_window_segment_clip_obj(type, start, end, window_1_x2, window_1_x1); \ - render_window_segment_clip(type, start, end, window_1_x1, DISPLAY_WIDTH, 1); \ - } else { \ - render_window_segment_clip_obj(type, start, end, 0, window_1_x1); \ - render_window_segment_clip(type, start, end, window_1_x1, window_1_x2, 1); \ - render_window_segment_clip_obj(type, start, end, window_1_x2, DISPLAY_WIDTH); \ - } \ - } else { \ - render_window_clip_obj(type, start, end); \ - } - -#define render_window_single(type, window_number) \ - u32 winin = read_ioreg(REG_ADDR_WININ); \ - window_coords(window_number); \ - if (window_##window_number##_x1 > window_##window_number##_x2) { \ - render_window_segment(type, 0, window_##window_number##_x2, window_number); \ - render_window_segment(type, window_##window_number##_x2, window_##window_number##_x1, out); \ - render_window_segment(type, window_##window_number##_x1, DISPLAY_WIDTH, window_number); \ - } else { \ - render_window_segment(type, 0, window_##window_number##_x1, out); \ - render_window_segment(type, window_##window_number##_x1, window_##window_number##_x2, window_number); \ - render_window_segment(type, window_##window_number##_x2, DISPLAY_WIDTH, out); \ - } - -#define render_window_multi(type, front, back) \ - if (window_##front##_x1 > window_##front##_x2) { \ - render_window_segment(type, 0, window_##front##_x2, front); \ - render_window_clip_##back(type, window_##front##_x2, window_##front##_x1); \ - render_window_segment(type, window_##front##_x1, DISPLAY_WIDTH, front); \ - } else { \ - render_window_clip_##back(type, 0, window_##front##_x1); \ - render_window_segment(type, window_##front##_x1, window_##front##_x2, front); \ - render_window_clip_##back(type, window_##front##_x2, DISPLAY_WIDTH); \ - } - -#define render_scanline_window_builder(type) \ - static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \ - { \ - u32 vcount = read_ioreg(REG_ADDR_VCOUNT); \ - u32 winout = read_ioreg(REG_ADDR_WINOUT); \ - u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); \ - u32 window_out_enable = winout & 0x3F; \ - \ - render_scanline_layer_functions_##type(); \ - \ - switch (dispcnt >> 13) { \ - /* Just window 0 */ \ - case 0x01: { \ - render_window_single(type, 0); \ - break; \ - } \ - \ - /* Just window 1 */ \ - case 0x02: { \ - render_window_single(type, 1); \ - break; \ - } \ - \ - /* Windows 1 and 2 */ \ - case 0x03: { \ - u32 winin = read_ioreg(REG_ADDR_WININ); \ - window_coords(0); \ - window_coords(1); \ - render_window_multi(type, 0, 1); \ - break; \ - } \ - \ - /* Just OBJ windows */ \ - case 0x04: { \ - render_window_clip_obj(type, 0, DISPLAY_WIDTH); \ - break; \ - } \ - \ - /* Window 0 and OBJ window */ \ - case 0x05: { \ - u32 winin = read_ioreg(REG_ADDR_WININ); \ - window_coords(0); \ - render_window_multi(type, 0, obj); \ - break; \ - } \ - \ - /* Window 1 and OBJ window */ \ - case 0x06: { \ - u32 winin = read_ioreg(REG_ADDR_WININ); \ - window_coords(1); \ - render_window_multi(type, 1, obj); \ - break; \ - } \ - \ - /* Window 0, 1, and OBJ window */ \ - case 0x07: { \ - u32 winin = read_ioreg(REG_ADDR_WININ); \ - window_coords(0); \ - window_coords(1); \ - render_window_multi(type, 0, 1_obj); \ - break; \ - } \ - } \ - } - -render_scanline_window_builder(tile); -render_scanline_window_builder(bitmap); - -static const u8 active_layers[] = { - 0x1F, // Mode 0, Tile BG0-3 and OBJ - 0x17, // Mode 1, Tile BG0-2 and OBJ - 0x1C, // Mode 2, Tile BG2-3 and OBJ - 0x14, // Mode 3, BMP BG2 and OBJ - 0x14, // Mode 4, BMP BG2 and OBJ - 0x14, // Mode 5, BMP BG2 and OBJ - 0, // Unused - 0, -}; - -void update_scanline(void) -{ - u32 pitch = get_screen_pitch(); - u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); - u32 vcount = read_ioreg(REG_ADDR_VCOUNT); - u16 *screen_offset = get_screen_pixels() + (vcount * pitch); - u32 video_mode = dispcnt & 0x07; - - order_layers((dispcnt >> 8) & active_layers[video_mode], vcount); - - // fill_line_color16(*(uint16_t *)PLTT, screen_offset, 0, DISPLAY_WIDTH); - - // If the screen is in in forced blank draw pure white. - if (dispcnt & DISPCNT_FORCED_BLANK) { - fill_line_color16(0xFFFF, screen_offset, 0, DISPLAY_WIDTH); - } else { - if (video_mode < 3) { - if (dispcnt >> 13) { - render_scanline_window_tile(screen_offset, dispcnt); - } else { - render_scanline_tile(screen_offset, dispcnt); - } - } else { - if (dispcnt >> 13) - render_scanline_window_bitmap(screen_offset, dispcnt); - else - render_scanline_bitmap(screen_offset, dispcnt); - } - } - - affine_reference_x[0] += (s16)read_ioreg(REG_ADDR_BG2PB); - affine_reference_y[0] += (s16)read_ioreg(REG_ADDR_BG2PD); - affine_reference_x[1] += (s16)read_ioreg(REG_ADDR_BG3PB); - affine_reference_y[1] += (s16)read_ioreg(REG_ADDR_BG3PD); -} - -void DrawFrame_Fast(u16 *pixels) -{ - int i; - - gba_screen_pixels = pixels; - video_reload_counters(); - // convert_whole_palette(); - - // assume that the oam is only updated once before the frame - // starts to be drawn - u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); - u32 video_mode = dispcnt & 0x07; - order_obj(video_mode); - - for (i = 0; i < DISPLAY_HEIGHT; i++) { - - REG_VCOUNT = i; - if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { - REG_DISPSTAT |= INTR_FLAG_VCOUNT; - if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) - gIntrTable[INTR_INDEX_VCOUNT](); - } - - // Render the backdrop color before each individual scanline. - // HBlank interrupt code could have changed it in between lines. - update_scanline(); - - REG_DISPSTAT |= INTR_FLAG_HBLANK; - - RunDMAs(DMA_HBLANK); - - if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) - gIntrTable[INTR_INDEX_HBLANK](); - - REG_DISPSTAT &= ~INTR_FLAG_HBLANK; - REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; - } -} - -#endif diff --git a/src/platform/shared/rendering/sw_renderer_fast.cc b/src/platform/shared/rendering/sw_renderer_fast.cc new file mode 100644 index 0000000000..10a505865c --- /dev/null +++ b/src/platform/shared/rendering/sw_renderer_fast.cc @@ -0,0 +1,2298 @@ +/* gameplaySP - Modified to fit the SA2 codebase (FreshOllie - 2026) + * + * Copyright (C) 2006 Exophase + * Copyright (C) 2023 David Guillen Fandos + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +extern "C" { +#include "config.h" +} + +#if RENDERER == RENDERER_SOFTWARE_FAST + +#include +#include + +extern "C" { +#include "global.h" +#include "core.h" +#include "gba/defines.h" +#include "gba/io_reg.h" +#include "gba/types.h" + +#include "platform/shared/dma.h" +} + +#define eswap16(value) (value) +#define eswap32(value) (value) + +#define GBA_SCREEN_PITCH DISPLAY_WIDTH + +typedef u32 fixed16_16; +typedef u32 fixed8_24; + +#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) + +#define fp16_16_to_float(value) (float)((value) / 65536.0) + +#define u32_to_fp16_16(value) ((value) << 16) + +#define fp16_16_to_u32(value) ((value) >> 16) + +#define fp16_16_fractional_part(value) ((value)&0xFFFF) + +#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) + +#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) + +#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) + +#define read_ioreg(regaddr) (eswap16(*(u16 *)(regaddr))) +#define read_ioreg32(regaddr) (read_ioreg(regaddr) | (read_ioreg((regaddr) + sizeof(u16)) << 16)) + +#define convert_palette(value) (value & 0x7FFF) + +u16 *gba_screen_pixels = NULL; + +#define get_screen_pixels() gba_screen_pixels +#define get_screen_pitch() GBA_SCREEN_PITCH + +#define REG_ADDR_BGxCNT(n) (REG_ADDR_BG0CNT + (n) * sizeof(u16)) +#define REG_ADDR_WINxH(n) (REG_ADDR_WIN0H + (n) * sizeof(winreg_t)) +#define REG_ADDR_WINxV(n) (REG_ADDR_WIN0V + (n) * sizeof(winreg_t)) +#define REG_ADDR_BGxHOFS(n) (REG_ADDR_BG0HOFS + ((n)*2) * sizeof(u16)) +#define REG_ADDR_BGxVOFS(n) (REG_ADDR_BG0VOFS + ((n)*2) * sizeof(u16)) +#define REG_ADDR_BGxPA(n) (REG_ADDR_BG2PA + ((n)-2) * 8 * sizeof(u16)) +#define REG_ADDR_BGxPB(n) (REG_ADDR_BG2PB + ((n)-2) * 8 * sizeof(u16)) +#define REG_ADDR_BGxPC(n) (REG_ADDR_BG2PC + ((n)-2) * 8 * sizeof(u16)) +#define REG_ADDR_BGxPD(n) (REG_ADDR_BG2PD + ((n)-2) * 8 * sizeof(u16)) + +typedef struct { + u16 pad0[OAM_DATA_COUNT_AFFINE - 1]; + u16 dx; + u16 pad1[OAM_DATA_COUNT_AFFINE - 1]; + u16 dmx; + u16 pad2[OAM_DATA_COUNT_AFFINE - 1]; + u16 dy; + u16 pad3[OAM_DATA_COUNT_AFFINE - 1]; + u16 dmy; +} t_affp; + +typedef void (*bitmap_render_function)(u32 start, u32 end, void *dest_ptr, const u16 *pal); +typedef void (*tile_render_function)(u32 layer, u32 start, u32 end, void *dest_ptr, const u16 *pal); + +typedef void (*render_function_u16)(u32 start, u32 end, u16 *scanline, u32 enable_flags); +typedef void (*render_function_u32)(u32 start, u32 end, u32 *scanline, u32 enable_flags); + +typedef void (*window_render_function)(u16 *scanline, u32 start, u32 end); + +static void render_scanline_conditional(u32 start, u32 end, u16 *scanline, u32 enable_flags = 0x3F); + +typedef struct { + bitmap_render_function blit_render; + bitmap_render_function scale_render; + bitmap_render_function affine_render; +} bitmap_layer_render_struct; + +typedef struct { + render_function_u16 fullcolor; + render_function_u16 indexed_u16; + render_function_u32 indexed_u32; + render_function_u32 stacked; +} layer_render_struct; + +// Object blending modes +#define OBJ_MOD_NORMAL 0 +#define OBJ_MOD_SEMITRAN 1 +#define OBJ_MOD_WINDOW 2 +#define OBJ_MOD_INVALID 3 + +// BLDCNT color effect modes +#define COL_EFFECT_NONE 0x0 +#define COL_EFFECT_BLEND 0x1 +#define COL_EFFECT_BRIGHT 0x2 +#define COL_EFFECT_DARK 0x3 + +// Background render modes +#define RENDER_NORMAL 0 +#define RENDER_COL16 1 +#define RENDER_COL32 2 +#define RENDER_ALPHA 3 + +// Byte lengths of complete tiles and tile rows in 4bpp and 8bpp. + +#define tile_width_4bpp 4 +#define tile_size_4bpp 32 +#define tile_width_8bpp 8 +#define tile_size_8bpp 64 + +// Sprite rendering cycles +#define REND_CYC_MAX 32768 /* Theoretical max is 17920 */ +#define REND_CYC_SCANLINE 1210 +#define REND_CYC_REDUCED 954 + +// Generate bit mask (bits 9th and 10th) with information about the pixel +// status (1st and/or 2nd target) for later blending. +static inline u16 color_flags(u32 layer) +{ + u32 bldcnt = read_ioreg(REG_ADDR_BLDCNT); + return (((bldcnt >> layer) & 0x01) | // 1st target + ((bldcnt >> (layer + 7)) & 0x02) // 2nd target + ) + << 9; +} + +static const u32 map_widths[] = { 256, 512, 256, 512 }; + +typedef enum { + FULLCOLOR, // Regular rendering, output a 16 bit color + INDXCOLOR, // Rendering to indexed color, so we can later apply dark/bright + STCKCOLOR, // Stacks two indexed pixels (+flags) to apply blending + PIXCOPY // Special mode used for sprites, to allow for obj-window drawing +} rendtype; + +s32 affine_reference_x[2]; +s32 affine_reference_y[2]; + +static inline s32 signext28(u32 value) +{ + s32 ret = (s32)(value << 4); + return ret >> 4; +} + +void video_reload_counters() +{ + /* This happens every Vblank */ + affine_reference_x[0] = signext28(read_ioreg32(REG_ADDR_BG2X_L)); + affine_reference_y[0] = signext28(read_ioreg32(REG_ADDR_BG2Y_L)); + affine_reference_x[1] = signext28(read_ioreg32(REG_ADDR_BG3X_L)); + affine_reference_y[1] = signext28(read_ioreg32(REG_ADDR_BG3Y_L)); +} + +// Renders non-affine tiled background layer. +// Will process a full or partial tile (start and end within 0..8) and draw +// it in either 8 or 4 bpp mode. Honors vertical and horizontal flip. + +// tile contains the tile info (contains tile index, flip bits, pal info) +// hflip causes the tile pixels lookup to be reversed (from MSB to LSB +// If isbase is not set, color 0 is interpreted as transparent, otherwise +// we are drawing the base layer, so palette[0] is used (backdrop). + +template +static inline void rend_part_tile_Nbpp(u32 bg_comb, u32 px_comb, dtype *dest_ptr, u32 start, u32 end, u16 tile, const u8 *tile_base, + int vertical_pixel_flip, const u16 *paltbl) +{ + // Seek to the specified tile, using the tile number and size. + // tile_base already points to the right tile-line vertical offset + const u8 *tile_ptr = &tile_base[(tile & 0x3FF) * (is8bpp ? 64 : 32)]; + u16 bgcolor = paltbl[0]; + + // On vertical flip, apply the mirror offset + if (tile & 0x800) + tile_ptr += vertical_pixel_flip; + + if (is8bpp) { + // Each byte is a color, mapped to a palete. 8 bytes can be read as 64bit + for (u32 i = start; i < end; i++, dest_ptr++) { + // Honor hflip by selecting bytes in the correct order + u32 sel = hflip ? (7 - i) : i; + u8 pval = tile_ptr[sel]; + // Alhpa mode stacks previous value (unless rendering the first layer) + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = paltbl[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_comb; // Add combine flags + else if (rdtype == STCKCOLOR) + // Stack pixels on top of the pixel value and combine flags + *dest_ptr = pval | px_comb | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + if (rdtype == FULLCOLOR) + *dest_ptr = bgcolor; + else + *dest_ptr = 0 | bg_comb; // Add combine flags + } + } + } else { + // In 4bpp mode, the tile[15..12] bits contain the sub-palette number. + u16 tilepal = (tile >> 12) << 4; + u16 pxflg = px_comb | tilepal; + const u16 *subpal = &paltbl[tilepal]; + // Read packed pixel data, skip start pixels + u32 tilepix = eswap32(*(u32 *)tile_ptr); + if (hflip) + tilepix <<= (start * 4); + else + tilepix >>= (start * 4); + // Only 32 bits (8 pixels * 4 bits) + for (u32 i = start; i < end; i++, dest_ptr++) { + u8 pval = hflip ? tilepix >> 28 : tilepix & 0xF; + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = subpal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pxflg | pval; + else if (rdtype == STCKCOLOR) // Stack pixels + *dest_ptr = pxflg | pval | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + if (rdtype == FULLCOLOR) + *dest_ptr = bgcolor; + else + *dest_ptr = 0 | bg_comb; + } + // Advance to next packed data + if (hflip) + tilepix <<= 4; + else + tilepix >>= 4; + } + } +} + +// Same as above, but optimized for full tiles. Skip comments here. +template +static inline void render_tile_Nbpp(u32 bg_comb, u32 px_comb, dtype *dest_ptr, u16 tile, const u8 *tile_base, int vertical_pixel_flip, + const u16 *paltbl) +{ + const u8 *tile_ptr = &tile_base[(tile & 0x3FF) * (is8bpp ? 64 : 32)]; + u16 bgcolor = paltbl[0]; + + if (tile & 0x800) + tile_ptr += vertical_pixel_flip; + + if (is8bpp) { + for (u32 j = 0; j < 2; j++) { + u32 tilepix = eswap32(((u32 *)tile_ptr)[hflip ? 1 - j : j]); + if (tilepix) { + for (u32 i = 0; i < 4; i++, dest_ptr++) { + u8 pval = hflip ? (tilepix >> (24 - i * 8)) : (tilepix >> (i * 8)); + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = paltbl[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_comb; // Add combine flags + else if (rdtype == STCKCOLOR) + *dest_ptr = pval | px_comb | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + *dest_ptr = (rdtype == FULLCOLOR) ? bgcolor : 0 | bg_comb; + } + } + } else { + for (u32 i = 0; i < 4; i++, dest_ptr++) + if (isbase) + *dest_ptr = (rdtype == FULLCOLOR) ? bgcolor : 0 | bg_comb; + } + } + } else { + u32 tilepix = eswap32(*(u32 *)tile_ptr); + if (tilepix) { // We can skip it all if the row is transparent + u16 tilepal = (tile >> 12) << 4; + u16 pxflg = px_comb | tilepal; + const u16 *subpal = &paltbl[tilepal]; + for (u32 i = 0; i < 8; i++, dest_ptr++) { + u8 pval = (hflip ? (tilepix >> ((7 - i) * 4)) : (tilepix >> (i * 4))) & 0xF; + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = subpal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pxflg | pval; + else if (rdtype == STCKCOLOR) + *dest_ptr = pxflg | pval | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + *dest_ptr = (rdtype == FULLCOLOR) ? bgcolor : 0 | bg_comb; + } + } + } else if (isbase) { + // In this case we simply fill the pixels with background pixels + for (u32 i = 0; i < 8; i++, dest_ptr++) + *dest_ptr = (rdtype == FULLCOLOR) ? bgcolor : 0 | bg_comb; + } + } +} + +template +static void render_scanline_text_fast(u32 layer, u32 start, u32 end, void *scanline, const u16 *paltbl) +{ + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u16 vcount = read_ioreg(REG_ADDR_VCOUNT); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 hoffset = (start + read_ioreg(REG_ADDR_BGxHOFS(layer))) % 512; + u32 voffset = (vcount + read_ioreg(REG_ADDR_BGxVOFS(layer))) % 512; + stype *dest_ptr = ((stype *)scanline) + start; + + // Calculate combine masks. These store 2 bits of info: 1st and 2nd target. + // If set, the current pixel belongs to a layer that is 1st or 2nd target. + u32 bg_comb = color_flags(5), px_comb = color_flags(layer); + + // Background map data is in VRAM, at an offset specified in 2K blocks. + // (each map data block is 32x32 tiles, at 16bpp, so 2KB) + u32 base_block = (bg_control & BGCNT_SCREENBASE_MASK) >> 8; + u16 *map_base = (u16 *)BG_SCREEN_ADDR(base_block); + u16 *map_ptr, *second_ptr; + + end -= start; + + // Skip the top one/two block(s) if using the bottom half + if ((map_size & 0x02) && (voffset >= 256)) + map_base += ((map_width / 8) * 32); + + // Skip the top tiles within the block + map_base += (((voffset % 256) / 8) * (map_width / 8)); + + // we might need to render from two charblocks, store a second pointer. + second_ptr = map_ptr = map_base; + + if (map_size & 0x01) { // If background is 512 pixels wide + if (hoffset >= 256) { + // If we are rendering the right block, skip a whole charblock + hoffset -= 256; + map_ptr += ((map_width / 8) * 32); + } else { + // If we are rendering the left block, we might overrun into the right + second_ptr += ((map_width / 8) * 32); + } + } else { + hoffset %= 256; // Background is 256 pixels wide + } + + // Skip the left blocks within the block + map_ptr += hoffset / 8; + + // Render a single scanline of text tiles + u32 tilewidth = is8bpp ? tile_width_8bpp : tile_width_4bpp; + u32 vert_pix_offset = (voffset % 8) * tilewidth; + // Calculate the pixel offset between a line and its "flipped" mirror. + // The values can be {56, 40, 24, 8, -8, -24, -40, -56} + s32 vflip_off + = is8bpp ? tile_size_8bpp - 2 * vert_pix_offset - tile_width_8bpp : tile_size_4bpp - 2 * vert_pix_offset - tile_width_4bpp; + + // The tilemap base is selected via bgcnt (16KiB chunks) + u32 tilecntrl = (bg_control >> 2) & 0x03; + // Account for the base offset plus the tile vertical offset + u8 *tile_base = BG_CHAR_ADDR(tilecntrl) + vert_pix_offset; + // Number of pixels available until the end of the tile block + u32 pixel_run = map_width - hoffset; + + u32 tile_hoff = hoffset % 8; + u32 partial_hcnt = 8 - tile_hoff; + + if (tile_hoff) { + // First partial tile, only right side is visible. + u32 todraw = MIN(end, partial_hcnt); // [1..7] + u32 stop = tile_hoff + todraw; // Usually 8, unless short run. + + u16 tile = eswap16(*map_ptr++); + if (tile & 0x400) // Tile horizontal flip + rend_part_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile_hoff, stop, tile, tile_base, + vflip_off, paltbl); + else + rend_part_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile_hoff, stop, tile, tile_base, + vflip_off, paltbl); + + dest_ptr += todraw; + end -= todraw; + pixel_run -= todraw; + } + + if (!end) + return; + + // Now render full tiles + u32 todraw = MIN(end, pixel_run) / 8; + + for (u32 i = 0; i < todraw; i++, dest_ptr += 8) { + u16 tile = eswap16(*map_ptr++); + if (tile & 0x400) // Tile horizontal flip + render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); + else + render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); + } + + end -= todraw * 8; + pixel_run -= todraw * 8; + + if (!end) + return; + + // Switch to the next char block if we ran out of tiles + if (!pixel_run) + map_ptr = second_ptr; + + todraw = end / 8; + for (u32 i = 0; i < todraw; i++, dest_ptr += 8) { + u16 tile = eswap16(*map_ptr++); + if (tile & 0x400) // Tile horizontal flip + render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); + else + render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); + } + + end -= todraw * 8; + + // Finalize the tile rendering the left side of it (from 0 up to "end"). + if (end) { + u16 tile = eswap16(*map_ptr++); + if (tile & 0x400) // Tile horizontal flip + rend_part_tile_Nbpp(bg_comb, px_comb, dest_ptr, 0, end, tile, tile_base, vflip_off, + paltbl); + else + rend_part_tile_Nbpp(bg_comb, px_comb, dest_ptr, 0, end, tile, tile_base, vflip_off, + paltbl); + } +} + +// A slow version of the above function that allows for mosaic effects +template +static void render_scanline_text_mosaic(u32 layer, u32 start, u32 end, void *scanline, const u16 *paltbl) +{ + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + const u32 mosh = (read_ioreg(REG_ADDR_MOSAIC) & 0xF) + 1; + const u32 mosv = ((read_ioreg(REG_ADDR_MOSAIC) >> 4) & 0xF) + 1; + u16 vcount = read_ioreg(REG_ADDR_VCOUNT); + u32 map_size = (bg_control >> 14) & 0x03; + u32 map_width = map_widths[map_size]; + u32 hoffset = (start + read_ioreg(REG_ADDR_BGxHOFS(layer))) % 512; + u16 vmosoff = vcount - vcount % mosv; + u32 voffset = (vmosoff + read_ioreg(REG_ADDR_BGxVOFS(layer))) % 512; + stype *dest_ptr = ((stype *)scanline) + start; + + u32 bg_comb = color_flags(5), px_comb = color_flags(layer); + + u32 base_block = (bg_control & BGCNT_SCREENBASE_MASK) >> 8; + u16 *map_base = (u16 *)BG_SCREEN_ADDR(base_block); + u16 *map_ptr, *second_ptr; + + if ((map_size & 0x02) && (voffset >= 256)) + map_base += ((map_width / 8) * 32); + + map_base += (((voffset % 256) / 8) * (map_width / 8)); + + second_ptr = map_ptr = map_base; + + if (map_size & 0x01) { // If background is 512 pixels wide + if (hoffset >= 256) { + // If we are rendering the right block, skip a whole charblock + hoffset -= 256; + map_ptr += ((map_width / 8) * 32); + } else { + // If we are rendering the left block, we might overrun into the right + second_ptr += ((map_width / 8) * 32); + } + } else { + hoffset %= 256; // Background is 256 pixels wide + } + + // Skip the left blocks within the block + map_ptr += hoffset / 8; + + // Render a single scanline of text tiles + u32 tilewidth = is8bpp ? tile_width_8bpp : tile_width_4bpp; + u32 vert_pix_offset = (voffset % 8) * tilewidth; + // Calculate the pixel offset between a line and its "flipped" mirror. + // The values can be {56, 40, 24, 8, -8, -24, -40, -56} + s32 vflip_off + = is8bpp ? tile_size_8bpp - 2 * vert_pix_offset - tile_width_8bpp : tile_size_4bpp - 2 * vert_pix_offset - tile_width_4bpp; + + // The tilemap base is selected via bgcnt (16KiB chunks) + u32 tilecntrl = (bg_control >> 2) & 0x03; + // Account for the base offset plus the tile vertical offset + u8 *tile_base = BG_CHAR_ADDR(tilecntrl) + vert_pix_offset; + + u16 bgcolor = paltbl[0]; + + // Iterate pixel by pixel, loading data every N pixels to honor mosaic effect + u8 pval = 0; + for (u32 i = 0; start < end; start++, i++, dest_ptr++) { + u16 tile = eswap16(*map_ptr); + + if (!(i % mosh)) { + const u8 *tile_ptr = &tile_base[(tile & 0x3FF) * (is8bpp ? 64 : 32)]; + + bool hflip = (tile & 0x400); + if (tile & 0x800) + tile_ptr += vflip_off; + + // Load byte or nibble with pixel data. + if (is8bpp) { + if (hflip) + pval = tile_ptr[7 - hoffset % 8]; + else + pval = tile_ptr[hoffset % 8]; + } else { + if (hflip) + pval = (tile_ptr[(7 - hoffset % 8) >> 1] >> (((hoffset & 1) ^ 1) * 4)) & 0xF; + else + pval = (tile_ptr[(hoffset % 8) >> 1] >> ((hoffset & 1) * 4)) & 0xF; + } + } + + if (is8bpp) { + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = paltbl[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_comb; // Add combine flags + else if (rdtype == STCKCOLOR) + *dest_ptr = pval | px_comb | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + *dest_ptr = (rdtype == FULLCOLOR) ? bgcolor : 0 | bg_comb; + } + } else { + u16 tilepal = (tile >> 12) << 4; + u16 pxflg = px_comb | tilepal; + const u16 *subpal = &paltbl[tilepal]; + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = subpal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pxflg | pval; + else if (rdtype == STCKCOLOR) + *dest_ptr = pxflg | pval | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + *dest_ptr = (rdtype == FULLCOLOR) ? bgcolor : 0 | bg_comb; + } + } + + // Need to continue from the next charblock + hoffset++; + if (hoffset % 8 == 0) + map_ptr++; + if (hoffset >= map_width) { + hoffset = 0; + map_ptr = second_ptr; + } + } +} + +template +static void render_scanline_text(u32 layer, u32 start, u32 end, void *scanline, const u16 *paltbl) +{ + // Tile mode has 4 and 8 bpp modes. + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + bool is8bpp = (read_ioreg(REG_ADDR_BGxCNT(layer)) & 0x80); + const u32 mosamount = read_ioreg(REG_ADDR_MOSAIC) & 0xFF; + bool has_mosaic = (bg_control & 0x40) && (mosamount != 0); + + if (has_mosaic) { + if (is8bpp) + render_scanline_text_mosaic(layer, start, end, scanline, paltbl); + else + render_scanline_text_mosaic(layer, start, end, scanline, paltbl); + } else { + if (is8bpp) + render_scanline_text_fast(layer, start, end, scanline, paltbl); + else + render_scanline_text_fast(layer, start, end, scanline, paltbl); + } +} + +static inline u8 lookup_pix_8bpp(u32 px, u32 py, const u8 *tile_base, const u8 *map_base, u32 map_size) +{ + // Pitch represents the log2(number of tiles per row) (from 16 to 128) + u32 map_pitch = map_size + 4; + // Given coords (px,py) in the background space, find the tile. + u32 mapoff = (px / 8) + ((py / 8) << map_pitch); + // Each tile is 8x8, so 64 bytes each. + const u8 *tile_ptr = &tile_base[map_base[mapoff] * tile_size_8bpp]; + // Read the 8bit color within the tile. + return tile_ptr[(px % 8) + ((py % 8) * 8)]; +} + +template +static inline void rend_pix_8bpp(dsttype *dest_ptr, u8 pval, u32 bg_comb, u32 px_comb, const u16 *pal) +{ + // Alhpa mode stacks previous value (unless rendering the first layer) + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = pal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_comb; // Add combine flags + else if (rdtype == STCKCOLOR) + // Stack pixels. If base, stack the base pixel. + *dest_ptr = pval | px_comb | ((isbase ? bg_comb : *dest_ptr) << 16); + } else if (isbase) { + // Transparent pixel, but we are base layer, so render background. + if (rdtype == FULLCOLOR) + *dest_ptr = pal[0]; + else + *dest_ptr = 0 | bg_comb; // Just backdrop color and combine flags + } +} + +template static inline void render_bdrop_pixel_8bpp(dsttype *dest_ptr, u32 bg_comb, u16 bgcol) +{ + // Alhpa mode stacks previous value (unless rendering the first layer) + if (rdtype == FULLCOLOR) + *dest_ptr = bgcol; + else + *dest_ptr = 0 | bg_comb; +} + +typedef void (*affine_render_function)(u32 layer, u32 start, u32 cnt, const u8 *map_base, u32 map_size, const u8 *tile_base, void *dst_ptr, + const u16 *pal); + +// Affine background rendering logic. +// wrap extends the background infinitely, otherwise transparent/backdrop fill +// rotate indicates if there's any rotation (optimized version for no-rotation) +// mosaic applies to horizontal mosaic (vertical is adjusted via affine ref) +template +static inline void render_affine_background(u32 layer, u32 start, u32 cnt, const u8 *map_base, u32 map_size, const u8 *tile_base, + void *dst_ptr_raw, const u16 *pal) +{ + + dtype *dst_ptr = (dtype *)dst_ptr_raw; + // Backdrop and current layer combine bits. + u32 bg_comb = color_flags(5); + u32 px_comb = color_flags(layer); + + s32 dx = (s16)read_ioreg(REG_ADDR_BGxPA(layer)); + s32 dy = (s16)read_ioreg(REG_ADDR_BGxPC(layer)); + + s32 source_x = affine_reference_x[layer - 2] + (start * dx); + s32 source_y = affine_reference_y[layer - 2] + (start * dy); + + // Maps are squared, four sizes available (128x128 to 1024x1024) + u32 width_height = 128 << map_size; + + // Horizontal mosaic effect. + const u32 mosh = (mosaic ? (read_ioreg(REG_ADDR_MOSAIC)) & 0xF : 0) + 1; + + if (wrap) { + // In wrap mode the entire space is covered, since it "wraps" at the edges + u8 pval = 0; + if (rotate) { + for (u32 i = 0; cnt; i++, cnt--) { + u32 pix_x = (u32)(source_x >> 8) & (width_height - 1); + u32 pix_y = (u32)(source_y >> 8) & (width_height - 1); + + // Lookup pixel and draw it (only every Nth if mosaic is on) + if (!mosaic || !(i % mosh)) + pval = lookup_pix_8bpp(pix_x, pix_y, tile_base, map_base, map_size); + rend_pix_8bpp(dst_ptr++, pval, bg_comb, px_comb, pal); + + source_x += dx; + source_y += dy; // Move to the next pixel + } + } else { + // Y coordinate stays contant across the walk. + const u32 pix_y = (u32)(source_y >> 8) & (width_height - 1); + for (u32 i = 0; cnt; i++, cnt--) { + u32 pix_x = (u32)(source_x >> 8) & (width_height - 1); + if (!mosaic || !(i % mosh)) + pval = lookup_pix_8bpp(pix_x, pix_y, tile_base, map_base, map_size); + rend_pix_8bpp(dst_ptr++, pval, bg_comb, px_comb, pal); + source_x += dx; // Only moving in the X direction. + } + } + } else { + u16 bgcol = pal[0]; + if (rotate) { + // Draw backdrop pixels if necessary until we reach the background edge. + while (cnt) { + // Draw backdrop pixels if they lie outside of the background. + u32 pix_x = (u32)(source_x >> 8), pix_y = (u32)(source_y >> 8); + + // Stop once we find a pixel that is actually *inside* the map. + if (pix_x < width_height && pix_y < width_height) + break; + + // Draw a backdrop pixel if we are the base layer. + if (isbase) + render_bdrop_pixel_8bpp(dst_ptr, bg_comb, bgcol); + + dst_ptr++; + source_x += dx; + source_y += dy; + cnt--; + } + + // Draw background pixels by looking them up in the map + u8 pval = 0; + for (u32 i = 0; cnt; i++, cnt--) { + u32 pix_x = (u32)(source_x >> 8), pix_y = (u32)(source_y >> 8); + + // Check if we run out of background pixels, stop drawing. + if (pix_x >= width_height || pix_y >= width_height) + break; + + // Lookup pixel and draw it. + if (!mosaic || !(i % mosh)) + pval = lookup_pix_8bpp(pix_x, pix_y, tile_base, map_base, map_size); + rend_pix_8bpp(dst_ptr++, pval, bg_comb, px_comb, pal); + + // Move to the next pixel, update coords accordingly + source_x += dx; + source_y += dy; + } + } else { + // Specialized version for scaled-only backgrounds + u8 pval = 0; + const u32 pix_y = (u32)(source_y >> 8); + if (pix_y < width_height) { // Check if within Y-coord range + // Draw/find till left edge + while (cnt) { + u32 pix_x = (u32)(source_x >> 8); + if (pix_x < width_height) + break; + + if (isbase) + render_bdrop_pixel_8bpp(dst_ptr, bg_comb, bgcol); + + dst_ptr++; + source_x += dx; + cnt--; + } + // Draw actual background + for (u32 i = 0; cnt; i++, cnt--) { + u32 pix_x = (u32)(source_x >> 8); + if (pix_x >= width_height) + break; + + if (!mosaic || !(i % mosh)) + pval = lookup_pix_8bpp(pix_x, pix_y, tile_base, map_base, map_size); + rend_pix_8bpp(dst_ptr++, pval, bg_comb, px_comb, pal); + + source_x += dx; + } + } + } + + // Complete the line on the right, if we ran out over the bg edge. + // Only necessary for the base layer, otherwise we can safely finish. + if (isbase) + while (cnt--) + render_bdrop_pixel_8bpp(dst_ptr++, bg_comb, bgcol); + } +} + +// Renders affine backgrounds. These differ substantially from non-affine +// ones. Tile maps are byte arrays (instead of 16 bit), limiting the map to +// 256 different tiles (with no flip bits and just one single 256 color pal). +// Optimize for common cases: wrap/non-wrap, scaling/rotation. +template +static void render_scanline_affine(u32 layer, u32 start, u32 end, void *scanline, const u16 *pal) +{ + + u32 bg_control = read_ioreg(REG_ADDR_BGxCNT(layer)); + u32 map_size = (bg_control >> 14) & 0x03; + + // Char block base pointer + u32 base_block = (bg_control & BGCNT_SCREENBASE_MASK) >> 8; + u8 *map_base = BG_SCREEN_ADDR(base_block); + // The tilemap base is selected via bgcnt (16KiB chunks) + u32 tilecntrl = (bg_control >> 2) & 0x03; + u8 *tile_base = BG_CHAR_ADDR(tilecntrl); + + dsttype *dest_ptr = ((dsttype *)scanline) + start; + const u32 mosamount = read_ioreg(REG_ADDR_MOSAIC) & 0xFF; + + bool has_mosaic = (bg_control & 0x40) && (mosamount != 0); + bool has_rotation = read_ioreg(REG_ADDR_BGxPC(layer)) != 0; + bool has_wrap = (bg_control >> 13) & 1; + + // Number of pixels to render + u32 cnt = end - start; + + // Four specialized versions for faster rendering on specific cases like + // scaling only or non-wrapped backgrounds. + u32 fidx = (has_wrap ? 0x4 : 0) | (has_rotation ? 0x2 : 0) | (has_mosaic ? 0x1 : 0); + + static const affine_render_function rdfns[8] = { + render_affine_background, + render_affine_background, + render_affine_background, + render_affine_background, + render_affine_background, + render_affine_background, + render_affine_background, + render_affine_background, + }; + + rdfns[fidx](layer, start, cnt, map_base, map_size, tile_base, dest_ptr, pal); +} + +template +static inline void bitmap_pixel_write(buftype *dst_ptr, pixfmt val, const u16 *palptr, u16 px_attr) +{ + if (mode != 4) + *dst_ptr = convert_palette(val); // Direct color, u16 bitmap + else if (val) { + if (rdmode == FULLCOLOR) + *dst_ptr = palptr[val]; + else if (rdmode == INDXCOLOR) + *dst_ptr = val | px_attr; // Add combine flags + else if (rdmode == STCKCOLOR) + *dst_ptr = val | px_attr | ((*dst_ptr) << 16); // Stack pixels + } +} + +typedef enum { + BLIT, // The bitmap has no scaling nor rotation on the X axis + SCALED, // The bitmap features some scaling (on the X axis) but no rotation + ROTATED // Bitmap has rotation (and perhaps scaling too) +} bm_rendmode; + +// Renders a bitmap honoring the pixel mode and any affine transformations. +// There's optimized versions for bitmaps without scaling / rotation. + +template // Whether mosaic effect is used. +static inline void render_scanline_bitmap(u32 start, u32 end, void *scanline, const u16 *palptr) +{ + s32 dx = (s16)read_ioreg(REG_ADDR_BG2PA); + s32 dy = (s16)read_ioreg(REG_ADDR_BG2PC); + s32 source_x = affine_reference_x[0] + (start * dx); // Always BG2 + s32 source_y = affine_reference_y[0] + (start * dy); + + // Premature abort render optimization if bitmap out of Y coordinate. + if ((rdmode != ROTATED) && ((u32)(source_y >> 8)) >= height) + return; + + // Modes 4 and 5 feature double buffering. + bool second_frame = (mode >= 4) && (read_ioreg(REG_ADDR_DISPCNT) & 0x10); + pixfmt *src_ptr = (pixfmt *)&VRAM[second_frame ? 0xA000 : 0x0000]; + dsttype *dst_ptr = ((dsttype *)scanline) + start; + u16 px_attr = color_flags(2); // Always BG2 + + const u32 mosh = (mosaic ? (read_ioreg(REG_ADDR_MOSAIC)) & 0xF : 0) + 1; + + if (rdmode == BLIT) { + // We just blit pixels (copy) from buffer to buffer. + const u32 pixel_y = (u32)(source_y >> 8); + if (source_x < 0) { + // The bitmap starts somewhere after "start", skip those pixels. + u32 delta = (-source_x + 255) >> 8; + dst_ptr += delta; + start += delta; + source_x = 0; + } + + u32 pixel_x = (u32)(source_x >> 8); + u32 pixcnt = MIN(end - start, width - pixel_x); + pixfmt *valptr = &src_ptr[pixel_x + (pixel_y * width)]; + pixfmt val = 0; + for (u32 i = 0; pixcnt; i++, pixcnt--, valptr++) { + // Pretty much pixel copier + if (!mosaic || !(i % mosh)) + val = sizeof(pixfmt) == 2 ? eswap16(*valptr) : *valptr; + bitmap_pixel_write(dst_ptr++, val, palptr, px_attr); + } + } else if (rdmode == SCALED) { + // Similarly to above, but now we need to sample pixels instead. + const u32 pixel_y = (u32)(source_y >> 8); + + // Find the "inside" of the bitmap + while (start < end) { + u32 pixel_x = (u32)(source_x >> 8); + if (pixel_x < width) + break; + source_x += dx; + start++; + dst_ptr++; + } + + u32 cnt = end - start; + pixfmt val = 0; + for (u32 i = 0; cnt; i++, cnt--) { + u32 pixel_x = (u32)(source_x >> 8); + if (pixel_x >= width) + break; // We reached the end of the bitmap + + if (!mosaic || !(i % mosh)) { + pixfmt *valptr = &src_ptr[pixel_x + (pixel_y * width)]; + val = sizeof(pixfmt) == 2 ? eswap16(*valptr) : *valptr; + } + + bitmap_pixel_write(dst_ptr++, val, palptr, px_attr); + source_x += dx; + } + } else { + // Look for the first pixel to be drawn. + while (start < end) { + u32 pixel_x = (u32)(source_x >> 8), pixel_y = (u32)(source_y >> 8); + if (pixel_x < width && pixel_y < height) + break; + start++; + dst_ptr++; + source_x += dx; + source_y += dy; + } + + pixfmt val = 0; + for (u32 i = 0; start < end; start++) { + u32 pixel_x = (u32)(source_x >> 8), pixel_y = (u32)(source_y >> 8); + + // Check if we run out of background pixels, stop drawing. + if (pixel_x >= width || pixel_y >= height) + break; + + // Lookup pixel and draw it. + if (!mosaic || !(i % mosh)) { + pixfmt *valptr = &src_ptr[pixel_x + (pixel_y * width)]; + val = sizeof(pixfmt) == 2 ? eswap16(*valptr) : *valptr; + } + + bitmap_pixel_write(dst_ptr++, val, palptr, px_attr); + + // Move to the next pixel, update coords accordingly + source_x += dx; + source_y += dy; + } + } +} + +// Object/Sprite rendering logic + +static const u8 obj_dim_table[3][4][2] = { { { 8, 8 }, { 16, 16 }, { 32, 32 }, { 64, 64 } }, + { { 16, 8 }, { 32, 8 }, { 32, 16 }, { 64, 32 } }, + { { 8, 16 }, { 8, 32 }, { 16, 32 }, { 32, 64 } } }; + +static u8 obj_priority_list[5][DISPLAY_HEIGHT][128]; +static u8 obj_priority_count[5][DISPLAY_HEIGHT]; +static u8 obj_alpha_count[DISPLAY_HEIGHT]; + +typedef struct { + s32 obj_x, obj_y; + s32 obj_w, obj_h; + const OamData *oam_data; + bool is_double; +} t_sprite; + +// Renders a tile row (8 pixels) for a regular (non-affine) object/sprite. +// tile_offset points to the VRAM offset where the data lives. +template +static inline void render_obj_part_tile_Nbpp(u32 px_comb, dsttype *dest_ptr, u32 start, u32 end, u32 tile_offset, u16 palette, + const u16 *pal) +{ + // Note that the last VRAM bank wrap around, hence the offset aliasing + const u8 *tile_ptr = OBJ_VRAM0 + (tile_offset & 0x7FFF); + u32 px_attr = px_comb | palette | 0x100; // Combine flags + high palette bit + + if (is8bpp) { + // Each byte is a color, mapped to a palete. + for (u32 i = start; i < end; i++, dest_ptr++) { + // Honor hflip by selecting bytes in the correct order + u32 sel = hflip ? (7 - i) : i; + u8 pval = tile_ptr[sel]; + // Alhpa mode stacks previous value + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = pal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_attr; // Add combine flags + else if (rdtype == STCKCOLOR) { + // Stack pixels on top of the pixel value and combine flags + // We do not stack OBJ on OBJ, rather overwrite the previous object + if (*dest_ptr & 0x100) + *dest_ptr = pval | px_attr | ((*dest_ptr) & 0xFFFF0000); + else + *dest_ptr = pval | px_attr | ((*dest_ptr) << 16); + } else if (rdtype == PIXCOPY) + *dest_ptr = dest_ptr[DISPLAY_WIDTH]; + } + } + } else { + // Only 32 bits (8 pixels * 4 bits) + for (u32 i = start; i < end; i++, dest_ptr++) { + u32 selb = hflip ? (3 - i / 2) : i / 2; + u32 seln = hflip ? ((i & 1) ^ 1) : (i & 1); + u8 pval = (tile_ptr[selb] >> (seln * 4)) & 0xF; + const u16 *subpal = &pal[palette]; + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = subpal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_attr; + else if (rdtype == STCKCOLOR) { + if (*dest_ptr & 0x100) + *dest_ptr = pval | px_attr | ((*dest_ptr) & 0xFFFF0000); + else + *dest_ptr = pval | px_attr | ((*dest_ptr) << 16); // Stack pixels + } else if (rdtype == PIXCOPY) + *dest_ptr = dest_ptr[DISPLAY_WIDTH]; + } + } + } +} + +// Same as above but optimized for full tiles +template +static inline void render_obj_tile_Nbpp(u32 px_comb, dsttype *dest_ptr, u32 tile_offset, u16 palette, const u16 *pal) +{ + const u8 *tile_ptr = &VRAM[0x10000 + (tile_offset & 0x7FFF)]; + u32 px_attr = px_comb | palette | 0x100; // Combine flags + high palette bit + + if (is8bpp) { + for (u32 j = 0; j < 2; j++) { + u32 tilepix = eswap32(((u32 *)tile_ptr)[hflip ? 1 - j : j]); + if (tilepix) { + for (u32 i = 0; i < 4; i++, dest_ptr++) { + u8 pval = hflip ? (tilepix >> (24 - i * 8)) : (tilepix >> (i * 8)); + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = pal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_attr; // Add combine flags + else if (rdtype == STCKCOLOR) { + if (*dest_ptr & 0x100) + *dest_ptr = pval | px_attr | ((*dest_ptr) & 0xFFFF0000); + else + *dest_ptr = pval | px_attr | ((*dest_ptr) << 16); + } else if (rdtype == PIXCOPY) + *dest_ptr = dest_ptr[DISPLAY_WIDTH]; + } + } + } else + dest_ptr += 4; + } + } else { + u32 tilepix = eswap32(*(u32 *)tile_ptr); + if (tilepix) { // Can skip all pixels if the row is just transparent + for (u32 i = 0; i < 8; i++, dest_ptr++) { + u8 pval = (hflip ? (tilepix >> ((7 - i) * 4)) : (tilepix >> (i * 4))) & 0xF; + const u16 *subpal = &pal[palette]; + if (pval) { + if (rdtype == FULLCOLOR) + *dest_ptr = subpal[pval]; + else if (rdtype == INDXCOLOR) + *dest_ptr = pval | px_attr; + else if (rdtype == STCKCOLOR) { // Stack background, replace sprite + if (*dest_ptr & 0x100) + *dest_ptr = pval | px_attr | ((*dest_ptr) & 0xFFFF0000); + else + *dest_ptr = pval | px_attr | ((*dest_ptr) << 16); + } else if (rdtype == PIXCOPY) + *dest_ptr = dest_ptr[DISPLAY_WIDTH]; + } + } + } + } +} + +// Renders a regular sprite (non-affine) row to screen. +// delta_x is the object X coordinate referenced from the window start. +// cnt is the maximum number of pixels to draw, honoring window, obj width, etc. +template +static void render_object(s32 delta_x, u32 cnt, stype *dst_ptr, u32 tile_offset, u32 px_comb, u16 palette, const u16 *palptr) +{ + // Tile size in bytes for each mode + const u32 tile_bsize = is8bpp ? tile_size_8bpp : tile_size_4bpp; + // Number of bytes to advance (or rewind) on the tile map + const s32 tile_size_off = hflip ? -tile_bsize : tile_bsize; + + if (delta_x < 0) { // Left part is outside of the screen/window. + u32 offx = -delta_x; // How many pixels did we skip from the object? + s32 block_off = offx / 8; + u32 tile_off = offx % 8; + + // Skip the first object tiles (skips in the flip direction) + tile_offset += block_off * tile_size_off; + + // Render a partial tile to the left + if (tile_off) { + u32 residual = 8 - tile_off; // Pixel count to complete the first tile + u32 maxpix = MIN(residual, cnt); + render_obj_part_tile_Nbpp(px_comb, dst_ptr, tile_off, tile_off + maxpix, tile_offset, palette, + palptr); + + // Move to the next tile + tile_offset += tile_size_off; + // Account for drawn pixels + cnt -= maxpix; + dst_ptr += maxpix; + } + } else { + // Render object completely from the left. Skip the empty space to the left + dst_ptr += delta_x; + } + + // Render full tiles to the scan line. + s32 num_tiles = cnt / 8; + while (num_tiles--) { + // Render full tiles + render_obj_tile_Nbpp(px_comb, dst_ptr, tile_offset, palette, palptr); + tile_offset += tile_size_off; + dst_ptr += 8; + } + + // Render any partial tile on the end + cnt = cnt % 8; + if (cnt) + render_obj_part_tile_Nbpp(px_comb, dst_ptr, 0, cnt, tile_offset, palette, palptr); +} + +// A slower version of the version above, that renders objects pixel by pixel. +// This allows proper mosaic effects whenever necessary. +template +static void render_object_mosaic(s32 delta_x, u32 cnt, stype *dst_ptr, u32 base_tile_offset, u32 mosh, u32 px_comb, u16 palette, + const u16 *pal) +{ + const u32 tile_bsize = is8bpp ? tile_size_8bpp : tile_size_4bpp; + const s32 tile_size_off = hflip ? -tile_bsize : tile_bsize; + + u32 offx = 0; + if (delta_x < 0) { // Left part is outside of the screen/window. + offx = -delta_x; // Number of skipped pixels + } else { + dst_ptr += delta_x; + } + + u32 px_attr = px_comb | palette | 0x100; // Combine flags + high palette bit + + u8 pval = 0; + for (u32 i = 0; i < cnt; i++, offx++, dst_ptr++) { + if (!(i % mosh)) { + // Load tile pixel color. + u32 tile_offset = base_tile_offset + (offx / 8) * tile_size_off; + const u8 *tile_ptr = &VRAM[0x10000 + (tile_offset & 0x7FFF)]; + + // Lookup for each mode and flip value. + if (is8bpp) { + if (hflip) + pval = tile_ptr[7 - offx % 8]; + else + pval = tile_ptr[offx % 8]; + } else { + if (hflip) + pval = (tile_ptr[(7 - offx % 8) >> 1] >> (((offx & 1) ^ 1) * 4)) & 0xF; + else + pval = (tile_ptr[(offx % 8) >> 1] >> ((offx & 1) * 4)) & 0xF; + } + } + + // Write the pixel value as required + const u16 *subpal = &pal[palette]; + if (pval) { + if (rdtype == FULLCOLOR) + *dst_ptr = is8bpp ? pal[pval] : subpal[pval]; + else if (rdtype == INDXCOLOR) + *dst_ptr = pval | px_attr; // Add combine flags + else if (rdtype == STCKCOLOR) { + if (*dst_ptr & 0x100) + *dst_ptr = pval | px_attr | ((*dst_ptr) & 0xFFFF0000); + else + *dst_ptr = pval | px_attr | ((*dst_ptr) << 16); + } else if (rdtype == PIXCOPY) + *dst_ptr = dst_ptr[DISPLAY_WIDTH]; + } + } +} + +// Renders an affine sprite row to screen. +// They support 4bpp and 8bpp modes. 1D and 2D tile mapping modes. +// Their render area is limited to their size (and optionally double size) +template +static void render_affine_object(const t_sprite *obji, const t_affp *affp, bool is_double, u32 start, u32 end, stype *dst_ptr, u32 mosv, + u32 mosh, u32 base_tile, u32 pxcomb, u16 palette, const u16 *palptr) +{ + // Tile size in bytes for each mode + const u32 tile_bsize = is8bpp ? tile_size_8bpp : tile_size_4bpp; + const u32 tile_bwidth = is8bpp ? tile_width_8bpp : tile_width_4bpp; + + // Affine params + s32 dx = (s16)eswap16(affp->dx); + s32 dy = (s16)eswap16(affp->dy); + s32 dmx = (s16)eswap16(affp->dmx); + s32 dmy = (s16)eswap16(affp->dmy); + + // Object dimensions and boundaries + u32 obj_dimw = obji->obj_w; + u32 obj_dimh = obji->obj_h; + s32 middle_x = is_double ? obji->obj_w : (obji->obj_w / 2); + s32 middle_y = is_double ? obji->obj_h : (obji->obj_h / 2); + s32 obj_width = is_double ? obji->obj_w * 2 : obji->obj_w; + s32 obj_height = is_double ? obji->obj_h * 2 : obji->obj_h; + + s32 vcount = read_ioreg(REG_ADDR_VCOUNT); + if (mosaic) + vcount -= vcount % mosv; + s32 y_delta = vcount - (obji->obj_y + middle_y); + + if (obji->obj_x < (signed)start) + middle_x -= (start - obji->obj_x); + s32 source_x = (obj_dimw << 7) + (y_delta * dmx) - (middle_x * dx); + s32 source_y = (obj_dimh << 7) + (y_delta * dmy) - (middle_x * dy); + + // Early optimization if Y-coord is out completely for this line. + // (if there's no rotation Y coord remains identical throughout the line). + if (!rotate && ((u32)(source_y >> 8)) >= (u32)obj_height) + return; + + u32 d_start = MAX((signed)start, obji->obj_x); + u32 d_end = MIN((signed)end, obji->obj_x + obj_width); + u32 cnt = d_end - d_start; + dst_ptr += d_start; + + bool obj1dmap = read_ioreg(REG_ADDR_DISPCNT) & 0x40; + const u32 tile_pitch = obj1dmap ? (obj_dimw / 8) * tile_bsize : 1024; + u32 px_attr = pxcomb | palette | 0x100; // Combine flags + high palette bit + + // Skip pixels outside of the sprite area, until we reach the sprite "inside" + while (cnt) { + u32 pixel_x = (u32)(source_x >> 8), pixel_y = (u32)(source_y >> 8); + + // Stop once we find a pixel that is actually *inside* the map. + if (pixel_x < obj_dimw && pixel_y < obj_dimh) + break; + + dst_ptr++; + source_x += dx; + if (rotate) + source_y += dy; + cnt--; + } + + // Draw sprite pixels by looking them up first. Lookup address is tricky! + u8 pixval = 0; + for (u32 i = 0; i < cnt; i++) { + u32 pixel_x = (u32)(source_x >> 8), pixel_y = (u32)(source_y >> 8); + + // Check if we run out of the sprite, then we can safely abort. + if (pixel_x >= obj_dimw || pixel_y >= obj_dimh) + return; + + // For mosaic, we "remember" the last looked up pixel. + if (!mosaic || !(i % mosh)) { + // Lookup pixel and draw it. + if (is8bpp) { + // We lookup the byte directly and render it. + const u32 tile_off = base_tile + // Character base + ((pixel_y >> 3) * tile_pitch) + // Skip vertical blocks + ((pixel_x >> 3) * tile_bsize) + // Skip horizontal blocks + ((pixel_y & 0x7) * tile_bwidth) + // Skip vertical rows to the pixel + (pixel_x & 0x7); // Skip the horizontal offset + + pixval = *(OBJ_VRAM0 + (tile_off & 0x7FFF)); // Read pixel value! + } else { + const u32 tile_off = base_tile + // Character base + ((pixel_y >> 3) * tile_pitch) + // Skip vertical blocks + ((pixel_x >> 3) * tile_bsize) + // Skip horizontal blocks + ((pixel_y & 0x7) * tile_bwidth) + // Skip vertical rows to the pixel + ((pixel_x >> 1) & 0x3); // Skip the horizontal offset + + u8 pixpair = *(OBJ_VRAM0 + (tile_off & 0x7FFF)); // Read 2 pixels @4bpp + pixval = ((pixel_x & 1) ? pixpair >> 4 : pixpair & 0xF); + } + } + + // Render the pixel value + if (pixval) { + if (rdtype == FULLCOLOR) + *dst_ptr = palptr[pixval | palette]; + else if (rdtype == INDXCOLOR) + *dst_ptr = pixval | px_attr; // Add combine flags + else if (rdtype == STCKCOLOR) { + // Stack pixels on top of the pixel value and combine flags + if (*dst_ptr & 0x100) + *dst_ptr = pixval | px_attr | ((*dst_ptr) & 0xFFFF0000); + else + *dst_ptr = pixval | px_attr | ((*dst_ptr) << 16); // Stack pixels + } else if (rdtype == PIXCOPY) + *dst_ptr = dst_ptr[DISPLAY_WIDTH]; + } + + // Move to the next pixel, update coords accordingly + dst_ptr++; + source_x += dx; + if (rotate) + source_y += dy; + } +} + +// Renders a single sprite on the current scanline. +// This function calls the affine or regular renderer depending on the sprite. +// Will calculate whether sprite has certain effects (flip, rotation ...) to +// use an optimized renderer function. +template +inline static void render_sprite(const t_sprite *obji, bool is_affine, u32 start, u32 end, stype *scanline, u32 pxcomb, const u16 *palptr) +{ + s32 vcount = read_ioreg(REG_ADDR_VCOUNT); + bool obj1dmap = read_ioreg(REG_ADDR_DISPCNT) & 0x40; + u32 tile = obji->oam_data->split.tileNum; + if (is8bpp && !obj1dmap) { + tile &= ~1; + } + u32 base_tile = tile * 32; + + const u32 mosv = (mosaic ? (read_ioreg(REG_ADDR_MOSAIC) >> 12) & 0xF : 0) + 1; + const u32 mosh = (mosaic ? (read_ioreg(REG_ADDR_MOSAIC) >> 8) & 0xF : 0) + 1; + + // Render the object scanline using the correct mode. + // (in 4bpp mode calculate the palette number) + // Objects use the higher palette part + u16 pal = (is8bpp ? 0 : (obji->oam_data->split.paletteNum << 4)); + + if (is_affine) { + u32 pnum = obji->oam_data->split.matrixNum; + const t_affp *affp_base = (t_affp *)OAM; + const t_affp *affp = &affp_base[pnum]; + + if (affp->dy == 0) // No rotation happening (just scale) + render_affine_object(obji, affp, obji->is_double, start, end, scanline, mosv, mosh, + base_tile, pxcomb, pal, palptr); + else // Full rotation and scaling + render_affine_object(obji, affp, obji->is_double, start, end, scanline, mosv, mosh, + base_tile, pxcomb, pal, palptr); + } else { + // The object could be out of the window, check and skip. + if (obji->obj_x >= (signed)end || obji->obj_x + obji->obj_w <= (signed)start) + return; + + // Non-affine objects can be flipped on both edges. + bool hflip = (obji->oam_data->split.matrixNum >> 3) & 1; + bool vflip = (obji->oam_data->split.matrixNum >> 4) & 1; + + // Calulate the vertical offset (row) to be displayed. Account for vflip. + u32 voffset = vflip ? obji->obj_y + obji->obj_h - vcount - 1 : vcount - obji->obj_y; + if (mosaic) + voffset -= voffset % mosv; + + // Calculate base tile for the object (points to the row to be drawn). + u32 tile_bsize = is8bpp ? tile_size_8bpp : tile_size_4bpp; + u32 tile_bwidth = is8bpp ? tile_width_8bpp : tile_width_4bpp; + u32 obj_pitch = obj1dmap ? (obji->obj_w / 8) * tile_bsize : 1024; + u32 hflip_off = hflip ? ((obji->obj_w / 8) - 1) * tile_bsize : 0; + + // Calculate the pointer to the tile. + const u32 tile_offset = base_tile + // Char offset + (voffset / 8) * obj_pitch + // Select tile row offset + (voffset % 8) * tile_bwidth + // Skip tile rows + hflip_off; // Account for horizontal flip + + // Make everything relative to start + s32 obj_x_offset = obji->obj_x - start; + u32 clipped_width = obj_x_offset >= 0 ? obji->obj_w : obji->obj_w + obj_x_offset; + u32 max_range = obj_x_offset >= 0 ? end - obji->obj_x : end - start; + u32 max_draw = MIN(max_range, clipped_width); + + if (mosaic && mosh > 1) { + if (hflip) + render_object_mosaic(obj_x_offset, max_draw, &scanline[start], tile_offset, mosh, pxcomb, pal, + palptr); + else + render_object_mosaic(obj_x_offset, max_draw, &scanline[start], tile_offset, mosh, pxcomb, pal, + palptr); + } else { + if (hflip) + render_object(obj_x_offset, max_draw, &scanline[start], tile_offset, pxcomb, pal, palptr); + else + render_object(obj_x_offset, max_draw, &scanline[start], tile_offset, pxcomb, pal, palptr); + } + } +} + +// Renders objects on a scanline for a given priority. +// This function assumes that order_obj has been called to prepare the objects. +template void render_scanline_objs(u32 priority, u32 start, u32 end, void *raw_ptr, const u16 *palptr) +{ + stype *scanline = (stype *)raw_ptr; + s32 vcount = read_ioreg(REG_ADDR_VCOUNT); + s32 objn; + u32 objcnt = obj_priority_count[priority][vcount]; + u8 *objlist = obj_priority_list[priority][vcount]; + + // Render all the visible objects for this priority (back to front) + for (objn = objcnt - 1; objn >= 0; objn--) { + // Objects in the list are pre-filtered and sorted in the appropriate order + u32 objoff = objlist[objn]; + const OamData *oam_data = (OamData *)&OAM[objoff * OAM_DATA_SIZE_AFFINE]; + + u16 obj_shape = oam_data->split.shape; + u16 obj_size = oam_data->split.size; + bool is_affine = oam_data->split.affineMode & 1; + bool is_trans = oam_data->split.objMode == OBJ_MOD_SEMITRAN; + s32 obj_x = oam_data->split.x; + s32 obj_y = oam_data->split.y; +#if !EXTENDED_OAM + if (obj_x > DISPLAY_WIDTH) + obj_x -= 512; +#endif + + t_sprite obji = { + .obj_x = obj_x, + .obj_y = obj_y, + .obj_w = obj_dim_table[obj_shape][obj_size][0], + .obj_h = obj_dim_table[obj_shape][obj_size][1], + .oam_data = oam_data, + .is_double = !!((oam_data->split.affineMode >> 1) & 1), + }; + + s32 obj_maxw = (is_affine && obji.is_double) ? obji.obj_w * 2 : obji.obj_w; + + // The object could be out of the window, check and skip. + if (obji.obj_x >= (signed)end || obji.obj_x + obj_maxw <= (signed)start) + continue; + + // ST-OBJs force 1st target bit (forced blending) + bool forcebld = is_trans && rdtype != FULLCOLOR; +#if !EXTENDED_OAM + if (obji.obj_y > DISPLAY_HEIGHT) + obji.obj_y -= 256; +#endif + // In PIXCOPY mode, we have already some stuff rendered (winout) and now + // we render the "win-in" area for this object. The PIXCOPY function will + // copy (merge) the two pixels depending on the result of the sprite render + // The temporary buffer is rendered on the next scanline area. + if (rdtype == PIXCOPY) { + u32 sec_start = MAX((signed)start, obji.obj_x); + u32 sec_end = MIN((signed)end, obji.obj_x + obj_maxw); + u32 obj_enable = read_ioreg(REG_ADDR_WINOUT) >> 8; + + // Render at the next scanline! + u16 *tmp_ptr = (u16 *)&scanline[GBA_SCREEN_PITCH]; + render_scanline_conditional(sec_start, sec_end, tmp_ptr, obj_enable); + } + + // Calculate combine masks. These store 2 bits of info: 1st and 2nd target. + // If set, the current pixel belongs to a layer that is 1st or 2nd target. + // For ST-objs, we set an extra bit, for later blending. + u32 pxcomb = (forcebld ? 0x800 : 0) | color_flags(4); + + bool emosaic = oam_data->split.mosaic; + bool is_8bpp = oam_data->split.bpp; + + // Some games enable mosaic but set it to size 0 (1), so ignore. + const u32 mosreg = read_ioreg(REG_ADDR_MOSAIC) & 0xFF00; + + if (emosaic && mosreg) { + if (is_8bpp) + render_sprite(&obji, is_affine, start, end, scanline, pxcomb, palptr); + else + render_sprite(&obji, is_affine, start, end, scanline, pxcomb, palptr); + } else { + if (is_8bpp) + render_sprite(&obji, is_affine, start, end, scanline, pxcomb, palptr); + else + render_sprite(&obji, is_affine, start, end, scanline, pxcomb, palptr); + } + } +} + +int sprite_limit = 0; + +// Goes through the object list in the OAM (from #127 to #0) and adds objects +// into a sorted list by priority for the current row. +// Invisible objects are discarded. ST-objects are flagged. Cycle counting is +// performed to discard excessive objects (to match HW capabilities). +static void order_obj(u32 video_mode) +{ + u32 obj_num; + u32 row; + u16 rend_cycles[DISPLAY_HEIGHT]; + + bool hblank_free = read_ioreg(REG_ADDR_DISPCNT) & 0x20; + u16 max_rend_cycles = !sprite_limit ? REND_CYC_MAX : hblank_free ? REND_CYC_REDUCED : REND_CYC_SCANLINE; + + memset(obj_priority_count, 0, sizeof(obj_priority_count)); + memset(obj_alpha_count, 0, sizeof(obj_alpha_count)); + memset(rend_cycles, 0, sizeof(rend_cycles)); + + for (obj_num = 0; obj_num < 128; obj_num++) { + const OamData *oam_data = (OamData *)&OAM[obj_num * OAM_DATA_SIZE_AFFINE]; + + // Bit 9 disables regular sprites (that is, non-affine ones). + if (oam_data->split.affineMode == 2) + continue; + + u16 obj_shape = oam_data->split.shape; + u32 obj_mode = oam_data->split.objMode; + + // Prohibited shape and mode + if ((obj_shape == 0x3) || (obj_mode == OBJ_MOD_INVALID)) + continue; + + // On bitmap modes, objs 0-511 are not usable, ingore them. + if ((video_mode >= 3) && (!(oam_data->split.tileNum & 0x200))) + continue; + + // Calculate object size (from size and shape attr bits) + u16 obj_size = oam_data->split.size; + s32 obj_height = obj_dim_table[obj_shape][obj_size][1]; + s32 obj_width = obj_dim_table[obj_shape][obj_size][0]; + s32 obj_y = oam_data->split.y; + +#if !EXTENDED_OAM + if (obj_y > DISPLAY_HEIGHT) + obj_y -= 256; +#endif + // Double size for affine sprites with double bit set + if ((oam_data->split.affineMode >> 1) & 1) { + obj_height *= 2; + obj_width *= 2; + } + + if (((obj_y + obj_height) > 0) && (obj_y < DISPLAY_HEIGHT)) { + s32 obj_x = oam_data->split.x; + +#if !EXTENDED_OAM + if (obj_x > DISPLAY_WIDTH) + obj_x -= 512; +#endif + if (((obj_x + obj_width) > 0) && (obj_x < DISPLAY_WIDTH)) { + u32 obj_priority = oam_data->split.priority; + bool is_affine = oam_data->split.affineMode & 1; + // Clip Y coord and height to the 0..159 interval + u32 starty = MAX(obj_y, 0); + u32 endy = MIN(obj_y + obj_height, DISPLAY_HEIGHT); + + // Calculate needed cycles to render the sprite + u16 cyccnt = is_affine ? (10 + obj_width * 2) : obj_width; + + switch (obj_mode) { + case OBJ_MOD_SEMITRAN: + for (row = starty; row < endy; row++) { + if (rend_cycles[row] < max_rend_cycles) { + u32 cur_cnt = obj_priority_count[obj_priority][row]; + obj_priority_list[obj_priority][row][cur_cnt] = obj_num; + obj_priority_count[obj_priority][row] = cur_cnt + 1; + rend_cycles[row] += cyccnt; + // Mark the row as having semi-transparent objects + obj_alpha_count[row] = 1; + } + } + break; + case OBJ_MOD_WINDOW: + obj_priority = 4; + /* fallthrough */ + case OBJ_MOD_NORMAL: + // Add the object to the list. + for (row = starty; row < endy; row++) { + if (rend_cycles[row] < max_rend_cycles) { + u32 cur_cnt = obj_priority_count[obj_priority][row]; + obj_priority_list[obj_priority][row][cur_cnt] = obj_num; + obj_priority_count[obj_priority][row] = cur_cnt + 1; + rend_cycles[row] += cyccnt; + } + } + break; + }; + } + } + } +} + +u32 layer_order[16]; +u32 layer_count; + +// Sorts active BG/OBJ layers and generates an ordered list of layers. +// Things are drawn back to front, so lowest priority goes first. +static void order_layers(u32 layer_flags, u32 vcnt) +{ + bool obj_enabled = (layer_flags & 0x10); + s32 priority; + + layer_count = 0; + + for (priority = 3; priority >= 0; priority--) { + bool anyobj = obj_priority_count[priority][vcnt] > 0; + s32 lnum; + + for (lnum = 3; lnum >= 0; lnum--) { + if (((layer_flags >> lnum) & 1) && ((read_ioreg(REG_ADDR_BGxCNT(lnum)) & 0x03) == priority)) { + layer_order[layer_count++] = lnum; + } + } + + if (obj_enabled && anyobj) + layer_order[layer_count++] = priority | 0x04; + } +} + +// Blending is performed by separating an RGB value into 0G0R0B (32 bit) +// Since blending factors are at most 16, mult/add operations do not overflow +// to the neighbouring color and can be performed much faster than separatedly + +// Here follow the mask value to separate/expand the color to 32 bit, +// the mask to detect overflows in the blend operation and + +#define BLND_MSK (SATR_MSK | SATG_MSK | SATB_MSK) + +#define OVFG_MSK 0x04000000 +#define OVFR_MSK 0x00008000 +#define OVFB_MSK 0x00000020 +#define SATG_MSK 0x03E00000 +#define SATR_MSK 0x00007C00 +#define SATB_MSK 0x0000001F + +typedef enum { + OBJ_BLEND, // No effects, just blend forced-blend pixels (ie. ST objects) + BLEND_ONLY, // Just alpha blending (if the pixels are 1st and 2nd target) + BLEND_BRIGHT, // Perform alpha blending if appropiate, and brighten otherwise + BLEND_DARK, // Same but with darken effecg +} blendtype; + +// Applies blending (and optional brighten/darken) effect to a bunch of +// color-indexed pixel pairs. Depending on the mode and the pixel target +// number, blending, darken/brighten or no effect will be applied. +// Bits 0-8 encode the color index (paletted colors) +// Bit 9 is set if the pixel belongs to a 1st target layer +// Bit 10 is set if the pixel belongs to a 2nd target layer +// Bit 11 is set if the pixel belongs to a ST-object +template static void merge_blend(u32 start, u32 end, u16 *dst, u32 *src) +{ + u32 bldalpha = read_ioreg(REG_ADDR_BLDALPHA); + u32 brightf = MIN(16, read_ioreg(REG_ADDR_BLDY) & 0x1F); + u32 blend_a = MIN(16, (bldalpha >> 0) & 0x1F); + u32 blend_b = MIN(16, (bldalpha >> 8) & 0x1F); + + bool can_saturate = blend_a + blend_b > 16; + + if (can_saturate) { + // If blending can result in saturation, we need to clamp output values. + while (start < end) { + u32 pixpair = src[start]; + // If ST-OBJ, force blending mode (has priority over other effects). + // If regular blending mode, blend if 1st/2nd bits are set respectively. + // Otherwise, apply other color effects if 1st bit is set. + bool force_blend = (pixpair & 0x04000800) == 0x04000800; + bool do_blend = (pixpair & 0x04000200) == 0x04000200; + if ((st_objs && force_blend) || (do_blend && bldtype == BLEND_ONLY)) { + // Top pixel is 1st target, pixel below is 2nd target. Blend! + u16 p1 = PLTT[(pixpair >> 0) & 0x1FF]; + u16 p2 = PLTT[(pixpair >> 16) & 0x1FF]; + u32 p1e = (p1 | (p1 << 16)) & BLND_MSK; + u32 p2e = (p2 | (p2 << 16)) & BLND_MSK; + u32 pfe = (((p1e * blend_a) + (p2e * blend_b)) >> 4); + + // If the overflow bit is set, saturate (set) all bits to one. + if (pfe & (OVFR_MSK | OVFG_MSK | OVFB_MSK)) { + if (pfe & OVFG_MSK) + pfe |= SATG_MSK; + if (pfe & OVFR_MSK) + pfe |= SATR_MSK; + if (pfe & OVFB_MSK) + pfe |= SATB_MSK; + } + pfe &= BLND_MSK; + dst[start++] = (pfe >> 16) | pfe; + } else if ((bldtype == BLEND_DARK || bldtype == BLEND_BRIGHT) && (pixpair & 0x200) == 0x200) { + // Top pixel is 1st-target, can still apply bright/dark effect. + u16 pidx = PLTT[pixpair & 0x1FF]; + u32 epixel = (pidx | (pidx << 16)) & BLND_MSK; + u32 pa = bldtype == BLEND_DARK ? 0 : ((BLND_MSK * brightf) >> 4) & BLND_MSK; + u32 pb = ((epixel * (16 - brightf)) >> 4) & BLND_MSK; + epixel = (pa + pb) & BLND_MSK; + dst[start++] = (epixel >> 16) | epixel; + } else { + dst[start++] = PLTT[pixpair & 0x1FF]; // No effects + } + } + } else { + while (start < end) { + u32 pixpair = src[start]; + bool do_blend = (pixpair & 0x04000200) == 0x04000200; + bool force_blend = (pixpair & 0x04000800) == 0x04000800; + if ((st_objs && force_blend) || (do_blend && bldtype == BLEND_ONLY)) { + // Top pixel is 1st target, pixel below is 2nd target. Blend! + u16 p1 = PLTT[(pixpair >> 0) & 0x1FF]; + u16 p2 = PLTT[(pixpair >> 16) & 0x1FF]; + u32 p1e = (p1 | (p1 << 16)) & BLND_MSK; + u32 p2e = (p2 | (p2 << 16)) & BLND_MSK; + u32 pfe = (((p1e * blend_a) + (p2e * blend_b)) >> 4) & BLND_MSK; + dst[start++] = (pfe >> 16) | pfe; + } else if ((bldtype == BLEND_DARK || bldtype == BLEND_BRIGHT) && (pixpair & 0x200) == 0x200) { + // Top pixel is 1st-target, can still apply bright/dark effect. + u16 pidx = PLTT[pixpair & 0x1FF]; + u32 epixel = (pidx | (pidx << 16)) & BLND_MSK; + u32 pa = bldtype == BLEND_DARK ? 0 : ((BLND_MSK * brightf) >> 4) & BLND_MSK; + u32 pb = ((epixel * (16 - brightf)) >> 4) & BLND_MSK; + epixel = (pa + pb) & BLND_MSK; + dst[start++] = (epixel >> 16) | epixel; + } else { + dst[start++] = PLTT[pixpair & 0x1FF]; // No effects + } + } + } +} + +// Applies brighten/darken effect to a bunch of color-indexed pixels. +template static void merge_brightness(u32 start, u32 end, u16 *srcdst) +{ + u32 brightness = MIN(16, read_ioreg(REG_ADDR_BLDY) & 0x1F); + + while (start < end) { + u16 spix = srcdst[start]; + u16 pixcol = PLTT[spix & 0x1FF]; + + if ((spix & 0x200) == 0x200) { + // Pixel is 1st target, can apply color effect. + u32 epixel = (pixcol | (pixcol << 16)) & BLND_MSK; + u32 pa = bldtype == BLEND_DARK ? 0 : ((BLND_MSK * brightness) >> 4) & BLND_MSK; // B/W + u32 pb = ((epixel * (16 - brightness)) >> 4) & BLND_MSK; // Pixel color + epixel = (pa + pb) & BLND_MSK; + pixcol = (epixel >> 16) | epixel; + } + + srcdst[start++] = pixcol; + } +} + +// Fills a segment using the backdrop color (in the right mode). +template void fill_line_background(u32 start, u32 end, dsttype *scanline) +{ + dsttype bgcol = PLTT[0]; + u16 bg_comb = color_flags(5); + while (start < end) + if (rdmode == FULLCOLOR) + scanline[start++] = bgcol; + else + scanline[start++] = 0 | bg_comb; +} + +// Renders the backdrop color (ie. whenever no layer is active) applying +// any effects that might still apply (usually darken/brighten). +static void render_backdrop(u32 start, u32 end, u16 *scanline) +{ + u16 bldcnt = read_ioreg(REG_ADDR_BLDCNT); + u16 pixcol = PLTT[0]; + u32 effect = (bldcnt >> 6) & 0x03; + u32 bd_1st_target = ((bldcnt >> 0x5) & 0x01); + + if (bd_1st_target && effect == COL_EFFECT_BRIGHT) { + u32 brightness = MIN(16, read_ioreg(REG_ADDR_BLDY) & 0x1F); + + // Unpack 16 bit pixel for fast blending operation + u32 epixel = (pixcol | (pixcol << 16)) & BLND_MSK; + u32 pa = ((BLND_MSK * brightness) >> 4) & BLND_MSK; // White color + u32 pb = ((epixel * (16 - brightness)) >> 4) & BLND_MSK; // Pixel color + epixel = (pa + pb) & BLND_MSK; + pixcol = (epixel >> 16) | epixel; + } else if (bd_1st_target && effect == COL_EFFECT_DARK) { + u32 brightness = MIN(16, read_ioreg(REG_ADDR_BLDY) & 0x1F); + u32 epixel = (pixcol | (pixcol << 16)) & BLND_MSK; + epixel = ((epixel * (16 - brightness)) >> 4) & BLND_MSK; // Pixel color + pixcol = (epixel >> 16) | epixel; + } + + // Fill the line with that color + while (start < end) + scanline[start++] = pixcol; +} + +// Renders all the available and enabled layers (in tiled mode). +// Walks the list of layers in visibility order and renders them in the +// specified mode (taking into consideration the first layer, etc). +template +void tile_render_layers(u32 start, u32 end, dsttype *dst_ptr, u32 enabled_layers) +{ + u32 lnum; + u32 base_done = 0; + u16 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u16 video_mode = dispcnt & 0x07; + bool obj_enabled = (enabled_layers & 0x10); // Objects are visible + + bool objlayer_is_1st_tgt = ((read_ioreg(REG_ADDR_BLDCNT) >> 4) & 1) != 0; + bool has_trans_obj = obj_alpha_count[read_ioreg(REG_ADDR_VCOUNT)]; + + for (lnum = 0; lnum < layer_count; lnum++) { + u32 layer = layer_order[lnum]; + bool is_obj = layer & 0x4; + if (is_obj && obj_enabled) { + bool can_skip_blend = !has_trans_obj && !objlayer_is_1st_tgt; + + // If it's the first layer, make sure to fill with backdrop color. + if (!base_done) + fill_line_background(start, end, dst_ptr); + + // Optimization: skip blending mode if no blending can happen to this layer + if (objmode == STCKCOLOR && can_skip_blend) + render_scanline_objs(layer & 0x3, start, end, dst_ptr, &PLTT[0x100]); + else + render_scanline_objs(layer & 0x3, start, end, dst_ptr, &PLTT[0x100]); + + base_done = 1; + } else if (!is_obj && ((1 << layer) & enabled_layers)) { + bool layer_is_1st_tgt = ((read_ioreg(REG_ADDR_BLDCNT) >> layer) & 1) != 0; + bool can_skip_blend = !has_trans_obj && !layer_is_1st_tgt; + + bool is_affine = (video_mode >= 1) && (layer >= 2); + u32 fnidx = (base_done) | (is_affine ? 2 : 0); + + // Can optimize rendering if no blending can really happen. + // If stack mode, no blending and not base layer, we might speed up a bit + if (bgmode == STCKCOLOR && can_skip_blend) { + static const tile_render_function rdfns[4] = { + render_scanline_text, + render_scanline_text, + render_scanline_affine, + render_scanline_affine, + }; + rdfns[fnidx](layer, start, end, dst_ptr, PLTT); + } else { + static const tile_render_function rdfns[4] = { + render_scanline_text, + render_scanline_text, + render_scanline_affine, + render_scanline_affine, + }; + rdfns[fnidx](layer, start, end, dst_ptr, PLTT); + } + + base_done = 1; + } + } + + // Render background if we did not render any active layer. + if (!base_done) + fill_line_background(start, end, dst_ptr); +} + +// Renders all layers honoring color effects (blending, brighten/darken). +// It uses different rendering routines depending on the coloring effect +// requirements, speeding up common cases where no effects are used. + +// No effects use NORMAL mode (RBB565 color is written on the buffer). +// For blending, we use BLEND mode to record the two top-most pixels. +// For other effects we use COLOR16, which records an indexed color in the +// buffer (used for darken/brighten effects at later passes) or COLOR32, +// which similarly uses an indexed color for rendering but recording one +// color for the background and another one for the object layer. + +static void render_w_effects(u32 start, u32 end, u16 *scanline, u32 enable_flags, const layer_render_struct *renderers) +{ + bool effects_enabled = enable_flags & 0x20; // Window bit for effects. + bool obj_blend = obj_alpha_count[read_ioreg(REG_ADDR_VCOUNT)] > 0; + u16 bldcnt = read_ioreg(REG_ADDR_BLDCNT); + + // If the window bits disable effects, default to NONE + u32 effect_type = effects_enabled ? ((bldcnt >> 6) & 0x03) : COL_EFFECT_NONE; + + switch (effect_type) { + case COL_EFFECT_BRIGHT: { + // If no layers are 1st target, no effect will really happen. + bool some_1st_tgt = (read_ioreg(REG_ADDR_BLDCNT) & 0x3F) != 0; + // If the factor is zero, it's the same as "regular" rendering. + bool non_zero_blend = (read_ioreg(REG_ADDR_BLDY) & 0x1F) != 0; + if (some_1st_tgt && non_zero_blend) { + if (obj_blend) { + u32 tmp_buf[DISPLAY_WIDTH]; + renderers->indexed_u32(start, end, tmp_buf, enable_flags); + merge_blend(start, end, scanline, tmp_buf); + } else { + renderers->indexed_u16(start, end, scanline, enable_flags); + merge_brightness(start, end, scanline); + } + return; + } + } break; + + case COL_EFFECT_DARK: { + // If no layers are 1st target, no effect will really happen. + bool some_1st_tgt = (read_ioreg(REG_ADDR_BLDCNT) & 0x3F) != 0; + // If the factor is zero, it's the same as "regular" rendering. + bool non_zero_blend = (read_ioreg(REG_ADDR_BLDY) & 0x1F) != 0; + if (some_1st_tgt && non_zero_blend) { + if (obj_blend) { + u32 tmp_buf[DISPLAY_WIDTH]; + renderers->indexed_u32(start, end, tmp_buf, enable_flags); + merge_blend(start, end, scanline, tmp_buf); + } else { + renderers->indexed_u16(start, end, scanline, enable_flags); + merge_brightness(start, end, scanline); + } + return; + } + } break; + + case COL_EFFECT_BLEND: { + // If no layers are 1st or 2nd target, no effect will really happen. + bool some_1st_tgt = (read_ioreg(REG_ADDR_BLDCNT) & 0x003F) != 0; + bool some_2nd_tgt = (read_ioreg(REG_ADDR_BLDCNT) & 0x3F00) != 0; + // If 1st target is 100% opacity and 2nd is 0%, just render regularly. + bool non_trns_tgt = (read_ioreg(REG_ADDR_BLDALPHA) & 0x1F1F) != 0x001F; + if (some_1st_tgt && some_2nd_tgt && non_trns_tgt) { + u32 tmp_buf[DISPLAY_WIDTH]; + renderers->stacked(start, end, tmp_buf, enable_flags); + if (obj_blend) + merge_blend(start, end, scanline, tmp_buf); + else + merge_blend(start, end, scanline, tmp_buf); + return; + } + } break; + + case COL_EFFECT_NONE: + // Default case, see below. + break; + }; + + // Default rendering mode, without layer effects (except perhaps sprites). + if (obj_blend) { + u32 tmp_buf[DISPLAY_WIDTH]; + renderers->stacked(start, end, tmp_buf, enable_flags); + merge_blend(start, end, scanline, tmp_buf); + } else { + renderers->fullcolor(start, end, scanline, enable_flags); + } +} + +#define bitmap_layer_render_functions(rdmode, dsttype, mode, ttype, w, h) \ + { \ + { \ + render_scanline_bitmap, \ + render_scanline_bitmap, \ + render_scanline_bitmap, \ + }, \ + { \ + render_scanline_bitmap, \ + render_scanline_bitmap, \ + render_scanline_bitmap, \ + } \ + } + +static const bitmap_layer_render_struct idx32_bmrend[3][2] + = { bitmap_layer_render_functions(INDXCOLOR, u32, 3, u16, DISPLAY_WIDTH, DISPLAY_HEIGHT), + bitmap_layer_render_functions(INDXCOLOR, u32, 4, u8, DISPLAY_WIDTH, DISPLAY_HEIGHT), + bitmap_layer_render_functions(INDXCOLOR, u32, 5, u16, DISPLAY_HEIGHT, 128) }; + +// Render the BG and OBJ in a bitmap scanline from start to end ONLY if +// enable_flag allows that layer/OBJ. + +template +static void bitmap_render_layers(u32 start, u32 end, dsttype *scanline, u32 enable_flags) +{ + u16 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + bool has_trans_obj = obj_alpha_count[read_ioreg(REG_ADDR_VCOUNT)]; + bool objlayer_is_1st_tgt = (read_ioreg(REG_ADDR_BLDCNT) & 0x10) != 0; + bool bg2_is_1st_tgt = (read_ioreg(REG_ADDR_BLDCNT) & 0x4) != 0; + + // Fill in the renderers for a layer based on the mode type, + static const bitmap_layer_render_struct renderers[3][2] + = { bitmap_layer_render_functions(bgmode, dsttype, 3, u16, DISPLAY_WIDTH, DISPLAY_HEIGHT), + bitmap_layer_render_functions(bgmode, dsttype, 4, u8, DISPLAY_WIDTH, DISPLAY_HEIGHT), + bitmap_layer_render_functions(bgmode, dsttype, 5, u16, DISPLAY_HEIGHT, 128) }; + + const u32 mosamount = read_ioreg(REG_ADDR_MOSAIC) & 0xFF; + u32 bg_control = read_ioreg(REG_ADDR_BG2CNT); + u32 mmode = ((bg_control & 0x40) && (mosamount != 0)) ? 1 : 0; + + unsigned modeidx = (dispcnt & 0x07) - 3; + const bitmap_layer_render_struct *mode_rend = &renderers[modeidx][mmode]; + const bitmap_layer_render_struct *idxm_rend = &idx32_bmrend[modeidx][mmode]; + + u32 current_layer; + u32 layer_order_pos; + + fill_line_background(start, end, scanline); + + for (layer_order_pos = 0; layer_order_pos < layer_count; layer_order_pos++) { + current_layer = layer_order[layer_order_pos]; + if (current_layer & 0x04) { + if (enable_flags & 0x10) { + bool can_skip_blend = !has_trans_obj && !objlayer_is_1st_tgt; + + // Optimization: skip blending mode if no blending can happen to this layer + if (objmode == STCKCOLOR && can_skip_blend) + render_scanline_objs(current_layer & 3, start, end, scanline, &PLTT[0x100]); + else + render_scanline_objs(current_layer & 3, start, end, scanline, &PLTT[0x100]); + } + } else { + if (enable_flags & 0x04) { + s32 dx = (s16)read_ioreg(REG_ADDR_BG2PA); + s32 dy = (s16)read_ioreg(REG_ADDR_BG2PC); + + // Optimization: Skip stack mode if there's no blending happening. + bool can_skip_blend = !has_trans_obj && !bg2_is_1st_tgt; + const bitmap_layer_render_struct *rd = (bgmode == STCKCOLOR && can_skip_blend) ? idxm_rend : mode_rend; + + if (dy) + rd->affine_render(start, end, scanline, PLTT); + else if (dx == 256) + rd->blit_render(start, end, scanline, PLTT); + else + rd->scale_render(start, end, scanline, PLTT); + } + } + } +} + +static const layer_render_struct tile_mode_renderers = { + .fullcolor = tile_render_layers, + .indexed_u16 = tile_render_layers, + .indexed_u32 = tile_render_layers, + .stacked = tile_render_layers, +}; + +static const layer_render_struct bitmap_mode_renderers = { + .fullcolor = bitmap_render_layers, + .indexed_u16 = bitmap_render_layers, + .indexed_u32 = bitmap_render_layers, + .stacked = bitmap_render_layers, +}; + +// Renders a full scanline, given an enable_flags mask (for which layers and +// effects are enabled). +static void render_scanline_conditional(u32 start, u32 end, u16 *scanline, u32 enable_flags) +{ + u16 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u32 video_mode = dispcnt & 0x07; + + // Check if any layer is actually active. + if (layer_count && (enable_flags & 0x1F)) { + // Color effects currently only supported in indexed-color modes (tiled and mode 4) + if (video_mode < 3) + render_w_effects(start, end, scanline, enable_flags, &tile_mode_renderers); + else if (video_mode == 4) + render_w_effects(start, end, scanline, enable_flags, &bitmap_mode_renderers); + else + // TODO: Implement mode 3 & 5 color effects (at least partially, ie. ST objs) + bitmap_mode_renderers.fullcolor(start, end, scanline, enable_flags); + } else + // Render the backdrop color, since no layers are enabled/visible. + render_backdrop(start, end, scanline); +} + +// Renders the are outside of all active windows +static void render_windowout_pass(u16 *scanline, u32 start, u32 end) +{ + u32 winout = read_ioreg(REG_ADDR_WINOUT); + u32 wndout_enable = winout & 0x3F; + + render_scanline_conditional(start, end, scanline, wndout_enable); +} + +// Renders window-obj. This is a pixel-level windowing effect, based on sprites +// (objects) with a special rendering mode (the sprites are not themselves +// visible but rather "enable" other pixels to be rendered conditionally). +static void render_windowobj_pass(u16 *scanline, u32 start, u32 end) +{ + u32 winout = read_ioreg(REG_ADDR_WINOUT); + u32 wndout_enable = winout & 0x3F; + + // First we render the "window-out" segment. + render_scanline_conditional(start, end, scanline, wndout_enable); + + // Now we render the objects in "copy" mode. This renders the scanline in + // WinObj-mode to a temporary buffer and performs a "copy-mode" render. + // In this mode, we copy pixels from the temp buffer to the final buffer + // whenever an object pixel is rendered. + render_scanline_objs(4, start, end, scanline, NULL); + + // TODO: Evaluate whether it's better to render the whole line and copy, + // or render subsegments and copy as we go (depends on the pixel/obj count) +} + +// If the window Y coordinates are out of the window range we can skip +// rendering the inside of the window. +inline bool in_window_y(u32 vcount, u32 top, u32 bottom) +{ + // TODO: check if these are reversed when top-bottom are also reversed. + if (top > DISPLAY_HEIGHT + 67) // This causes the window to be invisible + return false; + if (bottom > DISPLAY_HEIGHT + 67) // This makes it all visible + return true; + + if (top > bottom) /* Reversed: if not in the "band" */ + return vcount > top || vcount <= bottom; + + return vcount >= top && vcount < bottom; +} + +// Renders window 0/1. Checks boundaries and divides the segment into +// subsegments (if necessary) rendering each one in their right mode. +// outfn is called for "out-of-window" rendering. +template static void render_window_n_pass(u16 *scanline, u32 start, u32 end) +{ + u32 vcount = read_ioreg(REG_ADDR_VCOUNT); + // Check the Y coordinates to check if they fall in the right row + u32 win_top = WIN_GET_LOWER(*(winreg_t *)(REG_ADDR_WINxV(winnum))); + u32 win_bot = WIN_GET_HIGHER(*(winreg_t *)(REG_ADDR_WINxV(winnum))); + // Check the X coordinates and generate up to three segments + // Clip the coordinates to the [start, end) range. + u32 win_lraw = WIN_GET_LOWER(*(winreg_t *)(REG_ADDR_WINxH(winnum))); + u32 win_rraw = WIN_GET_HIGHER(*(winreg_t *)(REG_ADDR_WINxH(winnum))); + u32 win_l = MAX(start, MIN(end, win_lraw)); + u32 win_r = MAX(start, MIN(end, win_rraw)); + + bool goodwin = win_lraw < win_rraw; + + if (!in_window_y(vcount, win_top, win_bot) || (win_lraw == win_rraw)) + // WindowN is completely out, just render all out. + outfn(scanline, start, end); + else { + // Render window withtin the clipped range + // Enable bits for stuff inside the window (and outside) + u32 winin = (*(winreg_t *)REG_ADDR_WININ) & 0xFFFF; + u32 wndn_enable = (winin >> (8 * winnum)) & 0x3F; + + // If the window is defined upside down, the areas are inverted. + if (goodwin) { + // Render [start, win_l) range (which is outside the window) + if (win_l != start) + outfn(scanline, start, win_l); + // Render the actual window0 pixels + render_scanline_conditional(win_l, win_r, scanline, wndn_enable); + // Render the [win_l, end] range (outside) + if (win_r != end) + outfn(scanline, win_r, end); + } else { + // Render [0, win_r) range (which is "inside" window0) + if (win_r != start) + render_scanline_conditional(start, win_r, scanline, wndn_enable); + // The actual window is now outside, render recursively + outfn(scanline, win_r, win_l); + // Render the [win_l, DISPLAY_WIDTH] range ("inside") + if (win_l != end) + render_scanline_conditional(win_l, end, scanline, wndn_enable); + } + } +} + +// Renders a full scaleline, taking into consideration windowing effects. +// Breaks the rendering step into N steps, for each windowed region. +static void render_scanline_window(u16 *scanline) +{ + u16 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u32 win_ctrl = (dispcnt >> 13); + + // Priority decoding for windows + switch (win_ctrl) { + case 0x0: // No windows are active. + render_scanline_conditional(0, DISPLAY_WIDTH, scanline); + break; + + case 0x1: // Window 0 + render_window_n_pass(scanline, 0, DISPLAY_WIDTH); + break; + + case 0x2: // Window 1 + render_window_n_pass(scanline, 0, DISPLAY_WIDTH); + break; + + case 0x3: // Window 0 & 1 + render_window_n_pass, 0>(scanline, 0, DISPLAY_WIDTH); + break; + + case 0x4: // Window Obj + render_windowobj_pass(scanline, 0, DISPLAY_WIDTH); + break; + + case 0x5: // Window 0 & Obj + render_window_n_pass(scanline, 0, DISPLAY_WIDTH); + break; + + case 0x6: // Window 1 & Obj + render_window_n_pass(scanline, 0, DISPLAY_WIDTH); + break; + + case 0x7: // Window 0, 1 & Obj + render_window_n_pass, 0>(scanline, 0, DISPLAY_WIDTH); + break; + } +} + +static const u8 active_layers[] = { + 0x1F, // Mode 0, Tile BG0-3 and OBJ + 0x17, // Mode 1, Tile BG0-2 and OBJ + 0x1C, // Mode 2, Tile BG2-3 and OBJ + 0x14, // Mode 3, BMP BG2 and OBJ + 0x14, // Mode 4, BMP BG2 and OBJ + 0x14, // Mode 5, BMP BG2 and OBJ + 0, // Unused + 0, +}; + +void update_scanline(void) +{ + u32 pitch = get_screen_pitch(); + u16 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u32 vcount = read_ioreg(REG_ADDR_VCOUNT); + u16 *screen_offset = get_screen_pixels() + (vcount * pitch); + u32 video_mode = dispcnt & 0x07; + + order_layers((dispcnt >> 8) & active_layers[video_mode], vcount); + + // If the screen is in in forced blank draw pure white. + if (dispcnt & 0x80) + memset(screen_offset, 0xff, DISPLAY_WIDTH * sizeof(u16)); + else + render_scanline_window(screen_offset); + + // Mode 0 does not use any affine params at all. + if (video_mode) { + // Account for vertical mosaic effect, by correcting affine references. + const u32 bgmosv = ((read_ioreg(REG_ADDR_MOSAIC) >> 4) & 0xF) + 1; + + if (read_ioreg(REG_ADDR_BG2CNT) & 0x40) { // Mosaic enabled for this BG + if ((vcount % bgmosv) == bgmosv - 1) { // Correct after the last line + affine_reference_x[0] += (s16)read_ioreg(REG_ADDR_BG2PB) * bgmosv; + affine_reference_y[0] += (s16)read_ioreg(REG_ADDR_BG2PD) * bgmosv; + } + } else { + affine_reference_x[0] += (s16)read_ioreg(REG_ADDR_BG2PB); + affine_reference_y[0] += (s16)read_ioreg(REG_ADDR_BG2PD); + } + + if (read_ioreg(REG_ADDR_BG3CNT) & 0x40) { + if ((vcount % bgmosv) == bgmosv - 1) { + affine_reference_x[1] += (s16)read_ioreg(REG_ADDR_BG3PB) * bgmosv; + affine_reference_y[1] += (s16)read_ioreg(REG_ADDR_BG3PD) * bgmosv; + } + } else { + affine_reference_x[1] += (s16)read_ioreg(REG_ADDR_BG3PB); + affine_reference_y[1] += (s16)read_ioreg(REG_ADDR_BG3PD); + } + } +} + +extern "C" void DrawFrame_Fast(u16 *pixels) +{ + int i; + + gba_screen_pixels = pixels; + // convert_whole_palette(); + + // assume that the oam is only updated once before the frame + // starts to be drawn + u32 dispcnt = read_ioreg(REG_ADDR_DISPCNT); + u32 video_mode = dispcnt & 0x07; + order_obj(video_mode); + + for (i = 0; i < DISPLAY_HEIGHT; i++) { + + REG_VCOUNT = i; + if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { + REG_DISPSTAT |= INTR_FLAG_VCOUNT; + if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) + gIntrTable[INTR_INDEX_VCOUNT](); + } + + // Render the backdrop color before each individual scanline. + // HBlank interrupt code could have changed it in between lines. + update_scanline(); + + REG_DISPSTAT |= INTR_FLAG_HBLANK; + + RunDMAs(DMA_HBLANK); + + if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) + gIntrTable[INTR_INDEX_HBLANK](); + + REG_DISPSTAT &= ~INTR_FLAG_HBLANK; + REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; + } + + video_reload_counters(); +} + +#endif diff --git a/tools/scaninc/source_file.cpp b/tools/scaninc/source_file.cpp index 9d188eb738..53e258d955 100644 --- a/tools/scaninc/source_file.cpp +++ b/tools/scaninc/source_file.cpp @@ -31,7 +31,7 @@ SourceFileType GetFileType(std::string& path) std::string extension = path.substr(pos + 1); - if (extension == "c") + if (extension == "c" || extension == "cc") return SourceFileType::Cpp; else if (extension == "s") return SourceFileType::Asm; From f3004a40d43571bf12543fbd1c42e637bacb735e Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Fri, 20 Feb 2026 16:17:30 +0000 Subject: [PATCH 14/51] handle control input, clean up --- include/config.h | 6 +- .../gpsp_renderer.h} | 2 + src/game/special_stage/world.c | 4 +- src/platform/pret_sdl/sdl2.c | 7 +- src/platform/ps2/ps2.c | 440 +++++++++--------- .../gpsp_renderer.cc} | 30 +- src/sprite.c | 4 +- 7 files changed, 248 insertions(+), 245 deletions(-) rename include/platform/shared/{rendering/sw_renderer_common.h => video/gpsp_renderer.h} (97%) rename src/platform/shared/{rendering/sw_renderer_fast.cc => video/gpsp_renderer.cc} (99%) diff --git a/include/config.h b/include/config.h index dd1e301d21..86f6603b58 100644 --- a/include/config.h +++ b/include/config.h @@ -41,17 +41,17 @@ #define RENDERER_SOFTWARE 0 #define RENDERER_OPENGL 1 -#define RENDERER_SOFTWARE_FAST 2 +#define RENDERER_SOFTWARE_GPSP 2 #define RENDERER_COUNT 3 #ifndef RENDERER #if defined(__PSP__) || defined(__PS2__) -#define RENDERER RENDERER_SOFTWARE_FAST +#define RENDERER RENDERER_SOFTWARE_GPSP #elif PLATFORM_WIN32 && !PLATFORM_SDL // TODO: Only win32 for now #define RENDERER RENDERER_OPENGL #else -#define RENDERER RENDERER_SOFTWARE_FAST +#define RENDERER RENDERER_SOFTWARE_GPSP #endif #endif diff --git a/include/platform/shared/rendering/sw_renderer_common.h b/include/platform/shared/video/gpsp_renderer.h similarity index 97% rename from include/platform/shared/rendering/sw_renderer_common.h rename to include/platform/shared/video/gpsp_renderer.h index ddb85d7ff2..5c15b3f7ea 100644 --- a/include/platform/shared/rendering/sw_renderer_common.h +++ b/include/platform/shared/video/gpsp_renderer.h @@ -61,4 +61,6 @@ static inline uint16_t alphaBrightnessDecrease(uint16_t targetA, unsigned int ev return r | (g << 5) | (b << 10) | COLOR_OPAQUE; } +extern void gpsp_draw_frame(uint16_t *framebuf); + #endif // GUARD_SW_RENDERER_COMMON_H diff --git a/src/game/special_stage/world.c b/src/game/special_stage/world.c index a41ac6d5c3..947eb2d342 100644 --- a/src/game/special_stage/world.c +++ b/src/game/special_stage/world.c @@ -239,14 +239,14 @@ void sub_806EA04(void) *unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PA // HACK: in SDL we don't handle these PB and PD values properly -#if !PLATFORM_GBA && (RENDERER == RENDERER_SOFTWARE_FAST || RENDERER == RENDERER_SOFTWARE) +#if !PLATFORM_GBA && RENDERER == RENDERER_SOFTWARE *unk1884++ = 0; #else *unk1884++ = (Q_16_16_TO_INT(temp) * sin) >> 0x10; // BG2PB #endif *unk1884++ = (Q_16_16_TO_INT(temp) * -sin) >> 0x10; // BG2PC -#if !PLATFORM_GBA && (RENDERER == RENDERER_SOFTWARE_FAST || RENDERER == RENDERER_SOFTWARE) +#if !PLATFORM_GBA && RENDERER == RENDERER_SOFTWARE *unk1884++ = 0; #else *unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PD diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index f63b7ba7e6..eba3546218 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -26,7 +26,7 @@ extern int setupPspCallbacks(void); #include "lib/agb_flash/flash_internal.h" #include "platform/shared/dma.h" #include "platform/shared/input.h" -#include "platform/shared/rendering/sw_renderer_common.h" +#include "platform/shared/video/gpsp_renderer.h" #if ENABLE_AUDIO #include "platform/shared/audio/cgb_audio.h" @@ -2024,10 +2024,9 @@ void VramDraw(SDL_Texture *texture) void VDraw(SDL_Texture *texture) { -#if RENDERER == RENDERER_SOFTWARE_FAST +#if RENDERER == RENDERER_SOFTWARE_GPSP { - extern void DrawFrame_Fast(uint16_t * pixels); - DrawFrame_Fast(gameImage); + gpsp_draw_frame(gameImage); } #else DrawFrame(gameImage); diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index b0541e2e62..55b361c69c 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -1,16 +1,21 @@ #include #include +// PS2 libs #include #include #include #include + #include #include - +#include +#include +#include #include -#include "audsrv.h" +#include +// Game #include "global.h" #include "core.h" #include "multi_sio.h" @@ -18,13 +23,15 @@ #include "gba/io_reg.h" #include "gba/types.h" #include "lib/agb_flash/flash_internal.h" + +// Emulation #include "platform/shared/dma.h" +#include "platform/shared/audio/cgb_audio.h" +#include "platform/shared/video/gpsp_renderer.h" static GSGLOBAL *gsGlobal; static GSTEXTURE screen; -#include "platform/shared/audio/cgb_audio.h" - #ifndef TILE_WIDTH #define TILE_WIDTH 8 #endif @@ -64,14 +71,17 @@ static const struct VidMode vid_modes[] = { { "1080i", GS_MODE_DTV_1080I, GS_INTERLACED, GS_FRAME, 1920, 1080, 1920, 1080, 1, 2, 0, 0 }, }; -static int vsync_sema_1st_id; -static int vsync_sema_2nd_id; -static int vsync_sema_id = -1; -static int vsync_id = -1; - static const struct VidMode *vid_mode; static bool use_hires = false; +static u8 padbuf[256] __attribute__((aligned(64))); +static int init_done = 0; + +static int joy_port = -1; +static int joy_slot = -1; +static int joy_id = -1; +static struct padButtonStatus joy_buttons __attribute__((aligned(64))); + bool speedUp = false; bool isRunning = true; bool paused = false; @@ -87,10 +97,8 @@ double accumulator = 0.0; static FILE *sSaveFile = NULL; extern void AgbMain(void); -void DoSoftReset(void) {}; -void VDraw(void); -void UpdateTexture(void); +void VideoUpdateTexture(void); static void ReadSaveFile(char *path); static void StoreSaveFile(void); @@ -98,10 +106,9 @@ static void CloseSaveFile(void); u16 Platform_GetKeyInput(void); -#define SAMPLES_HIGH 544 -#define SAMPLES_LOW 528 +// Audio -static bool audio_ps2_init(void) +static bool AudioInit(void) { if (init_audio_driver() != 0) return false; @@ -122,43 +129,16 @@ static bool audio_ps2_init(void) return true; } -static int audio_ps2_buffered(void) { return audsrv_queued() / 4; } - -static void audio_ps2_play(const uint8_t *buf, size_t len) +static void AudioPlay(const uint8_t *buf, size_t len) { - if (audio_ps2_buffered() < 6000) { + if ((audsrv_queued() / 4) < 6000) { audsrv_play_audio(buf, len); } } -void reset_IOP() -{ - SifInitRpc(0); - while (!SifIopReset(NULL, 0)) { } // Comment this line if you want to "debug" through ps2link - while (!SifIopSync()) { } -} - -static void prepare_IOP() -{ - reset_IOP(); - SifInitRpc(0); - sbv_patch_enable_lmb(); - sbv_patch_disable_prefix_check(); -} - -static void init_drivers() -{ - init_only_boot_ps2_filesystem_driver(); - init_memcard_driver(true); -} - -static void deinit_drivers() -{ - deinit_memcard_driver(true); - deinit_only_boot_ps2_filesystem_driver(); -} +// Video -void platform_video_init(void) +void VideoInit(void) { if (vid_mode == NULL) { vid_mode = &vid_modes[3]; // Standard def 480p @@ -167,10 +147,6 @@ void platform_video_init(void) gsKit_hires_deinit_global(gsGlobal); } else { gsKit_deinit_global(gsGlobal); - if (vsync_id != -1) { - gsKit_remove_vsync_handler(vsync_id); - } - vsync_sema_id = -1; } } use_hires = (vid_mode->mode == GS_MODE_DTV_720P || vid_mode->mode == GS_MODE_DTV_1080I); @@ -216,10 +192,157 @@ void platform_video_init(void) screen.Mem = (void *)gameImage; } +void VideoUpdateTexture(void) +{ + gsKit_TexManager_invalidate(gsGlobal, &screen); + gsKit_TexManager_bind(gsGlobal, &screen); + + int startX = (gsGlobal->Width); + int startY = (gsGlobal->Height); + + gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0, 0, 0, 0, 0)); + + gsKit_prim_sprite_texture(gsGlobal, &screen, + 0.0f, // X1 + 0.0f, // Y2 + 0.0f, // U1 + 0.0f, // V1 + startX, // X2 + startY, // Y2 + gsGlobal->Width, // U2 + gsGlobal->Height, // V2 + 0, GS_SETREG_RGBAQ(128, 128, 128, 0, 0)); +} + +// Controller + +static inline int WaitPad(int tries) +{ + int state = padGetState(joy_port, joy_slot); + if (state == PAD_STATE_DISCONN) { + joy_id = -1; + return -1; + } + + while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) { + state = padGetState(joy_port, joy_slot); + if (--tries == 0) + break; + } + + return 0; +} + +static int DetectPad(void) +{ + int id = padInfoMode(joy_port, joy_slot, PAD_MODECURID, 0); + if (id <= 0) + return -1; + + const int ext = padInfoMode(joy_port, joy_slot, PAD_MODECUREXID, 0); + if (ext) + id = ext; + + printf("ControllerInit: detected pad type %d\n", id); + + if (id == PAD_TYPE_DIGITAL || id == PAD_TYPE_DUALSHOCK) + padSetMainMode(joy_port, joy_slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); + + return id; +} + +static void ControllerInit(void) +{ + int ret = -1; + + // MEMORY CARD already initied SIO2MAN + ret = init_joystick_driver(false); + + if (ret != 0) { + printf("ControllerInit: failed to init joystick driver: %d\n", ret); + return; + } + + const int numports = padGetPortMax(); + // Find the first device connected + for (int port = 0; port < numports && joy_port < 0; ++port) { + if (joy_port == -1 && joy_slot == -1 && mtapPortOpen(port)) { + const int maxslots = padGetSlotMax(port); + for (int slot = 0; slot < maxslots; ++slot) { + if (joy_port == -1 && joy_slot == -1 && padPortOpen(port, slot, padbuf) >= 0) { + joy_port = port; + joy_slot = slot; + printf("ControllerInit: using pad (%d, %d)\n", port, slot); + break; + } + } + } + } + + if (joy_slot < 0 || joy_port < 0) { + printf("ControllerInit: could not open a single port\n"); + return; + } + + init_done = 1; +} + +static u16 ControllerRead(void) +{ + if (!init_done) + return 0; + + if (WaitPad(10) < 0) + return 0; // nothing received + + if (joy_id < 0) { + // pad not detected yet, do it + joy_id = DetectPad(); + if (joy_id < 0) + return 0; // still nothing + if (WaitPad(10) < 0) + return 0; + } + + if (padRead(joy_port, joy_slot, &joy_buttons)) { + return 0xffff ^ joy_buttons.btns; + } + + return 0; +} + +// PS2 Drivers +void ResetIOP() +{ + SifInitRpc(0); + while (!SifIopReset(NULL, 0)) { } // Comment this line if you want to "debug" through ps2link + while (!SifIopSync()) { } +} + +static void PrepareIOP() +{ + ResetIOP(); + SifInitRpc(0); + sbv_patch_enable_lmb(); + sbv_patch_disable_prefix_check(); +} + +static void InitPS2Drivers() +{ + init_only_boot_ps2_filesystem_driver(); + init_memcard_driver(true); +} + +static void deInitPS2Drivers() +{ + deinit_memcard_driver(true); + deinit_only_boot_ps2_filesystem_driver(); +} + int main(int argc, char **argv) { - prepare_IOP(); - init_drivers(); + PrepareIOP(); + InitPS2Drivers(); // ReadSaveFile("sa2.sav"); @@ -227,32 +350,26 @@ int main(int argc, char **argv) REG_RCNT = 0x8000; REG_KEYINPUT = 0x3FF; - audio_ps2_init(); - platform_video_init(); - // controller init + AudioInit(); + VideoInit(); + ControllerInit(); cgb_audio_init(48000); - VDraw(); - // while (true) { - // UpdateTexture(); - // gsKit_sync_flip(gsGlobal); - // gsKit_queue_exec(gsGlobal); - // } + VideoUpdateTexture(); + + // Allow the game loop to take control AgbMain(); return 0; } -bool newFrameRequested = FALSE; -int skipFrame = 0; - -// called every gba frame. we process sdl events and render as many times -// as vsync needs, then return when a new game frame is needed. +// GBA callbacks void VBlankIntrWait(void) { #define HANDLE_VBLANK_INTRS() \ ({ \ + REG_VCOUNT = DISPLAY_HEIGHT + 1; \ REG_DISPSTAT |= INTR_FLAG_VBLANK; \ RunDMAs(DMA_VBLANK); \ if (REG_DISPSTAT & DISPSTAT_VBLANK_INTR) \ @@ -266,20 +383,10 @@ void VBlankIntrWait(void) if (isRunning) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); - // Only render 30fps when in widescreen as the draw func is too slow for the ps2 - // #if DISPLAY_WIDTH > 240 - // skipFrame++; - // skipFrame %= 2; - // #endif - if (skipFrame == 0) { - VDraw(); - } else { - UpdateTexture(); - } + gpsp_draw_frame(gameImage); + + VideoUpdateTexture(); HANDLE_VBLANK_INTRS(); - if (skipFrame != 0) { - return; - } if (use_hires) { gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1); @@ -290,82 +397,58 @@ void VBlankIntrWait(void) gsKit_TexManager_nextFrame(gsGlobal); return; } - // #define MAX_FRAME_SKIP 2 - - // while (isRunning) { - // if (!paused || stepOneFrame) { - // double dt = fixedTimestep / timeScale; // TODO: Fix speedup - - // // don't accumulate time if we already requested a new frame - // // this frame cycle (emulates threaded sdl behavior) - // if (!newFrameRequested) { - // double deltaTime = 0; - - // // TODO: fix - // curGameTime += dt; - // if (stepOneFrame) { - // deltaTime = dt; - // } else { - // // TODO: divide by expected frequency - // deltaTime = (double)((curGameTime - lastGameTime) / 1); - // if (deltaTime > (dt * 5)) - // deltaTime = dt * 5; - // } - // lastGameTime = curGameTime; - - // accumulator += deltaTime; - // } else { - // newFrameRequested = FALSE; - // } - - // while (accumulator >= dt) { - // REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); - // if (frameAvailable) { - // // frame skip: let game logic catch up when behind - // if (accumulator >= dt * 2.0 && frames_skipped < MAX_FRAME_SKIP) { - // frames_skipped++; - // frameAvailable = FALSE; - // HANDLE_VBLANK_INTRS(); - // accumulator -= dt; - // newFrameRequested = TRUE; - // return; - // } - // frames_skipped = 0; - // VDraw(); - // frameAvailable = FALSE; - // frameDrawn = true; - - // HANDLE_VBLANK_INTRS(); - - // accumulator -= dt; - // } else { - // newFrameRequested = TRUE; - // return; - // } - // } - - // if (paused && stepOneFrame) { - // stepOneFrame = false; - // } - // } - - // if (use_hires) { - // gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1); - // } else { - // // gsKit_flip(gs_global); - // gsKit_sync_flip(gsGlobal); - // gsKit_queue_exec(gsGlobal); - // } - // gsKit_TexManager_nextFrame(gsGlobal); - // } CloseSaveFile(); - deinit_drivers(); + deInitPS2Drivers(); exit(0); #undef HANDLE_VBLANK_INTRS } +void Platform_StoreSaveFile(void) { StoreSaveFile(); } + +s16 convertedAudio[4096]; + +void Platform_QueueAudio(const float *data, uint32_t bytesCount) +{ + u32 length = bytesCount / sizeof(float); + + for (u32 i = 0; i < length; i++) { + float sample = data[i]; + + if (sample > 1.0f) + sample = 1.0f; + else if (sample < -1.0f) + sample = -1.0f; + + // Convert to s16 + convertedAudio[i] = (int16_t)(sample * 32767.0f + (sample >= 0 ? 0.5f : -0.5f)); + } + + AudioPlay((uint8_t *)convertedAudio, length * sizeof(u16)); +} + +u16 Platform_GetKeyInput(void) +{ + static struct { + u16 gbaBtn; + u16 sceBtn; + } binds[] = { + { A_BUTTON, PAD_CROSS }, { B_BUTTON, PAD_SQUARE }, { L_BUTTON, PAD_L2 }, { R_BUTTON, PAD_R2 }, + { L_BUTTON, PAD_L1 }, { R_BUTTON, PAD_R1 }, { START_BUTTON, PAD_START }, { DPAD_LEFT, PAD_LEFT }, + { DPAD_RIGHT, PAD_RIGHT }, { DPAD_UP, PAD_UP }, { DPAD_DOWN, PAD_DOWN }, + }; + + u16 keys = 0; + u16 btns = ControllerRead(); + + for (int i = 0; i < ARRAY_COUNT(binds); ++i) + if (btns & binds[i].sceBtn) + keys |= binds[i].gbaBtn; + + return keys; +} + static void ReadSaveFile(char *path) { // Check whether the saveFile exists, and create it if not @@ -398,8 +481,6 @@ static void StoreSaveFile() } } -void Platform_StoreSaveFile(void) { StoreSaveFile(); } - static void CloseSaveFile() { if (sSaveFile != NULL) { @@ -407,35 +488,8 @@ static void CloseSaveFile() } } -s16 converted_audio[4096]; - -void float_audio_to_s16(const float *input, int16_t *output, size_t length) -{ - if (!input || !output) - return; - - for (size_t i = 0; i < length; i++) { - float sample = input[i]; - - if (sample > 1.0f) - sample = 1.0f; - else if (sample < -1.0f) - sample = -1.0f; - - output[i] = (int16_t)(sample * 32767.0f + (sample >= 0 ? 0.5f : -0.5f)); - } -} - -void Platform_QueueAudio(const float *data, uint32_t bytesCount) -{ - float_audio_to_s16(data, converted_audio, bytesCount / sizeof(float)); - audio_ps2_play((void *)converted_audio, bytesCount / sizeof(float) * sizeof(u16)); -} - -// TODO: handle input -u16 Platform_GetKeyInput(void) { return 0; } - // BIOS function implementations are based on the VBA-M source code. +// TODO: Link these functions from Libagbsyscall // safe unaligned access for MIPS static uint32_t CPUReadMemory(const void *src) @@ -865,33 +919,3 @@ u16 Sqrt(u32 num) } int MultiBoot(struct MultiBootParam *mp) { return 0; } - -void VDraw(void) -{ - extern void DrawFrame_Fast(uint16_t * pixels); - DrawFrame_Fast(gameImage); - UpdateTexture(); - REG_VCOUNT = DISPLAY_HEIGHT + 1; // prep for being in VBlank period -} - -void UpdateTexture(void) -{ - gsKit_TexManager_invalidate(gsGlobal, &screen); - gsKit_TexManager_bind(gsGlobal, &screen); - - int startX = (gsGlobal->Width); - int startY = (gsGlobal->Height); - - gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0, 0, 0, 0, 0)); - - gsKit_prim_sprite_texture(gsGlobal, &screen, - 0.0f, // X1 - 0.0f, // Y2 - 0.0f, // U1 - 0.0f, // V1 - startX, // X2 - startY, // Y2 - gsGlobal->Width, // U2 - gsGlobal->Height, // V2 - 0, GS_SETREG_RGBAQ(128, 128, 128, 0, 0)); -} diff --git a/src/platform/shared/rendering/sw_renderer_fast.cc b/src/platform/shared/video/gpsp_renderer.cc similarity index 99% rename from src/platform/shared/rendering/sw_renderer_fast.cc rename to src/platform/shared/video/gpsp_renderer.cc index 10a505865c..b4fe7bf8ea 100644 --- a/src/platform/shared/rendering/sw_renderer_fast.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -22,7 +22,7 @@ extern "C" { #include "config.h" } -#if RENDERER == RENDERER_SOFTWARE_FAST +#if RENDERER == RENDERER_SOFTWARE_GPSP #include #include @@ -35,6 +35,7 @@ extern "C" { #include "gba/types.h" #include "platform/shared/dma.h" +#include "platform/shared/video/gpsp_renderer.h" } #define eswap16(value) (value) @@ -42,25 +43,6 @@ extern "C" { #define GBA_SCREEN_PITCH DISPLAY_WIDTH -typedef u32 fixed16_16; -typedef u32 fixed8_24; - -#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) - -#define fp16_16_to_float(value) (float)((value) / 65536.0) - -#define u32_to_fp16_16(value) ((value) << 16) - -#define fp16_16_to_u32(value) ((value) >> 16) - -#define fp16_16_fractional_part(value) ((value)&0xFFFF) - -#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) - -#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) - -#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) - #define read_ioreg(regaddr) (eswap16(*(u16 *)(regaddr))) #define read_ioreg32(regaddr) (read_ioreg(regaddr) | (read_ioreg((regaddr) + sizeof(u16)) << 16)) @@ -2255,12 +2237,11 @@ void update_scanline(void) } } -extern "C" void DrawFrame_Fast(u16 *pixels) +void gpsp_draw_frame(u16 *framebuf) { int i; - gba_screen_pixels = pixels; - // convert_whole_palette(); + gba_screen_pixels = framebuf; // assume that the oam is only updated once before the frame // starts to be drawn @@ -2269,7 +2250,6 @@ extern "C" void DrawFrame_Fast(u16 *pixels) order_obj(video_mode); for (i = 0; i < DISPLAY_HEIGHT; i++) { - REG_VCOUNT = i; if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { REG_DISPSTAT |= INTR_FLAG_VCOUNT; @@ -2277,8 +2257,6 @@ extern "C" void DrawFrame_Fast(u16 *pixels) gIntrTable[INTR_INDEX_VCOUNT](); } - // Render the backdrop color before each individual scanline. - // HBlank interrupt code could have changed it in between lines. update_scanline(); REG_DISPSTAT |= INTR_FLAG_HBLANK; diff --git a/src/sprite.c b/src/sprite.c index 234ae233e5..a134f03033 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -9,7 +9,7 @@ #include "animation_commands.h" #include "platform/platform.h" -#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE_FAST && RENDERER != RENDERER_SOFTWARE +#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE_GPSP && RENDERER != RENDERER_SOFTWARE extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); #endif @@ -722,7 +722,7 @@ void DisplaySprite(Sprite *sprite) oam->split.paletteNum += sprite->palId; #endif -#if !PLATFORM_GBA && (RENDERER != RENDERER_SOFTWARE_FAST && RENDERER != RENDERER_SOFTWARE) +#if !PLATFORM_GBA && (RENDERER != RENDERER_SOFTWARE_GPSP && RENDERER != RENDERER_SOFTWARE) // TEMP // Quick hack for getting output in OpenGL test // The whole function call should be replaced by this! From 34563daf54ec2044e5ed606f4c2510c22b2bd4d5 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Fri, 20 Feb 2026 21:19:27 +0000 Subject: [PATCH 15/51] start this --- include/platform/shared/audio/cgb_audio.h | 27 + include/platform/shared/audio/cgb_tables.h | 4433 +++++++++++--------- src/platform/shared/audio/cgb_audio.c | 52 +- 3 files changed, 2406 insertions(+), 2106 deletions(-) diff --git a/include/platform/shared/audio/cgb_audio.h b/include/platform/shared/audio/cgb_audio.h index 65dd77a91e..39995f00d1 100644 --- a/include/platform/shared/audio/cgb_audio.h +++ b/include/platform/shared/audio/cgb_audio.h @@ -3,6 +3,33 @@ #include "lib/m4a/m4a_internal.h" +typedef s32 fixed16_16; +typedef s32 fixed8_24; + +#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) + +#define fp16_16_to_float(value) (float)((value) / 65536.0) + +#define u32_to_fp16_16(value) ((value) << 16) + +#define fp16_16_to_u32(value) ((value) >> 16) + +#define fp16_16_fractional_part(value) ((value)&0xFFFF) + +#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) + +#define fp8_24_to_float(value) (float)((value) / 16777216.0) + +#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) + +#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) + +#define address8(base, offset) *((u8 *)((u8 *)base + (offset))) + +#define address16(base, offset) *((u16 *)((u8 *)base + (offset))) + +#define address32(base, offset) *((u32 *)((u8 *)base + (offset))) + struct AudioCGB { u16 ch1Freq; u8 ch1SweepCounter; diff --git a/include/platform/shared/audio/cgb_tables.h b/include/platform/shared/audio/cgb_tables.h index 0966471aea..53278d27b3 100644 --- a/include/platform/shared/audio/cgb_tables.h +++ b/include/platform/shared/audio/cgb_tables.h @@ -1,6 +1,51 @@ #ifndef CGB_TABLES_H #define CGB_TABLES_H +#include "platform/shared/audio/cgb_audio.h" + +#define SAMPLE_RATE 48000 +#define FREQUENCY_RATE (SAMPLE_RATE / 32) + +// const fixed16_16 PU0[32] +// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; + +// const fixed16_16 PU1[32] +// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; + +// const fixed16_16 PU2[32] +// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; + +// const fixed16_16 PU3[32] +// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), +// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; + const int16_t PU0[32] = { 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; @@ -13,2088 +58,2314 @@ const int16_t PU3[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, int16_t WAV[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; -const float freqTable[2048] = { 32, - 32.0156326331216, - 32.0312805474096, - 32.0469437652812, - 32.0626223091976, - 32.0783162016642, - 32.0940254652302, - 32.109750122489, - 32.1254901960784, - 32.1412457086807, - 32.1570166830226, - 32.1728031418753, - 32.188605108055, - 32.2044226044226, - 32.220255653884, - 32.2361042793901, - 32.251968503937, - 32.2678483505662, - 32.2837438423645, - 32.2996550024643, - 32.3155818540434, - 32.3315244203256, - 32.3474827245805, - 32.3634567901235, - 32.3794466403162, - 32.3954522985665, - 32.4114737883284, - 32.4275111331024, - 32.4435643564356, - 32.4596334819217, - 32.4757185332012, - 32.4918195339613, - 32.5079365079365, - 32.5240694789082, - 32.5402184707051, - 32.5563835072032, - 32.572564612326, - 32.5887618100448, - 32.6049751243781, - 32.6212045793927, - 32.6374501992032, - 32.6537120079721, - 32.6699900299103, - 32.6862842892768, - 32.7025948103792, - 32.7189216175736, - 32.7352647352647, - 32.751624187906, - 32.768, - 32.784392196098, - 32.8008008008008, - 32.8172258387581, - 32.8336673346693, - 32.8501253132832, - 32.8665997993982, - 32.8830908178625, - 32.8995983935743, - 32.9161225514817, - 32.9326633165829, - 32.9492207139266, - 32.9657947686117, - 32.9823855057876, - 32.9989929506546, - 33.0156171284635, - 33.0322580645161, - 33.0489157841654, - 33.0655903128153, - 33.0822816759213, - 33.0989898989899, - 33.1157150075796, - 33.1324570273003, - 33.1492159838139, - 33.165991902834, - 33.1827848101266, - 33.1995947315096, - 33.2164216928535, - 33.2332657200811, - 33.2501268391679, - 33.2670050761421, - 33.2839004570848, - 33.3008130081301, - 33.3177427554652, - 33.3346897253306, - 33.3516539440204, - 33.3686354378819, - 33.3856342333164, - 33.4026503567788, - 33.4196838347782, - 33.4367346938776, - 33.4538029606942, - 33.4708886618999, - 33.4879918242207, - 33.5051124744376, - 33.5222506393862, - 33.539406345957, - 33.5565796210957, - 33.5737704918033, - 33.5909789851358, - 33.6082051282051, - 33.6254489481786, - 33.6427104722793, - 33.6599897277863, - 33.6772867420349, - 33.6946015424164, - 33.7119341563786, - 33.7292846114256, - 33.7466529351184, - 33.7640391550747, - 33.7814432989691, - 33.7988653945333, - 33.8163054695562, - 33.8337635518844, - 33.8512396694215, - 33.8687338501292, - 33.8862461220269, - 33.9037765131919, - 33.9213250517598, - 33.9388917659244, - 33.9564766839378, - 33.9740798341109, - 33.9917012448133, - 34.0093409444733, - 34.0269989615784, - 34.0446753246753, - 34.0623700623701, - 34.0800832033281, - 34.0978147762747, - 34.1155648099948, - 34.1333333333333, - 34.1511203751954, - 34.1689259645464, - 34.1867501304121, - 34.2045929018789, - 34.222454308094, - 34.2403343782654, - 34.2582331416623, - 34.2761506276151, - 34.2940868655154, - 34.3120418848168, - 34.330015715034, - 34.3480083857442, - 34.3660199265863, - 34.3840503672613, - 34.4020997375328, - 34.4201680672269, - 34.4382553862323, - 34.4563617245005, - 34.4744871120463, - 34.4926315789474, - 34.5107951553449, - 34.5289778714436, - 34.5471797575119, - 34.5654008438819, - 34.5836411609499, - 34.6019007391763, - 34.6201796090861, - 34.6384778012685, - 34.6567953463776, - 34.6751322751323, - 34.6934886183166, - 34.7118644067797, - 34.7302596714361, - 34.7486744432662, - 34.7671087533156, - 34.7855626326964, - 34.8040361125863, - 34.8225292242295, - 34.8410419989367, - 34.8595744680851, - 34.8781266631187, - 34.8966986155485, - 34.9152903569526, - 34.9339019189765, - 34.9525333333333, - 34.9711846318036, - 34.989855846236, - 35.008547008547, - 35.0272581507215, - 35.0459893048128, - 35.0647405029427, - 35.0835117773019, - 35.10230316015, - 35.1211146838156, - 35.1399463806971, - 35.1587982832618, - 35.1776704240472, - 35.1965628356606, - 35.2154755507792, - 35.2344086021505, - 35.2533620225928, - 35.2723358449946, - 35.2913301023156, - 35.3103448275862, - 35.3293800539084, - 35.3484358144552, - 35.3675121424717, - 35.3866090712743, - 35.4057266342518, - 35.4248648648649, - 35.4440237966468, - 35.4632034632035, - 35.4824038982133, - 35.501625135428, - 35.5208672086721, - 35.5401301518438, - 35.5594139989148, - 35.5787187839305, - 35.5980445410103, - 35.6173913043478, - 35.636759108211, - 35.6561479869423, - 35.6755579749592, - 35.6949891067538, - 35.7144414168937, - 35.7339149400218, - 35.7534097108565, - 35.7729257641921, - 35.792463134899, - 35.8120218579235, - 35.8316019682887, - 35.8512035010941, - 35.8708264915161, - 35.8904709748083, - 35.9101369863014, - 35.9298245614035, - 35.9495337356007, - 35.9692645444566, - 35.9890170236134, - 36.0087912087912, - 36.0285871357889, - 36.048404840484, - 36.0682443588332, - 36.0881057268722, - 36.1079889807162, - 36.1278941565601, - 36.1478212906784, - 36.167770419426, - 36.187741579238, - 36.2077348066298, - 36.2277501381979, - 36.2477876106195, - 36.267847260653, - 36.2879291251384, - 36.3080332409972, - 36.3281596452328, - 36.3483083749307, - 36.3684794672586, - 36.388672959467, - 36.4088888888889, - 36.4291272929405, - 36.4493882091212, - 36.4696716750139, - 36.4899777282851, - 36.5103064066852, - 36.5306577480491, - 36.5510317902956, - 36.5714285714286, - 36.5918481295366, - 36.6122905027933, - 36.6327557294578, - 36.6532438478747, - 36.6737548964745, - 36.6942889137738, - 36.7148459383753, - 36.7354260089686, - 36.7560291643298, - 36.7766554433221, - 36.7973048848961, - 36.8179775280899, - 36.8386734120292, - 36.859392575928, - 36.8801350590884, - 36.9009009009009, - 36.9216901408451, - 36.9425028184893, - 36.9633389734913, - 36.9841986455982, - 37.0050818746471, - 37.025988700565, - 37.0469191633691, - 37.0678733031674, - 37.0888511601585, - 37.1098527746319, - 37.1308781869688, - 37.1519274376417, - 37.173000567215, - 37.1940976163451, - 37.2152186257808, - 37.2363636363636, - 37.2575326890279, - 37.2787258248009, - 37.2999430848036, - 37.3211845102506, - 37.3424501424501, - 37.363740022805, - 37.3850541928123, - 37.4063926940639, - 37.4277555682467, - 37.4491428571429, - 37.4705546026301, - 37.4919908466819, - 37.5134516313681, - 37.5349369988545, - 37.556446991404, - 37.5779816513761, - 37.5995410212278, - 37.6211251435132, - 37.6427340608845, - 37.664367816092, - 37.6860264519839, - 37.7077100115075, - 37.7294185377087, - 37.7511520737327, - 37.7729106628242, - 37.7946943483276, - 37.8165031736872, - 37.838337182448, - 37.8601964182553, - 37.8820809248555, - 37.903990746096, - 37.9259259259259, - 37.9478865083961, - 37.9698725376593, - 37.991884057971, - 38.0139211136891, - 38.0359837492745, - 38.0580720092915, - 38.0801859384079, - 38.1023255813953, - 38.1244909831297, - 38.1466821885914, - 38.1688992428655, - 38.1911421911422, - 38.2134110787172, - 38.2357059509918, - 38.2580268534734, - 38.2803738317757, - 38.3027469316189, - 38.3251461988304, - 38.3475716793446, - 38.3700234192037, - 38.3925014645577, - 38.4150058616647, - 38.4375366568915, - 38.4600938967136, - 38.4826776277158, - 38.5052878965922, - 38.527924750147, - 38.5505882352941, - 38.5732783990583, - 38.5959952885748, - 38.6187389510902, - 38.6415094339623, - 38.6643067846608, - 38.6871310507674, - 38.7099822799764, - 38.7328605200946, - 38.755765819042, - 38.7786982248521, - 38.801657785672, - 38.824644549763, - 38.8476585655009, - 38.870699881376, - 38.8937685459941, - 38.916864608076, - 38.9399881164587, - 38.9631391200951, - 38.9863176680547, - 39.0095238095238, - 39.0327575938058, - 39.0560190703218, - 39.0793082886106, - 39.1026252983294, - 39.1259701492537, - 39.1493428912784, - 39.1727435744172, - 39.1961722488038, - 39.2196289646918, - 39.2431137724551, - 39.2666267225884, - 39.2901678657074, - 39.3137372525495, - 39.3373349339736, - 39.360960960961, - 39.3846153846154, - 39.4082982561636, - 39.4320096269555, - 39.4557495484648, - 39.4795180722892, - 39.5033152501507, - 39.5271411338963, - 39.5509957754979, - 39.5748792270531, - 39.5987915407855, - 39.6227327690447, - 39.6467029643073, - 39.6707021791768, - 39.694730466384, - 39.7187878787879, - 39.7428744693754, - 39.7669902912621, - 39.7911353976928, - 39.8153098420413, - 39.8395136778115, - 39.8637469586375, - 39.8880097382836, - 39.9123020706455, - 39.9366240097502, - 39.9609756097561, - 39.9853569249542, - 40.009768009768, - 40.0342089187538, - 40.0586797066015, - 40.0831804281346, - 40.1077111383109, - 40.1322718922229, - 40.156862745098, - 40.1814837522992, - 40.2061349693252, - 40.2308164518109, - 40.2555282555283, - 40.280270436386, - 40.3050430504305, - 40.3298461538462, - 40.3546798029557, - 40.3795440542206, - 40.4044389642417, - 40.4293645897594, - 40.4543209876543, - 40.4793082149475, - 40.504326328801, - 40.5293753865182, - 40.5544554455446, - 40.5795665634675, - 40.6047087980174, - 40.6298822070676, - 40.6550868486352, - 40.6803227808814, - 40.7055900621118, - 40.7308887507769, - 40.7562189054726, - 40.7815805849409, - 40.8069738480697, - 40.8323987538941, - 40.857855361596, - 40.8833437305053, - 40.9088639200999, - 40.9344159900062, - 40.96, - 40.9856160100063, - 41.0112640801001, - 41.0369442705072, - 41.062656641604, - 41.0884012539185, - 41.1141781681305, - 41.1399874450722, - 41.1658291457287, - 41.1917033312382, - 41.2176100628931, - 41.2435494021397, - 41.2695214105793, - 41.2955261499685, - 41.3215636822194, - 41.3476340694006, - 41.3737373737374, - 41.3998736576121, - 41.4260429835651, - 41.4522454142948, - 41.4784810126582, - 41.504749841672, - 41.531051964512, - 41.5573874445149, - 41.5837563451777, - 41.6101587301587, - 41.6365946632783, - 41.6630642085188, - 41.6895674300254, - 41.7161043921069, - 41.7426751592357, - 41.7692797960484, - 41.7959183673469, - 41.8225909380983, - 41.8492975734355, - 41.8760383386582, - 41.9028132992327, - 41.9296225207934, - 41.9564660691421, - 41.9833440102498, - 42.0102564102564, - 42.0372033354715, - 42.0641848523748, - 42.0912010276172, - 42.1182519280206, - 42.1453376205788, - 42.1724581724582, - 42.1996136509981, - 42.2268041237113, - 42.254029658285, - 42.2812903225807, - 42.3085861846352, - 42.3359173126615, - 42.3632837750485, - 42.3906856403622, - 42.4181229773463, - 42.4455958549223, - 42.4731043421905, - 42.5006485084306, - 42.5282284231019, - 42.5558441558442, - 42.5834957764782, - 42.6111833550065, - 42.6389069616135, - 42.6666666666667, - 42.6944625407166, - 42.722294654498, - 42.7501630789302, - 42.7780678851175, - 42.8060091443501, - 42.8339869281046, - 42.8620013080445, - 42.890052356021, - 42.9181401440733, - 42.9462647444299, - 42.9744262295082, - 43.002624671916, - 43.0308601444517, - 43.0591327201051, - 43.0874424720579, - 43.1157894736842, - 43.1441737985517, - 43.1725955204216, - 43.2010547132498, - 43.2295514511873, - 43.2580858085809, - 43.2866578599736, - 43.3152676801057, - 43.3439153439153, - 43.3726009265387, - 43.4013245033113, - 43.4300861497681, - 43.4588859416446, - 43.4877239548772, - 43.5166002656043, - 43.5455149501661, - 43.5744680851064, - 43.6034597471723, - 43.6324900133156, - 43.6615589606929, - 43.6906666666667, - 43.7198132088059, - 43.7489986648865, - 43.7782231128925, - 43.807486631016, - 43.8367892976589, - 43.8661311914324, - 43.8955123911587, - 43.9249329758713, - 43.9543930248156, - 43.9838926174497, - 44.0134318334453, - 44.0430107526882, - 44.0726294552791, - 44.1022880215343, - 44.1319865319865, - 44.1617250673855, - 44.1915037086986, - 44.221322537112, - 44.2511816340311, - 44.2810810810811, - 44.3110209601082, - 44.34100135318, - 44.3710223425863, - 44.4010840108401, - 44.431186440678, - 44.4613297150611, - 44.4915139171758, - 44.5217391304348, - 44.5520054384772, - 44.5823129251701, - 44.6126616746086, - 44.6430517711172, - 44.6734832992502, - 44.7039563437926, - 44.7344709897611, - 44.7650273224044, - 44.7956254272044, - 44.8262653898769, - 44.8569472963724, - 44.8876712328767, - 44.9184372858122, - 44.9492455418381, - 44.9800960878518, - 45.010989010989, - 45.0419243986254, - 45.0729023383769, - 45.1039229181005, - 45.1349862258953, - 45.1660923501034, - 45.1972413793103, - 45.2284334023465, - 45.2596685082873, - 45.2909467864547, - 45.3222683264177, - 45.3536332179931, - 45.3850415512465, - 45.4164934164934, - 45.4479889042996, - 45.4795281054823, - 45.5111111111111, - 45.5427380125087, - 45.5744089012517, - 45.6061238691719, - 45.6378830083566, - 45.6696864111498, - 45.7015341701534, - 45.7334263782275, - 45.7653631284916, - 45.7973445143256, - 45.8293706293706, - 45.8614415675297, - 45.8935574229692, - 45.9257182901191, - 45.9579242636746, - 45.9901754385965, - 46.0224719101124, - 46.0548137737175, - 46.0872011251758, - 46.1196340605208, - 46.1521126760563, - 46.184637068358, - 46.2172073342736, - 46.2498235709245, - 46.2824858757062, - 46.3151943462898, - 46.3479490806223, - 46.3807501769285, - 46.4135977337111, - 46.446491849752, - 46.4794326241135, - 46.5124201561391, - 46.5454545454545, - 46.5785358919687, - 46.6116642958748, - 46.6448398576513, - 46.6780626780627, - 46.7113328581611, - 46.7446504992867, - 46.7780157030692, - 46.8114285714286, - 46.8448892065761, - 46.8783977110157, - 46.9119541875447, - 46.945558739255, - 46.9792114695341, - 47.012912482066, - 47.0466618808327, - 47.0804597701149, - 47.1143062544932, - 47.1482014388489, - 47.1821454283657, - 47.2161383285303, - 47.2501802451334, - 47.2842712842713, - 47.3184115523466, - 47.3526011560694, - 47.3868402024584, - 47.4211287988423, - 47.4554670528602, - 47.4898550724638, - 47.5242929659173, - 47.5587808417997, - 47.5933188090051, - 47.6279069767442, - 47.6625454545455, - 47.6972343522562, - 47.7319737800437, - 47.7667638483965, - 47.8016046681255, - 47.836496350365, - 47.8714390065741, - 47.906432748538, - 47.9414776883687, - 47.9765739385066, - 48.0117216117216, - 48.0469208211144, - 48.0821716801174, - 48.1174743024963, - 48.1528288023512, - 48.1882352941176, - 48.2236938925681, - 48.259204712813, - 48.2947678703021, - 48.330383480826, - 48.3660516605166, - 48.4017725258493, - 48.4375461936438, - 48.4733727810651, - 48.5092524056255, - 48.5451851851852, - 48.581171237954, - 48.6172106824926, - 48.6533036377134, - 48.6894502228826, - 48.7256505576208, - 48.7619047619048, - 48.7982129560685, - 48.8345752608048, - 48.8709917971663, - 48.9074626865672, - 48.9439880507842, - 48.9805680119582, - 49.0172026925954, - 49.0538922155689, - 49.0906367041199, - 49.1274362818591, - 49.1642910727682, - 49.2012012012012, - 49.2381667918858, - 49.2751879699248, - 49.3122648607976, - 49.3493975903615, - 49.3865862848531, - 49.4238310708899, - 49.4611320754717, - 49.4984894259819, - 49.535903250189, - 49.5733736762481, - 49.6109008327025, - 49.6484848484849, - 49.6861258529189, - 49.7238239757208, - 49.7615793470008, - 49.7993920972644, - 49.8372623574145, - 49.8751902587519, - 49.9131759329779, - 49.9512195121951, - 49.9893211289092, - 50.0274809160305, - 50.0656990068755, - 50.1039755351682, - 50.1423106350421, - 50.1807044410413, - 50.2191570881226, - 50.2576687116564, - 50.296239447429, - 50.3348694316436, - 50.3735588009224, - 50.4123076923077, - 50.451116243264, - 50.4899845916795, - 50.5289128758674, - 50.5679012345679, - 50.6069498069498, - 50.6460587326121, - 50.6852281515855, - 50.7244582043344, - 50.7637490317583, - 50.8031007751938, - 50.8425135764158, - 50.8819875776397, - 50.9215229215229, - 50.9611197511664, - 51.0007782101167, - 51.0404984423676, - 51.0802805923617, - 51.1201248049922, - 51.160031225605, - 51.2, - 51.2400312744331, - 51.2801251956182, - 51.3202819107283, - 51.3605015673981, - 51.4007843137255, - 51.4411302982732, - 51.4815396700707, - 51.5220125786164, - 51.5625491738788, - 51.6031496062992, - 51.6438140267928, - 51.6845425867508, - 51.7253354380426, - 51.7661927330174, - 51.8071146245059, - 51.8481012658228, - 51.889152810768, - 51.9302694136292, - 51.9714512291832, - 52.0126984126984, - 52.0540111199365, - 52.0953895071542, - 52.1368337311058, - 52.1783439490446, - 52.2199203187251, - 52.2615629984051, - 52.3032721468476, - 52.3450479233227, - 52.3868904876099, - 52.4288, - 52.470776621297, - 52.5128205128205, - 52.5549318364074, - 52.5971107544141, - 52.6393574297189, - 52.6816720257235, - 52.7240547063556, - 52.7665056360709, - 52.809024979855, - 52.8516129032258, - 52.8942695722357, - 52.9369951534734, - 52.9797898140663, - 53.0226537216829, - 53.0655870445344, - 53.1085899513776, - 53.1516626115166, - 53.1948051948052, - 53.2380178716491, - 53.2813008130081, - 53.3246541903987, - 53.3680781758958, - 53.4115729421353, - 53.4551386623165, - 53.4987755102041, - 53.5424836601307, - 53.5862632869992, - 53.6301145662848, - 53.6740376740377, - 53.7180327868852, - 53.7621000820345, - 53.8062397372742, - 53.8504519309778, - 53.8947368421053, - 53.9390946502058, - 53.9835255354201, - 54.0280296784831, - 54.0726072607261, - 54.1172584640793, - 54.1619834710744, - 54.206782464847, - 54.2516556291391, - 54.2966031483016, - 54.3416252072969, - 54.3867219917012, - 54.4318936877076, - 54.477140482128, - 54.522462562396, - 54.5678601165695, - 54.6133333333333, - 54.6588824020017, - 54.7045075125209, - 54.750208855472, - 54.7959866220736, - 54.8418410041841, - 54.8877721943049, - 54.9337803855826, - 54.9798657718121, - 55.0260285474391, - 55.072268907563, - 55.1185870479394, - 55.1649831649832, - 55.2114574557709, - 55.2580101180438, - 55.304641350211, - 55.3513513513514, - 55.3981403212172, - 55.4450084602369, - 55.4919559695174, - 55.5389830508475, - 55.5860899067006, - 55.6332767402377, - 55.6805437553101, - 55.7278911564626, - 55.7753191489362, - 55.8228279386712, - 55.8704177323103, - 55.9180887372014, - 55.9658411614005, - 56.0136752136752, - 56.0615911035073, - 56.1095890410959, - 56.1576692373608, - 56.2058319039451, - 56.2540772532189, - 56.3024054982818, - 56.3508168529665, - 56.3993115318417, - 56.4478897502153, - 56.4965517241379, - 56.5452976704055, - 56.594127806563, - 56.6430423509075, - 56.6920415224914, - 56.7411255411255, - 56.790294627383, - 56.8395490026019, - 56.8888888888889, - 56.9383145091225, - 56.9878260869565, - 57.0374238468233, - 57.0871080139373, - 57.1368788142982, - 57.1867364746946, - 57.2366812227074, - 57.2867132867133, - 57.336832895888, - 57.3870402802102, - 57.4373356704645, - 57.4877192982456, - 57.5381913959614, - 57.5887521968366, - 57.6394019349165, - 57.6901408450704, - 57.7409691629956, - 57.7918871252205, - 57.8428949691086, - 57.8939929328622, - 57.9451812555261, - 57.9964601769912, - 58.0478299379982, - 58.0992907801418, - 58.150842945874, - 58.202486678508, - 58.2542222222222, - 58.3060498220641, - 58.3579697239537, - 58.4099821746881, - 58.4620874219447, - 58.5142857142857, - 58.5665773011618, - 58.6189624329159, - 58.6714413607878, - 58.7240143369176, - 58.7766816143498, - 58.8294434470377, - 58.8823000898473, - 58.9352517985612, - 58.988298829883, - 59.0414414414414, - 59.0946798917944, - 59.1480144404332, - 59.2014453477868, - 59.254972875226, - 59.3085972850679, - 59.3623188405797, - 59.4161378059837, - 59.470054446461, - 59.5240690281562, - 59.5781818181818, - 59.6323930846224, - 59.6867030965392, - 59.7411121239745, - 59.7956204379562, - 59.8502283105023, - 59.9049360146252, - 59.9597438243367, - 60.014652014652, - 60.0696608615949, - 60.1247706422018, - 60.1799816345271, - 60.2352941176471, - 60.2907083716651, - 60.3462246777164, - 60.4018433179724, - 60.4575645756458, - 60.5133887349954, - 60.5693160813309, - 60.6253469010176, - 60.6814814814815, - 60.7377201112141, - 60.7940630797774, - 60.8505106778087, - 60.907063197026, - 60.9637209302326, - 61.0204841713222, - 61.0773532152843, - 61.134328358209, - 61.1914098972923, - 61.2485981308411, - 61.3058933582788, - 61.3632958801498, - 61.4208059981256, - 61.4784240150094, - 61.5361502347418, - 61.593984962406, - 61.6519285042333, - 61.7099811676083, - 61.7681432610745, - 61.8264150943396, - 61.8847969782814, - 61.9432892249527, - 62.0018921475875, - 62.0606060606061, - 62.1194312796209, - 62.1783681214421, - 62.2374169040836, - 62.2965779467681, - 62.3558515699334, - 62.4152380952381, - 62.4747378455672, - 62.5343511450382, - 62.5940783190067, - 62.6539196940727, - 62.7138755980861, - 62.7739463601533, - 62.8341323106424, - 62.89443378119, - 62.954851104707, - 63.0153846153846, - 63.0760346487007, - 63.1368015414258, - 63.1976856316297, - 63.2586872586873, - 63.319806763285, - 63.3810444874275, - 63.4424007744434, - 63.5038759689923, - 63.5654704170708, - 63.6271844660194, - 63.6890184645287, - 63.7509727626459, - 63.8130477117819, - 63.8752436647174, - 63.9375609756098, - 64, - 64.0625610948192, - 64.1252446183953, - 64.1880509304603, - 64.2509803921569, - 64.3140333660451, - 64.37721021611, - 64.440511307768, - 64.503937007874, - 64.5674876847291, - 64.6311637080868, - 64.6949654491609, - 64.7588932806324, - 64.8229475766568, - 64.8871287128713, - 64.9514370664024, - 65.015873015873, - 65.0804369414101, - 65.1451292246521, - 65.2099502487562, - 65.2749003984064, - 65.3399800598205, - 65.4051896207585, - 65.4705294705295, - 65.536, - 65.6016016016016, - 65.6673346693387, - 65.7331995987964, - 65.7991967871486, - 65.8653266331658, - 65.9315895372234, - 65.9979859013092, - 66.0645161290323, - 66.1311806256307, - 66.1979797979798, - 66.2649140546006, - 66.331983805668, - 66.3991894630193, - 66.4665314401623, - 66.5340101522843, - 66.6016260162602, - 66.6693794506612, - 66.7372708757637, - 66.8053007135576, - 66.8734693877551, - 66.9417773237998, - 67.0102249488753, - 67.078812691914, - 67.1475409836066, - 67.2164102564103, - 67.2854209445585, - 67.3545734840699, - 67.4238683127572, - 67.4933058702369, - 67.5628865979382, - 67.6326109391125, - 67.702479338843, - 67.7724922440538, - 67.8426501035197, - 67.9129533678757, - 67.9834024896266, - 68.0539979231568, - 68.1247401247401, - 68.1956295525494, - 68.2666666666667, - 68.3378519290928, - 68.4091858037578, - 68.4806687565308, - 68.5523012552301, - 68.6240837696335, - 68.6960167714885, - 68.7681007345226, - 68.8403361344538, - 68.9127234490011, - 68.9852631578947, - 69.0579557428872, - 69.1308016877637, - 69.2038014783527, - 69.276955602537, - 69.3502645502646, - 69.4237288135593, - 69.4973488865324, - 69.5711252653928, - 69.6450584484591, - 69.7191489361702, - 69.7933972310969, - 69.8678038379531, - 69.9423692636073, - 70.017094017094, - 70.0919786096257, - 70.1670235546039, - 70.2422293676313, - 70.3175965665236, - 70.3931256713212, - 70.4688172043011, - 70.5446716899892, - 70.6206896551724, - 70.6968716289105, - 70.7732181425486, - 70.8497297297297, - 70.9264069264069, - 71.0032502708559, - 71.0802603036876, - 71.157437567861, - 71.2347826086957, - 71.3122959738847, - 71.3899782135076, - 71.4678298800436, - 71.5458515283843, - 71.624043715847, - 71.7024070021882, - 71.7809419496166, - 71.859649122807, - 71.9385290889133, - 72.0175824175824, - 72.0968096809681, - 72.1762114537445, - 72.2557883131202, - 72.3355408388521, - 72.4154696132597, - 72.4955752212389, - 72.5758582502769, - 72.6563192904656, - 72.7369589345172, - 72.8177777777778, - 72.8987764182425, - 72.9799554565702, - 73.0613154960981, - 73.1428571428571, - 73.2245810055866, - 73.3064876957494, - 73.3885778275476, - 73.4708520179372, - 73.5533108866442, - 73.6359550561798, - 73.718785151856, - 73.8018018018018, - 73.8850056369786, - 73.9683972911964, - 74.0519774011299, - 74.1357466063348, - 74.2197055492639, - 74.3038548752835, - 74.3881952326901, - 74.4727272727273, - 74.5574516496018, - 74.6423690205011, - 74.72748004561, - 74.8127853881279, - 74.8982857142857, - 74.9839816933639, - 75.0698739977091, - 75.1559633027523, - 75.2422502870264, - 75.3287356321839, - 75.415420023015, - 75.5023041474654, - 75.5893886966551, - 75.6766743648961, - 75.764161849711, - 75.8518518518518, - 75.9397450753187, - 76.0278422273782, - 76.116144018583, - 76.2046511627907, - 76.2933643771828, - 76.3822843822844, - 76.4714119019837, - 76.5607476635514, - 76.6502923976608, - 76.7400468384075, - 76.8300117233294, - 76.9201877934272, - 77.0105757931845, - 77.1011764705882, - 77.1919905771496, - 77.2830188679245, - 77.3742621015348, - 77.4657210401891, - 77.5573964497041, - 77.6492890995261, - 77.7413997627521, - 77.833729216152, - 77.9262782401902, - 78.0190476190476, - 78.1120381406436, - 78.2052505966587, - 78.2986857825568, - 78.3923444976077, - 78.4862275449102, - 78.5803357314149, - 78.6746698679472, - 78.7692307692308, - 78.864019253911, - 78.9590361445783, - 79.0542822677925, - 79.1497584541063, - 79.2454655380895, - 79.3414043583535, - 79.4375757575758, - 79.5339805825243, - 79.6306196840826, - 79.7274939172749, - 79.8246041412911, - 79.9219512195122, - 80.019536019536, - 80.1173594132029, - 80.2154222766218, - 80.3137254901961, - 80.4122699386503, - 80.5110565110565, - 80.610086100861, - 80.7093596059113, - 80.8088779284834, - 80.9086419753086, - 81.008652657602, - 81.1089108910891, - 81.2094175960347, - 81.3101736972705, - 81.4111801242236, - 81.5124378109453, - 81.6139476961395, - 81.715710723192, - 81.8177278401998, - 81.92, - 82.0225281602002, - 82.125313283208, - 82.228356336261, - 82.3316582914573, - 82.4352201257862, - 82.5390428211587, - 82.6431273644388, - 82.7474747474748, - 82.8520859671302, - 82.9569620253165, - 83.0621039290241, - 83.1675126903553, - 83.2731893265565, - 83.3791348600509, - 83.4853503184713, - 83.5918367346939, - 83.698595146871, - 83.8056265984655, - 83.9129321382842, - 84.0205128205128, - 84.1283697047497, - 84.2365038560411, - 84.3449163449163, - 84.4536082474227, - 84.5625806451613, - 84.671834625323, - 84.7813712807245, - 84.8911917098446, - 85.0012970168612, - 85.1116883116883, - 85.222366710013, - 85.3333333333333, - 85.4445893089961, - 85.556135770235, - 85.6679738562091, - 85.7801047120419, - 85.8925294888598, - 86.005249343832, - 86.1182654402102, - 86.2315789473684, - 86.3451910408432, - 86.4591029023747, - 86.5733157199472, - 86.6878306878307, - 86.8026490066225, - 86.9177718832891, - 87.0332005312085, - 87.1489361702128, - 87.2649800266312, - 87.3813333333333, - 87.497997329773, - 87.6149732620321, - 87.7322623828648, - 87.8498659517426, - 87.9677852348993, - 88.0860215053763, - 88.2045760430686, - 88.3234501347709, - 88.442645074224, - 88.5621621621622, - 88.68200270636, - 88.8021680216802, - 88.9226594301221, - 89.0434782608696, - 89.1646258503401, - 89.2861035422343, - 89.4079126875853, - 89.5300546448087, - 89.6525307797538, - 89.7753424657534, - 89.8984910836763, - 90.021978021978, - 90.1458046767538, - 90.2699724517906, - 90.3944827586207, - 90.5193370165746, - 90.6445366528354, - 90.7700831024931, - 90.8959778085992, - 91.0222222222222, - 91.1488178025035, - 91.2757660167131, - 91.4030683403068, - 91.5307262569833, - 91.6587412587413, - 91.7871148459384, - 91.9158485273492, - 92.0449438202247, - 92.1744022503516, - 92.3042253521127, - 92.4344146685472, - 92.5649717514124, - 92.6958981612447, - 92.8271954674221, - 92.958865248227, - 93.0909090909091, - 93.2233285917497, - 93.3561253561254, - 93.4893009985735, - 93.6228571428572, - 93.7567954220315, - 93.89111747851, - 94.025824964132, - 94.1609195402299, - 94.2964028776978, - 94.4322766570605, - 94.5685425685426, - 94.7052023121387, - 94.8422575976845, - 94.9797101449275, - 95.1175616835994, - 95.2558139534884, - 95.3944687045124, - 95.533527696793, - 95.6729927007299, - 95.812865497076, - 95.9531478770132, - 96.0938416422287, - 96.2349486049927, - 96.3764705882353, - 96.5184094256259, - 96.6607669616519, - 96.8035450516987, - 96.9467455621302, - 97.0903703703704, - 97.2344213649852, - 97.3789004457652, - 97.5238095238095, - 97.6691505216095, - 97.8149253731343, - 97.9611360239163, - 98.1077844311377, - 98.2548725637181, - 98.4024024024024, - 98.5503759398496, - 98.6987951807229, - 98.8476621417798, - 98.9969788519637, - 99.1467473524962, - 99.2969696969697, - 99.4476479514416, - 99.5987841945289, - 99.7503805175038, - 99.9024390243902, - 100.054961832061, - 100.207951070336, - 100.361408882083, - 100.515337423313, - 100.669738863287, - 100.824615384615, - 100.979969183359, - 101.135802469136, - 101.292117465224, - 101.448916408669, - 101.606201550388, - 101.76397515528, - 101.922239502333, - 102.080996884735, - 102.240249609984, - 102.4, - 102.560250391236, - 102.721003134796, - 102.882260596546, - 103.044025157233, - 103.206299212598, - 103.369085173502, - 103.532385466035, - 103.696202531646, - 103.860538827258, - 104.025396825397, - 104.190779014308, - 104.356687898089, - 104.52312599681, - 104.690095846645, - 104.8576, - 105.025641025641, - 105.194221508828, - 105.363344051447, - 105.533011272142, - 105.703225806452, - 105.873990306947, - 106.045307443366, - 106.217179902755, - 106.38961038961, - 106.562601626016, - 106.736156351792, - 106.910277324633, - 107.084967320261, - 107.26022913257, - 107.436065573771, - 107.612479474548, - 107.789473684211, - 107.96705107084, - 108.145214521452, - 108.323966942149, - 108.503311258278, - 108.683250414594, - 108.863787375415, - 109.044925124792, - 109.226666666667, - 109.409015025042, - 109.591973244147, - 109.77554438861, - 109.959731543624, - 110.144537815126, - 110.329966329966, - 110.516020236088, - 110.702702702703, - 110.890016920474, - 111.077966101695, - 111.266553480475, - 111.455782312925, - 111.645655877342, - 111.836177474403, - 112.02735042735, - 112.219178082192, - 112.41166380789, - 112.604810996564, - 112.798623063683, - 112.993103448276, - 113.188255613126, - 113.384083044983, - 113.580589254766, - 113.777777777778, - 113.975652173913, - 114.174216027875, - 114.373472949389, - 114.573426573427, - 114.77408056042, - 114.975438596491, - 115.177504393673, - 115.380281690141, - 115.583774250441, - 115.787985865724, - 115.992920353982, - 116.198581560284, - 116.404973357016, - 116.612099644128, - 116.819964349376, - 117.028571428571, - 117.237924865832, - 117.448028673835, - 117.658886894075, - 117.870503597122, - 118.082882882883, - 118.296028880866, - 118.509945750452, - 118.724637681159, - 118.940108892922, - 119.156363636364, - 119.373406193078, - 119.591240875912, - 119.80987202925, - 120.029304029304, - 120.249541284404, - 120.470588235294, - 120.692449355433, - 120.915129151292, - 121.138632162662, - 121.362962962963, - 121.588126159555, - 121.814126394052, - 122.040968342644, - 122.268656716418, - 122.497196261682, - 122.7265917603, - 122.956848030019, - 123.187969924812, - 123.419962335217, - 123.652830188679, - 123.886578449906, - 124.121212121212, - 124.356736242884, - 124.593155893536, - 124.830476190476, - 125.068702290076, - 125.307839388145, - 125.547892720307, - 125.78886756238, - 126.030769230769, - 126.273603082852, - 126.517374517375, - 126.762088974855, - 127.007751937985, - 127.254368932039, - 127.501945525292, - 127.750487329435, - 128, - 128.250489236791, - 128.501960784314, - 128.75442043222, - 129.007874015748, - 129.262327416174, - 129.517786561265, - 129.774257425743, - 130.031746031746, - 130.290258449304, - 130.549800796813, - 130.810379241517, - 131.072, - 131.334669338677, - 131.598393574297, - 131.863179074447, - 132.129032258065, - 132.39595959596, - 132.663967611336, - 132.933062880325, - 133.20325203252, - 133.474541751527, - 133.74693877551, - 134.020449897751, - 134.295081967213, - 134.570841889117, - 134.847736625514, - 135.125773195876, - 135.404958677686, - 135.685300207039, - 135.966804979253, - 136.24948024948, - 136.533333333333, - 136.818371607516, - 137.10460251046, - 137.392033542977, - 137.680672268908, - 137.970526315789, - 138.261603375527, - 138.553911205074, - 138.847457627119, - 139.142250530786, - 139.43829787234, - 139.735607675906, - 140.034188034188, - 140.334047109208, - 140.635193133047, - 140.937634408602, - 141.241379310345, - 141.546436285097, - 141.852813852814, - 142.160520607375, - 142.469565217391, - 142.779956427015, - 143.091703056769, - 143.404814004376, - 143.719298245614, - 144.035164835165, - 144.352422907489, - 144.671081677704, - 144.991150442478, - 145.312638580931, - 145.635555555556, - 145.95991091314, - 146.285714285714, - 146.612975391499, - 146.941704035874, - 147.27191011236, - 147.603603603604, - 147.936794582393, - 148.27149321267, - 148.607709750567, - 148.945454545455, - 149.284738041002, - 149.625570776256, - 149.967963386728, - 150.311926605505, - 150.657471264368, - 151.004608294931, - 151.353348729792, - 151.703703703704, - 152.055684454756, - 152.409302325581, - 152.764568764569, - 153.121495327103, - 153.480093676815, - 153.840375586854, - 154.202352941176, - 154.566037735849, - 154.931442080378, - 155.298578199052, - 155.667458432304, - 156.038095238095, - 156.410501193317, - 156.784688995215, - 157.16067146283, - 157.538461538462, - 157.918072289157, - 158.299516908213, - 158.682808716707, - 159.067961165049, - 159.45498783455, - 159.843902439024, - 160.234718826406, - 160.627450980392, - 161.022113022113, - 161.418719211823, - 161.817283950617, - 162.217821782178, - 162.620347394541, - 163.024875621891, - 163.431421446384, - 163.84, - 164.250626566416, - 164.663316582915, - 165.078085642317, - 165.49494949495, - 165.913924050633, - 166.335025380711, - 166.758269720102, - 167.183673469388, - 167.611253196931, - 168.041025641026, - 168.473007712082, - 168.907216494845, - 169.343669250646, - 169.782383419689, - 170.223376623377, - 170.666666666667, - 171.11227154047, - 171.560209424084, - 172.010498687664, - 172.463157894737, - 172.918205804749, - 173.375661375661, - 173.835543766578, - 174.297872340426, - 174.762666666667, - 175.229946524064, - 175.699731903485, - 176.172043010753, - 176.646900269542, - 177.124324324324, - 177.60433604336, - 178.086956521739, - 178.572207084469, - 179.060109289618, - 179.550684931507, - 180.043956043956, - 180.539944903581, - 181.038674033149, - 181.540166204986, - 182.044444444444, - 182.551532033426, - 183.061452513966, - 183.574229691877, - 184.089887640449, - 184.608450704225, - 185.129943502825, - 185.654390934844, - 186.181818181818, - 186.712250712251, - 187.245714285714, - 187.78223495702, - 188.32183908046, - 188.864553314121, - 189.410404624277, - 189.959420289855, - 190.511627906977, - 191.067055393586, - 191.625730994152, - 192.187683284457, - 192.752941176471, - 193.321533923304, - 193.89349112426, - 194.46884272997, - 195.047619047619, - 195.629850746269, - 196.215568862275, - 196.804804804805, - 197.397590361446, - 197.993957703928, - 198.593939393939, - 199.197568389058, - 199.804878048781, - 200.415902140673, - 201.030674846626, - 201.649230769231, - 202.271604938272, - 202.897832817337, - 203.527950310559, - 204.16199376947, - 204.8, - 205.442006269592, - 206.088050314465, - 206.738170347003, - 207.392405063291, - 208.050793650794, - 208.713375796178, - 209.380191693291, - 210.051282051282, - 210.726688102894, - 211.406451612903, - 212.090614886731, - 212.779220779221, - 213.472312703583, - 214.169934640523, - 214.872131147541, - 215.578947368421, - 216.290429042904, - 217.006622516556, - 217.727574750831, - 218.453333333333, - 219.183946488294, - 219.919463087248, - 220.659932659933, - 221.405405405405, - 222.15593220339, - 222.91156462585, - 223.672354948805, - 224.438356164384, - 225.209621993127, - 225.986206896552, - 226.768166089965, - 227.555555555556, - 228.348432055749, - 229.146853146853, - 229.950877192982, - 230.760563380282, - 231.575971731449, - 232.397163120567, - 233.224199288256, - 234.057142857143, - 234.89605734767, - 235.741007194245, - 236.592057761733, - 237.449275362319, - 238.312727272727, - 239.182481751825, - 240.058608058608, - 240.941176470588, - 241.830258302583, - 242.725925925926, - 243.628252788104, - 244.537313432836, - 245.453183520599, - 246.375939849624, - 247.305660377358, - 248.242424242424, - 249.186311787072, - 250.137404580153, - 251.095785440613, - 252.061538461538, - 253.034749034749, - 254.015503875969, - 255.003891050584, - 256, - 257.003921568627, - 258.015748031496, - 259.03557312253, - 260.063492063492, - 261.099601593625, - 262.144, - 263.196787148594, - 264.258064516129, - 265.327935222672, - 266.406504065041, - 267.49387755102, - 268.590163934426, - 269.695473251029, - 270.809917355372, - 271.933609958506, - 273.066666666667, - 274.20920502092, - 275.361344537815, - 276.523206751055, - 277.694915254237, - 278.876595744681, - 280.068376068376, - 281.270386266094, - 282.48275862069, - 283.705627705628, - 284.939130434783, - 286.183406113537, - 287.438596491228, - 288.704845814978, - 289.982300884956, - 291.271111111111, - 292.571428571429, - 293.883408071749, - 295.207207207207, - 296.542986425339, - 297.890909090909, - 299.251141552511, - 300.623853211009, - 302.009216589862, - 303.407407407407, - 304.818604651163, - 306.242990654206, - 307.680751173709, - 309.132075471698, - 310.597156398104, - 312.07619047619, - 313.569377990431, - 315.076923076923, - 316.599033816425, - 318.135922330097, - 319.687804878049, - 321.254901960784, - 322.837438423645, - 324.435643564356, - 326.049751243781, - 327.68, - 329.326633165829, - 330.989898989899, - 332.670050761421, - 334.367346938775, - 336.082051282051, - 337.814432989691, - 339.564766839378, - 341.333333333333, - 343.120418848168, - 344.926315789474, - 346.751322751323, - 348.595744680851, - 350.459893048128, - 352.344086021505, - 354.248648648649, - 356.173913043478, - 358.120218579235, - 360.087912087912, - 362.077348066298, - 364.088888888889, - 366.122905027933, - 368.179775280899, - 370.25988700565, - 372.363636363636, - 374.491428571429, - 376.64367816092, - 378.820809248555, - 381.023255813953, - 383.251461988304, - 385.505882352941, - 387.786982248521, - 390.095238095238, - 392.431137724551, - 394.795180722892, - 397.187878787879, - 399.609756097561, - 402.061349693252, - 404.543209876543, - 407.055900621118, - 409.6, - 412.176100628931, - 414.784810126582, - 417.426751592357, - 420.102564102564, - 422.812903225807, - 425.558441558442, - 428.339869281046, - 431.157894736842, - 434.013245033113, - 436.906666666667, - 439.838926174497, - 442.810810810811, - 445.823129251701, - 448.876712328767, - 451.972413793103, - 455.111111111111, - 458.293706293706, - 461.521126760563, - 464.794326241135, - 468.114285714286, - 471.482014388489, - 474.898550724638, - 478.36496350365, - 481.882352941176, - 485.451851851852, - 489.074626865672, - 492.751879699248, - 496.484848484849, - 500.274809160305, - 504.123076923077, - 508.031007751938, - 512, - 516.031496062992, - 520.126984126984, - 524.288, - 528.516129032258, - 532.813008130081, - 537.180327868852, - 541.619834710744, - 546.133333333333, - 550.72268907563, - 555.389830508475, - 560.136752136752, - 564.965517241379, - 569.878260869565, - 574.877192982456, - 579.964601769912, - 585.142857142857, - 590.414414414414, - 595.781818181818, - 601.247706422018, - 606.814814814815, - 612.485981308411, - 618.264150943396, - 624.152380952381, - 630.153846153846, - 636.271844660194, - 642.509803921569, - 648.871287128713, - 655.36, - 661.979797979798, - 668.734693877551, - 675.628865979381, - 682.666666666667, - 689.852631578947, - 697.191489361702, - 704.688172043011, - 712.347826086956, - 720.175824175824, - 728.177777777778, - 736.359550561798, - 744.727272727273, - 753.287356321839, - 762.046511627907, - 771.011764705882, - 780.190476190476, - 789.590361445783, - 799.219512195122, - 809.086419753086, - 819.2, - 829.569620253165, - 840.205128205128, - 851.116883116883, - 862.315789473684, - 873.813333333333, - 885.621621621622, - 897.753424657534, - 910.222222222222, - 923.042253521127, - 936.228571428571, - 949.797101449275, - 963.764705882353, - 978.149253731343, - 992.969696969697, - 1008.24615384615, - 1024, - 1040.25396825397, - 1057.03225806452, - 1074.36065573771, - 1092.26666666667, - 1110.77966101695, - 1129.93103448276, - 1149.75438596491, - 1170.28571428571, - 1191.56363636364, - 1213.62962962963, - 1236.52830188679, - 1260.30769230769, - 1285.01960784314, - 1310.72, - 1337.4693877551, - 1365.33333333333, - 1394.3829787234, - 1424.69565217391, - 1456.35555555556, - 1489.45454545455, - 1524.09302325581, - 1560.38095238095, - 1598.43902439024, - 1638.4, - 1680.41025641026, - 1724.63157894737, - 1771.24324324324, - 1820.44444444444, - 1872.45714285714, - 1927.52941176471, - 1985.93939393939, - 2048, - 2114.06451612903, - 2184.53333333333, - 2259.86206896552, - 2340.57142857143, - 2427.25925925926, - 2520.61538461538, - 2621.44, - 2730.66666666667, - 2849.39130434783, - 2978.90909090909, - 3120.7619047619, - 3276.8, - 3449.26315789474, - 3640.88888888889, - 3855.05882352941, - 4096, - 4369.06666666667, - 4681.14285714286, - 5041.23076923077, - 5461.33333333333, - 5957.81818181818, - 6553.6, - 7281.77777777778, - 8192, - 9362.28571428571, - 10922.6666666667, - 13107.2, - 16384, - 21845.3333333333, - 32768, - 65536 }; +const fixed16_16 freqTable[2048] = { + float_to_fp16_16(32 / FREQUENCY_RATE), + float_to_fp16_16(32.0156326331216 / FREQUENCY_RATE), + float_to_fp16_16(32.0312805474096 / FREQUENCY_RATE), + float_to_fp16_16(32.0469437652812 / FREQUENCY_RATE), + float_to_fp16_16(32.0626223091976 / FREQUENCY_RATE), + float_to_fp16_16(32.0783162016642 / FREQUENCY_RATE), + float_to_fp16_16(32.0940254652302 / FREQUENCY_RATE), + float_to_fp16_16(32.109750122489 / FREQUENCY_RATE), + float_to_fp16_16(32.1254901960784 / FREQUENCY_RATE), + float_to_fp16_16(32.1412457086807 / FREQUENCY_RATE), + float_to_fp16_16(32.1570166830226 / FREQUENCY_RATE), + float_to_fp16_16(32.1728031418753 / FREQUENCY_RATE), + float_to_fp16_16(32.188605108055 / FREQUENCY_RATE), + float_to_fp16_16(32.2044226044226 / FREQUENCY_RATE), + float_to_fp16_16(32.220255653884 / FREQUENCY_RATE), + float_to_fp16_16(32.2361042793901 / FREQUENCY_RATE), + float_to_fp16_16(32.251968503937 / FREQUENCY_RATE), + float_to_fp16_16(32.2678483505662 / FREQUENCY_RATE), + float_to_fp16_16(32.2837438423645 / FREQUENCY_RATE), + float_to_fp16_16(32.2996550024643 / FREQUENCY_RATE), + float_to_fp16_16(32.3155818540434 / FREQUENCY_RATE), + float_to_fp16_16(32.3315244203256 / FREQUENCY_RATE), + float_to_fp16_16(32.3474827245805 / FREQUENCY_RATE), + float_to_fp16_16(32.3634567901235 / FREQUENCY_RATE), + float_to_fp16_16(32.3794466403162 / FREQUENCY_RATE), + float_to_fp16_16(32.3954522985665 / FREQUENCY_RATE), + float_to_fp16_16(32.4114737883284 / FREQUENCY_RATE), + float_to_fp16_16(32.4275111331024 / FREQUENCY_RATE), + float_to_fp16_16(32.4435643564356 / FREQUENCY_RATE), + float_to_fp16_16(32.4596334819217 / FREQUENCY_RATE), + float_to_fp16_16(32.4757185332012 / FREQUENCY_RATE), + float_to_fp16_16(32.4918195339613 / FREQUENCY_RATE), + float_to_fp16_16(32.5079365079365 / FREQUENCY_RATE), + float_to_fp16_16(32.5240694789082 / FREQUENCY_RATE), + float_to_fp16_16(32.5402184707051 / FREQUENCY_RATE), + float_to_fp16_16(32.5563835072032 / FREQUENCY_RATE), + float_to_fp16_16(32.572564612326 / FREQUENCY_RATE), + float_to_fp16_16(32.5887618100448 / FREQUENCY_RATE), + float_to_fp16_16(32.6049751243781 / FREQUENCY_RATE), + float_to_fp16_16(32.6212045793927 / FREQUENCY_RATE), + float_to_fp16_16(32.6374501992032 / FREQUENCY_RATE), + float_to_fp16_16(32.6537120079721 / FREQUENCY_RATE), + float_to_fp16_16(32.6699900299103 / FREQUENCY_RATE), + float_to_fp16_16(32.6862842892768 / FREQUENCY_RATE), + float_to_fp16_16(32.7025948103792 / FREQUENCY_RATE), + float_to_fp16_16(32.7189216175736 / FREQUENCY_RATE), + float_to_fp16_16(32.7352647352647 / FREQUENCY_RATE), + float_to_fp16_16(32.751624187906 / FREQUENCY_RATE), + float_to_fp16_16(32.768 / FREQUENCY_RATE), + float_to_fp16_16(32.784392196098 / FREQUENCY_RATE), + float_to_fp16_16(32.8008008008008 / FREQUENCY_RATE), + float_to_fp16_16(32.8172258387581 / FREQUENCY_RATE), + float_to_fp16_16(32.8336673346693 / FREQUENCY_RATE), + float_to_fp16_16(32.8501253132832 / FREQUENCY_RATE), + float_to_fp16_16(32.8665997993982 / FREQUENCY_RATE), + float_to_fp16_16(32.8830908178625 / FREQUENCY_RATE), + float_to_fp16_16(32.8995983935743 / FREQUENCY_RATE), + float_to_fp16_16(32.9161225514817 / FREQUENCY_RATE), + float_to_fp16_16(32.9326633165829 / FREQUENCY_RATE), + float_to_fp16_16(32.9492207139266 / FREQUENCY_RATE), + float_to_fp16_16(32.9657947686117 / FREQUENCY_RATE), + float_to_fp16_16(32.9823855057876 / FREQUENCY_RATE), + float_to_fp16_16(32.9989929506546 / FREQUENCY_RATE), + float_to_fp16_16(33.0156171284635 / FREQUENCY_RATE), + float_to_fp16_16(33.0322580645161 / FREQUENCY_RATE), + float_to_fp16_16(33.0489157841654 / FREQUENCY_RATE), + float_to_fp16_16(33.0655903128153 / FREQUENCY_RATE), + float_to_fp16_16(33.0822816759213 / FREQUENCY_RATE), + float_to_fp16_16(33.0989898989899 / FREQUENCY_RATE), + float_to_fp16_16(33.1157150075796 / FREQUENCY_RATE), + float_to_fp16_16(33.1324570273003 / FREQUENCY_RATE), + float_to_fp16_16(33.1492159838139 / FREQUENCY_RATE), + float_to_fp16_16(33.165991902834 / FREQUENCY_RATE), + float_to_fp16_16(33.1827848101266 / FREQUENCY_RATE), + float_to_fp16_16(33.1995947315096 / FREQUENCY_RATE), + float_to_fp16_16(33.2164216928535 / FREQUENCY_RATE), + float_to_fp16_16(33.2332657200811 / FREQUENCY_RATE), + float_to_fp16_16(33.2501268391679 / FREQUENCY_RATE), + float_to_fp16_16(33.2670050761421 / FREQUENCY_RATE), + float_to_fp16_16(33.2839004570848 / FREQUENCY_RATE), + float_to_fp16_16(33.3008130081301 / FREQUENCY_RATE), + float_to_fp16_16(33.3177427554652 / FREQUENCY_RATE), + float_to_fp16_16(33.3346897253306 / FREQUENCY_RATE), + float_to_fp16_16(33.3516539440204 / FREQUENCY_RATE), + float_to_fp16_16(33.3686354378819 / FREQUENCY_RATE), + float_to_fp16_16(33.3856342333164 / FREQUENCY_RATE), + float_to_fp16_16(33.4026503567788 / FREQUENCY_RATE), + float_to_fp16_16(33.4196838347782 / FREQUENCY_RATE), + float_to_fp16_16(33.4367346938776 / FREQUENCY_RATE), + float_to_fp16_16(33.4538029606942 / FREQUENCY_RATE), + float_to_fp16_16(33.4708886618999 / FREQUENCY_RATE), + float_to_fp16_16(33.4879918242207 / FREQUENCY_RATE), + float_to_fp16_16(33.5051124744376 / FREQUENCY_RATE), + float_to_fp16_16(33.5222506393862 / FREQUENCY_RATE), + float_to_fp16_16(33.539406345957 / FREQUENCY_RATE), + float_to_fp16_16(33.5565796210957 / FREQUENCY_RATE), + float_to_fp16_16(33.5737704918033 / FREQUENCY_RATE), + float_to_fp16_16(33.5909789851358 / FREQUENCY_RATE), + float_to_fp16_16(33.6082051282051 / FREQUENCY_RATE), + float_to_fp16_16(33.6254489481786 / FREQUENCY_RATE), + float_to_fp16_16(33.6427104722793 / FREQUENCY_RATE), + float_to_fp16_16(33.6599897277863 / FREQUENCY_RATE), + float_to_fp16_16(33.6772867420349 / FREQUENCY_RATE), + float_to_fp16_16(33.6946015424164 / FREQUENCY_RATE), + float_to_fp16_16(33.7119341563786 / FREQUENCY_RATE), + float_to_fp16_16(33.7292846114256 / FREQUENCY_RATE), + float_to_fp16_16(33.7466529351184 / FREQUENCY_RATE), + float_to_fp16_16(33.7640391550747 / FREQUENCY_RATE), + float_to_fp16_16(33.7814432989691 / FREQUENCY_RATE), + float_to_fp16_16(33.7988653945333 / FREQUENCY_RATE), + float_to_fp16_16(33.8163054695562 / FREQUENCY_RATE), + float_to_fp16_16(33.8337635518844 / FREQUENCY_RATE), + float_to_fp16_16(33.8512396694215 / FREQUENCY_RATE), + float_to_fp16_16(33.8687338501292 / FREQUENCY_RATE), + float_to_fp16_16(33.8862461220269 / FREQUENCY_RATE), + float_to_fp16_16(33.9037765131919 / FREQUENCY_RATE), + float_to_fp16_16(33.9213250517598 / FREQUENCY_RATE), + float_to_fp16_16(33.9388917659244 / FREQUENCY_RATE), + float_to_fp16_16(33.9564766839378 / FREQUENCY_RATE), + float_to_fp16_16(33.9740798341109 / FREQUENCY_RATE), + float_to_fp16_16(33.9917012448133 / FREQUENCY_RATE), + float_to_fp16_16(34.0093409444733 / FREQUENCY_RATE), + float_to_fp16_16(34.0269989615784 / FREQUENCY_RATE), + float_to_fp16_16(34.0446753246753 / FREQUENCY_RATE), + float_to_fp16_16(34.0623700623701 / FREQUENCY_RATE), + float_to_fp16_16(34.0800832033281 / FREQUENCY_RATE), + float_to_fp16_16(34.0978147762747 / FREQUENCY_RATE), + float_to_fp16_16(34.1155648099948 / FREQUENCY_RATE), + float_to_fp16_16(34.1333333333333 / FREQUENCY_RATE), + float_to_fp16_16(34.1511203751954 / FREQUENCY_RATE), + float_to_fp16_16(34.1689259645464 / FREQUENCY_RATE), + float_to_fp16_16(34.1867501304121 / FREQUENCY_RATE), + float_to_fp16_16(34.2045929018789 / FREQUENCY_RATE), + float_to_fp16_16(34.222454308094 / FREQUENCY_RATE), + float_to_fp16_16(34.2403343782654 / FREQUENCY_RATE), + float_to_fp16_16(34.2582331416623 / FREQUENCY_RATE), + float_to_fp16_16(34.2761506276151 / FREQUENCY_RATE), + float_to_fp16_16(34.2940868655154 / FREQUENCY_RATE), + float_to_fp16_16(34.3120418848168 / FREQUENCY_RATE), + float_to_fp16_16(34.330015715034 / FREQUENCY_RATE), + float_to_fp16_16(34.3480083857442 / FREQUENCY_RATE), + float_to_fp16_16(34.3660199265863 / FREQUENCY_RATE), + float_to_fp16_16(34.3840503672613 / FREQUENCY_RATE), + float_to_fp16_16(34.4020997375328 / FREQUENCY_RATE), + float_to_fp16_16(34.4201680672269 / FREQUENCY_RATE), + float_to_fp16_16(34.4382553862323 / FREQUENCY_RATE), + float_to_fp16_16(34.4563617245005 / FREQUENCY_RATE), + float_to_fp16_16(34.4744871120463 / FREQUENCY_RATE), + float_to_fp16_16(34.4926315789474 / FREQUENCY_RATE), + float_to_fp16_16(34.5107951553449 / FREQUENCY_RATE), + float_to_fp16_16(34.5289778714436 / FREQUENCY_RATE), + float_to_fp16_16(34.5471797575119 / FREQUENCY_RATE), + float_to_fp16_16(34.5654008438819 / FREQUENCY_RATE), + float_to_fp16_16(34.5836411609499 / FREQUENCY_RATE), + float_to_fp16_16(34.6019007391763 / FREQUENCY_RATE), + float_to_fp16_16(34.6201796090861 / FREQUENCY_RATE), + float_to_fp16_16(34.6384778012685 / FREQUENCY_RATE), + float_to_fp16_16(34.6567953463776 / FREQUENCY_RATE), + float_to_fp16_16(34.6751322751323 / FREQUENCY_RATE), + float_to_fp16_16(34.6934886183166 / FREQUENCY_RATE), + float_to_fp16_16(34.7118644067797 / FREQUENCY_RATE), + float_to_fp16_16(34.7302596714361 / FREQUENCY_RATE), + float_to_fp16_16(34.7486744432662 / FREQUENCY_RATE), + float_to_fp16_16(34.7671087533156 / FREQUENCY_RATE), + float_to_fp16_16(34.7855626326964 / FREQUENCY_RATE), + float_to_fp16_16(34.8040361125863 / FREQUENCY_RATE), + float_to_fp16_16(34.8225292242295 / FREQUENCY_RATE), + float_to_fp16_16(34.8410419989367 / FREQUENCY_RATE), + float_to_fp16_16(34.8595744680851 / FREQUENCY_RATE), + float_to_fp16_16(34.8781266631187 / FREQUENCY_RATE), + float_to_fp16_16(34.8966986155485 / FREQUENCY_RATE), + float_to_fp16_16(34.9152903569526 / FREQUENCY_RATE), + float_to_fp16_16(34.9339019189765 / FREQUENCY_RATE), + float_to_fp16_16(34.9525333333333 / FREQUENCY_RATE), + float_to_fp16_16(34.9711846318036 / FREQUENCY_RATE), + float_to_fp16_16(34.989855846236 / FREQUENCY_RATE), + float_to_fp16_16(35.008547008547 / FREQUENCY_RATE), + float_to_fp16_16(35.0272581507215 / FREQUENCY_RATE), + float_to_fp16_16(35.0459893048128 / FREQUENCY_RATE), + float_to_fp16_16(35.0647405029427 / FREQUENCY_RATE), + float_to_fp16_16(35.0835117773019 / FREQUENCY_RATE), + float_to_fp16_16(35.10230316015 / FREQUENCY_RATE), + float_to_fp16_16(35.1211146838156 / FREQUENCY_RATE), + float_to_fp16_16(35.1399463806971 / FREQUENCY_RATE), + float_to_fp16_16(35.1587982832618 / FREQUENCY_RATE), + float_to_fp16_16(35.1776704240472 / FREQUENCY_RATE), + float_to_fp16_16(35.1965628356606 / FREQUENCY_RATE), + float_to_fp16_16(35.2154755507792 / FREQUENCY_RATE), + float_to_fp16_16(35.2344086021505 / FREQUENCY_RATE), + float_to_fp16_16(35.2533620225928 / FREQUENCY_RATE), + float_to_fp16_16(35.2723358449946 / FREQUENCY_RATE), + float_to_fp16_16(35.2913301023156 / FREQUENCY_RATE), + float_to_fp16_16(35.3103448275862 / FREQUENCY_RATE), + float_to_fp16_16(35.3293800539084 / FREQUENCY_RATE), + float_to_fp16_16(35.3484358144552 / FREQUENCY_RATE), + float_to_fp16_16(35.3675121424717 / FREQUENCY_RATE), + float_to_fp16_16(35.3866090712743 / FREQUENCY_RATE), + float_to_fp16_16(35.4057266342518 / FREQUENCY_RATE), + float_to_fp16_16(35.4248648648649 / FREQUENCY_RATE), + float_to_fp16_16(35.4440237966468 / FREQUENCY_RATE), + float_to_fp16_16(35.4632034632035 / FREQUENCY_RATE), + float_to_fp16_16(35.4824038982133 / FREQUENCY_RATE), + float_to_fp16_16(35.501625135428 / FREQUENCY_RATE), + float_to_fp16_16(35.5208672086721 / FREQUENCY_RATE), + float_to_fp16_16(35.5401301518438 / FREQUENCY_RATE), + float_to_fp16_16(35.5594139989148 / FREQUENCY_RATE), + float_to_fp16_16(35.5787187839305 / FREQUENCY_RATE), + float_to_fp16_16(35.5980445410103 / FREQUENCY_RATE), + float_to_fp16_16(35.6173913043478 / FREQUENCY_RATE), + float_to_fp16_16(35.636759108211 / FREQUENCY_RATE), + float_to_fp16_16(35.6561479869423 / FREQUENCY_RATE), + float_to_fp16_16(35.6755579749592 / FREQUENCY_RATE), + float_to_fp16_16(35.6949891067538 / FREQUENCY_RATE), + float_to_fp16_16(35.7144414168937 / FREQUENCY_RATE), + float_to_fp16_16(35.7339149400218 / FREQUENCY_RATE), + float_to_fp16_16(35.7534097108565 / FREQUENCY_RATE), + float_to_fp16_16(35.7729257641921 / FREQUENCY_RATE), + float_to_fp16_16(35.792463134899 / FREQUENCY_RATE), + float_to_fp16_16(35.8120218579235 / FREQUENCY_RATE), + float_to_fp16_16(35.8316019682887 / FREQUENCY_RATE), + float_to_fp16_16(35.8512035010941 / FREQUENCY_RATE), + float_to_fp16_16(35.8708264915161 / FREQUENCY_RATE), + float_to_fp16_16(35.8904709748083 / FREQUENCY_RATE), + float_to_fp16_16(35.9101369863014 / FREQUENCY_RATE), + float_to_fp16_16(35.9298245614035 / FREQUENCY_RATE), + float_to_fp16_16(35.9495337356007 / FREQUENCY_RATE), + float_to_fp16_16(35.9692645444566 / FREQUENCY_RATE), + float_to_fp16_16(35.9890170236134 / FREQUENCY_RATE), + float_to_fp16_16(36.0087912087912 / FREQUENCY_RATE), + float_to_fp16_16(36.0285871357889 / FREQUENCY_RATE), + float_to_fp16_16(36.048404840484 / FREQUENCY_RATE), + float_to_fp16_16(36.0682443588332 / FREQUENCY_RATE), + float_to_fp16_16(36.0881057268722 / FREQUENCY_RATE), + float_to_fp16_16(36.1079889807162 / FREQUENCY_RATE), + float_to_fp16_16(36.1278941565601 / FREQUENCY_RATE), + float_to_fp16_16(36.1478212906784 / FREQUENCY_RATE), + float_to_fp16_16(36.167770419426 / FREQUENCY_RATE), + float_to_fp16_16(36.187741579238 / FREQUENCY_RATE), + float_to_fp16_16(36.2077348066298 / FREQUENCY_RATE), + float_to_fp16_16(36.2277501381979 / FREQUENCY_RATE), + float_to_fp16_16(36.2477876106195 / FREQUENCY_RATE), + float_to_fp16_16(36.267847260653 / FREQUENCY_RATE), + float_to_fp16_16(36.2879291251384 / FREQUENCY_RATE), + float_to_fp16_16(36.3080332409972 / FREQUENCY_RATE), + float_to_fp16_16(36.3281596452328 / FREQUENCY_RATE), + float_to_fp16_16(36.3483083749307 / FREQUENCY_RATE), + float_to_fp16_16(36.3684794672586 / FREQUENCY_RATE), + float_to_fp16_16(36.388672959467 / FREQUENCY_RATE), + float_to_fp16_16(36.4088888888889 / FREQUENCY_RATE), + float_to_fp16_16(36.4291272929405 / FREQUENCY_RATE), + float_to_fp16_16(36.4493882091212 / FREQUENCY_RATE), + float_to_fp16_16(36.4696716750139 / FREQUENCY_RATE), + float_to_fp16_16(36.4899777282851 / FREQUENCY_RATE), + float_to_fp16_16(36.5103064066852 / FREQUENCY_RATE), + float_to_fp16_16(36.5306577480491 / FREQUENCY_RATE), + float_to_fp16_16(36.5510317902956 / FREQUENCY_RATE), + float_to_fp16_16(36.5714285714286 / FREQUENCY_RATE), + float_to_fp16_16(36.5918481295366 / FREQUENCY_RATE), + float_to_fp16_16(36.6122905027933 / FREQUENCY_RATE), + float_to_fp16_16(36.6327557294578 / FREQUENCY_RATE), + float_to_fp16_16(36.6532438478747 / FREQUENCY_RATE), + float_to_fp16_16(36.6737548964745 / FREQUENCY_RATE), + float_to_fp16_16(36.6942889137738 / FREQUENCY_RATE), + float_to_fp16_16(36.7148459383753 / FREQUENCY_RATE), + float_to_fp16_16(36.7354260089686 / FREQUENCY_RATE), + float_to_fp16_16(36.7560291643298 / FREQUENCY_RATE), + float_to_fp16_16(36.7766554433221 / FREQUENCY_RATE), + float_to_fp16_16(36.7973048848961 / FREQUENCY_RATE), + float_to_fp16_16(36.8179775280899 / FREQUENCY_RATE), + float_to_fp16_16(36.8386734120292 / FREQUENCY_RATE), + float_to_fp16_16(36.859392575928 / FREQUENCY_RATE), + float_to_fp16_16(36.8801350590884 / FREQUENCY_RATE), + float_to_fp16_16(36.9009009009009 / FREQUENCY_RATE), + float_to_fp16_16(36.9216901408451 / FREQUENCY_RATE), + float_to_fp16_16(36.9425028184893 / FREQUENCY_RATE), + float_to_fp16_16(36.9633389734913 / FREQUENCY_RATE), + float_to_fp16_16(36.9841986455982 / FREQUENCY_RATE), + float_to_fp16_16(37.0050818746471 / FREQUENCY_RATE), + float_to_fp16_16(37.025988700565 / FREQUENCY_RATE), + float_to_fp16_16(37.0469191633691 / FREQUENCY_RATE), + float_to_fp16_16(37.0678733031674 / FREQUENCY_RATE), + float_to_fp16_16(37.0888511601585 / FREQUENCY_RATE), + float_to_fp16_16(37.1098527746319 / FREQUENCY_RATE), + float_to_fp16_16(37.1308781869688 / FREQUENCY_RATE), + float_to_fp16_16(37.1519274376417 / FREQUENCY_RATE), + float_to_fp16_16(37.173000567215 / FREQUENCY_RATE), + float_to_fp16_16(37.1940976163451 / FREQUENCY_RATE), + float_to_fp16_16(37.2152186257808 / FREQUENCY_RATE), + float_to_fp16_16(37.2363636363636 / FREQUENCY_RATE), + float_to_fp16_16(37.2575326890279 / FREQUENCY_RATE), + float_to_fp16_16(37.2787258248009 / FREQUENCY_RATE), + float_to_fp16_16(37.2999430848036 / FREQUENCY_RATE), + float_to_fp16_16(37.3211845102506 / FREQUENCY_RATE), + float_to_fp16_16(37.3424501424501 / FREQUENCY_RATE), + float_to_fp16_16(37.363740022805 / FREQUENCY_RATE), + float_to_fp16_16(37.3850541928123 / FREQUENCY_RATE), + float_to_fp16_16(37.4063926940639 / FREQUENCY_RATE), + float_to_fp16_16(37.4277555682467 / FREQUENCY_RATE), + float_to_fp16_16(37.4491428571429 / FREQUENCY_RATE), + float_to_fp16_16(37.4705546026301 / FREQUENCY_RATE), + float_to_fp16_16(37.4919908466819 / FREQUENCY_RATE), + float_to_fp16_16(37.5134516313681 / FREQUENCY_RATE), + float_to_fp16_16(37.5349369988545 / FREQUENCY_RATE), + float_to_fp16_16(37.556446991404 / FREQUENCY_RATE), + float_to_fp16_16(37.5779816513761 / FREQUENCY_RATE), + float_to_fp16_16(37.5995410212278 / FREQUENCY_RATE), + float_to_fp16_16(37.6211251435132 / FREQUENCY_RATE), + float_to_fp16_16(37.6427340608845 / FREQUENCY_RATE), + float_to_fp16_16(37.664367816092 / FREQUENCY_RATE), + float_to_fp16_16(37.6860264519839 / FREQUENCY_RATE), + float_to_fp16_16(37.7077100115075 / FREQUENCY_RATE), + float_to_fp16_16(37.7294185377087 / FREQUENCY_RATE), + float_to_fp16_16(37.7511520737327 / FREQUENCY_RATE), + float_to_fp16_16(37.7729106628242 / FREQUENCY_RATE), + float_to_fp16_16(37.7946943483276 / FREQUENCY_RATE), + float_to_fp16_16(37.8165031736872 / FREQUENCY_RATE), + float_to_fp16_16(37.838337182448 / FREQUENCY_RATE), + float_to_fp16_16(37.8601964182553 / FREQUENCY_RATE), + float_to_fp16_16(37.8820809248555 / FREQUENCY_RATE), + float_to_fp16_16(37.903990746096 / FREQUENCY_RATE), + float_to_fp16_16(37.9259259259259 / FREQUENCY_RATE), + float_to_fp16_16(37.9478865083961 / FREQUENCY_RATE), + float_to_fp16_16(37.9698725376593 / FREQUENCY_RATE), + float_to_fp16_16(37.991884057971 / FREQUENCY_RATE), + float_to_fp16_16(38.0139211136891 / FREQUENCY_RATE), + float_to_fp16_16(38.0359837492745 / FREQUENCY_RATE), + float_to_fp16_16(38.0580720092915 / FREQUENCY_RATE), + float_to_fp16_16(38.0801859384079 / FREQUENCY_RATE), + float_to_fp16_16(38.1023255813953 / FREQUENCY_RATE), + float_to_fp16_16(38.1244909831297 / FREQUENCY_RATE), + float_to_fp16_16(38.1466821885914 / FREQUENCY_RATE), + float_to_fp16_16(38.1688992428655 / FREQUENCY_RATE), + float_to_fp16_16(38.1911421911422 / FREQUENCY_RATE), + float_to_fp16_16(38.2134110787172 / FREQUENCY_RATE), + float_to_fp16_16(38.2357059509918 / FREQUENCY_RATE), + float_to_fp16_16(38.2580268534734 / FREQUENCY_RATE), + float_to_fp16_16(38.2803738317757 / FREQUENCY_RATE), + float_to_fp16_16(38.3027469316189 / FREQUENCY_RATE), + float_to_fp16_16(38.3251461988304 / FREQUENCY_RATE), + float_to_fp16_16(38.3475716793446 / FREQUENCY_RATE), + float_to_fp16_16(38.3700234192037 / FREQUENCY_RATE), + float_to_fp16_16(38.3925014645577 / FREQUENCY_RATE), + float_to_fp16_16(38.4150058616647 / FREQUENCY_RATE), + float_to_fp16_16(38.4375366568915 / FREQUENCY_RATE), + float_to_fp16_16(38.4600938967136 / FREQUENCY_RATE), + float_to_fp16_16(38.4826776277158 / FREQUENCY_RATE), + float_to_fp16_16(38.5052878965922 / FREQUENCY_RATE), + float_to_fp16_16(38.527924750147 / FREQUENCY_RATE), + float_to_fp16_16(38.5505882352941 / FREQUENCY_RATE), + float_to_fp16_16(38.5732783990583 / FREQUENCY_RATE), + float_to_fp16_16(38.5959952885748 / FREQUENCY_RATE), + float_to_fp16_16(38.6187389510902 / FREQUENCY_RATE), + float_to_fp16_16(38.6415094339623 / FREQUENCY_RATE), + float_to_fp16_16(38.6643067846608 / FREQUENCY_RATE), + float_to_fp16_16(38.6871310507674 / FREQUENCY_RATE), + float_to_fp16_16(38.7099822799764 / FREQUENCY_RATE), + float_to_fp16_16(38.7328605200946 / FREQUENCY_RATE), + float_to_fp16_16(38.755765819042 / FREQUENCY_RATE), + float_to_fp16_16(38.7786982248521 / FREQUENCY_RATE), + float_to_fp16_16(38.801657785672 / FREQUENCY_RATE), + float_to_fp16_16(38.824644549763 / FREQUENCY_RATE), + float_to_fp16_16(38.8476585655009 / FREQUENCY_RATE), + float_to_fp16_16(38.870699881376 / FREQUENCY_RATE), + float_to_fp16_16(38.8937685459941 / FREQUENCY_RATE), + float_to_fp16_16(38.916864608076 / FREQUENCY_RATE), + float_to_fp16_16(38.9399881164587 / FREQUENCY_RATE), + float_to_fp16_16(38.9631391200951 / FREQUENCY_RATE), + float_to_fp16_16(38.9863176680547 / FREQUENCY_RATE), + float_to_fp16_16(39.0095238095238 / FREQUENCY_RATE), + float_to_fp16_16(39.0327575938058 / FREQUENCY_RATE), + float_to_fp16_16(39.0560190703218 / FREQUENCY_RATE), + float_to_fp16_16(39.0793082886106 / FREQUENCY_RATE), + float_to_fp16_16(39.1026252983294 / FREQUENCY_RATE), + float_to_fp16_16(39.1259701492537 / FREQUENCY_RATE), + float_to_fp16_16(39.1493428912784 / FREQUENCY_RATE), + float_to_fp16_16(39.1727435744172 / FREQUENCY_RATE), + float_to_fp16_16(39.1961722488038 / FREQUENCY_RATE), + float_to_fp16_16(39.2196289646918 / FREQUENCY_RATE), + float_to_fp16_16(39.2431137724551 / FREQUENCY_RATE), + float_to_fp16_16(39.2666267225884 / FREQUENCY_RATE), + float_to_fp16_16(39.2901678657074 / FREQUENCY_RATE), + float_to_fp16_16(39.3137372525495 / FREQUENCY_RATE), + float_to_fp16_16(39.3373349339736 / FREQUENCY_RATE), + float_to_fp16_16(39.360960960961 / FREQUENCY_RATE), + float_to_fp16_16(39.3846153846154 / FREQUENCY_RATE), + float_to_fp16_16(39.4082982561636 / FREQUENCY_RATE), + float_to_fp16_16(39.4320096269555 / FREQUENCY_RATE), + float_to_fp16_16(39.4557495484648 / FREQUENCY_RATE), + float_to_fp16_16(39.4795180722892 / FREQUENCY_RATE), + float_to_fp16_16(39.5033152501507 / FREQUENCY_RATE), + float_to_fp16_16(39.5271411338963 / FREQUENCY_RATE), + float_to_fp16_16(39.5509957754979 / FREQUENCY_RATE), + float_to_fp16_16(39.5748792270531 / FREQUENCY_RATE), + float_to_fp16_16(39.5987915407855 / FREQUENCY_RATE), + float_to_fp16_16(39.6227327690447 / FREQUENCY_RATE), + float_to_fp16_16(39.6467029643073 / FREQUENCY_RATE), + float_to_fp16_16(39.6707021791768 / FREQUENCY_RATE), + float_to_fp16_16(39.694730466384 / FREQUENCY_RATE), + float_to_fp16_16(39.7187878787879 / FREQUENCY_RATE), + float_to_fp16_16(39.7428744693754 / FREQUENCY_RATE), + float_to_fp16_16(39.7669902912621 / FREQUENCY_RATE), + float_to_fp16_16(39.7911353976928 / FREQUENCY_RATE), + float_to_fp16_16(39.8153098420413 / FREQUENCY_RATE), + float_to_fp16_16(39.8395136778115 / FREQUENCY_RATE), + float_to_fp16_16(39.8637469586375 / FREQUENCY_RATE), + float_to_fp16_16(39.8880097382836 / FREQUENCY_RATE), + float_to_fp16_16(39.9123020706455 / FREQUENCY_RATE), + float_to_fp16_16(39.9366240097502 / FREQUENCY_RATE), + float_to_fp16_16(39.9609756097561 / FREQUENCY_RATE), + float_to_fp16_16(39.9853569249542 / FREQUENCY_RATE), + float_to_fp16_16(40.009768009768 / FREQUENCY_RATE), + float_to_fp16_16(40.0342089187538 / FREQUENCY_RATE), + float_to_fp16_16(40.0586797066015 / FREQUENCY_RATE), + float_to_fp16_16(40.0831804281346 / FREQUENCY_RATE), + float_to_fp16_16(40.1077111383109 / FREQUENCY_RATE), + float_to_fp16_16(40.1322718922229 / FREQUENCY_RATE), + float_to_fp16_16(40.156862745098 / FREQUENCY_RATE), + float_to_fp16_16(40.1814837522992 / FREQUENCY_RATE), + float_to_fp16_16(40.2061349693252 / FREQUENCY_RATE), + float_to_fp16_16(40.2308164518109 / FREQUENCY_RATE), + float_to_fp16_16(40.2555282555283 / FREQUENCY_RATE), + float_to_fp16_16(40.280270436386 / FREQUENCY_RATE), + float_to_fp16_16(40.3050430504305 / FREQUENCY_RATE), + float_to_fp16_16(40.3298461538462 / FREQUENCY_RATE), + float_to_fp16_16(40.3546798029557 / FREQUENCY_RATE), + float_to_fp16_16(40.3795440542206 / FREQUENCY_RATE), + float_to_fp16_16(40.4044389642417 / FREQUENCY_RATE), + float_to_fp16_16(40.4293645897594 / FREQUENCY_RATE), + float_to_fp16_16(40.4543209876543 / FREQUENCY_RATE), + float_to_fp16_16(40.4793082149475 / FREQUENCY_RATE), + float_to_fp16_16(40.504326328801 / FREQUENCY_RATE), + float_to_fp16_16(40.5293753865182 / FREQUENCY_RATE), + float_to_fp16_16(40.5544554455446 / FREQUENCY_RATE), + float_to_fp16_16(40.5795665634675 / FREQUENCY_RATE), + float_to_fp16_16(40.6047087980174 / FREQUENCY_RATE), + float_to_fp16_16(40.6298822070676 / FREQUENCY_RATE), + float_to_fp16_16(40.6550868486352 / FREQUENCY_RATE), + float_to_fp16_16(40.6803227808814 / FREQUENCY_RATE), + float_to_fp16_16(40.7055900621118 / FREQUENCY_RATE), + float_to_fp16_16(40.7308887507769 / FREQUENCY_RATE), + float_to_fp16_16(40.7562189054726 / FREQUENCY_RATE), + float_to_fp16_16(40.7815805849409 / FREQUENCY_RATE), + float_to_fp16_16(40.8069738480697 / FREQUENCY_RATE), + float_to_fp16_16(40.8323987538941 / FREQUENCY_RATE), + float_to_fp16_16(40.857855361596 / FREQUENCY_RATE), + float_to_fp16_16(40.8833437305053 / FREQUENCY_RATE), + float_to_fp16_16(40.9088639200999 / FREQUENCY_RATE), + float_to_fp16_16(40.9344159900062 / FREQUENCY_RATE), + float_to_fp16_16(40.96 / FREQUENCY_RATE), + float_to_fp16_16(40.9856160100063 / FREQUENCY_RATE), + float_to_fp16_16(41.0112640801001 / FREQUENCY_RATE), + float_to_fp16_16(41.0369442705072 / FREQUENCY_RATE), + float_to_fp16_16(41.062656641604 / FREQUENCY_RATE), + float_to_fp16_16(41.0884012539185 / FREQUENCY_RATE), + float_to_fp16_16(41.1141781681305 / FREQUENCY_RATE), + float_to_fp16_16(41.1399874450722 / FREQUENCY_RATE), + float_to_fp16_16(41.1658291457287 / FREQUENCY_RATE), + float_to_fp16_16(41.1917033312382 / FREQUENCY_RATE), + float_to_fp16_16(41.2176100628931 / FREQUENCY_RATE), + float_to_fp16_16(41.2435494021397 / FREQUENCY_RATE), + float_to_fp16_16(41.2695214105793 / FREQUENCY_RATE), + float_to_fp16_16(41.2955261499685 / FREQUENCY_RATE), + float_to_fp16_16(41.3215636822194 / FREQUENCY_RATE), + float_to_fp16_16(41.3476340694006 / FREQUENCY_RATE), + float_to_fp16_16(41.3737373737374 / FREQUENCY_RATE), + float_to_fp16_16(41.3998736576121 / FREQUENCY_RATE), + float_to_fp16_16(41.4260429835651 / FREQUENCY_RATE), + float_to_fp16_16(41.4522454142948 / FREQUENCY_RATE), + float_to_fp16_16(41.4784810126582 / FREQUENCY_RATE), + float_to_fp16_16(41.504749841672 / FREQUENCY_RATE), + float_to_fp16_16(41.531051964512 / FREQUENCY_RATE), + float_to_fp16_16(41.5573874445149 / FREQUENCY_RATE), + float_to_fp16_16(41.5837563451777 / FREQUENCY_RATE), + float_to_fp16_16(41.6101587301587 / FREQUENCY_RATE), + float_to_fp16_16(41.6365946632783 / FREQUENCY_RATE), + float_to_fp16_16(41.6630642085188 / FREQUENCY_RATE), + float_to_fp16_16(41.6895674300254 / FREQUENCY_RATE), + float_to_fp16_16(41.7161043921069 / FREQUENCY_RATE), + float_to_fp16_16(41.7426751592357 / FREQUENCY_RATE), + float_to_fp16_16(41.7692797960484 / FREQUENCY_RATE), + float_to_fp16_16(41.7959183673469 / FREQUENCY_RATE), + float_to_fp16_16(41.8225909380983 / FREQUENCY_RATE), + float_to_fp16_16(41.8492975734355 / FREQUENCY_RATE), + float_to_fp16_16(41.8760383386582 / FREQUENCY_RATE), + float_to_fp16_16(41.9028132992327 / FREQUENCY_RATE), + float_to_fp16_16(41.9296225207934 / FREQUENCY_RATE), + float_to_fp16_16(41.9564660691421 / FREQUENCY_RATE), + float_to_fp16_16(41.9833440102498 / FREQUENCY_RATE), + float_to_fp16_16(42.0102564102564 / FREQUENCY_RATE), + float_to_fp16_16(42.0372033354715 / FREQUENCY_RATE), + float_to_fp16_16(42.0641848523748 / FREQUENCY_RATE), + float_to_fp16_16(42.0912010276172 / FREQUENCY_RATE), + float_to_fp16_16(42.1182519280206 / FREQUENCY_RATE), + float_to_fp16_16(42.1453376205788 / FREQUENCY_RATE), + float_to_fp16_16(42.1724581724582 / FREQUENCY_RATE), + float_to_fp16_16(42.1996136509981 / FREQUENCY_RATE), + float_to_fp16_16(42.2268041237113 / FREQUENCY_RATE), + float_to_fp16_16(42.254029658285 / FREQUENCY_RATE), + float_to_fp16_16(42.2812903225807 / FREQUENCY_RATE), + float_to_fp16_16(42.3085861846352 / FREQUENCY_RATE), + float_to_fp16_16(42.3359173126615 / FREQUENCY_RATE), + float_to_fp16_16(42.3632837750485 / FREQUENCY_RATE), + float_to_fp16_16(42.3906856403622 / FREQUENCY_RATE), + float_to_fp16_16(42.4181229773463 / FREQUENCY_RATE), + float_to_fp16_16(42.4455958549223 / FREQUENCY_RATE), + float_to_fp16_16(42.4731043421905 / FREQUENCY_RATE), + float_to_fp16_16(42.5006485084306 / FREQUENCY_RATE), + float_to_fp16_16(42.5282284231019 / FREQUENCY_RATE), + float_to_fp16_16(42.5558441558442 / FREQUENCY_RATE), + float_to_fp16_16(42.5834957764782 / FREQUENCY_RATE), + float_to_fp16_16(42.6111833550065 / FREQUENCY_RATE), + float_to_fp16_16(42.6389069616135 / FREQUENCY_RATE), + float_to_fp16_16(42.6666666666667 / FREQUENCY_RATE), + float_to_fp16_16(42.6944625407166 / FREQUENCY_RATE), + float_to_fp16_16(42.722294654498 / FREQUENCY_RATE), + float_to_fp16_16(42.7501630789302 / FREQUENCY_RATE), + float_to_fp16_16(42.7780678851175 / FREQUENCY_RATE), + float_to_fp16_16(42.8060091443501 / FREQUENCY_RATE), + float_to_fp16_16(42.8339869281046 / FREQUENCY_RATE), + float_to_fp16_16(42.8620013080445 / FREQUENCY_RATE), + float_to_fp16_16(42.890052356021 / FREQUENCY_RATE), + float_to_fp16_16(42.9181401440733 / FREQUENCY_RATE), + float_to_fp16_16(42.9462647444299 / FREQUENCY_RATE), + float_to_fp16_16(42.9744262295082 / FREQUENCY_RATE), + float_to_fp16_16(43.002624671916 / FREQUENCY_RATE), + float_to_fp16_16(43.0308601444517 / FREQUENCY_RATE), + float_to_fp16_16(43.0591327201051 / FREQUENCY_RATE), + float_to_fp16_16(43.0874424720579 / FREQUENCY_RATE), + float_to_fp16_16(43.1157894736842 / FREQUENCY_RATE), + float_to_fp16_16(43.1441737985517 / FREQUENCY_RATE), + float_to_fp16_16(43.1725955204216 / FREQUENCY_RATE), + float_to_fp16_16(43.2010547132498 / FREQUENCY_RATE), + float_to_fp16_16(43.2295514511873 / FREQUENCY_RATE), + float_to_fp16_16(43.2580858085809 / FREQUENCY_RATE), + float_to_fp16_16(43.2866578599736 / FREQUENCY_RATE), + float_to_fp16_16(43.3152676801057 / FREQUENCY_RATE), + float_to_fp16_16(43.3439153439153 / FREQUENCY_RATE), + float_to_fp16_16(43.3726009265387 / FREQUENCY_RATE), + float_to_fp16_16(43.4013245033113 / FREQUENCY_RATE), + float_to_fp16_16(43.4300861497681 / FREQUENCY_RATE), + float_to_fp16_16(43.4588859416446 / FREQUENCY_RATE), + float_to_fp16_16(43.4877239548772 / FREQUENCY_RATE), + float_to_fp16_16(43.5166002656043 / FREQUENCY_RATE), + float_to_fp16_16(43.5455149501661 / FREQUENCY_RATE), + float_to_fp16_16(43.5744680851064 / FREQUENCY_RATE), + float_to_fp16_16(43.6034597471723 / FREQUENCY_RATE), + float_to_fp16_16(43.6324900133156 / FREQUENCY_RATE), + float_to_fp16_16(43.6615589606929 / FREQUENCY_RATE), + float_to_fp16_16(43.6906666666667 / FREQUENCY_RATE), + float_to_fp16_16(43.7198132088059 / FREQUENCY_RATE), + float_to_fp16_16(43.7489986648865 / FREQUENCY_RATE), + float_to_fp16_16(43.7782231128925 / FREQUENCY_RATE), + float_to_fp16_16(43.807486631016 / FREQUENCY_RATE), + float_to_fp16_16(43.8367892976589 / FREQUENCY_RATE), + float_to_fp16_16(43.8661311914324 / FREQUENCY_RATE), + float_to_fp16_16(43.8955123911587 / FREQUENCY_RATE), + float_to_fp16_16(43.9249329758713 / FREQUENCY_RATE), + float_to_fp16_16(43.9543930248156 / FREQUENCY_RATE), + float_to_fp16_16(43.9838926174497 / FREQUENCY_RATE), + float_to_fp16_16(44.0134318334453 / FREQUENCY_RATE), + float_to_fp16_16(44.0430107526882 / FREQUENCY_RATE), + float_to_fp16_16(44.0726294552791 / FREQUENCY_RATE), + float_to_fp16_16(44.1022880215343 / FREQUENCY_RATE), + float_to_fp16_16(44.1319865319865 / FREQUENCY_RATE), + float_to_fp16_16(44.1617250673855 / FREQUENCY_RATE), + float_to_fp16_16(44.1915037086986 / FREQUENCY_RATE), + float_to_fp16_16(44.221322537112 / FREQUENCY_RATE), + float_to_fp16_16(44.2511816340311 / FREQUENCY_RATE), + float_to_fp16_16(44.2810810810811 / FREQUENCY_RATE), + float_to_fp16_16(44.3110209601082 / FREQUENCY_RATE), + float_to_fp16_16(44.34100135318 / FREQUENCY_RATE), + float_to_fp16_16(44.3710223425863 / FREQUENCY_RATE), + float_to_fp16_16(44.4010840108401 / FREQUENCY_RATE), + float_to_fp16_16(44.431186440678 / FREQUENCY_RATE), + float_to_fp16_16(44.4613297150611 / FREQUENCY_RATE), + float_to_fp16_16(44.4915139171758 / FREQUENCY_RATE), + float_to_fp16_16(44.5217391304348 / FREQUENCY_RATE), + float_to_fp16_16(44.5520054384772 / FREQUENCY_RATE), + float_to_fp16_16(44.5823129251701 / FREQUENCY_RATE), + float_to_fp16_16(44.6126616746086 / FREQUENCY_RATE), + float_to_fp16_16(44.6430517711172 / FREQUENCY_RATE), + float_to_fp16_16(44.6734832992502 / FREQUENCY_RATE), + float_to_fp16_16(44.7039563437926 / FREQUENCY_RATE), + float_to_fp16_16(44.7344709897611 / FREQUENCY_RATE), + float_to_fp16_16(44.7650273224044 / FREQUENCY_RATE), + float_to_fp16_16(44.7956254272044 / FREQUENCY_RATE), + float_to_fp16_16(44.8262653898769 / FREQUENCY_RATE), + float_to_fp16_16(44.8569472963724 / FREQUENCY_RATE), + float_to_fp16_16(44.8876712328767 / FREQUENCY_RATE), + float_to_fp16_16(44.9184372858122 / FREQUENCY_RATE), + float_to_fp16_16(44.9492455418381 / FREQUENCY_RATE), + float_to_fp16_16(44.9800960878518 / FREQUENCY_RATE), + float_to_fp16_16(45.010989010989 / FREQUENCY_RATE), + float_to_fp16_16(45.0419243986254 / FREQUENCY_RATE), + float_to_fp16_16(45.0729023383769 / FREQUENCY_RATE), + float_to_fp16_16(45.1039229181005 / FREQUENCY_RATE), + float_to_fp16_16(45.1349862258953 / FREQUENCY_RATE), + float_to_fp16_16(45.1660923501034 / FREQUENCY_RATE), + float_to_fp16_16(45.1972413793103 / FREQUENCY_RATE), + float_to_fp16_16(45.2284334023465 / FREQUENCY_RATE), + float_to_fp16_16(45.2596685082873 / FREQUENCY_RATE), + float_to_fp16_16(45.2909467864547 / FREQUENCY_RATE), + float_to_fp16_16(45.3222683264177 / FREQUENCY_RATE), + float_to_fp16_16(45.3536332179931 / FREQUENCY_RATE), + float_to_fp16_16(45.3850415512465 / FREQUENCY_RATE), + float_to_fp16_16(45.4164934164934 / FREQUENCY_RATE), + float_to_fp16_16(45.4479889042996 / FREQUENCY_RATE), + float_to_fp16_16(45.4795281054823 / FREQUENCY_RATE), + float_to_fp16_16(45.5111111111111 / FREQUENCY_RATE), + float_to_fp16_16(45.5427380125087 / FREQUENCY_RATE), + float_to_fp16_16(45.5744089012517 / FREQUENCY_RATE), + float_to_fp16_16(45.6061238691719 / FREQUENCY_RATE), + float_to_fp16_16(45.6378830083566 / FREQUENCY_RATE), + float_to_fp16_16(45.6696864111498 / FREQUENCY_RATE), + float_to_fp16_16(45.7015341701534 / FREQUENCY_RATE), + float_to_fp16_16(45.7334263782275 / FREQUENCY_RATE), + float_to_fp16_16(45.7653631284916 / FREQUENCY_RATE), + float_to_fp16_16(45.7973445143256 / FREQUENCY_RATE), + float_to_fp16_16(45.8293706293706 / FREQUENCY_RATE), + float_to_fp16_16(45.8614415675297 / FREQUENCY_RATE), + float_to_fp16_16(45.8935574229692 / FREQUENCY_RATE), + float_to_fp16_16(45.9257182901191 / FREQUENCY_RATE), + float_to_fp16_16(45.9579242636746 / FREQUENCY_RATE), + float_to_fp16_16(45.9901754385965 / FREQUENCY_RATE), + float_to_fp16_16(46.0224719101124 / FREQUENCY_RATE), + float_to_fp16_16(46.0548137737175 / FREQUENCY_RATE), + float_to_fp16_16(46.0872011251758 / FREQUENCY_RATE), + float_to_fp16_16(46.1196340605208 / FREQUENCY_RATE), + float_to_fp16_16(46.1521126760563 / FREQUENCY_RATE), + float_to_fp16_16(46.184637068358 / FREQUENCY_RATE), + float_to_fp16_16(46.2172073342736 / FREQUENCY_RATE), + float_to_fp16_16(46.2498235709245 / FREQUENCY_RATE), + float_to_fp16_16(46.2824858757062 / FREQUENCY_RATE), + float_to_fp16_16(46.3151943462898 / FREQUENCY_RATE), + float_to_fp16_16(46.3479490806223 / FREQUENCY_RATE), + float_to_fp16_16(46.3807501769285 / FREQUENCY_RATE), + float_to_fp16_16(46.4135977337111 / FREQUENCY_RATE), + float_to_fp16_16(46.446491849752 / FREQUENCY_RATE), + float_to_fp16_16(46.4794326241135 / FREQUENCY_RATE), + float_to_fp16_16(46.5124201561391 / FREQUENCY_RATE), + float_to_fp16_16(46.5454545454545 / FREQUENCY_RATE), + float_to_fp16_16(46.5785358919687 / FREQUENCY_RATE), + float_to_fp16_16(46.6116642958748 / FREQUENCY_RATE), + float_to_fp16_16(46.6448398576513 / FREQUENCY_RATE), + float_to_fp16_16(46.6780626780627 / FREQUENCY_RATE), + float_to_fp16_16(46.7113328581611 / FREQUENCY_RATE), + float_to_fp16_16(46.7446504992867 / FREQUENCY_RATE), + float_to_fp16_16(46.7780157030692 / FREQUENCY_RATE), + float_to_fp16_16(46.8114285714286 / FREQUENCY_RATE), + float_to_fp16_16(46.8448892065761 / FREQUENCY_RATE), + float_to_fp16_16(46.8783977110157 / FREQUENCY_RATE), + float_to_fp16_16(46.9119541875447 / FREQUENCY_RATE), + float_to_fp16_16(46.945558739255 / FREQUENCY_RATE), + float_to_fp16_16(46.9792114695341 / FREQUENCY_RATE), + float_to_fp16_16(47.012912482066 / FREQUENCY_RATE), + float_to_fp16_16(47.0466618808327 / FREQUENCY_RATE), + float_to_fp16_16(47.0804597701149 / FREQUENCY_RATE), + float_to_fp16_16(47.1143062544932 / FREQUENCY_RATE), + float_to_fp16_16(47.1482014388489 / FREQUENCY_RATE), + float_to_fp16_16(47.1821454283657 / FREQUENCY_RATE), + float_to_fp16_16(47.2161383285303 / FREQUENCY_RATE), + float_to_fp16_16(47.2501802451334 / FREQUENCY_RATE), + float_to_fp16_16(47.2842712842713 / FREQUENCY_RATE), + float_to_fp16_16(47.3184115523466 / FREQUENCY_RATE), + float_to_fp16_16(47.3526011560694 / FREQUENCY_RATE), + float_to_fp16_16(47.3868402024584 / FREQUENCY_RATE), + float_to_fp16_16(47.4211287988423 / FREQUENCY_RATE), + float_to_fp16_16(47.4554670528602 / FREQUENCY_RATE), + float_to_fp16_16(47.4898550724638 / FREQUENCY_RATE), + float_to_fp16_16(47.5242929659173 / FREQUENCY_RATE), + float_to_fp16_16(47.5587808417997 / FREQUENCY_RATE), + float_to_fp16_16(47.5933188090051 / FREQUENCY_RATE), + float_to_fp16_16(47.6279069767442 / FREQUENCY_RATE), + float_to_fp16_16(47.6625454545455 / FREQUENCY_RATE), + float_to_fp16_16(47.6972343522562 / FREQUENCY_RATE), + float_to_fp16_16(47.7319737800437 / FREQUENCY_RATE), + float_to_fp16_16(47.7667638483965 / FREQUENCY_RATE), + float_to_fp16_16(47.8016046681255 / FREQUENCY_RATE), + float_to_fp16_16(47.836496350365 / FREQUENCY_RATE), + float_to_fp16_16(47.8714390065741 / FREQUENCY_RATE), + float_to_fp16_16(47.906432748538 / FREQUENCY_RATE), + float_to_fp16_16(47.9414776883687 / FREQUENCY_RATE), + float_to_fp16_16(47.9765739385066 / FREQUENCY_RATE), + float_to_fp16_16(48.0117216117216 / FREQUENCY_RATE), + float_to_fp16_16(48.0469208211144 / FREQUENCY_RATE), + float_to_fp16_16(48.0821716801174 / FREQUENCY_RATE), + float_to_fp16_16(48.1174743024963 / FREQUENCY_RATE), + float_to_fp16_16(48.1528288023512 / FREQUENCY_RATE), + float_to_fp16_16(48.1882352941176 / FREQUENCY_RATE), + float_to_fp16_16(48.2236938925681 / FREQUENCY_RATE), + float_to_fp16_16(48.259204712813 / FREQUENCY_RATE), + float_to_fp16_16(48.2947678703021 / FREQUENCY_RATE), + float_to_fp16_16(48.330383480826 / FREQUENCY_RATE), + float_to_fp16_16(48.3660516605166 / FREQUENCY_RATE), + float_to_fp16_16(48.4017725258493 / FREQUENCY_RATE), + float_to_fp16_16(48.4375461936438 / FREQUENCY_RATE), + float_to_fp16_16(48.4733727810651 / FREQUENCY_RATE), + float_to_fp16_16(48.5092524056255 / FREQUENCY_RATE), + float_to_fp16_16(48.5451851851852 / FREQUENCY_RATE), + float_to_fp16_16(48.581171237954 / FREQUENCY_RATE), + float_to_fp16_16(48.6172106824926 / FREQUENCY_RATE), + float_to_fp16_16(48.6533036377134 / FREQUENCY_RATE), + float_to_fp16_16(48.6894502228826 / FREQUENCY_RATE), + float_to_fp16_16(48.7256505576208 / FREQUENCY_RATE), + float_to_fp16_16(48.7619047619048 / FREQUENCY_RATE), + float_to_fp16_16(48.7982129560685 / FREQUENCY_RATE), + float_to_fp16_16(48.8345752608048 / FREQUENCY_RATE), + float_to_fp16_16(48.8709917971663 / FREQUENCY_RATE), + float_to_fp16_16(48.9074626865672 / FREQUENCY_RATE), + float_to_fp16_16(48.9439880507842 / FREQUENCY_RATE), + float_to_fp16_16(48.9805680119582 / FREQUENCY_RATE), + float_to_fp16_16(49.0172026925954 / FREQUENCY_RATE), + float_to_fp16_16(49.0538922155689 / FREQUENCY_RATE), + float_to_fp16_16(49.0906367041199 / FREQUENCY_RATE), + float_to_fp16_16(49.1274362818591 / FREQUENCY_RATE), + float_to_fp16_16(49.1642910727682 / FREQUENCY_RATE), + float_to_fp16_16(49.2012012012012 / FREQUENCY_RATE), + float_to_fp16_16(49.2381667918858 / FREQUENCY_RATE), + float_to_fp16_16(49.2751879699248 / FREQUENCY_RATE), + float_to_fp16_16(49.3122648607976 / FREQUENCY_RATE), + float_to_fp16_16(49.3493975903615 / FREQUENCY_RATE), + float_to_fp16_16(49.3865862848531 / FREQUENCY_RATE), + float_to_fp16_16(49.4238310708899 / FREQUENCY_RATE), + float_to_fp16_16(49.4611320754717 / FREQUENCY_RATE), + float_to_fp16_16(49.4984894259819 / FREQUENCY_RATE), + float_to_fp16_16(49.535903250189 / FREQUENCY_RATE), + float_to_fp16_16(49.5733736762481 / FREQUENCY_RATE), + float_to_fp16_16(49.6109008327025 / FREQUENCY_RATE), + float_to_fp16_16(49.6484848484849 / FREQUENCY_RATE), + float_to_fp16_16(49.6861258529189 / FREQUENCY_RATE), + float_to_fp16_16(49.7238239757208 / FREQUENCY_RATE), + float_to_fp16_16(49.7615793470008 / FREQUENCY_RATE), + float_to_fp16_16(49.7993920972644 / FREQUENCY_RATE), + float_to_fp16_16(49.8372623574145 / FREQUENCY_RATE), + float_to_fp16_16(49.8751902587519 / FREQUENCY_RATE), + float_to_fp16_16(49.9131759329779 / FREQUENCY_RATE), + float_to_fp16_16(49.9512195121951 / FREQUENCY_RATE), + float_to_fp16_16(49.9893211289092 / FREQUENCY_RATE), + float_to_fp16_16(50.0274809160305 / FREQUENCY_RATE), + float_to_fp16_16(50.0656990068755 / FREQUENCY_RATE), + float_to_fp16_16(50.1039755351682 / FREQUENCY_RATE), + float_to_fp16_16(50.1423106350421 / FREQUENCY_RATE), + float_to_fp16_16(50.1807044410413 / FREQUENCY_RATE), + float_to_fp16_16(50.2191570881226 / FREQUENCY_RATE), + float_to_fp16_16(50.2576687116564 / FREQUENCY_RATE), + float_to_fp16_16(50.296239447429 / FREQUENCY_RATE), + float_to_fp16_16(50.3348694316436 / FREQUENCY_RATE), + float_to_fp16_16(50.3735588009224 / FREQUENCY_RATE), + float_to_fp16_16(50.4123076923077 / FREQUENCY_RATE), + float_to_fp16_16(50.451116243264 / FREQUENCY_RATE), + float_to_fp16_16(50.4899845916795 / FREQUENCY_RATE), + float_to_fp16_16(50.5289128758674 / FREQUENCY_RATE), + float_to_fp16_16(50.5679012345679 / FREQUENCY_RATE), + float_to_fp16_16(50.6069498069498 / FREQUENCY_RATE), + float_to_fp16_16(50.6460587326121 / FREQUENCY_RATE), + float_to_fp16_16(50.6852281515855 / FREQUENCY_RATE), + float_to_fp16_16(50.7244582043344 / FREQUENCY_RATE), + float_to_fp16_16(50.7637490317583 / FREQUENCY_RATE), + float_to_fp16_16(50.8031007751938 / FREQUENCY_RATE), + float_to_fp16_16(50.8425135764158 / FREQUENCY_RATE), + float_to_fp16_16(50.8819875776397 / FREQUENCY_RATE), + float_to_fp16_16(50.9215229215229 / FREQUENCY_RATE), + float_to_fp16_16(50.9611197511664 / FREQUENCY_RATE), + float_to_fp16_16(51.0007782101167 / FREQUENCY_RATE), + float_to_fp16_16(51.0404984423676 / FREQUENCY_RATE), + float_to_fp16_16(51.0802805923617 / FREQUENCY_RATE), + float_to_fp16_16(51.1201248049922 / FREQUENCY_RATE), + float_to_fp16_16(51.160031225605 / FREQUENCY_RATE), + float_to_fp16_16(51.2 / FREQUENCY_RATE), + float_to_fp16_16(51.2400312744331 / FREQUENCY_RATE), + float_to_fp16_16(51.2801251956182 / FREQUENCY_RATE), + float_to_fp16_16(51.3202819107283 / FREQUENCY_RATE), + float_to_fp16_16(51.3605015673981 / FREQUENCY_RATE), + float_to_fp16_16(51.4007843137255 / FREQUENCY_RATE), + float_to_fp16_16(51.4411302982732 / FREQUENCY_RATE), + float_to_fp16_16(51.4815396700707 / FREQUENCY_RATE), + float_to_fp16_16(51.5220125786164 / FREQUENCY_RATE), + float_to_fp16_16(51.5625491738788 / FREQUENCY_RATE), + float_to_fp16_16(51.6031496062992 / FREQUENCY_RATE), + float_to_fp16_16(51.6438140267928 / FREQUENCY_RATE), + float_to_fp16_16(51.6845425867508 / FREQUENCY_RATE), + float_to_fp16_16(51.7253354380426 / FREQUENCY_RATE), + float_to_fp16_16(51.7661927330174 / FREQUENCY_RATE), + float_to_fp16_16(51.8071146245059 / FREQUENCY_RATE), + float_to_fp16_16(51.8481012658228 / FREQUENCY_RATE), + float_to_fp16_16(51.889152810768 / FREQUENCY_RATE), + float_to_fp16_16(51.9302694136292 / FREQUENCY_RATE), + float_to_fp16_16(51.9714512291832 / FREQUENCY_RATE), + float_to_fp16_16(52.0126984126984 / FREQUENCY_RATE), + float_to_fp16_16(52.0540111199365 / FREQUENCY_RATE), + float_to_fp16_16(52.0953895071542 / FREQUENCY_RATE), + float_to_fp16_16(52.1368337311058 / FREQUENCY_RATE), + float_to_fp16_16(52.1783439490446 / FREQUENCY_RATE), + float_to_fp16_16(52.2199203187251 / FREQUENCY_RATE), + float_to_fp16_16(52.2615629984051 / FREQUENCY_RATE), + float_to_fp16_16(52.3032721468476 / FREQUENCY_RATE), + float_to_fp16_16(52.3450479233227 / FREQUENCY_RATE), + float_to_fp16_16(52.3868904876099 / FREQUENCY_RATE), + float_to_fp16_16(52.4288 / FREQUENCY_RATE), + float_to_fp16_16(52.470776621297 / FREQUENCY_RATE), + float_to_fp16_16(52.5128205128205 / FREQUENCY_RATE), + float_to_fp16_16(52.5549318364074 / FREQUENCY_RATE), + float_to_fp16_16(52.5971107544141 / FREQUENCY_RATE), + float_to_fp16_16(52.6393574297189 / FREQUENCY_RATE), + float_to_fp16_16(52.6816720257235 / FREQUENCY_RATE), + float_to_fp16_16(52.7240547063556 / FREQUENCY_RATE), + float_to_fp16_16(52.7665056360709 / FREQUENCY_RATE), + float_to_fp16_16(52.809024979855 / FREQUENCY_RATE), + float_to_fp16_16(52.8516129032258 / FREQUENCY_RATE), + float_to_fp16_16(52.8942695722357 / FREQUENCY_RATE), + float_to_fp16_16(52.9369951534734 / FREQUENCY_RATE), + float_to_fp16_16(52.9797898140663 / FREQUENCY_RATE), + float_to_fp16_16(53.0226537216829 / FREQUENCY_RATE), + float_to_fp16_16(53.0655870445344 / FREQUENCY_RATE), + float_to_fp16_16(53.1085899513776 / FREQUENCY_RATE), + float_to_fp16_16(53.1516626115166 / FREQUENCY_RATE), + float_to_fp16_16(53.1948051948052 / FREQUENCY_RATE), + float_to_fp16_16(53.2380178716491 / FREQUENCY_RATE), + float_to_fp16_16(53.2813008130081 / FREQUENCY_RATE), + float_to_fp16_16(53.3246541903987 / FREQUENCY_RATE), + float_to_fp16_16(53.3680781758958 / FREQUENCY_RATE), + float_to_fp16_16(53.4115729421353 / FREQUENCY_RATE), + float_to_fp16_16(53.4551386623165 / FREQUENCY_RATE), + float_to_fp16_16(53.4987755102041 / FREQUENCY_RATE), + float_to_fp16_16(53.5424836601307 / FREQUENCY_RATE), + float_to_fp16_16(53.5862632869992 / FREQUENCY_RATE), + float_to_fp16_16(53.6301145662848 / FREQUENCY_RATE), + float_to_fp16_16(53.6740376740377 / FREQUENCY_RATE), + float_to_fp16_16(53.7180327868852 / FREQUENCY_RATE), + float_to_fp16_16(53.7621000820345 / FREQUENCY_RATE), + float_to_fp16_16(53.8062397372742 / FREQUENCY_RATE), + float_to_fp16_16(53.8504519309778 / FREQUENCY_RATE), + float_to_fp16_16(53.8947368421053 / FREQUENCY_RATE), + float_to_fp16_16(53.9390946502058 / FREQUENCY_RATE), + float_to_fp16_16(53.9835255354201 / FREQUENCY_RATE), + float_to_fp16_16(54.0280296784831 / FREQUENCY_RATE), + float_to_fp16_16(54.0726072607261 / FREQUENCY_RATE), + float_to_fp16_16(54.1172584640793 / FREQUENCY_RATE), + float_to_fp16_16(54.1619834710744 / FREQUENCY_RATE), + float_to_fp16_16(54.206782464847 / FREQUENCY_RATE), + float_to_fp16_16(54.2516556291391 / FREQUENCY_RATE), + float_to_fp16_16(54.2966031483016 / FREQUENCY_RATE), + float_to_fp16_16(54.3416252072969 / FREQUENCY_RATE), + float_to_fp16_16(54.3867219917012 / FREQUENCY_RATE), + float_to_fp16_16(54.4318936877076 / FREQUENCY_RATE), + float_to_fp16_16(54.477140482128 / FREQUENCY_RATE), + float_to_fp16_16(54.522462562396 / FREQUENCY_RATE), + float_to_fp16_16(54.5678601165695 / FREQUENCY_RATE), + float_to_fp16_16(54.6133333333333 / FREQUENCY_RATE), + float_to_fp16_16(54.6588824020017 / FREQUENCY_RATE), + float_to_fp16_16(54.7045075125209 / FREQUENCY_RATE), + float_to_fp16_16(54.750208855472 / FREQUENCY_RATE), + float_to_fp16_16(54.7959866220736 / FREQUENCY_RATE), + float_to_fp16_16(54.8418410041841 / FREQUENCY_RATE), + float_to_fp16_16(54.8877721943049 / FREQUENCY_RATE), + float_to_fp16_16(54.9337803855826 / FREQUENCY_RATE), + float_to_fp16_16(54.9798657718121 / FREQUENCY_RATE), + float_to_fp16_16(55.0260285474391 / FREQUENCY_RATE), + float_to_fp16_16(55.072268907563 / FREQUENCY_RATE), + float_to_fp16_16(55.1185870479394 / FREQUENCY_RATE), + float_to_fp16_16(55.1649831649832 / FREQUENCY_RATE), + float_to_fp16_16(55.2114574557709 / FREQUENCY_RATE), + float_to_fp16_16(55.2580101180438 / FREQUENCY_RATE), + float_to_fp16_16(55.304641350211 / FREQUENCY_RATE), + float_to_fp16_16(55.3513513513514 / FREQUENCY_RATE), + float_to_fp16_16(55.3981403212172 / FREQUENCY_RATE), + float_to_fp16_16(55.4450084602369 / FREQUENCY_RATE), + float_to_fp16_16(55.4919559695174 / FREQUENCY_RATE), + float_to_fp16_16(55.5389830508475 / FREQUENCY_RATE), + float_to_fp16_16(55.5860899067006 / FREQUENCY_RATE), + float_to_fp16_16(55.6332767402377 / FREQUENCY_RATE), + float_to_fp16_16(55.6805437553101 / FREQUENCY_RATE), + float_to_fp16_16(55.7278911564626 / FREQUENCY_RATE), + float_to_fp16_16(55.7753191489362 / FREQUENCY_RATE), + float_to_fp16_16(55.8228279386712 / FREQUENCY_RATE), + float_to_fp16_16(55.8704177323103 / FREQUENCY_RATE), + float_to_fp16_16(55.9180887372014 / FREQUENCY_RATE), + float_to_fp16_16(55.9658411614005 / FREQUENCY_RATE), + float_to_fp16_16(56.0136752136752 / FREQUENCY_RATE), + float_to_fp16_16(56.0615911035073 / FREQUENCY_RATE), + float_to_fp16_16(56.1095890410959 / FREQUENCY_RATE), + float_to_fp16_16(56.1576692373608 / FREQUENCY_RATE), + float_to_fp16_16(56.2058319039451 / FREQUENCY_RATE), + float_to_fp16_16(56.2540772532189 / FREQUENCY_RATE), + float_to_fp16_16(56.3024054982818 / FREQUENCY_RATE), + float_to_fp16_16(56.3508168529665 / FREQUENCY_RATE), + float_to_fp16_16(56.3993115318417 / FREQUENCY_RATE), + float_to_fp16_16(56.4478897502153 / FREQUENCY_RATE), + float_to_fp16_16(56.4965517241379 / FREQUENCY_RATE), + float_to_fp16_16(56.5452976704055 / FREQUENCY_RATE), + float_to_fp16_16(56.594127806563 / FREQUENCY_RATE), + float_to_fp16_16(56.6430423509075 / FREQUENCY_RATE), + float_to_fp16_16(56.6920415224914 / FREQUENCY_RATE), + float_to_fp16_16(56.7411255411255 / FREQUENCY_RATE), + float_to_fp16_16(56.790294627383 / FREQUENCY_RATE), + float_to_fp16_16(56.8395490026019 / FREQUENCY_RATE), + float_to_fp16_16(56.8888888888889 / FREQUENCY_RATE), + float_to_fp16_16(56.9383145091225 / FREQUENCY_RATE), + float_to_fp16_16(56.9878260869565 / FREQUENCY_RATE), + float_to_fp16_16(57.0374238468233 / FREQUENCY_RATE), + float_to_fp16_16(57.0871080139373 / FREQUENCY_RATE), + float_to_fp16_16(57.1368788142982 / FREQUENCY_RATE), + float_to_fp16_16(57.1867364746946 / FREQUENCY_RATE), + float_to_fp16_16(57.2366812227074 / FREQUENCY_RATE), + float_to_fp16_16(57.2867132867133 / FREQUENCY_RATE), + float_to_fp16_16(57.336832895888 / FREQUENCY_RATE), + float_to_fp16_16(57.3870402802102 / FREQUENCY_RATE), + float_to_fp16_16(57.4373356704645 / FREQUENCY_RATE), + float_to_fp16_16(57.4877192982456 / FREQUENCY_RATE), + float_to_fp16_16(57.5381913959614 / FREQUENCY_RATE), + float_to_fp16_16(57.5887521968366 / FREQUENCY_RATE), + float_to_fp16_16(57.6394019349165 / FREQUENCY_RATE), + float_to_fp16_16(57.6901408450704 / FREQUENCY_RATE), + float_to_fp16_16(57.7409691629956 / FREQUENCY_RATE), + float_to_fp16_16(57.7918871252205 / FREQUENCY_RATE), + float_to_fp16_16(57.8428949691086 / FREQUENCY_RATE), + float_to_fp16_16(57.8939929328622 / FREQUENCY_RATE), + float_to_fp16_16(57.9451812555261 / FREQUENCY_RATE), + float_to_fp16_16(57.9964601769912 / FREQUENCY_RATE), + float_to_fp16_16(58.0478299379982 / FREQUENCY_RATE), + float_to_fp16_16(58.0992907801418 / FREQUENCY_RATE), + float_to_fp16_16(58.150842945874 / FREQUENCY_RATE), + float_to_fp16_16(58.202486678508 / FREQUENCY_RATE), + float_to_fp16_16(58.2542222222222 / FREQUENCY_RATE), + float_to_fp16_16(58.3060498220641 / FREQUENCY_RATE), + float_to_fp16_16(58.3579697239537 / FREQUENCY_RATE), + float_to_fp16_16(58.4099821746881 / FREQUENCY_RATE), + float_to_fp16_16(58.4620874219447 / FREQUENCY_RATE), + float_to_fp16_16(58.5142857142857 / FREQUENCY_RATE), + float_to_fp16_16(58.5665773011618 / FREQUENCY_RATE), + float_to_fp16_16(58.6189624329159 / FREQUENCY_RATE), + float_to_fp16_16(58.6714413607878 / FREQUENCY_RATE), + float_to_fp16_16(58.7240143369176 / FREQUENCY_RATE), + float_to_fp16_16(58.7766816143498 / FREQUENCY_RATE), + float_to_fp16_16(58.8294434470377 / FREQUENCY_RATE), + float_to_fp16_16(58.8823000898473 / FREQUENCY_RATE), + float_to_fp16_16(58.9352517985612 / FREQUENCY_RATE), + float_to_fp16_16(58.988298829883 / FREQUENCY_RATE), + float_to_fp16_16(59.0414414414414 / FREQUENCY_RATE), + float_to_fp16_16(59.0946798917944 / FREQUENCY_RATE), + float_to_fp16_16(59.1480144404332 / FREQUENCY_RATE), + float_to_fp16_16(59.2014453477868 / FREQUENCY_RATE), + float_to_fp16_16(59.254972875226 / FREQUENCY_RATE), + float_to_fp16_16(59.3085972850679 / FREQUENCY_RATE), + float_to_fp16_16(59.3623188405797 / FREQUENCY_RATE), + float_to_fp16_16(59.4161378059837 / FREQUENCY_RATE), + float_to_fp16_16(59.470054446461 / FREQUENCY_RATE), + float_to_fp16_16(59.5240690281562 / FREQUENCY_RATE), + float_to_fp16_16(59.5781818181818 / FREQUENCY_RATE), + float_to_fp16_16(59.6323930846224 / FREQUENCY_RATE), + float_to_fp16_16(59.6867030965392 / FREQUENCY_RATE), + float_to_fp16_16(59.7411121239745 / FREQUENCY_RATE), + float_to_fp16_16(59.7956204379562 / FREQUENCY_RATE), + float_to_fp16_16(59.8502283105023 / FREQUENCY_RATE), + float_to_fp16_16(59.9049360146252 / FREQUENCY_RATE), + float_to_fp16_16(59.9597438243367 / FREQUENCY_RATE), + float_to_fp16_16(60.014652014652 / FREQUENCY_RATE), + float_to_fp16_16(60.0696608615949 / FREQUENCY_RATE), + float_to_fp16_16(60.1247706422018 / FREQUENCY_RATE), + float_to_fp16_16(60.1799816345271 / FREQUENCY_RATE), + float_to_fp16_16(60.2352941176471 / FREQUENCY_RATE), + float_to_fp16_16(60.2907083716651 / FREQUENCY_RATE), + float_to_fp16_16(60.3462246777164 / FREQUENCY_RATE), + float_to_fp16_16(60.4018433179724 / FREQUENCY_RATE), + float_to_fp16_16(60.4575645756458 / FREQUENCY_RATE), + float_to_fp16_16(60.5133887349954 / FREQUENCY_RATE), + float_to_fp16_16(60.5693160813309 / FREQUENCY_RATE), + float_to_fp16_16(60.6253469010176 / FREQUENCY_RATE), + float_to_fp16_16(60.6814814814815 / FREQUENCY_RATE), + float_to_fp16_16(60.7377201112141 / FREQUENCY_RATE), + float_to_fp16_16(60.7940630797774 / FREQUENCY_RATE), + float_to_fp16_16(60.8505106778087 / FREQUENCY_RATE), + float_to_fp16_16(60.907063197026 / FREQUENCY_RATE), + float_to_fp16_16(60.9637209302326 / FREQUENCY_RATE), + float_to_fp16_16(61.0204841713222 / FREQUENCY_RATE), + float_to_fp16_16(61.0773532152843 / FREQUENCY_RATE), + float_to_fp16_16(61.134328358209 / FREQUENCY_RATE), + float_to_fp16_16(61.1914098972923 / FREQUENCY_RATE), + float_to_fp16_16(61.2485981308411 / FREQUENCY_RATE), + float_to_fp16_16(61.3058933582788 / FREQUENCY_RATE), + float_to_fp16_16(61.3632958801498 / FREQUENCY_RATE), + float_to_fp16_16(61.4208059981256 / FREQUENCY_RATE), + float_to_fp16_16(61.4784240150094 / FREQUENCY_RATE), + float_to_fp16_16(61.5361502347418 / FREQUENCY_RATE), + float_to_fp16_16(61.593984962406 / FREQUENCY_RATE), + float_to_fp16_16(61.6519285042333 / FREQUENCY_RATE), + float_to_fp16_16(61.7099811676083 / FREQUENCY_RATE), + float_to_fp16_16(61.7681432610745 / FREQUENCY_RATE), + float_to_fp16_16(61.8264150943396 / FREQUENCY_RATE), + float_to_fp16_16(61.8847969782814 / FREQUENCY_RATE), + float_to_fp16_16(61.9432892249527 / FREQUENCY_RATE), + float_to_fp16_16(62.0018921475875 / FREQUENCY_RATE), + float_to_fp16_16(62.0606060606061 / FREQUENCY_RATE), + float_to_fp16_16(62.1194312796209 / FREQUENCY_RATE), + float_to_fp16_16(62.1783681214421 / FREQUENCY_RATE), + float_to_fp16_16(62.2374169040836 / FREQUENCY_RATE), + float_to_fp16_16(62.2965779467681 / FREQUENCY_RATE), + float_to_fp16_16(62.3558515699334 / FREQUENCY_RATE), + float_to_fp16_16(62.4152380952381 / FREQUENCY_RATE), + float_to_fp16_16(62.4747378455672 / FREQUENCY_RATE), + float_to_fp16_16(62.5343511450382 / FREQUENCY_RATE), + float_to_fp16_16(62.5940783190067 / FREQUENCY_RATE), + float_to_fp16_16(62.6539196940727 / FREQUENCY_RATE), + float_to_fp16_16(62.7138755980861 / FREQUENCY_RATE), + float_to_fp16_16(62.7739463601533 / FREQUENCY_RATE), + float_to_fp16_16(62.8341323106424 / FREQUENCY_RATE), + float_to_fp16_16(62.89443378119 / FREQUENCY_RATE), + float_to_fp16_16(62.954851104707 / FREQUENCY_RATE), + float_to_fp16_16(63.0153846153846 / FREQUENCY_RATE), + float_to_fp16_16(63.0760346487007 / FREQUENCY_RATE), + float_to_fp16_16(63.1368015414258 / FREQUENCY_RATE), + float_to_fp16_16(63.1976856316297 / FREQUENCY_RATE), + float_to_fp16_16(63.2586872586873 / FREQUENCY_RATE), + float_to_fp16_16(63.319806763285 / FREQUENCY_RATE), + float_to_fp16_16(63.3810444874275 / FREQUENCY_RATE), + float_to_fp16_16(63.4424007744434 / FREQUENCY_RATE), + float_to_fp16_16(63.5038759689923 / FREQUENCY_RATE), + float_to_fp16_16(63.5654704170708 / FREQUENCY_RATE), + float_to_fp16_16(63.6271844660194 / FREQUENCY_RATE), + float_to_fp16_16(63.6890184645287 / FREQUENCY_RATE), + float_to_fp16_16(63.7509727626459 / FREQUENCY_RATE), + float_to_fp16_16(63.8130477117819 / FREQUENCY_RATE), + float_to_fp16_16(63.8752436647174 / FREQUENCY_RATE), + float_to_fp16_16(63.9375609756098 / FREQUENCY_RATE), + float_to_fp16_16(64 / FREQUENCY_RATE), + float_to_fp16_16(64.0625610948192 / FREQUENCY_RATE), + float_to_fp16_16(64.1252446183953 / FREQUENCY_RATE), + float_to_fp16_16(64.1880509304603 / FREQUENCY_RATE), + float_to_fp16_16(64.2509803921569 / FREQUENCY_RATE), + float_to_fp16_16(64.3140333660451 / FREQUENCY_RATE), + float_to_fp16_16(64.37721021611 / FREQUENCY_RATE), + float_to_fp16_16(64.440511307768 / FREQUENCY_RATE), + float_to_fp16_16(64.503937007874 / FREQUENCY_RATE), + float_to_fp16_16(64.5674876847291 / FREQUENCY_RATE), + float_to_fp16_16(64.6311637080868 / FREQUENCY_RATE), + float_to_fp16_16(64.6949654491609 / FREQUENCY_RATE), + float_to_fp16_16(64.7588932806324 / FREQUENCY_RATE), + float_to_fp16_16(64.8229475766568 / FREQUENCY_RATE), + float_to_fp16_16(64.8871287128713 / FREQUENCY_RATE), + float_to_fp16_16(64.9514370664024 / FREQUENCY_RATE), + float_to_fp16_16(65.015873015873 / FREQUENCY_RATE), + float_to_fp16_16(65.0804369414101 / FREQUENCY_RATE), + float_to_fp16_16(65.1451292246521 / FREQUENCY_RATE), + float_to_fp16_16(65.2099502487562 / FREQUENCY_RATE), + float_to_fp16_16(65.2749003984064 / FREQUENCY_RATE), + float_to_fp16_16(65.3399800598205 / FREQUENCY_RATE), + float_to_fp16_16(65.4051896207585 / FREQUENCY_RATE), + float_to_fp16_16(65.4705294705295 / FREQUENCY_RATE), + float_to_fp16_16(65.536 / FREQUENCY_RATE), + float_to_fp16_16(65.6016016016016 / FREQUENCY_RATE), + float_to_fp16_16(65.6673346693387 / FREQUENCY_RATE), + float_to_fp16_16(65.7331995987964 / FREQUENCY_RATE), + float_to_fp16_16(65.7991967871486 / FREQUENCY_RATE), + float_to_fp16_16(65.8653266331658 / FREQUENCY_RATE), + float_to_fp16_16(65.9315895372234 / FREQUENCY_RATE), + float_to_fp16_16(65.9979859013092 / FREQUENCY_RATE), + float_to_fp16_16(66.0645161290323 / FREQUENCY_RATE), + float_to_fp16_16(66.1311806256307 / FREQUENCY_RATE), + float_to_fp16_16(66.1979797979798 / FREQUENCY_RATE), + float_to_fp16_16(66.2649140546006 / FREQUENCY_RATE), + float_to_fp16_16(66.331983805668 / FREQUENCY_RATE), + float_to_fp16_16(66.3991894630193 / FREQUENCY_RATE), + float_to_fp16_16(66.4665314401623 / FREQUENCY_RATE), + float_to_fp16_16(66.5340101522843 / FREQUENCY_RATE), + float_to_fp16_16(66.6016260162602 / FREQUENCY_RATE), + float_to_fp16_16(66.6693794506612 / FREQUENCY_RATE), + float_to_fp16_16(66.7372708757637 / FREQUENCY_RATE), + float_to_fp16_16(66.8053007135576 / FREQUENCY_RATE), + float_to_fp16_16(66.8734693877551 / FREQUENCY_RATE), + float_to_fp16_16(66.9417773237998 / FREQUENCY_RATE), + float_to_fp16_16(67.0102249488753 / FREQUENCY_RATE), + float_to_fp16_16(67.078812691914 / FREQUENCY_RATE), + float_to_fp16_16(67.1475409836066 / FREQUENCY_RATE), + float_to_fp16_16(67.2164102564103 / FREQUENCY_RATE), + float_to_fp16_16(67.2854209445585 / FREQUENCY_RATE), + float_to_fp16_16(67.3545734840699 / FREQUENCY_RATE), + float_to_fp16_16(67.4238683127572 / FREQUENCY_RATE), + float_to_fp16_16(67.4933058702369 / FREQUENCY_RATE), + float_to_fp16_16(67.5628865979382 / FREQUENCY_RATE), + float_to_fp16_16(67.6326109391125 / FREQUENCY_RATE), + float_to_fp16_16(67.702479338843 / FREQUENCY_RATE), + float_to_fp16_16(67.7724922440538 / FREQUENCY_RATE), + float_to_fp16_16(67.8426501035197 / FREQUENCY_RATE), + float_to_fp16_16(67.9129533678757 / FREQUENCY_RATE), + float_to_fp16_16(67.9834024896266 / FREQUENCY_RATE), + float_to_fp16_16(68.0539979231568 / FREQUENCY_RATE), + float_to_fp16_16(68.1247401247401 / FREQUENCY_RATE), + float_to_fp16_16(68.1956295525494 / FREQUENCY_RATE), + float_to_fp16_16(68.2666666666667 / FREQUENCY_RATE), + float_to_fp16_16(68.3378519290928 / FREQUENCY_RATE), + float_to_fp16_16(68.4091858037578 / FREQUENCY_RATE), + float_to_fp16_16(68.4806687565308 / FREQUENCY_RATE), + float_to_fp16_16(68.5523012552301 / FREQUENCY_RATE), + float_to_fp16_16(68.6240837696335 / FREQUENCY_RATE), + float_to_fp16_16(68.6960167714885 / FREQUENCY_RATE), + float_to_fp16_16(68.7681007345226 / FREQUENCY_RATE), + float_to_fp16_16(68.8403361344538 / FREQUENCY_RATE), + float_to_fp16_16(68.9127234490011 / FREQUENCY_RATE), + float_to_fp16_16(68.9852631578947 / FREQUENCY_RATE), + float_to_fp16_16(69.0579557428872 / FREQUENCY_RATE), + float_to_fp16_16(69.1308016877637 / FREQUENCY_RATE), + float_to_fp16_16(69.2038014783527 / FREQUENCY_RATE), + float_to_fp16_16(69.276955602537 / FREQUENCY_RATE), + float_to_fp16_16(69.3502645502646 / FREQUENCY_RATE), + float_to_fp16_16(69.4237288135593 / FREQUENCY_RATE), + float_to_fp16_16(69.4973488865324 / FREQUENCY_RATE), + float_to_fp16_16(69.5711252653928 / FREQUENCY_RATE), + float_to_fp16_16(69.6450584484591 / FREQUENCY_RATE), + float_to_fp16_16(69.7191489361702 / FREQUENCY_RATE), + float_to_fp16_16(69.7933972310969 / FREQUENCY_RATE), + float_to_fp16_16(69.8678038379531 / FREQUENCY_RATE), + float_to_fp16_16(69.9423692636073 / FREQUENCY_RATE), + float_to_fp16_16(70.017094017094 / FREQUENCY_RATE), + float_to_fp16_16(70.0919786096257 / FREQUENCY_RATE), + float_to_fp16_16(70.1670235546039 / FREQUENCY_RATE), + float_to_fp16_16(70.2422293676313 / FREQUENCY_RATE), + float_to_fp16_16(70.3175965665236 / FREQUENCY_RATE), + float_to_fp16_16(70.3931256713212 / FREQUENCY_RATE), + float_to_fp16_16(70.4688172043011 / FREQUENCY_RATE), + float_to_fp16_16(70.5446716899892 / FREQUENCY_RATE), + float_to_fp16_16(70.6206896551724 / FREQUENCY_RATE), + float_to_fp16_16(70.6968716289105 / FREQUENCY_RATE), + float_to_fp16_16(70.7732181425486 / FREQUENCY_RATE), + float_to_fp16_16(70.8497297297297 / FREQUENCY_RATE), + float_to_fp16_16(70.9264069264069 / FREQUENCY_RATE), + float_to_fp16_16(71.0032502708559 / FREQUENCY_RATE), + float_to_fp16_16(71.0802603036876 / FREQUENCY_RATE), + float_to_fp16_16(71.157437567861 / FREQUENCY_RATE), + float_to_fp16_16(71.2347826086957 / FREQUENCY_RATE), + float_to_fp16_16(71.3122959738847 / FREQUENCY_RATE), + float_to_fp16_16(71.3899782135076 / FREQUENCY_RATE), + float_to_fp16_16(71.4678298800436 / FREQUENCY_RATE), + float_to_fp16_16(71.5458515283843 / FREQUENCY_RATE), + float_to_fp16_16(71.624043715847 / FREQUENCY_RATE), + float_to_fp16_16(71.7024070021882 / FREQUENCY_RATE), + float_to_fp16_16(71.7809419496166 / FREQUENCY_RATE), + float_to_fp16_16(71.859649122807 / FREQUENCY_RATE), + float_to_fp16_16(71.9385290889133 / FREQUENCY_RATE), + float_to_fp16_16(72.0175824175824 / FREQUENCY_RATE), + float_to_fp16_16(72.0968096809681 / FREQUENCY_RATE), + float_to_fp16_16(72.1762114537445 / FREQUENCY_RATE), + float_to_fp16_16(72.2557883131202 / FREQUENCY_RATE), + float_to_fp16_16(72.3355408388521 / FREQUENCY_RATE), + float_to_fp16_16(72.4154696132597 / FREQUENCY_RATE), + float_to_fp16_16(72.4955752212389 / FREQUENCY_RATE), + float_to_fp16_16(72.5758582502769 / FREQUENCY_RATE), + float_to_fp16_16(72.6563192904656 / FREQUENCY_RATE), + float_to_fp16_16(72.7369589345172 / FREQUENCY_RATE), + float_to_fp16_16(72.8177777777778 / FREQUENCY_RATE), + float_to_fp16_16(72.8987764182425 / FREQUENCY_RATE), + float_to_fp16_16(72.9799554565702 / FREQUENCY_RATE), + float_to_fp16_16(73.0613154960981 / FREQUENCY_RATE), + float_to_fp16_16(73.1428571428571 / FREQUENCY_RATE), + float_to_fp16_16(73.2245810055866 / FREQUENCY_RATE), + float_to_fp16_16(73.3064876957494 / FREQUENCY_RATE), + float_to_fp16_16(73.3885778275476 / FREQUENCY_RATE), + float_to_fp16_16(73.4708520179372 / FREQUENCY_RATE), + float_to_fp16_16(73.5533108866442 / FREQUENCY_RATE), + float_to_fp16_16(73.6359550561798 / FREQUENCY_RATE), + float_to_fp16_16(73.718785151856 / FREQUENCY_RATE), + float_to_fp16_16(73.8018018018018 / FREQUENCY_RATE), + float_to_fp16_16(73.8850056369786 / FREQUENCY_RATE), + float_to_fp16_16(73.9683972911964 / FREQUENCY_RATE), + float_to_fp16_16(74.0519774011299 / FREQUENCY_RATE), + float_to_fp16_16(74.1357466063348 / FREQUENCY_RATE), + float_to_fp16_16(74.2197055492639 / FREQUENCY_RATE), + float_to_fp16_16(74.3038548752835 / FREQUENCY_RATE), + float_to_fp16_16(74.3881952326901 / FREQUENCY_RATE), + float_to_fp16_16(74.4727272727273 / FREQUENCY_RATE), + float_to_fp16_16(74.5574516496018 / FREQUENCY_RATE), + float_to_fp16_16(74.6423690205011 / FREQUENCY_RATE), + float_to_fp16_16(74.72748004561 / FREQUENCY_RATE), + float_to_fp16_16(74.8127853881279 / FREQUENCY_RATE), + float_to_fp16_16(74.8982857142857 / FREQUENCY_RATE), + float_to_fp16_16(74.9839816933639 / FREQUENCY_RATE), + float_to_fp16_16(75.0698739977091 / FREQUENCY_RATE), + float_to_fp16_16(75.1559633027523 / FREQUENCY_RATE), + float_to_fp16_16(75.2422502870264 / FREQUENCY_RATE), + float_to_fp16_16(75.3287356321839 / FREQUENCY_RATE), + float_to_fp16_16(75.415420023015 / FREQUENCY_RATE), + float_to_fp16_16(75.5023041474654 / FREQUENCY_RATE), + float_to_fp16_16(75.5893886966551 / FREQUENCY_RATE), + float_to_fp16_16(75.6766743648961 / FREQUENCY_RATE), + float_to_fp16_16(75.764161849711 / FREQUENCY_RATE), + float_to_fp16_16(75.8518518518518 / FREQUENCY_RATE), + float_to_fp16_16(75.9397450753187 / FREQUENCY_RATE), + float_to_fp16_16(76.0278422273782 / FREQUENCY_RATE), + float_to_fp16_16(76.116144018583 / FREQUENCY_RATE), + float_to_fp16_16(76.2046511627907 / FREQUENCY_RATE), + float_to_fp16_16(76.2933643771828 / FREQUENCY_RATE), + float_to_fp16_16(76.3822843822844 / FREQUENCY_RATE), + float_to_fp16_16(76.4714119019837 / FREQUENCY_RATE), + float_to_fp16_16(76.5607476635514 / FREQUENCY_RATE), + float_to_fp16_16(76.6502923976608 / FREQUENCY_RATE), + float_to_fp16_16(76.7400468384075 / FREQUENCY_RATE), + float_to_fp16_16(76.8300117233294 / FREQUENCY_RATE), + float_to_fp16_16(76.9201877934272 / FREQUENCY_RATE), + float_to_fp16_16(77.0105757931845 / FREQUENCY_RATE), + float_to_fp16_16(77.1011764705882 / FREQUENCY_RATE), + float_to_fp16_16(77.1919905771496 / FREQUENCY_RATE), + float_to_fp16_16(77.2830188679245 / FREQUENCY_RATE), + float_to_fp16_16(77.3742621015348 / FREQUENCY_RATE), + float_to_fp16_16(77.4657210401891 / FREQUENCY_RATE), + float_to_fp16_16(77.5573964497041 / FREQUENCY_RATE), + float_to_fp16_16(77.6492890995261 / FREQUENCY_RATE), + float_to_fp16_16(77.7413997627521 / FREQUENCY_RATE), + float_to_fp16_16(77.833729216152 / FREQUENCY_RATE), + float_to_fp16_16(77.9262782401902 / FREQUENCY_RATE), + float_to_fp16_16(78.0190476190476 / FREQUENCY_RATE), + float_to_fp16_16(78.1120381406436 / FREQUENCY_RATE), + float_to_fp16_16(78.2052505966587 / FREQUENCY_RATE), + float_to_fp16_16(78.2986857825568 / FREQUENCY_RATE), + float_to_fp16_16(78.3923444976077 / FREQUENCY_RATE), + float_to_fp16_16(78.4862275449102 / FREQUENCY_RATE), + float_to_fp16_16(78.5803357314149 / FREQUENCY_RATE), + float_to_fp16_16(78.6746698679472 / FREQUENCY_RATE), + float_to_fp16_16(78.7692307692308 / FREQUENCY_RATE), + float_to_fp16_16(78.864019253911 / FREQUENCY_RATE), + float_to_fp16_16(78.9590361445783 / FREQUENCY_RATE), + float_to_fp16_16(79.0542822677925 / FREQUENCY_RATE), + float_to_fp16_16(79.1497584541063 / FREQUENCY_RATE), + float_to_fp16_16(79.2454655380895 / FREQUENCY_RATE), + float_to_fp16_16(79.3414043583535 / FREQUENCY_RATE), + float_to_fp16_16(79.4375757575758 / FREQUENCY_RATE), + float_to_fp16_16(79.5339805825243 / FREQUENCY_RATE), + float_to_fp16_16(79.6306196840826 / FREQUENCY_RATE), + float_to_fp16_16(79.7274939172749 / FREQUENCY_RATE), + float_to_fp16_16(79.8246041412911 / FREQUENCY_RATE), + float_to_fp16_16(79.9219512195122 / FREQUENCY_RATE), + float_to_fp16_16(80.019536019536 / FREQUENCY_RATE), + float_to_fp16_16(80.1173594132029 / FREQUENCY_RATE), + float_to_fp16_16(80.2154222766218 / FREQUENCY_RATE), + float_to_fp16_16(80.3137254901961 / FREQUENCY_RATE), + float_to_fp16_16(80.4122699386503 / FREQUENCY_RATE), + float_to_fp16_16(80.5110565110565 / FREQUENCY_RATE), + float_to_fp16_16(80.610086100861 / FREQUENCY_RATE), + float_to_fp16_16(80.7093596059113 / FREQUENCY_RATE), + float_to_fp16_16(80.8088779284834 / FREQUENCY_RATE), + float_to_fp16_16(80.9086419753086 / FREQUENCY_RATE), + float_to_fp16_16(81.008652657602 / FREQUENCY_RATE), + float_to_fp16_16(81.1089108910891 / FREQUENCY_RATE), + float_to_fp16_16(81.2094175960347 / FREQUENCY_RATE), + float_to_fp16_16(81.3101736972705 / FREQUENCY_RATE), + float_to_fp16_16(81.4111801242236 / FREQUENCY_RATE), + float_to_fp16_16(81.5124378109453 / FREQUENCY_RATE), + float_to_fp16_16(81.6139476961395 / FREQUENCY_RATE), + float_to_fp16_16(81.715710723192 / FREQUENCY_RATE), + float_to_fp16_16(81.8177278401998 / FREQUENCY_RATE), + float_to_fp16_16(81.92 / FREQUENCY_RATE), + float_to_fp16_16(82.0225281602002 / FREQUENCY_RATE), + float_to_fp16_16(82.125313283208 / FREQUENCY_RATE), + float_to_fp16_16(82.228356336261 / FREQUENCY_RATE), + float_to_fp16_16(82.3316582914573 / FREQUENCY_RATE), + float_to_fp16_16(82.4352201257862 / FREQUENCY_RATE), + float_to_fp16_16(82.5390428211587 / FREQUENCY_RATE), + float_to_fp16_16(82.6431273644388 / FREQUENCY_RATE), + float_to_fp16_16(82.7474747474748 / FREQUENCY_RATE), + float_to_fp16_16(82.8520859671302 / FREQUENCY_RATE), + float_to_fp16_16(82.9569620253165 / FREQUENCY_RATE), + float_to_fp16_16(83.0621039290241 / FREQUENCY_RATE), + float_to_fp16_16(83.1675126903553 / FREQUENCY_RATE), + float_to_fp16_16(83.2731893265565 / FREQUENCY_RATE), + float_to_fp16_16(83.3791348600509 / FREQUENCY_RATE), + float_to_fp16_16(83.4853503184713 / FREQUENCY_RATE), + float_to_fp16_16(83.5918367346939 / FREQUENCY_RATE), + float_to_fp16_16(83.698595146871 / FREQUENCY_RATE), + float_to_fp16_16(83.8056265984655 / FREQUENCY_RATE), + float_to_fp16_16(83.9129321382842 / FREQUENCY_RATE), + float_to_fp16_16(84.0205128205128 / FREQUENCY_RATE), + float_to_fp16_16(84.1283697047497 / FREQUENCY_RATE), + float_to_fp16_16(84.2365038560411 / FREQUENCY_RATE), + float_to_fp16_16(84.3449163449163 / FREQUENCY_RATE), + float_to_fp16_16(84.4536082474227 / FREQUENCY_RATE), + float_to_fp16_16(84.5625806451613 / FREQUENCY_RATE), + float_to_fp16_16(84.671834625323 / FREQUENCY_RATE), + float_to_fp16_16(84.7813712807245 / FREQUENCY_RATE), + float_to_fp16_16(84.8911917098446 / FREQUENCY_RATE), + float_to_fp16_16(85.0012970168612 / FREQUENCY_RATE), + float_to_fp16_16(85.1116883116883 / FREQUENCY_RATE), + float_to_fp16_16(85.222366710013 / FREQUENCY_RATE), + float_to_fp16_16(85.3333333333333 / FREQUENCY_RATE), + float_to_fp16_16(85.4445893089961 / FREQUENCY_RATE), + float_to_fp16_16(85.556135770235 / FREQUENCY_RATE), + float_to_fp16_16(85.6679738562091 / FREQUENCY_RATE), + float_to_fp16_16(85.7801047120419 / FREQUENCY_RATE), + float_to_fp16_16(85.8925294888598 / FREQUENCY_RATE), + float_to_fp16_16(86.005249343832 / FREQUENCY_RATE), + float_to_fp16_16(86.1182654402102 / FREQUENCY_RATE), + float_to_fp16_16(86.2315789473684 / FREQUENCY_RATE), + float_to_fp16_16(86.3451910408432 / FREQUENCY_RATE), + float_to_fp16_16(86.4591029023747 / FREQUENCY_RATE), + float_to_fp16_16(86.5733157199472 / FREQUENCY_RATE), + float_to_fp16_16(86.6878306878307 / FREQUENCY_RATE), + float_to_fp16_16(86.8026490066225 / FREQUENCY_RATE), + float_to_fp16_16(86.9177718832891 / FREQUENCY_RATE), + float_to_fp16_16(87.0332005312085 / FREQUENCY_RATE), + float_to_fp16_16(87.1489361702128 / FREQUENCY_RATE), + float_to_fp16_16(87.2649800266312 / FREQUENCY_RATE), + float_to_fp16_16(87.3813333333333 / FREQUENCY_RATE), + float_to_fp16_16(87.497997329773 / FREQUENCY_RATE), + float_to_fp16_16(87.6149732620321 / FREQUENCY_RATE), + float_to_fp16_16(87.7322623828648 / FREQUENCY_RATE), + float_to_fp16_16(87.8498659517426 / FREQUENCY_RATE), + float_to_fp16_16(87.9677852348993 / FREQUENCY_RATE), + float_to_fp16_16(88.0860215053763 / FREQUENCY_RATE), + float_to_fp16_16(88.2045760430686 / FREQUENCY_RATE), + float_to_fp16_16(88.3234501347709 / FREQUENCY_RATE), + float_to_fp16_16(88.442645074224 / FREQUENCY_RATE), + float_to_fp16_16(88.5621621621622 / FREQUENCY_RATE), + float_to_fp16_16(88.68200270636 / FREQUENCY_RATE), + float_to_fp16_16(88.8021680216802 / FREQUENCY_RATE), + float_to_fp16_16(88.9226594301221 / FREQUENCY_RATE), + float_to_fp16_16(89.0434782608696 / FREQUENCY_RATE), + float_to_fp16_16(89.1646258503401 / FREQUENCY_RATE), + float_to_fp16_16(89.2861035422343 / FREQUENCY_RATE), + float_to_fp16_16(89.4079126875853 / FREQUENCY_RATE), + float_to_fp16_16(89.5300546448087 / FREQUENCY_RATE), + float_to_fp16_16(89.6525307797538 / FREQUENCY_RATE), + float_to_fp16_16(89.7753424657534 / FREQUENCY_RATE), + float_to_fp16_16(89.8984910836763 / FREQUENCY_RATE), + float_to_fp16_16(90.021978021978 / FREQUENCY_RATE), + float_to_fp16_16(90.1458046767538 / FREQUENCY_RATE), + float_to_fp16_16(90.2699724517906 / FREQUENCY_RATE), + float_to_fp16_16(90.3944827586207 / FREQUENCY_RATE), + float_to_fp16_16(90.5193370165746 / FREQUENCY_RATE), + float_to_fp16_16(90.6445366528354 / FREQUENCY_RATE), + float_to_fp16_16(90.7700831024931 / FREQUENCY_RATE), + float_to_fp16_16(90.8959778085992 / FREQUENCY_RATE), + float_to_fp16_16(91.0222222222222 / FREQUENCY_RATE), + float_to_fp16_16(91.1488178025035 / FREQUENCY_RATE), + float_to_fp16_16(91.2757660167131 / FREQUENCY_RATE), + float_to_fp16_16(91.4030683403068 / FREQUENCY_RATE), + float_to_fp16_16(91.5307262569833 / FREQUENCY_RATE), + float_to_fp16_16(91.6587412587413 / FREQUENCY_RATE), + float_to_fp16_16(91.7871148459384 / FREQUENCY_RATE), + float_to_fp16_16(91.9158485273492 / FREQUENCY_RATE), + float_to_fp16_16(92.0449438202247 / FREQUENCY_RATE), + float_to_fp16_16(92.1744022503516 / FREQUENCY_RATE), + float_to_fp16_16(92.3042253521127 / FREQUENCY_RATE), + float_to_fp16_16(92.4344146685472 / FREQUENCY_RATE), + float_to_fp16_16(92.5649717514124 / FREQUENCY_RATE), + float_to_fp16_16(92.6958981612447 / FREQUENCY_RATE), + float_to_fp16_16(92.8271954674221 / FREQUENCY_RATE), + float_to_fp16_16(92.958865248227 / FREQUENCY_RATE), + float_to_fp16_16(93.0909090909091 / FREQUENCY_RATE), + float_to_fp16_16(93.2233285917497 / FREQUENCY_RATE), + float_to_fp16_16(93.3561253561254 / FREQUENCY_RATE), + float_to_fp16_16(93.4893009985735 / FREQUENCY_RATE), + float_to_fp16_16(93.6228571428572 / FREQUENCY_RATE), + float_to_fp16_16(93.7567954220315 / FREQUENCY_RATE), + float_to_fp16_16(93.89111747851 / FREQUENCY_RATE), + float_to_fp16_16(94.025824964132 / FREQUENCY_RATE), + float_to_fp16_16(94.1609195402299 / FREQUENCY_RATE), + float_to_fp16_16(94.2964028776978 / FREQUENCY_RATE), + float_to_fp16_16(94.4322766570605 / FREQUENCY_RATE), + float_to_fp16_16(94.5685425685426 / FREQUENCY_RATE), + float_to_fp16_16(94.7052023121387 / FREQUENCY_RATE), + float_to_fp16_16(94.8422575976845 / FREQUENCY_RATE), + float_to_fp16_16(94.9797101449275 / FREQUENCY_RATE), + float_to_fp16_16(95.1175616835994 / FREQUENCY_RATE), + float_to_fp16_16(95.2558139534884 / FREQUENCY_RATE), + float_to_fp16_16(95.3944687045124 / FREQUENCY_RATE), + float_to_fp16_16(95.533527696793 / FREQUENCY_RATE), + float_to_fp16_16(95.6729927007299 / FREQUENCY_RATE), + float_to_fp16_16(95.812865497076 / FREQUENCY_RATE), + float_to_fp16_16(95.9531478770132 / FREQUENCY_RATE), + float_to_fp16_16(96.0938416422287 / FREQUENCY_RATE), + float_to_fp16_16(96.2349486049927 / FREQUENCY_RATE), + float_to_fp16_16(96.3764705882353 / FREQUENCY_RATE), + float_to_fp16_16(96.5184094256259 / FREQUENCY_RATE), + float_to_fp16_16(96.6607669616519 / FREQUENCY_RATE), + float_to_fp16_16(96.8035450516987 / FREQUENCY_RATE), + float_to_fp16_16(96.9467455621302 / FREQUENCY_RATE), + float_to_fp16_16(97.0903703703704 / FREQUENCY_RATE), + float_to_fp16_16(97.2344213649852 / FREQUENCY_RATE), + float_to_fp16_16(97.3789004457652 / FREQUENCY_RATE), + float_to_fp16_16(97.5238095238095 / FREQUENCY_RATE), + float_to_fp16_16(97.6691505216095 / FREQUENCY_RATE), + float_to_fp16_16(97.8149253731343 / FREQUENCY_RATE), + float_to_fp16_16(97.9611360239163 / FREQUENCY_RATE), + float_to_fp16_16(98.1077844311377 / FREQUENCY_RATE), + float_to_fp16_16(98.2548725637181 / FREQUENCY_RATE), + float_to_fp16_16(98.4024024024024 / FREQUENCY_RATE), + float_to_fp16_16(98.5503759398496 / FREQUENCY_RATE), + float_to_fp16_16(98.6987951807229 / FREQUENCY_RATE), + float_to_fp16_16(98.8476621417798 / FREQUENCY_RATE), + float_to_fp16_16(98.9969788519637 / FREQUENCY_RATE), + float_to_fp16_16(99.1467473524962 / FREQUENCY_RATE), + float_to_fp16_16(99.2969696969697 / FREQUENCY_RATE), + float_to_fp16_16(99.4476479514416 / FREQUENCY_RATE), + float_to_fp16_16(99.5987841945289 / FREQUENCY_RATE), + float_to_fp16_16(99.7503805175038 / FREQUENCY_RATE), + float_to_fp16_16(99.9024390243902 / FREQUENCY_RATE), + float_to_fp16_16(100.054961832061 / FREQUENCY_RATE), + float_to_fp16_16(100.207951070336 / FREQUENCY_RATE), + float_to_fp16_16(100.361408882083 / FREQUENCY_RATE), + float_to_fp16_16(100.515337423313 / FREQUENCY_RATE), + float_to_fp16_16(100.669738863287 / FREQUENCY_RATE), + float_to_fp16_16(100.824615384615 / FREQUENCY_RATE), + float_to_fp16_16(100.979969183359 / FREQUENCY_RATE), + float_to_fp16_16(101.135802469136 / FREQUENCY_RATE), + float_to_fp16_16(101.292117465224 / FREQUENCY_RATE), + float_to_fp16_16(101.448916408669 / FREQUENCY_RATE), + float_to_fp16_16(101.606201550388 / FREQUENCY_RATE), + float_to_fp16_16(101.76397515528 / FREQUENCY_RATE), + float_to_fp16_16(101.922239502333 / FREQUENCY_RATE), + float_to_fp16_16(102.080996884735 / FREQUENCY_RATE), + float_to_fp16_16(102.240249609984 / FREQUENCY_RATE), + float_to_fp16_16(102.4 / FREQUENCY_RATE), + float_to_fp16_16(102.560250391236 / FREQUENCY_RATE), + float_to_fp16_16(102.721003134796 / FREQUENCY_RATE), + float_to_fp16_16(102.882260596546 / FREQUENCY_RATE), + float_to_fp16_16(103.044025157233 / FREQUENCY_RATE), + float_to_fp16_16(103.206299212598 / FREQUENCY_RATE), + float_to_fp16_16(103.369085173502 / FREQUENCY_RATE), + float_to_fp16_16(103.532385466035 / FREQUENCY_RATE), + float_to_fp16_16(103.696202531646 / FREQUENCY_RATE), + float_to_fp16_16(103.860538827258 / FREQUENCY_RATE), + float_to_fp16_16(104.025396825397 / FREQUENCY_RATE), + float_to_fp16_16(104.190779014308 / FREQUENCY_RATE), + float_to_fp16_16(104.356687898089 / FREQUENCY_RATE), + float_to_fp16_16(104.52312599681 / FREQUENCY_RATE), + float_to_fp16_16(104.690095846645 / FREQUENCY_RATE), + float_to_fp16_16(104.8576 / FREQUENCY_RATE), + float_to_fp16_16(105.025641025641 / FREQUENCY_RATE), + float_to_fp16_16(105.194221508828 / FREQUENCY_RATE), + float_to_fp16_16(105.363344051447 / FREQUENCY_RATE), + float_to_fp16_16(105.533011272142 / FREQUENCY_RATE), + float_to_fp16_16(105.703225806452 / FREQUENCY_RATE), + float_to_fp16_16(105.873990306947 / FREQUENCY_RATE), + float_to_fp16_16(106.045307443366 / FREQUENCY_RATE), + float_to_fp16_16(106.217179902755 / FREQUENCY_RATE), + float_to_fp16_16(106.38961038961 / FREQUENCY_RATE), + float_to_fp16_16(106.562601626016 / FREQUENCY_RATE), + float_to_fp16_16(106.736156351792 / FREQUENCY_RATE), + float_to_fp16_16(106.910277324633 / FREQUENCY_RATE), + float_to_fp16_16(107.084967320261 / FREQUENCY_RATE), + float_to_fp16_16(107.26022913257 / FREQUENCY_RATE), + float_to_fp16_16(107.436065573771 / FREQUENCY_RATE), + float_to_fp16_16(107.612479474548 / FREQUENCY_RATE), + float_to_fp16_16(107.789473684211 / FREQUENCY_RATE), + float_to_fp16_16(107.96705107084 / FREQUENCY_RATE), + float_to_fp16_16(108.145214521452 / FREQUENCY_RATE), + float_to_fp16_16(108.323966942149 / FREQUENCY_RATE), + float_to_fp16_16(108.503311258278 / FREQUENCY_RATE), + float_to_fp16_16(108.683250414594 / FREQUENCY_RATE), + float_to_fp16_16(108.863787375415 / FREQUENCY_RATE), + float_to_fp16_16(109.044925124792 / FREQUENCY_RATE), + float_to_fp16_16(109.226666666667 / FREQUENCY_RATE), + float_to_fp16_16(109.409015025042 / FREQUENCY_RATE), + float_to_fp16_16(109.591973244147 / FREQUENCY_RATE), + float_to_fp16_16(109.77554438861 / FREQUENCY_RATE), + float_to_fp16_16(109.959731543624 / FREQUENCY_RATE), + float_to_fp16_16(110.144537815126 / FREQUENCY_RATE), + float_to_fp16_16(110.329966329966 / FREQUENCY_RATE), + float_to_fp16_16(110.516020236088 / FREQUENCY_RATE), + float_to_fp16_16(110.702702702703 / FREQUENCY_RATE), + float_to_fp16_16(110.890016920474 / FREQUENCY_RATE), + float_to_fp16_16(111.077966101695 / FREQUENCY_RATE), + float_to_fp16_16(111.266553480475 / FREQUENCY_RATE), + float_to_fp16_16(111.455782312925 / FREQUENCY_RATE), + float_to_fp16_16(111.645655877342 / FREQUENCY_RATE), + float_to_fp16_16(111.836177474403 / FREQUENCY_RATE), + float_to_fp16_16(112.02735042735 / FREQUENCY_RATE), + float_to_fp16_16(112.219178082192 / FREQUENCY_RATE), + float_to_fp16_16(112.41166380789 / FREQUENCY_RATE), + float_to_fp16_16(112.604810996564 / FREQUENCY_RATE), + float_to_fp16_16(112.798623063683 / FREQUENCY_RATE), + float_to_fp16_16(112.993103448276 / FREQUENCY_RATE), + float_to_fp16_16(113.188255613126 / FREQUENCY_RATE), + float_to_fp16_16(113.384083044983 / FREQUENCY_RATE), + float_to_fp16_16(113.580589254766 / FREQUENCY_RATE), + float_to_fp16_16(113.777777777778 / FREQUENCY_RATE), + float_to_fp16_16(113.975652173913 / FREQUENCY_RATE), + float_to_fp16_16(114.174216027875 / FREQUENCY_RATE), + float_to_fp16_16(114.373472949389 / FREQUENCY_RATE), + float_to_fp16_16(114.573426573427 / FREQUENCY_RATE), + float_to_fp16_16(114.77408056042 / FREQUENCY_RATE), + float_to_fp16_16(114.975438596491 / FREQUENCY_RATE), + float_to_fp16_16(115.177504393673 / FREQUENCY_RATE), + float_to_fp16_16(115.380281690141 / FREQUENCY_RATE), + float_to_fp16_16(115.583774250441 / FREQUENCY_RATE), + float_to_fp16_16(115.787985865724 / FREQUENCY_RATE), + float_to_fp16_16(115.992920353982 / FREQUENCY_RATE), + float_to_fp16_16(116.198581560284 / FREQUENCY_RATE), + float_to_fp16_16(116.404973357016 / FREQUENCY_RATE), + float_to_fp16_16(116.612099644128 / FREQUENCY_RATE), + float_to_fp16_16(116.819964349376 / FREQUENCY_RATE), + float_to_fp16_16(117.028571428571 / FREQUENCY_RATE), + float_to_fp16_16(117.237924865832 / FREQUENCY_RATE), + float_to_fp16_16(117.448028673835 / FREQUENCY_RATE), + float_to_fp16_16(117.658886894075 / FREQUENCY_RATE), + float_to_fp16_16(117.870503597122 / FREQUENCY_RATE), + float_to_fp16_16(118.082882882883 / FREQUENCY_RATE), + float_to_fp16_16(118.296028880866 / FREQUENCY_RATE), + float_to_fp16_16(118.509945750452 / FREQUENCY_RATE), + float_to_fp16_16(118.724637681159 / FREQUENCY_RATE), + float_to_fp16_16(118.940108892922 / FREQUENCY_RATE), + float_to_fp16_16(119.156363636364 / FREQUENCY_RATE), + float_to_fp16_16(119.373406193078 / FREQUENCY_RATE), + float_to_fp16_16(119.591240875912 / FREQUENCY_RATE), + float_to_fp16_16(119.80987202925 / FREQUENCY_RATE), + float_to_fp16_16(120.029304029304 / FREQUENCY_RATE), + float_to_fp16_16(120.249541284404 / FREQUENCY_RATE), + float_to_fp16_16(120.470588235294 / FREQUENCY_RATE), + float_to_fp16_16(120.692449355433 / FREQUENCY_RATE), + float_to_fp16_16(120.915129151292 / FREQUENCY_RATE), + float_to_fp16_16(121.138632162662 / FREQUENCY_RATE), + float_to_fp16_16(121.362962962963 / FREQUENCY_RATE), + float_to_fp16_16(121.588126159555 / FREQUENCY_RATE), + float_to_fp16_16(121.814126394052 / FREQUENCY_RATE), + float_to_fp16_16(122.040968342644 / FREQUENCY_RATE), + float_to_fp16_16(122.268656716418 / FREQUENCY_RATE), + float_to_fp16_16(122.497196261682 / FREQUENCY_RATE), + float_to_fp16_16(122.7265917603 / FREQUENCY_RATE), + float_to_fp16_16(122.956848030019 / FREQUENCY_RATE), + float_to_fp16_16(123.187969924812 / FREQUENCY_RATE), + float_to_fp16_16(123.419962335217 / FREQUENCY_RATE), + float_to_fp16_16(123.652830188679 / FREQUENCY_RATE), + float_to_fp16_16(123.886578449906 / FREQUENCY_RATE), + float_to_fp16_16(124.121212121212 / FREQUENCY_RATE), + float_to_fp16_16(124.356736242884 / FREQUENCY_RATE), + float_to_fp16_16(124.593155893536 / FREQUENCY_RATE), + float_to_fp16_16(124.830476190476 / FREQUENCY_RATE), + float_to_fp16_16(125.068702290076 / FREQUENCY_RATE), + float_to_fp16_16(125.307839388145 / FREQUENCY_RATE), + float_to_fp16_16(125.547892720307 / FREQUENCY_RATE), + float_to_fp16_16(125.78886756238 / FREQUENCY_RATE), + float_to_fp16_16(126.030769230769 / FREQUENCY_RATE), + float_to_fp16_16(126.273603082852 / FREQUENCY_RATE), + float_to_fp16_16(126.517374517375 / FREQUENCY_RATE), + float_to_fp16_16(126.762088974855 / FREQUENCY_RATE), + float_to_fp16_16(127.007751937985 / FREQUENCY_RATE), + float_to_fp16_16(127.254368932039 / FREQUENCY_RATE), + float_to_fp16_16(127.501945525292 / FREQUENCY_RATE), + float_to_fp16_16(127.750487329435 / FREQUENCY_RATE), + float_to_fp16_16(128 / FREQUENCY_RATE), + float_to_fp16_16(128.250489236791 / FREQUENCY_RATE), + float_to_fp16_16(128.501960784314 / FREQUENCY_RATE), + float_to_fp16_16(128.75442043222 / FREQUENCY_RATE), + float_to_fp16_16(129.007874015748 / FREQUENCY_RATE), + float_to_fp16_16(129.262327416174 / FREQUENCY_RATE), + float_to_fp16_16(129.517786561265 / FREQUENCY_RATE), + float_to_fp16_16(129.774257425743 / FREQUENCY_RATE), + float_to_fp16_16(130.031746031746 / FREQUENCY_RATE), + float_to_fp16_16(130.290258449304 / FREQUENCY_RATE), + float_to_fp16_16(130.549800796813 / FREQUENCY_RATE), + float_to_fp16_16(130.810379241517 / FREQUENCY_RATE), + float_to_fp16_16(131.072 / FREQUENCY_RATE), + float_to_fp16_16(131.334669338677 / FREQUENCY_RATE), + float_to_fp16_16(131.598393574297 / FREQUENCY_RATE), + float_to_fp16_16(131.863179074447 / FREQUENCY_RATE), + float_to_fp16_16(132.129032258065 / FREQUENCY_RATE), + float_to_fp16_16(132.39595959596 / FREQUENCY_RATE), + float_to_fp16_16(132.663967611336 / FREQUENCY_RATE), + float_to_fp16_16(132.933062880325 / FREQUENCY_RATE), + float_to_fp16_16(133.20325203252 / FREQUENCY_RATE), + float_to_fp16_16(133.474541751527 / FREQUENCY_RATE), + float_to_fp16_16(133.74693877551 / FREQUENCY_RATE), + float_to_fp16_16(134.020449897751 / FREQUENCY_RATE), + float_to_fp16_16(134.295081967213 / FREQUENCY_RATE), + float_to_fp16_16(134.570841889117 / FREQUENCY_RATE), + float_to_fp16_16(134.847736625514 / FREQUENCY_RATE), + float_to_fp16_16(135.125773195876 / FREQUENCY_RATE), + float_to_fp16_16(135.404958677686 / FREQUENCY_RATE), + float_to_fp16_16(135.685300207039 / FREQUENCY_RATE), + float_to_fp16_16(135.966804979253 / FREQUENCY_RATE), + float_to_fp16_16(136.24948024948 / FREQUENCY_RATE), + float_to_fp16_16(136.533333333333 / FREQUENCY_RATE), + float_to_fp16_16(136.818371607516 / FREQUENCY_RATE), + float_to_fp16_16(137.10460251046 / FREQUENCY_RATE), + float_to_fp16_16(137.392033542977 / FREQUENCY_RATE), + float_to_fp16_16(137.680672268908 / FREQUENCY_RATE), + float_to_fp16_16(137.970526315789 / FREQUENCY_RATE), + float_to_fp16_16(138.261603375527 / FREQUENCY_RATE), + float_to_fp16_16(138.553911205074 / FREQUENCY_RATE), + float_to_fp16_16(138.847457627119 / FREQUENCY_RATE), + float_to_fp16_16(139.142250530786 / FREQUENCY_RATE), + float_to_fp16_16(139.43829787234 / FREQUENCY_RATE), + float_to_fp16_16(139.735607675906 / FREQUENCY_RATE), + float_to_fp16_16(140.034188034188 / FREQUENCY_RATE), + float_to_fp16_16(140.334047109208 / FREQUENCY_RATE), + float_to_fp16_16(140.635193133047 / FREQUENCY_RATE), + float_to_fp16_16(140.937634408602 / FREQUENCY_RATE), + float_to_fp16_16(141.241379310345 / FREQUENCY_RATE), + float_to_fp16_16(141.546436285097 / FREQUENCY_RATE), + float_to_fp16_16(141.852813852814 / FREQUENCY_RATE), + float_to_fp16_16(142.160520607375 / FREQUENCY_RATE), + float_to_fp16_16(142.469565217391 / FREQUENCY_RATE), + float_to_fp16_16(142.779956427015 / FREQUENCY_RATE), + float_to_fp16_16(143.091703056769 / FREQUENCY_RATE), + float_to_fp16_16(143.404814004376 / FREQUENCY_RATE), + float_to_fp16_16(143.719298245614 / FREQUENCY_RATE), + float_to_fp16_16(144.035164835165 / FREQUENCY_RATE), + float_to_fp16_16(144.352422907489 / FREQUENCY_RATE), + float_to_fp16_16(144.671081677704 / FREQUENCY_RATE), + float_to_fp16_16(144.991150442478 / FREQUENCY_RATE), + float_to_fp16_16(145.312638580931 / FREQUENCY_RATE), + float_to_fp16_16(145.635555555556 / FREQUENCY_RATE), + float_to_fp16_16(145.95991091314 / FREQUENCY_RATE), + float_to_fp16_16(146.285714285714 / FREQUENCY_RATE), + float_to_fp16_16(146.612975391499 / FREQUENCY_RATE), + float_to_fp16_16(146.941704035874 / FREQUENCY_RATE), + float_to_fp16_16(147.27191011236 / FREQUENCY_RATE), + float_to_fp16_16(147.603603603604 / FREQUENCY_RATE), + float_to_fp16_16(147.936794582393 / FREQUENCY_RATE), + float_to_fp16_16(148.27149321267 / FREQUENCY_RATE), + float_to_fp16_16(148.607709750567 / FREQUENCY_RATE), + float_to_fp16_16(148.945454545455 / FREQUENCY_RATE), + float_to_fp16_16(149.284738041002 / FREQUENCY_RATE), + float_to_fp16_16(149.625570776256 / FREQUENCY_RATE), + float_to_fp16_16(149.967963386728 / FREQUENCY_RATE), + float_to_fp16_16(150.311926605505 / FREQUENCY_RATE), + float_to_fp16_16(150.657471264368 / FREQUENCY_RATE), + float_to_fp16_16(151.004608294931 / FREQUENCY_RATE), + float_to_fp16_16(151.353348729792 / FREQUENCY_RATE), + float_to_fp16_16(151.703703703704 / FREQUENCY_RATE), + float_to_fp16_16(152.055684454756 / FREQUENCY_RATE), + float_to_fp16_16(152.409302325581 / FREQUENCY_RATE), + float_to_fp16_16(152.764568764569 / FREQUENCY_RATE), + float_to_fp16_16(153.121495327103 / FREQUENCY_RATE), + float_to_fp16_16(153.480093676815 / FREQUENCY_RATE), + float_to_fp16_16(153.840375586854 / FREQUENCY_RATE), + float_to_fp16_16(154.202352941176 / FREQUENCY_RATE), + float_to_fp16_16(154.566037735849 / FREQUENCY_RATE), + float_to_fp16_16(154.931442080378 / FREQUENCY_RATE), + float_to_fp16_16(155.298578199052 / FREQUENCY_RATE), + float_to_fp16_16(155.667458432304 / FREQUENCY_RATE), + float_to_fp16_16(156.038095238095 / FREQUENCY_RATE), + float_to_fp16_16(156.410501193317 / FREQUENCY_RATE), + float_to_fp16_16(156.784688995215 / FREQUENCY_RATE), + float_to_fp16_16(157.16067146283 / FREQUENCY_RATE), + float_to_fp16_16(157.538461538462 / FREQUENCY_RATE), + float_to_fp16_16(157.918072289157 / FREQUENCY_RATE), + float_to_fp16_16(158.299516908213 / FREQUENCY_RATE), + float_to_fp16_16(158.682808716707 / FREQUENCY_RATE), + float_to_fp16_16(159.067961165049 / FREQUENCY_RATE), + float_to_fp16_16(159.45498783455 / FREQUENCY_RATE), + float_to_fp16_16(159.843902439024 / FREQUENCY_RATE), + float_to_fp16_16(160.234718826406 / FREQUENCY_RATE), + float_to_fp16_16(160.627450980392 / FREQUENCY_RATE), + float_to_fp16_16(161.022113022113 / FREQUENCY_RATE), + float_to_fp16_16(161.418719211823 / FREQUENCY_RATE), + float_to_fp16_16(161.817283950617 / FREQUENCY_RATE), + float_to_fp16_16(162.217821782178 / FREQUENCY_RATE), + float_to_fp16_16(162.620347394541 / FREQUENCY_RATE), + float_to_fp16_16(163.024875621891 / FREQUENCY_RATE), + float_to_fp16_16(163.431421446384 / FREQUENCY_RATE), + float_to_fp16_16(163.84 / FREQUENCY_RATE), + float_to_fp16_16(164.250626566416 / FREQUENCY_RATE), + float_to_fp16_16(164.663316582915 / FREQUENCY_RATE), + float_to_fp16_16(165.078085642317 / FREQUENCY_RATE), + float_to_fp16_16(165.49494949495 / FREQUENCY_RATE), + float_to_fp16_16(165.913924050633 / FREQUENCY_RATE), + float_to_fp16_16(166.335025380711 / FREQUENCY_RATE), + float_to_fp16_16(166.758269720102 / FREQUENCY_RATE), + float_to_fp16_16(167.183673469388 / FREQUENCY_RATE), + float_to_fp16_16(167.611253196931 / FREQUENCY_RATE), + float_to_fp16_16(168.041025641026 / FREQUENCY_RATE), + float_to_fp16_16(168.473007712082 / FREQUENCY_RATE), + float_to_fp16_16(168.907216494845 / FREQUENCY_RATE), + float_to_fp16_16(169.343669250646 / FREQUENCY_RATE), + float_to_fp16_16(169.782383419689 / FREQUENCY_RATE), + float_to_fp16_16(170.223376623377 / FREQUENCY_RATE), + float_to_fp16_16(170.666666666667 / FREQUENCY_RATE), + float_to_fp16_16(171.11227154047 / FREQUENCY_RATE), + float_to_fp16_16(171.560209424084 / FREQUENCY_RATE), + float_to_fp16_16(172.010498687664 / FREQUENCY_RATE), + float_to_fp16_16(172.463157894737 / FREQUENCY_RATE), + float_to_fp16_16(172.918205804749 / FREQUENCY_RATE), + float_to_fp16_16(173.375661375661 / FREQUENCY_RATE), + float_to_fp16_16(173.835543766578 / FREQUENCY_RATE), + float_to_fp16_16(174.297872340426 / FREQUENCY_RATE), + float_to_fp16_16(174.762666666667 / FREQUENCY_RATE), + float_to_fp16_16(175.229946524064 / FREQUENCY_RATE), + float_to_fp16_16(175.699731903485 / FREQUENCY_RATE), + float_to_fp16_16(176.172043010753 / FREQUENCY_RATE), + float_to_fp16_16(176.646900269542 / FREQUENCY_RATE), + float_to_fp16_16(177.124324324324 / FREQUENCY_RATE), + float_to_fp16_16(177.60433604336 / FREQUENCY_RATE), + float_to_fp16_16(178.086956521739 / FREQUENCY_RATE), + float_to_fp16_16(178.572207084469 / FREQUENCY_RATE), + float_to_fp16_16(179.060109289618 / FREQUENCY_RATE), + float_to_fp16_16(179.550684931507 / FREQUENCY_RATE), + float_to_fp16_16(180.043956043956 / FREQUENCY_RATE), + float_to_fp16_16(180.539944903581 / FREQUENCY_RATE), + float_to_fp16_16(181.038674033149 / FREQUENCY_RATE), + float_to_fp16_16(181.540166204986 / FREQUENCY_RATE), + float_to_fp16_16(182.044444444444 / FREQUENCY_RATE), + float_to_fp16_16(182.551532033426 / FREQUENCY_RATE), + float_to_fp16_16(183.061452513966 / FREQUENCY_RATE), + float_to_fp16_16(183.574229691877 / FREQUENCY_RATE), + float_to_fp16_16(184.089887640449 / FREQUENCY_RATE), + float_to_fp16_16(184.608450704225 / FREQUENCY_RATE), + float_to_fp16_16(185.129943502825 / FREQUENCY_RATE), + float_to_fp16_16(185.654390934844 / FREQUENCY_RATE), + float_to_fp16_16(186.181818181818 / FREQUENCY_RATE), + float_to_fp16_16(186.712250712251 / FREQUENCY_RATE), + float_to_fp16_16(187.245714285714 / FREQUENCY_RATE), + float_to_fp16_16(187.78223495702 / FREQUENCY_RATE), + float_to_fp16_16(188.32183908046 / FREQUENCY_RATE), + float_to_fp16_16(188.864553314121 / FREQUENCY_RATE), + float_to_fp16_16(189.410404624277 / FREQUENCY_RATE), + float_to_fp16_16(189.959420289855 / FREQUENCY_RATE), + float_to_fp16_16(190.511627906977 / FREQUENCY_RATE), + float_to_fp16_16(191.067055393586 / FREQUENCY_RATE), + float_to_fp16_16(191.625730994152 / FREQUENCY_RATE), + float_to_fp16_16(192.187683284457 / FREQUENCY_RATE), + float_to_fp16_16(192.752941176471 / FREQUENCY_RATE), + float_to_fp16_16(193.321533923304 / FREQUENCY_RATE), + float_to_fp16_16(193.89349112426 / FREQUENCY_RATE), + float_to_fp16_16(194.46884272997 / FREQUENCY_RATE), + float_to_fp16_16(195.047619047619 / FREQUENCY_RATE), + float_to_fp16_16(195.629850746269 / FREQUENCY_RATE), + float_to_fp16_16(196.215568862275 / FREQUENCY_RATE), + float_to_fp16_16(196.804804804805 / FREQUENCY_RATE), + float_to_fp16_16(197.397590361446 / FREQUENCY_RATE), + float_to_fp16_16(197.993957703928 / FREQUENCY_RATE), + float_to_fp16_16(198.593939393939 / FREQUENCY_RATE), + float_to_fp16_16(199.197568389058 / FREQUENCY_RATE), + float_to_fp16_16(199.804878048781 / FREQUENCY_RATE), + float_to_fp16_16(200.415902140673 / FREQUENCY_RATE), + float_to_fp16_16(201.030674846626 / FREQUENCY_RATE), + float_to_fp16_16(201.649230769231 / FREQUENCY_RATE), + float_to_fp16_16(202.271604938272 / FREQUENCY_RATE), + float_to_fp16_16(202.897832817337 / FREQUENCY_RATE), + float_to_fp16_16(203.527950310559 / FREQUENCY_RATE), + float_to_fp16_16(204.16199376947 / FREQUENCY_RATE), + float_to_fp16_16(204.8 / FREQUENCY_RATE), + float_to_fp16_16(205.442006269592 / FREQUENCY_RATE), + float_to_fp16_16(206.088050314465 / FREQUENCY_RATE), + float_to_fp16_16(206.738170347003 / FREQUENCY_RATE), + float_to_fp16_16(207.392405063291 / FREQUENCY_RATE), + float_to_fp16_16(208.050793650794 / FREQUENCY_RATE), + float_to_fp16_16(208.713375796178 / FREQUENCY_RATE), + float_to_fp16_16(209.380191693291 / FREQUENCY_RATE), + float_to_fp16_16(210.051282051282 / FREQUENCY_RATE), + float_to_fp16_16(210.726688102894 / FREQUENCY_RATE), + float_to_fp16_16(211.406451612903 / FREQUENCY_RATE), + float_to_fp16_16(212.090614886731 / FREQUENCY_RATE), + float_to_fp16_16(212.779220779221 / FREQUENCY_RATE), + float_to_fp16_16(213.472312703583 / FREQUENCY_RATE), + float_to_fp16_16(214.169934640523 / FREQUENCY_RATE), + float_to_fp16_16(214.872131147541 / FREQUENCY_RATE), + float_to_fp16_16(215.578947368421 / FREQUENCY_RATE), + float_to_fp16_16(216.290429042904 / FREQUENCY_RATE), + float_to_fp16_16(217.006622516556 / FREQUENCY_RATE), + float_to_fp16_16(217.727574750831 / FREQUENCY_RATE), + float_to_fp16_16(218.453333333333 / FREQUENCY_RATE), + float_to_fp16_16(219.183946488294 / FREQUENCY_RATE), + float_to_fp16_16(219.919463087248 / FREQUENCY_RATE), + float_to_fp16_16(220.659932659933 / FREQUENCY_RATE), + float_to_fp16_16(221.405405405405 / FREQUENCY_RATE), + float_to_fp16_16(222.15593220339 / FREQUENCY_RATE), + float_to_fp16_16(222.91156462585 / FREQUENCY_RATE), + float_to_fp16_16(223.672354948805 / FREQUENCY_RATE), + float_to_fp16_16(224.438356164384 / FREQUENCY_RATE), + float_to_fp16_16(225.209621993127 / FREQUENCY_RATE), + float_to_fp16_16(225.986206896552 / FREQUENCY_RATE), + float_to_fp16_16(226.768166089965 / FREQUENCY_RATE), + float_to_fp16_16(227.555555555556 / FREQUENCY_RATE), + float_to_fp16_16(228.348432055749 / FREQUENCY_RATE), + float_to_fp16_16(229.146853146853 / FREQUENCY_RATE), + float_to_fp16_16(229.950877192982 / FREQUENCY_RATE), + float_to_fp16_16(230.760563380282 / FREQUENCY_RATE), + float_to_fp16_16(231.575971731449 / FREQUENCY_RATE), + float_to_fp16_16(232.397163120567 / FREQUENCY_RATE), + float_to_fp16_16(233.224199288256 / FREQUENCY_RATE), + float_to_fp16_16(234.057142857143 / FREQUENCY_RATE), + float_to_fp16_16(234.89605734767 / FREQUENCY_RATE), + float_to_fp16_16(235.741007194245 / FREQUENCY_RATE), + float_to_fp16_16(236.592057761733 / FREQUENCY_RATE), + float_to_fp16_16(237.449275362319 / FREQUENCY_RATE), + float_to_fp16_16(238.312727272727 / FREQUENCY_RATE), + float_to_fp16_16(239.182481751825 / FREQUENCY_RATE), + float_to_fp16_16(240.058608058608 / FREQUENCY_RATE), + float_to_fp16_16(240.941176470588 / FREQUENCY_RATE), + float_to_fp16_16(241.830258302583 / FREQUENCY_RATE), + float_to_fp16_16(242.725925925926 / FREQUENCY_RATE), + float_to_fp16_16(243.628252788104 / FREQUENCY_RATE), + float_to_fp16_16(244.537313432836 / FREQUENCY_RATE), + float_to_fp16_16(245.453183520599 / FREQUENCY_RATE), + float_to_fp16_16(246.375939849624 / FREQUENCY_RATE), + float_to_fp16_16(247.305660377358 / FREQUENCY_RATE), + float_to_fp16_16(248.242424242424 / FREQUENCY_RATE), + float_to_fp16_16(249.186311787072 / FREQUENCY_RATE), + float_to_fp16_16(250.137404580153 / FREQUENCY_RATE), + float_to_fp16_16(251.095785440613 / FREQUENCY_RATE), + float_to_fp16_16(252.061538461538 / FREQUENCY_RATE), + float_to_fp16_16(253.034749034749 / FREQUENCY_RATE), + float_to_fp16_16(254.015503875969 / FREQUENCY_RATE), + float_to_fp16_16(255.003891050584 / FREQUENCY_RATE), + float_to_fp16_16(256 / FREQUENCY_RATE), + float_to_fp16_16(257.003921568627 / FREQUENCY_RATE), + float_to_fp16_16(258.015748031496 / FREQUENCY_RATE), + float_to_fp16_16(259.03557312253 / FREQUENCY_RATE), + float_to_fp16_16(260.063492063492 / FREQUENCY_RATE), + float_to_fp16_16(261.099601593625 / FREQUENCY_RATE), + float_to_fp16_16(262.144 / FREQUENCY_RATE), + float_to_fp16_16(263.196787148594 / FREQUENCY_RATE), + float_to_fp16_16(264.258064516129 / FREQUENCY_RATE), + float_to_fp16_16(265.327935222672 / FREQUENCY_RATE), + float_to_fp16_16(266.406504065041 / FREQUENCY_RATE), + float_to_fp16_16(267.49387755102 / FREQUENCY_RATE), + float_to_fp16_16(268.590163934426 / FREQUENCY_RATE), + float_to_fp16_16(269.695473251029 / FREQUENCY_RATE), + float_to_fp16_16(270.809917355372 / FREQUENCY_RATE), + float_to_fp16_16(271.933609958506 / FREQUENCY_RATE), + float_to_fp16_16(273.066666666667 / FREQUENCY_RATE), + float_to_fp16_16(274.20920502092 / FREQUENCY_RATE), + float_to_fp16_16(275.361344537815 / FREQUENCY_RATE), + float_to_fp16_16(276.523206751055 / FREQUENCY_RATE), + float_to_fp16_16(277.694915254237 / FREQUENCY_RATE), + float_to_fp16_16(278.876595744681 / FREQUENCY_RATE), + float_to_fp16_16(280.068376068376 / FREQUENCY_RATE), + float_to_fp16_16(281.270386266094 / FREQUENCY_RATE), + float_to_fp16_16(282.48275862069 / FREQUENCY_RATE), + float_to_fp16_16(283.705627705628 / FREQUENCY_RATE), + float_to_fp16_16(284.939130434783 / FREQUENCY_RATE), + float_to_fp16_16(286.183406113537 / FREQUENCY_RATE), + float_to_fp16_16(287.438596491228 / FREQUENCY_RATE), + float_to_fp16_16(288.704845814978 / FREQUENCY_RATE), + float_to_fp16_16(289.982300884956 / FREQUENCY_RATE), + float_to_fp16_16(291.271111111111 / FREQUENCY_RATE), + float_to_fp16_16(292.571428571429 / FREQUENCY_RATE), + float_to_fp16_16(293.883408071749 / FREQUENCY_RATE), + float_to_fp16_16(295.207207207207 / FREQUENCY_RATE), + float_to_fp16_16(296.542986425339 / FREQUENCY_RATE), + float_to_fp16_16(297.890909090909 / FREQUENCY_RATE), + float_to_fp16_16(299.251141552511 / FREQUENCY_RATE), + float_to_fp16_16(300.623853211009 / FREQUENCY_RATE), + float_to_fp16_16(302.009216589862 / FREQUENCY_RATE), + float_to_fp16_16(303.407407407407 / FREQUENCY_RATE), + float_to_fp16_16(304.818604651163 / FREQUENCY_RATE), + float_to_fp16_16(306.242990654206 / FREQUENCY_RATE), + float_to_fp16_16(307.680751173709 / FREQUENCY_RATE), + float_to_fp16_16(309.132075471698 / FREQUENCY_RATE), + float_to_fp16_16(310.597156398104 / FREQUENCY_RATE), + float_to_fp16_16(312.07619047619 / FREQUENCY_RATE), + float_to_fp16_16(313.569377990431 / FREQUENCY_RATE), + float_to_fp16_16(315.076923076923 / FREQUENCY_RATE), + float_to_fp16_16(316.599033816425 / FREQUENCY_RATE), + float_to_fp16_16(318.135922330097 / FREQUENCY_RATE), + float_to_fp16_16(319.687804878049 / FREQUENCY_RATE), + float_to_fp16_16(321.254901960784 / FREQUENCY_RATE), + float_to_fp16_16(322.837438423645 / FREQUENCY_RATE), + float_to_fp16_16(324.435643564356 / FREQUENCY_RATE), + float_to_fp16_16(326.049751243781 / FREQUENCY_RATE), + float_to_fp16_16(327.68 / FREQUENCY_RATE), + float_to_fp16_16(329.326633165829 / FREQUENCY_RATE), + float_to_fp16_16(330.989898989899 / FREQUENCY_RATE), + float_to_fp16_16(332.670050761421 / FREQUENCY_RATE), + float_to_fp16_16(334.367346938775 / FREQUENCY_RATE), + float_to_fp16_16(336.082051282051 / FREQUENCY_RATE), + float_to_fp16_16(337.814432989691 / FREQUENCY_RATE), + float_to_fp16_16(339.564766839378 / FREQUENCY_RATE), + float_to_fp16_16(341.333333333333 / FREQUENCY_RATE), + float_to_fp16_16(343.120418848168 / FREQUENCY_RATE), + float_to_fp16_16(344.926315789474 / FREQUENCY_RATE), + float_to_fp16_16(346.751322751323 / FREQUENCY_RATE), + float_to_fp16_16(348.595744680851 / FREQUENCY_RATE), + float_to_fp16_16(350.459893048128 / FREQUENCY_RATE), + float_to_fp16_16(352.344086021505 / FREQUENCY_RATE), + float_to_fp16_16(354.248648648649 / FREQUENCY_RATE), + float_to_fp16_16(356.173913043478 / FREQUENCY_RATE), + float_to_fp16_16(358.120218579235 / FREQUENCY_RATE), + float_to_fp16_16(360.087912087912 / FREQUENCY_RATE), + float_to_fp16_16(362.077348066298 / FREQUENCY_RATE), + float_to_fp16_16(364.088888888889 / FREQUENCY_RATE), + float_to_fp16_16(366.122905027933 / FREQUENCY_RATE), + float_to_fp16_16(368.179775280899 / FREQUENCY_RATE), + float_to_fp16_16(370.25988700565 / FREQUENCY_RATE), + float_to_fp16_16(372.363636363636 / FREQUENCY_RATE), + float_to_fp16_16(374.491428571429 / FREQUENCY_RATE), + float_to_fp16_16(376.64367816092 / FREQUENCY_RATE), + float_to_fp16_16(378.820809248555 / FREQUENCY_RATE), + float_to_fp16_16(381.023255813953 / FREQUENCY_RATE), + float_to_fp16_16(383.251461988304 / FREQUENCY_RATE), + float_to_fp16_16(385.505882352941 / FREQUENCY_RATE), + float_to_fp16_16(387.786982248521 / FREQUENCY_RATE), + float_to_fp16_16(390.095238095238 / FREQUENCY_RATE), + float_to_fp16_16(392.431137724551 / FREQUENCY_RATE), + float_to_fp16_16(394.795180722892 / FREQUENCY_RATE), + float_to_fp16_16(397.187878787879 / FREQUENCY_RATE), + float_to_fp16_16(399.609756097561 / FREQUENCY_RATE), + float_to_fp16_16(402.061349693252 / FREQUENCY_RATE), + float_to_fp16_16(404.543209876543 / FREQUENCY_RATE), + float_to_fp16_16(407.055900621118 / FREQUENCY_RATE), + float_to_fp16_16(409.6 / FREQUENCY_RATE), + float_to_fp16_16(412.176100628931 / FREQUENCY_RATE), + float_to_fp16_16(414.784810126582 / FREQUENCY_RATE), + float_to_fp16_16(417.426751592357 / FREQUENCY_RATE), + float_to_fp16_16(420.102564102564 / FREQUENCY_RATE), + float_to_fp16_16(422.812903225807 / FREQUENCY_RATE), + float_to_fp16_16(425.558441558442 / FREQUENCY_RATE), + float_to_fp16_16(428.339869281046 / FREQUENCY_RATE), + float_to_fp16_16(431.157894736842 / FREQUENCY_RATE), + float_to_fp16_16(434.013245033113 / FREQUENCY_RATE), + float_to_fp16_16(436.906666666667 / FREQUENCY_RATE), + float_to_fp16_16(439.838926174497 / FREQUENCY_RATE), + float_to_fp16_16(442.810810810811 / FREQUENCY_RATE), + float_to_fp16_16(445.823129251701 / FREQUENCY_RATE), + float_to_fp16_16(448.876712328767 / FREQUENCY_RATE), + float_to_fp16_16(451.972413793103 / FREQUENCY_RATE), + float_to_fp16_16(455.111111111111 / FREQUENCY_RATE), + float_to_fp16_16(458.293706293706 / FREQUENCY_RATE), + float_to_fp16_16(461.521126760563 / FREQUENCY_RATE), + float_to_fp16_16(464.794326241135 / FREQUENCY_RATE), + float_to_fp16_16(468.114285714286 / FREQUENCY_RATE), + float_to_fp16_16(471.482014388489 / FREQUENCY_RATE), + float_to_fp16_16(474.898550724638 / FREQUENCY_RATE), + float_to_fp16_16(478.36496350365 / FREQUENCY_RATE), + float_to_fp16_16(481.882352941176 / FREQUENCY_RATE), + float_to_fp16_16(485.451851851852 / FREQUENCY_RATE), + float_to_fp16_16(489.074626865672 / FREQUENCY_RATE), + float_to_fp16_16(492.751879699248 / FREQUENCY_RATE), + float_to_fp16_16(496.484848484849 / FREQUENCY_RATE), + float_to_fp16_16(500.274809160305 / FREQUENCY_RATE), + float_to_fp16_16(504.123076923077 / FREQUENCY_RATE), + float_to_fp16_16(508.031007751938 / FREQUENCY_RATE), + float_to_fp16_16(512 / FREQUENCY_RATE), + float_to_fp16_16(516.031496062992 / FREQUENCY_RATE), + float_to_fp16_16(520.126984126984 / FREQUENCY_RATE), + float_to_fp16_16(524.288 / FREQUENCY_RATE), + float_to_fp16_16(528.516129032258 / FREQUENCY_RATE), + float_to_fp16_16(532.813008130081 / FREQUENCY_RATE), + float_to_fp16_16(537.180327868852 / FREQUENCY_RATE), + float_to_fp16_16(541.619834710744 / FREQUENCY_RATE), + float_to_fp16_16(546.133333333333 / FREQUENCY_RATE), + float_to_fp16_16(550.72268907563 / FREQUENCY_RATE), + float_to_fp16_16(555.389830508475 / FREQUENCY_RATE), + float_to_fp16_16(560.136752136752 / FREQUENCY_RATE), + float_to_fp16_16(564.965517241379 / FREQUENCY_RATE), + float_to_fp16_16(569.878260869565 / FREQUENCY_RATE), + float_to_fp16_16(574.877192982456 / FREQUENCY_RATE), + float_to_fp16_16(579.964601769912 / FREQUENCY_RATE), + float_to_fp16_16(585.142857142857 / FREQUENCY_RATE), + float_to_fp16_16(590.414414414414 / FREQUENCY_RATE), + float_to_fp16_16(595.781818181818 / FREQUENCY_RATE), + float_to_fp16_16(601.247706422018 / FREQUENCY_RATE), + float_to_fp16_16(606.814814814815 / FREQUENCY_RATE), + float_to_fp16_16(612.485981308411 / FREQUENCY_RATE), + float_to_fp16_16(618.264150943396 / FREQUENCY_RATE), + float_to_fp16_16(624.152380952381 / FREQUENCY_RATE), + float_to_fp16_16(630.153846153846 / FREQUENCY_RATE), + float_to_fp16_16(636.271844660194 / FREQUENCY_RATE), + float_to_fp16_16(642.509803921569 / FREQUENCY_RATE), + float_to_fp16_16(648.871287128713 / FREQUENCY_RATE), + float_to_fp16_16(655.36 / FREQUENCY_RATE), + float_to_fp16_16(661.979797979798 / FREQUENCY_RATE), + float_to_fp16_16(668.734693877551 / FREQUENCY_RATE), + float_to_fp16_16(675.628865979381 / FREQUENCY_RATE), + float_to_fp16_16(682.666666666667 / FREQUENCY_RATE), + float_to_fp16_16(689.852631578947 / FREQUENCY_RATE), + float_to_fp16_16(697.191489361702 / FREQUENCY_RATE), + float_to_fp16_16(704.688172043011 / FREQUENCY_RATE), + float_to_fp16_16(712.347826086956 / FREQUENCY_RATE), + float_to_fp16_16(720.175824175824 / FREQUENCY_RATE), + float_to_fp16_16(728.177777777778 / FREQUENCY_RATE), + float_to_fp16_16(736.359550561798 / FREQUENCY_RATE), + float_to_fp16_16(744.727272727273 / FREQUENCY_RATE), + float_to_fp16_16(753.287356321839 / FREQUENCY_RATE), + float_to_fp16_16(762.046511627907 / FREQUENCY_RATE), + float_to_fp16_16(771.011764705882 / FREQUENCY_RATE), + float_to_fp16_16(780.190476190476 / FREQUENCY_RATE), + float_to_fp16_16(789.590361445783 / FREQUENCY_RATE), + float_to_fp16_16(799.219512195122 / FREQUENCY_RATE), + float_to_fp16_16(809.086419753086 / FREQUENCY_RATE), + float_to_fp16_16(819.2 / FREQUENCY_RATE), + float_to_fp16_16(829.569620253165 / FREQUENCY_RATE), + float_to_fp16_16(840.205128205128 / FREQUENCY_RATE), + float_to_fp16_16(851.116883116883 / FREQUENCY_RATE), + float_to_fp16_16(862.315789473684 / FREQUENCY_RATE), + float_to_fp16_16(873.813333333333 / FREQUENCY_RATE), + float_to_fp16_16(885.621621621622 / FREQUENCY_RATE), + float_to_fp16_16(897.753424657534 / FREQUENCY_RATE), + float_to_fp16_16(910.222222222222 / FREQUENCY_RATE), + float_to_fp16_16(923.042253521127 / FREQUENCY_RATE), + float_to_fp16_16(936.228571428571 / FREQUENCY_RATE), + float_to_fp16_16(949.797101449275 / FREQUENCY_RATE), + float_to_fp16_16(963.764705882353 / FREQUENCY_RATE), + float_to_fp16_16(978.149253731343 / FREQUENCY_RATE), + float_to_fp16_16(992.969696969697 / FREQUENCY_RATE), + float_to_fp16_16(1008.24615384615 / FREQUENCY_RATE), + float_to_fp16_16(1024 / FREQUENCY_RATE), + float_to_fp16_16(1040.25396825397 / FREQUENCY_RATE), + float_to_fp16_16(1057.03225806452 / FREQUENCY_RATE), + float_to_fp16_16(1074.36065573771 / FREQUENCY_RATE), + float_to_fp16_16(1092.26666666667 / FREQUENCY_RATE), + float_to_fp16_16(1110.77966101695 / FREQUENCY_RATE), + float_to_fp16_16(1129.93103448276 / FREQUENCY_RATE), + float_to_fp16_16(1149.75438596491 / FREQUENCY_RATE), + float_to_fp16_16(1170.28571428571 / FREQUENCY_RATE), + float_to_fp16_16(1191.56363636364 / FREQUENCY_RATE), + float_to_fp16_16(1213.62962962963 / FREQUENCY_RATE), + float_to_fp16_16(1236.52830188679 / FREQUENCY_RATE), + float_to_fp16_16(1260.30769230769 / FREQUENCY_RATE), + float_to_fp16_16(1285.01960784314 / FREQUENCY_RATE), + float_to_fp16_16(1310.72 / FREQUENCY_RATE), + float_to_fp16_16(1337.4693877551 / FREQUENCY_RATE), + float_to_fp16_16(1365.33333333333 / FREQUENCY_RATE), + float_to_fp16_16(1394.3829787234 / FREQUENCY_RATE), + float_to_fp16_16(1424.69565217391 / FREQUENCY_RATE), + float_to_fp16_16(1456.35555555556 / FREQUENCY_RATE), + float_to_fp16_16(1489.45454545455 / FREQUENCY_RATE), + float_to_fp16_16(1524.09302325581 / FREQUENCY_RATE), + float_to_fp16_16(1560.38095238095 / FREQUENCY_RATE), + float_to_fp16_16(1598.43902439024 / FREQUENCY_RATE), + float_to_fp16_16(1638.4 / FREQUENCY_RATE), + float_to_fp16_16(1680.41025641026 / FREQUENCY_RATE), + float_to_fp16_16(1724.63157894737 / FREQUENCY_RATE), + float_to_fp16_16(1771.24324324324 / FREQUENCY_RATE), + float_to_fp16_16(1820.44444444444 / FREQUENCY_RATE), + float_to_fp16_16(1872.45714285714 / FREQUENCY_RATE), + float_to_fp16_16(1927.52941176471 / FREQUENCY_RATE), + float_to_fp16_16(1985.93939393939 / FREQUENCY_RATE), + float_to_fp16_16(2048 / FREQUENCY_RATE), + float_to_fp16_16(2114.06451612903 / FREQUENCY_RATE), + float_to_fp16_16(2184.53333333333 / FREQUENCY_RATE), + float_to_fp16_16(2259.86206896552 / FREQUENCY_RATE), + float_to_fp16_16(2340.57142857143 / FREQUENCY_RATE), + float_to_fp16_16(2427.25925925926 / FREQUENCY_RATE), + float_to_fp16_16(2520.61538461538 / FREQUENCY_RATE), + float_to_fp16_16(2621.44 / FREQUENCY_RATE), + float_to_fp16_16(2730.66666666667 / FREQUENCY_RATE), + float_to_fp16_16(2849.39130434783 / FREQUENCY_RATE), + float_to_fp16_16(2978.90909090909 / FREQUENCY_RATE), + float_to_fp16_16(3120.7619047619 / FREQUENCY_RATE), + float_to_fp16_16(3276.8 / FREQUENCY_RATE), + float_to_fp16_16(3449.26315789474 / FREQUENCY_RATE), + float_to_fp16_16(3640.88888888889 / FREQUENCY_RATE), + float_to_fp16_16(3855.05882352941 / FREQUENCY_RATE), + float_to_fp16_16(4096 / FREQUENCY_RATE), + float_to_fp16_16(4369.06666666667 / FREQUENCY_RATE), + float_to_fp16_16(4681.14285714286 / FREQUENCY_RATE), + float_to_fp16_16(5041.23076923077 / FREQUENCY_RATE), + float_to_fp16_16(5461.33333333333 / FREQUENCY_RATE), + float_to_fp16_16(5957.81818181818 / FREQUENCY_RATE), + float_to_fp16_16(6553.6 / FREQUENCY_RATE), + float_to_fp16_16(7281.77777777778 / FREQUENCY_RATE), + float_to_fp16_16(8192 / FREQUENCY_RATE), + float_to_fp16_16(9362.28571428571 / FREQUENCY_RATE), + float_to_fp16_16(10922.6666666667 / FREQUENCY_RATE), + float_to_fp16_16(13107.2 / FREQUENCY_RATE), + float_to_fp16_16(16384 / FREQUENCY_RATE), + float_to_fp16_16(21845.3333333333 / FREQUENCY_RATE), + float_to_fp16_16(32768 / FREQUENCY_RATE), + float_to_fp16_16(65536 / FREQUENCY_RATE), +}; -const float freqTableNSE[256] = { - 524288, 262144, 131072, 87381.3333333333, 65536, 52428.8, 43690.6666666667, 37449.1428571429, - 524288, 262144, 131072, 87381.3333333333, 65536, 52428.8, 43690.6666666667, 37449.1428571429, - 262144, 131072, 65536, 43690.6666666667, 32768, 26214.4, 21845.3333333333, 18724.5714285714, - 262144, 131072, 65536, 43690.6666666667, 32768, 26214.4, 21845.3333333333, 18724.5714285714, - 131072, 65536, 32768, 21845.3333333333, 16384, 13107.2, 10922.6666666667, 9362.28571428571, - 131072, 65536, 32768, 21845.3333333333, 16384, 13107.2, 10922.6666666667, 9362.28571428571, - 65536, 32768, 16384, 10922.6666666667, 8192, 6553.6, 5461.33333333333, 4681.14285714286, - 65536, 32768, 16384, 10922.6666666667, 8192, 6553.6, 5461.33333333333, 4681.14285714286, - 32768, 16384, 8192, 5461.33333333333, 4096, 3276.8, 2730.66666666667, 2340.57142857143, - 32768, 16384, 8192, 5461.33333333333, 4096, 3276.8, 2730.66666666667, 2340.57142857143, - 16384, 8192, 4096, 2730.66666666667, 2048, 1638.4, 1365.33333333333, 1170.28571428571, - 16384, 8192, 4096, 2730.66666666667, 2048, 1638.4, 1365.33333333333, 1170.28571428571, - 8192, 4096, 2048, 1365.33333333333, 1024, 819.2, 682.666666666667, 585.142857142857, - 8192, 4096, 2048, 1365.33333333333, 1024, 819.2, 682.666666666667, 585.142857142857, - 4096, 2048, 1024, 682.666666666667, 512, 409.6, 341.333333333333, 292.571428571429, - 4096, 2048, 1024, 682.666666666667, 512, 409.6, 341.333333333333, 292.571428571429, - 2048, 1024, 512, 341.333333333333, 256, 204.8, 170.666666666667, 146.285714285714, - 2048, 1024, 512, 341.333333333333, 256, 204.8, 170.666666666667, 146.285714285714, - 1024, 512, 256, 170.666666666667, 128, 102.4, 85.3333333333333, 73.1428571428571, - 1024, 512, 256, 170.666666666667, 128, 102.4, 85.3333333333333, 73.1428571428571, - 512, 256, 128, 85.3333333333333, 64, 51.2, 42.6666666666667, 36.5714285714286, - 512, 256, 128, 85.3333333333333, 64, 51.2, 42.6666666666667, 36.5714285714286, - 256, 128, 64, 42.6666666666667, 32, 25.6, 21.3333333333333, 18.2857142857143, - 256, 128, 64, 42.6666666666667, 32, 25.6, 21.3333333333333, 18.2857142857143, - 128, 64, 32, 21.3333333333333, 16, 12.8, 10.6666666666667, 9.14285714285714, - 128, 64, 32, 21.3333333333333, 16, 12.8, 10.6666666666667, 9.14285714285714, - 64, 32, 16, 10.6666666666667, 8, 6.4, 5.33333333333333, 4.57142857142857, - 64, 32, 16, 10.6666666666667, 8, 6.4, 5.33333333333333, 4.57142857142857, - 32, 16, 8, 5.33333333333333, 4, 3.2, 2.66666666666667, 2.28571428571429, - 32, 16, 8, 5.33333333333333, 4, 3.2, 2.66666666666667, 2.28571428571429, - 16, 8, 4, 2.66666666666667, 2, 1.6, 1.33333333333333, 1.14285714285714, - 16, 8, 4, 2.66666666666667, 2, 1.6, 1.33333333333333, 1.14285714285714, +const fixed16_16 freqTableNSE[256] = { + float_to_fp16_16(524288 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(52428.8 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), + float_to_fp16_16(524288 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(52428.8 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(26214.4 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(26214.4 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(13107.2 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(13107.2 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(6553.6 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(6553.6 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(3276.8 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(3276.8 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1638.4 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1638.4 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(819.2 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(585.142857142857 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(819.2 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(585.142857142857 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(409.6 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(292.571428571429 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(409.6 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(292.571428571429 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(204.8 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(146.285714285714 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(204.8 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(146.285714285714 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(102.4 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(102.4 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(51.2 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(51.2 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(25.6 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(25.6 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(12.8 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(12.8 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(6.4 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(6.4 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(3.2 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(3.2 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2 / SAMPLE_RATE), + float_to_fp16_16(1.6 / SAMPLE_RATE), + float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2 / SAMPLE_RATE), + float_to_fp16_16(1.6 / SAMPLE_RATE), + float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), }; #endif diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 787a65f43b..654d951477 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -3,14 +3,14 @@ #include "platform/shared/audio/cgb_tables.h" static struct AudioCGB gb; -static float soundChannelPos[4]; -static const s16 *PU1Table; -static const s16 *PU2Table; +static fixed16_16 soundChannelPos[4]; +static const int16_t *PU1Table; +static const int16_t *PU2Table; static u32 apuFrame; static u8 apuCycle; static u32 sampleRate; static u16 lfsrMax[2]; -float ch4Samples; +fixed16_16 ch4Samples; void cgb_audio_init(u32 rate) { @@ -101,6 +101,8 @@ void cgb_trigger_note(u8 channel) } } +#include + void cgb_audio_generate(u16 samplesPerFrame) { float *outBuffer = gb.outBuffer; @@ -193,39 +195,39 @@ void cgb_audio_generate(u16 samplesPerFrame) } } // Sound generation loop - soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF] / (sampleRate / 32); - soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF] / (sampleRate / 32); - soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF] / (sampleRate / 32); - while (soundChannelPos[0] >= 32) - soundChannelPos[0] -= 32; - while (soundChannelPos[1] >= 32) - soundChannelPos[1] -= 32; - while (soundChannelPos[2] >= 32) - soundChannelPos[2] -= 32; + soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF]; + soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF]; + soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF]; + while (soundChannelPos[0] >= u32_to_fp16_16(32)) + soundChannelPos[0] -= u32_to_fp16_16(32); + while (soundChannelPos[1] >= u32_to_fp16_16(32)) + soundChannelPos[1] -= u32_to_fp16_16(32); + while (soundChannelPos[2] >= u32_to_fp16_16(32)) + soundChannelPos[2] -= u32_to_fp16_16(32); float outputL = 0; float outputR = 0; if (REG_NR52 & 0x80) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if (REG_NR51 & 0x10) - outputL += gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])] / 15.0f; + outputL += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])] / 15.0f); if (REG_NR51 & 0x01) - outputR += gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])] / 15.0f; + outputR += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])] / 15.0f); } if ((gb.DAC[1]) && (REG_NR52 & 0x02)) { if (REG_NR51 & 0x20) - outputL += gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])] / 15.0f; + outputL += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])] / 15.0f); if (REG_NR51 & 0x02) - outputR += gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])] / 15.0f; + outputR += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])] / 15.0f); } if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) { if (REG_NR51 & 0x40) - outputL += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f; + outputL += gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] / 4.0f; if (REG_NR51 & 0x04) - outputR += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f; + outputR += gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] / 4.0f; } if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); - ch4Samples += freqTableNSE[REG_SOUND4CNT_H & 0xFF] / sampleRate; + ch4Samples += freqTableNSE[REG_SOUND4CNT_H & 0xFF]; int ch4Out = 0; if (gb.ch4LFSR[lfsrMode] & 1) { ch4Out++; @@ -233,7 +235,7 @@ void cgb_audio_generate(u16 samplesPerFrame) ch4Out--; } int avgDiv = 1; - while (ch4Samples >= 1) { + while (ch4Samples >= u32_to_fp16_16(1)) { avgDiv++; bool8 lfsrCarry = 0; if (gb.ch4LFSR[lfsrMode] & 2) @@ -248,15 +250,15 @@ void cgb_audio_generate(u16 samplesPerFrame) } else { ch4Out--; } - ch4Samples--; + ch4Samples -= u32_to_fp16_16(1); } - float sample = ch4Out; + fixed16_16 sample = float_to_fp16_16(ch4Out); if (avgDiv > 1) sample /= avgDiv; if (REG_NR51 & 0x80) - outputL += gb.Vol[3] * sample / 15.0f; + outputL += fp16_16_to_float(gb.Vol[3] * sample / 15); if (REG_NR51 & 0x08) - outputR += gb.Vol[3] * sample / 15.0f; + outputR += fp16_16_to_float(gb.Vol[3] * sample / 15); } } outBuffer[0] = outputL * 0.25f; From 1cd03df41fa58125c588eee43bd688f2fe9f2bc5 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Fri, 20 Feb 2026 21:53:03 +0000 Subject: [PATCH 16/51] fixes --- include/platform/shared/audio/cgb_tables.h | 86 ++++++++++------------ src/platform/shared/audio/cgb_audio.c | 12 +-- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/include/platform/shared/audio/cgb_tables.h b/include/platform/shared/audio/cgb_tables.h index 53278d27b3..202807cf50 100644 --- a/include/platform/shared/audio/cgb_tables.h +++ b/include/platform/shared/audio/cgb_tables.h @@ -3,58 +3,48 @@ #include "platform/shared/audio/cgb_audio.h" -#define SAMPLE_RATE 48000 -#define FREQUENCY_RATE (SAMPLE_RATE / 32) +#define SAMPLE_RATE 48000.0 +#define FREQUENCY_RATE (SAMPLE_RATE / 32.0) -// const fixed16_16 PU0[32] -// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed16_16 PU0[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; -// const fixed16_16 PU1[32] -// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed16_16 PU1[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; -// const fixed16_16 PU2[32] -// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed16_16 PU2[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; -// const fixed16_16 PU3[32] -// = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), -// float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; - -const int16_t PU0[32] - = { 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - -const int16_t PU1[32] - = { 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - -const int16_t PU2[32] = { 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1 }; - -const int16_t PU3[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; +const fixed16_16 PU3[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; int16_t WAV[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 654d951477..20599b2eb4 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -4,8 +4,8 @@ static struct AudioCGB gb; static fixed16_16 soundChannelPos[4]; -static const int16_t *PU1Table; -static const int16_t *PU2Table; +static const fixed16_16 *PU1Table; +static const fixed16_16 *PU2Table; static u32 apuFrame; static u8 apuCycle; static u32 sampleRate; @@ -209,15 +209,15 @@ void cgb_audio_generate(u16 samplesPerFrame) if (REG_NR52 & 0x80) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if (REG_NR51 & 0x10) - outputL += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])] / 15.0f); + outputL += fp16_16_to_float(gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); if (REG_NR51 & 0x01) - outputR += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])] / 15.0f); + outputR += fp16_16_to_float(gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); } if ((gb.DAC[1]) && (REG_NR52 & 0x02)) { if (REG_NR51 & 0x20) - outputL += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])] / 15.0f); + outputL += fp16_16_to_float(gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); if (REG_NR51 & 0x02) - outputR += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])] / 15.0f); + outputR += fp16_16_to_float(gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); } if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) { if (REG_NR51 & 0x40) From caa9d52582afcb56f04d44efe22702e03543ae96 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Fri, 20 Feb 2026 23:27:59 +0000 Subject: [PATCH 17/51] reverse some audio changes, leave in precacled division --- include/gba/types.h | 4 +- include/lib/m4a/m4a_internal.h | 27 + include/platform/shared/audio/cgb_audio.h | 27 - include/platform/shared/audio/cgb_tables.h | 4664 ++++++++++---------- src/game/stage/camera.c | 4 + src/platform/ps2/ps2.c | 2 +- src/platform/shared/audio/cgb_audio.c | 42 +- 7 files changed, 2377 insertions(+), 2393 deletions(-) diff --git a/include/gba/types.h b/include/gba/types.h index 419e1fdda4..d22c4a6848 100644 --- a/include/gba/types.h +++ b/include/gba/types.h @@ -42,12 +42,12 @@ typedef u16 MetatileIndexType; // If the DISPLAY_HEIGHT was >255, scanline effects would break, // so we have to make this variable bigger. // (u16 should be plenty for screen coordinates, right?) -#if !defined(WIDESCREEN_HACK) +#if !defined(WIDESCREEN_HACK) && !PLATFORM_GBA #error WIDESCREEN_HACK not defined. #endif /// TODO: Technically this should only be #if (DISPLAY_HEIGHT > 255), // we should probably replace uses of int_vcount with a different type where a high DISPLAY_WIDTH necessitates u16. -#if WIDESCREEN_HACK +#if !PLATFORM_GBA && WIDESCREEN_HACK typedef u16 int_vcount; #else typedef u8 int_vcount; diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 0ae01ef882..737e25127d 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -106,6 +106,33 @@ #define MAX_LINES 0 #endif +typedef s32 fixed16_16; +typedef s32 fixed8_24; + +#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) + +#define fp16_16_to_float(value) (float)((value) / 65536.0) + +#define u32_to_fp16_16(value) ((value) << 16) + +#define fp16_16_to_u32(value) ((value) >> 16) + +#define fp16_16_fractional_part(value) ((value)&0xFFFF) + +#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) + +#define fp8_24_to_float(value) (float)((value) / 16777216.0) + +#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) + +#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) + +#define address8(base, offset) *((u8 *)((u8 *)base + (offset))) + +#define address16(base, offset) *((u16 *)((u8 *)base + (offset))) + +#define address32(base, offset) *((u32 *)((u8 *)base + (offset))) + struct MP2KTrack; struct MP2KPlayerState; diff --git a/include/platform/shared/audio/cgb_audio.h b/include/platform/shared/audio/cgb_audio.h index 39995f00d1..65dd77a91e 100644 --- a/include/platform/shared/audio/cgb_audio.h +++ b/include/platform/shared/audio/cgb_audio.h @@ -3,33 +3,6 @@ #include "lib/m4a/m4a_internal.h" -typedef s32 fixed16_16; -typedef s32 fixed8_24; - -#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) - -#define fp16_16_to_float(value) (float)((value) / 65536.0) - -#define u32_to_fp16_16(value) ((value) << 16) - -#define fp16_16_to_u32(value) ((value) >> 16) - -#define fp16_16_fractional_part(value) ((value)&0xFFFF) - -#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) - -#define fp8_24_to_float(value) (float)((value) / 16777216.0) - -#define fp8_24_fractional_part(value) ((value)&0xFFFFFF) - -#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) - -#define address8(base, offset) *((u8 *)((u8 *)base + (offset))) - -#define address16(base, offset) *((u16 *)((u8 *)base + (offset))) - -#define address32(base, offset) *((u32 *)((u8 *)base + (offset))) - struct AudioCGB { u16 ch1Freq; u8 ch1SweepCounter; diff --git a/include/platform/shared/audio/cgb_tables.h b/include/platform/shared/audio/cgb_tables.h index 202807cf50..e6c5c683f9 100644 --- a/include/platform/shared/audio/cgb_tables.h +++ b/include/platform/shared/audio/cgb_tables.h @@ -6,2356 +6,2336 @@ #define SAMPLE_RATE 48000.0 #define FREQUENCY_RATE (SAMPLE_RATE / 32.0) -const fixed16_16 PU0[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const float PU0[32] = { (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; -const fixed16_16 PU1[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const float PU1[32] = { (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; -const fixed16_16 PU2[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const float PU2[32] = { (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), + (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), + (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; -const fixed16_16 PU3[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const float PU3[32] = { (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), + (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), + (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), + (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; int16_t WAV[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; -const fixed16_16 freqTable[2048] = { - float_to_fp16_16(32 / FREQUENCY_RATE), - float_to_fp16_16(32.0156326331216 / FREQUENCY_RATE), - float_to_fp16_16(32.0312805474096 / FREQUENCY_RATE), - float_to_fp16_16(32.0469437652812 / FREQUENCY_RATE), - float_to_fp16_16(32.0626223091976 / FREQUENCY_RATE), - float_to_fp16_16(32.0783162016642 / FREQUENCY_RATE), - float_to_fp16_16(32.0940254652302 / FREQUENCY_RATE), - float_to_fp16_16(32.109750122489 / FREQUENCY_RATE), - float_to_fp16_16(32.1254901960784 / FREQUENCY_RATE), - float_to_fp16_16(32.1412457086807 / FREQUENCY_RATE), - float_to_fp16_16(32.1570166830226 / FREQUENCY_RATE), - float_to_fp16_16(32.1728031418753 / FREQUENCY_RATE), - float_to_fp16_16(32.188605108055 / FREQUENCY_RATE), - float_to_fp16_16(32.2044226044226 / FREQUENCY_RATE), - float_to_fp16_16(32.220255653884 / FREQUENCY_RATE), - float_to_fp16_16(32.2361042793901 / FREQUENCY_RATE), - float_to_fp16_16(32.251968503937 / FREQUENCY_RATE), - float_to_fp16_16(32.2678483505662 / FREQUENCY_RATE), - float_to_fp16_16(32.2837438423645 / FREQUENCY_RATE), - float_to_fp16_16(32.2996550024643 / FREQUENCY_RATE), - float_to_fp16_16(32.3155818540434 / FREQUENCY_RATE), - float_to_fp16_16(32.3315244203256 / FREQUENCY_RATE), - float_to_fp16_16(32.3474827245805 / FREQUENCY_RATE), - float_to_fp16_16(32.3634567901235 / FREQUENCY_RATE), - float_to_fp16_16(32.3794466403162 / FREQUENCY_RATE), - float_to_fp16_16(32.3954522985665 / FREQUENCY_RATE), - float_to_fp16_16(32.4114737883284 / FREQUENCY_RATE), - float_to_fp16_16(32.4275111331024 / FREQUENCY_RATE), - float_to_fp16_16(32.4435643564356 / FREQUENCY_RATE), - float_to_fp16_16(32.4596334819217 / FREQUENCY_RATE), - float_to_fp16_16(32.4757185332012 / FREQUENCY_RATE), - float_to_fp16_16(32.4918195339613 / FREQUENCY_RATE), - float_to_fp16_16(32.5079365079365 / FREQUENCY_RATE), - float_to_fp16_16(32.5240694789082 / FREQUENCY_RATE), - float_to_fp16_16(32.5402184707051 / FREQUENCY_RATE), - float_to_fp16_16(32.5563835072032 / FREQUENCY_RATE), - float_to_fp16_16(32.572564612326 / FREQUENCY_RATE), - float_to_fp16_16(32.5887618100448 / FREQUENCY_RATE), - float_to_fp16_16(32.6049751243781 / FREQUENCY_RATE), - float_to_fp16_16(32.6212045793927 / FREQUENCY_RATE), - float_to_fp16_16(32.6374501992032 / FREQUENCY_RATE), - float_to_fp16_16(32.6537120079721 / FREQUENCY_RATE), - float_to_fp16_16(32.6699900299103 / FREQUENCY_RATE), - float_to_fp16_16(32.6862842892768 / FREQUENCY_RATE), - float_to_fp16_16(32.7025948103792 / FREQUENCY_RATE), - float_to_fp16_16(32.7189216175736 / FREQUENCY_RATE), - float_to_fp16_16(32.7352647352647 / FREQUENCY_RATE), - float_to_fp16_16(32.751624187906 / FREQUENCY_RATE), - float_to_fp16_16(32.768 / FREQUENCY_RATE), - float_to_fp16_16(32.784392196098 / FREQUENCY_RATE), - float_to_fp16_16(32.8008008008008 / FREQUENCY_RATE), - float_to_fp16_16(32.8172258387581 / FREQUENCY_RATE), - float_to_fp16_16(32.8336673346693 / FREQUENCY_RATE), - float_to_fp16_16(32.8501253132832 / FREQUENCY_RATE), - float_to_fp16_16(32.8665997993982 / FREQUENCY_RATE), - float_to_fp16_16(32.8830908178625 / FREQUENCY_RATE), - float_to_fp16_16(32.8995983935743 / FREQUENCY_RATE), - float_to_fp16_16(32.9161225514817 / FREQUENCY_RATE), - float_to_fp16_16(32.9326633165829 / FREQUENCY_RATE), - float_to_fp16_16(32.9492207139266 / FREQUENCY_RATE), - float_to_fp16_16(32.9657947686117 / FREQUENCY_RATE), - float_to_fp16_16(32.9823855057876 / FREQUENCY_RATE), - float_to_fp16_16(32.9989929506546 / FREQUENCY_RATE), - float_to_fp16_16(33.0156171284635 / FREQUENCY_RATE), - float_to_fp16_16(33.0322580645161 / FREQUENCY_RATE), - float_to_fp16_16(33.0489157841654 / FREQUENCY_RATE), - float_to_fp16_16(33.0655903128153 / FREQUENCY_RATE), - float_to_fp16_16(33.0822816759213 / FREQUENCY_RATE), - float_to_fp16_16(33.0989898989899 / FREQUENCY_RATE), - float_to_fp16_16(33.1157150075796 / FREQUENCY_RATE), - float_to_fp16_16(33.1324570273003 / FREQUENCY_RATE), - float_to_fp16_16(33.1492159838139 / FREQUENCY_RATE), - float_to_fp16_16(33.165991902834 / FREQUENCY_RATE), - float_to_fp16_16(33.1827848101266 / FREQUENCY_RATE), - float_to_fp16_16(33.1995947315096 / FREQUENCY_RATE), - float_to_fp16_16(33.2164216928535 / FREQUENCY_RATE), - float_to_fp16_16(33.2332657200811 / FREQUENCY_RATE), - float_to_fp16_16(33.2501268391679 / FREQUENCY_RATE), - float_to_fp16_16(33.2670050761421 / FREQUENCY_RATE), - float_to_fp16_16(33.2839004570848 / FREQUENCY_RATE), - float_to_fp16_16(33.3008130081301 / FREQUENCY_RATE), - float_to_fp16_16(33.3177427554652 / FREQUENCY_RATE), - float_to_fp16_16(33.3346897253306 / FREQUENCY_RATE), - float_to_fp16_16(33.3516539440204 / FREQUENCY_RATE), - float_to_fp16_16(33.3686354378819 / FREQUENCY_RATE), - float_to_fp16_16(33.3856342333164 / FREQUENCY_RATE), - float_to_fp16_16(33.4026503567788 / FREQUENCY_RATE), - float_to_fp16_16(33.4196838347782 / FREQUENCY_RATE), - float_to_fp16_16(33.4367346938776 / FREQUENCY_RATE), - float_to_fp16_16(33.4538029606942 / FREQUENCY_RATE), - float_to_fp16_16(33.4708886618999 / FREQUENCY_RATE), - float_to_fp16_16(33.4879918242207 / FREQUENCY_RATE), - float_to_fp16_16(33.5051124744376 / FREQUENCY_RATE), - float_to_fp16_16(33.5222506393862 / FREQUENCY_RATE), - float_to_fp16_16(33.539406345957 / FREQUENCY_RATE), - float_to_fp16_16(33.5565796210957 / FREQUENCY_RATE), - float_to_fp16_16(33.5737704918033 / FREQUENCY_RATE), - float_to_fp16_16(33.5909789851358 / FREQUENCY_RATE), - float_to_fp16_16(33.6082051282051 / FREQUENCY_RATE), - float_to_fp16_16(33.6254489481786 / FREQUENCY_RATE), - float_to_fp16_16(33.6427104722793 / FREQUENCY_RATE), - float_to_fp16_16(33.6599897277863 / FREQUENCY_RATE), - float_to_fp16_16(33.6772867420349 / FREQUENCY_RATE), - float_to_fp16_16(33.6946015424164 / FREQUENCY_RATE), - float_to_fp16_16(33.7119341563786 / FREQUENCY_RATE), - float_to_fp16_16(33.7292846114256 / FREQUENCY_RATE), - float_to_fp16_16(33.7466529351184 / FREQUENCY_RATE), - float_to_fp16_16(33.7640391550747 / FREQUENCY_RATE), - float_to_fp16_16(33.7814432989691 / FREQUENCY_RATE), - float_to_fp16_16(33.7988653945333 / FREQUENCY_RATE), - float_to_fp16_16(33.8163054695562 / FREQUENCY_RATE), - float_to_fp16_16(33.8337635518844 / FREQUENCY_RATE), - float_to_fp16_16(33.8512396694215 / FREQUENCY_RATE), - float_to_fp16_16(33.8687338501292 / FREQUENCY_RATE), - float_to_fp16_16(33.8862461220269 / FREQUENCY_RATE), - float_to_fp16_16(33.9037765131919 / FREQUENCY_RATE), - float_to_fp16_16(33.9213250517598 / FREQUENCY_RATE), - float_to_fp16_16(33.9388917659244 / FREQUENCY_RATE), - float_to_fp16_16(33.9564766839378 / FREQUENCY_RATE), - float_to_fp16_16(33.9740798341109 / FREQUENCY_RATE), - float_to_fp16_16(33.9917012448133 / FREQUENCY_RATE), - float_to_fp16_16(34.0093409444733 / FREQUENCY_RATE), - float_to_fp16_16(34.0269989615784 / FREQUENCY_RATE), - float_to_fp16_16(34.0446753246753 / FREQUENCY_RATE), - float_to_fp16_16(34.0623700623701 / FREQUENCY_RATE), - float_to_fp16_16(34.0800832033281 / FREQUENCY_RATE), - float_to_fp16_16(34.0978147762747 / FREQUENCY_RATE), - float_to_fp16_16(34.1155648099948 / FREQUENCY_RATE), - float_to_fp16_16(34.1333333333333 / FREQUENCY_RATE), - float_to_fp16_16(34.1511203751954 / FREQUENCY_RATE), - float_to_fp16_16(34.1689259645464 / FREQUENCY_RATE), - float_to_fp16_16(34.1867501304121 / FREQUENCY_RATE), - float_to_fp16_16(34.2045929018789 / FREQUENCY_RATE), - float_to_fp16_16(34.222454308094 / FREQUENCY_RATE), - float_to_fp16_16(34.2403343782654 / FREQUENCY_RATE), - float_to_fp16_16(34.2582331416623 / FREQUENCY_RATE), - float_to_fp16_16(34.2761506276151 / FREQUENCY_RATE), - float_to_fp16_16(34.2940868655154 / FREQUENCY_RATE), - float_to_fp16_16(34.3120418848168 / FREQUENCY_RATE), - float_to_fp16_16(34.330015715034 / FREQUENCY_RATE), - float_to_fp16_16(34.3480083857442 / FREQUENCY_RATE), - float_to_fp16_16(34.3660199265863 / FREQUENCY_RATE), - float_to_fp16_16(34.3840503672613 / FREQUENCY_RATE), - float_to_fp16_16(34.4020997375328 / FREQUENCY_RATE), - float_to_fp16_16(34.4201680672269 / FREQUENCY_RATE), - float_to_fp16_16(34.4382553862323 / FREQUENCY_RATE), - float_to_fp16_16(34.4563617245005 / FREQUENCY_RATE), - float_to_fp16_16(34.4744871120463 / FREQUENCY_RATE), - float_to_fp16_16(34.4926315789474 / FREQUENCY_RATE), - float_to_fp16_16(34.5107951553449 / FREQUENCY_RATE), - float_to_fp16_16(34.5289778714436 / FREQUENCY_RATE), - float_to_fp16_16(34.5471797575119 / FREQUENCY_RATE), - float_to_fp16_16(34.5654008438819 / FREQUENCY_RATE), - float_to_fp16_16(34.5836411609499 / FREQUENCY_RATE), - float_to_fp16_16(34.6019007391763 / FREQUENCY_RATE), - float_to_fp16_16(34.6201796090861 / FREQUENCY_RATE), - float_to_fp16_16(34.6384778012685 / FREQUENCY_RATE), - float_to_fp16_16(34.6567953463776 / FREQUENCY_RATE), - float_to_fp16_16(34.6751322751323 / FREQUENCY_RATE), - float_to_fp16_16(34.6934886183166 / FREQUENCY_RATE), - float_to_fp16_16(34.7118644067797 / FREQUENCY_RATE), - float_to_fp16_16(34.7302596714361 / FREQUENCY_RATE), - float_to_fp16_16(34.7486744432662 / FREQUENCY_RATE), - float_to_fp16_16(34.7671087533156 / FREQUENCY_RATE), - float_to_fp16_16(34.7855626326964 / FREQUENCY_RATE), - float_to_fp16_16(34.8040361125863 / FREQUENCY_RATE), - float_to_fp16_16(34.8225292242295 / FREQUENCY_RATE), - float_to_fp16_16(34.8410419989367 / FREQUENCY_RATE), - float_to_fp16_16(34.8595744680851 / FREQUENCY_RATE), - float_to_fp16_16(34.8781266631187 / FREQUENCY_RATE), - float_to_fp16_16(34.8966986155485 / FREQUENCY_RATE), - float_to_fp16_16(34.9152903569526 / FREQUENCY_RATE), - float_to_fp16_16(34.9339019189765 / FREQUENCY_RATE), - float_to_fp16_16(34.9525333333333 / FREQUENCY_RATE), - float_to_fp16_16(34.9711846318036 / FREQUENCY_RATE), - float_to_fp16_16(34.989855846236 / FREQUENCY_RATE), - float_to_fp16_16(35.008547008547 / FREQUENCY_RATE), - float_to_fp16_16(35.0272581507215 / FREQUENCY_RATE), - float_to_fp16_16(35.0459893048128 / FREQUENCY_RATE), - float_to_fp16_16(35.0647405029427 / FREQUENCY_RATE), - float_to_fp16_16(35.0835117773019 / FREQUENCY_RATE), - float_to_fp16_16(35.10230316015 / FREQUENCY_RATE), - float_to_fp16_16(35.1211146838156 / FREQUENCY_RATE), - float_to_fp16_16(35.1399463806971 / FREQUENCY_RATE), - float_to_fp16_16(35.1587982832618 / FREQUENCY_RATE), - float_to_fp16_16(35.1776704240472 / FREQUENCY_RATE), - float_to_fp16_16(35.1965628356606 / FREQUENCY_RATE), - float_to_fp16_16(35.2154755507792 / FREQUENCY_RATE), - float_to_fp16_16(35.2344086021505 / FREQUENCY_RATE), - float_to_fp16_16(35.2533620225928 / FREQUENCY_RATE), - float_to_fp16_16(35.2723358449946 / FREQUENCY_RATE), - float_to_fp16_16(35.2913301023156 / FREQUENCY_RATE), - float_to_fp16_16(35.3103448275862 / FREQUENCY_RATE), - float_to_fp16_16(35.3293800539084 / FREQUENCY_RATE), - float_to_fp16_16(35.3484358144552 / FREQUENCY_RATE), - float_to_fp16_16(35.3675121424717 / FREQUENCY_RATE), - float_to_fp16_16(35.3866090712743 / FREQUENCY_RATE), - float_to_fp16_16(35.4057266342518 / FREQUENCY_RATE), - float_to_fp16_16(35.4248648648649 / FREQUENCY_RATE), - float_to_fp16_16(35.4440237966468 / FREQUENCY_RATE), - float_to_fp16_16(35.4632034632035 / FREQUENCY_RATE), - float_to_fp16_16(35.4824038982133 / FREQUENCY_RATE), - float_to_fp16_16(35.501625135428 / FREQUENCY_RATE), - float_to_fp16_16(35.5208672086721 / FREQUENCY_RATE), - float_to_fp16_16(35.5401301518438 / FREQUENCY_RATE), - float_to_fp16_16(35.5594139989148 / FREQUENCY_RATE), - float_to_fp16_16(35.5787187839305 / FREQUENCY_RATE), - float_to_fp16_16(35.5980445410103 / FREQUENCY_RATE), - float_to_fp16_16(35.6173913043478 / FREQUENCY_RATE), - float_to_fp16_16(35.636759108211 / FREQUENCY_RATE), - float_to_fp16_16(35.6561479869423 / FREQUENCY_RATE), - float_to_fp16_16(35.6755579749592 / FREQUENCY_RATE), - float_to_fp16_16(35.6949891067538 / FREQUENCY_RATE), - float_to_fp16_16(35.7144414168937 / FREQUENCY_RATE), - float_to_fp16_16(35.7339149400218 / FREQUENCY_RATE), - float_to_fp16_16(35.7534097108565 / FREQUENCY_RATE), - float_to_fp16_16(35.7729257641921 / FREQUENCY_RATE), - float_to_fp16_16(35.792463134899 / FREQUENCY_RATE), - float_to_fp16_16(35.8120218579235 / FREQUENCY_RATE), - float_to_fp16_16(35.8316019682887 / FREQUENCY_RATE), - float_to_fp16_16(35.8512035010941 / FREQUENCY_RATE), - float_to_fp16_16(35.8708264915161 / FREQUENCY_RATE), - float_to_fp16_16(35.8904709748083 / FREQUENCY_RATE), - float_to_fp16_16(35.9101369863014 / FREQUENCY_RATE), - float_to_fp16_16(35.9298245614035 / FREQUENCY_RATE), - float_to_fp16_16(35.9495337356007 / FREQUENCY_RATE), - float_to_fp16_16(35.9692645444566 / FREQUENCY_RATE), - float_to_fp16_16(35.9890170236134 / FREQUENCY_RATE), - float_to_fp16_16(36.0087912087912 / FREQUENCY_RATE), - float_to_fp16_16(36.0285871357889 / FREQUENCY_RATE), - float_to_fp16_16(36.048404840484 / FREQUENCY_RATE), - float_to_fp16_16(36.0682443588332 / FREQUENCY_RATE), - float_to_fp16_16(36.0881057268722 / FREQUENCY_RATE), - float_to_fp16_16(36.1079889807162 / FREQUENCY_RATE), - float_to_fp16_16(36.1278941565601 / FREQUENCY_RATE), - float_to_fp16_16(36.1478212906784 / FREQUENCY_RATE), - float_to_fp16_16(36.167770419426 / FREQUENCY_RATE), - float_to_fp16_16(36.187741579238 / FREQUENCY_RATE), - float_to_fp16_16(36.2077348066298 / FREQUENCY_RATE), - float_to_fp16_16(36.2277501381979 / FREQUENCY_RATE), - float_to_fp16_16(36.2477876106195 / FREQUENCY_RATE), - float_to_fp16_16(36.267847260653 / FREQUENCY_RATE), - float_to_fp16_16(36.2879291251384 / FREQUENCY_RATE), - float_to_fp16_16(36.3080332409972 / FREQUENCY_RATE), - float_to_fp16_16(36.3281596452328 / FREQUENCY_RATE), - float_to_fp16_16(36.3483083749307 / FREQUENCY_RATE), - float_to_fp16_16(36.3684794672586 / FREQUENCY_RATE), - float_to_fp16_16(36.388672959467 / FREQUENCY_RATE), - float_to_fp16_16(36.4088888888889 / FREQUENCY_RATE), - float_to_fp16_16(36.4291272929405 / FREQUENCY_RATE), - float_to_fp16_16(36.4493882091212 / FREQUENCY_RATE), - float_to_fp16_16(36.4696716750139 / FREQUENCY_RATE), - float_to_fp16_16(36.4899777282851 / FREQUENCY_RATE), - float_to_fp16_16(36.5103064066852 / FREQUENCY_RATE), - float_to_fp16_16(36.5306577480491 / FREQUENCY_RATE), - float_to_fp16_16(36.5510317902956 / FREQUENCY_RATE), - float_to_fp16_16(36.5714285714286 / FREQUENCY_RATE), - float_to_fp16_16(36.5918481295366 / FREQUENCY_RATE), - float_to_fp16_16(36.6122905027933 / FREQUENCY_RATE), - float_to_fp16_16(36.6327557294578 / FREQUENCY_RATE), - float_to_fp16_16(36.6532438478747 / FREQUENCY_RATE), - float_to_fp16_16(36.6737548964745 / FREQUENCY_RATE), - float_to_fp16_16(36.6942889137738 / FREQUENCY_RATE), - float_to_fp16_16(36.7148459383753 / FREQUENCY_RATE), - float_to_fp16_16(36.7354260089686 / FREQUENCY_RATE), - float_to_fp16_16(36.7560291643298 / FREQUENCY_RATE), - float_to_fp16_16(36.7766554433221 / FREQUENCY_RATE), - float_to_fp16_16(36.7973048848961 / FREQUENCY_RATE), - float_to_fp16_16(36.8179775280899 / FREQUENCY_RATE), - float_to_fp16_16(36.8386734120292 / FREQUENCY_RATE), - float_to_fp16_16(36.859392575928 / FREQUENCY_RATE), - float_to_fp16_16(36.8801350590884 / FREQUENCY_RATE), - float_to_fp16_16(36.9009009009009 / FREQUENCY_RATE), - float_to_fp16_16(36.9216901408451 / FREQUENCY_RATE), - float_to_fp16_16(36.9425028184893 / FREQUENCY_RATE), - float_to_fp16_16(36.9633389734913 / FREQUENCY_RATE), - float_to_fp16_16(36.9841986455982 / FREQUENCY_RATE), - float_to_fp16_16(37.0050818746471 / FREQUENCY_RATE), - float_to_fp16_16(37.025988700565 / FREQUENCY_RATE), - float_to_fp16_16(37.0469191633691 / FREQUENCY_RATE), - float_to_fp16_16(37.0678733031674 / FREQUENCY_RATE), - float_to_fp16_16(37.0888511601585 / FREQUENCY_RATE), - float_to_fp16_16(37.1098527746319 / FREQUENCY_RATE), - float_to_fp16_16(37.1308781869688 / FREQUENCY_RATE), - float_to_fp16_16(37.1519274376417 / FREQUENCY_RATE), - float_to_fp16_16(37.173000567215 / FREQUENCY_RATE), - float_to_fp16_16(37.1940976163451 / FREQUENCY_RATE), - float_to_fp16_16(37.2152186257808 / FREQUENCY_RATE), - float_to_fp16_16(37.2363636363636 / FREQUENCY_RATE), - float_to_fp16_16(37.2575326890279 / FREQUENCY_RATE), - float_to_fp16_16(37.2787258248009 / FREQUENCY_RATE), - float_to_fp16_16(37.2999430848036 / FREQUENCY_RATE), - float_to_fp16_16(37.3211845102506 / FREQUENCY_RATE), - float_to_fp16_16(37.3424501424501 / FREQUENCY_RATE), - float_to_fp16_16(37.363740022805 / FREQUENCY_RATE), - float_to_fp16_16(37.3850541928123 / FREQUENCY_RATE), - float_to_fp16_16(37.4063926940639 / FREQUENCY_RATE), - float_to_fp16_16(37.4277555682467 / FREQUENCY_RATE), - float_to_fp16_16(37.4491428571429 / FREQUENCY_RATE), - float_to_fp16_16(37.4705546026301 / FREQUENCY_RATE), - float_to_fp16_16(37.4919908466819 / FREQUENCY_RATE), - float_to_fp16_16(37.5134516313681 / FREQUENCY_RATE), - float_to_fp16_16(37.5349369988545 / FREQUENCY_RATE), - float_to_fp16_16(37.556446991404 / FREQUENCY_RATE), - float_to_fp16_16(37.5779816513761 / FREQUENCY_RATE), - float_to_fp16_16(37.5995410212278 / FREQUENCY_RATE), - float_to_fp16_16(37.6211251435132 / FREQUENCY_RATE), - float_to_fp16_16(37.6427340608845 / FREQUENCY_RATE), - float_to_fp16_16(37.664367816092 / FREQUENCY_RATE), - float_to_fp16_16(37.6860264519839 / FREQUENCY_RATE), - float_to_fp16_16(37.7077100115075 / FREQUENCY_RATE), - float_to_fp16_16(37.7294185377087 / FREQUENCY_RATE), - float_to_fp16_16(37.7511520737327 / FREQUENCY_RATE), - float_to_fp16_16(37.7729106628242 / FREQUENCY_RATE), - float_to_fp16_16(37.7946943483276 / FREQUENCY_RATE), - float_to_fp16_16(37.8165031736872 / FREQUENCY_RATE), - float_to_fp16_16(37.838337182448 / FREQUENCY_RATE), - float_to_fp16_16(37.8601964182553 / FREQUENCY_RATE), - float_to_fp16_16(37.8820809248555 / FREQUENCY_RATE), - float_to_fp16_16(37.903990746096 / FREQUENCY_RATE), - float_to_fp16_16(37.9259259259259 / FREQUENCY_RATE), - float_to_fp16_16(37.9478865083961 / FREQUENCY_RATE), - float_to_fp16_16(37.9698725376593 / FREQUENCY_RATE), - float_to_fp16_16(37.991884057971 / FREQUENCY_RATE), - float_to_fp16_16(38.0139211136891 / FREQUENCY_RATE), - float_to_fp16_16(38.0359837492745 / FREQUENCY_RATE), - float_to_fp16_16(38.0580720092915 / FREQUENCY_RATE), - float_to_fp16_16(38.0801859384079 / FREQUENCY_RATE), - float_to_fp16_16(38.1023255813953 / FREQUENCY_RATE), - float_to_fp16_16(38.1244909831297 / FREQUENCY_RATE), - float_to_fp16_16(38.1466821885914 / FREQUENCY_RATE), - float_to_fp16_16(38.1688992428655 / FREQUENCY_RATE), - float_to_fp16_16(38.1911421911422 / FREQUENCY_RATE), - float_to_fp16_16(38.2134110787172 / FREQUENCY_RATE), - float_to_fp16_16(38.2357059509918 / FREQUENCY_RATE), - float_to_fp16_16(38.2580268534734 / FREQUENCY_RATE), - float_to_fp16_16(38.2803738317757 / FREQUENCY_RATE), - float_to_fp16_16(38.3027469316189 / FREQUENCY_RATE), - float_to_fp16_16(38.3251461988304 / FREQUENCY_RATE), - float_to_fp16_16(38.3475716793446 / FREQUENCY_RATE), - float_to_fp16_16(38.3700234192037 / FREQUENCY_RATE), - float_to_fp16_16(38.3925014645577 / FREQUENCY_RATE), - float_to_fp16_16(38.4150058616647 / FREQUENCY_RATE), - float_to_fp16_16(38.4375366568915 / FREQUENCY_RATE), - float_to_fp16_16(38.4600938967136 / FREQUENCY_RATE), - float_to_fp16_16(38.4826776277158 / FREQUENCY_RATE), - float_to_fp16_16(38.5052878965922 / FREQUENCY_RATE), - float_to_fp16_16(38.527924750147 / FREQUENCY_RATE), - float_to_fp16_16(38.5505882352941 / FREQUENCY_RATE), - float_to_fp16_16(38.5732783990583 / FREQUENCY_RATE), - float_to_fp16_16(38.5959952885748 / FREQUENCY_RATE), - float_to_fp16_16(38.6187389510902 / FREQUENCY_RATE), - float_to_fp16_16(38.6415094339623 / FREQUENCY_RATE), - float_to_fp16_16(38.6643067846608 / FREQUENCY_RATE), - float_to_fp16_16(38.6871310507674 / FREQUENCY_RATE), - float_to_fp16_16(38.7099822799764 / FREQUENCY_RATE), - float_to_fp16_16(38.7328605200946 / FREQUENCY_RATE), - float_to_fp16_16(38.755765819042 / FREQUENCY_RATE), - float_to_fp16_16(38.7786982248521 / FREQUENCY_RATE), - float_to_fp16_16(38.801657785672 / FREQUENCY_RATE), - float_to_fp16_16(38.824644549763 / FREQUENCY_RATE), - float_to_fp16_16(38.8476585655009 / FREQUENCY_RATE), - float_to_fp16_16(38.870699881376 / FREQUENCY_RATE), - float_to_fp16_16(38.8937685459941 / FREQUENCY_RATE), - float_to_fp16_16(38.916864608076 / FREQUENCY_RATE), - float_to_fp16_16(38.9399881164587 / FREQUENCY_RATE), - float_to_fp16_16(38.9631391200951 / FREQUENCY_RATE), - float_to_fp16_16(38.9863176680547 / FREQUENCY_RATE), - float_to_fp16_16(39.0095238095238 / FREQUENCY_RATE), - float_to_fp16_16(39.0327575938058 / FREQUENCY_RATE), - float_to_fp16_16(39.0560190703218 / FREQUENCY_RATE), - float_to_fp16_16(39.0793082886106 / FREQUENCY_RATE), - float_to_fp16_16(39.1026252983294 / FREQUENCY_RATE), - float_to_fp16_16(39.1259701492537 / FREQUENCY_RATE), - float_to_fp16_16(39.1493428912784 / FREQUENCY_RATE), - float_to_fp16_16(39.1727435744172 / FREQUENCY_RATE), - float_to_fp16_16(39.1961722488038 / FREQUENCY_RATE), - float_to_fp16_16(39.2196289646918 / FREQUENCY_RATE), - float_to_fp16_16(39.2431137724551 / FREQUENCY_RATE), - float_to_fp16_16(39.2666267225884 / FREQUENCY_RATE), - float_to_fp16_16(39.2901678657074 / FREQUENCY_RATE), - float_to_fp16_16(39.3137372525495 / FREQUENCY_RATE), - float_to_fp16_16(39.3373349339736 / FREQUENCY_RATE), - float_to_fp16_16(39.360960960961 / FREQUENCY_RATE), - float_to_fp16_16(39.3846153846154 / FREQUENCY_RATE), - float_to_fp16_16(39.4082982561636 / FREQUENCY_RATE), - float_to_fp16_16(39.4320096269555 / FREQUENCY_RATE), - float_to_fp16_16(39.4557495484648 / FREQUENCY_RATE), - float_to_fp16_16(39.4795180722892 / FREQUENCY_RATE), - float_to_fp16_16(39.5033152501507 / FREQUENCY_RATE), - float_to_fp16_16(39.5271411338963 / FREQUENCY_RATE), - float_to_fp16_16(39.5509957754979 / FREQUENCY_RATE), - float_to_fp16_16(39.5748792270531 / FREQUENCY_RATE), - float_to_fp16_16(39.5987915407855 / FREQUENCY_RATE), - float_to_fp16_16(39.6227327690447 / FREQUENCY_RATE), - float_to_fp16_16(39.6467029643073 / FREQUENCY_RATE), - float_to_fp16_16(39.6707021791768 / FREQUENCY_RATE), - float_to_fp16_16(39.694730466384 / FREQUENCY_RATE), - float_to_fp16_16(39.7187878787879 / FREQUENCY_RATE), - float_to_fp16_16(39.7428744693754 / FREQUENCY_RATE), - float_to_fp16_16(39.7669902912621 / FREQUENCY_RATE), - float_to_fp16_16(39.7911353976928 / FREQUENCY_RATE), - float_to_fp16_16(39.8153098420413 / FREQUENCY_RATE), - float_to_fp16_16(39.8395136778115 / FREQUENCY_RATE), - float_to_fp16_16(39.8637469586375 / FREQUENCY_RATE), - float_to_fp16_16(39.8880097382836 / FREQUENCY_RATE), - float_to_fp16_16(39.9123020706455 / FREQUENCY_RATE), - float_to_fp16_16(39.9366240097502 / FREQUENCY_RATE), - float_to_fp16_16(39.9609756097561 / FREQUENCY_RATE), - float_to_fp16_16(39.9853569249542 / FREQUENCY_RATE), - float_to_fp16_16(40.009768009768 / FREQUENCY_RATE), - float_to_fp16_16(40.0342089187538 / FREQUENCY_RATE), - float_to_fp16_16(40.0586797066015 / FREQUENCY_RATE), - float_to_fp16_16(40.0831804281346 / FREQUENCY_RATE), - float_to_fp16_16(40.1077111383109 / FREQUENCY_RATE), - float_to_fp16_16(40.1322718922229 / FREQUENCY_RATE), - float_to_fp16_16(40.156862745098 / FREQUENCY_RATE), - float_to_fp16_16(40.1814837522992 / FREQUENCY_RATE), - float_to_fp16_16(40.2061349693252 / FREQUENCY_RATE), - float_to_fp16_16(40.2308164518109 / FREQUENCY_RATE), - float_to_fp16_16(40.2555282555283 / FREQUENCY_RATE), - float_to_fp16_16(40.280270436386 / FREQUENCY_RATE), - float_to_fp16_16(40.3050430504305 / FREQUENCY_RATE), - float_to_fp16_16(40.3298461538462 / FREQUENCY_RATE), - float_to_fp16_16(40.3546798029557 / FREQUENCY_RATE), - float_to_fp16_16(40.3795440542206 / FREQUENCY_RATE), - float_to_fp16_16(40.4044389642417 / FREQUENCY_RATE), - float_to_fp16_16(40.4293645897594 / FREQUENCY_RATE), - float_to_fp16_16(40.4543209876543 / FREQUENCY_RATE), - float_to_fp16_16(40.4793082149475 / FREQUENCY_RATE), - float_to_fp16_16(40.504326328801 / FREQUENCY_RATE), - float_to_fp16_16(40.5293753865182 / FREQUENCY_RATE), - float_to_fp16_16(40.5544554455446 / FREQUENCY_RATE), - float_to_fp16_16(40.5795665634675 / FREQUENCY_RATE), - float_to_fp16_16(40.6047087980174 / FREQUENCY_RATE), - float_to_fp16_16(40.6298822070676 / FREQUENCY_RATE), - float_to_fp16_16(40.6550868486352 / FREQUENCY_RATE), - float_to_fp16_16(40.6803227808814 / FREQUENCY_RATE), - float_to_fp16_16(40.7055900621118 / FREQUENCY_RATE), - float_to_fp16_16(40.7308887507769 / FREQUENCY_RATE), - float_to_fp16_16(40.7562189054726 / FREQUENCY_RATE), - float_to_fp16_16(40.7815805849409 / FREQUENCY_RATE), - float_to_fp16_16(40.8069738480697 / FREQUENCY_RATE), - float_to_fp16_16(40.8323987538941 / FREQUENCY_RATE), - float_to_fp16_16(40.857855361596 / FREQUENCY_RATE), - float_to_fp16_16(40.8833437305053 / FREQUENCY_RATE), - float_to_fp16_16(40.9088639200999 / FREQUENCY_RATE), - float_to_fp16_16(40.9344159900062 / FREQUENCY_RATE), - float_to_fp16_16(40.96 / FREQUENCY_RATE), - float_to_fp16_16(40.9856160100063 / FREQUENCY_RATE), - float_to_fp16_16(41.0112640801001 / FREQUENCY_RATE), - float_to_fp16_16(41.0369442705072 / FREQUENCY_RATE), - float_to_fp16_16(41.062656641604 / FREQUENCY_RATE), - float_to_fp16_16(41.0884012539185 / FREQUENCY_RATE), - float_to_fp16_16(41.1141781681305 / FREQUENCY_RATE), - float_to_fp16_16(41.1399874450722 / FREQUENCY_RATE), - float_to_fp16_16(41.1658291457287 / FREQUENCY_RATE), - float_to_fp16_16(41.1917033312382 / FREQUENCY_RATE), - float_to_fp16_16(41.2176100628931 / FREQUENCY_RATE), - float_to_fp16_16(41.2435494021397 / FREQUENCY_RATE), - float_to_fp16_16(41.2695214105793 / FREQUENCY_RATE), - float_to_fp16_16(41.2955261499685 / FREQUENCY_RATE), - float_to_fp16_16(41.3215636822194 / FREQUENCY_RATE), - float_to_fp16_16(41.3476340694006 / FREQUENCY_RATE), - float_to_fp16_16(41.3737373737374 / FREQUENCY_RATE), - float_to_fp16_16(41.3998736576121 / FREQUENCY_RATE), - float_to_fp16_16(41.4260429835651 / FREQUENCY_RATE), - float_to_fp16_16(41.4522454142948 / FREQUENCY_RATE), - float_to_fp16_16(41.4784810126582 / FREQUENCY_RATE), - float_to_fp16_16(41.504749841672 / FREQUENCY_RATE), - float_to_fp16_16(41.531051964512 / FREQUENCY_RATE), - float_to_fp16_16(41.5573874445149 / FREQUENCY_RATE), - float_to_fp16_16(41.5837563451777 / FREQUENCY_RATE), - float_to_fp16_16(41.6101587301587 / FREQUENCY_RATE), - float_to_fp16_16(41.6365946632783 / FREQUENCY_RATE), - float_to_fp16_16(41.6630642085188 / FREQUENCY_RATE), - float_to_fp16_16(41.6895674300254 / FREQUENCY_RATE), - float_to_fp16_16(41.7161043921069 / FREQUENCY_RATE), - float_to_fp16_16(41.7426751592357 / FREQUENCY_RATE), - float_to_fp16_16(41.7692797960484 / FREQUENCY_RATE), - float_to_fp16_16(41.7959183673469 / FREQUENCY_RATE), - float_to_fp16_16(41.8225909380983 / FREQUENCY_RATE), - float_to_fp16_16(41.8492975734355 / FREQUENCY_RATE), - float_to_fp16_16(41.8760383386582 / FREQUENCY_RATE), - float_to_fp16_16(41.9028132992327 / FREQUENCY_RATE), - float_to_fp16_16(41.9296225207934 / FREQUENCY_RATE), - float_to_fp16_16(41.9564660691421 / FREQUENCY_RATE), - float_to_fp16_16(41.9833440102498 / FREQUENCY_RATE), - float_to_fp16_16(42.0102564102564 / FREQUENCY_RATE), - float_to_fp16_16(42.0372033354715 / FREQUENCY_RATE), - float_to_fp16_16(42.0641848523748 / FREQUENCY_RATE), - float_to_fp16_16(42.0912010276172 / FREQUENCY_RATE), - float_to_fp16_16(42.1182519280206 / FREQUENCY_RATE), - float_to_fp16_16(42.1453376205788 / FREQUENCY_RATE), - float_to_fp16_16(42.1724581724582 / FREQUENCY_RATE), - float_to_fp16_16(42.1996136509981 / FREQUENCY_RATE), - float_to_fp16_16(42.2268041237113 / FREQUENCY_RATE), - float_to_fp16_16(42.254029658285 / FREQUENCY_RATE), - float_to_fp16_16(42.2812903225807 / FREQUENCY_RATE), - float_to_fp16_16(42.3085861846352 / FREQUENCY_RATE), - float_to_fp16_16(42.3359173126615 / FREQUENCY_RATE), - float_to_fp16_16(42.3632837750485 / FREQUENCY_RATE), - float_to_fp16_16(42.3906856403622 / FREQUENCY_RATE), - float_to_fp16_16(42.4181229773463 / FREQUENCY_RATE), - float_to_fp16_16(42.4455958549223 / FREQUENCY_RATE), - float_to_fp16_16(42.4731043421905 / FREQUENCY_RATE), - float_to_fp16_16(42.5006485084306 / FREQUENCY_RATE), - float_to_fp16_16(42.5282284231019 / FREQUENCY_RATE), - float_to_fp16_16(42.5558441558442 / FREQUENCY_RATE), - float_to_fp16_16(42.5834957764782 / FREQUENCY_RATE), - float_to_fp16_16(42.6111833550065 / FREQUENCY_RATE), - float_to_fp16_16(42.6389069616135 / FREQUENCY_RATE), - float_to_fp16_16(42.6666666666667 / FREQUENCY_RATE), - float_to_fp16_16(42.6944625407166 / FREQUENCY_RATE), - float_to_fp16_16(42.722294654498 / FREQUENCY_RATE), - float_to_fp16_16(42.7501630789302 / FREQUENCY_RATE), - float_to_fp16_16(42.7780678851175 / FREQUENCY_RATE), - float_to_fp16_16(42.8060091443501 / FREQUENCY_RATE), - float_to_fp16_16(42.8339869281046 / FREQUENCY_RATE), - float_to_fp16_16(42.8620013080445 / FREQUENCY_RATE), - float_to_fp16_16(42.890052356021 / FREQUENCY_RATE), - float_to_fp16_16(42.9181401440733 / FREQUENCY_RATE), - float_to_fp16_16(42.9462647444299 / FREQUENCY_RATE), - float_to_fp16_16(42.9744262295082 / FREQUENCY_RATE), - float_to_fp16_16(43.002624671916 / FREQUENCY_RATE), - float_to_fp16_16(43.0308601444517 / FREQUENCY_RATE), - float_to_fp16_16(43.0591327201051 / FREQUENCY_RATE), - float_to_fp16_16(43.0874424720579 / FREQUENCY_RATE), - float_to_fp16_16(43.1157894736842 / FREQUENCY_RATE), - float_to_fp16_16(43.1441737985517 / FREQUENCY_RATE), - float_to_fp16_16(43.1725955204216 / FREQUENCY_RATE), - float_to_fp16_16(43.2010547132498 / FREQUENCY_RATE), - float_to_fp16_16(43.2295514511873 / FREQUENCY_RATE), - float_to_fp16_16(43.2580858085809 / FREQUENCY_RATE), - float_to_fp16_16(43.2866578599736 / FREQUENCY_RATE), - float_to_fp16_16(43.3152676801057 / FREQUENCY_RATE), - float_to_fp16_16(43.3439153439153 / FREQUENCY_RATE), - float_to_fp16_16(43.3726009265387 / FREQUENCY_RATE), - float_to_fp16_16(43.4013245033113 / FREQUENCY_RATE), - float_to_fp16_16(43.4300861497681 / FREQUENCY_RATE), - float_to_fp16_16(43.4588859416446 / FREQUENCY_RATE), - float_to_fp16_16(43.4877239548772 / FREQUENCY_RATE), - float_to_fp16_16(43.5166002656043 / FREQUENCY_RATE), - float_to_fp16_16(43.5455149501661 / FREQUENCY_RATE), - float_to_fp16_16(43.5744680851064 / FREQUENCY_RATE), - float_to_fp16_16(43.6034597471723 / FREQUENCY_RATE), - float_to_fp16_16(43.6324900133156 / FREQUENCY_RATE), - float_to_fp16_16(43.6615589606929 / FREQUENCY_RATE), - float_to_fp16_16(43.6906666666667 / FREQUENCY_RATE), - float_to_fp16_16(43.7198132088059 / FREQUENCY_RATE), - float_to_fp16_16(43.7489986648865 / FREQUENCY_RATE), - float_to_fp16_16(43.7782231128925 / FREQUENCY_RATE), - float_to_fp16_16(43.807486631016 / FREQUENCY_RATE), - float_to_fp16_16(43.8367892976589 / FREQUENCY_RATE), - float_to_fp16_16(43.8661311914324 / FREQUENCY_RATE), - float_to_fp16_16(43.8955123911587 / FREQUENCY_RATE), - float_to_fp16_16(43.9249329758713 / FREQUENCY_RATE), - float_to_fp16_16(43.9543930248156 / FREQUENCY_RATE), - float_to_fp16_16(43.9838926174497 / FREQUENCY_RATE), - float_to_fp16_16(44.0134318334453 / FREQUENCY_RATE), - float_to_fp16_16(44.0430107526882 / FREQUENCY_RATE), - float_to_fp16_16(44.0726294552791 / FREQUENCY_RATE), - float_to_fp16_16(44.1022880215343 / FREQUENCY_RATE), - float_to_fp16_16(44.1319865319865 / FREQUENCY_RATE), - float_to_fp16_16(44.1617250673855 / FREQUENCY_RATE), - float_to_fp16_16(44.1915037086986 / FREQUENCY_RATE), - float_to_fp16_16(44.221322537112 / FREQUENCY_RATE), - float_to_fp16_16(44.2511816340311 / FREQUENCY_RATE), - float_to_fp16_16(44.2810810810811 / FREQUENCY_RATE), - float_to_fp16_16(44.3110209601082 / FREQUENCY_RATE), - float_to_fp16_16(44.34100135318 / FREQUENCY_RATE), - float_to_fp16_16(44.3710223425863 / FREQUENCY_RATE), - float_to_fp16_16(44.4010840108401 / FREQUENCY_RATE), - float_to_fp16_16(44.431186440678 / FREQUENCY_RATE), - float_to_fp16_16(44.4613297150611 / FREQUENCY_RATE), - float_to_fp16_16(44.4915139171758 / FREQUENCY_RATE), - float_to_fp16_16(44.5217391304348 / FREQUENCY_RATE), - float_to_fp16_16(44.5520054384772 / FREQUENCY_RATE), - float_to_fp16_16(44.5823129251701 / FREQUENCY_RATE), - float_to_fp16_16(44.6126616746086 / FREQUENCY_RATE), - float_to_fp16_16(44.6430517711172 / FREQUENCY_RATE), - float_to_fp16_16(44.6734832992502 / FREQUENCY_RATE), - float_to_fp16_16(44.7039563437926 / FREQUENCY_RATE), - float_to_fp16_16(44.7344709897611 / FREQUENCY_RATE), - float_to_fp16_16(44.7650273224044 / FREQUENCY_RATE), - float_to_fp16_16(44.7956254272044 / FREQUENCY_RATE), - float_to_fp16_16(44.8262653898769 / FREQUENCY_RATE), - float_to_fp16_16(44.8569472963724 / FREQUENCY_RATE), - float_to_fp16_16(44.8876712328767 / FREQUENCY_RATE), - float_to_fp16_16(44.9184372858122 / FREQUENCY_RATE), - float_to_fp16_16(44.9492455418381 / FREQUENCY_RATE), - float_to_fp16_16(44.9800960878518 / FREQUENCY_RATE), - float_to_fp16_16(45.010989010989 / FREQUENCY_RATE), - float_to_fp16_16(45.0419243986254 / FREQUENCY_RATE), - float_to_fp16_16(45.0729023383769 / FREQUENCY_RATE), - float_to_fp16_16(45.1039229181005 / FREQUENCY_RATE), - float_to_fp16_16(45.1349862258953 / FREQUENCY_RATE), - float_to_fp16_16(45.1660923501034 / FREQUENCY_RATE), - float_to_fp16_16(45.1972413793103 / FREQUENCY_RATE), - float_to_fp16_16(45.2284334023465 / FREQUENCY_RATE), - float_to_fp16_16(45.2596685082873 / FREQUENCY_RATE), - float_to_fp16_16(45.2909467864547 / FREQUENCY_RATE), - float_to_fp16_16(45.3222683264177 / FREQUENCY_RATE), - float_to_fp16_16(45.3536332179931 / FREQUENCY_RATE), - float_to_fp16_16(45.3850415512465 / FREQUENCY_RATE), - float_to_fp16_16(45.4164934164934 / FREQUENCY_RATE), - float_to_fp16_16(45.4479889042996 / FREQUENCY_RATE), - float_to_fp16_16(45.4795281054823 / FREQUENCY_RATE), - float_to_fp16_16(45.5111111111111 / FREQUENCY_RATE), - float_to_fp16_16(45.5427380125087 / FREQUENCY_RATE), - float_to_fp16_16(45.5744089012517 / FREQUENCY_RATE), - float_to_fp16_16(45.6061238691719 / FREQUENCY_RATE), - float_to_fp16_16(45.6378830083566 / FREQUENCY_RATE), - float_to_fp16_16(45.6696864111498 / FREQUENCY_RATE), - float_to_fp16_16(45.7015341701534 / FREQUENCY_RATE), - float_to_fp16_16(45.7334263782275 / FREQUENCY_RATE), - float_to_fp16_16(45.7653631284916 / FREQUENCY_RATE), - float_to_fp16_16(45.7973445143256 / FREQUENCY_RATE), - float_to_fp16_16(45.8293706293706 / FREQUENCY_RATE), - float_to_fp16_16(45.8614415675297 / FREQUENCY_RATE), - float_to_fp16_16(45.8935574229692 / FREQUENCY_RATE), - float_to_fp16_16(45.9257182901191 / FREQUENCY_RATE), - float_to_fp16_16(45.9579242636746 / FREQUENCY_RATE), - float_to_fp16_16(45.9901754385965 / FREQUENCY_RATE), - float_to_fp16_16(46.0224719101124 / FREQUENCY_RATE), - float_to_fp16_16(46.0548137737175 / FREQUENCY_RATE), - float_to_fp16_16(46.0872011251758 / FREQUENCY_RATE), - float_to_fp16_16(46.1196340605208 / FREQUENCY_RATE), - float_to_fp16_16(46.1521126760563 / FREQUENCY_RATE), - float_to_fp16_16(46.184637068358 / FREQUENCY_RATE), - float_to_fp16_16(46.2172073342736 / FREQUENCY_RATE), - float_to_fp16_16(46.2498235709245 / FREQUENCY_RATE), - float_to_fp16_16(46.2824858757062 / FREQUENCY_RATE), - float_to_fp16_16(46.3151943462898 / FREQUENCY_RATE), - float_to_fp16_16(46.3479490806223 / FREQUENCY_RATE), - float_to_fp16_16(46.3807501769285 / FREQUENCY_RATE), - float_to_fp16_16(46.4135977337111 / FREQUENCY_RATE), - float_to_fp16_16(46.446491849752 / FREQUENCY_RATE), - float_to_fp16_16(46.4794326241135 / FREQUENCY_RATE), - float_to_fp16_16(46.5124201561391 / FREQUENCY_RATE), - float_to_fp16_16(46.5454545454545 / FREQUENCY_RATE), - float_to_fp16_16(46.5785358919687 / FREQUENCY_RATE), - float_to_fp16_16(46.6116642958748 / FREQUENCY_RATE), - float_to_fp16_16(46.6448398576513 / FREQUENCY_RATE), - float_to_fp16_16(46.6780626780627 / FREQUENCY_RATE), - float_to_fp16_16(46.7113328581611 / FREQUENCY_RATE), - float_to_fp16_16(46.7446504992867 / FREQUENCY_RATE), - float_to_fp16_16(46.7780157030692 / FREQUENCY_RATE), - float_to_fp16_16(46.8114285714286 / FREQUENCY_RATE), - float_to_fp16_16(46.8448892065761 / FREQUENCY_RATE), - float_to_fp16_16(46.8783977110157 / FREQUENCY_RATE), - float_to_fp16_16(46.9119541875447 / FREQUENCY_RATE), - float_to_fp16_16(46.945558739255 / FREQUENCY_RATE), - float_to_fp16_16(46.9792114695341 / FREQUENCY_RATE), - float_to_fp16_16(47.012912482066 / FREQUENCY_RATE), - float_to_fp16_16(47.0466618808327 / FREQUENCY_RATE), - float_to_fp16_16(47.0804597701149 / FREQUENCY_RATE), - float_to_fp16_16(47.1143062544932 / FREQUENCY_RATE), - float_to_fp16_16(47.1482014388489 / FREQUENCY_RATE), - float_to_fp16_16(47.1821454283657 / FREQUENCY_RATE), - float_to_fp16_16(47.2161383285303 / FREQUENCY_RATE), - float_to_fp16_16(47.2501802451334 / FREQUENCY_RATE), - float_to_fp16_16(47.2842712842713 / FREQUENCY_RATE), - float_to_fp16_16(47.3184115523466 / FREQUENCY_RATE), - float_to_fp16_16(47.3526011560694 / FREQUENCY_RATE), - float_to_fp16_16(47.3868402024584 / FREQUENCY_RATE), - float_to_fp16_16(47.4211287988423 / FREQUENCY_RATE), - float_to_fp16_16(47.4554670528602 / FREQUENCY_RATE), - float_to_fp16_16(47.4898550724638 / FREQUENCY_RATE), - float_to_fp16_16(47.5242929659173 / FREQUENCY_RATE), - float_to_fp16_16(47.5587808417997 / FREQUENCY_RATE), - float_to_fp16_16(47.5933188090051 / FREQUENCY_RATE), - float_to_fp16_16(47.6279069767442 / FREQUENCY_RATE), - float_to_fp16_16(47.6625454545455 / FREQUENCY_RATE), - float_to_fp16_16(47.6972343522562 / FREQUENCY_RATE), - float_to_fp16_16(47.7319737800437 / FREQUENCY_RATE), - float_to_fp16_16(47.7667638483965 / FREQUENCY_RATE), - float_to_fp16_16(47.8016046681255 / FREQUENCY_RATE), - float_to_fp16_16(47.836496350365 / FREQUENCY_RATE), - float_to_fp16_16(47.8714390065741 / FREQUENCY_RATE), - float_to_fp16_16(47.906432748538 / FREQUENCY_RATE), - float_to_fp16_16(47.9414776883687 / FREQUENCY_RATE), - float_to_fp16_16(47.9765739385066 / FREQUENCY_RATE), - float_to_fp16_16(48.0117216117216 / FREQUENCY_RATE), - float_to_fp16_16(48.0469208211144 / FREQUENCY_RATE), - float_to_fp16_16(48.0821716801174 / FREQUENCY_RATE), - float_to_fp16_16(48.1174743024963 / FREQUENCY_RATE), - float_to_fp16_16(48.1528288023512 / FREQUENCY_RATE), - float_to_fp16_16(48.1882352941176 / FREQUENCY_RATE), - float_to_fp16_16(48.2236938925681 / FREQUENCY_RATE), - float_to_fp16_16(48.259204712813 / FREQUENCY_RATE), - float_to_fp16_16(48.2947678703021 / FREQUENCY_RATE), - float_to_fp16_16(48.330383480826 / FREQUENCY_RATE), - float_to_fp16_16(48.3660516605166 / FREQUENCY_RATE), - float_to_fp16_16(48.4017725258493 / FREQUENCY_RATE), - float_to_fp16_16(48.4375461936438 / FREQUENCY_RATE), - float_to_fp16_16(48.4733727810651 / FREQUENCY_RATE), - float_to_fp16_16(48.5092524056255 / FREQUENCY_RATE), - float_to_fp16_16(48.5451851851852 / FREQUENCY_RATE), - float_to_fp16_16(48.581171237954 / FREQUENCY_RATE), - float_to_fp16_16(48.6172106824926 / FREQUENCY_RATE), - float_to_fp16_16(48.6533036377134 / FREQUENCY_RATE), - float_to_fp16_16(48.6894502228826 / FREQUENCY_RATE), - float_to_fp16_16(48.7256505576208 / FREQUENCY_RATE), - float_to_fp16_16(48.7619047619048 / FREQUENCY_RATE), - float_to_fp16_16(48.7982129560685 / FREQUENCY_RATE), - float_to_fp16_16(48.8345752608048 / FREQUENCY_RATE), - float_to_fp16_16(48.8709917971663 / FREQUENCY_RATE), - float_to_fp16_16(48.9074626865672 / FREQUENCY_RATE), - float_to_fp16_16(48.9439880507842 / FREQUENCY_RATE), - float_to_fp16_16(48.9805680119582 / FREQUENCY_RATE), - float_to_fp16_16(49.0172026925954 / FREQUENCY_RATE), - float_to_fp16_16(49.0538922155689 / FREQUENCY_RATE), - float_to_fp16_16(49.0906367041199 / FREQUENCY_RATE), - float_to_fp16_16(49.1274362818591 / FREQUENCY_RATE), - float_to_fp16_16(49.1642910727682 / FREQUENCY_RATE), - float_to_fp16_16(49.2012012012012 / FREQUENCY_RATE), - float_to_fp16_16(49.2381667918858 / FREQUENCY_RATE), - float_to_fp16_16(49.2751879699248 / FREQUENCY_RATE), - float_to_fp16_16(49.3122648607976 / FREQUENCY_RATE), - float_to_fp16_16(49.3493975903615 / FREQUENCY_RATE), - float_to_fp16_16(49.3865862848531 / FREQUENCY_RATE), - float_to_fp16_16(49.4238310708899 / FREQUENCY_RATE), - float_to_fp16_16(49.4611320754717 / FREQUENCY_RATE), - float_to_fp16_16(49.4984894259819 / FREQUENCY_RATE), - float_to_fp16_16(49.535903250189 / FREQUENCY_RATE), - float_to_fp16_16(49.5733736762481 / FREQUENCY_RATE), - float_to_fp16_16(49.6109008327025 / FREQUENCY_RATE), - float_to_fp16_16(49.6484848484849 / FREQUENCY_RATE), - float_to_fp16_16(49.6861258529189 / FREQUENCY_RATE), - float_to_fp16_16(49.7238239757208 / FREQUENCY_RATE), - float_to_fp16_16(49.7615793470008 / FREQUENCY_RATE), - float_to_fp16_16(49.7993920972644 / FREQUENCY_RATE), - float_to_fp16_16(49.8372623574145 / FREQUENCY_RATE), - float_to_fp16_16(49.8751902587519 / FREQUENCY_RATE), - float_to_fp16_16(49.9131759329779 / FREQUENCY_RATE), - float_to_fp16_16(49.9512195121951 / FREQUENCY_RATE), - float_to_fp16_16(49.9893211289092 / FREQUENCY_RATE), - float_to_fp16_16(50.0274809160305 / FREQUENCY_RATE), - float_to_fp16_16(50.0656990068755 / FREQUENCY_RATE), - float_to_fp16_16(50.1039755351682 / FREQUENCY_RATE), - float_to_fp16_16(50.1423106350421 / FREQUENCY_RATE), - float_to_fp16_16(50.1807044410413 / FREQUENCY_RATE), - float_to_fp16_16(50.2191570881226 / FREQUENCY_RATE), - float_to_fp16_16(50.2576687116564 / FREQUENCY_RATE), - float_to_fp16_16(50.296239447429 / FREQUENCY_RATE), - float_to_fp16_16(50.3348694316436 / FREQUENCY_RATE), - float_to_fp16_16(50.3735588009224 / FREQUENCY_RATE), - float_to_fp16_16(50.4123076923077 / FREQUENCY_RATE), - float_to_fp16_16(50.451116243264 / FREQUENCY_RATE), - float_to_fp16_16(50.4899845916795 / FREQUENCY_RATE), - float_to_fp16_16(50.5289128758674 / FREQUENCY_RATE), - float_to_fp16_16(50.5679012345679 / FREQUENCY_RATE), - float_to_fp16_16(50.6069498069498 / FREQUENCY_RATE), - float_to_fp16_16(50.6460587326121 / FREQUENCY_RATE), - float_to_fp16_16(50.6852281515855 / FREQUENCY_RATE), - float_to_fp16_16(50.7244582043344 / FREQUENCY_RATE), - float_to_fp16_16(50.7637490317583 / FREQUENCY_RATE), - float_to_fp16_16(50.8031007751938 / FREQUENCY_RATE), - float_to_fp16_16(50.8425135764158 / FREQUENCY_RATE), - float_to_fp16_16(50.8819875776397 / FREQUENCY_RATE), - float_to_fp16_16(50.9215229215229 / FREQUENCY_RATE), - float_to_fp16_16(50.9611197511664 / FREQUENCY_RATE), - float_to_fp16_16(51.0007782101167 / FREQUENCY_RATE), - float_to_fp16_16(51.0404984423676 / FREQUENCY_RATE), - float_to_fp16_16(51.0802805923617 / FREQUENCY_RATE), - float_to_fp16_16(51.1201248049922 / FREQUENCY_RATE), - float_to_fp16_16(51.160031225605 / FREQUENCY_RATE), - float_to_fp16_16(51.2 / FREQUENCY_RATE), - float_to_fp16_16(51.2400312744331 / FREQUENCY_RATE), - float_to_fp16_16(51.2801251956182 / FREQUENCY_RATE), - float_to_fp16_16(51.3202819107283 / FREQUENCY_RATE), - float_to_fp16_16(51.3605015673981 / FREQUENCY_RATE), - float_to_fp16_16(51.4007843137255 / FREQUENCY_RATE), - float_to_fp16_16(51.4411302982732 / FREQUENCY_RATE), - float_to_fp16_16(51.4815396700707 / FREQUENCY_RATE), - float_to_fp16_16(51.5220125786164 / FREQUENCY_RATE), - float_to_fp16_16(51.5625491738788 / FREQUENCY_RATE), - float_to_fp16_16(51.6031496062992 / FREQUENCY_RATE), - float_to_fp16_16(51.6438140267928 / FREQUENCY_RATE), - float_to_fp16_16(51.6845425867508 / FREQUENCY_RATE), - float_to_fp16_16(51.7253354380426 / FREQUENCY_RATE), - float_to_fp16_16(51.7661927330174 / FREQUENCY_RATE), - float_to_fp16_16(51.8071146245059 / FREQUENCY_RATE), - float_to_fp16_16(51.8481012658228 / FREQUENCY_RATE), - float_to_fp16_16(51.889152810768 / FREQUENCY_RATE), - float_to_fp16_16(51.9302694136292 / FREQUENCY_RATE), - float_to_fp16_16(51.9714512291832 / FREQUENCY_RATE), - float_to_fp16_16(52.0126984126984 / FREQUENCY_RATE), - float_to_fp16_16(52.0540111199365 / FREQUENCY_RATE), - float_to_fp16_16(52.0953895071542 / FREQUENCY_RATE), - float_to_fp16_16(52.1368337311058 / FREQUENCY_RATE), - float_to_fp16_16(52.1783439490446 / FREQUENCY_RATE), - float_to_fp16_16(52.2199203187251 / FREQUENCY_RATE), - float_to_fp16_16(52.2615629984051 / FREQUENCY_RATE), - float_to_fp16_16(52.3032721468476 / FREQUENCY_RATE), - float_to_fp16_16(52.3450479233227 / FREQUENCY_RATE), - float_to_fp16_16(52.3868904876099 / FREQUENCY_RATE), - float_to_fp16_16(52.4288 / FREQUENCY_RATE), - float_to_fp16_16(52.470776621297 / FREQUENCY_RATE), - float_to_fp16_16(52.5128205128205 / FREQUENCY_RATE), - float_to_fp16_16(52.5549318364074 / FREQUENCY_RATE), - float_to_fp16_16(52.5971107544141 / FREQUENCY_RATE), - float_to_fp16_16(52.6393574297189 / FREQUENCY_RATE), - float_to_fp16_16(52.6816720257235 / FREQUENCY_RATE), - float_to_fp16_16(52.7240547063556 / FREQUENCY_RATE), - float_to_fp16_16(52.7665056360709 / FREQUENCY_RATE), - float_to_fp16_16(52.809024979855 / FREQUENCY_RATE), - float_to_fp16_16(52.8516129032258 / FREQUENCY_RATE), - float_to_fp16_16(52.8942695722357 / FREQUENCY_RATE), - float_to_fp16_16(52.9369951534734 / FREQUENCY_RATE), - float_to_fp16_16(52.9797898140663 / FREQUENCY_RATE), - float_to_fp16_16(53.0226537216829 / FREQUENCY_RATE), - float_to_fp16_16(53.0655870445344 / FREQUENCY_RATE), - float_to_fp16_16(53.1085899513776 / FREQUENCY_RATE), - float_to_fp16_16(53.1516626115166 / FREQUENCY_RATE), - float_to_fp16_16(53.1948051948052 / FREQUENCY_RATE), - float_to_fp16_16(53.2380178716491 / FREQUENCY_RATE), - float_to_fp16_16(53.2813008130081 / FREQUENCY_RATE), - float_to_fp16_16(53.3246541903987 / FREQUENCY_RATE), - float_to_fp16_16(53.3680781758958 / FREQUENCY_RATE), - float_to_fp16_16(53.4115729421353 / FREQUENCY_RATE), - float_to_fp16_16(53.4551386623165 / FREQUENCY_RATE), - float_to_fp16_16(53.4987755102041 / FREQUENCY_RATE), - float_to_fp16_16(53.5424836601307 / FREQUENCY_RATE), - float_to_fp16_16(53.5862632869992 / FREQUENCY_RATE), - float_to_fp16_16(53.6301145662848 / FREQUENCY_RATE), - float_to_fp16_16(53.6740376740377 / FREQUENCY_RATE), - float_to_fp16_16(53.7180327868852 / FREQUENCY_RATE), - float_to_fp16_16(53.7621000820345 / FREQUENCY_RATE), - float_to_fp16_16(53.8062397372742 / FREQUENCY_RATE), - float_to_fp16_16(53.8504519309778 / FREQUENCY_RATE), - float_to_fp16_16(53.8947368421053 / FREQUENCY_RATE), - float_to_fp16_16(53.9390946502058 / FREQUENCY_RATE), - float_to_fp16_16(53.9835255354201 / FREQUENCY_RATE), - float_to_fp16_16(54.0280296784831 / FREQUENCY_RATE), - float_to_fp16_16(54.0726072607261 / FREQUENCY_RATE), - float_to_fp16_16(54.1172584640793 / FREQUENCY_RATE), - float_to_fp16_16(54.1619834710744 / FREQUENCY_RATE), - float_to_fp16_16(54.206782464847 / FREQUENCY_RATE), - float_to_fp16_16(54.2516556291391 / FREQUENCY_RATE), - float_to_fp16_16(54.2966031483016 / FREQUENCY_RATE), - float_to_fp16_16(54.3416252072969 / FREQUENCY_RATE), - float_to_fp16_16(54.3867219917012 / FREQUENCY_RATE), - float_to_fp16_16(54.4318936877076 / FREQUENCY_RATE), - float_to_fp16_16(54.477140482128 / FREQUENCY_RATE), - float_to_fp16_16(54.522462562396 / FREQUENCY_RATE), - float_to_fp16_16(54.5678601165695 / FREQUENCY_RATE), - float_to_fp16_16(54.6133333333333 / FREQUENCY_RATE), - float_to_fp16_16(54.6588824020017 / FREQUENCY_RATE), - float_to_fp16_16(54.7045075125209 / FREQUENCY_RATE), - float_to_fp16_16(54.750208855472 / FREQUENCY_RATE), - float_to_fp16_16(54.7959866220736 / FREQUENCY_RATE), - float_to_fp16_16(54.8418410041841 / FREQUENCY_RATE), - float_to_fp16_16(54.8877721943049 / FREQUENCY_RATE), - float_to_fp16_16(54.9337803855826 / FREQUENCY_RATE), - float_to_fp16_16(54.9798657718121 / FREQUENCY_RATE), - float_to_fp16_16(55.0260285474391 / FREQUENCY_RATE), - float_to_fp16_16(55.072268907563 / FREQUENCY_RATE), - float_to_fp16_16(55.1185870479394 / FREQUENCY_RATE), - float_to_fp16_16(55.1649831649832 / FREQUENCY_RATE), - float_to_fp16_16(55.2114574557709 / FREQUENCY_RATE), - float_to_fp16_16(55.2580101180438 / FREQUENCY_RATE), - float_to_fp16_16(55.304641350211 / FREQUENCY_RATE), - float_to_fp16_16(55.3513513513514 / FREQUENCY_RATE), - float_to_fp16_16(55.3981403212172 / FREQUENCY_RATE), - float_to_fp16_16(55.4450084602369 / FREQUENCY_RATE), - float_to_fp16_16(55.4919559695174 / FREQUENCY_RATE), - float_to_fp16_16(55.5389830508475 / FREQUENCY_RATE), - float_to_fp16_16(55.5860899067006 / FREQUENCY_RATE), - float_to_fp16_16(55.6332767402377 / FREQUENCY_RATE), - float_to_fp16_16(55.6805437553101 / FREQUENCY_RATE), - float_to_fp16_16(55.7278911564626 / FREQUENCY_RATE), - float_to_fp16_16(55.7753191489362 / FREQUENCY_RATE), - float_to_fp16_16(55.8228279386712 / FREQUENCY_RATE), - float_to_fp16_16(55.8704177323103 / FREQUENCY_RATE), - float_to_fp16_16(55.9180887372014 / FREQUENCY_RATE), - float_to_fp16_16(55.9658411614005 / FREQUENCY_RATE), - float_to_fp16_16(56.0136752136752 / FREQUENCY_RATE), - float_to_fp16_16(56.0615911035073 / FREQUENCY_RATE), - float_to_fp16_16(56.1095890410959 / FREQUENCY_RATE), - float_to_fp16_16(56.1576692373608 / FREQUENCY_RATE), - float_to_fp16_16(56.2058319039451 / FREQUENCY_RATE), - float_to_fp16_16(56.2540772532189 / FREQUENCY_RATE), - float_to_fp16_16(56.3024054982818 / FREQUENCY_RATE), - float_to_fp16_16(56.3508168529665 / FREQUENCY_RATE), - float_to_fp16_16(56.3993115318417 / FREQUENCY_RATE), - float_to_fp16_16(56.4478897502153 / FREQUENCY_RATE), - float_to_fp16_16(56.4965517241379 / FREQUENCY_RATE), - float_to_fp16_16(56.5452976704055 / FREQUENCY_RATE), - float_to_fp16_16(56.594127806563 / FREQUENCY_RATE), - float_to_fp16_16(56.6430423509075 / FREQUENCY_RATE), - float_to_fp16_16(56.6920415224914 / FREQUENCY_RATE), - float_to_fp16_16(56.7411255411255 / FREQUENCY_RATE), - float_to_fp16_16(56.790294627383 / FREQUENCY_RATE), - float_to_fp16_16(56.8395490026019 / FREQUENCY_RATE), - float_to_fp16_16(56.8888888888889 / FREQUENCY_RATE), - float_to_fp16_16(56.9383145091225 / FREQUENCY_RATE), - float_to_fp16_16(56.9878260869565 / FREQUENCY_RATE), - float_to_fp16_16(57.0374238468233 / FREQUENCY_RATE), - float_to_fp16_16(57.0871080139373 / FREQUENCY_RATE), - float_to_fp16_16(57.1368788142982 / FREQUENCY_RATE), - float_to_fp16_16(57.1867364746946 / FREQUENCY_RATE), - float_to_fp16_16(57.2366812227074 / FREQUENCY_RATE), - float_to_fp16_16(57.2867132867133 / FREQUENCY_RATE), - float_to_fp16_16(57.336832895888 / FREQUENCY_RATE), - float_to_fp16_16(57.3870402802102 / FREQUENCY_RATE), - float_to_fp16_16(57.4373356704645 / FREQUENCY_RATE), - float_to_fp16_16(57.4877192982456 / FREQUENCY_RATE), - float_to_fp16_16(57.5381913959614 / FREQUENCY_RATE), - float_to_fp16_16(57.5887521968366 / FREQUENCY_RATE), - float_to_fp16_16(57.6394019349165 / FREQUENCY_RATE), - float_to_fp16_16(57.6901408450704 / FREQUENCY_RATE), - float_to_fp16_16(57.7409691629956 / FREQUENCY_RATE), - float_to_fp16_16(57.7918871252205 / FREQUENCY_RATE), - float_to_fp16_16(57.8428949691086 / FREQUENCY_RATE), - float_to_fp16_16(57.8939929328622 / FREQUENCY_RATE), - float_to_fp16_16(57.9451812555261 / FREQUENCY_RATE), - float_to_fp16_16(57.9964601769912 / FREQUENCY_RATE), - float_to_fp16_16(58.0478299379982 / FREQUENCY_RATE), - float_to_fp16_16(58.0992907801418 / FREQUENCY_RATE), - float_to_fp16_16(58.150842945874 / FREQUENCY_RATE), - float_to_fp16_16(58.202486678508 / FREQUENCY_RATE), - float_to_fp16_16(58.2542222222222 / FREQUENCY_RATE), - float_to_fp16_16(58.3060498220641 / FREQUENCY_RATE), - float_to_fp16_16(58.3579697239537 / FREQUENCY_RATE), - float_to_fp16_16(58.4099821746881 / FREQUENCY_RATE), - float_to_fp16_16(58.4620874219447 / FREQUENCY_RATE), - float_to_fp16_16(58.5142857142857 / FREQUENCY_RATE), - float_to_fp16_16(58.5665773011618 / FREQUENCY_RATE), - float_to_fp16_16(58.6189624329159 / FREQUENCY_RATE), - float_to_fp16_16(58.6714413607878 / FREQUENCY_RATE), - float_to_fp16_16(58.7240143369176 / FREQUENCY_RATE), - float_to_fp16_16(58.7766816143498 / FREQUENCY_RATE), - float_to_fp16_16(58.8294434470377 / FREQUENCY_RATE), - float_to_fp16_16(58.8823000898473 / FREQUENCY_RATE), - float_to_fp16_16(58.9352517985612 / FREQUENCY_RATE), - float_to_fp16_16(58.988298829883 / FREQUENCY_RATE), - float_to_fp16_16(59.0414414414414 / FREQUENCY_RATE), - float_to_fp16_16(59.0946798917944 / FREQUENCY_RATE), - float_to_fp16_16(59.1480144404332 / FREQUENCY_RATE), - float_to_fp16_16(59.2014453477868 / FREQUENCY_RATE), - float_to_fp16_16(59.254972875226 / FREQUENCY_RATE), - float_to_fp16_16(59.3085972850679 / FREQUENCY_RATE), - float_to_fp16_16(59.3623188405797 / FREQUENCY_RATE), - float_to_fp16_16(59.4161378059837 / FREQUENCY_RATE), - float_to_fp16_16(59.470054446461 / FREQUENCY_RATE), - float_to_fp16_16(59.5240690281562 / FREQUENCY_RATE), - float_to_fp16_16(59.5781818181818 / FREQUENCY_RATE), - float_to_fp16_16(59.6323930846224 / FREQUENCY_RATE), - float_to_fp16_16(59.6867030965392 / FREQUENCY_RATE), - float_to_fp16_16(59.7411121239745 / FREQUENCY_RATE), - float_to_fp16_16(59.7956204379562 / FREQUENCY_RATE), - float_to_fp16_16(59.8502283105023 / FREQUENCY_RATE), - float_to_fp16_16(59.9049360146252 / FREQUENCY_RATE), - float_to_fp16_16(59.9597438243367 / FREQUENCY_RATE), - float_to_fp16_16(60.014652014652 / FREQUENCY_RATE), - float_to_fp16_16(60.0696608615949 / FREQUENCY_RATE), - float_to_fp16_16(60.1247706422018 / FREQUENCY_RATE), - float_to_fp16_16(60.1799816345271 / FREQUENCY_RATE), - float_to_fp16_16(60.2352941176471 / FREQUENCY_RATE), - float_to_fp16_16(60.2907083716651 / FREQUENCY_RATE), - float_to_fp16_16(60.3462246777164 / FREQUENCY_RATE), - float_to_fp16_16(60.4018433179724 / FREQUENCY_RATE), - float_to_fp16_16(60.4575645756458 / FREQUENCY_RATE), - float_to_fp16_16(60.5133887349954 / FREQUENCY_RATE), - float_to_fp16_16(60.5693160813309 / FREQUENCY_RATE), - float_to_fp16_16(60.6253469010176 / FREQUENCY_RATE), - float_to_fp16_16(60.6814814814815 / FREQUENCY_RATE), - float_to_fp16_16(60.7377201112141 / FREQUENCY_RATE), - float_to_fp16_16(60.7940630797774 / FREQUENCY_RATE), - float_to_fp16_16(60.8505106778087 / FREQUENCY_RATE), - float_to_fp16_16(60.907063197026 / FREQUENCY_RATE), - float_to_fp16_16(60.9637209302326 / FREQUENCY_RATE), - float_to_fp16_16(61.0204841713222 / FREQUENCY_RATE), - float_to_fp16_16(61.0773532152843 / FREQUENCY_RATE), - float_to_fp16_16(61.134328358209 / FREQUENCY_RATE), - float_to_fp16_16(61.1914098972923 / FREQUENCY_RATE), - float_to_fp16_16(61.2485981308411 / FREQUENCY_RATE), - float_to_fp16_16(61.3058933582788 / FREQUENCY_RATE), - float_to_fp16_16(61.3632958801498 / FREQUENCY_RATE), - float_to_fp16_16(61.4208059981256 / FREQUENCY_RATE), - float_to_fp16_16(61.4784240150094 / FREQUENCY_RATE), - float_to_fp16_16(61.5361502347418 / FREQUENCY_RATE), - float_to_fp16_16(61.593984962406 / FREQUENCY_RATE), - float_to_fp16_16(61.6519285042333 / FREQUENCY_RATE), - float_to_fp16_16(61.7099811676083 / FREQUENCY_RATE), - float_to_fp16_16(61.7681432610745 / FREQUENCY_RATE), - float_to_fp16_16(61.8264150943396 / FREQUENCY_RATE), - float_to_fp16_16(61.8847969782814 / FREQUENCY_RATE), - float_to_fp16_16(61.9432892249527 / FREQUENCY_RATE), - float_to_fp16_16(62.0018921475875 / FREQUENCY_RATE), - float_to_fp16_16(62.0606060606061 / FREQUENCY_RATE), - float_to_fp16_16(62.1194312796209 / FREQUENCY_RATE), - float_to_fp16_16(62.1783681214421 / FREQUENCY_RATE), - float_to_fp16_16(62.2374169040836 / FREQUENCY_RATE), - float_to_fp16_16(62.2965779467681 / FREQUENCY_RATE), - float_to_fp16_16(62.3558515699334 / FREQUENCY_RATE), - float_to_fp16_16(62.4152380952381 / FREQUENCY_RATE), - float_to_fp16_16(62.4747378455672 / FREQUENCY_RATE), - float_to_fp16_16(62.5343511450382 / FREQUENCY_RATE), - float_to_fp16_16(62.5940783190067 / FREQUENCY_RATE), - float_to_fp16_16(62.6539196940727 / FREQUENCY_RATE), - float_to_fp16_16(62.7138755980861 / FREQUENCY_RATE), - float_to_fp16_16(62.7739463601533 / FREQUENCY_RATE), - float_to_fp16_16(62.8341323106424 / FREQUENCY_RATE), - float_to_fp16_16(62.89443378119 / FREQUENCY_RATE), - float_to_fp16_16(62.954851104707 / FREQUENCY_RATE), - float_to_fp16_16(63.0153846153846 / FREQUENCY_RATE), - float_to_fp16_16(63.0760346487007 / FREQUENCY_RATE), - float_to_fp16_16(63.1368015414258 / FREQUENCY_RATE), - float_to_fp16_16(63.1976856316297 / FREQUENCY_RATE), - float_to_fp16_16(63.2586872586873 / FREQUENCY_RATE), - float_to_fp16_16(63.319806763285 / FREQUENCY_RATE), - float_to_fp16_16(63.3810444874275 / FREQUENCY_RATE), - float_to_fp16_16(63.4424007744434 / FREQUENCY_RATE), - float_to_fp16_16(63.5038759689923 / FREQUENCY_RATE), - float_to_fp16_16(63.5654704170708 / FREQUENCY_RATE), - float_to_fp16_16(63.6271844660194 / FREQUENCY_RATE), - float_to_fp16_16(63.6890184645287 / FREQUENCY_RATE), - float_to_fp16_16(63.7509727626459 / FREQUENCY_RATE), - float_to_fp16_16(63.8130477117819 / FREQUENCY_RATE), - float_to_fp16_16(63.8752436647174 / FREQUENCY_RATE), - float_to_fp16_16(63.9375609756098 / FREQUENCY_RATE), - float_to_fp16_16(64 / FREQUENCY_RATE), - float_to_fp16_16(64.0625610948192 / FREQUENCY_RATE), - float_to_fp16_16(64.1252446183953 / FREQUENCY_RATE), - float_to_fp16_16(64.1880509304603 / FREQUENCY_RATE), - float_to_fp16_16(64.2509803921569 / FREQUENCY_RATE), - float_to_fp16_16(64.3140333660451 / FREQUENCY_RATE), - float_to_fp16_16(64.37721021611 / FREQUENCY_RATE), - float_to_fp16_16(64.440511307768 / FREQUENCY_RATE), - float_to_fp16_16(64.503937007874 / FREQUENCY_RATE), - float_to_fp16_16(64.5674876847291 / FREQUENCY_RATE), - float_to_fp16_16(64.6311637080868 / FREQUENCY_RATE), - float_to_fp16_16(64.6949654491609 / FREQUENCY_RATE), - float_to_fp16_16(64.7588932806324 / FREQUENCY_RATE), - float_to_fp16_16(64.8229475766568 / FREQUENCY_RATE), - float_to_fp16_16(64.8871287128713 / FREQUENCY_RATE), - float_to_fp16_16(64.9514370664024 / FREQUENCY_RATE), - float_to_fp16_16(65.015873015873 / FREQUENCY_RATE), - float_to_fp16_16(65.0804369414101 / FREQUENCY_RATE), - float_to_fp16_16(65.1451292246521 / FREQUENCY_RATE), - float_to_fp16_16(65.2099502487562 / FREQUENCY_RATE), - float_to_fp16_16(65.2749003984064 / FREQUENCY_RATE), - float_to_fp16_16(65.3399800598205 / FREQUENCY_RATE), - float_to_fp16_16(65.4051896207585 / FREQUENCY_RATE), - float_to_fp16_16(65.4705294705295 / FREQUENCY_RATE), - float_to_fp16_16(65.536 / FREQUENCY_RATE), - float_to_fp16_16(65.6016016016016 / FREQUENCY_RATE), - float_to_fp16_16(65.6673346693387 / FREQUENCY_RATE), - float_to_fp16_16(65.7331995987964 / FREQUENCY_RATE), - float_to_fp16_16(65.7991967871486 / FREQUENCY_RATE), - float_to_fp16_16(65.8653266331658 / FREQUENCY_RATE), - float_to_fp16_16(65.9315895372234 / FREQUENCY_RATE), - float_to_fp16_16(65.9979859013092 / FREQUENCY_RATE), - float_to_fp16_16(66.0645161290323 / FREQUENCY_RATE), - float_to_fp16_16(66.1311806256307 / FREQUENCY_RATE), - float_to_fp16_16(66.1979797979798 / FREQUENCY_RATE), - float_to_fp16_16(66.2649140546006 / FREQUENCY_RATE), - float_to_fp16_16(66.331983805668 / FREQUENCY_RATE), - float_to_fp16_16(66.3991894630193 / FREQUENCY_RATE), - float_to_fp16_16(66.4665314401623 / FREQUENCY_RATE), - float_to_fp16_16(66.5340101522843 / FREQUENCY_RATE), - float_to_fp16_16(66.6016260162602 / FREQUENCY_RATE), - float_to_fp16_16(66.6693794506612 / FREQUENCY_RATE), - float_to_fp16_16(66.7372708757637 / FREQUENCY_RATE), - float_to_fp16_16(66.8053007135576 / FREQUENCY_RATE), - float_to_fp16_16(66.8734693877551 / FREQUENCY_RATE), - float_to_fp16_16(66.9417773237998 / FREQUENCY_RATE), - float_to_fp16_16(67.0102249488753 / FREQUENCY_RATE), - float_to_fp16_16(67.078812691914 / FREQUENCY_RATE), - float_to_fp16_16(67.1475409836066 / FREQUENCY_RATE), - float_to_fp16_16(67.2164102564103 / FREQUENCY_RATE), - float_to_fp16_16(67.2854209445585 / FREQUENCY_RATE), - float_to_fp16_16(67.3545734840699 / FREQUENCY_RATE), - float_to_fp16_16(67.4238683127572 / FREQUENCY_RATE), - float_to_fp16_16(67.4933058702369 / FREQUENCY_RATE), - float_to_fp16_16(67.5628865979382 / FREQUENCY_RATE), - float_to_fp16_16(67.6326109391125 / FREQUENCY_RATE), - float_to_fp16_16(67.702479338843 / FREQUENCY_RATE), - float_to_fp16_16(67.7724922440538 / FREQUENCY_RATE), - float_to_fp16_16(67.8426501035197 / FREQUENCY_RATE), - float_to_fp16_16(67.9129533678757 / FREQUENCY_RATE), - float_to_fp16_16(67.9834024896266 / FREQUENCY_RATE), - float_to_fp16_16(68.0539979231568 / FREQUENCY_RATE), - float_to_fp16_16(68.1247401247401 / FREQUENCY_RATE), - float_to_fp16_16(68.1956295525494 / FREQUENCY_RATE), - float_to_fp16_16(68.2666666666667 / FREQUENCY_RATE), - float_to_fp16_16(68.3378519290928 / FREQUENCY_RATE), - float_to_fp16_16(68.4091858037578 / FREQUENCY_RATE), - float_to_fp16_16(68.4806687565308 / FREQUENCY_RATE), - float_to_fp16_16(68.5523012552301 / FREQUENCY_RATE), - float_to_fp16_16(68.6240837696335 / FREQUENCY_RATE), - float_to_fp16_16(68.6960167714885 / FREQUENCY_RATE), - float_to_fp16_16(68.7681007345226 / FREQUENCY_RATE), - float_to_fp16_16(68.8403361344538 / FREQUENCY_RATE), - float_to_fp16_16(68.9127234490011 / FREQUENCY_RATE), - float_to_fp16_16(68.9852631578947 / FREQUENCY_RATE), - float_to_fp16_16(69.0579557428872 / FREQUENCY_RATE), - float_to_fp16_16(69.1308016877637 / FREQUENCY_RATE), - float_to_fp16_16(69.2038014783527 / FREQUENCY_RATE), - float_to_fp16_16(69.276955602537 / FREQUENCY_RATE), - float_to_fp16_16(69.3502645502646 / FREQUENCY_RATE), - float_to_fp16_16(69.4237288135593 / FREQUENCY_RATE), - float_to_fp16_16(69.4973488865324 / FREQUENCY_RATE), - float_to_fp16_16(69.5711252653928 / FREQUENCY_RATE), - float_to_fp16_16(69.6450584484591 / FREQUENCY_RATE), - float_to_fp16_16(69.7191489361702 / FREQUENCY_RATE), - float_to_fp16_16(69.7933972310969 / FREQUENCY_RATE), - float_to_fp16_16(69.8678038379531 / FREQUENCY_RATE), - float_to_fp16_16(69.9423692636073 / FREQUENCY_RATE), - float_to_fp16_16(70.017094017094 / FREQUENCY_RATE), - float_to_fp16_16(70.0919786096257 / FREQUENCY_RATE), - float_to_fp16_16(70.1670235546039 / FREQUENCY_RATE), - float_to_fp16_16(70.2422293676313 / FREQUENCY_RATE), - float_to_fp16_16(70.3175965665236 / FREQUENCY_RATE), - float_to_fp16_16(70.3931256713212 / FREQUENCY_RATE), - float_to_fp16_16(70.4688172043011 / FREQUENCY_RATE), - float_to_fp16_16(70.5446716899892 / FREQUENCY_RATE), - float_to_fp16_16(70.6206896551724 / FREQUENCY_RATE), - float_to_fp16_16(70.6968716289105 / FREQUENCY_RATE), - float_to_fp16_16(70.7732181425486 / FREQUENCY_RATE), - float_to_fp16_16(70.8497297297297 / FREQUENCY_RATE), - float_to_fp16_16(70.9264069264069 / FREQUENCY_RATE), - float_to_fp16_16(71.0032502708559 / FREQUENCY_RATE), - float_to_fp16_16(71.0802603036876 / FREQUENCY_RATE), - float_to_fp16_16(71.157437567861 / FREQUENCY_RATE), - float_to_fp16_16(71.2347826086957 / FREQUENCY_RATE), - float_to_fp16_16(71.3122959738847 / FREQUENCY_RATE), - float_to_fp16_16(71.3899782135076 / FREQUENCY_RATE), - float_to_fp16_16(71.4678298800436 / FREQUENCY_RATE), - float_to_fp16_16(71.5458515283843 / FREQUENCY_RATE), - float_to_fp16_16(71.624043715847 / FREQUENCY_RATE), - float_to_fp16_16(71.7024070021882 / FREQUENCY_RATE), - float_to_fp16_16(71.7809419496166 / FREQUENCY_RATE), - float_to_fp16_16(71.859649122807 / FREQUENCY_RATE), - float_to_fp16_16(71.9385290889133 / FREQUENCY_RATE), - float_to_fp16_16(72.0175824175824 / FREQUENCY_RATE), - float_to_fp16_16(72.0968096809681 / FREQUENCY_RATE), - float_to_fp16_16(72.1762114537445 / FREQUENCY_RATE), - float_to_fp16_16(72.2557883131202 / FREQUENCY_RATE), - float_to_fp16_16(72.3355408388521 / FREQUENCY_RATE), - float_to_fp16_16(72.4154696132597 / FREQUENCY_RATE), - float_to_fp16_16(72.4955752212389 / FREQUENCY_RATE), - float_to_fp16_16(72.5758582502769 / FREQUENCY_RATE), - float_to_fp16_16(72.6563192904656 / FREQUENCY_RATE), - float_to_fp16_16(72.7369589345172 / FREQUENCY_RATE), - float_to_fp16_16(72.8177777777778 / FREQUENCY_RATE), - float_to_fp16_16(72.8987764182425 / FREQUENCY_RATE), - float_to_fp16_16(72.9799554565702 / FREQUENCY_RATE), - float_to_fp16_16(73.0613154960981 / FREQUENCY_RATE), - float_to_fp16_16(73.1428571428571 / FREQUENCY_RATE), - float_to_fp16_16(73.2245810055866 / FREQUENCY_RATE), - float_to_fp16_16(73.3064876957494 / FREQUENCY_RATE), - float_to_fp16_16(73.3885778275476 / FREQUENCY_RATE), - float_to_fp16_16(73.4708520179372 / FREQUENCY_RATE), - float_to_fp16_16(73.5533108866442 / FREQUENCY_RATE), - float_to_fp16_16(73.6359550561798 / FREQUENCY_RATE), - float_to_fp16_16(73.718785151856 / FREQUENCY_RATE), - float_to_fp16_16(73.8018018018018 / FREQUENCY_RATE), - float_to_fp16_16(73.8850056369786 / FREQUENCY_RATE), - float_to_fp16_16(73.9683972911964 / FREQUENCY_RATE), - float_to_fp16_16(74.0519774011299 / FREQUENCY_RATE), - float_to_fp16_16(74.1357466063348 / FREQUENCY_RATE), - float_to_fp16_16(74.2197055492639 / FREQUENCY_RATE), - float_to_fp16_16(74.3038548752835 / FREQUENCY_RATE), - float_to_fp16_16(74.3881952326901 / FREQUENCY_RATE), - float_to_fp16_16(74.4727272727273 / FREQUENCY_RATE), - float_to_fp16_16(74.5574516496018 / FREQUENCY_RATE), - float_to_fp16_16(74.6423690205011 / FREQUENCY_RATE), - float_to_fp16_16(74.72748004561 / FREQUENCY_RATE), - float_to_fp16_16(74.8127853881279 / FREQUENCY_RATE), - float_to_fp16_16(74.8982857142857 / FREQUENCY_RATE), - float_to_fp16_16(74.9839816933639 / FREQUENCY_RATE), - float_to_fp16_16(75.0698739977091 / FREQUENCY_RATE), - float_to_fp16_16(75.1559633027523 / FREQUENCY_RATE), - float_to_fp16_16(75.2422502870264 / FREQUENCY_RATE), - float_to_fp16_16(75.3287356321839 / FREQUENCY_RATE), - float_to_fp16_16(75.415420023015 / FREQUENCY_RATE), - float_to_fp16_16(75.5023041474654 / FREQUENCY_RATE), - float_to_fp16_16(75.5893886966551 / FREQUENCY_RATE), - float_to_fp16_16(75.6766743648961 / FREQUENCY_RATE), - float_to_fp16_16(75.764161849711 / FREQUENCY_RATE), - float_to_fp16_16(75.8518518518518 / FREQUENCY_RATE), - float_to_fp16_16(75.9397450753187 / FREQUENCY_RATE), - float_to_fp16_16(76.0278422273782 / FREQUENCY_RATE), - float_to_fp16_16(76.116144018583 / FREQUENCY_RATE), - float_to_fp16_16(76.2046511627907 / FREQUENCY_RATE), - float_to_fp16_16(76.2933643771828 / FREQUENCY_RATE), - float_to_fp16_16(76.3822843822844 / FREQUENCY_RATE), - float_to_fp16_16(76.4714119019837 / FREQUENCY_RATE), - float_to_fp16_16(76.5607476635514 / FREQUENCY_RATE), - float_to_fp16_16(76.6502923976608 / FREQUENCY_RATE), - float_to_fp16_16(76.7400468384075 / FREQUENCY_RATE), - float_to_fp16_16(76.8300117233294 / FREQUENCY_RATE), - float_to_fp16_16(76.9201877934272 / FREQUENCY_RATE), - float_to_fp16_16(77.0105757931845 / FREQUENCY_RATE), - float_to_fp16_16(77.1011764705882 / FREQUENCY_RATE), - float_to_fp16_16(77.1919905771496 / FREQUENCY_RATE), - float_to_fp16_16(77.2830188679245 / FREQUENCY_RATE), - float_to_fp16_16(77.3742621015348 / FREQUENCY_RATE), - float_to_fp16_16(77.4657210401891 / FREQUENCY_RATE), - float_to_fp16_16(77.5573964497041 / FREQUENCY_RATE), - float_to_fp16_16(77.6492890995261 / FREQUENCY_RATE), - float_to_fp16_16(77.7413997627521 / FREQUENCY_RATE), - float_to_fp16_16(77.833729216152 / FREQUENCY_RATE), - float_to_fp16_16(77.9262782401902 / FREQUENCY_RATE), - float_to_fp16_16(78.0190476190476 / FREQUENCY_RATE), - float_to_fp16_16(78.1120381406436 / FREQUENCY_RATE), - float_to_fp16_16(78.2052505966587 / FREQUENCY_RATE), - float_to_fp16_16(78.2986857825568 / FREQUENCY_RATE), - float_to_fp16_16(78.3923444976077 / FREQUENCY_RATE), - float_to_fp16_16(78.4862275449102 / FREQUENCY_RATE), - float_to_fp16_16(78.5803357314149 / FREQUENCY_RATE), - float_to_fp16_16(78.6746698679472 / FREQUENCY_RATE), - float_to_fp16_16(78.7692307692308 / FREQUENCY_RATE), - float_to_fp16_16(78.864019253911 / FREQUENCY_RATE), - float_to_fp16_16(78.9590361445783 / FREQUENCY_RATE), - float_to_fp16_16(79.0542822677925 / FREQUENCY_RATE), - float_to_fp16_16(79.1497584541063 / FREQUENCY_RATE), - float_to_fp16_16(79.2454655380895 / FREQUENCY_RATE), - float_to_fp16_16(79.3414043583535 / FREQUENCY_RATE), - float_to_fp16_16(79.4375757575758 / FREQUENCY_RATE), - float_to_fp16_16(79.5339805825243 / FREQUENCY_RATE), - float_to_fp16_16(79.6306196840826 / FREQUENCY_RATE), - float_to_fp16_16(79.7274939172749 / FREQUENCY_RATE), - float_to_fp16_16(79.8246041412911 / FREQUENCY_RATE), - float_to_fp16_16(79.9219512195122 / FREQUENCY_RATE), - float_to_fp16_16(80.019536019536 / FREQUENCY_RATE), - float_to_fp16_16(80.1173594132029 / FREQUENCY_RATE), - float_to_fp16_16(80.2154222766218 / FREQUENCY_RATE), - float_to_fp16_16(80.3137254901961 / FREQUENCY_RATE), - float_to_fp16_16(80.4122699386503 / FREQUENCY_RATE), - float_to_fp16_16(80.5110565110565 / FREQUENCY_RATE), - float_to_fp16_16(80.610086100861 / FREQUENCY_RATE), - float_to_fp16_16(80.7093596059113 / FREQUENCY_RATE), - float_to_fp16_16(80.8088779284834 / FREQUENCY_RATE), - float_to_fp16_16(80.9086419753086 / FREQUENCY_RATE), - float_to_fp16_16(81.008652657602 / FREQUENCY_RATE), - float_to_fp16_16(81.1089108910891 / FREQUENCY_RATE), - float_to_fp16_16(81.2094175960347 / FREQUENCY_RATE), - float_to_fp16_16(81.3101736972705 / FREQUENCY_RATE), - float_to_fp16_16(81.4111801242236 / FREQUENCY_RATE), - float_to_fp16_16(81.5124378109453 / FREQUENCY_RATE), - float_to_fp16_16(81.6139476961395 / FREQUENCY_RATE), - float_to_fp16_16(81.715710723192 / FREQUENCY_RATE), - float_to_fp16_16(81.8177278401998 / FREQUENCY_RATE), - float_to_fp16_16(81.92 / FREQUENCY_RATE), - float_to_fp16_16(82.0225281602002 / FREQUENCY_RATE), - float_to_fp16_16(82.125313283208 / FREQUENCY_RATE), - float_to_fp16_16(82.228356336261 / FREQUENCY_RATE), - float_to_fp16_16(82.3316582914573 / FREQUENCY_RATE), - float_to_fp16_16(82.4352201257862 / FREQUENCY_RATE), - float_to_fp16_16(82.5390428211587 / FREQUENCY_RATE), - float_to_fp16_16(82.6431273644388 / FREQUENCY_RATE), - float_to_fp16_16(82.7474747474748 / FREQUENCY_RATE), - float_to_fp16_16(82.8520859671302 / FREQUENCY_RATE), - float_to_fp16_16(82.9569620253165 / FREQUENCY_RATE), - float_to_fp16_16(83.0621039290241 / FREQUENCY_RATE), - float_to_fp16_16(83.1675126903553 / FREQUENCY_RATE), - float_to_fp16_16(83.2731893265565 / FREQUENCY_RATE), - float_to_fp16_16(83.3791348600509 / FREQUENCY_RATE), - float_to_fp16_16(83.4853503184713 / FREQUENCY_RATE), - float_to_fp16_16(83.5918367346939 / FREQUENCY_RATE), - float_to_fp16_16(83.698595146871 / FREQUENCY_RATE), - float_to_fp16_16(83.8056265984655 / FREQUENCY_RATE), - float_to_fp16_16(83.9129321382842 / FREQUENCY_RATE), - float_to_fp16_16(84.0205128205128 / FREQUENCY_RATE), - float_to_fp16_16(84.1283697047497 / FREQUENCY_RATE), - float_to_fp16_16(84.2365038560411 / FREQUENCY_RATE), - float_to_fp16_16(84.3449163449163 / FREQUENCY_RATE), - float_to_fp16_16(84.4536082474227 / FREQUENCY_RATE), - float_to_fp16_16(84.5625806451613 / FREQUENCY_RATE), - float_to_fp16_16(84.671834625323 / FREQUENCY_RATE), - float_to_fp16_16(84.7813712807245 / FREQUENCY_RATE), - float_to_fp16_16(84.8911917098446 / FREQUENCY_RATE), - float_to_fp16_16(85.0012970168612 / FREQUENCY_RATE), - float_to_fp16_16(85.1116883116883 / FREQUENCY_RATE), - float_to_fp16_16(85.222366710013 / FREQUENCY_RATE), - float_to_fp16_16(85.3333333333333 / FREQUENCY_RATE), - float_to_fp16_16(85.4445893089961 / FREQUENCY_RATE), - float_to_fp16_16(85.556135770235 / FREQUENCY_RATE), - float_to_fp16_16(85.6679738562091 / FREQUENCY_RATE), - float_to_fp16_16(85.7801047120419 / FREQUENCY_RATE), - float_to_fp16_16(85.8925294888598 / FREQUENCY_RATE), - float_to_fp16_16(86.005249343832 / FREQUENCY_RATE), - float_to_fp16_16(86.1182654402102 / FREQUENCY_RATE), - float_to_fp16_16(86.2315789473684 / FREQUENCY_RATE), - float_to_fp16_16(86.3451910408432 / FREQUENCY_RATE), - float_to_fp16_16(86.4591029023747 / FREQUENCY_RATE), - float_to_fp16_16(86.5733157199472 / FREQUENCY_RATE), - float_to_fp16_16(86.6878306878307 / FREQUENCY_RATE), - float_to_fp16_16(86.8026490066225 / FREQUENCY_RATE), - float_to_fp16_16(86.9177718832891 / FREQUENCY_RATE), - float_to_fp16_16(87.0332005312085 / FREQUENCY_RATE), - float_to_fp16_16(87.1489361702128 / FREQUENCY_RATE), - float_to_fp16_16(87.2649800266312 / FREQUENCY_RATE), - float_to_fp16_16(87.3813333333333 / FREQUENCY_RATE), - float_to_fp16_16(87.497997329773 / FREQUENCY_RATE), - float_to_fp16_16(87.6149732620321 / FREQUENCY_RATE), - float_to_fp16_16(87.7322623828648 / FREQUENCY_RATE), - float_to_fp16_16(87.8498659517426 / FREQUENCY_RATE), - float_to_fp16_16(87.9677852348993 / FREQUENCY_RATE), - float_to_fp16_16(88.0860215053763 / FREQUENCY_RATE), - float_to_fp16_16(88.2045760430686 / FREQUENCY_RATE), - float_to_fp16_16(88.3234501347709 / FREQUENCY_RATE), - float_to_fp16_16(88.442645074224 / FREQUENCY_RATE), - float_to_fp16_16(88.5621621621622 / FREQUENCY_RATE), - float_to_fp16_16(88.68200270636 / FREQUENCY_RATE), - float_to_fp16_16(88.8021680216802 / FREQUENCY_RATE), - float_to_fp16_16(88.9226594301221 / FREQUENCY_RATE), - float_to_fp16_16(89.0434782608696 / FREQUENCY_RATE), - float_to_fp16_16(89.1646258503401 / FREQUENCY_RATE), - float_to_fp16_16(89.2861035422343 / FREQUENCY_RATE), - float_to_fp16_16(89.4079126875853 / FREQUENCY_RATE), - float_to_fp16_16(89.5300546448087 / FREQUENCY_RATE), - float_to_fp16_16(89.6525307797538 / FREQUENCY_RATE), - float_to_fp16_16(89.7753424657534 / FREQUENCY_RATE), - float_to_fp16_16(89.8984910836763 / FREQUENCY_RATE), - float_to_fp16_16(90.021978021978 / FREQUENCY_RATE), - float_to_fp16_16(90.1458046767538 / FREQUENCY_RATE), - float_to_fp16_16(90.2699724517906 / FREQUENCY_RATE), - float_to_fp16_16(90.3944827586207 / FREQUENCY_RATE), - float_to_fp16_16(90.5193370165746 / FREQUENCY_RATE), - float_to_fp16_16(90.6445366528354 / FREQUENCY_RATE), - float_to_fp16_16(90.7700831024931 / FREQUENCY_RATE), - float_to_fp16_16(90.8959778085992 / FREQUENCY_RATE), - float_to_fp16_16(91.0222222222222 / FREQUENCY_RATE), - float_to_fp16_16(91.1488178025035 / FREQUENCY_RATE), - float_to_fp16_16(91.2757660167131 / FREQUENCY_RATE), - float_to_fp16_16(91.4030683403068 / FREQUENCY_RATE), - float_to_fp16_16(91.5307262569833 / FREQUENCY_RATE), - float_to_fp16_16(91.6587412587413 / FREQUENCY_RATE), - float_to_fp16_16(91.7871148459384 / FREQUENCY_RATE), - float_to_fp16_16(91.9158485273492 / FREQUENCY_RATE), - float_to_fp16_16(92.0449438202247 / FREQUENCY_RATE), - float_to_fp16_16(92.1744022503516 / FREQUENCY_RATE), - float_to_fp16_16(92.3042253521127 / FREQUENCY_RATE), - float_to_fp16_16(92.4344146685472 / FREQUENCY_RATE), - float_to_fp16_16(92.5649717514124 / FREQUENCY_RATE), - float_to_fp16_16(92.6958981612447 / FREQUENCY_RATE), - float_to_fp16_16(92.8271954674221 / FREQUENCY_RATE), - float_to_fp16_16(92.958865248227 / FREQUENCY_RATE), - float_to_fp16_16(93.0909090909091 / FREQUENCY_RATE), - float_to_fp16_16(93.2233285917497 / FREQUENCY_RATE), - float_to_fp16_16(93.3561253561254 / FREQUENCY_RATE), - float_to_fp16_16(93.4893009985735 / FREQUENCY_RATE), - float_to_fp16_16(93.6228571428572 / FREQUENCY_RATE), - float_to_fp16_16(93.7567954220315 / FREQUENCY_RATE), - float_to_fp16_16(93.89111747851 / FREQUENCY_RATE), - float_to_fp16_16(94.025824964132 / FREQUENCY_RATE), - float_to_fp16_16(94.1609195402299 / FREQUENCY_RATE), - float_to_fp16_16(94.2964028776978 / FREQUENCY_RATE), - float_to_fp16_16(94.4322766570605 / FREQUENCY_RATE), - float_to_fp16_16(94.5685425685426 / FREQUENCY_RATE), - float_to_fp16_16(94.7052023121387 / FREQUENCY_RATE), - float_to_fp16_16(94.8422575976845 / FREQUENCY_RATE), - float_to_fp16_16(94.9797101449275 / FREQUENCY_RATE), - float_to_fp16_16(95.1175616835994 / FREQUENCY_RATE), - float_to_fp16_16(95.2558139534884 / FREQUENCY_RATE), - float_to_fp16_16(95.3944687045124 / FREQUENCY_RATE), - float_to_fp16_16(95.533527696793 / FREQUENCY_RATE), - float_to_fp16_16(95.6729927007299 / FREQUENCY_RATE), - float_to_fp16_16(95.812865497076 / FREQUENCY_RATE), - float_to_fp16_16(95.9531478770132 / FREQUENCY_RATE), - float_to_fp16_16(96.0938416422287 / FREQUENCY_RATE), - float_to_fp16_16(96.2349486049927 / FREQUENCY_RATE), - float_to_fp16_16(96.3764705882353 / FREQUENCY_RATE), - float_to_fp16_16(96.5184094256259 / FREQUENCY_RATE), - float_to_fp16_16(96.6607669616519 / FREQUENCY_RATE), - float_to_fp16_16(96.8035450516987 / FREQUENCY_RATE), - float_to_fp16_16(96.9467455621302 / FREQUENCY_RATE), - float_to_fp16_16(97.0903703703704 / FREQUENCY_RATE), - float_to_fp16_16(97.2344213649852 / FREQUENCY_RATE), - float_to_fp16_16(97.3789004457652 / FREQUENCY_RATE), - float_to_fp16_16(97.5238095238095 / FREQUENCY_RATE), - float_to_fp16_16(97.6691505216095 / FREQUENCY_RATE), - float_to_fp16_16(97.8149253731343 / FREQUENCY_RATE), - float_to_fp16_16(97.9611360239163 / FREQUENCY_RATE), - float_to_fp16_16(98.1077844311377 / FREQUENCY_RATE), - float_to_fp16_16(98.2548725637181 / FREQUENCY_RATE), - float_to_fp16_16(98.4024024024024 / FREQUENCY_RATE), - float_to_fp16_16(98.5503759398496 / FREQUENCY_RATE), - float_to_fp16_16(98.6987951807229 / FREQUENCY_RATE), - float_to_fp16_16(98.8476621417798 / FREQUENCY_RATE), - float_to_fp16_16(98.9969788519637 / FREQUENCY_RATE), - float_to_fp16_16(99.1467473524962 / FREQUENCY_RATE), - float_to_fp16_16(99.2969696969697 / FREQUENCY_RATE), - float_to_fp16_16(99.4476479514416 / FREQUENCY_RATE), - float_to_fp16_16(99.5987841945289 / FREQUENCY_RATE), - float_to_fp16_16(99.7503805175038 / FREQUENCY_RATE), - float_to_fp16_16(99.9024390243902 / FREQUENCY_RATE), - float_to_fp16_16(100.054961832061 / FREQUENCY_RATE), - float_to_fp16_16(100.207951070336 / FREQUENCY_RATE), - float_to_fp16_16(100.361408882083 / FREQUENCY_RATE), - float_to_fp16_16(100.515337423313 / FREQUENCY_RATE), - float_to_fp16_16(100.669738863287 / FREQUENCY_RATE), - float_to_fp16_16(100.824615384615 / FREQUENCY_RATE), - float_to_fp16_16(100.979969183359 / FREQUENCY_RATE), - float_to_fp16_16(101.135802469136 / FREQUENCY_RATE), - float_to_fp16_16(101.292117465224 / FREQUENCY_RATE), - float_to_fp16_16(101.448916408669 / FREQUENCY_RATE), - float_to_fp16_16(101.606201550388 / FREQUENCY_RATE), - float_to_fp16_16(101.76397515528 / FREQUENCY_RATE), - float_to_fp16_16(101.922239502333 / FREQUENCY_RATE), - float_to_fp16_16(102.080996884735 / FREQUENCY_RATE), - float_to_fp16_16(102.240249609984 / FREQUENCY_RATE), - float_to_fp16_16(102.4 / FREQUENCY_RATE), - float_to_fp16_16(102.560250391236 / FREQUENCY_RATE), - float_to_fp16_16(102.721003134796 / FREQUENCY_RATE), - float_to_fp16_16(102.882260596546 / FREQUENCY_RATE), - float_to_fp16_16(103.044025157233 / FREQUENCY_RATE), - float_to_fp16_16(103.206299212598 / FREQUENCY_RATE), - float_to_fp16_16(103.369085173502 / FREQUENCY_RATE), - float_to_fp16_16(103.532385466035 / FREQUENCY_RATE), - float_to_fp16_16(103.696202531646 / FREQUENCY_RATE), - float_to_fp16_16(103.860538827258 / FREQUENCY_RATE), - float_to_fp16_16(104.025396825397 / FREQUENCY_RATE), - float_to_fp16_16(104.190779014308 / FREQUENCY_RATE), - float_to_fp16_16(104.356687898089 / FREQUENCY_RATE), - float_to_fp16_16(104.52312599681 / FREQUENCY_RATE), - float_to_fp16_16(104.690095846645 / FREQUENCY_RATE), - float_to_fp16_16(104.8576 / FREQUENCY_RATE), - float_to_fp16_16(105.025641025641 / FREQUENCY_RATE), - float_to_fp16_16(105.194221508828 / FREQUENCY_RATE), - float_to_fp16_16(105.363344051447 / FREQUENCY_RATE), - float_to_fp16_16(105.533011272142 / FREQUENCY_RATE), - float_to_fp16_16(105.703225806452 / FREQUENCY_RATE), - float_to_fp16_16(105.873990306947 / FREQUENCY_RATE), - float_to_fp16_16(106.045307443366 / FREQUENCY_RATE), - float_to_fp16_16(106.217179902755 / FREQUENCY_RATE), - float_to_fp16_16(106.38961038961 / FREQUENCY_RATE), - float_to_fp16_16(106.562601626016 / FREQUENCY_RATE), - float_to_fp16_16(106.736156351792 / FREQUENCY_RATE), - float_to_fp16_16(106.910277324633 / FREQUENCY_RATE), - float_to_fp16_16(107.084967320261 / FREQUENCY_RATE), - float_to_fp16_16(107.26022913257 / FREQUENCY_RATE), - float_to_fp16_16(107.436065573771 / FREQUENCY_RATE), - float_to_fp16_16(107.612479474548 / FREQUENCY_RATE), - float_to_fp16_16(107.789473684211 / FREQUENCY_RATE), - float_to_fp16_16(107.96705107084 / FREQUENCY_RATE), - float_to_fp16_16(108.145214521452 / FREQUENCY_RATE), - float_to_fp16_16(108.323966942149 / FREQUENCY_RATE), - float_to_fp16_16(108.503311258278 / FREQUENCY_RATE), - float_to_fp16_16(108.683250414594 / FREQUENCY_RATE), - float_to_fp16_16(108.863787375415 / FREQUENCY_RATE), - float_to_fp16_16(109.044925124792 / FREQUENCY_RATE), - float_to_fp16_16(109.226666666667 / FREQUENCY_RATE), - float_to_fp16_16(109.409015025042 / FREQUENCY_RATE), - float_to_fp16_16(109.591973244147 / FREQUENCY_RATE), - float_to_fp16_16(109.77554438861 / FREQUENCY_RATE), - float_to_fp16_16(109.959731543624 / FREQUENCY_RATE), - float_to_fp16_16(110.144537815126 / FREQUENCY_RATE), - float_to_fp16_16(110.329966329966 / FREQUENCY_RATE), - float_to_fp16_16(110.516020236088 / FREQUENCY_RATE), - float_to_fp16_16(110.702702702703 / FREQUENCY_RATE), - float_to_fp16_16(110.890016920474 / FREQUENCY_RATE), - float_to_fp16_16(111.077966101695 / FREQUENCY_RATE), - float_to_fp16_16(111.266553480475 / FREQUENCY_RATE), - float_to_fp16_16(111.455782312925 / FREQUENCY_RATE), - float_to_fp16_16(111.645655877342 / FREQUENCY_RATE), - float_to_fp16_16(111.836177474403 / FREQUENCY_RATE), - float_to_fp16_16(112.02735042735 / FREQUENCY_RATE), - float_to_fp16_16(112.219178082192 / FREQUENCY_RATE), - float_to_fp16_16(112.41166380789 / FREQUENCY_RATE), - float_to_fp16_16(112.604810996564 / FREQUENCY_RATE), - float_to_fp16_16(112.798623063683 / FREQUENCY_RATE), - float_to_fp16_16(112.993103448276 / FREQUENCY_RATE), - float_to_fp16_16(113.188255613126 / FREQUENCY_RATE), - float_to_fp16_16(113.384083044983 / FREQUENCY_RATE), - float_to_fp16_16(113.580589254766 / FREQUENCY_RATE), - float_to_fp16_16(113.777777777778 / FREQUENCY_RATE), - float_to_fp16_16(113.975652173913 / FREQUENCY_RATE), - float_to_fp16_16(114.174216027875 / FREQUENCY_RATE), - float_to_fp16_16(114.373472949389 / FREQUENCY_RATE), - float_to_fp16_16(114.573426573427 / FREQUENCY_RATE), - float_to_fp16_16(114.77408056042 / FREQUENCY_RATE), - float_to_fp16_16(114.975438596491 / FREQUENCY_RATE), - float_to_fp16_16(115.177504393673 / FREQUENCY_RATE), - float_to_fp16_16(115.380281690141 / FREQUENCY_RATE), - float_to_fp16_16(115.583774250441 / FREQUENCY_RATE), - float_to_fp16_16(115.787985865724 / FREQUENCY_RATE), - float_to_fp16_16(115.992920353982 / FREQUENCY_RATE), - float_to_fp16_16(116.198581560284 / FREQUENCY_RATE), - float_to_fp16_16(116.404973357016 / FREQUENCY_RATE), - float_to_fp16_16(116.612099644128 / FREQUENCY_RATE), - float_to_fp16_16(116.819964349376 / FREQUENCY_RATE), - float_to_fp16_16(117.028571428571 / FREQUENCY_RATE), - float_to_fp16_16(117.237924865832 / FREQUENCY_RATE), - float_to_fp16_16(117.448028673835 / FREQUENCY_RATE), - float_to_fp16_16(117.658886894075 / FREQUENCY_RATE), - float_to_fp16_16(117.870503597122 / FREQUENCY_RATE), - float_to_fp16_16(118.082882882883 / FREQUENCY_RATE), - float_to_fp16_16(118.296028880866 / FREQUENCY_RATE), - float_to_fp16_16(118.509945750452 / FREQUENCY_RATE), - float_to_fp16_16(118.724637681159 / FREQUENCY_RATE), - float_to_fp16_16(118.940108892922 / FREQUENCY_RATE), - float_to_fp16_16(119.156363636364 / FREQUENCY_RATE), - float_to_fp16_16(119.373406193078 / FREQUENCY_RATE), - float_to_fp16_16(119.591240875912 / FREQUENCY_RATE), - float_to_fp16_16(119.80987202925 / FREQUENCY_RATE), - float_to_fp16_16(120.029304029304 / FREQUENCY_RATE), - float_to_fp16_16(120.249541284404 / FREQUENCY_RATE), - float_to_fp16_16(120.470588235294 / FREQUENCY_RATE), - float_to_fp16_16(120.692449355433 / FREQUENCY_RATE), - float_to_fp16_16(120.915129151292 / FREQUENCY_RATE), - float_to_fp16_16(121.138632162662 / FREQUENCY_RATE), - float_to_fp16_16(121.362962962963 / FREQUENCY_RATE), - float_to_fp16_16(121.588126159555 / FREQUENCY_RATE), - float_to_fp16_16(121.814126394052 / FREQUENCY_RATE), - float_to_fp16_16(122.040968342644 / FREQUENCY_RATE), - float_to_fp16_16(122.268656716418 / FREQUENCY_RATE), - float_to_fp16_16(122.497196261682 / FREQUENCY_RATE), - float_to_fp16_16(122.7265917603 / FREQUENCY_RATE), - float_to_fp16_16(122.956848030019 / FREQUENCY_RATE), - float_to_fp16_16(123.187969924812 / FREQUENCY_RATE), - float_to_fp16_16(123.419962335217 / FREQUENCY_RATE), - float_to_fp16_16(123.652830188679 / FREQUENCY_RATE), - float_to_fp16_16(123.886578449906 / FREQUENCY_RATE), - float_to_fp16_16(124.121212121212 / FREQUENCY_RATE), - float_to_fp16_16(124.356736242884 / FREQUENCY_RATE), - float_to_fp16_16(124.593155893536 / FREQUENCY_RATE), - float_to_fp16_16(124.830476190476 / FREQUENCY_RATE), - float_to_fp16_16(125.068702290076 / FREQUENCY_RATE), - float_to_fp16_16(125.307839388145 / FREQUENCY_RATE), - float_to_fp16_16(125.547892720307 / FREQUENCY_RATE), - float_to_fp16_16(125.78886756238 / FREQUENCY_RATE), - float_to_fp16_16(126.030769230769 / FREQUENCY_RATE), - float_to_fp16_16(126.273603082852 / FREQUENCY_RATE), - float_to_fp16_16(126.517374517375 / FREQUENCY_RATE), - float_to_fp16_16(126.762088974855 / FREQUENCY_RATE), - float_to_fp16_16(127.007751937985 / FREQUENCY_RATE), - float_to_fp16_16(127.254368932039 / FREQUENCY_RATE), - float_to_fp16_16(127.501945525292 / FREQUENCY_RATE), - float_to_fp16_16(127.750487329435 / FREQUENCY_RATE), - float_to_fp16_16(128 / FREQUENCY_RATE), - float_to_fp16_16(128.250489236791 / FREQUENCY_RATE), - float_to_fp16_16(128.501960784314 / FREQUENCY_RATE), - float_to_fp16_16(128.75442043222 / FREQUENCY_RATE), - float_to_fp16_16(129.007874015748 / FREQUENCY_RATE), - float_to_fp16_16(129.262327416174 / FREQUENCY_RATE), - float_to_fp16_16(129.517786561265 / FREQUENCY_RATE), - float_to_fp16_16(129.774257425743 / FREQUENCY_RATE), - float_to_fp16_16(130.031746031746 / FREQUENCY_RATE), - float_to_fp16_16(130.290258449304 / FREQUENCY_RATE), - float_to_fp16_16(130.549800796813 / FREQUENCY_RATE), - float_to_fp16_16(130.810379241517 / FREQUENCY_RATE), - float_to_fp16_16(131.072 / FREQUENCY_RATE), - float_to_fp16_16(131.334669338677 / FREQUENCY_RATE), - float_to_fp16_16(131.598393574297 / FREQUENCY_RATE), - float_to_fp16_16(131.863179074447 / FREQUENCY_RATE), - float_to_fp16_16(132.129032258065 / FREQUENCY_RATE), - float_to_fp16_16(132.39595959596 / FREQUENCY_RATE), - float_to_fp16_16(132.663967611336 / FREQUENCY_RATE), - float_to_fp16_16(132.933062880325 / FREQUENCY_RATE), - float_to_fp16_16(133.20325203252 / FREQUENCY_RATE), - float_to_fp16_16(133.474541751527 / FREQUENCY_RATE), - float_to_fp16_16(133.74693877551 / FREQUENCY_RATE), - float_to_fp16_16(134.020449897751 / FREQUENCY_RATE), - float_to_fp16_16(134.295081967213 / FREQUENCY_RATE), - float_to_fp16_16(134.570841889117 / FREQUENCY_RATE), - float_to_fp16_16(134.847736625514 / FREQUENCY_RATE), - float_to_fp16_16(135.125773195876 / FREQUENCY_RATE), - float_to_fp16_16(135.404958677686 / FREQUENCY_RATE), - float_to_fp16_16(135.685300207039 / FREQUENCY_RATE), - float_to_fp16_16(135.966804979253 / FREQUENCY_RATE), - float_to_fp16_16(136.24948024948 / FREQUENCY_RATE), - float_to_fp16_16(136.533333333333 / FREQUENCY_RATE), - float_to_fp16_16(136.818371607516 / FREQUENCY_RATE), - float_to_fp16_16(137.10460251046 / FREQUENCY_RATE), - float_to_fp16_16(137.392033542977 / FREQUENCY_RATE), - float_to_fp16_16(137.680672268908 / FREQUENCY_RATE), - float_to_fp16_16(137.970526315789 / FREQUENCY_RATE), - float_to_fp16_16(138.261603375527 / FREQUENCY_RATE), - float_to_fp16_16(138.553911205074 / FREQUENCY_RATE), - float_to_fp16_16(138.847457627119 / FREQUENCY_RATE), - float_to_fp16_16(139.142250530786 / FREQUENCY_RATE), - float_to_fp16_16(139.43829787234 / FREQUENCY_RATE), - float_to_fp16_16(139.735607675906 / FREQUENCY_RATE), - float_to_fp16_16(140.034188034188 / FREQUENCY_RATE), - float_to_fp16_16(140.334047109208 / FREQUENCY_RATE), - float_to_fp16_16(140.635193133047 / FREQUENCY_RATE), - float_to_fp16_16(140.937634408602 / FREQUENCY_RATE), - float_to_fp16_16(141.241379310345 / FREQUENCY_RATE), - float_to_fp16_16(141.546436285097 / FREQUENCY_RATE), - float_to_fp16_16(141.852813852814 / FREQUENCY_RATE), - float_to_fp16_16(142.160520607375 / FREQUENCY_RATE), - float_to_fp16_16(142.469565217391 / FREQUENCY_RATE), - float_to_fp16_16(142.779956427015 / FREQUENCY_RATE), - float_to_fp16_16(143.091703056769 / FREQUENCY_RATE), - float_to_fp16_16(143.404814004376 / FREQUENCY_RATE), - float_to_fp16_16(143.719298245614 / FREQUENCY_RATE), - float_to_fp16_16(144.035164835165 / FREQUENCY_RATE), - float_to_fp16_16(144.352422907489 / FREQUENCY_RATE), - float_to_fp16_16(144.671081677704 / FREQUENCY_RATE), - float_to_fp16_16(144.991150442478 / FREQUENCY_RATE), - float_to_fp16_16(145.312638580931 / FREQUENCY_RATE), - float_to_fp16_16(145.635555555556 / FREQUENCY_RATE), - float_to_fp16_16(145.95991091314 / FREQUENCY_RATE), - float_to_fp16_16(146.285714285714 / FREQUENCY_RATE), - float_to_fp16_16(146.612975391499 / FREQUENCY_RATE), - float_to_fp16_16(146.941704035874 / FREQUENCY_RATE), - float_to_fp16_16(147.27191011236 / FREQUENCY_RATE), - float_to_fp16_16(147.603603603604 / FREQUENCY_RATE), - float_to_fp16_16(147.936794582393 / FREQUENCY_RATE), - float_to_fp16_16(148.27149321267 / FREQUENCY_RATE), - float_to_fp16_16(148.607709750567 / FREQUENCY_RATE), - float_to_fp16_16(148.945454545455 / FREQUENCY_RATE), - float_to_fp16_16(149.284738041002 / FREQUENCY_RATE), - float_to_fp16_16(149.625570776256 / FREQUENCY_RATE), - float_to_fp16_16(149.967963386728 / FREQUENCY_RATE), - float_to_fp16_16(150.311926605505 / FREQUENCY_RATE), - float_to_fp16_16(150.657471264368 / FREQUENCY_RATE), - float_to_fp16_16(151.004608294931 / FREQUENCY_RATE), - float_to_fp16_16(151.353348729792 / FREQUENCY_RATE), - float_to_fp16_16(151.703703703704 / FREQUENCY_RATE), - float_to_fp16_16(152.055684454756 / FREQUENCY_RATE), - float_to_fp16_16(152.409302325581 / FREQUENCY_RATE), - float_to_fp16_16(152.764568764569 / FREQUENCY_RATE), - float_to_fp16_16(153.121495327103 / FREQUENCY_RATE), - float_to_fp16_16(153.480093676815 / FREQUENCY_RATE), - float_to_fp16_16(153.840375586854 / FREQUENCY_RATE), - float_to_fp16_16(154.202352941176 / FREQUENCY_RATE), - float_to_fp16_16(154.566037735849 / FREQUENCY_RATE), - float_to_fp16_16(154.931442080378 / FREQUENCY_RATE), - float_to_fp16_16(155.298578199052 / FREQUENCY_RATE), - float_to_fp16_16(155.667458432304 / FREQUENCY_RATE), - float_to_fp16_16(156.038095238095 / FREQUENCY_RATE), - float_to_fp16_16(156.410501193317 / FREQUENCY_RATE), - float_to_fp16_16(156.784688995215 / FREQUENCY_RATE), - float_to_fp16_16(157.16067146283 / FREQUENCY_RATE), - float_to_fp16_16(157.538461538462 / FREQUENCY_RATE), - float_to_fp16_16(157.918072289157 / FREQUENCY_RATE), - float_to_fp16_16(158.299516908213 / FREQUENCY_RATE), - float_to_fp16_16(158.682808716707 / FREQUENCY_RATE), - float_to_fp16_16(159.067961165049 / FREQUENCY_RATE), - float_to_fp16_16(159.45498783455 / FREQUENCY_RATE), - float_to_fp16_16(159.843902439024 / FREQUENCY_RATE), - float_to_fp16_16(160.234718826406 / FREQUENCY_RATE), - float_to_fp16_16(160.627450980392 / FREQUENCY_RATE), - float_to_fp16_16(161.022113022113 / FREQUENCY_RATE), - float_to_fp16_16(161.418719211823 / FREQUENCY_RATE), - float_to_fp16_16(161.817283950617 / FREQUENCY_RATE), - float_to_fp16_16(162.217821782178 / FREQUENCY_RATE), - float_to_fp16_16(162.620347394541 / FREQUENCY_RATE), - float_to_fp16_16(163.024875621891 / FREQUENCY_RATE), - float_to_fp16_16(163.431421446384 / FREQUENCY_RATE), - float_to_fp16_16(163.84 / FREQUENCY_RATE), - float_to_fp16_16(164.250626566416 / FREQUENCY_RATE), - float_to_fp16_16(164.663316582915 / FREQUENCY_RATE), - float_to_fp16_16(165.078085642317 / FREQUENCY_RATE), - float_to_fp16_16(165.49494949495 / FREQUENCY_RATE), - float_to_fp16_16(165.913924050633 / FREQUENCY_RATE), - float_to_fp16_16(166.335025380711 / FREQUENCY_RATE), - float_to_fp16_16(166.758269720102 / FREQUENCY_RATE), - float_to_fp16_16(167.183673469388 / FREQUENCY_RATE), - float_to_fp16_16(167.611253196931 / FREQUENCY_RATE), - float_to_fp16_16(168.041025641026 / FREQUENCY_RATE), - float_to_fp16_16(168.473007712082 / FREQUENCY_RATE), - float_to_fp16_16(168.907216494845 / FREQUENCY_RATE), - float_to_fp16_16(169.343669250646 / FREQUENCY_RATE), - float_to_fp16_16(169.782383419689 / FREQUENCY_RATE), - float_to_fp16_16(170.223376623377 / FREQUENCY_RATE), - float_to_fp16_16(170.666666666667 / FREQUENCY_RATE), - float_to_fp16_16(171.11227154047 / FREQUENCY_RATE), - float_to_fp16_16(171.560209424084 / FREQUENCY_RATE), - float_to_fp16_16(172.010498687664 / FREQUENCY_RATE), - float_to_fp16_16(172.463157894737 / FREQUENCY_RATE), - float_to_fp16_16(172.918205804749 / FREQUENCY_RATE), - float_to_fp16_16(173.375661375661 / FREQUENCY_RATE), - float_to_fp16_16(173.835543766578 / FREQUENCY_RATE), - float_to_fp16_16(174.297872340426 / FREQUENCY_RATE), - float_to_fp16_16(174.762666666667 / FREQUENCY_RATE), - float_to_fp16_16(175.229946524064 / FREQUENCY_RATE), - float_to_fp16_16(175.699731903485 / FREQUENCY_RATE), - float_to_fp16_16(176.172043010753 / FREQUENCY_RATE), - float_to_fp16_16(176.646900269542 / FREQUENCY_RATE), - float_to_fp16_16(177.124324324324 / FREQUENCY_RATE), - float_to_fp16_16(177.60433604336 / FREQUENCY_RATE), - float_to_fp16_16(178.086956521739 / FREQUENCY_RATE), - float_to_fp16_16(178.572207084469 / FREQUENCY_RATE), - float_to_fp16_16(179.060109289618 / FREQUENCY_RATE), - float_to_fp16_16(179.550684931507 / FREQUENCY_RATE), - float_to_fp16_16(180.043956043956 / FREQUENCY_RATE), - float_to_fp16_16(180.539944903581 / FREQUENCY_RATE), - float_to_fp16_16(181.038674033149 / FREQUENCY_RATE), - float_to_fp16_16(181.540166204986 / FREQUENCY_RATE), - float_to_fp16_16(182.044444444444 / FREQUENCY_RATE), - float_to_fp16_16(182.551532033426 / FREQUENCY_RATE), - float_to_fp16_16(183.061452513966 / FREQUENCY_RATE), - float_to_fp16_16(183.574229691877 / FREQUENCY_RATE), - float_to_fp16_16(184.089887640449 / FREQUENCY_RATE), - float_to_fp16_16(184.608450704225 / FREQUENCY_RATE), - float_to_fp16_16(185.129943502825 / FREQUENCY_RATE), - float_to_fp16_16(185.654390934844 / FREQUENCY_RATE), - float_to_fp16_16(186.181818181818 / FREQUENCY_RATE), - float_to_fp16_16(186.712250712251 / FREQUENCY_RATE), - float_to_fp16_16(187.245714285714 / FREQUENCY_RATE), - float_to_fp16_16(187.78223495702 / FREQUENCY_RATE), - float_to_fp16_16(188.32183908046 / FREQUENCY_RATE), - float_to_fp16_16(188.864553314121 / FREQUENCY_RATE), - float_to_fp16_16(189.410404624277 / FREQUENCY_RATE), - float_to_fp16_16(189.959420289855 / FREQUENCY_RATE), - float_to_fp16_16(190.511627906977 / FREQUENCY_RATE), - float_to_fp16_16(191.067055393586 / FREQUENCY_RATE), - float_to_fp16_16(191.625730994152 / FREQUENCY_RATE), - float_to_fp16_16(192.187683284457 / FREQUENCY_RATE), - float_to_fp16_16(192.752941176471 / FREQUENCY_RATE), - float_to_fp16_16(193.321533923304 / FREQUENCY_RATE), - float_to_fp16_16(193.89349112426 / FREQUENCY_RATE), - float_to_fp16_16(194.46884272997 / FREQUENCY_RATE), - float_to_fp16_16(195.047619047619 / FREQUENCY_RATE), - float_to_fp16_16(195.629850746269 / FREQUENCY_RATE), - float_to_fp16_16(196.215568862275 / FREQUENCY_RATE), - float_to_fp16_16(196.804804804805 / FREQUENCY_RATE), - float_to_fp16_16(197.397590361446 / FREQUENCY_RATE), - float_to_fp16_16(197.993957703928 / FREQUENCY_RATE), - float_to_fp16_16(198.593939393939 / FREQUENCY_RATE), - float_to_fp16_16(199.197568389058 / FREQUENCY_RATE), - float_to_fp16_16(199.804878048781 / FREQUENCY_RATE), - float_to_fp16_16(200.415902140673 / FREQUENCY_RATE), - float_to_fp16_16(201.030674846626 / FREQUENCY_RATE), - float_to_fp16_16(201.649230769231 / FREQUENCY_RATE), - float_to_fp16_16(202.271604938272 / FREQUENCY_RATE), - float_to_fp16_16(202.897832817337 / FREQUENCY_RATE), - float_to_fp16_16(203.527950310559 / FREQUENCY_RATE), - float_to_fp16_16(204.16199376947 / FREQUENCY_RATE), - float_to_fp16_16(204.8 / FREQUENCY_RATE), - float_to_fp16_16(205.442006269592 / FREQUENCY_RATE), - float_to_fp16_16(206.088050314465 / FREQUENCY_RATE), - float_to_fp16_16(206.738170347003 / FREQUENCY_RATE), - float_to_fp16_16(207.392405063291 / FREQUENCY_RATE), - float_to_fp16_16(208.050793650794 / FREQUENCY_RATE), - float_to_fp16_16(208.713375796178 / FREQUENCY_RATE), - float_to_fp16_16(209.380191693291 / FREQUENCY_RATE), - float_to_fp16_16(210.051282051282 / FREQUENCY_RATE), - float_to_fp16_16(210.726688102894 / FREQUENCY_RATE), - float_to_fp16_16(211.406451612903 / FREQUENCY_RATE), - float_to_fp16_16(212.090614886731 / FREQUENCY_RATE), - float_to_fp16_16(212.779220779221 / FREQUENCY_RATE), - float_to_fp16_16(213.472312703583 / FREQUENCY_RATE), - float_to_fp16_16(214.169934640523 / FREQUENCY_RATE), - float_to_fp16_16(214.872131147541 / FREQUENCY_RATE), - float_to_fp16_16(215.578947368421 / FREQUENCY_RATE), - float_to_fp16_16(216.290429042904 / FREQUENCY_RATE), - float_to_fp16_16(217.006622516556 / FREQUENCY_RATE), - float_to_fp16_16(217.727574750831 / FREQUENCY_RATE), - float_to_fp16_16(218.453333333333 / FREQUENCY_RATE), - float_to_fp16_16(219.183946488294 / FREQUENCY_RATE), - float_to_fp16_16(219.919463087248 / FREQUENCY_RATE), - float_to_fp16_16(220.659932659933 / FREQUENCY_RATE), - float_to_fp16_16(221.405405405405 / FREQUENCY_RATE), - float_to_fp16_16(222.15593220339 / FREQUENCY_RATE), - float_to_fp16_16(222.91156462585 / FREQUENCY_RATE), - float_to_fp16_16(223.672354948805 / FREQUENCY_RATE), - float_to_fp16_16(224.438356164384 / FREQUENCY_RATE), - float_to_fp16_16(225.209621993127 / FREQUENCY_RATE), - float_to_fp16_16(225.986206896552 / FREQUENCY_RATE), - float_to_fp16_16(226.768166089965 / FREQUENCY_RATE), - float_to_fp16_16(227.555555555556 / FREQUENCY_RATE), - float_to_fp16_16(228.348432055749 / FREQUENCY_RATE), - float_to_fp16_16(229.146853146853 / FREQUENCY_RATE), - float_to_fp16_16(229.950877192982 / FREQUENCY_RATE), - float_to_fp16_16(230.760563380282 / FREQUENCY_RATE), - float_to_fp16_16(231.575971731449 / FREQUENCY_RATE), - float_to_fp16_16(232.397163120567 / FREQUENCY_RATE), - float_to_fp16_16(233.224199288256 / FREQUENCY_RATE), - float_to_fp16_16(234.057142857143 / FREQUENCY_RATE), - float_to_fp16_16(234.89605734767 / FREQUENCY_RATE), - float_to_fp16_16(235.741007194245 / FREQUENCY_RATE), - float_to_fp16_16(236.592057761733 / FREQUENCY_RATE), - float_to_fp16_16(237.449275362319 / FREQUENCY_RATE), - float_to_fp16_16(238.312727272727 / FREQUENCY_RATE), - float_to_fp16_16(239.182481751825 / FREQUENCY_RATE), - float_to_fp16_16(240.058608058608 / FREQUENCY_RATE), - float_to_fp16_16(240.941176470588 / FREQUENCY_RATE), - float_to_fp16_16(241.830258302583 / FREQUENCY_RATE), - float_to_fp16_16(242.725925925926 / FREQUENCY_RATE), - float_to_fp16_16(243.628252788104 / FREQUENCY_RATE), - float_to_fp16_16(244.537313432836 / FREQUENCY_RATE), - float_to_fp16_16(245.453183520599 / FREQUENCY_RATE), - float_to_fp16_16(246.375939849624 / FREQUENCY_RATE), - float_to_fp16_16(247.305660377358 / FREQUENCY_RATE), - float_to_fp16_16(248.242424242424 / FREQUENCY_RATE), - float_to_fp16_16(249.186311787072 / FREQUENCY_RATE), - float_to_fp16_16(250.137404580153 / FREQUENCY_RATE), - float_to_fp16_16(251.095785440613 / FREQUENCY_RATE), - float_to_fp16_16(252.061538461538 / FREQUENCY_RATE), - float_to_fp16_16(253.034749034749 / FREQUENCY_RATE), - float_to_fp16_16(254.015503875969 / FREQUENCY_RATE), - float_to_fp16_16(255.003891050584 / FREQUENCY_RATE), - float_to_fp16_16(256 / FREQUENCY_RATE), - float_to_fp16_16(257.003921568627 / FREQUENCY_RATE), - float_to_fp16_16(258.015748031496 / FREQUENCY_RATE), - float_to_fp16_16(259.03557312253 / FREQUENCY_RATE), - float_to_fp16_16(260.063492063492 / FREQUENCY_RATE), - float_to_fp16_16(261.099601593625 / FREQUENCY_RATE), - float_to_fp16_16(262.144 / FREQUENCY_RATE), - float_to_fp16_16(263.196787148594 / FREQUENCY_RATE), - float_to_fp16_16(264.258064516129 / FREQUENCY_RATE), - float_to_fp16_16(265.327935222672 / FREQUENCY_RATE), - float_to_fp16_16(266.406504065041 / FREQUENCY_RATE), - float_to_fp16_16(267.49387755102 / FREQUENCY_RATE), - float_to_fp16_16(268.590163934426 / FREQUENCY_RATE), - float_to_fp16_16(269.695473251029 / FREQUENCY_RATE), - float_to_fp16_16(270.809917355372 / FREQUENCY_RATE), - float_to_fp16_16(271.933609958506 / FREQUENCY_RATE), - float_to_fp16_16(273.066666666667 / FREQUENCY_RATE), - float_to_fp16_16(274.20920502092 / FREQUENCY_RATE), - float_to_fp16_16(275.361344537815 / FREQUENCY_RATE), - float_to_fp16_16(276.523206751055 / FREQUENCY_RATE), - float_to_fp16_16(277.694915254237 / FREQUENCY_RATE), - float_to_fp16_16(278.876595744681 / FREQUENCY_RATE), - float_to_fp16_16(280.068376068376 / FREQUENCY_RATE), - float_to_fp16_16(281.270386266094 / FREQUENCY_RATE), - float_to_fp16_16(282.48275862069 / FREQUENCY_RATE), - float_to_fp16_16(283.705627705628 / FREQUENCY_RATE), - float_to_fp16_16(284.939130434783 / FREQUENCY_RATE), - float_to_fp16_16(286.183406113537 / FREQUENCY_RATE), - float_to_fp16_16(287.438596491228 / FREQUENCY_RATE), - float_to_fp16_16(288.704845814978 / FREQUENCY_RATE), - float_to_fp16_16(289.982300884956 / FREQUENCY_RATE), - float_to_fp16_16(291.271111111111 / FREQUENCY_RATE), - float_to_fp16_16(292.571428571429 / FREQUENCY_RATE), - float_to_fp16_16(293.883408071749 / FREQUENCY_RATE), - float_to_fp16_16(295.207207207207 / FREQUENCY_RATE), - float_to_fp16_16(296.542986425339 / FREQUENCY_RATE), - float_to_fp16_16(297.890909090909 / FREQUENCY_RATE), - float_to_fp16_16(299.251141552511 / FREQUENCY_RATE), - float_to_fp16_16(300.623853211009 / FREQUENCY_RATE), - float_to_fp16_16(302.009216589862 / FREQUENCY_RATE), - float_to_fp16_16(303.407407407407 / FREQUENCY_RATE), - float_to_fp16_16(304.818604651163 / FREQUENCY_RATE), - float_to_fp16_16(306.242990654206 / FREQUENCY_RATE), - float_to_fp16_16(307.680751173709 / FREQUENCY_RATE), - float_to_fp16_16(309.132075471698 / FREQUENCY_RATE), - float_to_fp16_16(310.597156398104 / FREQUENCY_RATE), - float_to_fp16_16(312.07619047619 / FREQUENCY_RATE), - float_to_fp16_16(313.569377990431 / FREQUENCY_RATE), - float_to_fp16_16(315.076923076923 / FREQUENCY_RATE), - float_to_fp16_16(316.599033816425 / FREQUENCY_RATE), - float_to_fp16_16(318.135922330097 / FREQUENCY_RATE), - float_to_fp16_16(319.687804878049 / FREQUENCY_RATE), - float_to_fp16_16(321.254901960784 / FREQUENCY_RATE), - float_to_fp16_16(322.837438423645 / FREQUENCY_RATE), - float_to_fp16_16(324.435643564356 / FREQUENCY_RATE), - float_to_fp16_16(326.049751243781 / FREQUENCY_RATE), - float_to_fp16_16(327.68 / FREQUENCY_RATE), - float_to_fp16_16(329.326633165829 / FREQUENCY_RATE), - float_to_fp16_16(330.989898989899 / FREQUENCY_RATE), - float_to_fp16_16(332.670050761421 / FREQUENCY_RATE), - float_to_fp16_16(334.367346938775 / FREQUENCY_RATE), - float_to_fp16_16(336.082051282051 / FREQUENCY_RATE), - float_to_fp16_16(337.814432989691 / FREQUENCY_RATE), - float_to_fp16_16(339.564766839378 / FREQUENCY_RATE), - float_to_fp16_16(341.333333333333 / FREQUENCY_RATE), - float_to_fp16_16(343.120418848168 / FREQUENCY_RATE), - float_to_fp16_16(344.926315789474 / FREQUENCY_RATE), - float_to_fp16_16(346.751322751323 / FREQUENCY_RATE), - float_to_fp16_16(348.595744680851 / FREQUENCY_RATE), - float_to_fp16_16(350.459893048128 / FREQUENCY_RATE), - float_to_fp16_16(352.344086021505 / FREQUENCY_RATE), - float_to_fp16_16(354.248648648649 / FREQUENCY_RATE), - float_to_fp16_16(356.173913043478 / FREQUENCY_RATE), - float_to_fp16_16(358.120218579235 / FREQUENCY_RATE), - float_to_fp16_16(360.087912087912 / FREQUENCY_RATE), - float_to_fp16_16(362.077348066298 / FREQUENCY_RATE), - float_to_fp16_16(364.088888888889 / FREQUENCY_RATE), - float_to_fp16_16(366.122905027933 / FREQUENCY_RATE), - float_to_fp16_16(368.179775280899 / FREQUENCY_RATE), - float_to_fp16_16(370.25988700565 / FREQUENCY_RATE), - float_to_fp16_16(372.363636363636 / FREQUENCY_RATE), - float_to_fp16_16(374.491428571429 / FREQUENCY_RATE), - float_to_fp16_16(376.64367816092 / FREQUENCY_RATE), - float_to_fp16_16(378.820809248555 / FREQUENCY_RATE), - float_to_fp16_16(381.023255813953 / FREQUENCY_RATE), - float_to_fp16_16(383.251461988304 / FREQUENCY_RATE), - float_to_fp16_16(385.505882352941 / FREQUENCY_RATE), - float_to_fp16_16(387.786982248521 / FREQUENCY_RATE), - float_to_fp16_16(390.095238095238 / FREQUENCY_RATE), - float_to_fp16_16(392.431137724551 / FREQUENCY_RATE), - float_to_fp16_16(394.795180722892 / FREQUENCY_RATE), - float_to_fp16_16(397.187878787879 / FREQUENCY_RATE), - float_to_fp16_16(399.609756097561 / FREQUENCY_RATE), - float_to_fp16_16(402.061349693252 / FREQUENCY_RATE), - float_to_fp16_16(404.543209876543 / FREQUENCY_RATE), - float_to_fp16_16(407.055900621118 / FREQUENCY_RATE), - float_to_fp16_16(409.6 / FREQUENCY_RATE), - float_to_fp16_16(412.176100628931 / FREQUENCY_RATE), - float_to_fp16_16(414.784810126582 / FREQUENCY_RATE), - float_to_fp16_16(417.426751592357 / FREQUENCY_RATE), - float_to_fp16_16(420.102564102564 / FREQUENCY_RATE), - float_to_fp16_16(422.812903225807 / FREQUENCY_RATE), - float_to_fp16_16(425.558441558442 / FREQUENCY_RATE), - float_to_fp16_16(428.339869281046 / FREQUENCY_RATE), - float_to_fp16_16(431.157894736842 / FREQUENCY_RATE), - float_to_fp16_16(434.013245033113 / FREQUENCY_RATE), - float_to_fp16_16(436.906666666667 / FREQUENCY_RATE), - float_to_fp16_16(439.838926174497 / FREQUENCY_RATE), - float_to_fp16_16(442.810810810811 / FREQUENCY_RATE), - float_to_fp16_16(445.823129251701 / FREQUENCY_RATE), - float_to_fp16_16(448.876712328767 / FREQUENCY_RATE), - float_to_fp16_16(451.972413793103 / FREQUENCY_RATE), - float_to_fp16_16(455.111111111111 / FREQUENCY_RATE), - float_to_fp16_16(458.293706293706 / FREQUENCY_RATE), - float_to_fp16_16(461.521126760563 / FREQUENCY_RATE), - float_to_fp16_16(464.794326241135 / FREQUENCY_RATE), - float_to_fp16_16(468.114285714286 / FREQUENCY_RATE), - float_to_fp16_16(471.482014388489 / FREQUENCY_RATE), - float_to_fp16_16(474.898550724638 / FREQUENCY_RATE), - float_to_fp16_16(478.36496350365 / FREQUENCY_RATE), - float_to_fp16_16(481.882352941176 / FREQUENCY_RATE), - float_to_fp16_16(485.451851851852 / FREQUENCY_RATE), - float_to_fp16_16(489.074626865672 / FREQUENCY_RATE), - float_to_fp16_16(492.751879699248 / FREQUENCY_RATE), - float_to_fp16_16(496.484848484849 / FREQUENCY_RATE), - float_to_fp16_16(500.274809160305 / FREQUENCY_RATE), - float_to_fp16_16(504.123076923077 / FREQUENCY_RATE), - float_to_fp16_16(508.031007751938 / FREQUENCY_RATE), - float_to_fp16_16(512 / FREQUENCY_RATE), - float_to_fp16_16(516.031496062992 / FREQUENCY_RATE), - float_to_fp16_16(520.126984126984 / FREQUENCY_RATE), - float_to_fp16_16(524.288 / FREQUENCY_RATE), - float_to_fp16_16(528.516129032258 / FREQUENCY_RATE), - float_to_fp16_16(532.813008130081 / FREQUENCY_RATE), - float_to_fp16_16(537.180327868852 / FREQUENCY_RATE), - float_to_fp16_16(541.619834710744 / FREQUENCY_RATE), - float_to_fp16_16(546.133333333333 / FREQUENCY_RATE), - float_to_fp16_16(550.72268907563 / FREQUENCY_RATE), - float_to_fp16_16(555.389830508475 / FREQUENCY_RATE), - float_to_fp16_16(560.136752136752 / FREQUENCY_RATE), - float_to_fp16_16(564.965517241379 / FREQUENCY_RATE), - float_to_fp16_16(569.878260869565 / FREQUENCY_RATE), - float_to_fp16_16(574.877192982456 / FREQUENCY_RATE), - float_to_fp16_16(579.964601769912 / FREQUENCY_RATE), - float_to_fp16_16(585.142857142857 / FREQUENCY_RATE), - float_to_fp16_16(590.414414414414 / FREQUENCY_RATE), - float_to_fp16_16(595.781818181818 / FREQUENCY_RATE), - float_to_fp16_16(601.247706422018 / FREQUENCY_RATE), - float_to_fp16_16(606.814814814815 / FREQUENCY_RATE), - float_to_fp16_16(612.485981308411 / FREQUENCY_RATE), - float_to_fp16_16(618.264150943396 / FREQUENCY_RATE), - float_to_fp16_16(624.152380952381 / FREQUENCY_RATE), - float_to_fp16_16(630.153846153846 / FREQUENCY_RATE), - float_to_fp16_16(636.271844660194 / FREQUENCY_RATE), - float_to_fp16_16(642.509803921569 / FREQUENCY_RATE), - float_to_fp16_16(648.871287128713 / FREQUENCY_RATE), - float_to_fp16_16(655.36 / FREQUENCY_RATE), - float_to_fp16_16(661.979797979798 / FREQUENCY_RATE), - float_to_fp16_16(668.734693877551 / FREQUENCY_RATE), - float_to_fp16_16(675.628865979381 / FREQUENCY_RATE), - float_to_fp16_16(682.666666666667 / FREQUENCY_RATE), - float_to_fp16_16(689.852631578947 / FREQUENCY_RATE), - float_to_fp16_16(697.191489361702 / FREQUENCY_RATE), - float_to_fp16_16(704.688172043011 / FREQUENCY_RATE), - float_to_fp16_16(712.347826086956 / FREQUENCY_RATE), - float_to_fp16_16(720.175824175824 / FREQUENCY_RATE), - float_to_fp16_16(728.177777777778 / FREQUENCY_RATE), - float_to_fp16_16(736.359550561798 / FREQUENCY_RATE), - float_to_fp16_16(744.727272727273 / FREQUENCY_RATE), - float_to_fp16_16(753.287356321839 / FREQUENCY_RATE), - float_to_fp16_16(762.046511627907 / FREQUENCY_RATE), - float_to_fp16_16(771.011764705882 / FREQUENCY_RATE), - float_to_fp16_16(780.190476190476 / FREQUENCY_RATE), - float_to_fp16_16(789.590361445783 / FREQUENCY_RATE), - float_to_fp16_16(799.219512195122 / FREQUENCY_RATE), - float_to_fp16_16(809.086419753086 / FREQUENCY_RATE), - float_to_fp16_16(819.2 / FREQUENCY_RATE), - float_to_fp16_16(829.569620253165 / FREQUENCY_RATE), - float_to_fp16_16(840.205128205128 / FREQUENCY_RATE), - float_to_fp16_16(851.116883116883 / FREQUENCY_RATE), - float_to_fp16_16(862.315789473684 / FREQUENCY_RATE), - float_to_fp16_16(873.813333333333 / FREQUENCY_RATE), - float_to_fp16_16(885.621621621622 / FREQUENCY_RATE), - float_to_fp16_16(897.753424657534 / FREQUENCY_RATE), - float_to_fp16_16(910.222222222222 / FREQUENCY_RATE), - float_to_fp16_16(923.042253521127 / FREQUENCY_RATE), - float_to_fp16_16(936.228571428571 / FREQUENCY_RATE), - float_to_fp16_16(949.797101449275 / FREQUENCY_RATE), - float_to_fp16_16(963.764705882353 / FREQUENCY_RATE), - float_to_fp16_16(978.149253731343 / FREQUENCY_RATE), - float_to_fp16_16(992.969696969697 / FREQUENCY_RATE), - float_to_fp16_16(1008.24615384615 / FREQUENCY_RATE), - float_to_fp16_16(1024 / FREQUENCY_RATE), - float_to_fp16_16(1040.25396825397 / FREQUENCY_RATE), - float_to_fp16_16(1057.03225806452 / FREQUENCY_RATE), - float_to_fp16_16(1074.36065573771 / FREQUENCY_RATE), - float_to_fp16_16(1092.26666666667 / FREQUENCY_RATE), - float_to_fp16_16(1110.77966101695 / FREQUENCY_RATE), - float_to_fp16_16(1129.93103448276 / FREQUENCY_RATE), - float_to_fp16_16(1149.75438596491 / FREQUENCY_RATE), - float_to_fp16_16(1170.28571428571 / FREQUENCY_RATE), - float_to_fp16_16(1191.56363636364 / FREQUENCY_RATE), - float_to_fp16_16(1213.62962962963 / FREQUENCY_RATE), - float_to_fp16_16(1236.52830188679 / FREQUENCY_RATE), - float_to_fp16_16(1260.30769230769 / FREQUENCY_RATE), - float_to_fp16_16(1285.01960784314 / FREQUENCY_RATE), - float_to_fp16_16(1310.72 / FREQUENCY_RATE), - float_to_fp16_16(1337.4693877551 / FREQUENCY_RATE), - float_to_fp16_16(1365.33333333333 / FREQUENCY_RATE), - float_to_fp16_16(1394.3829787234 / FREQUENCY_RATE), - float_to_fp16_16(1424.69565217391 / FREQUENCY_RATE), - float_to_fp16_16(1456.35555555556 / FREQUENCY_RATE), - float_to_fp16_16(1489.45454545455 / FREQUENCY_RATE), - float_to_fp16_16(1524.09302325581 / FREQUENCY_RATE), - float_to_fp16_16(1560.38095238095 / FREQUENCY_RATE), - float_to_fp16_16(1598.43902439024 / FREQUENCY_RATE), - float_to_fp16_16(1638.4 / FREQUENCY_RATE), - float_to_fp16_16(1680.41025641026 / FREQUENCY_RATE), - float_to_fp16_16(1724.63157894737 / FREQUENCY_RATE), - float_to_fp16_16(1771.24324324324 / FREQUENCY_RATE), - float_to_fp16_16(1820.44444444444 / FREQUENCY_RATE), - float_to_fp16_16(1872.45714285714 / FREQUENCY_RATE), - float_to_fp16_16(1927.52941176471 / FREQUENCY_RATE), - float_to_fp16_16(1985.93939393939 / FREQUENCY_RATE), - float_to_fp16_16(2048 / FREQUENCY_RATE), - float_to_fp16_16(2114.06451612903 / FREQUENCY_RATE), - float_to_fp16_16(2184.53333333333 / FREQUENCY_RATE), - float_to_fp16_16(2259.86206896552 / FREQUENCY_RATE), - float_to_fp16_16(2340.57142857143 / FREQUENCY_RATE), - float_to_fp16_16(2427.25925925926 / FREQUENCY_RATE), - float_to_fp16_16(2520.61538461538 / FREQUENCY_RATE), - float_to_fp16_16(2621.44 / FREQUENCY_RATE), - float_to_fp16_16(2730.66666666667 / FREQUENCY_RATE), - float_to_fp16_16(2849.39130434783 / FREQUENCY_RATE), - float_to_fp16_16(2978.90909090909 / FREQUENCY_RATE), - float_to_fp16_16(3120.7619047619 / FREQUENCY_RATE), - float_to_fp16_16(3276.8 / FREQUENCY_RATE), - float_to_fp16_16(3449.26315789474 / FREQUENCY_RATE), - float_to_fp16_16(3640.88888888889 / FREQUENCY_RATE), - float_to_fp16_16(3855.05882352941 / FREQUENCY_RATE), - float_to_fp16_16(4096 / FREQUENCY_RATE), - float_to_fp16_16(4369.06666666667 / FREQUENCY_RATE), - float_to_fp16_16(4681.14285714286 / FREQUENCY_RATE), - float_to_fp16_16(5041.23076923077 / FREQUENCY_RATE), - float_to_fp16_16(5461.33333333333 / FREQUENCY_RATE), - float_to_fp16_16(5957.81818181818 / FREQUENCY_RATE), - float_to_fp16_16(6553.6 / FREQUENCY_RATE), - float_to_fp16_16(7281.77777777778 / FREQUENCY_RATE), - float_to_fp16_16(8192 / FREQUENCY_RATE), - float_to_fp16_16(9362.28571428571 / FREQUENCY_RATE), - float_to_fp16_16(10922.6666666667 / FREQUENCY_RATE), - float_to_fp16_16(13107.2 / FREQUENCY_RATE), - float_to_fp16_16(16384 / FREQUENCY_RATE), - float_to_fp16_16(21845.3333333333 / FREQUENCY_RATE), - float_to_fp16_16(32768 / FREQUENCY_RATE), - float_to_fp16_16(65536 / FREQUENCY_RATE), +const float freqTable[2048] = { + (32 / FREQUENCY_RATE), + (32.0156326331216 / FREQUENCY_RATE), + (32.0312805474096 / FREQUENCY_RATE), + (32.0469437652812 / FREQUENCY_RATE), + (32.0626223091976 / FREQUENCY_RATE), + (32.0783162016642 / FREQUENCY_RATE), + (32.0940254652302 / FREQUENCY_RATE), + (32.109750122489 / FREQUENCY_RATE), + (32.1254901960784 / FREQUENCY_RATE), + (32.1412457086807 / FREQUENCY_RATE), + (32.1570166830226 / FREQUENCY_RATE), + (32.1728031418753 / FREQUENCY_RATE), + (32.188605108055 / FREQUENCY_RATE), + (32.2044226044226 / FREQUENCY_RATE), + (32.220255653884 / FREQUENCY_RATE), + (32.2361042793901 / FREQUENCY_RATE), + (32.251968503937 / FREQUENCY_RATE), + (32.2678483505662 / FREQUENCY_RATE), + (32.2837438423645 / FREQUENCY_RATE), + (32.2996550024643 / FREQUENCY_RATE), + (32.3155818540434 / FREQUENCY_RATE), + (32.3315244203256 / FREQUENCY_RATE), + (32.3474827245805 / FREQUENCY_RATE), + (32.3634567901235 / FREQUENCY_RATE), + (32.3794466403162 / FREQUENCY_RATE), + (32.3954522985665 / FREQUENCY_RATE), + (32.4114737883284 / FREQUENCY_RATE), + (32.4275111331024 / FREQUENCY_RATE), + (32.4435643564356 / FREQUENCY_RATE), + (32.4596334819217 / FREQUENCY_RATE), + (32.4757185332012 / FREQUENCY_RATE), + (32.4918195339613 / FREQUENCY_RATE), + (32.5079365079365 / FREQUENCY_RATE), + (32.5240694789082 / FREQUENCY_RATE), + (32.5402184707051 / FREQUENCY_RATE), + (32.5563835072032 / FREQUENCY_RATE), + (32.572564612326 / FREQUENCY_RATE), + (32.5887618100448 / FREQUENCY_RATE), + (32.6049751243781 / FREQUENCY_RATE), + (32.6212045793927 / FREQUENCY_RATE), + (32.6374501992032 / FREQUENCY_RATE), + (32.6537120079721 / FREQUENCY_RATE), + (32.6699900299103 / FREQUENCY_RATE), + (32.6862842892768 / FREQUENCY_RATE), + (32.7025948103792 / FREQUENCY_RATE), + (32.7189216175736 / FREQUENCY_RATE), + (32.7352647352647 / FREQUENCY_RATE), + (32.751624187906 / FREQUENCY_RATE), + (32.768 / FREQUENCY_RATE), + (32.784392196098 / FREQUENCY_RATE), + (32.8008008008008 / FREQUENCY_RATE), + (32.8172258387581 / FREQUENCY_RATE), + (32.8336673346693 / FREQUENCY_RATE), + (32.8501253132832 / FREQUENCY_RATE), + (32.8665997993982 / FREQUENCY_RATE), + (32.8830908178625 / FREQUENCY_RATE), + (32.8995983935743 / FREQUENCY_RATE), + (32.9161225514817 / FREQUENCY_RATE), + (32.9326633165829 / FREQUENCY_RATE), + (32.9492207139266 / FREQUENCY_RATE), + (32.9657947686117 / FREQUENCY_RATE), + (32.9823855057876 / FREQUENCY_RATE), + (32.9989929506546 / FREQUENCY_RATE), + (33.0156171284635 / FREQUENCY_RATE), + (33.0322580645161 / FREQUENCY_RATE), + (33.0489157841654 / FREQUENCY_RATE), + (33.0655903128153 / FREQUENCY_RATE), + (33.0822816759213 / FREQUENCY_RATE), + (33.0989898989899 / FREQUENCY_RATE), + (33.1157150075796 / FREQUENCY_RATE), + (33.1324570273003 / FREQUENCY_RATE), + (33.1492159838139 / FREQUENCY_RATE), + (33.165991902834 / FREQUENCY_RATE), + (33.1827848101266 / FREQUENCY_RATE), + (33.1995947315096 / FREQUENCY_RATE), + (33.2164216928535 / FREQUENCY_RATE), + (33.2332657200811 / FREQUENCY_RATE), + (33.2501268391679 / FREQUENCY_RATE), + (33.2670050761421 / FREQUENCY_RATE), + (33.2839004570848 / FREQUENCY_RATE), + (33.3008130081301 / FREQUENCY_RATE), + (33.3177427554652 / FREQUENCY_RATE), + (33.3346897253306 / FREQUENCY_RATE), + (33.3516539440204 / FREQUENCY_RATE), + (33.3686354378819 / FREQUENCY_RATE), + (33.3856342333164 / FREQUENCY_RATE), + (33.4026503567788 / FREQUENCY_RATE), + (33.4196838347782 / FREQUENCY_RATE), + (33.4367346938776 / FREQUENCY_RATE), + (33.4538029606942 / FREQUENCY_RATE), + (33.4708886618999 / FREQUENCY_RATE), + (33.4879918242207 / FREQUENCY_RATE), + (33.5051124744376 / FREQUENCY_RATE), + (33.5222506393862 / FREQUENCY_RATE), + (33.539406345957 / FREQUENCY_RATE), + (33.5565796210957 / FREQUENCY_RATE), + (33.5737704918033 / FREQUENCY_RATE), + (33.5909789851358 / FREQUENCY_RATE), + (33.6082051282051 / FREQUENCY_RATE), + (33.6254489481786 / FREQUENCY_RATE), + (33.6427104722793 / FREQUENCY_RATE), + (33.6599897277863 / FREQUENCY_RATE), + (33.6772867420349 / FREQUENCY_RATE), + (33.6946015424164 / FREQUENCY_RATE), + (33.7119341563786 / FREQUENCY_RATE), + (33.7292846114256 / FREQUENCY_RATE), + (33.7466529351184 / FREQUENCY_RATE), + (33.7640391550747 / FREQUENCY_RATE), + (33.7814432989691 / FREQUENCY_RATE), + (33.7988653945333 / FREQUENCY_RATE), + (33.8163054695562 / FREQUENCY_RATE), + (33.8337635518844 / FREQUENCY_RATE), + (33.8512396694215 / FREQUENCY_RATE), + (33.8687338501292 / FREQUENCY_RATE), + (33.8862461220269 / FREQUENCY_RATE), + (33.9037765131919 / FREQUENCY_RATE), + (33.9213250517598 / FREQUENCY_RATE), + (33.9388917659244 / FREQUENCY_RATE), + (33.9564766839378 / FREQUENCY_RATE), + (33.9740798341109 / FREQUENCY_RATE), + (33.9917012448133 / FREQUENCY_RATE), + (34.0093409444733 / FREQUENCY_RATE), + (34.0269989615784 / FREQUENCY_RATE), + (34.0446753246753 / FREQUENCY_RATE), + (34.0623700623701 / FREQUENCY_RATE), + (34.0800832033281 / FREQUENCY_RATE), + (34.0978147762747 / FREQUENCY_RATE), + (34.1155648099948 / FREQUENCY_RATE), + (34.1333333333333 / FREQUENCY_RATE), + (34.1511203751954 / FREQUENCY_RATE), + (34.1689259645464 / FREQUENCY_RATE), + (34.1867501304121 / FREQUENCY_RATE), + (34.2045929018789 / FREQUENCY_RATE), + (34.222454308094 / FREQUENCY_RATE), + (34.2403343782654 / FREQUENCY_RATE), + (34.2582331416623 / FREQUENCY_RATE), + (34.2761506276151 / FREQUENCY_RATE), + (34.2940868655154 / FREQUENCY_RATE), + (34.3120418848168 / FREQUENCY_RATE), + (34.330015715034 / FREQUENCY_RATE), + (34.3480083857442 / FREQUENCY_RATE), + (34.3660199265863 / FREQUENCY_RATE), + (34.3840503672613 / FREQUENCY_RATE), + (34.4020997375328 / FREQUENCY_RATE), + (34.4201680672269 / FREQUENCY_RATE), + (34.4382553862323 / FREQUENCY_RATE), + (34.4563617245005 / FREQUENCY_RATE), + (34.4744871120463 / FREQUENCY_RATE), + (34.4926315789474 / FREQUENCY_RATE), + (34.5107951553449 / FREQUENCY_RATE), + (34.5289778714436 / FREQUENCY_RATE), + (34.5471797575119 / FREQUENCY_RATE), + (34.5654008438819 / FREQUENCY_RATE), + (34.5836411609499 / FREQUENCY_RATE), + (34.6019007391763 / FREQUENCY_RATE), + (34.6201796090861 / FREQUENCY_RATE), + (34.6384778012685 / FREQUENCY_RATE), + (34.6567953463776 / FREQUENCY_RATE), + (34.6751322751323 / FREQUENCY_RATE), + (34.6934886183166 / FREQUENCY_RATE), + (34.7118644067797 / FREQUENCY_RATE), + (34.7302596714361 / FREQUENCY_RATE), + (34.7486744432662 / FREQUENCY_RATE), + (34.7671087533156 / FREQUENCY_RATE), + (34.7855626326964 / FREQUENCY_RATE), + (34.8040361125863 / FREQUENCY_RATE), + (34.8225292242295 / FREQUENCY_RATE), + (34.8410419989367 / FREQUENCY_RATE), + (34.8595744680851 / FREQUENCY_RATE), + (34.8781266631187 / FREQUENCY_RATE), + (34.8966986155485 / FREQUENCY_RATE), + (34.9152903569526 / FREQUENCY_RATE), + (34.9339019189765 / FREQUENCY_RATE), + (34.9525333333333 / FREQUENCY_RATE), + (34.9711846318036 / FREQUENCY_RATE), + (34.989855846236 / FREQUENCY_RATE), + (35.008547008547 / FREQUENCY_RATE), + (35.0272581507215 / FREQUENCY_RATE), + (35.0459893048128 / FREQUENCY_RATE), + (35.0647405029427 / FREQUENCY_RATE), + (35.0835117773019 / FREQUENCY_RATE), + (35.10230316015 / FREQUENCY_RATE), + (35.1211146838156 / FREQUENCY_RATE), + (35.1399463806971 / FREQUENCY_RATE), + (35.1587982832618 / FREQUENCY_RATE), + (35.1776704240472 / FREQUENCY_RATE), + (35.1965628356606 / FREQUENCY_RATE), + (35.2154755507792 / FREQUENCY_RATE), + (35.2344086021505 / FREQUENCY_RATE), + (35.2533620225928 / FREQUENCY_RATE), + (35.2723358449946 / FREQUENCY_RATE), + (35.2913301023156 / FREQUENCY_RATE), + (35.3103448275862 / FREQUENCY_RATE), + (35.3293800539084 / FREQUENCY_RATE), + (35.3484358144552 / FREQUENCY_RATE), + (35.3675121424717 / FREQUENCY_RATE), + (35.3866090712743 / FREQUENCY_RATE), + (35.4057266342518 / FREQUENCY_RATE), + (35.4248648648649 / FREQUENCY_RATE), + (35.4440237966468 / FREQUENCY_RATE), + (35.4632034632035 / FREQUENCY_RATE), + (35.4824038982133 / FREQUENCY_RATE), + (35.501625135428 / FREQUENCY_RATE), + (35.5208672086721 / FREQUENCY_RATE), + (35.5401301518438 / FREQUENCY_RATE), + (35.5594139989148 / FREQUENCY_RATE), + (35.5787187839305 / FREQUENCY_RATE), + (35.5980445410103 / FREQUENCY_RATE), + (35.6173913043478 / FREQUENCY_RATE), + (35.636759108211 / FREQUENCY_RATE), + (35.6561479869423 / FREQUENCY_RATE), + (35.6755579749592 / FREQUENCY_RATE), + (35.6949891067538 / FREQUENCY_RATE), + (35.7144414168937 / FREQUENCY_RATE), + (35.7339149400218 / FREQUENCY_RATE), + (35.7534097108565 / FREQUENCY_RATE), + (35.7729257641921 / FREQUENCY_RATE), + (35.792463134899 / FREQUENCY_RATE), + (35.8120218579235 / FREQUENCY_RATE), + (35.8316019682887 / FREQUENCY_RATE), + (35.8512035010941 / FREQUENCY_RATE), + (35.8708264915161 / FREQUENCY_RATE), + (35.8904709748083 / FREQUENCY_RATE), + (35.9101369863014 / FREQUENCY_RATE), + (35.9298245614035 / FREQUENCY_RATE), + (35.9495337356007 / FREQUENCY_RATE), + (35.9692645444566 / FREQUENCY_RATE), + (35.9890170236134 / FREQUENCY_RATE), + (36.0087912087912 / FREQUENCY_RATE), + (36.0285871357889 / FREQUENCY_RATE), + (36.048404840484 / FREQUENCY_RATE), + (36.0682443588332 / FREQUENCY_RATE), + (36.0881057268722 / FREQUENCY_RATE), + (36.1079889807162 / FREQUENCY_RATE), + (36.1278941565601 / FREQUENCY_RATE), + (36.1478212906784 / FREQUENCY_RATE), + (36.167770419426 / FREQUENCY_RATE), + (36.187741579238 / FREQUENCY_RATE), + (36.2077348066298 / FREQUENCY_RATE), + (36.2277501381979 / FREQUENCY_RATE), + (36.2477876106195 / FREQUENCY_RATE), + (36.267847260653 / FREQUENCY_RATE), + (36.2879291251384 / FREQUENCY_RATE), + (36.3080332409972 / FREQUENCY_RATE), + (36.3281596452328 / FREQUENCY_RATE), + (36.3483083749307 / FREQUENCY_RATE), + (36.3684794672586 / FREQUENCY_RATE), + (36.388672959467 / FREQUENCY_RATE), + (36.4088888888889 / FREQUENCY_RATE), + (36.4291272929405 / FREQUENCY_RATE), + (36.4493882091212 / FREQUENCY_RATE), + (36.4696716750139 / FREQUENCY_RATE), + (36.4899777282851 / FREQUENCY_RATE), + (36.5103064066852 / FREQUENCY_RATE), + (36.5306577480491 / FREQUENCY_RATE), + (36.5510317902956 / FREQUENCY_RATE), + (36.5714285714286 / FREQUENCY_RATE), + (36.5918481295366 / FREQUENCY_RATE), + (36.6122905027933 / FREQUENCY_RATE), + (36.6327557294578 / FREQUENCY_RATE), + (36.6532438478747 / FREQUENCY_RATE), + (36.6737548964745 / FREQUENCY_RATE), + (36.6942889137738 / FREQUENCY_RATE), + (36.7148459383753 / FREQUENCY_RATE), + (36.7354260089686 / FREQUENCY_RATE), + (36.7560291643298 / FREQUENCY_RATE), + (36.7766554433221 / FREQUENCY_RATE), + (36.7973048848961 / FREQUENCY_RATE), + (36.8179775280899 / FREQUENCY_RATE), + (36.8386734120292 / FREQUENCY_RATE), + (36.859392575928 / FREQUENCY_RATE), + (36.8801350590884 / FREQUENCY_RATE), + (36.9009009009009 / FREQUENCY_RATE), + (36.9216901408451 / FREQUENCY_RATE), + (36.9425028184893 / FREQUENCY_RATE), + (36.9633389734913 / FREQUENCY_RATE), + (36.9841986455982 / FREQUENCY_RATE), + (37.0050818746471 / FREQUENCY_RATE), + (37.025988700565 / FREQUENCY_RATE), + (37.0469191633691 / FREQUENCY_RATE), + (37.0678733031674 / FREQUENCY_RATE), + (37.0888511601585 / FREQUENCY_RATE), + (37.1098527746319 / FREQUENCY_RATE), + (37.1308781869688 / FREQUENCY_RATE), + (37.1519274376417 / FREQUENCY_RATE), + (37.173000567215 / FREQUENCY_RATE), + (37.1940976163451 / FREQUENCY_RATE), + (37.2152186257808 / FREQUENCY_RATE), + (37.2363636363636 / FREQUENCY_RATE), + (37.2575326890279 / FREQUENCY_RATE), + (37.2787258248009 / FREQUENCY_RATE), + (37.2999430848036 / FREQUENCY_RATE), + (37.3211845102506 / FREQUENCY_RATE), + (37.3424501424501 / FREQUENCY_RATE), + (37.363740022805 / FREQUENCY_RATE), + (37.3850541928123 / FREQUENCY_RATE), + (37.4063926940639 / FREQUENCY_RATE), + (37.4277555682467 / FREQUENCY_RATE), + (37.4491428571429 / FREQUENCY_RATE), + (37.4705546026301 / FREQUENCY_RATE), + (37.4919908466819 / FREQUENCY_RATE), + (37.5134516313681 / FREQUENCY_RATE), + (37.5349369988545 / FREQUENCY_RATE), + (37.556446991404 / FREQUENCY_RATE), + (37.5779816513761 / FREQUENCY_RATE), + (37.5995410212278 / FREQUENCY_RATE), + (37.6211251435132 / FREQUENCY_RATE), + (37.6427340608845 / FREQUENCY_RATE), + (37.664367816092 / FREQUENCY_RATE), + (37.6860264519839 / FREQUENCY_RATE), + (37.7077100115075 / FREQUENCY_RATE), + (37.7294185377087 / FREQUENCY_RATE), + (37.7511520737327 / FREQUENCY_RATE), + (37.7729106628242 / FREQUENCY_RATE), + (37.7946943483276 / FREQUENCY_RATE), + (37.8165031736872 / FREQUENCY_RATE), + (37.838337182448 / FREQUENCY_RATE), + (37.8601964182553 / FREQUENCY_RATE), + (37.8820809248555 / FREQUENCY_RATE), + (37.903990746096 / FREQUENCY_RATE), + (37.9259259259259 / FREQUENCY_RATE), + (37.9478865083961 / FREQUENCY_RATE), + (37.9698725376593 / FREQUENCY_RATE), + (37.991884057971 / FREQUENCY_RATE), + (38.0139211136891 / FREQUENCY_RATE), + (38.0359837492745 / FREQUENCY_RATE), + (38.0580720092915 / FREQUENCY_RATE), + (38.0801859384079 / FREQUENCY_RATE), + (38.1023255813953 / FREQUENCY_RATE), + (38.1244909831297 / FREQUENCY_RATE), + (38.1466821885914 / FREQUENCY_RATE), + (38.1688992428655 / FREQUENCY_RATE), + (38.1911421911422 / FREQUENCY_RATE), + (38.2134110787172 / FREQUENCY_RATE), + (38.2357059509918 / FREQUENCY_RATE), + (38.2580268534734 / FREQUENCY_RATE), + (38.2803738317757 / FREQUENCY_RATE), + (38.3027469316189 / FREQUENCY_RATE), + (38.3251461988304 / FREQUENCY_RATE), + (38.3475716793446 / FREQUENCY_RATE), + (38.3700234192037 / FREQUENCY_RATE), + (38.3925014645577 / FREQUENCY_RATE), + (38.4150058616647 / FREQUENCY_RATE), + (38.4375366568915 / FREQUENCY_RATE), + (38.4600938967136 / FREQUENCY_RATE), + (38.4826776277158 / FREQUENCY_RATE), + (38.5052878965922 / FREQUENCY_RATE), + (38.527924750147 / FREQUENCY_RATE), + (38.5505882352941 / FREQUENCY_RATE), + (38.5732783990583 / FREQUENCY_RATE), + (38.5959952885748 / FREQUENCY_RATE), + (38.6187389510902 / FREQUENCY_RATE), + (38.6415094339623 / FREQUENCY_RATE), + (38.6643067846608 / FREQUENCY_RATE), + (38.6871310507674 / FREQUENCY_RATE), + (38.7099822799764 / FREQUENCY_RATE), + (38.7328605200946 / FREQUENCY_RATE), + (38.755765819042 / FREQUENCY_RATE), + (38.7786982248521 / FREQUENCY_RATE), + (38.801657785672 / FREQUENCY_RATE), + (38.824644549763 / FREQUENCY_RATE), + (38.8476585655009 / FREQUENCY_RATE), + (38.870699881376 / FREQUENCY_RATE), + (38.8937685459941 / FREQUENCY_RATE), + (38.916864608076 / FREQUENCY_RATE), + (38.9399881164587 / FREQUENCY_RATE), + (38.9631391200951 / FREQUENCY_RATE), + (38.9863176680547 / FREQUENCY_RATE), + (39.0095238095238 / FREQUENCY_RATE), + (39.0327575938058 / FREQUENCY_RATE), + (39.0560190703218 / FREQUENCY_RATE), + (39.0793082886106 / FREQUENCY_RATE), + (39.1026252983294 / FREQUENCY_RATE), + (39.1259701492537 / FREQUENCY_RATE), + (39.1493428912784 / FREQUENCY_RATE), + (39.1727435744172 / FREQUENCY_RATE), + (39.1961722488038 / FREQUENCY_RATE), + (39.2196289646918 / FREQUENCY_RATE), + (39.2431137724551 / FREQUENCY_RATE), + (39.2666267225884 / FREQUENCY_RATE), + (39.2901678657074 / FREQUENCY_RATE), + (39.3137372525495 / FREQUENCY_RATE), + (39.3373349339736 / FREQUENCY_RATE), + (39.360960960961 / FREQUENCY_RATE), + (39.3846153846154 / FREQUENCY_RATE), + (39.4082982561636 / FREQUENCY_RATE), + (39.4320096269555 / FREQUENCY_RATE), + (39.4557495484648 / FREQUENCY_RATE), + (39.4795180722892 / FREQUENCY_RATE), + (39.5033152501507 / FREQUENCY_RATE), + (39.5271411338963 / FREQUENCY_RATE), + (39.5509957754979 / FREQUENCY_RATE), + (39.5748792270531 / FREQUENCY_RATE), + (39.5987915407855 / FREQUENCY_RATE), + (39.6227327690447 / FREQUENCY_RATE), + (39.6467029643073 / FREQUENCY_RATE), + (39.6707021791768 / FREQUENCY_RATE), + (39.694730466384 / FREQUENCY_RATE), + (39.7187878787879 / FREQUENCY_RATE), + (39.7428744693754 / FREQUENCY_RATE), + (39.7669902912621 / FREQUENCY_RATE), + (39.7911353976928 / FREQUENCY_RATE), + (39.8153098420413 / FREQUENCY_RATE), + (39.8395136778115 / FREQUENCY_RATE), + (39.8637469586375 / FREQUENCY_RATE), + (39.8880097382836 / FREQUENCY_RATE), + (39.9123020706455 / FREQUENCY_RATE), + (39.9366240097502 / FREQUENCY_RATE), + (39.9609756097561 / FREQUENCY_RATE), + (39.9853569249542 / FREQUENCY_RATE), + (40.009768009768 / FREQUENCY_RATE), + (40.0342089187538 / FREQUENCY_RATE), + (40.0586797066015 / FREQUENCY_RATE), + (40.0831804281346 / FREQUENCY_RATE), + (40.1077111383109 / FREQUENCY_RATE), + (40.1322718922229 / FREQUENCY_RATE), + (40.156862745098 / FREQUENCY_RATE), + (40.1814837522992 / FREQUENCY_RATE), + (40.2061349693252 / FREQUENCY_RATE), + (40.2308164518109 / FREQUENCY_RATE), + (40.2555282555283 / FREQUENCY_RATE), + (40.280270436386 / FREQUENCY_RATE), + (40.3050430504305 / FREQUENCY_RATE), + (40.3298461538462 / FREQUENCY_RATE), + (40.3546798029557 / FREQUENCY_RATE), + (40.3795440542206 / FREQUENCY_RATE), + (40.4044389642417 / FREQUENCY_RATE), + (40.4293645897594 / FREQUENCY_RATE), + (40.4543209876543 / FREQUENCY_RATE), + (40.4793082149475 / FREQUENCY_RATE), + (40.504326328801 / FREQUENCY_RATE), + (40.5293753865182 / FREQUENCY_RATE), + (40.5544554455446 / FREQUENCY_RATE), + (40.5795665634675 / FREQUENCY_RATE), + (40.6047087980174 / FREQUENCY_RATE), + (40.6298822070676 / FREQUENCY_RATE), + (40.6550868486352 / FREQUENCY_RATE), + (40.6803227808814 / FREQUENCY_RATE), + (40.7055900621118 / FREQUENCY_RATE), + (40.7308887507769 / FREQUENCY_RATE), + (40.7562189054726 / FREQUENCY_RATE), + (40.7815805849409 / FREQUENCY_RATE), + (40.8069738480697 / FREQUENCY_RATE), + (40.8323987538941 / FREQUENCY_RATE), + (40.857855361596 / FREQUENCY_RATE), + (40.8833437305053 / FREQUENCY_RATE), + (40.9088639200999 / FREQUENCY_RATE), + (40.9344159900062 / FREQUENCY_RATE), + (40.96 / FREQUENCY_RATE), + (40.9856160100063 / FREQUENCY_RATE), + (41.0112640801001 / FREQUENCY_RATE), + (41.0369442705072 / FREQUENCY_RATE), + (41.062656641604 / FREQUENCY_RATE), + (41.0884012539185 / FREQUENCY_RATE), + (41.1141781681305 / FREQUENCY_RATE), + (41.1399874450722 / FREQUENCY_RATE), + (41.1658291457287 / FREQUENCY_RATE), + (41.1917033312382 / FREQUENCY_RATE), + (41.2176100628931 / FREQUENCY_RATE), + (41.2435494021397 / FREQUENCY_RATE), + (41.2695214105793 / FREQUENCY_RATE), + (41.2955261499685 / FREQUENCY_RATE), + (41.3215636822194 / FREQUENCY_RATE), + (41.3476340694006 / FREQUENCY_RATE), + (41.3737373737374 / FREQUENCY_RATE), + (41.3998736576121 / FREQUENCY_RATE), + (41.4260429835651 / FREQUENCY_RATE), + (41.4522454142948 / FREQUENCY_RATE), + (41.4784810126582 / FREQUENCY_RATE), + (41.504749841672 / FREQUENCY_RATE), + (41.531051964512 / FREQUENCY_RATE), + (41.5573874445149 / FREQUENCY_RATE), + (41.5837563451777 / FREQUENCY_RATE), + (41.6101587301587 / FREQUENCY_RATE), + (41.6365946632783 / FREQUENCY_RATE), + (41.6630642085188 / FREQUENCY_RATE), + (41.6895674300254 / FREQUENCY_RATE), + (41.7161043921069 / FREQUENCY_RATE), + (41.7426751592357 / FREQUENCY_RATE), + (41.7692797960484 / FREQUENCY_RATE), + (41.7959183673469 / FREQUENCY_RATE), + (41.8225909380983 / FREQUENCY_RATE), + (41.8492975734355 / FREQUENCY_RATE), + (41.8760383386582 / FREQUENCY_RATE), + (41.9028132992327 / FREQUENCY_RATE), + (41.9296225207934 / FREQUENCY_RATE), + (41.9564660691421 / FREQUENCY_RATE), + (41.9833440102498 / FREQUENCY_RATE), + (42.0102564102564 / FREQUENCY_RATE), + (42.0372033354715 / FREQUENCY_RATE), + (42.0641848523748 / FREQUENCY_RATE), + (42.0912010276172 / FREQUENCY_RATE), + (42.1182519280206 / FREQUENCY_RATE), + (42.1453376205788 / FREQUENCY_RATE), + (42.1724581724582 / FREQUENCY_RATE), + (42.1996136509981 / FREQUENCY_RATE), + (42.2268041237113 / FREQUENCY_RATE), + (42.254029658285 / FREQUENCY_RATE), + (42.2812903225807 / FREQUENCY_RATE), + (42.3085861846352 / FREQUENCY_RATE), + (42.3359173126615 / FREQUENCY_RATE), + (42.3632837750485 / FREQUENCY_RATE), + (42.3906856403622 / FREQUENCY_RATE), + (42.4181229773463 / FREQUENCY_RATE), + (42.4455958549223 / FREQUENCY_RATE), + (42.4731043421905 / FREQUENCY_RATE), + (42.5006485084306 / FREQUENCY_RATE), + (42.5282284231019 / FREQUENCY_RATE), + (42.5558441558442 / FREQUENCY_RATE), + (42.5834957764782 / FREQUENCY_RATE), + (42.6111833550065 / FREQUENCY_RATE), + (42.6389069616135 / FREQUENCY_RATE), + (42.6666666666667 / FREQUENCY_RATE), + (42.6944625407166 / FREQUENCY_RATE), + (42.722294654498 / FREQUENCY_RATE), + (42.7501630789302 / FREQUENCY_RATE), + (42.7780678851175 / FREQUENCY_RATE), + (42.8060091443501 / FREQUENCY_RATE), + (42.8339869281046 / FREQUENCY_RATE), + (42.8620013080445 / FREQUENCY_RATE), + (42.890052356021 / FREQUENCY_RATE), + (42.9181401440733 / FREQUENCY_RATE), + (42.9462647444299 / FREQUENCY_RATE), + (42.9744262295082 / FREQUENCY_RATE), + (43.002624671916 / FREQUENCY_RATE), + (43.0308601444517 / FREQUENCY_RATE), + (43.0591327201051 / FREQUENCY_RATE), + (43.0874424720579 / FREQUENCY_RATE), + (43.1157894736842 / FREQUENCY_RATE), + (43.1441737985517 / FREQUENCY_RATE), + (43.1725955204216 / FREQUENCY_RATE), + (43.2010547132498 / FREQUENCY_RATE), + (43.2295514511873 / FREQUENCY_RATE), + (43.2580858085809 / FREQUENCY_RATE), + (43.2866578599736 / FREQUENCY_RATE), + (43.3152676801057 / FREQUENCY_RATE), + (43.3439153439153 / FREQUENCY_RATE), + (43.3726009265387 / FREQUENCY_RATE), + (43.4013245033113 / FREQUENCY_RATE), + (43.4300861497681 / FREQUENCY_RATE), + (43.4588859416446 / FREQUENCY_RATE), + (43.4877239548772 / FREQUENCY_RATE), + (43.5166002656043 / FREQUENCY_RATE), + (43.5455149501661 / FREQUENCY_RATE), + (43.5744680851064 / FREQUENCY_RATE), + (43.6034597471723 / FREQUENCY_RATE), + (43.6324900133156 / FREQUENCY_RATE), + (43.6615589606929 / FREQUENCY_RATE), + (43.6906666666667 / FREQUENCY_RATE), + (43.7198132088059 / FREQUENCY_RATE), + (43.7489986648865 / FREQUENCY_RATE), + (43.7782231128925 / FREQUENCY_RATE), + (43.807486631016 / FREQUENCY_RATE), + (43.8367892976589 / FREQUENCY_RATE), + (43.8661311914324 / FREQUENCY_RATE), + (43.8955123911587 / FREQUENCY_RATE), + (43.9249329758713 / FREQUENCY_RATE), + (43.9543930248156 / FREQUENCY_RATE), + (43.9838926174497 / FREQUENCY_RATE), + (44.0134318334453 / FREQUENCY_RATE), + (44.0430107526882 / FREQUENCY_RATE), + (44.0726294552791 / FREQUENCY_RATE), + (44.1022880215343 / FREQUENCY_RATE), + (44.1319865319865 / FREQUENCY_RATE), + (44.1617250673855 / FREQUENCY_RATE), + (44.1915037086986 / FREQUENCY_RATE), + (44.221322537112 / FREQUENCY_RATE), + (44.2511816340311 / FREQUENCY_RATE), + (44.2810810810811 / FREQUENCY_RATE), + (44.3110209601082 / FREQUENCY_RATE), + (44.34100135318 / FREQUENCY_RATE), + (44.3710223425863 / FREQUENCY_RATE), + (44.4010840108401 / FREQUENCY_RATE), + (44.431186440678 / FREQUENCY_RATE), + (44.4613297150611 / FREQUENCY_RATE), + (44.4915139171758 / FREQUENCY_RATE), + (44.5217391304348 / FREQUENCY_RATE), + (44.5520054384772 / FREQUENCY_RATE), + (44.5823129251701 / FREQUENCY_RATE), + (44.6126616746086 / FREQUENCY_RATE), + (44.6430517711172 / FREQUENCY_RATE), + (44.6734832992502 / FREQUENCY_RATE), + (44.7039563437926 / FREQUENCY_RATE), + (44.7344709897611 / FREQUENCY_RATE), + (44.7650273224044 / FREQUENCY_RATE), + (44.7956254272044 / FREQUENCY_RATE), + (44.8262653898769 / FREQUENCY_RATE), + (44.8569472963724 / FREQUENCY_RATE), + (44.8876712328767 / FREQUENCY_RATE), + (44.9184372858122 / FREQUENCY_RATE), + (44.9492455418381 / FREQUENCY_RATE), + (44.9800960878518 / FREQUENCY_RATE), + (45.010989010989 / FREQUENCY_RATE), + (45.0419243986254 / FREQUENCY_RATE), + (45.0729023383769 / FREQUENCY_RATE), + (45.1039229181005 / FREQUENCY_RATE), + (45.1349862258953 / FREQUENCY_RATE), + (45.1660923501034 / FREQUENCY_RATE), + (45.1972413793103 / FREQUENCY_RATE), + (45.2284334023465 / FREQUENCY_RATE), + (45.2596685082873 / FREQUENCY_RATE), + (45.2909467864547 / FREQUENCY_RATE), + (45.3222683264177 / FREQUENCY_RATE), + (45.3536332179931 / FREQUENCY_RATE), + (45.3850415512465 / FREQUENCY_RATE), + (45.4164934164934 / FREQUENCY_RATE), + (45.4479889042996 / FREQUENCY_RATE), + (45.4795281054823 / FREQUENCY_RATE), + (45.5111111111111 / FREQUENCY_RATE), + (45.5427380125087 / FREQUENCY_RATE), + (45.5744089012517 / FREQUENCY_RATE), + (45.6061238691719 / FREQUENCY_RATE), + (45.6378830083566 / FREQUENCY_RATE), + (45.6696864111498 / FREQUENCY_RATE), + (45.7015341701534 / FREQUENCY_RATE), + (45.7334263782275 / FREQUENCY_RATE), + (45.7653631284916 / FREQUENCY_RATE), + (45.7973445143256 / FREQUENCY_RATE), + (45.8293706293706 / FREQUENCY_RATE), + (45.8614415675297 / FREQUENCY_RATE), + (45.8935574229692 / FREQUENCY_RATE), + (45.9257182901191 / FREQUENCY_RATE), + (45.9579242636746 / FREQUENCY_RATE), + (45.9901754385965 / FREQUENCY_RATE), + (46.0224719101124 / FREQUENCY_RATE), + (46.0548137737175 / FREQUENCY_RATE), + (46.0872011251758 / FREQUENCY_RATE), + (46.1196340605208 / FREQUENCY_RATE), + (46.1521126760563 / FREQUENCY_RATE), + (46.184637068358 / FREQUENCY_RATE), + (46.2172073342736 / FREQUENCY_RATE), + (46.2498235709245 / FREQUENCY_RATE), + (46.2824858757062 / FREQUENCY_RATE), + (46.3151943462898 / FREQUENCY_RATE), + (46.3479490806223 / FREQUENCY_RATE), + (46.3807501769285 / FREQUENCY_RATE), + (46.4135977337111 / FREQUENCY_RATE), + (46.446491849752 / FREQUENCY_RATE), + (46.4794326241135 / FREQUENCY_RATE), + (46.5124201561391 / FREQUENCY_RATE), + (46.5454545454545 / FREQUENCY_RATE), + (46.5785358919687 / FREQUENCY_RATE), + (46.6116642958748 / FREQUENCY_RATE), + (46.6448398576513 / FREQUENCY_RATE), + (46.6780626780627 / FREQUENCY_RATE), + (46.7113328581611 / FREQUENCY_RATE), + (46.7446504992867 / FREQUENCY_RATE), + (46.7780157030692 / FREQUENCY_RATE), + (46.8114285714286 / FREQUENCY_RATE), + (46.8448892065761 / FREQUENCY_RATE), + (46.8783977110157 / FREQUENCY_RATE), + (46.9119541875447 / FREQUENCY_RATE), + (46.945558739255 / FREQUENCY_RATE), + (46.9792114695341 / FREQUENCY_RATE), + (47.012912482066 / FREQUENCY_RATE), + (47.0466618808327 / FREQUENCY_RATE), + (47.0804597701149 / FREQUENCY_RATE), + (47.1143062544932 / FREQUENCY_RATE), + (47.1482014388489 / FREQUENCY_RATE), + (47.1821454283657 / FREQUENCY_RATE), + (47.2161383285303 / FREQUENCY_RATE), + (47.2501802451334 / FREQUENCY_RATE), + (47.2842712842713 / FREQUENCY_RATE), + (47.3184115523466 / FREQUENCY_RATE), + (47.3526011560694 / FREQUENCY_RATE), + (47.3868402024584 / FREQUENCY_RATE), + (47.4211287988423 / FREQUENCY_RATE), + (47.4554670528602 / FREQUENCY_RATE), + (47.4898550724638 / FREQUENCY_RATE), + (47.5242929659173 / FREQUENCY_RATE), + (47.5587808417997 / FREQUENCY_RATE), + (47.5933188090051 / FREQUENCY_RATE), + (47.6279069767442 / FREQUENCY_RATE), + (47.6625454545455 / FREQUENCY_RATE), + (47.6972343522562 / FREQUENCY_RATE), + (47.7319737800437 / FREQUENCY_RATE), + (47.7667638483965 / FREQUENCY_RATE), + (47.8016046681255 / FREQUENCY_RATE), + (47.836496350365 / FREQUENCY_RATE), + (47.8714390065741 / FREQUENCY_RATE), + (47.906432748538 / FREQUENCY_RATE), + (47.9414776883687 / FREQUENCY_RATE), + (47.9765739385066 / FREQUENCY_RATE), + (48.0117216117216 / FREQUENCY_RATE), + (48.0469208211144 / FREQUENCY_RATE), + (48.0821716801174 / FREQUENCY_RATE), + (48.1174743024963 / FREQUENCY_RATE), + (48.1528288023512 / FREQUENCY_RATE), + (48.1882352941176 / FREQUENCY_RATE), + (48.2236938925681 / FREQUENCY_RATE), + (48.259204712813 / FREQUENCY_RATE), + (48.2947678703021 / FREQUENCY_RATE), + (48.330383480826 / FREQUENCY_RATE), + (48.3660516605166 / FREQUENCY_RATE), + (48.4017725258493 / FREQUENCY_RATE), + (48.4375461936438 / FREQUENCY_RATE), + (48.4733727810651 / FREQUENCY_RATE), + (48.5092524056255 / FREQUENCY_RATE), + (48.5451851851852 / FREQUENCY_RATE), + (48.581171237954 / FREQUENCY_RATE), + (48.6172106824926 / FREQUENCY_RATE), + (48.6533036377134 / FREQUENCY_RATE), + (48.6894502228826 / FREQUENCY_RATE), + (48.7256505576208 / FREQUENCY_RATE), + (48.7619047619048 / FREQUENCY_RATE), + (48.7982129560685 / FREQUENCY_RATE), + (48.8345752608048 / FREQUENCY_RATE), + (48.8709917971663 / FREQUENCY_RATE), + (48.9074626865672 / FREQUENCY_RATE), + (48.9439880507842 / FREQUENCY_RATE), + (48.9805680119582 / FREQUENCY_RATE), + (49.0172026925954 / FREQUENCY_RATE), + (49.0538922155689 / FREQUENCY_RATE), + (49.0906367041199 / FREQUENCY_RATE), + (49.1274362818591 / FREQUENCY_RATE), + (49.1642910727682 / FREQUENCY_RATE), + (49.2012012012012 / FREQUENCY_RATE), + (49.2381667918858 / FREQUENCY_RATE), + (49.2751879699248 / FREQUENCY_RATE), + (49.3122648607976 / FREQUENCY_RATE), + (49.3493975903615 / FREQUENCY_RATE), + (49.3865862848531 / FREQUENCY_RATE), + (49.4238310708899 / FREQUENCY_RATE), + (49.4611320754717 / FREQUENCY_RATE), + (49.4984894259819 / FREQUENCY_RATE), + (49.535903250189 / FREQUENCY_RATE), + (49.5733736762481 / FREQUENCY_RATE), + (49.6109008327025 / FREQUENCY_RATE), + (49.6484848484849 / FREQUENCY_RATE), + (49.6861258529189 / FREQUENCY_RATE), + (49.7238239757208 / FREQUENCY_RATE), + (49.7615793470008 / FREQUENCY_RATE), + (49.7993920972644 / FREQUENCY_RATE), + (49.8372623574145 / FREQUENCY_RATE), + (49.8751902587519 / FREQUENCY_RATE), + (49.9131759329779 / FREQUENCY_RATE), + (49.9512195121951 / FREQUENCY_RATE), + (49.9893211289092 / FREQUENCY_RATE), + (50.0274809160305 / FREQUENCY_RATE), + (50.0656990068755 / FREQUENCY_RATE), + (50.1039755351682 / FREQUENCY_RATE), + (50.1423106350421 / FREQUENCY_RATE), + (50.1807044410413 / FREQUENCY_RATE), + (50.2191570881226 / FREQUENCY_RATE), + (50.2576687116564 / FREQUENCY_RATE), + (50.296239447429 / FREQUENCY_RATE), + (50.3348694316436 / FREQUENCY_RATE), + (50.3735588009224 / FREQUENCY_RATE), + (50.4123076923077 / FREQUENCY_RATE), + (50.451116243264 / FREQUENCY_RATE), + (50.4899845916795 / FREQUENCY_RATE), + (50.5289128758674 / FREQUENCY_RATE), + (50.5679012345679 / FREQUENCY_RATE), + (50.6069498069498 / FREQUENCY_RATE), + (50.6460587326121 / FREQUENCY_RATE), + (50.6852281515855 / FREQUENCY_RATE), + (50.7244582043344 / FREQUENCY_RATE), + (50.7637490317583 / FREQUENCY_RATE), + (50.8031007751938 / FREQUENCY_RATE), + (50.8425135764158 / FREQUENCY_RATE), + (50.8819875776397 / FREQUENCY_RATE), + (50.9215229215229 / FREQUENCY_RATE), + (50.9611197511664 / FREQUENCY_RATE), + (51.0007782101167 / FREQUENCY_RATE), + (51.0404984423676 / FREQUENCY_RATE), + (51.0802805923617 / FREQUENCY_RATE), + (51.1201248049922 / FREQUENCY_RATE), + (51.160031225605 / FREQUENCY_RATE), + (51.2 / FREQUENCY_RATE), + (51.2400312744331 / FREQUENCY_RATE), + (51.2801251956182 / FREQUENCY_RATE), + (51.3202819107283 / FREQUENCY_RATE), + (51.3605015673981 / FREQUENCY_RATE), + (51.4007843137255 / FREQUENCY_RATE), + (51.4411302982732 / FREQUENCY_RATE), + (51.4815396700707 / FREQUENCY_RATE), + (51.5220125786164 / FREQUENCY_RATE), + (51.5625491738788 / FREQUENCY_RATE), + (51.6031496062992 / FREQUENCY_RATE), + (51.6438140267928 / FREQUENCY_RATE), + (51.6845425867508 / FREQUENCY_RATE), + (51.7253354380426 / FREQUENCY_RATE), + (51.7661927330174 / FREQUENCY_RATE), + (51.8071146245059 / FREQUENCY_RATE), + (51.8481012658228 / FREQUENCY_RATE), + (51.889152810768 / FREQUENCY_RATE), + (51.9302694136292 / FREQUENCY_RATE), + (51.9714512291832 / FREQUENCY_RATE), + (52.0126984126984 / FREQUENCY_RATE), + (52.0540111199365 / FREQUENCY_RATE), + (52.0953895071542 / FREQUENCY_RATE), + (52.1368337311058 / FREQUENCY_RATE), + (52.1783439490446 / FREQUENCY_RATE), + (52.2199203187251 / FREQUENCY_RATE), + (52.2615629984051 / FREQUENCY_RATE), + (52.3032721468476 / FREQUENCY_RATE), + (52.3450479233227 / FREQUENCY_RATE), + (52.3868904876099 / FREQUENCY_RATE), + (52.4288 / FREQUENCY_RATE), + (52.470776621297 / FREQUENCY_RATE), + (52.5128205128205 / FREQUENCY_RATE), + (52.5549318364074 / FREQUENCY_RATE), + (52.5971107544141 / FREQUENCY_RATE), + (52.6393574297189 / FREQUENCY_RATE), + (52.6816720257235 / FREQUENCY_RATE), + (52.7240547063556 / FREQUENCY_RATE), + (52.7665056360709 / FREQUENCY_RATE), + (52.809024979855 / FREQUENCY_RATE), + (52.8516129032258 / FREQUENCY_RATE), + (52.8942695722357 / FREQUENCY_RATE), + (52.9369951534734 / FREQUENCY_RATE), + (52.9797898140663 / FREQUENCY_RATE), + (53.0226537216829 / FREQUENCY_RATE), + (53.0655870445344 / FREQUENCY_RATE), + (53.1085899513776 / FREQUENCY_RATE), + (53.1516626115166 / FREQUENCY_RATE), + (53.1948051948052 / FREQUENCY_RATE), + (53.2380178716491 / FREQUENCY_RATE), + (53.2813008130081 / FREQUENCY_RATE), + (53.3246541903987 / FREQUENCY_RATE), + (53.3680781758958 / FREQUENCY_RATE), + (53.4115729421353 / FREQUENCY_RATE), + (53.4551386623165 / FREQUENCY_RATE), + (53.4987755102041 / FREQUENCY_RATE), + (53.5424836601307 / FREQUENCY_RATE), + (53.5862632869992 / FREQUENCY_RATE), + (53.6301145662848 / FREQUENCY_RATE), + (53.6740376740377 / FREQUENCY_RATE), + (53.7180327868852 / FREQUENCY_RATE), + (53.7621000820345 / FREQUENCY_RATE), + (53.8062397372742 / FREQUENCY_RATE), + (53.8504519309778 / FREQUENCY_RATE), + (53.8947368421053 / FREQUENCY_RATE), + (53.9390946502058 / FREQUENCY_RATE), + (53.9835255354201 / FREQUENCY_RATE), + (54.0280296784831 / FREQUENCY_RATE), + (54.0726072607261 / FREQUENCY_RATE), + (54.1172584640793 / FREQUENCY_RATE), + (54.1619834710744 / FREQUENCY_RATE), + (54.206782464847 / FREQUENCY_RATE), + (54.2516556291391 / FREQUENCY_RATE), + (54.2966031483016 / FREQUENCY_RATE), + (54.3416252072969 / FREQUENCY_RATE), + (54.3867219917012 / FREQUENCY_RATE), + (54.4318936877076 / FREQUENCY_RATE), + (54.477140482128 / FREQUENCY_RATE), + (54.522462562396 / FREQUENCY_RATE), + (54.5678601165695 / FREQUENCY_RATE), + (54.6133333333333 / FREQUENCY_RATE), + (54.6588824020017 / FREQUENCY_RATE), + (54.7045075125209 / FREQUENCY_RATE), + (54.750208855472 / FREQUENCY_RATE), + (54.7959866220736 / FREQUENCY_RATE), + (54.8418410041841 / FREQUENCY_RATE), + (54.8877721943049 / FREQUENCY_RATE), + (54.9337803855826 / FREQUENCY_RATE), + (54.9798657718121 / FREQUENCY_RATE), + (55.0260285474391 / FREQUENCY_RATE), + (55.072268907563 / FREQUENCY_RATE), + (55.1185870479394 / FREQUENCY_RATE), + (55.1649831649832 / FREQUENCY_RATE), + (55.2114574557709 / FREQUENCY_RATE), + (55.2580101180438 / FREQUENCY_RATE), + (55.304641350211 / FREQUENCY_RATE), + (55.3513513513514 / FREQUENCY_RATE), + (55.3981403212172 / FREQUENCY_RATE), + (55.4450084602369 / FREQUENCY_RATE), + (55.4919559695174 / FREQUENCY_RATE), + (55.5389830508475 / FREQUENCY_RATE), + (55.5860899067006 / FREQUENCY_RATE), + (55.6332767402377 / FREQUENCY_RATE), + (55.6805437553101 / FREQUENCY_RATE), + (55.7278911564626 / FREQUENCY_RATE), + (55.7753191489362 / FREQUENCY_RATE), + (55.8228279386712 / FREQUENCY_RATE), + (55.8704177323103 / FREQUENCY_RATE), + (55.9180887372014 / FREQUENCY_RATE), + (55.9658411614005 / FREQUENCY_RATE), + (56.0136752136752 / FREQUENCY_RATE), + (56.0615911035073 / FREQUENCY_RATE), + (56.1095890410959 / FREQUENCY_RATE), + (56.1576692373608 / FREQUENCY_RATE), + (56.2058319039451 / FREQUENCY_RATE), + (56.2540772532189 / FREQUENCY_RATE), + (56.3024054982818 / FREQUENCY_RATE), + (56.3508168529665 / FREQUENCY_RATE), + (56.3993115318417 / FREQUENCY_RATE), + (56.4478897502153 / FREQUENCY_RATE), + (56.4965517241379 / FREQUENCY_RATE), + (56.5452976704055 / FREQUENCY_RATE), + (56.594127806563 / FREQUENCY_RATE), + (56.6430423509075 / FREQUENCY_RATE), + (56.6920415224914 / FREQUENCY_RATE), + (56.7411255411255 / FREQUENCY_RATE), + (56.790294627383 / FREQUENCY_RATE), + (56.8395490026019 / FREQUENCY_RATE), + (56.8888888888889 / FREQUENCY_RATE), + (56.9383145091225 / FREQUENCY_RATE), + (56.9878260869565 / FREQUENCY_RATE), + (57.0374238468233 / FREQUENCY_RATE), + (57.0871080139373 / FREQUENCY_RATE), + (57.1368788142982 / FREQUENCY_RATE), + (57.1867364746946 / FREQUENCY_RATE), + (57.2366812227074 / FREQUENCY_RATE), + (57.2867132867133 / FREQUENCY_RATE), + (57.336832895888 / FREQUENCY_RATE), + (57.3870402802102 / FREQUENCY_RATE), + (57.4373356704645 / FREQUENCY_RATE), + (57.4877192982456 / FREQUENCY_RATE), + (57.5381913959614 / FREQUENCY_RATE), + (57.5887521968366 / FREQUENCY_RATE), + (57.6394019349165 / FREQUENCY_RATE), + (57.6901408450704 / FREQUENCY_RATE), + (57.7409691629956 / FREQUENCY_RATE), + (57.7918871252205 / FREQUENCY_RATE), + (57.8428949691086 / FREQUENCY_RATE), + (57.8939929328622 / FREQUENCY_RATE), + (57.9451812555261 / FREQUENCY_RATE), + (57.9964601769912 / FREQUENCY_RATE), + (58.0478299379982 / FREQUENCY_RATE), + (58.0992907801418 / FREQUENCY_RATE), + (58.150842945874 / FREQUENCY_RATE), + (58.202486678508 / FREQUENCY_RATE), + (58.2542222222222 / FREQUENCY_RATE), + (58.3060498220641 / FREQUENCY_RATE), + (58.3579697239537 / FREQUENCY_RATE), + (58.4099821746881 / FREQUENCY_RATE), + (58.4620874219447 / FREQUENCY_RATE), + (58.5142857142857 / FREQUENCY_RATE), + (58.5665773011618 / FREQUENCY_RATE), + (58.6189624329159 / FREQUENCY_RATE), + (58.6714413607878 / FREQUENCY_RATE), + (58.7240143369176 / FREQUENCY_RATE), + (58.7766816143498 / FREQUENCY_RATE), + (58.8294434470377 / FREQUENCY_RATE), + (58.8823000898473 / FREQUENCY_RATE), + (58.9352517985612 / FREQUENCY_RATE), + (58.988298829883 / FREQUENCY_RATE), + (59.0414414414414 / FREQUENCY_RATE), + (59.0946798917944 / FREQUENCY_RATE), + (59.1480144404332 / FREQUENCY_RATE), + (59.2014453477868 / FREQUENCY_RATE), + (59.254972875226 / FREQUENCY_RATE), + (59.3085972850679 / FREQUENCY_RATE), + (59.3623188405797 / FREQUENCY_RATE), + (59.4161378059837 / FREQUENCY_RATE), + (59.470054446461 / FREQUENCY_RATE), + (59.5240690281562 / FREQUENCY_RATE), + (59.5781818181818 / FREQUENCY_RATE), + (59.6323930846224 / FREQUENCY_RATE), + (59.6867030965392 / FREQUENCY_RATE), + (59.7411121239745 / FREQUENCY_RATE), + (59.7956204379562 / FREQUENCY_RATE), + (59.8502283105023 / FREQUENCY_RATE), + (59.9049360146252 / FREQUENCY_RATE), + (59.9597438243367 / FREQUENCY_RATE), + (60.014652014652 / FREQUENCY_RATE), + (60.0696608615949 / FREQUENCY_RATE), + (60.1247706422018 / FREQUENCY_RATE), + (60.1799816345271 / FREQUENCY_RATE), + (60.2352941176471 / FREQUENCY_RATE), + (60.2907083716651 / FREQUENCY_RATE), + (60.3462246777164 / FREQUENCY_RATE), + (60.4018433179724 / FREQUENCY_RATE), + (60.4575645756458 / FREQUENCY_RATE), + (60.5133887349954 / FREQUENCY_RATE), + (60.5693160813309 / FREQUENCY_RATE), + (60.6253469010176 / FREQUENCY_RATE), + (60.6814814814815 / FREQUENCY_RATE), + (60.7377201112141 / FREQUENCY_RATE), + (60.7940630797774 / FREQUENCY_RATE), + (60.8505106778087 / FREQUENCY_RATE), + (60.907063197026 / FREQUENCY_RATE), + (60.9637209302326 / FREQUENCY_RATE), + (61.0204841713222 / FREQUENCY_RATE), + (61.0773532152843 / FREQUENCY_RATE), + (61.134328358209 / FREQUENCY_RATE), + (61.1914098972923 / FREQUENCY_RATE), + (61.2485981308411 / FREQUENCY_RATE), + (61.3058933582788 / FREQUENCY_RATE), + (61.3632958801498 / FREQUENCY_RATE), + (61.4208059981256 / FREQUENCY_RATE), + (61.4784240150094 / FREQUENCY_RATE), + (61.5361502347418 / FREQUENCY_RATE), + (61.593984962406 / FREQUENCY_RATE), + (61.6519285042333 / FREQUENCY_RATE), + (61.7099811676083 / FREQUENCY_RATE), + (61.7681432610745 / FREQUENCY_RATE), + (61.8264150943396 / FREQUENCY_RATE), + (61.8847969782814 / FREQUENCY_RATE), + (61.9432892249527 / FREQUENCY_RATE), + (62.0018921475875 / FREQUENCY_RATE), + (62.0606060606061 / FREQUENCY_RATE), + (62.1194312796209 / FREQUENCY_RATE), + (62.1783681214421 / FREQUENCY_RATE), + (62.2374169040836 / FREQUENCY_RATE), + (62.2965779467681 / FREQUENCY_RATE), + (62.3558515699334 / FREQUENCY_RATE), + (62.4152380952381 / FREQUENCY_RATE), + (62.4747378455672 / FREQUENCY_RATE), + (62.5343511450382 / FREQUENCY_RATE), + (62.5940783190067 / FREQUENCY_RATE), + (62.6539196940727 / FREQUENCY_RATE), + (62.7138755980861 / FREQUENCY_RATE), + (62.7739463601533 / FREQUENCY_RATE), + (62.8341323106424 / FREQUENCY_RATE), + (62.89443378119 / FREQUENCY_RATE), + (62.954851104707 / FREQUENCY_RATE), + (63.0153846153846 / FREQUENCY_RATE), + (63.0760346487007 / FREQUENCY_RATE), + (63.1368015414258 / FREQUENCY_RATE), + (63.1976856316297 / FREQUENCY_RATE), + (63.2586872586873 / FREQUENCY_RATE), + (63.319806763285 / FREQUENCY_RATE), + (63.3810444874275 / FREQUENCY_RATE), + (63.4424007744434 / FREQUENCY_RATE), + (63.5038759689923 / FREQUENCY_RATE), + (63.5654704170708 / FREQUENCY_RATE), + (63.6271844660194 / FREQUENCY_RATE), + (63.6890184645287 / FREQUENCY_RATE), + (63.7509727626459 / FREQUENCY_RATE), + (63.8130477117819 / FREQUENCY_RATE), + (63.8752436647174 / FREQUENCY_RATE), + (63.9375609756098 / FREQUENCY_RATE), + (64 / FREQUENCY_RATE), + (64.0625610948192 / FREQUENCY_RATE), + (64.1252446183953 / FREQUENCY_RATE), + (64.1880509304603 / FREQUENCY_RATE), + (64.2509803921569 / FREQUENCY_RATE), + (64.3140333660451 / FREQUENCY_RATE), + (64.37721021611 / FREQUENCY_RATE), + (64.440511307768 / FREQUENCY_RATE), + (64.503937007874 / FREQUENCY_RATE), + (64.5674876847291 / FREQUENCY_RATE), + (64.6311637080868 / FREQUENCY_RATE), + (64.6949654491609 / FREQUENCY_RATE), + (64.7588932806324 / FREQUENCY_RATE), + (64.8229475766568 / FREQUENCY_RATE), + (64.8871287128713 / FREQUENCY_RATE), + (64.9514370664024 / FREQUENCY_RATE), + (65.015873015873 / FREQUENCY_RATE), + (65.0804369414101 / FREQUENCY_RATE), + (65.1451292246521 / FREQUENCY_RATE), + (65.2099502487562 / FREQUENCY_RATE), + (65.2749003984064 / FREQUENCY_RATE), + (65.3399800598205 / FREQUENCY_RATE), + (65.4051896207585 / FREQUENCY_RATE), + (65.4705294705295 / FREQUENCY_RATE), + (65.536 / FREQUENCY_RATE), + (65.6016016016016 / FREQUENCY_RATE), + (65.6673346693387 / FREQUENCY_RATE), + (65.7331995987964 / FREQUENCY_RATE), + (65.7991967871486 / FREQUENCY_RATE), + (65.8653266331658 / FREQUENCY_RATE), + (65.9315895372234 / FREQUENCY_RATE), + (65.9979859013092 / FREQUENCY_RATE), + (66.0645161290323 / FREQUENCY_RATE), + (66.1311806256307 / FREQUENCY_RATE), + (66.1979797979798 / FREQUENCY_RATE), + (66.2649140546006 / FREQUENCY_RATE), + (66.331983805668 / FREQUENCY_RATE), + (66.3991894630193 / FREQUENCY_RATE), + (66.4665314401623 / FREQUENCY_RATE), + (66.5340101522843 / FREQUENCY_RATE), + (66.6016260162602 / FREQUENCY_RATE), + (66.6693794506612 / FREQUENCY_RATE), + (66.7372708757637 / FREQUENCY_RATE), + (66.8053007135576 / FREQUENCY_RATE), + (66.8734693877551 / FREQUENCY_RATE), + (66.9417773237998 / FREQUENCY_RATE), + (67.0102249488753 / FREQUENCY_RATE), + (67.078812691914 / FREQUENCY_RATE), + (67.1475409836066 / FREQUENCY_RATE), + (67.2164102564103 / FREQUENCY_RATE), + (67.2854209445585 / FREQUENCY_RATE), + (67.3545734840699 / FREQUENCY_RATE), + (67.4238683127572 / FREQUENCY_RATE), + (67.4933058702369 / FREQUENCY_RATE), + (67.5628865979382 / FREQUENCY_RATE), + (67.6326109391125 / FREQUENCY_RATE), + (67.702479338843 / FREQUENCY_RATE), + (67.7724922440538 / FREQUENCY_RATE), + (67.8426501035197 / FREQUENCY_RATE), + (67.9129533678757 / FREQUENCY_RATE), + (67.9834024896266 / FREQUENCY_RATE), + (68.0539979231568 / FREQUENCY_RATE), + (68.1247401247401 / FREQUENCY_RATE), + (68.1956295525494 / FREQUENCY_RATE), + (68.2666666666667 / FREQUENCY_RATE), + (68.3378519290928 / FREQUENCY_RATE), + (68.4091858037578 / FREQUENCY_RATE), + (68.4806687565308 / FREQUENCY_RATE), + (68.5523012552301 / FREQUENCY_RATE), + (68.6240837696335 / FREQUENCY_RATE), + (68.6960167714885 / FREQUENCY_RATE), + (68.7681007345226 / FREQUENCY_RATE), + (68.8403361344538 / FREQUENCY_RATE), + (68.9127234490011 / FREQUENCY_RATE), + (68.9852631578947 / FREQUENCY_RATE), + (69.0579557428872 / FREQUENCY_RATE), + (69.1308016877637 / FREQUENCY_RATE), + (69.2038014783527 / FREQUENCY_RATE), + (69.276955602537 / FREQUENCY_RATE), + (69.3502645502646 / FREQUENCY_RATE), + (69.4237288135593 / FREQUENCY_RATE), + (69.4973488865324 / FREQUENCY_RATE), + (69.5711252653928 / FREQUENCY_RATE), + (69.6450584484591 / FREQUENCY_RATE), + (69.7191489361702 / FREQUENCY_RATE), + (69.7933972310969 / FREQUENCY_RATE), + (69.8678038379531 / FREQUENCY_RATE), + (69.9423692636073 / FREQUENCY_RATE), + (70.017094017094 / FREQUENCY_RATE), + (70.0919786096257 / FREQUENCY_RATE), + (70.1670235546039 / FREQUENCY_RATE), + (70.2422293676313 / FREQUENCY_RATE), + (70.3175965665236 / FREQUENCY_RATE), + (70.3931256713212 / FREQUENCY_RATE), + (70.4688172043011 / FREQUENCY_RATE), + (70.5446716899892 / FREQUENCY_RATE), + (70.6206896551724 / FREQUENCY_RATE), + (70.6968716289105 / FREQUENCY_RATE), + (70.7732181425486 / FREQUENCY_RATE), + (70.8497297297297 / FREQUENCY_RATE), + (70.9264069264069 / FREQUENCY_RATE), + (71.0032502708559 / FREQUENCY_RATE), + (71.0802603036876 / FREQUENCY_RATE), + (71.157437567861 / FREQUENCY_RATE), + (71.2347826086957 / FREQUENCY_RATE), + (71.3122959738847 / FREQUENCY_RATE), + (71.3899782135076 / FREQUENCY_RATE), + (71.4678298800436 / FREQUENCY_RATE), + (71.5458515283843 / FREQUENCY_RATE), + (71.624043715847 / FREQUENCY_RATE), + (71.7024070021882 / FREQUENCY_RATE), + (71.7809419496166 / FREQUENCY_RATE), + (71.859649122807 / FREQUENCY_RATE), + (71.9385290889133 / FREQUENCY_RATE), + (72.0175824175824 / FREQUENCY_RATE), + (72.0968096809681 / FREQUENCY_RATE), + (72.1762114537445 / FREQUENCY_RATE), + (72.2557883131202 / FREQUENCY_RATE), + (72.3355408388521 / FREQUENCY_RATE), + (72.4154696132597 / FREQUENCY_RATE), + (72.4955752212389 / FREQUENCY_RATE), + (72.5758582502769 / FREQUENCY_RATE), + (72.6563192904656 / FREQUENCY_RATE), + (72.7369589345172 / FREQUENCY_RATE), + (72.8177777777778 / FREQUENCY_RATE), + (72.8987764182425 / FREQUENCY_RATE), + (72.9799554565702 / FREQUENCY_RATE), + (73.0613154960981 / FREQUENCY_RATE), + (73.1428571428571 / FREQUENCY_RATE), + (73.2245810055866 / FREQUENCY_RATE), + (73.3064876957494 / FREQUENCY_RATE), + (73.3885778275476 / FREQUENCY_RATE), + (73.4708520179372 / FREQUENCY_RATE), + (73.5533108866442 / FREQUENCY_RATE), + (73.6359550561798 / FREQUENCY_RATE), + (73.718785151856 / FREQUENCY_RATE), + (73.8018018018018 / FREQUENCY_RATE), + (73.8850056369786 / FREQUENCY_RATE), + (73.9683972911964 / FREQUENCY_RATE), + (74.0519774011299 / FREQUENCY_RATE), + (74.1357466063348 / FREQUENCY_RATE), + (74.2197055492639 / FREQUENCY_RATE), + (74.3038548752835 / FREQUENCY_RATE), + (74.3881952326901 / FREQUENCY_RATE), + (74.4727272727273 / FREQUENCY_RATE), + (74.5574516496018 / FREQUENCY_RATE), + (74.6423690205011 / FREQUENCY_RATE), + (74.72748004561 / FREQUENCY_RATE), + (74.8127853881279 / FREQUENCY_RATE), + (74.8982857142857 / FREQUENCY_RATE), + (74.9839816933639 / FREQUENCY_RATE), + (75.0698739977091 / FREQUENCY_RATE), + (75.1559633027523 / FREQUENCY_RATE), + (75.2422502870264 / FREQUENCY_RATE), + (75.3287356321839 / FREQUENCY_RATE), + (75.415420023015 / FREQUENCY_RATE), + (75.5023041474654 / FREQUENCY_RATE), + (75.5893886966551 / FREQUENCY_RATE), + (75.6766743648961 / FREQUENCY_RATE), + (75.764161849711 / FREQUENCY_RATE), + (75.8518518518518 / FREQUENCY_RATE), + (75.9397450753187 / FREQUENCY_RATE), + (76.0278422273782 / FREQUENCY_RATE), + (76.116144018583 / FREQUENCY_RATE), + (76.2046511627907 / FREQUENCY_RATE), + (76.2933643771828 / FREQUENCY_RATE), + (76.3822843822844 / FREQUENCY_RATE), + (76.4714119019837 / FREQUENCY_RATE), + (76.5607476635514 / FREQUENCY_RATE), + (76.6502923976608 / FREQUENCY_RATE), + (76.7400468384075 / FREQUENCY_RATE), + (76.8300117233294 / FREQUENCY_RATE), + (76.9201877934272 / FREQUENCY_RATE), + (77.0105757931845 / FREQUENCY_RATE), + (77.1011764705882 / FREQUENCY_RATE), + (77.1919905771496 / FREQUENCY_RATE), + (77.2830188679245 / FREQUENCY_RATE), + (77.3742621015348 / FREQUENCY_RATE), + (77.4657210401891 / FREQUENCY_RATE), + (77.5573964497041 / FREQUENCY_RATE), + (77.6492890995261 / FREQUENCY_RATE), + (77.7413997627521 / FREQUENCY_RATE), + (77.833729216152 / FREQUENCY_RATE), + (77.9262782401902 / FREQUENCY_RATE), + (78.0190476190476 / FREQUENCY_RATE), + (78.1120381406436 / FREQUENCY_RATE), + (78.2052505966587 / FREQUENCY_RATE), + (78.2986857825568 / FREQUENCY_RATE), + (78.3923444976077 / FREQUENCY_RATE), + (78.4862275449102 / FREQUENCY_RATE), + (78.5803357314149 / FREQUENCY_RATE), + (78.6746698679472 / FREQUENCY_RATE), + (78.7692307692308 / FREQUENCY_RATE), + (78.864019253911 / FREQUENCY_RATE), + (78.9590361445783 / FREQUENCY_RATE), + (79.0542822677925 / FREQUENCY_RATE), + (79.1497584541063 / FREQUENCY_RATE), + (79.2454655380895 / FREQUENCY_RATE), + (79.3414043583535 / FREQUENCY_RATE), + (79.4375757575758 / FREQUENCY_RATE), + (79.5339805825243 / FREQUENCY_RATE), + (79.6306196840826 / FREQUENCY_RATE), + (79.7274939172749 / FREQUENCY_RATE), + (79.8246041412911 / FREQUENCY_RATE), + (79.9219512195122 / FREQUENCY_RATE), + (80.019536019536 / FREQUENCY_RATE), + (80.1173594132029 / FREQUENCY_RATE), + (80.2154222766218 / FREQUENCY_RATE), + (80.3137254901961 / FREQUENCY_RATE), + (80.4122699386503 / FREQUENCY_RATE), + (80.5110565110565 / FREQUENCY_RATE), + (80.610086100861 / FREQUENCY_RATE), + (80.7093596059113 / FREQUENCY_RATE), + (80.8088779284834 / FREQUENCY_RATE), + (80.9086419753086 / FREQUENCY_RATE), + (81.008652657602 / FREQUENCY_RATE), + (81.1089108910891 / FREQUENCY_RATE), + (81.2094175960347 / FREQUENCY_RATE), + (81.3101736972705 / FREQUENCY_RATE), + (81.4111801242236 / FREQUENCY_RATE), + (81.5124378109453 / FREQUENCY_RATE), + (81.6139476961395 / FREQUENCY_RATE), + (81.715710723192 / FREQUENCY_RATE), + (81.8177278401998 / FREQUENCY_RATE), + (81.92 / FREQUENCY_RATE), + (82.0225281602002 / FREQUENCY_RATE), + (82.125313283208 / FREQUENCY_RATE), + (82.228356336261 / FREQUENCY_RATE), + (82.3316582914573 / FREQUENCY_RATE), + (82.4352201257862 / FREQUENCY_RATE), + (82.5390428211587 / FREQUENCY_RATE), + (82.6431273644388 / FREQUENCY_RATE), + (82.7474747474748 / FREQUENCY_RATE), + (82.8520859671302 / FREQUENCY_RATE), + (82.9569620253165 / FREQUENCY_RATE), + (83.0621039290241 / FREQUENCY_RATE), + (83.1675126903553 / FREQUENCY_RATE), + (83.2731893265565 / FREQUENCY_RATE), + (83.3791348600509 / FREQUENCY_RATE), + (83.4853503184713 / FREQUENCY_RATE), + (83.5918367346939 / FREQUENCY_RATE), + (83.698595146871 / FREQUENCY_RATE), + (83.8056265984655 / FREQUENCY_RATE), + (83.9129321382842 / FREQUENCY_RATE), + (84.0205128205128 / FREQUENCY_RATE), + (84.1283697047497 / FREQUENCY_RATE), + (84.2365038560411 / FREQUENCY_RATE), + (84.3449163449163 / FREQUENCY_RATE), + (84.4536082474227 / FREQUENCY_RATE), + (84.5625806451613 / FREQUENCY_RATE), + (84.671834625323 / FREQUENCY_RATE), + (84.7813712807245 / FREQUENCY_RATE), + (84.8911917098446 / FREQUENCY_RATE), + (85.0012970168612 / FREQUENCY_RATE), + (85.1116883116883 / FREQUENCY_RATE), + (85.222366710013 / FREQUENCY_RATE), + (85.3333333333333 / FREQUENCY_RATE), + (85.4445893089961 / FREQUENCY_RATE), + (85.556135770235 / FREQUENCY_RATE), + (85.6679738562091 / FREQUENCY_RATE), + (85.7801047120419 / FREQUENCY_RATE), + (85.8925294888598 / FREQUENCY_RATE), + (86.005249343832 / FREQUENCY_RATE), + (86.1182654402102 / FREQUENCY_RATE), + (86.2315789473684 / FREQUENCY_RATE), + (86.3451910408432 / FREQUENCY_RATE), + (86.4591029023747 / FREQUENCY_RATE), + (86.5733157199472 / FREQUENCY_RATE), + (86.6878306878307 / FREQUENCY_RATE), + (86.8026490066225 / FREQUENCY_RATE), + (86.9177718832891 / FREQUENCY_RATE), + (87.0332005312085 / FREQUENCY_RATE), + (87.1489361702128 / FREQUENCY_RATE), + (87.2649800266312 / FREQUENCY_RATE), + (87.3813333333333 / FREQUENCY_RATE), + (87.497997329773 / FREQUENCY_RATE), + (87.6149732620321 / FREQUENCY_RATE), + (87.7322623828648 / FREQUENCY_RATE), + (87.8498659517426 / FREQUENCY_RATE), + (87.9677852348993 / FREQUENCY_RATE), + (88.0860215053763 / FREQUENCY_RATE), + (88.2045760430686 / FREQUENCY_RATE), + (88.3234501347709 / FREQUENCY_RATE), + (88.442645074224 / FREQUENCY_RATE), + (88.5621621621622 / FREQUENCY_RATE), + (88.68200270636 / FREQUENCY_RATE), + (88.8021680216802 / FREQUENCY_RATE), + (88.9226594301221 / FREQUENCY_RATE), + (89.0434782608696 / FREQUENCY_RATE), + (89.1646258503401 / FREQUENCY_RATE), + (89.2861035422343 / FREQUENCY_RATE), + (89.4079126875853 / FREQUENCY_RATE), + (89.5300546448087 / FREQUENCY_RATE), + (89.6525307797538 / FREQUENCY_RATE), + (89.7753424657534 / FREQUENCY_RATE), + (89.8984910836763 / FREQUENCY_RATE), + (90.021978021978 / FREQUENCY_RATE), + (90.1458046767538 / FREQUENCY_RATE), + (90.2699724517906 / FREQUENCY_RATE), + (90.3944827586207 / FREQUENCY_RATE), + (90.5193370165746 / FREQUENCY_RATE), + (90.6445366528354 / FREQUENCY_RATE), + (90.7700831024931 / FREQUENCY_RATE), + (90.8959778085992 / FREQUENCY_RATE), + (91.0222222222222 / FREQUENCY_RATE), + (91.1488178025035 / FREQUENCY_RATE), + (91.2757660167131 / FREQUENCY_RATE), + (91.4030683403068 / FREQUENCY_RATE), + (91.5307262569833 / FREQUENCY_RATE), + (91.6587412587413 / FREQUENCY_RATE), + (91.7871148459384 / FREQUENCY_RATE), + (91.9158485273492 / FREQUENCY_RATE), + (92.0449438202247 / FREQUENCY_RATE), + (92.1744022503516 / FREQUENCY_RATE), + (92.3042253521127 / FREQUENCY_RATE), + (92.4344146685472 / FREQUENCY_RATE), + (92.5649717514124 / FREQUENCY_RATE), + (92.6958981612447 / FREQUENCY_RATE), + (92.8271954674221 / FREQUENCY_RATE), + (92.958865248227 / FREQUENCY_RATE), + (93.0909090909091 / FREQUENCY_RATE), + (93.2233285917497 / FREQUENCY_RATE), + (93.3561253561254 / FREQUENCY_RATE), + (93.4893009985735 / FREQUENCY_RATE), + (93.6228571428572 / FREQUENCY_RATE), + (93.7567954220315 / FREQUENCY_RATE), + (93.89111747851 / FREQUENCY_RATE), + (94.025824964132 / FREQUENCY_RATE), + (94.1609195402299 / FREQUENCY_RATE), + (94.2964028776978 / FREQUENCY_RATE), + (94.4322766570605 / FREQUENCY_RATE), + (94.5685425685426 / FREQUENCY_RATE), + (94.7052023121387 / FREQUENCY_RATE), + (94.8422575976845 / FREQUENCY_RATE), + (94.9797101449275 / FREQUENCY_RATE), + (95.1175616835994 / FREQUENCY_RATE), + (95.2558139534884 / FREQUENCY_RATE), + (95.3944687045124 / FREQUENCY_RATE), + (95.533527696793 / FREQUENCY_RATE), + (95.6729927007299 / FREQUENCY_RATE), + (95.812865497076 / FREQUENCY_RATE), + (95.9531478770132 / FREQUENCY_RATE), + (96.0938416422287 / FREQUENCY_RATE), + (96.2349486049927 / FREQUENCY_RATE), + (96.3764705882353 / FREQUENCY_RATE), + (96.5184094256259 / FREQUENCY_RATE), + (96.6607669616519 / FREQUENCY_RATE), + (96.8035450516987 / FREQUENCY_RATE), + (96.9467455621302 / FREQUENCY_RATE), + (97.0903703703704 / FREQUENCY_RATE), + (97.2344213649852 / FREQUENCY_RATE), + (97.3789004457652 / FREQUENCY_RATE), + (97.5238095238095 / FREQUENCY_RATE), + (97.6691505216095 / FREQUENCY_RATE), + (97.8149253731343 / FREQUENCY_RATE), + (97.9611360239163 / FREQUENCY_RATE), + (98.1077844311377 / FREQUENCY_RATE), + (98.2548725637181 / FREQUENCY_RATE), + (98.4024024024024 / FREQUENCY_RATE), + (98.5503759398496 / FREQUENCY_RATE), + (98.6987951807229 / FREQUENCY_RATE), + (98.8476621417798 / FREQUENCY_RATE), + (98.9969788519637 / FREQUENCY_RATE), + (99.1467473524962 / FREQUENCY_RATE), + (99.2969696969697 / FREQUENCY_RATE), + (99.4476479514416 / FREQUENCY_RATE), + (99.5987841945289 / FREQUENCY_RATE), + (99.7503805175038 / FREQUENCY_RATE), + (99.9024390243902 / FREQUENCY_RATE), + (100.054961832061 / FREQUENCY_RATE), + (100.207951070336 / FREQUENCY_RATE), + (100.361408882083 / FREQUENCY_RATE), + (100.515337423313 / FREQUENCY_RATE), + (100.669738863287 / FREQUENCY_RATE), + (100.824615384615 / FREQUENCY_RATE), + (100.979969183359 / FREQUENCY_RATE), + (101.135802469136 / FREQUENCY_RATE), + (101.292117465224 / FREQUENCY_RATE), + (101.448916408669 / FREQUENCY_RATE), + (101.606201550388 / FREQUENCY_RATE), + (101.76397515528 / FREQUENCY_RATE), + (101.922239502333 / FREQUENCY_RATE), + (102.080996884735 / FREQUENCY_RATE), + (102.240249609984 / FREQUENCY_RATE), + (102.4 / FREQUENCY_RATE), + (102.560250391236 / FREQUENCY_RATE), + (102.721003134796 / FREQUENCY_RATE), + (102.882260596546 / FREQUENCY_RATE), + (103.044025157233 / FREQUENCY_RATE), + (103.206299212598 / FREQUENCY_RATE), + (103.369085173502 / FREQUENCY_RATE), + (103.532385466035 / FREQUENCY_RATE), + (103.696202531646 / FREQUENCY_RATE), + (103.860538827258 / FREQUENCY_RATE), + (104.025396825397 / FREQUENCY_RATE), + (104.190779014308 / FREQUENCY_RATE), + (104.356687898089 / FREQUENCY_RATE), + (104.52312599681 / FREQUENCY_RATE), + (104.690095846645 / FREQUENCY_RATE), + (104.8576 / FREQUENCY_RATE), + (105.025641025641 / FREQUENCY_RATE), + (105.194221508828 / FREQUENCY_RATE), + (105.363344051447 / FREQUENCY_RATE), + (105.533011272142 / FREQUENCY_RATE), + (105.703225806452 / FREQUENCY_RATE), + (105.873990306947 / FREQUENCY_RATE), + (106.045307443366 / FREQUENCY_RATE), + (106.217179902755 / FREQUENCY_RATE), + (106.38961038961 / FREQUENCY_RATE), + (106.562601626016 / FREQUENCY_RATE), + (106.736156351792 / FREQUENCY_RATE), + (106.910277324633 / FREQUENCY_RATE), + (107.084967320261 / FREQUENCY_RATE), + (107.26022913257 / FREQUENCY_RATE), + (107.436065573771 / FREQUENCY_RATE), + (107.612479474548 / FREQUENCY_RATE), + (107.789473684211 / FREQUENCY_RATE), + (107.96705107084 / FREQUENCY_RATE), + (108.145214521452 / FREQUENCY_RATE), + (108.323966942149 / FREQUENCY_RATE), + (108.503311258278 / FREQUENCY_RATE), + (108.683250414594 / FREQUENCY_RATE), + (108.863787375415 / FREQUENCY_RATE), + (109.044925124792 / FREQUENCY_RATE), + (109.226666666667 / FREQUENCY_RATE), + (109.409015025042 / FREQUENCY_RATE), + (109.591973244147 / FREQUENCY_RATE), + (109.77554438861 / FREQUENCY_RATE), + (109.959731543624 / FREQUENCY_RATE), + (110.144537815126 / FREQUENCY_RATE), + (110.329966329966 / FREQUENCY_RATE), + (110.516020236088 / FREQUENCY_RATE), + (110.702702702703 / FREQUENCY_RATE), + (110.890016920474 / FREQUENCY_RATE), + (111.077966101695 / FREQUENCY_RATE), + (111.266553480475 / FREQUENCY_RATE), + (111.455782312925 / FREQUENCY_RATE), + (111.645655877342 / FREQUENCY_RATE), + (111.836177474403 / FREQUENCY_RATE), + (112.02735042735 / FREQUENCY_RATE), + (112.219178082192 / FREQUENCY_RATE), + (112.41166380789 / FREQUENCY_RATE), + (112.604810996564 / FREQUENCY_RATE), + (112.798623063683 / FREQUENCY_RATE), + (112.993103448276 / FREQUENCY_RATE), + (113.188255613126 / FREQUENCY_RATE), + (113.384083044983 / FREQUENCY_RATE), + (113.580589254766 / FREQUENCY_RATE), + (113.777777777778 / FREQUENCY_RATE), + (113.975652173913 / FREQUENCY_RATE), + (114.174216027875 / FREQUENCY_RATE), + (114.373472949389 / FREQUENCY_RATE), + (114.573426573427 / FREQUENCY_RATE), + (114.77408056042 / FREQUENCY_RATE), + (114.975438596491 / FREQUENCY_RATE), + (115.177504393673 / FREQUENCY_RATE), + (115.380281690141 / FREQUENCY_RATE), + (115.583774250441 / FREQUENCY_RATE), + (115.787985865724 / FREQUENCY_RATE), + (115.992920353982 / FREQUENCY_RATE), + (116.198581560284 / FREQUENCY_RATE), + (116.404973357016 / FREQUENCY_RATE), + (116.612099644128 / FREQUENCY_RATE), + (116.819964349376 / FREQUENCY_RATE), + (117.028571428571 / FREQUENCY_RATE), + (117.237924865832 / FREQUENCY_RATE), + (117.448028673835 / FREQUENCY_RATE), + (117.658886894075 / FREQUENCY_RATE), + (117.870503597122 / FREQUENCY_RATE), + (118.082882882883 / FREQUENCY_RATE), + (118.296028880866 / FREQUENCY_RATE), + (118.509945750452 / FREQUENCY_RATE), + (118.724637681159 / FREQUENCY_RATE), + (118.940108892922 / FREQUENCY_RATE), + (119.156363636364 / FREQUENCY_RATE), + (119.373406193078 / FREQUENCY_RATE), + (119.591240875912 / FREQUENCY_RATE), + (119.80987202925 / FREQUENCY_RATE), + (120.029304029304 / FREQUENCY_RATE), + (120.249541284404 / FREQUENCY_RATE), + (120.470588235294 / FREQUENCY_RATE), + (120.692449355433 / FREQUENCY_RATE), + (120.915129151292 / FREQUENCY_RATE), + (121.138632162662 / FREQUENCY_RATE), + (121.362962962963 / FREQUENCY_RATE), + (121.588126159555 / FREQUENCY_RATE), + (121.814126394052 / FREQUENCY_RATE), + (122.040968342644 / FREQUENCY_RATE), + (122.268656716418 / FREQUENCY_RATE), + (122.497196261682 / FREQUENCY_RATE), + (122.7265917603 / FREQUENCY_RATE), + (122.956848030019 / FREQUENCY_RATE), + (123.187969924812 / FREQUENCY_RATE), + (123.419962335217 / FREQUENCY_RATE), + (123.652830188679 / FREQUENCY_RATE), + (123.886578449906 / FREQUENCY_RATE), + (124.121212121212 / FREQUENCY_RATE), + (124.356736242884 / FREQUENCY_RATE), + (124.593155893536 / FREQUENCY_RATE), + (124.830476190476 / FREQUENCY_RATE), + (125.068702290076 / FREQUENCY_RATE), + (125.307839388145 / FREQUENCY_RATE), + (125.547892720307 / FREQUENCY_RATE), + (125.78886756238 / FREQUENCY_RATE), + (126.030769230769 / FREQUENCY_RATE), + (126.273603082852 / FREQUENCY_RATE), + (126.517374517375 / FREQUENCY_RATE), + (126.762088974855 / FREQUENCY_RATE), + (127.007751937985 / FREQUENCY_RATE), + (127.254368932039 / FREQUENCY_RATE), + (127.501945525292 / FREQUENCY_RATE), + (127.750487329435 / FREQUENCY_RATE), + (128 / FREQUENCY_RATE), + (128.250489236791 / FREQUENCY_RATE), + (128.501960784314 / FREQUENCY_RATE), + (128.75442043222 / FREQUENCY_RATE), + (129.007874015748 / FREQUENCY_RATE), + (129.262327416174 / FREQUENCY_RATE), + (129.517786561265 / FREQUENCY_RATE), + (129.774257425743 / FREQUENCY_RATE), + (130.031746031746 / FREQUENCY_RATE), + (130.290258449304 / FREQUENCY_RATE), + (130.549800796813 / FREQUENCY_RATE), + (130.810379241517 / FREQUENCY_RATE), + (131.072 / FREQUENCY_RATE), + (131.334669338677 / FREQUENCY_RATE), + (131.598393574297 / FREQUENCY_RATE), + (131.863179074447 / FREQUENCY_RATE), + (132.129032258065 / FREQUENCY_RATE), + (132.39595959596 / FREQUENCY_RATE), + (132.663967611336 / FREQUENCY_RATE), + (132.933062880325 / FREQUENCY_RATE), + (133.20325203252 / FREQUENCY_RATE), + (133.474541751527 / FREQUENCY_RATE), + (133.74693877551 / FREQUENCY_RATE), + (134.020449897751 / FREQUENCY_RATE), + (134.295081967213 / FREQUENCY_RATE), + (134.570841889117 / FREQUENCY_RATE), + (134.847736625514 / FREQUENCY_RATE), + (135.125773195876 / FREQUENCY_RATE), + (135.404958677686 / FREQUENCY_RATE), + (135.685300207039 / FREQUENCY_RATE), + (135.966804979253 / FREQUENCY_RATE), + (136.24948024948 / FREQUENCY_RATE), + (136.533333333333 / FREQUENCY_RATE), + (136.818371607516 / FREQUENCY_RATE), + (137.10460251046 / FREQUENCY_RATE), + (137.392033542977 / FREQUENCY_RATE), + (137.680672268908 / FREQUENCY_RATE), + (137.970526315789 / FREQUENCY_RATE), + (138.261603375527 / FREQUENCY_RATE), + (138.553911205074 / FREQUENCY_RATE), + (138.847457627119 / FREQUENCY_RATE), + (139.142250530786 / FREQUENCY_RATE), + (139.43829787234 / FREQUENCY_RATE), + (139.735607675906 / FREQUENCY_RATE), + (140.034188034188 / FREQUENCY_RATE), + (140.334047109208 / FREQUENCY_RATE), + (140.635193133047 / FREQUENCY_RATE), + (140.937634408602 / FREQUENCY_RATE), + (141.241379310345 / FREQUENCY_RATE), + (141.546436285097 / FREQUENCY_RATE), + (141.852813852814 / FREQUENCY_RATE), + (142.160520607375 / FREQUENCY_RATE), + (142.469565217391 / FREQUENCY_RATE), + (142.779956427015 / FREQUENCY_RATE), + (143.091703056769 / FREQUENCY_RATE), + (143.404814004376 / FREQUENCY_RATE), + (143.719298245614 / FREQUENCY_RATE), + (144.035164835165 / FREQUENCY_RATE), + (144.352422907489 / FREQUENCY_RATE), + (144.671081677704 / FREQUENCY_RATE), + (144.991150442478 / FREQUENCY_RATE), + (145.312638580931 / FREQUENCY_RATE), + (145.635555555556 / FREQUENCY_RATE), + (145.95991091314 / FREQUENCY_RATE), + (146.285714285714 / FREQUENCY_RATE), + (146.612975391499 / FREQUENCY_RATE), + (146.941704035874 / FREQUENCY_RATE), + (147.27191011236 / FREQUENCY_RATE), + (147.603603603604 / FREQUENCY_RATE), + (147.936794582393 / FREQUENCY_RATE), + (148.27149321267 / FREQUENCY_RATE), + (148.607709750567 / FREQUENCY_RATE), + (148.945454545455 / FREQUENCY_RATE), + (149.284738041002 / FREQUENCY_RATE), + (149.625570776256 / FREQUENCY_RATE), + (149.967963386728 / FREQUENCY_RATE), + (150.311926605505 / FREQUENCY_RATE), + (150.657471264368 / FREQUENCY_RATE), + (151.004608294931 / FREQUENCY_RATE), + (151.353348729792 / FREQUENCY_RATE), + (151.703703703704 / FREQUENCY_RATE), + (152.055684454756 / FREQUENCY_RATE), + (152.409302325581 / FREQUENCY_RATE), + (152.764568764569 / FREQUENCY_RATE), + (153.121495327103 / FREQUENCY_RATE), + (153.480093676815 / FREQUENCY_RATE), + (153.840375586854 / FREQUENCY_RATE), + (154.202352941176 / FREQUENCY_RATE), + (154.566037735849 / FREQUENCY_RATE), + (154.931442080378 / FREQUENCY_RATE), + (155.298578199052 / FREQUENCY_RATE), + (155.667458432304 / FREQUENCY_RATE), + (156.038095238095 / FREQUENCY_RATE), + (156.410501193317 / FREQUENCY_RATE), + (156.784688995215 / FREQUENCY_RATE), + (157.16067146283 / FREQUENCY_RATE), + (157.538461538462 / FREQUENCY_RATE), + (157.918072289157 / FREQUENCY_RATE), + (158.299516908213 / FREQUENCY_RATE), + (158.682808716707 / FREQUENCY_RATE), + (159.067961165049 / FREQUENCY_RATE), + (159.45498783455 / FREQUENCY_RATE), + (159.843902439024 / FREQUENCY_RATE), + (160.234718826406 / FREQUENCY_RATE), + (160.627450980392 / FREQUENCY_RATE), + (161.022113022113 / FREQUENCY_RATE), + (161.418719211823 / FREQUENCY_RATE), + (161.817283950617 / FREQUENCY_RATE), + (162.217821782178 / FREQUENCY_RATE), + (162.620347394541 / FREQUENCY_RATE), + (163.024875621891 / FREQUENCY_RATE), + (163.431421446384 / FREQUENCY_RATE), + (163.84 / FREQUENCY_RATE), + (164.250626566416 / FREQUENCY_RATE), + (164.663316582915 / FREQUENCY_RATE), + (165.078085642317 / FREQUENCY_RATE), + (165.49494949495 / FREQUENCY_RATE), + (165.913924050633 / FREQUENCY_RATE), + (166.335025380711 / FREQUENCY_RATE), + (166.758269720102 / FREQUENCY_RATE), + (167.183673469388 / FREQUENCY_RATE), + (167.611253196931 / FREQUENCY_RATE), + (168.041025641026 / FREQUENCY_RATE), + (168.473007712082 / FREQUENCY_RATE), + (168.907216494845 / FREQUENCY_RATE), + (169.343669250646 / FREQUENCY_RATE), + (169.782383419689 / FREQUENCY_RATE), + (170.223376623377 / FREQUENCY_RATE), + (170.666666666667 / FREQUENCY_RATE), + (171.11227154047 / FREQUENCY_RATE), + (171.560209424084 / FREQUENCY_RATE), + (172.010498687664 / FREQUENCY_RATE), + (172.463157894737 / FREQUENCY_RATE), + (172.918205804749 / FREQUENCY_RATE), + (173.375661375661 / FREQUENCY_RATE), + (173.835543766578 / FREQUENCY_RATE), + (174.297872340426 / FREQUENCY_RATE), + (174.762666666667 / FREQUENCY_RATE), + (175.229946524064 / FREQUENCY_RATE), + (175.699731903485 / FREQUENCY_RATE), + (176.172043010753 / FREQUENCY_RATE), + (176.646900269542 / FREQUENCY_RATE), + (177.124324324324 / FREQUENCY_RATE), + (177.60433604336 / FREQUENCY_RATE), + (178.086956521739 / FREQUENCY_RATE), + (178.572207084469 / FREQUENCY_RATE), + (179.060109289618 / FREQUENCY_RATE), + (179.550684931507 / FREQUENCY_RATE), + (180.043956043956 / FREQUENCY_RATE), + (180.539944903581 / FREQUENCY_RATE), + (181.038674033149 / FREQUENCY_RATE), + (181.540166204986 / FREQUENCY_RATE), + (182.044444444444 / FREQUENCY_RATE), + (182.551532033426 / FREQUENCY_RATE), + (183.061452513966 / FREQUENCY_RATE), + (183.574229691877 / FREQUENCY_RATE), + (184.089887640449 / FREQUENCY_RATE), + (184.608450704225 / FREQUENCY_RATE), + (185.129943502825 / FREQUENCY_RATE), + (185.654390934844 / FREQUENCY_RATE), + (186.181818181818 / FREQUENCY_RATE), + (186.712250712251 / FREQUENCY_RATE), + (187.245714285714 / FREQUENCY_RATE), + (187.78223495702 / FREQUENCY_RATE), + (188.32183908046 / FREQUENCY_RATE), + (188.864553314121 / FREQUENCY_RATE), + (189.410404624277 / FREQUENCY_RATE), + (189.959420289855 / FREQUENCY_RATE), + (190.511627906977 / FREQUENCY_RATE), + (191.067055393586 / FREQUENCY_RATE), + (191.625730994152 / FREQUENCY_RATE), + (192.187683284457 / FREQUENCY_RATE), + (192.752941176471 / FREQUENCY_RATE), + (193.321533923304 / FREQUENCY_RATE), + (193.89349112426 / FREQUENCY_RATE), + (194.46884272997 / FREQUENCY_RATE), + (195.047619047619 / FREQUENCY_RATE), + (195.629850746269 / FREQUENCY_RATE), + (196.215568862275 / FREQUENCY_RATE), + (196.804804804805 / FREQUENCY_RATE), + (197.397590361446 / FREQUENCY_RATE), + (197.993957703928 / FREQUENCY_RATE), + (198.593939393939 / FREQUENCY_RATE), + (199.197568389058 / FREQUENCY_RATE), + (199.804878048781 / FREQUENCY_RATE), + (200.415902140673 / FREQUENCY_RATE), + (201.030674846626 / FREQUENCY_RATE), + (201.649230769231 / FREQUENCY_RATE), + (202.271604938272 / FREQUENCY_RATE), + (202.897832817337 / FREQUENCY_RATE), + (203.527950310559 / FREQUENCY_RATE), + (204.16199376947 / FREQUENCY_RATE), + (204.8 / FREQUENCY_RATE), + (205.442006269592 / FREQUENCY_RATE), + (206.088050314465 / FREQUENCY_RATE), + (206.738170347003 / FREQUENCY_RATE), + (207.392405063291 / FREQUENCY_RATE), + (208.050793650794 / FREQUENCY_RATE), + (208.713375796178 / FREQUENCY_RATE), + (209.380191693291 / FREQUENCY_RATE), + (210.051282051282 / FREQUENCY_RATE), + (210.726688102894 / FREQUENCY_RATE), + (211.406451612903 / FREQUENCY_RATE), + (212.090614886731 / FREQUENCY_RATE), + (212.779220779221 / FREQUENCY_RATE), + (213.472312703583 / FREQUENCY_RATE), + (214.169934640523 / FREQUENCY_RATE), + (214.872131147541 / FREQUENCY_RATE), + (215.578947368421 / FREQUENCY_RATE), + (216.290429042904 / FREQUENCY_RATE), + (217.006622516556 / FREQUENCY_RATE), + (217.727574750831 / FREQUENCY_RATE), + (218.453333333333 / FREQUENCY_RATE), + (219.183946488294 / FREQUENCY_RATE), + (219.919463087248 / FREQUENCY_RATE), + (220.659932659933 / FREQUENCY_RATE), + (221.405405405405 / FREQUENCY_RATE), + (222.15593220339 / FREQUENCY_RATE), + (222.91156462585 / FREQUENCY_RATE), + (223.672354948805 / FREQUENCY_RATE), + (224.438356164384 / FREQUENCY_RATE), + (225.209621993127 / FREQUENCY_RATE), + (225.986206896552 / FREQUENCY_RATE), + (226.768166089965 / FREQUENCY_RATE), + (227.555555555556 / FREQUENCY_RATE), + (228.348432055749 / FREQUENCY_RATE), + (229.146853146853 / FREQUENCY_RATE), + (229.950877192982 / FREQUENCY_RATE), + (230.760563380282 / FREQUENCY_RATE), + (231.575971731449 / FREQUENCY_RATE), + (232.397163120567 / FREQUENCY_RATE), + (233.224199288256 / FREQUENCY_RATE), + (234.057142857143 / FREQUENCY_RATE), + (234.89605734767 / FREQUENCY_RATE), + (235.741007194245 / FREQUENCY_RATE), + (236.592057761733 / FREQUENCY_RATE), + (237.449275362319 / FREQUENCY_RATE), + (238.312727272727 / FREQUENCY_RATE), + (239.182481751825 / FREQUENCY_RATE), + (240.058608058608 / FREQUENCY_RATE), + (240.941176470588 / FREQUENCY_RATE), + (241.830258302583 / FREQUENCY_RATE), + (242.725925925926 / FREQUENCY_RATE), + (243.628252788104 / FREQUENCY_RATE), + (244.537313432836 / FREQUENCY_RATE), + (245.453183520599 / FREQUENCY_RATE), + (246.375939849624 / FREQUENCY_RATE), + (247.305660377358 / FREQUENCY_RATE), + (248.242424242424 / FREQUENCY_RATE), + (249.186311787072 / FREQUENCY_RATE), + (250.137404580153 / FREQUENCY_RATE), + (251.095785440613 / FREQUENCY_RATE), + (252.061538461538 / FREQUENCY_RATE), + (253.034749034749 / FREQUENCY_RATE), + (254.015503875969 / FREQUENCY_RATE), + (255.003891050584 / FREQUENCY_RATE), + (256 / FREQUENCY_RATE), + (257.003921568627 / FREQUENCY_RATE), + (258.015748031496 / FREQUENCY_RATE), + (259.03557312253 / FREQUENCY_RATE), + (260.063492063492 / FREQUENCY_RATE), + (261.099601593625 / FREQUENCY_RATE), + (262.144 / FREQUENCY_RATE), + (263.196787148594 / FREQUENCY_RATE), + (264.258064516129 / FREQUENCY_RATE), + (265.327935222672 / FREQUENCY_RATE), + (266.406504065041 / FREQUENCY_RATE), + (267.49387755102 / FREQUENCY_RATE), + (268.590163934426 / FREQUENCY_RATE), + (269.695473251029 / FREQUENCY_RATE), + (270.809917355372 / FREQUENCY_RATE), + (271.933609958506 / FREQUENCY_RATE), + (273.066666666667 / FREQUENCY_RATE), + (274.20920502092 / FREQUENCY_RATE), + (275.361344537815 / FREQUENCY_RATE), + (276.523206751055 / FREQUENCY_RATE), + (277.694915254237 / FREQUENCY_RATE), + (278.876595744681 / FREQUENCY_RATE), + (280.068376068376 / FREQUENCY_RATE), + (281.270386266094 / FREQUENCY_RATE), + (282.48275862069 / FREQUENCY_RATE), + (283.705627705628 / FREQUENCY_RATE), + (284.939130434783 / FREQUENCY_RATE), + (286.183406113537 / FREQUENCY_RATE), + (287.438596491228 / FREQUENCY_RATE), + (288.704845814978 / FREQUENCY_RATE), + (289.982300884956 / FREQUENCY_RATE), + (291.271111111111 / FREQUENCY_RATE), + (292.571428571429 / FREQUENCY_RATE), + (293.883408071749 / FREQUENCY_RATE), + (295.207207207207 / FREQUENCY_RATE), + (296.542986425339 / FREQUENCY_RATE), + (297.890909090909 / FREQUENCY_RATE), + (299.251141552511 / FREQUENCY_RATE), + (300.623853211009 / FREQUENCY_RATE), + (302.009216589862 / FREQUENCY_RATE), + (303.407407407407 / FREQUENCY_RATE), + (304.818604651163 / FREQUENCY_RATE), + (306.242990654206 / FREQUENCY_RATE), + (307.680751173709 / FREQUENCY_RATE), + (309.132075471698 / FREQUENCY_RATE), + (310.597156398104 / FREQUENCY_RATE), + (312.07619047619 / FREQUENCY_RATE), + (313.569377990431 / FREQUENCY_RATE), + (315.076923076923 / FREQUENCY_RATE), + (316.599033816425 / FREQUENCY_RATE), + (318.135922330097 / FREQUENCY_RATE), + (319.687804878049 / FREQUENCY_RATE), + (321.254901960784 / FREQUENCY_RATE), + (322.837438423645 / FREQUENCY_RATE), + (324.435643564356 / FREQUENCY_RATE), + (326.049751243781 / FREQUENCY_RATE), + (327.68 / FREQUENCY_RATE), + (329.326633165829 / FREQUENCY_RATE), + (330.989898989899 / FREQUENCY_RATE), + (332.670050761421 / FREQUENCY_RATE), + (334.367346938775 / FREQUENCY_RATE), + (336.082051282051 / FREQUENCY_RATE), + (337.814432989691 / FREQUENCY_RATE), + (339.564766839378 / FREQUENCY_RATE), + (341.333333333333 / FREQUENCY_RATE), + (343.120418848168 / FREQUENCY_RATE), + (344.926315789474 / FREQUENCY_RATE), + (346.751322751323 / FREQUENCY_RATE), + (348.595744680851 / FREQUENCY_RATE), + (350.459893048128 / FREQUENCY_RATE), + (352.344086021505 / FREQUENCY_RATE), + (354.248648648649 / FREQUENCY_RATE), + (356.173913043478 / FREQUENCY_RATE), + (358.120218579235 / FREQUENCY_RATE), + (360.087912087912 / FREQUENCY_RATE), + (362.077348066298 / FREQUENCY_RATE), + (364.088888888889 / FREQUENCY_RATE), + (366.122905027933 / FREQUENCY_RATE), + (368.179775280899 / FREQUENCY_RATE), + (370.25988700565 / FREQUENCY_RATE), + (372.363636363636 / FREQUENCY_RATE), + (374.491428571429 / FREQUENCY_RATE), + (376.64367816092 / FREQUENCY_RATE), + (378.820809248555 / FREQUENCY_RATE), + (381.023255813953 / FREQUENCY_RATE), + (383.251461988304 / FREQUENCY_RATE), + (385.505882352941 / FREQUENCY_RATE), + (387.786982248521 / FREQUENCY_RATE), + (390.095238095238 / FREQUENCY_RATE), + (392.431137724551 / FREQUENCY_RATE), + (394.795180722892 / FREQUENCY_RATE), + (397.187878787879 / FREQUENCY_RATE), + (399.609756097561 / FREQUENCY_RATE), + (402.061349693252 / FREQUENCY_RATE), + (404.543209876543 / FREQUENCY_RATE), + (407.055900621118 / FREQUENCY_RATE), + (409.6 / FREQUENCY_RATE), + (412.176100628931 / FREQUENCY_RATE), + (414.784810126582 / FREQUENCY_RATE), + (417.426751592357 / FREQUENCY_RATE), + (420.102564102564 / FREQUENCY_RATE), + (422.812903225807 / FREQUENCY_RATE), + (425.558441558442 / FREQUENCY_RATE), + (428.339869281046 / FREQUENCY_RATE), + (431.157894736842 / FREQUENCY_RATE), + (434.013245033113 / FREQUENCY_RATE), + (436.906666666667 / FREQUENCY_RATE), + (439.838926174497 / FREQUENCY_RATE), + (442.810810810811 / FREQUENCY_RATE), + (445.823129251701 / FREQUENCY_RATE), + (448.876712328767 / FREQUENCY_RATE), + (451.972413793103 / FREQUENCY_RATE), + (455.111111111111 / FREQUENCY_RATE), + (458.293706293706 / FREQUENCY_RATE), + (461.521126760563 / FREQUENCY_RATE), + (464.794326241135 / FREQUENCY_RATE), + (468.114285714286 / FREQUENCY_RATE), + (471.482014388489 / FREQUENCY_RATE), + (474.898550724638 / FREQUENCY_RATE), + (478.36496350365 / FREQUENCY_RATE), + (481.882352941176 / FREQUENCY_RATE), + (485.451851851852 / FREQUENCY_RATE), + (489.074626865672 / FREQUENCY_RATE), + (492.751879699248 / FREQUENCY_RATE), + (496.484848484849 / FREQUENCY_RATE), + (500.274809160305 / FREQUENCY_RATE), + (504.123076923077 / FREQUENCY_RATE), + (508.031007751938 / FREQUENCY_RATE), + (512 / FREQUENCY_RATE), + (516.031496062992 / FREQUENCY_RATE), + (520.126984126984 / FREQUENCY_RATE), + (524.288 / FREQUENCY_RATE), + (528.516129032258 / FREQUENCY_RATE), + (532.813008130081 / FREQUENCY_RATE), + (537.180327868852 / FREQUENCY_RATE), + (541.619834710744 / FREQUENCY_RATE), + (546.133333333333 / FREQUENCY_RATE), + (550.72268907563 / FREQUENCY_RATE), + (555.389830508475 / FREQUENCY_RATE), + (560.136752136752 / FREQUENCY_RATE), + (564.965517241379 / FREQUENCY_RATE), + (569.878260869565 / FREQUENCY_RATE), + (574.877192982456 / FREQUENCY_RATE), + (579.964601769912 / FREQUENCY_RATE), + (585.142857142857 / FREQUENCY_RATE), + (590.414414414414 / FREQUENCY_RATE), + (595.781818181818 / FREQUENCY_RATE), + (601.247706422018 / FREQUENCY_RATE), + (606.814814814815 / FREQUENCY_RATE), + (612.485981308411 / FREQUENCY_RATE), + (618.264150943396 / FREQUENCY_RATE), + (624.152380952381 / FREQUENCY_RATE), + (630.153846153846 / FREQUENCY_RATE), + (636.271844660194 / FREQUENCY_RATE), + (642.509803921569 / FREQUENCY_RATE), + (648.871287128713 / FREQUENCY_RATE), + (655.36 / FREQUENCY_RATE), + (661.979797979798 / FREQUENCY_RATE), + (668.734693877551 / FREQUENCY_RATE), + (675.628865979381 / FREQUENCY_RATE), + (682.666666666667 / FREQUENCY_RATE), + (689.852631578947 / FREQUENCY_RATE), + (697.191489361702 / FREQUENCY_RATE), + (704.688172043011 / FREQUENCY_RATE), + (712.347826086956 / FREQUENCY_RATE), + (720.175824175824 / FREQUENCY_RATE), + (728.177777777778 / FREQUENCY_RATE), + (736.359550561798 / FREQUENCY_RATE), + (744.727272727273 / FREQUENCY_RATE), + (753.287356321839 / FREQUENCY_RATE), + (762.046511627907 / FREQUENCY_RATE), + (771.011764705882 / FREQUENCY_RATE), + (780.190476190476 / FREQUENCY_RATE), + (789.590361445783 / FREQUENCY_RATE), + (799.219512195122 / FREQUENCY_RATE), + (809.086419753086 / FREQUENCY_RATE), + (819.2 / FREQUENCY_RATE), + (829.569620253165 / FREQUENCY_RATE), + (840.205128205128 / FREQUENCY_RATE), + (851.116883116883 / FREQUENCY_RATE), + (862.315789473684 / FREQUENCY_RATE), + (873.813333333333 / FREQUENCY_RATE), + (885.621621621622 / FREQUENCY_RATE), + (897.753424657534 / FREQUENCY_RATE), + (910.222222222222 / FREQUENCY_RATE), + (923.042253521127 / FREQUENCY_RATE), + (936.228571428571 / FREQUENCY_RATE), + (949.797101449275 / FREQUENCY_RATE), + (963.764705882353 / FREQUENCY_RATE), + (978.149253731343 / FREQUENCY_RATE), + (992.969696969697 / FREQUENCY_RATE), + (1008.24615384615 / FREQUENCY_RATE), + (1024 / FREQUENCY_RATE), + (1040.25396825397 / FREQUENCY_RATE), + (1057.03225806452 / FREQUENCY_RATE), + (1074.36065573771 / FREQUENCY_RATE), + (1092.26666666667 / FREQUENCY_RATE), + (1110.77966101695 / FREQUENCY_RATE), + (1129.93103448276 / FREQUENCY_RATE), + (1149.75438596491 / FREQUENCY_RATE), + (1170.28571428571 / FREQUENCY_RATE), + (1191.56363636364 / FREQUENCY_RATE), + (1213.62962962963 / FREQUENCY_RATE), + (1236.52830188679 / FREQUENCY_RATE), + (1260.30769230769 / FREQUENCY_RATE), + (1285.01960784314 / FREQUENCY_RATE), + (1310.72 / FREQUENCY_RATE), + (1337.4693877551 / FREQUENCY_RATE), + (1365.33333333333 / FREQUENCY_RATE), + (1394.3829787234 / FREQUENCY_RATE), + (1424.69565217391 / FREQUENCY_RATE), + (1456.35555555556 / FREQUENCY_RATE), + (1489.45454545455 / FREQUENCY_RATE), + (1524.09302325581 / FREQUENCY_RATE), + (1560.38095238095 / FREQUENCY_RATE), + (1598.43902439024 / FREQUENCY_RATE), + (1638.4 / FREQUENCY_RATE), + (1680.41025641026 / FREQUENCY_RATE), + (1724.63157894737 / FREQUENCY_RATE), + (1771.24324324324 / FREQUENCY_RATE), + (1820.44444444444 / FREQUENCY_RATE), + (1872.45714285714 / FREQUENCY_RATE), + (1927.52941176471 / FREQUENCY_RATE), + (1985.93939393939 / FREQUENCY_RATE), + (2048 / FREQUENCY_RATE), + (2114.06451612903 / FREQUENCY_RATE), + (2184.53333333333 / FREQUENCY_RATE), + (2259.86206896552 / FREQUENCY_RATE), + (2340.57142857143 / FREQUENCY_RATE), + (2427.25925925926 / FREQUENCY_RATE), + (2520.61538461538 / FREQUENCY_RATE), + (2621.44 / FREQUENCY_RATE), + (2730.66666666667 / FREQUENCY_RATE), + (2849.39130434783 / FREQUENCY_RATE), + (2978.90909090909 / FREQUENCY_RATE), + (3120.7619047619 / FREQUENCY_RATE), + (3276.8 / FREQUENCY_RATE), + (3449.26315789474 / FREQUENCY_RATE), + (3640.88888888889 / FREQUENCY_RATE), + (3855.05882352941 / FREQUENCY_RATE), + (4096 / FREQUENCY_RATE), + (4369.06666666667 / FREQUENCY_RATE), + (4681.14285714286 / FREQUENCY_RATE), + (5041.23076923077 / FREQUENCY_RATE), + (5461.33333333333 / FREQUENCY_RATE), + (5957.81818181818 / FREQUENCY_RATE), + (6553.6 / FREQUENCY_RATE), + (7281.77777777778 / FREQUENCY_RATE), + (8192 / FREQUENCY_RATE), + (9362.28571428571 / FREQUENCY_RATE), + (10922.6666666667 / FREQUENCY_RATE), + (13107.2 / FREQUENCY_RATE), + (16384 / FREQUENCY_RATE), + (21845.3333333333 / FREQUENCY_RATE), + (32768 / FREQUENCY_RATE), + (65536 / FREQUENCY_RATE), }; -const fixed16_16 freqTableNSE[256] = { - float_to_fp16_16(524288 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(52428.8 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), - float_to_fp16_16(524288 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(52428.8 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(26214.4 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(26214.4 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(13107.2 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(13107.2 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(6553.6 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(6553.6 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(3276.8 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(3276.8 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1638.4 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1638.4 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(819.2 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(585.142857142857 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(819.2 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(585.142857142857 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(409.6 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(292.571428571429 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(409.6 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(292.571428571429 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(204.8 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(146.285714285714 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(204.8 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(146.285714285714 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(102.4 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(102.4 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(51.2 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(51.2 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(25.6 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(25.6 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(12.8 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(12.8 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(6.4 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(6.4 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(3.2 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(3.2 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2 / SAMPLE_RATE), - float_to_fp16_16(1.6 / SAMPLE_RATE), - float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2 / SAMPLE_RATE), - float_to_fp16_16(1.6 / SAMPLE_RATE), - float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), +const float freqTableNSE[256] = { + (524288 / SAMPLE_RATE), + (262144 / SAMPLE_RATE), + (131072 / SAMPLE_RATE), + (87381.3333333333 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (52428.8 / SAMPLE_RATE), + (43690.6666666667 / SAMPLE_RATE), + (37449.1428571429 / SAMPLE_RATE), + (524288 / SAMPLE_RATE), + (262144 / SAMPLE_RATE), + (131072 / SAMPLE_RATE), + (87381.3333333333 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (52428.8 / SAMPLE_RATE), + (43690.6666666667 / SAMPLE_RATE), + (37449.1428571429 / SAMPLE_RATE), + (262144 / SAMPLE_RATE), + (131072 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (43690.6666666667 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (26214.4 / SAMPLE_RATE), + (21845.3333333333 / SAMPLE_RATE), + (18724.5714285714 / SAMPLE_RATE), + (262144 / SAMPLE_RATE), + (131072 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (43690.6666666667 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (26214.4 / SAMPLE_RATE), + (21845.3333333333 / SAMPLE_RATE), + (18724.5714285714 / SAMPLE_RATE), + (131072 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (21845.3333333333 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (13107.2 / SAMPLE_RATE), + (10922.6666666667 / SAMPLE_RATE), + (9362.28571428571 / SAMPLE_RATE), + (131072 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (21845.3333333333 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (13107.2 / SAMPLE_RATE), + (10922.6666666667 / SAMPLE_RATE), + (9362.28571428571 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (10922.6666666667 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (6553.6 / SAMPLE_RATE), + (5461.33333333333 / SAMPLE_RATE), + (4681.14285714286 / SAMPLE_RATE), + (65536 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (10922.6666666667 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (6553.6 / SAMPLE_RATE), + (5461.33333333333 / SAMPLE_RATE), + (4681.14285714286 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (5461.33333333333 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (3276.8 / SAMPLE_RATE), + (2730.66666666667 / SAMPLE_RATE), + (2340.57142857143 / SAMPLE_RATE), + (32768 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (5461.33333333333 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (3276.8 / SAMPLE_RATE), + (2730.66666666667 / SAMPLE_RATE), + (2340.57142857143 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (2730.66666666667 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1638.4 / SAMPLE_RATE), + (1365.33333333333 / SAMPLE_RATE), + (1170.28571428571 / SAMPLE_RATE), + (16384 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (2730.66666666667 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1638.4 / SAMPLE_RATE), + (1365.33333333333 / SAMPLE_RATE), + (1170.28571428571 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1365.33333333333 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (819.2 / SAMPLE_RATE), + (682.666666666667 / SAMPLE_RATE), + (585.142857142857 / SAMPLE_RATE), + (8192 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1365.33333333333 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (819.2 / SAMPLE_RATE), + (682.666666666667 / SAMPLE_RATE), + (585.142857142857 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (682.666666666667 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (409.6 / SAMPLE_RATE), + (341.333333333333 / SAMPLE_RATE), + (292.571428571429 / SAMPLE_RATE), + (4096 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (682.666666666667 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (409.6 / SAMPLE_RATE), + (341.333333333333 / SAMPLE_RATE), + (292.571428571429 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (341.333333333333 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (204.8 / SAMPLE_RATE), + (170.666666666667 / SAMPLE_RATE), + (146.285714285714 / SAMPLE_RATE), + (2048 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (341.333333333333 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (204.8 / SAMPLE_RATE), + (170.666666666667 / SAMPLE_RATE), + (146.285714285714 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (170.666666666667 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (102.4 / SAMPLE_RATE), + (85.3333333333333 / SAMPLE_RATE), + (73.1428571428571 / SAMPLE_RATE), + (1024 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (170.666666666667 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (102.4 / SAMPLE_RATE), + (85.3333333333333 / SAMPLE_RATE), + (73.1428571428571 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (85.3333333333333 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (51.2 / SAMPLE_RATE), + (42.6666666666667 / SAMPLE_RATE), + (36.5714285714286 / SAMPLE_RATE), + (512 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (85.3333333333333 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (51.2 / SAMPLE_RATE), + (42.6666666666667 / SAMPLE_RATE), + (36.5714285714286 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (42.6666666666667 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (25.6 / SAMPLE_RATE), + (21.3333333333333 / SAMPLE_RATE), + (18.2857142857143 / SAMPLE_RATE), + (256 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (42.6666666666667 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (25.6 / SAMPLE_RATE), + (21.3333333333333 / SAMPLE_RATE), + (18.2857142857143 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (21.3333333333333 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (12.8 / SAMPLE_RATE), + (10.6666666666667 / SAMPLE_RATE), + (9.14285714285714 / SAMPLE_RATE), + (128 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (21.3333333333333 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (12.8 / SAMPLE_RATE), + (10.6666666666667 / SAMPLE_RATE), + (9.14285714285714 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (10.6666666666667 / SAMPLE_RATE), + (8 / SAMPLE_RATE), + (6.4 / SAMPLE_RATE), + (5.33333333333333 / SAMPLE_RATE), + (4.57142857142857 / SAMPLE_RATE), + (64 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (10.6666666666667 / SAMPLE_RATE), + (8 / SAMPLE_RATE), + (6.4 / SAMPLE_RATE), + (5.33333333333333 / SAMPLE_RATE), + (4.57142857142857 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (8 / SAMPLE_RATE), + (5.33333333333333 / SAMPLE_RATE), + (4 / SAMPLE_RATE), + (3.2 / SAMPLE_RATE), + (2.66666666666667 / SAMPLE_RATE), + (2.28571428571429 / SAMPLE_RATE), + (32 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (8 / SAMPLE_RATE), + (5.33333333333333 / SAMPLE_RATE), + (4 / SAMPLE_RATE), + (3.2 / SAMPLE_RATE), + (2.66666666666667 / SAMPLE_RATE), + (2.28571428571429 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (8 / SAMPLE_RATE), + (4 / SAMPLE_RATE), + (2.66666666666667 / SAMPLE_RATE), + (2 / SAMPLE_RATE), + (1.6 / SAMPLE_RATE), + (1.33333333333333 / SAMPLE_RATE), + (1.14285714285714 / SAMPLE_RATE), + (16 / SAMPLE_RATE), + (8 / SAMPLE_RATE), + (4 / SAMPLE_RATE), + (2.66666666666667 / SAMPLE_RATE), + (2 / SAMPLE_RATE), + (1.6 / SAMPLE_RATE), + (1.33333333333333 / SAMPLE_RATE), + (1.14285714285714 / SAMPLE_RATE), }; #endif diff --git a/src/game/stage/camera.c b/src/game/stage/camera.c index 541eee949c..47d2657292 100644 --- a/src/game/stage/camera.c +++ b/src/game/stage/camera.c @@ -1206,9 +1206,13 @@ void CreateStageBg_Zone4(void) gBgScrollRegs[3][0] = 0; gBgScrollRegs[3][1] = 0; +// Software renderer for these devices are too slow +// to handle these spotlights +#if !defined(__PS2__) && !defined(__PSP__) if (IS_SINGLE_PLAYER) { CreateSpotLightBeams(); } +#endif } void StageBgUpdate_Zone4Acts12(s32 cameraX, s32 cameraY) diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 55b361c69c..6cc12e1fd1 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -38,7 +38,7 @@ static GSTEXTURE screen; extern IntrFunc gIntrTable[16]; -ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * DISPLAY_HEIGHT]; +ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * (DISPLAY_HEIGHT + 1)]; struct VidMode { const char *name; diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 20599b2eb4..3823bcf830 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -3,14 +3,14 @@ #include "platform/shared/audio/cgb_tables.h" static struct AudioCGB gb; -static fixed16_16 soundChannelPos[4]; -static const fixed16_16 *PU1Table; -static const fixed16_16 *PU2Table; +static float soundChannelPos[4]; +static const float *PU1Table; +static const float *PU2Table; static u32 apuFrame; static u8 apuCycle; static u32 sampleRate; static u16 lfsrMax[2]; -fixed16_16 ch4Samples; +float ch4Samples; void cgb_audio_init(u32 rate) { @@ -198,32 +198,32 @@ void cgb_audio_generate(u16 samplesPerFrame) soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF]; soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF]; soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF]; - while (soundChannelPos[0] >= u32_to_fp16_16(32)) - soundChannelPos[0] -= u32_to_fp16_16(32); - while (soundChannelPos[1] >= u32_to_fp16_16(32)) - soundChannelPos[1] -= u32_to_fp16_16(32); - while (soundChannelPos[2] >= u32_to_fp16_16(32)) - soundChannelPos[2] -= u32_to_fp16_16(32); + while (soundChannelPos[0] >= (32)) + soundChannelPos[0] -= (32); + while (soundChannelPos[1] >= (32)) + soundChannelPos[1] -= (32); + while (soundChannelPos[2] >= (32)) + soundChannelPos[2] -= (32); float outputL = 0; float outputR = 0; if (REG_NR52 & 0x80) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if (REG_NR51 & 0x10) - outputL += fp16_16_to_float(gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); + outputL += (gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])]); if (REG_NR51 & 0x01) - outputR += fp16_16_to_float(gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); + outputR += (gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])]); } if ((gb.DAC[1]) && (REG_NR52 & 0x02)) { if (REG_NR51 & 0x20) - outputL += fp16_16_to_float(gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); + outputL += (gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])]); if (REG_NR51 & 0x02) - outputR += fp16_16_to_float(gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); + outputR += (gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])]); } if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) { if (REG_NR51 & 0x40) - outputL += gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] / 4.0f; + outputL += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f; if (REG_NR51 & 0x04) - outputR += gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] / 4.0f; + outputR += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f; } if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); @@ -235,7 +235,7 @@ void cgb_audio_generate(u16 samplesPerFrame) ch4Out--; } int avgDiv = 1; - while (ch4Samples >= u32_to_fp16_16(1)) { + while (ch4Samples >= 1) { avgDiv++; bool8 lfsrCarry = 0; if (gb.ch4LFSR[lfsrMode] & 2) @@ -250,15 +250,15 @@ void cgb_audio_generate(u16 samplesPerFrame) } else { ch4Out--; } - ch4Samples -= u32_to_fp16_16(1); + ch4Samples -= 1; } - fixed16_16 sample = float_to_fp16_16(ch4Out); + float sample = ch4Out; if (avgDiv > 1) sample /= avgDiv; if (REG_NR51 & 0x80) - outputL += fp16_16_to_float(gb.Vol[3] * sample / 15); + outputL += (gb.Vol[3] * sample / 15); if (REG_NR51 & 0x08) - outputR += fp16_16_to_float(gb.Vol[3] * sample / 15); + outputR += (gb.Vol[3] * sample / 15); } } outBuffer[0] = outputL * 0.25f; From ac1877ab0c7db46370021633e7028e8912d28416 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 21 Feb 2026 15:21:57 +0000 Subject: [PATCH 18/51] switch cgb audio to 16bit fixed --- include/lib/m4a/m4a_internal.h | 4 +- include/platform/shared/audio/cgb_audio.h | 2 +- include/platform/shared/audio/cgb_tables.h | 4664 ++++++++++---------- src/platform/ps2/ps2.c | 12 +- src/platform/shared/audio/cgb_audio.c | 69 +- 5 files changed, 2396 insertions(+), 2355 deletions(-) diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 737e25127d..dec6699065 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -109,9 +109,9 @@ typedef s32 fixed16_16; typedef s32 fixed8_24; -#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0) +#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0f) -#define fp16_16_to_float(value) (float)((value) / 65536.0) +#define fp16_16_to_float(value) (float)((value) / 65536.0f) #define u32_to_fp16_16(value) ((value) << 16) diff --git a/include/platform/shared/audio/cgb_audio.h b/include/platform/shared/audio/cgb_audio.h index 65dd77a91e..5efce08e29 100644 --- a/include/platform/shared/audio/cgb_audio.h +++ b/include/platform/shared/audio/cgb_audio.h @@ -18,7 +18,7 @@ struct AudioCGB { u8 EnvCounterI[4]; bool8 EnvDir[4]; bool8 DAC[4]; - float WAVRAM[32]; + fixed16_16 WAVRAM[32]; u16 ch4LFSR[2]; float outBuffer[PCM_DMA_BUF_SIZE * 2]; }; diff --git a/include/platform/shared/audio/cgb_tables.h b/include/platform/shared/audio/cgb_tables.h index e6c5c683f9..202807cf50 100644 --- a/include/platform/shared/audio/cgb_tables.h +++ b/include/platform/shared/audio/cgb_tables.h @@ -6,2336 +6,2356 @@ #define SAMPLE_RATE 48000.0 #define FREQUENCY_RATE (SAMPLE_RATE / 32.0) -const float PU0[32] = { (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; +const fixed16_16 PU0[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; -const float PU1[32] = { (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; +const fixed16_16 PU1[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; -const float PU2[32] = { (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), - (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), - (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; +const fixed16_16 PU2[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; -const float PU3[32] = { (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), - (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), - (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), - (1.0 / 15), (1.0 / 15), (1.0 / 15), (1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15), (-1.0 / 15) }; +const fixed16_16 PU3[32] + = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), + float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; int16_t WAV[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; -const float freqTable[2048] = { - (32 / FREQUENCY_RATE), - (32.0156326331216 / FREQUENCY_RATE), - (32.0312805474096 / FREQUENCY_RATE), - (32.0469437652812 / FREQUENCY_RATE), - (32.0626223091976 / FREQUENCY_RATE), - (32.0783162016642 / FREQUENCY_RATE), - (32.0940254652302 / FREQUENCY_RATE), - (32.109750122489 / FREQUENCY_RATE), - (32.1254901960784 / FREQUENCY_RATE), - (32.1412457086807 / FREQUENCY_RATE), - (32.1570166830226 / FREQUENCY_RATE), - (32.1728031418753 / FREQUENCY_RATE), - (32.188605108055 / FREQUENCY_RATE), - (32.2044226044226 / FREQUENCY_RATE), - (32.220255653884 / FREQUENCY_RATE), - (32.2361042793901 / FREQUENCY_RATE), - (32.251968503937 / FREQUENCY_RATE), - (32.2678483505662 / FREQUENCY_RATE), - (32.2837438423645 / FREQUENCY_RATE), - (32.2996550024643 / FREQUENCY_RATE), - (32.3155818540434 / FREQUENCY_RATE), - (32.3315244203256 / FREQUENCY_RATE), - (32.3474827245805 / FREQUENCY_RATE), - (32.3634567901235 / FREQUENCY_RATE), - (32.3794466403162 / FREQUENCY_RATE), - (32.3954522985665 / FREQUENCY_RATE), - (32.4114737883284 / FREQUENCY_RATE), - (32.4275111331024 / FREQUENCY_RATE), - (32.4435643564356 / FREQUENCY_RATE), - (32.4596334819217 / FREQUENCY_RATE), - (32.4757185332012 / FREQUENCY_RATE), - (32.4918195339613 / FREQUENCY_RATE), - (32.5079365079365 / FREQUENCY_RATE), - (32.5240694789082 / FREQUENCY_RATE), - (32.5402184707051 / FREQUENCY_RATE), - (32.5563835072032 / FREQUENCY_RATE), - (32.572564612326 / FREQUENCY_RATE), - (32.5887618100448 / FREQUENCY_RATE), - (32.6049751243781 / FREQUENCY_RATE), - (32.6212045793927 / FREQUENCY_RATE), - (32.6374501992032 / FREQUENCY_RATE), - (32.6537120079721 / FREQUENCY_RATE), - (32.6699900299103 / FREQUENCY_RATE), - (32.6862842892768 / FREQUENCY_RATE), - (32.7025948103792 / FREQUENCY_RATE), - (32.7189216175736 / FREQUENCY_RATE), - (32.7352647352647 / FREQUENCY_RATE), - (32.751624187906 / FREQUENCY_RATE), - (32.768 / FREQUENCY_RATE), - (32.784392196098 / FREQUENCY_RATE), - (32.8008008008008 / FREQUENCY_RATE), - (32.8172258387581 / FREQUENCY_RATE), - (32.8336673346693 / FREQUENCY_RATE), - (32.8501253132832 / FREQUENCY_RATE), - (32.8665997993982 / FREQUENCY_RATE), - (32.8830908178625 / FREQUENCY_RATE), - (32.8995983935743 / FREQUENCY_RATE), - (32.9161225514817 / FREQUENCY_RATE), - (32.9326633165829 / FREQUENCY_RATE), - (32.9492207139266 / FREQUENCY_RATE), - (32.9657947686117 / FREQUENCY_RATE), - (32.9823855057876 / FREQUENCY_RATE), - (32.9989929506546 / FREQUENCY_RATE), - (33.0156171284635 / FREQUENCY_RATE), - (33.0322580645161 / FREQUENCY_RATE), - (33.0489157841654 / FREQUENCY_RATE), - (33.0655903128153 / FREQUENCY_RATE), - (33.0822816759213 / FREQUENCY_RATE), - (33.0989898989899 / FREQUENCY_RATE), - (33.1157150075796 / FREQUENCY_RATE), - (33.1324570273003 / FREQUENCY_RATE), - (33.1492159838139 / FREQUENCY_RATE), - (33.165991902834 / FREQUENCY_RATE), - (33.1827848101266 / FREQUENCY_RATE), - (33.1995947315096 / FREQUENCY_RATE), - (33.2164216928535 / FREQUENCY_RATE), - (33.2332657200811 / FREQUENCY_RATE), - (33.2501268391679 / FREQUENCY_RATE), - (33.2670050761421 / FREQUENCY_RATE), - (33.2839004570848 / FREQUENCY_RATE), - (33.3008130081301 / FREQUENCY_RATE), - (33.3177427554652 / FREQUENCY_RATE), - (33.3346897253306 / FREQUENCY_RATE), - (33.3516539440204 / FREQUENCY_RATE), - (33.3686354378819 / FREQUENCY_RATE), - (33.3856342333164 / FREQUENCY_RATE), - (33.4026503567788 / FREQUENCY_RATE), - (33.4196838347782 / FREQUENCY_RATE), - (33.4367346938776 / FREQUENCY_RATE), - (33.4538029606942 / FREQUENCY_RATE), - (33.4708886618999 / FREQUENCY_RATE), - (33.4879918242207 / FREQUENCY_RATE), - (33.5051124744376 / FREQUENCY_RATE), - (33.5222506393862 / FREQUENCY_RATE), - (33.539406345957 / FREQUENCY_RATE), - (33.5565796210957 / FREQUENCY_RATE), - (33.5737704918033 / FREQUENCY_RATE), - (33.5909789851358 / FREQUENCY_RATE), - (33.6082051282051 / FREQUENCY_RATE), - (33.6254489481786 / FREQUENCY_RATE), - (33.6427104722793 / FREQUENCY_RATE), - (33.6599897277863 / FREQUENCY_RATE), - (33.6772867420349 / FREQUENCY_RATE), - (33.6946015424164 / FREQUENCY_RATE), - (33.7119341563786 / FREQUENCY_RATE), - (33.7292846114256 / FREQUENCY_RATE), - (33.7466529351184 / FREQUENCY_RATE), - (33.7640391550747 / FREQUENCY_RATE), - (33.7814432989691 / FREQUENCY_RATE), - (33.7988653945333 / FREQUENCY_RATE), - (33.8163054695562 / FREQUENCY_RATE), - (33.8337635518844 / FREQUENCY_RATE), - (33.8512396694215 / FREQUENCY_RATE), - (33.8687338501292 / FREQUENCY_RATE), - (33.8862461220269 / FREQUENCY_RATE), - (33.9037765131919 / FREQUENCY_RATE), - (33.9213250517598 / FREQUENCY_RATE), - (33.9388917659244 / FREQUENCY_RATE), - (33.9564766839378 / FREQUENCY_RATE), - (33.9740798341109 / FREQUENCY_RATE), - (33.9917012448133 / FREQUENCY_RATE), - (34.0093409444733 / FREQUENCY_RATE), - (34.0269989615784 / FREQUENCY_RATE), - (34.0446753246753 / FREQUENCY_RATE), - (34.0623700623701 / FREQUENCY_RATE), - (34.0800832033281 / FREQUENCY_RATE), - (34.0978147762747 / FREQUENCY_RATE), - (34.1155648099948 / FREQUENCY_RATE), - (34.1333333333333 / FREQUENCY_RATE), - (34.1511203751954 / FREQUENCY_RATE), - (34.1689259645464 / FREQUENCY_RATE), - (34.1867501304121 / FREQUENCY_RATE), - (34.2045929018789 / FREQUENCY_RATE), - (34.222454308094 / FREQUENCY_RATE), - (34.2403343782654 / FREQUENCY_RATE), - (34.2582331416623 / FREQUENCY_RATE), - (34.2761506276151 / FREQUENCY_RATE), - (34.2940868655154 / FREQUENCY_RATE), - (34.3120418848168 / FREQUENCY_RATE), - (34.330015715034 / FREQUENCY_RATE), - (34.3480083857442 / FREQUENCY_RATE), - (34.3660199265863 / FREQUENCY_RATE), - (34.3840503672613 / FREQUENCY_RATE), - (34.4020997375328 / FREQUENCY_RATE), - (34.4201680672269 / FREQUENCY_RATE), - (34.4382553862323 / FREQUENCY_RATE), - (34.4563617245005 / FREQUENCY_RATE), - (34.4744871120463 / FREQUENCY_RATE), - (34.4926315789474 / FREQUENCY_RATE), - (34.5107951553449 / FREQUENCY_RATE), - (34.5289778714436 / FREQUENCY_RATE), - (34.5471797575119 / FREQUENCY_RATE), - (34.5654008438819 / FREQUENCY_RATE), - (34.5836411609499 / FREQUENCY_RATE), - (34.6019007391763 / FREQUENCY_RATE), - (34.6201796090861 / FREQUENCY_RATE), - (34.6384778012685 / FREQUENCY_RATE), - (34.6567953463776 / FREQUENCY_RATE), - (34.6751322751323 / FREQUENCY_RATE), - (34.6934886183166 / FREQUENCY_RATE), - (34.7118644067797 / FREQUENCY_RATE), - (34.7302596714361 / FREQUENCY_RATE), - (34.7486744432662 / FREQUENCY_RATE), - (34.7671087533156 / FREQUENCY_RATE), - (34.7855626326964 / FREQUENCY_RATE), - (34.8040361125863 / FREQUENCY_RATE), - (34.8225292242295 / FREQUENCY_RATE), - (34.8410419989367 / FREQUENCY_RATE), - (34.8595744680851 / FREQUENCY_RATE), - (34.8781266631187 / FREQUENCY_RATE), - (34.8966986155485 / FREQUENCY_RATE), - (34.9152903569526 / FREQUENCY_RATE), - (34.9339019189765 / FREQUENCY_RATE), - (34.9525333333333 / FREQUENCY_RATE), - (34.9711846318036 / FREQUENCY_RATE), - (34.989855846236 / FREQUENCY_RATE), - (35.008547008547 / FREQUENCY_RATE), - (35.0272581507215 / FREQUENCY_RATE), - (35.0459893048128 / FREQUENCY_RATE), - (35.0647405029427 / FREQUENCY_RATE), - (35.0835117773019 / FREQUENCY_RATE), - (35.10230316015 / FREQUENCY_RATE), - (35.1211146838156 / FREQUENCY_RATE), - (35.1399463806971 / FREQUENCY_RATE), - (35.1587982832618 / FREQUENCY_RATE), - (35.1776704240472 / FREQUENCY_RATE), - (35.1965628356606 / FREQUENCY_RATE), - (35.2154755507792 / FREQUENCY_RATE), - (35.2344086021505 / FREQUENCY_RATE), - (35.2533620225928 / FREQUENCY_RATE), - (35.2723358449946 / FREQUENCY_RATE), - (35.2913301023156 / FREQUENCY_RATE), - (35.3103448275862 / FREQUENCY_RATE), - (35.3293800539084 / FREQUENCY_RATE), - (35.3484358144552 / FREQUENCY_RATE), - (35.3675121424717 / FREQUENCY_RATE), - (35.3866090712743 / FREQUENCY_RATE), - (35.4057266342518 / FREQUENCY_RATE), - (35.4248648648649 / FREQUENCY_RATE), - (35.4440237966468 / FREQUENCY_RATE), - (35.4632034632035 / FREQUENCY_RATE), - (35.4824038982133 / FREQUENCY_RATE), - (35.501625135428 / FREQUENCY_RATE), - (35.5208672086721 / FREQUENCY_RATE), - (35.5401301518438 / FREQUENCY_RATE), - (35.5594139989148 / FREQUENCY_RATE), - (35.5787187839305 / FREQUENCY_RATE), - (35.5980445410103 / FREQUENCY_RATE), - (35.6173913043478 / FREQUENCY_RATE), - (35.636759108211 / FREQUENCY_RATE), - (35.6561479869423 / FREQUENCY_RATE), - (35.6755579749592 / FREQUENCY_RATE), - (35.6949891067538 / FREQUENCY_RATE), - (35.7144414168937 / FREQUENCY_RATE), - (35.7339149400218 / FREQUENCY_RATE), - (35.7534097108565 / FREQUENCY_RATE), - (35.7729257641921 / FREQUENCY_RATE), - (35.792463134899 / FREQUENCY_RATE), - (35.8120218579235 / FREQUENCY_RATE), - (35.8316019682887 / FREQUENCY_RATE), - (35.8512035010941 / FREQUENCY_RATE), - (35.8708264915161 / FREQUENCY_RATE), - (35.8904709748083 / FREQUENCY_RATE), - (35.9101369863014 / FREQUENCY_RATE), - (35.9298245614035 / FREQUENCY_RATE), - (35.9495337356007 / FREQUENCY_RATE), - (35.9692645444566 / FREQUENCY_RATE), - (35.9890170236134 / FREQUENCY_RATE), - (36.0087912087912 / FREQUENCY_RATE), - (36.0285871357889 / FREQUENCY_RATE), - (36.048404840484 / FREQUENCY_RATE), - (36.0682443588332 / FREQUENCY_RATE), - (36.0881057268722 / FREQUENCY_RATE), - (36.1079889807162 / FREQUENCY_RATE), - (36.1278941565601 / FREQUENCY_RATE), - (36.1478212906784 / FREQUENCY_RATE), - (36.167770419426 / FREQUENCY_RATE), - (36.187741579238 / FREQUENCY_RATE), - (36.2077348066298 / FREQUENCY_RATE), - (36.2277501381979 / FREQUENCY_RATE), - (36.2477876106195 / FREQUENCY_RATE), - (36.267847260653 / FREQUENCY_RATE), - (36.2879291251384 / FREQUENCY_RATE), - (36.3080332409972 / FREQUENCY_RATE), - (36.3281596452328 / FREQUENCY_RATE), - (36.3483083749307 / FREQUENCY_RATE), - (36.3684794672586 / FREQUENCY_RATE), - (36.388672959467 / FREQUENCY_RATE), - (36.4088888888889 / FREQUENCY_RATE), - (36.4291272929405 / FREQUENCY_RATE), - (36.4493882091212 / FREQUENCY_RATE), - (36.4696716750139 / FREQUENCY_RATE), - (36.4899777282851 / FREQUENCY_RATE), - (36.5103064066852 / FREQUENCY_RATE), - (36.5306577480491 / FREQUENCY_RATE), - (36.5510317902956 / FREQUENCY_RATE), - (36.5714285714286 / FREQUENCY_RATE), - (36.5918481295366 / FREQUENCY_RATE), - (36.6122905027933 / FREQUENCY_RATE), - (36.6327557294578 / FREQUENCY_RATE), - (36.6532438478747 / FREQUENCY_RATE), - (36.6737548964745 / FREQUENCY_RATE), - (36.6942889137738 / FREQUENCY_RATE), - (36.7148459383753 / FREQUENCY_RATE), - (36.7354260089686 / FREQUENCY_RATE), - (36.7560291643298 / FREQUENCY_RATE), - (36.7766554433221 / FREQUENCY_RATE), - (36.7973048848961 / FREQUENCY_RATE), - (36.8179775280899 / FREQUENCY_RATE), - (36.8386734120292 / FREQUENCY_RATE), - (36.859392575928 / FREQUENCY_RATE), - (36.8801350590884 / FREQUENCY_RATE), - (36.9009009009009 / FREQUENCY_RATE), - (36.9216901408451 / FREQUENCY_RATE), - (36.9425028184893 / FREQUENCY_RATE), - (36.9633389734913 / FREQUENCY_RATE), - (36.9841986455982 / FREQUENCY_RATE), - (37.0050818746471 / FREQUENCY_RATE), - (37.025988700565 / FREQUENCY_RATE), - (37.0469191633691 / FREQUENCY_RATE), - (37.0678733031674 / FREQUENCY_RATE), - (37.0888511601585 / FREQUENCY_RATE), - (37.1098527746319 / FREQUENCY_RATE), - (37.1308781869688 / FREQUENCY_RATE), - (37.1519274376417 / FREQUENCY_RATE), - (37.173000567215 / FREQUENCY_RATE), - (37.1940976163451 / FREQUENCY_RATE), - (37.2152186257808 / FREQUENCY_RATE), - (37.2363636363636 / FREQUENCY_RATE), - (37.2575326890279 / FREQUENCY_RATE), - (37.2787258248009 / FREQUENCY_RATE), - (37.2999430848036 / FREQUENCY_RATE), - (37.3211845102506 / FREQUENCY_RATE), - (37.3424501424501 / FREQUENCY_RATE), - (37.363740022805 / FREQUENCY_RATE), - (37.3850541928123 / FREQUENCY_RATE), - (37.4063926940639 / FREQUENCY_RATE), - (37.4277555682467 / FREQUENCY_RATE), - (37.4491428571429 / FREQUENCY_RATE), - (37.4705546026301 / FREQUENCY_RATE), - (37.4919908466819 / FREQUENCY_RATE), - (37.5134516313681 / FREQUENCY_RATE), - (37.5349369988545 / FREQUENCY_RATE), - (37.556446991404 / FREQUENCY_RATE), - (37.5779816513761 / FREQUENCY_RATE), - (37.5995410212278 / FREQUENCY_RATE), - (37.6211251435132 / FREQUENCY_RATE), - (37.6427340608845 / FREQUENCY_RATE), - (37.664367816092 / FREQUENCY_RATE), - (37.6860264519839 / FREQUENCY_RATE), - (37.7077100115075 / FREQUENCY_RATE), - (37.7294185377087 / FREQUENCY_RATE), - (37.7511520737327 / FREQUENCY_RATE), - (37.7729106628242 / FREQUENCY_RATE), - (37.7946943483276 / FREQUENCY_RATE), - (37.8165031736872 / FREQUENCY_RATE), - (37.838337182448 / FREQUENCY_RATE), - (37.8601964182553 / FREQUENCY_RATE), - (37.8820809248555 / FREQUENCY_RATE), - (37.903990746096 / FREQUENCY_RATE), - (37.9259259259259 / FREQUENCY_RATE), - (37.9478865083961 / FREQUENCY_RATE), - (37.9698725376593 / FREQUENCY_RATE), - (37.991884057971 / FREQUENCY_RATE), - (38.0139211136891 / FREQUENCY_RATE), - (38.0359837492745 / FREQUENCY_RATE), - (38.0580720092915 / FREQUENCY_RATE), - (38.0801859384079 / FREQUENCY_RATE), - (38.1023255813953 / FREQUENCY_RATE), - (38.1244909831297 / FREQUENCY_RATE), - (38.1466821885914 / FREQUENCY_RATE), - (38.1688992428655 / FREQUENCY_RATE), - (38.1911421911422 / FREQUENCY_RATE), - (38.2134110787172 / FREQUENCY_RATE), - (38.2357059509918 / FREQUENCY_RATE), - (38.2580268534734 / FREQUENCY_RATE), - (38.2803738317757 / FREQUENCY_RATE), - (38.3027469316189 / FREQUENCY_RATE), - (38.3251461988304 / FREQUENCY_RATE), - (38.3475716793446 / FREQUENCY_RATE), - (38.3700234192037 / FREQUENCY_RATE), - (38.3925014645577 / FREQUENCY_RATE), - (38.4150058616647 / FREQUENCY_RATE), - (38.4375366568915 / FREQUENCY_RATE), - (38.4600938967136 / FREQUENCY_RATE), - (38.4826776277158 / FREQUENCY_RATE), - (38.5052878965922 / FREQUENCY_RATE), - (38.527924750147 / FREQUENCY_RATE), - (38.5505882352941 / FREQUENCY_RATE), - (38.5732783990583 / FREQUENCY_RATE), - (38.5959952885748 / FREQUENCY_RATE), - (38.6187389510902 / FREQUENCY_RATE), - (38.6415094339623 / FREQUENCY_RATE), - (38.6643067846608 / FREQUENCY_RATE), - (38.6871310507674 / FREQUENCY_RATE), - (38.7099822799764 / FREQUENCY_RATE), - (38.7328605200946 / FREQUENCY_RATE), - (38.755765819042 / FREQUENCY_RATE), - (38.7786982248521 / FREQUENCY_RATE), - (38.801657785672 / FREQUENCY_RATE), - (38.824644549763 / FREQUENCY_RATE), - (38.8476585655009 / FREQUENCY_RATE), - (38.870699881376 / FREQUENCY_RATE), - (38.8937685459941 / FREQUENCY_RATE), - (38.916864608076 / FREQUENCY_RATE), - (38.9399881164587 / FREQUENCY_RATE), - (38.9631391200951 / FREQUENCY_RATE), - (38.9863176680547 / FREQUENCY_RATE), - (39.0095238095238 / FREQUENCY_RATE), - (39.0327575938058 / FREQUENCY_RATE), - (39.0560190703218 / FREQUENCY_RATE), - (39.0793082886106 / FREQUENCY_RATE), - (39.1026252983294 / FREQUENCY_RATE), - (39.1259701492537 / FREQUENCY_RATE), - (39.1493428912784 / FREQUENCY_RATE), - (39.1727435744172 / FREQUENCY_RATE), - (39.1961722488038 / FREQUENCY_RATE), - (39.2196289646918 / FREQUENCY_RATE), - (39.2431137724551 / FREQUENCY_RATE), - (39.2666267225884 / FREQUENCY_RATE), - (39.2901678657074 / FREQUENCY_RATE), - (39.3137372525495 / FREQUENCY_RATE), - (39.3373349339736 / FREQUENCY_RATE), - (39.360960960961 / FREQUENCY_RATE), - (39.3846153846154 / FREQUENCY_RATE), - (39.4082982561636 / FREQUENCY_RATE), - (39.4320096269555 / FREQUENCY_RATE), - (39.4557495484648 / FREQUENCY_RATE), - (39.4795180722892 / FREQUENCY_RATE), - (39.5033152501507 / FREQUENCY_RATE), - (39.5271411338963 / FREQUENCY_RATE), - (39.5509957754979 / FREQUENCY_RATE), - (39.5748792270531 / FREQUENCY_RATE), - (39.5987915407855 / FREQUENCY_RATE), - (39.6227327690447 / FREQUENCY_RATE), - (39.6467029643073 / FREQUENCY_RATE), - (39.6707021791768 / FREQUENCY_RATE), - (39.694730466384 / FREQUENCY_RATE), - (39.7187878787879 / FREQUENCY_RATE), - (39.7428744693754 / FREQUENCY_RATE), - (39.7669902912621 / FREQUENCY_RATE), - (39.7911353976928 / FREQUENCY_RATE), - (39.8153098420413 / FREQUENCY_RATE), - (39.8395136778115 / FREQUENCY_RATE), - (39.8637469586375 / FREQUENCY_RATE), - (39.8880097382836 / FREQUENCY_RATE), - (39.9123020706455 / FREQUENCY_RATE), - (39.9366240097502 / FREQUENCY_RATE), - (39.9609756097561 / FREQUENCY_RATE), - (39.9853569249542 / FREQUENCY_RATE), - (40.009768009768 / FREQUENCY_RATE), - (40.0342089187538 / FREQUENCY_RATE), - (40.0586797066015 / FREQUENCY_RATE), - (40.0831804281346 / FREQUENCY_RATE), - (40.1077111383109 / FREQUENCY_RATE), - (40.1322718922229 / FREQUENCY_RATE), - (40.156862745098 / FREQUENCY_RATE), - (40.1814837522992 / FREQUENCY_RATE), - (40.2061349693252 / FREQUENCY_RATE), - (40.2308164518109 / FREQUENCY_RATE), - (40.2555282555283 / FREQUENCY_RATE), - (40.280270436386 / FREQUENCY_RATE), - (40.3050430504305 / FREQUENCY_RATE), - (40.3298461538462 / FREQUENCY_RATE), - (40.3546798029557 / FREQUENCY_RATE), - (40.3795440542206 / FREQUENCY_RATE), - (40.4044389642417 / FREQUENCY_RATE), - (40.4293645897594 / FREQUENCY_RATE), - (40.4543209876543 / FREQUENCY_RATE), - (40.4793082149475 / FREQUENCY_RATE), - (40.504326328801 / FREQUENCY_RATE), - (40.5293753865182 / FREQUENCY_RATE), - (40.5544554455446 / FREQUENCY_RATE), - (40.5795665634675 / FREQUENCY_RATE), - (40.6047087980174 / FREQUENCY_RATE), - (40.6298822070676 / FREQUENCY_RATE), - (40.6550868486352 / FREQUENCY_RATE), - (40.6803227808814 / FREQUENCY_RATE), - (40.7055900621118 / FREQUENCY_RATE), - (40.7308887507769 / FREQUENCY_RATE), - (40.7562189054726 / FREQUENCY_RATE), - (40.7815805849409 / FREQUENCY_RATE), - (40.8069738480697 / FREQUENCY_RATE), - (40.8323987538941 / FREQUENCY_RATE), - (40.857855361596 / FREQUENCY_RATE), - (40.8833437305053 / FREQUENCY_RATE), - (40.9088639200999 / FREQUENCY_RATE), - (40.9344159900062 / FREQUENCY_RATE), - (40.96 / FREQUENCY_RATE), - (40.9856160100063 / FREQUENCY_RATE), - (41.0112640801001 / FREQUENCY_RATE), - (41.0369442705072 / FREQUENCY_RATE), - (41.062656641604 / FREQUENCY_RATE), - (41.0884012539185 / FREQUENCY_RATE), - (41.1141781681305 / FREQUENCY_RATE), - (41.1399874450722 / FREQUENCY_RATE), - (41.1658291457287 / FREQUENCY_RATE), - (41.1917033312382 / FREQUENCY_RATE), - (41.2176100628931 / FREQUENCY_RATE), - (41.2435494021397 / FREQUENCY_RATE), - (41.2695214105793 / FREQUENCY_RATE), - (41.2955261499685 / FREQUENCY_RATE), - (41.3215636822194 / FREQUENCY_RATE), - (41.3476340694006 / FREQUENCY_RATE), - (41.3737373737374 / FREQUENCY_RATE), - (41.3998736576121 / FREQUENCY_RATE), - (41.4260429835651 / FREQUENCY_RATE), - (41.4522454142948 / FREQUENCY_RATE), - (41.4784810126582 / FREQUENCY_RATE), - (41.504749841672 / FREQUENCY_RATE), - (41.531051964512 / FREQUENCY_RATE), - (41.5573874445149 / FREQUENCY_RATE), - (41.5837563451777 / FREQUENCY_RATE), - (41.6101587301587 / FREQUENCY_RATE), - (41.6365946632783 / FREQUENCY_RATE), - (41.6630642085188 / FREQUENCY_RATE), - (41.6895674300254 / FREQUENCY_RATE), - (41.7161043921069 / FREQUENCY_RATE), - (41.7426751592357 / FREQUENCY_RATE), - (41.7692797960484 / FREQUENCY_RATE), - (41.7959183673469 / FREQUENCY_RATE), - (41.8225909380983 / FREQUENCY_RATE), - (41.8492975734355 / FREQUENCY_RATE), - (41.8760383386582 / FREQUENCY_RATE), - (41.9028132992327 / FREQUENCY_RATE), - (41.9296225207934 / FREQUENCY_RATE), - (41.9564660691421 / FREQUENCY_RATE), - (41.9833440102498 / FREQUENCY_RATE), - (42.0102564102564 / FREQUENCY_RATE), - (42.0372033354715 / FREQUENCY_RATE), - (42.0641848523748 / FREQUENCY_RATE), - (42.0912010276172 / FREQUENCY_RATE), - (42.1182519280206 / FREQUENCY_RATE), - (42.1453376205788 / FREQUENCY_RATE), - (42.1724581724582 / FREQUENCY_RATE), - (42.1996136509981 / FREQUENCY_RATE), - (42.2268041237113 / FREQUENCY_RATE), - (42.254029658285 / FREQUENCY_RATE), - (42.2812903225807 / FREQUENCY_RATE), - (42.3085861846352 / FREQUENCY_RATE), - (42.3359173126615 / FREQUENCY_RATE), - (42.3632837750485 / FREQUENCY_RATE), - (42.3906856403622 / FREQUENCY_RATE), - (42.4181229773463 / FREQUENCY_RATE), - (42.4455958549223 / FREQUENCY_RATE), - (42.4731043421905 / FREQUENCY_RATE), - (42.5006485084306 / FREQUENCY_RATE), - (42.5282284231019 / FREQUENCY_RATE), - (42.5558441558442 / FREQUENCY_RATE), - (42.5834957764782 / FREQUENCY_RATE), - (42.6111833550065 / FREQUENCY_RATE), - (42.6389069616135 / FREQUENCY_RATE), - (42.6666666666667 / FREQUENCY_RATE), - (42.6944625407166 / FREQUENCY_RATE), - (42.722294654498 / FREQUENCY_RATE), - (42.7501630789302 / FREQUENCY_RATE), - (42.7780678851175 / FREQUENCY_RATE), - (42.8060091443501 / FREQUENCY_RATE), - (42.8339869281046 / FREQUENCY_RATE), - (42.8620013080445 / FREQUENCY_RATE), - (42.890052356021 / FREQUENCY_RATE), - (42.9181401440733 / FREQUENCY_RATE), - (42.9462647444299 / FREQUENCY_RATE), - (42.9744262295082 / FREQUENCY_RATE), - (43.002624671916 / FREQUENCY_RATE), - (43.0308601444517 / FREQUENCY_RATE), - (43.0591327201051 / FREQUENCY_RATE), - (43.0874424720579 / FREQUENCY_RATE), - (43.1157894736842 / FREQUENCY_RATE), - (43.1441737985517 / FREQUENCY_RATE), - (43.1725955204216 / FREQUENCY_RATE), - (43.2010547132498 / FREQUENCY_RATE), - (43.2295514511873 / FREQUENCY_RATE), - (43.2580858085809 / FREQUENCY_RATE), - (43.2866578599736 / FREQUENCY_RATE), - (43.3152676801057 / FREQUENCY_RATE), - (43.3439153439153 / FREQUENCY_RATE), - (43.3726009265387 / FREQUENCY_RATE), - (43.4013245033113 / FREQUENCY_RATE), - (43.4300861497681 / FREQUENCY_RATE), - (43.4588859416446 / FREQUENCY_RATE), - (43.4877239548772 / FREQUENCY_RATE), - (43.5166002656043 / FREQUENCY_RATE), - (43.5455149501661 / FREQUENCY_RATE), - (43.5744680851064 / FREQUENCY_RATE), - (43.6034597471723 / FREQUENCY_RATE), - (43.6324900133156 / FREQUENCY_RATE), - (43.6615589606929 / FREQUENCY_RATE), - (43.6906666666667 / FREQUENCY_RATE), - (43.7198132088059 / FREQUENCY_RATE), - (43.7489986648865 / FREQUENCY_RATE), - (43.7782231128925 / FREQUENCY_RATE), - (43.807486631016 / FREQUENCY_RATE), - (43.8367892976589 / FREQUENCY_RATE), - (43.8661311914324 / FREQUENCY_RATE), - (43.8955123911587 / FREQUENCY_RATE), - (43.9249329758713 / FREQUENCY_RATE), - (43.9543930248156 / FREQUENCY_RATE), - (43.9838926174497 / FREQUENCY_RATE), - (44.0134318334453 / FREQUENCY_RATE), - (44.0430107526882 / FREQUENCY_RATE), - (44.0726294552791 / FREQUENCY_RATE), - (44.1022880215343 / FREQUENCY_RATE), - (44.1319865319865 / FREQUENCY_RATE), - (44.1617250673855 / FREQUENCY_RATE), - (44.1915037086986 / FREQUENCY_RATE), - (44.221322537112 / FREQUENCY_RATE), - (44.2511816340311 / FREQUENCY_RATE), - (44.2810810810811 / FREQUENCY_RATE), - (44.3110209601082 / FREQUENCY_RATE), - (44.34100135318 / FREQUENCY_RATE), - (44.3710223425863 / FREQUENCY_RATE), - (44.4010840108401 / FREQUENCY_RATE), - (44.431186440678 / FREQUENCY_RATE), - (44.4613297150611 / FREQUENCY_RATE), - (44.4915139171758 / FREQUENCY_RATE), - (44.5217391304348 / FREQUENCY_RATE), - (44.5520054384772 / FREQUENCY_RATE), - (44.5823129251701 / FREQUENCY_RATE), - (44.6126616746086 / FREQUENCY_RATE), - (44.6430517711172 / FREQUENCY_RATE), - (44.6734832992502 / FREQUENCY_RATE), - (44.7039563437926 / FREQUENCY_RATE), - (44.7344709897611 / FREQUENCY_RATE), - (44.7650273224044 / FREQUENCY_RATE), - (44.7956254272044 / FREQUENCY_RATE), - (44.8262653898769 / FREQUENCY_RATE), - (44.8569472963724 / FREQUENCY_RATE), - (44.8876712328767 / FREQUENCY_RATE), - (44.9184372858122 / FREQUENCY_RATE), - (44.9492455418381 / FREQUENCY_RATE), - (44.9800960878518 / FREQUENCY_RATE), - (45.010989010989 / FREQUENCY_RATE), - (45.0419243986254 / FREQUENCY_RATE), - (45.0729023383769 / FREQUENCY_RATE), - (45.1039229181005 / FREQUENCY_RATE), - (45.1349862258953 / FREQUENCY_RATE), - (45.1660923501034 / FREQUENCY_RATE), - (45.1972413793103 / FREQUENCY_RATE), - (45.2284334023465 / FREQUENCY_RATE), - (45.2596685082873 / FREQUENCY_RATE), - (45.2909467864547 / FREQUENCY_RATE), - (45.3222683264177 / FREQUENCY_RATE), - (45.3536332179931 / FREQUENCY_RATE), - (45.3850415512465 / FREQUENCY_RATE), - (45.4164934164934 / FREQUENCY_RATE), - (45.4479889042996 / FREQUENCY_RATE), - (45.4795281054823 / FREQUENCY_RATE), - (45.5111111111111 / FREQUENCY_RATE), - (45.5427380125087 / FREQUENCY_RATE), - (45.5744089012517 / FREQUENCY_RATE), - (45.6061238691719 / FREQUENCY_RATE), - (45.6378830083566 / FREQUENCY_RATE), - (45.6696864111498 / FREQUENCY_RATE), - (45.7015341701534 / FREQUENCY_RATE), - (45.7334263782275 / FREQUENCY_RATE), - (45.7653631284916 / FREQUENCY_RATE), - (45.7973445143256 / FREQUENCY_RATE), - (45.8293706293706 / FREQUENCY_RATE), - (45.8614415675297 / FREQUENCY_RATE), - (45.8935574229692 / FREQUENCY_RATE), - (45.9257182901191 / FREQUENCY_RATE), - (45.9579242636746 / FREQUENCY_RATE), - (45.9901754385965 / FREQUENCY_RATE), - (46.0224719101124 / FREQUENCY_RATE), - (46.0548137737175 / FREQUENCY_RATE), - (46.0872011251758 / FREQUENCY_RATE), - (46.1196340605208 / FREQUENCY_RATE), - (46.1521126760563 / FREQUENCY_RATE), - (46.184637068358 / FREQUENCY_RATE), - (46.2172073342736 / FREQUENCY_RATE), - (46.2498235709245 / FREQUENCY_RATE), - (46.2824858757062 / FREQUENCY_RATE), - (46.3151943462898 / FREQUENCY_RATE), - (46.3479490806223 / FREQUENCY_RATE), - (46.3807501769285 / FREQUENCY_RATE), - (46.4135977337111 / FREQUENCY_RATE), - (46.446491849752 / FREQUENCY_RATE), - (46.4794326241135 / FREQUENCY_RATE), - (46.5124201561391 / FREQUENCY_RATE), - (46.5454545454545 / FREQUENCY_RATE), - (46.5785358919687 / FREQUENCY_RATE), - (46.6116642958748 / FREQUENCY_RATE), - (46.6448398576513 / FREQUENCY_RATE), - (46.6780626780627 / FREQUENCY_RATE), - (46.7113328581611 / FREQUENCY_RATE), - (46.7446504992867 / FREQUENCY_RATE), - (46.7780157030692 / FREQUENCY_RATE), - (46.8114285714286 / FREQUENCY_RATE), - (46.8448892065761 / FREQUENCY_RATE), - (46.8783977110157 / FREQUENCY_RATE), - (46.9119541875447 / FREQUENCY_RATE), - (46.945558739255 / FREQUENCY_RATE), - (46.9792114695341 / FREQUENCY_RATE), - (47.012912482066 / FREQUENCY_RATE), - (47.0466618808327 / FREQUENCY_RATE), - (47.0804597701149 / FREQUENCY_RATE), - (47.1143062544932 / FREQUENCY_RATE), - (47.1482014388489 / FREQUENCY_RATE), - (47.1821454283657 / FREQUENCY_RATE), - (47.2161383285303 / FREQUENCY_RATE), - (47.2501802451334 / FREQUENCY_RATE), - (47.2842712842713 / FREQUENCY_RATE), - (47.3184115523466 / FREQUENCY_RATE), - (47.3526011560694 / FREQUENCY_RATE), - (47.3868402024584 / FREQUENCY_RATE), - (47.4211287988423 / FREQUENCY_RATE), - (47.4554670528602 / FREQUENCY_RATE), - (47.4898550724638 / FREQUENCY_RATE), - (47.5242929659173 / FREQUENCY_RATE), - (47.5587808417997 / FREQUENCY_RATE), - (47.5933188090051 / FREQUENCY_RATE), - (47.6279069767442 / FREQUENCY_RATE), - (47.6625454545455 / FREQUENCY_RATE), - (47.6972343522562 / FREQUENCY_RATE), - (47.7319737800437 / FREQUENCY_RATE), - (47.7667638483965 / FREQUENCY_RATE), - (47.8016046681255 / FREQUENCY_RATE), - (47.836496350365 / FREQUENCY_RATE), - (47.8714390065741 / FREQUENCY_RATE), - (47.906432748538 / FREQUENCY_RATE), - (47.9414776883687 / FREQUENCY_RATE), - (47.9765739385066 / FREQUENCY_RATE), - (48.0117216117216 / FREQUENCY_RATE), - (48.0469208211144 / FREQUENCY_RATE), - (48.0821716801174 / FREQUENCY_RATE), - (48.1174743024963 / FREQUENCY_RATE), - (48.1528288023512 / FREQUENCY_RATE), - (48.1882352941176 / FREQUENCY_RATE), - (48.2236938925681 / FREQUENCY_RATE), - (48.259204712813 / FREQUENCY_RATE), - (48.2947678703021 / FREQUENCY_RATE), - (48.330383480826 / FREQUENCY_RATE), - (48.3660516605166 / FREQUENCY_RATE), - (48.4017725258493 / FREQUENCY_RATE), - (48.4375461936438 / FREQUENCY_RATE), - (48.4733727810651 / FREQUENCY_RATE), - (48.5092524056255 / FREQUENCY_RATE), - (48.5451851851852 / FREQUENCY_RATE), - (48.581171237954 / FREQUENCY_RATE), - (48.6172106824926 / FREQUENCY_RATE), - (48.6533036377134 / FREQUENCY_RATE), - (48.6894502228826 / FREQUENCY_RATE), - (48.7256505576208 / FREQUENCY_RATE), - (48.7619047619048 / FREQUENCY_RATE), - (48.7982129560685 / FREQUENCY_RATE), - (48.8345752608048 / FREQUENCY_RATE), - (48.8709917971663 / FREQUENCY_RATE), - (48.9074626865672 / FREQUENCY_RATE), - (48.9439880507842 / FREQUENCY_RATE), - (48.9805680119582 / FREQUENCY_RATE), - (49.0172026925954 / FREQUENCY_RATE), - (49.0538922155689 / FREQUENCY_RATE), - (49.0906367041199 / FREQUENCY_RATE), - (49.1274362818591 / FREQUENCY_RATE), - (49.1642910727682 / FREQUENCY_RATE), - (49.2012012012012 / FREQUENCY_RATE), - (49.2381667918858 / FREQUENCY_RATE), - (49.2751879699248 / FREQUENCY_RATE), - (49.3122648607976 / FREQUENCY_RATE), - (49.3493975903615 / FREQUENCY_RATE), - (49.3865862848531 / FREQUENCY_RATE), - (49.4238310708899 / FREQUENCY_RATE), - (49.4611320754717 / FREQUENCY_RATE), - (49.4984894259819 / FREQUENCY_RATE), - (49.535903250189 / FREQUENCY_RATE), - (49.5733736762481 / FREQUENCY_RATE), - (49.6109008327025 / FREQUENCY_RATE), - (49.6484848484849 / FREQUENCY_RATE), - (49.6861258529189 / FREQUENCY_RATE), - (49.7238239757208 / FREQUENCY_RATE), - (49.7615793470008 / FREQUENCY_RATE), - (49.7993920972644 / FREQUENCY_RATE), - (49.8372623574145 / FREQUENCY_RATE), - (49.8751902587519 / FREQUENCY_RATE), - (49.9131759329779 / FREQUENCY_RATE), - (49.9512195121951 / FREQUENCY_RATE), - (49.9893211289092 / FREQUENCY_RATE), - (50.0274809160305 / FREQUENCY_RATE), - (50.0656990068755 / FREQUENCY_RATE), - (50.1039755351682 / FREQUENCY_RATE), - (50.1423106350421 / FREQUENCY_RATE), - (50.1807044410413 / FREQUENCY_RATE), - (50.2191570881226 / FREQUENCY_RATE), - (50.2576687116564 / FREQUENCY_RATE), - (50.296239447429 / FREQUENCY_RATE), - (50.3348694316436 / FREQUENCY_RATE), - (50.3735588009224 / FREQUENCY_RATE), - (50.4123076923077 / FREQUENCY_RATE), - (50.451116243264 / FREQUENCY_RATE), - (50.4899845916795 / FREQUENCY_RATE), - (50.5289128758674 / FREQUENCY_RATE), - (50.5679012345679 / FREQUENCY_RATE), - (50.6069498069498 / FREQUENCY_RATE), - (50.6460587326121 / FREQUENCY_RATE), - (50.6852281515855 / FREQUENCY_RATE), - (50.7244582043344 / FREQUENCY_RATE), - (50.7637490317583 / FREQUENCY_RATE), - (50.8031007751938 / FREQUENCY_RATE), - (50.8425135764158 / FREQUENCY_RATE), - (50.8819875776397 / FREQUENCY_RATE), - (50.9215229215229 / FREQUENCY_RATE), - (50.9611197511664 / FREQUENCY_RATE), - (51.0007782101167 / FREQUENCY_RATE), - (51.0404984423676 / FREQUENCY_RATE), - (51.0802805923617 / FREQUENCY_RATE), - (51.1201248049922 / FREQUENCY_RATE), - (51.160031225605 / FREQUENCY_RATE), - (51.2 / FREQUENCY_RATE), - (51.2400312744331 / FREQUENCY_RATE), - (51.2801251956182 / FREQUENCY_RATE), - (51.3202819107283 / FREQUENCY_RATE), - (51.3605015673981 / FREQUENCY_RATE), - (51.4007843137255 / FREQUENCY_RATE), - (51.4411302982732 / FREQUENCY_RATE), - (51.4815396700707 / FREQUENCY_RATE), - (51.5220125786164 / FREQUENCY_RATE), - (51.5625491738788 / FREQUENCY_RATE), - (51.6031496062992 / FREQUENCY_RATE), - (51.6438140267928 / FREQUENCY_RATE), - (51.6845425867508 / FREQUENCY_RATE), - (51.7253354380426 / FREQUENCY_RATE), - (51.7661927330174 / FREQUENCY_RATE), - (51.8071146245059 / FREQUENCY_RATE), - (51.8481012658228 / FREQUENCY_RATE), - (51.889152810768 / FREQUENCY_RATE), - (51.9302694136292 / FREQUENCY_RATE), - (51.9714512291832 / FREQUENCY_RATE), - (52.0126984126984 / FREQUENCY_RATE), - (52.0540111199365 / FREQUENCY_RATE), - (52.0953895071542 / FREQUENCY_RATE), - (52.1368337311058 / FREQUENCY_RATE), - (52.1783439490446 / FREQUENCY_RATE), - (52.2199203187251 / FREQUENCY_RATE), - (52.2615629984051 / FREQUENCY_RATE), - (52.3032721468476 / FREQUENCY_RATE), - (52.3450479233227 / FREQUENCY_RATE), - (52.3868904876099 / FREQUENCY_RATE), - (52.4288 / FREQUENCY_RATE), - (52.470776621297 / FREQUENCY_RATE), - (52.5128205128205 / FREQUENCY_RATE), - (52.5549318364074 / FREQUENCY_RATE), - (52.5971107544141 / FREQUENCY_RATE), - (52.6393574297189 / FREQUENCY_RATE), - (52.6816720257235 / FREQUENCY_RATE), - (52.7240547063556 / FREQUENCY_RATE), - (52.7665056360709 / FREQUENCY_RATE), - (52.809024979855 / FREQUENCY_RATE), - (52.8516129032258 / FREQUENCY_RATE), - (52.8942695722357 / FREQUENCY_RATE), - (52.9369951534734 / FREQUENCY_RATE), - (52.9797898140663 / FREQUENCY_RATE), - (53.0226537216829 / FREQUENCY_RATE), - (53.0655870445344 / FREQUENCY_RATE), - (53.1085899513776 / FREQUENCY_RATE), - (53.1516626115166 / FREQUENCY_RATE), - (53.1948051948052 / FREQUENCY_RATE), - (53.2380178716491 / FREQUENCY_RATE), - (53.2813008130081 / FREQUENCY_RATE), - (53.3246541903987 / FREQUENCY_RATE), - (53.3680781758958 / FREQUENCY_RATE), - (53.4115729421353 / FREQUENCY_RATE), - (53.4551386623165 / FREQUENCY_RATE), - (53.4987755102041 / FREQUENCY_RATE), - (53.5424836601307 / FREQUENCY_RATE), - (53.5862632869992 / FREQUENCY_RATE), - (53.6301145662848 / FREQUENCY_RATE), - (53.6740376740377 / FREQUENCY_RATE), - (53.7180327868852 / FREQUENCY_RATE), - (53.7621000820345 / FREQUENCY_RATE), - (53.8062397372742 / FREQUENCY_RATE), - (53.8504519309778 / FREQUENCY_RATE), - (53.8947368421053 / FREQUENCY_RATE), - (53.9390946502058 / FREQUENCY_RATE), - (53.9835255354201 / FREQUENCY_RATE), - (54.0280296784831 / FREQUENCY_RATE), - (54.0726072607261 / FREQUENCY_RATE), - (54.1172584640793 / FREQUENCY_RATE), - (54.1619834710744 / FREQUENCY_RATE), - (54.206782464847 / FREQUENCY_RATE), - (54.2516556291391 / FREQUENCY_RATE), - (54.2966031483016 / FREQUENCY_RATE), - (54.3416252072969 / FREQUENCY_RATE), - (54.3867219917012 / FREQUENCY_RATE), - (54.4318936877076 / FREQUENCY_RATE), - (54.477140482128 / FREQUENCY_RATE), - (54.522462562396 / FREQUENCY_RATE), - (54.5678601165695 / FREQUENCY_RATE), - (54.6133333333333 / FREQUENCY_RATE), - (54.6588824020017 / FREQUENCY_RATE), - (54.7045075125209 / FREQUENCY_RATE), - (54.750208855472 / FREQUENCY_RATE), - (54.7959866220736 / FREQUENCY_RATE), - (54.8418410041841 / FREQUENCY_RATE), - (54.8877721943049 / FREQUENCY_RATE), - (54.9337803855826 / FREQUENCY_RATE), - (54.9798657718121 / FREQUENCY_RATE), - (55.0260285474391 / FREQUENCY_RATE), - (55.072268907563 / FREQUENCY_RATE), - (55.1185870479394 / FREQUENCY_RATE), - (55.1649831649832 / FREQUENCY_RATE), - (55.2114574557709 / FREQUENCY_RATE), - (55.2580101180438 / FREQUENCY_RATE), - (55.304641350211 / FREQUENCY_RATE), - (55.3513513513514 / FREQUENCY_RATE), - (55.3981403212172 / FREQUENCY_RATE), - (55.4450084602369 / FREQUENCY_RATE), - (55.4919559695174 / FREQUENCY_RATE), - (55.5389830508475 / FREQUENCY_RATE), - (55.5860899067006 / FREQUENCY_RATE), - (55.6332767402377 / FREQUENCY_RATE), - (55.6805437553101 / FREQUENCY_RATE), - (55.7278911564626 / FREQUENCY_RATE), - (55.7753191489362 / FREQUENCY_RATE), - (55.8228279386712 / FREQUENCY_RATE), - (55.8704177323103 / FREQUENCY_RATE), - (55.9180887372014 / FREQUENCY_RATE), - (55.9658411614005 / FREQUENCY_RATE), - (56.0136752136752 / FREQUENCY_RATE), - (56.0615911035073 / FREQUENCY_RATE), - (56.1095890410959 / FREQUENCY_RATE), - (56.1576692373608 / FREQUENCY_RATE), - (56.2058319039451 / FREQUENCY_RATE), - (56.2540772532189 / FREQUENCY_RATE), - (56.3024054982818 / FREQUENCY_RATE), - (56.3508168529665 / FREQUENCY_RATE), - (56.3993115318417 / FREQUENCY_RATE), - (56.4478897502153 / FREQUENCY_RATE), - (56.4965517241379 / FREQUENCY_RATE), - (56.5452976704055 / FREQUENCY_RATE), - (56.594127806563 / FREQUENCY_RATE), - (56.6430423509075 / FREQUENCY_RATE), - (56.6920415224914 / FREQUENCY_RATE), - (56.7411255411255 / FREQUENCY_RATE), - (56.790294627383 / FREQUENCY_RATE), - (56.8395490026019 / FREQUENCY_RATE), - (56.8888888888889 / FREQUENCY_RATE), - (56.9383145091225 / FREQUENCY_RATE), - (56.9878260869565 / FREQUENCY_RATE), - (57.0374238468233 / FREQUENCY_RATE), - (57.0871080139373 / FREQUENCY_RATE), - (57.1368788142982 / FREQUENCY_RATE), - (57.1867364746946 / FREQUENCY_RATE), - (57.2366812227074 / FREQUENCY_RATE), - (57.2867132867133 / FREQUENCY_RATE), - (57.336832895888 / FREQUENCY_RATE), - (57.3870402802102 / FREQUENCY_RATE), - (57.4373356704645 / FREQUENCY_RATE), - (57.4877192982456 / FREQUENCY_RATE), - (57.5381913959614 / FREQUENCY_RATE), - (57.5887521968366 / FREQUENCY_RATE), - (57.6394019349165 / FREQUENCY_RATE), - (57.6901408450704 / FREQUENCY_RATE), - (57.7409691629956 / FREQUENCY_RATE), - (57.7918871252205 / FREQUENCY_RATE), - (57.8428949691086 / FREQUENCY_RATE), - (57.8939929328622 / FREQUENCY_RATE), - (57.9451812555261 / FREQUENCY_RATE), - (57.9964601769912 / FREQUENCY_RATE), - (58.0478299379982 / FREQUENCY_RATE), - (58.0992907801418 / FREQUENCY_RATE), - (58.150842945874 / FREQUENCY_RATE), - (58.202486678508 / FREQUENCY_RATE), - (58.2542222222222 / FREQUENCY_RATE), - (58.3060498220641 / FREQUENCY_RATE), - (58.3579697239537 / FREQUENCY_RATE), - (58.4099821746881 / FREQUENCY_RATE), - (58.4620874219447 / FREQUENCY_RATE), - (58.5142857142857 / FREQUENCY_RATE), - (58.5665773011618 / FREQUENCY_RATE), - (58.6189624329159 / FREQUENCY_RATE), - (58.6714413607878 / FREQUENCY_RATE), - (58.7240143369176 / FREQUENCY_RATE), - (58.7766816143498 / FREQUENCY_RATE), - (58.8294434470377 / FREQUENCY_RATE), - (58.8823000898473 / FREQUENCY_RATE), - (58.9352517985612 / FREQUENCY_RATE), - (58.988298829883 / FREQUENCY_RATE), - (59.0414414414414 / FREQUENCY_RATE), - (59.0946798917944 / FREQUENCY_RATE), - (59.1480144404332 / FREQUENCY_RATE), - (59.2014453477868 / FREQUENCY_RATE), - (59.254972875226 / FREQUENCY_RATE), - (59.3085972850679 / FREQUENCY_RATE), - (59.3623188405797 / FREQUENCY_RATE), - (59.4161378059837 / FREQUENCY_RATE), - (59.470054446461 / FREQUENCY_RATE), - (59.5240690281562 / FREQUENCY_RATE), - (59.5781818181818 / FREQUENCY_RATE), - (59.6323930846224 / FREQUENCY_RATE), - (59.6867030965392 / FREQUENCY_RATE), - (59.7411121239745 / FREQUENCY_RATE), - (59.7956204379562 / FREQUENCY_RATE), - (59.8502283105023 / FREQUENCY_RATE), - (59.9049360146252 / FREQUENCY_RATE), - (59.9597438243367 / FREQUENCY_RATE), - (60.014652014652 / FREQUENCY_RATE), - (60.0696608615949 / FREQUENCY_RATE), - (60.1247706422018 / FREQUENCY_RATE), - (60.1799816345271 / FREQUENCY_RATE), - (60.2352941176471 / FREQUENCY_RATE), - (60.2907083716651 / FREQUENCY_RATE), - (60.3462246777164 / FREQUENCY_RATE), - (60.4018433179724 / FREQUENCY_RATE), - (60.4575645756458 / FREQUENCY_RATE), - (60.5133887349954 / FREQUENCY_RATE), - (60.5693160813309 / FREQUENCY_RATE), - (60.6253469010176 / FREQUENCY_RATE), - (60.6814814814815 / FREQUENCY_RATE), - (60.7377201112141 / FREQUENCY_RATE), - (60.7940630797774 / FREQUENCY_RATE), - (60.8505106778087 / FREQUENCY_RATE), - (60.907063197026 / FREQUENCY_RATE), - (60.9637209302326 / FREQUENCY_RATE), - (61.0204841713222 / FREQUENCY_RATE), - (61.0773532152843 / FREQUENCY_RATE), - (61.134328358209 / FREQUENCY_RATE), - (61.1914098972923 / FREQUENCY_RATE), - (61.2485981308411 / FREQUENCY_RATE), - (61.3058933582788 / FREQUENCY_RATE), - (61.3632958801498 / FREQUENCY_RATE), - (61.4208059981256 / FREQUENCY_RATE), - (61.4784240150094 / FREQUENCY_RATE), - (61.5361502347418 / FREQUENCY_RATE), - (61.593984962406 / FREQUENCY_RATE), - (61.6519285042333 / FREQUENCY_RATE), - (61.7099811676083 / FREQUENCY_RATE), - (61.7681432610745 / FREQUENCY_RATE), - (61.8264150943396 / FREQUENCY_RATE), - (61.8847969782814 / FREQUENCY_RATE), - (61.9432892249527 / FREQUENCY_RATE), - (62.0018921475875 / FREQUENCY_RATE), - (62.0606060606061 / FREQUENCY_RATE), - (62.1194312796209 / FREQUENCY_RATE), - (62.1783681214421 / FREQUENCY_RATE), - (62.2374169040836 / FREQUENCY_RATE), - (62.2965779467681 / FREQUENCY_RATE), - (62.3558515699334 / FREQUENCY_RATE), - (62.4152380952381 / FREQUENCY_RATE), - (62.4747378455672 / FREQUENCY_RATE), - (62.5343511450382 / FREQUENCY_RATE), - (62.5940783190067 / FREQUENCY_RATE), - (62.6539196940727 / FREQUENCY_RATE), - (62.7138755980861 / FREQUENCY_RATE), - (62.7739463601533 / FREQUENCY_RATE), - (62.8341323106424 / FREQUENCY_RATE), - (62.89443378119 / FREQUENCY_RATE), - (62.954851104707 / FREQUENCY_RATE), - (63.0153846153846 / FREQUENCY_RATE), - (63.0760346487007 / FREQUENCY_RATE), - (63.1368015414258 / FREQUENCY_RATE), - (63.1976856316297 / FREQUENCY_RATE), - (63.2586872586873 / FREQUENCY_RATE), - (63.319806763285 / FREQUENCY_RATE), - (63.3810444874275 / FREQUENCY_RATE), - (63.4424007744434 / FREQUENCY_RATE), - (63.5038759689923 / FREQUENCY_RATE), - (63.5654704170708 / FREQUENCY_RATE), - (63.6271844660194 / FREQUENCY_RATE), - (63.6890184645287 / FREQUENCY_RATE), - (63.7509727626459 / FREQUENCY_RATE), - (63.8130477117819 / FREQUENCY_RATE), - (63.8752436647174 / FREQUENCY_RATE), - (63.9375609756098 / FREQUENCY_RATE), - (64 / FREQUENCY_RATE), - (64.0625610948192 / FREQUENCY_RATE), - (64.1252446183953 / FREQUENCY_RATE), - (64.1880509304603 / FREQUENCY_RATE), - (64.2509803921569 / FREQUENCY_RATE), - (64.3140333660451 / FREQUENCY_RATE), - (64.37721021611 / FREQUENCY_RATE), - (64.440511307768 / FREQUENCY_RATE), - (64.503937007874 / FREQUENCY_RATE), - (64.5674876847291 / FREQUENCY_RATE), - (64.6311637080868 / FREQUENCY_RATE), - (64.6949654491609 / FREQUENCY_RATE), - (64.7588932806324 / FREQUENCY_RATE), - (64.8229475766568 / FREQUENCY_RATE), - (64.8871287128713 / FREQUENCY_RATE), - (64.9514370664024 / FREQUENCY_RATE), - (65.015873015873 / FREQUENCY_RATE), - (65.0804369414101 / FREQUENCY_RATE), - (65.1451292246521 / FREQUENCY_RATE), - (65.2099502487562 / FREQUENCY_RATE), - (65.2749003984064 / FREQUENCY_RATE), - (65.3399800598205 / FREQUENCY_RATE), - (65.4051896207585 / FREQUENCY_RATE), - (65.4705294705295 / FREQUENCY_RATE), - (65.536 / FREQUENCY_RATE), - (65.6016016016016 / FREQUENCY_RATE), - (65.6673346693387 / FREQUENCY_RATE), - (65.7331995987964 / FREQUENCY_RATE), - (65.7991967871486 / FREQUENCY_RATE), - (65.8653266331658 / FREQUENCY_RATE), - (65.9315895372234 / FREQUENCY_RATE), - (65.9979859013092 / FREQUENCY_RATE), - (66.0645161290323 / FREQUENCY_RATE), - (66.1311806256307 / FREQUENCY_RATE), - (66.1979797979798 / FREQUENCY_RATE), - (66.2649140546006 / FREQUENCY_RATE), - (66.331983805668 / FREQUENCY_RATE), - (66.3991894630193 / FREQUENCY_RATE), - (66.4665314401623 / FREQUENCY_RATE), - (66.5340101522843 / FREQUENCY_RATE), - (66.6016260162602 / FREQUENCY_RATE), - (66.6693794506612 / FREQUENCY_RATE), - (66.7372708757637 / FREQUENCY_RATE), - (66.8053007135576 / FREQUENCY_RATE), - (66.8734693877551 / FREQUENCY_RATE), - (66.9417773237998 / FREQUENCY_RATE), - (67.0102249488753 / FREQUENCY_RATE), - (67.078812691914 / FREQUENCY_RATE), - (67.1475409836066 / FREQUENCY_RATE), - (67.2164102564103 / FREQUENCY_RATE), - (67.2854209445585 / FREQUENCY_RATE), - (67.3545734840699 / FREQUENCY_RATE), - (67.4238683127572 / FREQUENCY_RATE), - (67.4933058702369 / FREQUENCY_RATE), - (67.5628865979382 / FREQUENCY_RATE), - (67.6326109391125 / FREQUENCY_RATE), - (67.702479338843 / FREQUENCY_RATE), - (67.7724922440538 / FREQUENCY_RATE), - (67.8426501035197 / FREQUENCY_RATE), - (67.9129533678757 / FREQUENCY_RATE), - (67.9834024896266 / FREQUENCY_RATE), - (68.0539979231568 / FREQUENCY_RATE), - (68.1247401247401 / FREQUENCY_RATE), - (68.1956295525494 / FREQUENCY_RATE), - (68.2666666666667 / FREQUENCY_RATE), - (68.3378519290928 / FREQUENCY_RATE), - (68.4091858037578 / FREQUENCY_RATE), - (68.4806687565308 / FREQUENCY_RATE), - (68.5523012552301 / FREQUENCY_RATE), - (68.6240837696335 / FREQUENCY_RATE), - (68.6960167714885 / FREQUENCY_RATE), - (68.7681007345226 / FREQUENCY_RATE), - (68.8403361344538 / FREQUENCY_RATE), - (68.9127234490011 / FREQUENCY_RATE), - (68.9852631578947 / FREQUENCY_RATE), - (69.0579557428872 / FREQUENCY_RATE), - (69.1308016877637 / FREQUENCY_RATE), - (69.2038014783527 / FREQUENCY_RATE), - (69.276955602537 / FREQUENCY_RATE), - (69.3502645502646 / FREQUENCY_RATE), - (69.4237288135593 / FREQUENCY_RATE), - (69.4973488865324 / FREQUENCY_RATE), - (69.5711252653928 / FREQUENCY_RATE), - (69.6450584484591 / FREQUENCY_RATE), - (69.7191489361702 / FREQUENCY_RATE), - (69.7933972310969 / FREQUENCY_RATE), - (69.8678038379531 / FREQUENCY_RATE), - (69.9423692636073 / FREQUENCY_RATE), - (70.017094017094 / FREQUENCY_RATE), - (70.0919786096257 / FREQUENCY_RATE), - (70.1670235546039 / FREQUENCY_RATE), - (70.2422293676313 / FREQUENCY_RATE), - (70.3175965665236 / FREQUENCY_RATE), - (70.3931256713212 / FREQUENCY_RATE), - (70.4688172043011 / FREQUENCY_RATE), - (70.5446716899892 / FREQUENCY_RATE), - (70.6206896551724 / FREQUENCY_RATE), - (70.6968716289105 / FREQUENCY_RATE), - (70.7732181425486 / FREQUENCY_RATE), - (70.8497297297297 / FREQUENCY_RATE), - (70.9264069264069 / FREQUENCY_RATE), - (71.0032502708559 / FREQUENCY_RATE), - (71.0802603036876 / FREQUENCY_RATE), - (71.157437567861 / FREQUENCY_RATE), - (71.2347826086957 / FREQUENCY_RATE), - (71.3122959738847 / FREQUENCY_RATE), - (71.3899782135076 / FREQUENCY_RATE), - (71.4678298800436 / FREQUENCY_RATE), - (71.5458515283843 / FREQUENCY_RATE), - (71.624043715847 / FREQUENCY_RATE), - (71.7024070021882 / FREQUENCY_RATE), - (71.7809419496166 / FREQUENCY_RATE), - (71.859649122807 / FREQUENCY_RATE), - (71.9385290889133 / FREQUENCY_RATE), - (72.0175824175824 / FREQUENCY_RATE), - (72.0968096809681 / FREQUENCY_RATE), - (72.1762114537445 / FREQUENCY_RATE), - (72.2557883131202 / FREQUENCY_RATE), - (72.3355408388521 / FREQUENCY_RATE), - (72.4154696132597 / FREQUENCY_RATE), - (72.4955752212389 / FREQUENCY_RATE), - (72.5758582502769 / FREQUENCY_RATE), - (72.6563192904656 / FREQUENCY_RATE), - (72.7369589345172 / FREQUENCY_RATE), - (72.8177777777778 / FREQUENCY_RATE), - (72.8987764182425 / FREQUENCY_RATE), - (72.9799554565702 / FREQUENCY_RATE), - (73.0613154960981 / FREQUENCY_RATE), - (73.1428571428571 / FREQUENCY_RATE), - (73.2245810055866 / FREQUENCY_RATE), - (73.3064876957494 / FREQUENCY_RATE), - (73.3885778275476 / FREQUENCY_RATE), - (73.4708520179372 / FREQUENCY_RATE), - (73.5533108866442 / FREQUENCY_RATE), - (73.6359550561798 / FREQUENCY_RATE), - (73.718785151856 / FREQUENCY_RATE), - (73.8018018018018 / FREQUENCY_RATE), - (73.8850056369786 / FREQUENCY_RATE), - (73.9683972911964 / FREQUENCY_RATE), - (74.0519774011299 / FREQUENCY_RATE), - (74.1357466063348 / FREQUENCY_RATE), - (74.2197055492639 / FREQUENCY_RATE), - (74.3038548752835 / FREQUENCY_RATE), - (74.3881952326901 / FREQUENCY_RATE), - (74.4727272727273 / FREQUENCY_RATE), - (74.5574516496018 / FREQUENCY_RATE), - (74.6423690205011 / FREQUENCY_RATE), - (74.72748004561 / FREQUENCY_RATE), - (74.8127853881279 / FREQUENCY_RATE), - (74.8982857142857 / FREQUENCY_RATE), - (74.9839816933639 / FREQUENCY_RATE), - (75.0698739977091 / FREQUENCY_RATE), - (75.1559633027523 / FREQUENCY_RATE), - (75.2422502870264 / FREQUENCY_RATE), - (75.3287356321839 / FREQUENCY_RATE), - (75.415420023015 / FREQUENCY_RATE), - (75.5023041474654 / FREQUENCY_RATE), - (75.5893886966551 / FREQUENCY_RATE), - (75.6766743648961 / FREQUENCY_RATE), - (75.764161849711 / FREQUENCY_RATE), - (75.8518518518518 / FREQUENCY_RATE), - (75.9397450753187 / FREQUENCY_RATE), - (76.0278422273782 / FREQUENCY_RATE), - (76.116144018583 / FREQUENCY_RATE), - (76.2046511627907 / FREQUENCY_RATE), - (76.2933643771828 / FREQUENCY_RATE), - (76.3822843822844 / FREQUENCY_RATE), - (76.4714119019837 / FREQUENCY_RATE), - (76.5607476635514 / FREQUENCY_RATE), - (76.6502923976608 / FREQUENCY_RATE), - (76.7400468384075 / FREQUENCY_RATE), - (76.8300117233294 / FREQUENCY_RATE), - (76.9201877934272 / FREQUENCY_RATE), - (77.0105757931845 / FREQUENCY_RATE), - (77.1011764705882 / FREQUENCY_RATE), - (77.1919905771496 / FREQUENCY_RATE), - (77.2830188679245 / FREQUENCY_RATE), - (77.3742621015348 / FREQUENCY_RATE), - (77.4657210401891 / FREQUENCY_RATE), - (77.5573964497041 / FREQUENCY_RATE), - (77.6492890995261 / FREQUENCY_RATE), - (77.7413997627521 / FREQUENCY_RATE), - (77.833729216152 / FREQUENCY_RATE), - (77.9262782401902 / FREQUENCY_RATE), - (78.0190476190476 / FREQUENCY_RATE), - (78.1120381406436 / FREQUENCY_RATE), - (78.2052505966587 / FREQUENCY_RATE), - (78.2986857825568 / FREQUENCY_RATE), - (78.3923444976077 / FREQUENCY_RATE), - (78.4862275449102 / FREQUENCY_RATE), - (78.5803357314149 / FREQUENCY_RATE), - (78.6746698679472 / FREQUENCY_RATE), - (78.7692307692308 / FREQUENCY_RATE), - (78.864019253911 / FREQUENCY_RATE), - (78.9590361445783 / FREQUENCY_RATE), - (79.0542822677925 / FREQUENCY_RATE), - (79.1497584541063 / FREQUENCY_RATE), - (79.2454655380895 / FREQUENCY_RATE), - (79.3414043583535 / FREQUENCY_RATE), - (79.4375757575758 / FREQUENCY_RATE), - (79.5339805825243 / FREQUENCY_RATE), - (79.6306196840826 / FREQUENCY_RATE), - (79.7274939172749 / FREQUENCY_RATE), - (79.8246041412911 / FREQUENCY_RATE), - (79.9219512195122 / FREQUENCY_RATE), - (80.019536019536 / FREQUENCY_RATE), - (80.1173594132029 / FREQUENCY_RATE), - (80.2154222766218 / FREQUENCY_RATE), - (80.3137254901961 / FREQUENCY_RATE), - (80.4122699386503 / FREQUENCY_RATE), - (80.5110565110565 / FREQUENCY_RATE), - (80.610086100861 / FREQUENCY_RATE), - (80.7093596059113 / FREQUENCY_RATE), - (80.8088779284834 / FREQUENCY_RATE), - (80.9086419753086 / FREQUENCY_RATE), - (81.008652657602 / FREQUENCY_RATE), - (81.1089108910891 / FREQUENCY_RATE), - (81.2094175960347 / FREQUENCY_RATE), - (81.3101736972705 / FREQUENCY_RATE), - (81.4111801242236 / FREQUENCY_RATE), - (81.5124378109453 / FREQUENCY_RATE), - (81.6139476961395 / FREQUENCY_RATE), - (81.715710723192 / FREQUENCY_RATE), - (81.8177278401998 / FREQUENCY_RATE), - (81.92 / FREQUENCY_RATE), - (82.0225281602002 / FREQUENCY_RATE), - (82.125313283208 / FREQUENCY_RATE), - (82.228356336261 / FREQUENCY_RATE), - (82.3316582914573 / FREQUENCY_RATE), - (82.4352201257862 / FREQUENCY_RATE), - (82.5390428211587 / FREQUENCY_RATE), - (82.6431273644388 / FREQUENCY_RATE), - (82.7474747474748 / FREQUENCY_RATE), - (82.8520859671302 / FREQUENCY_RATE), - (82.9569620253165 / FREQUENCY_RATE), - (83.0621039290241 / FREQUENCY_RATE), - (83.1675126903553 / FREQUENCY_RATE), - (83.2731893265565 / FREQUENCY_RATE), - (83.3791348600509 / FREQUENCY_RATE), - (83.4853503184713 / FREQUENCY_RATE), - (83.5918367346939 / FREQUENCY_RATE), - (83.698595146871 / FREQUENCY_RATE), - (83.8056265984655 / FREQUENCY_RATE), - (83.9129321382842 / FREQUENCY_RATE), - (84.0205128205128 / FREQUENCY_RATE), - (84.1283697047497 / FREQUENCY_RATE), - (84.2365038560411 / FREQUENCY_RATE), - (84.3449163449163 / FREQUENCY_RATE), - (84.4536082474227 / FREQUENCY_RATE), - (84.5625806451613 / FREQUENCY_RATE), - (84.671834625323 / FREQUENCY_RATE), - (84.7813712807245 / FREQUENCY_RATE), - (84.8911917098446 / FREQUENCY_RATE), - (85.0012970168612 / FREQUENCY_RATE), - (85.1116883116883 / FREQUENCY_RATE), - (85.222366710013 / FREQUENCY_RATE), - (85.3333333333333 / FREQUENCY_RATE), - (85.4445893089961 / FREQUENCY_RATE), - (85.556135770235 / FREQUENCY_RATE), - (85.6679738562091 / FREQUENCY_RATE), - (85.7801047120419 / FREQUENCY_RATE), - (85.8925294888598 / FREQUENCY_RATE), - (86.005249343832 / FREQUENCY_RATE), - (86.1182654402102 / FREQUENCY_RATE), - (86.2315789473684 / FREQUENCY_RATE), - (86.3451910408432 / FREQUENCY_RATE), - (86.4591029023747 / FREQUENCY_RATE), - (86.5733157199472 / FREQUENCY_RATE), - (86.6878306878307 / FREQUENCY_RATE), - (86.8026490066225 / FREQUENCY_RATE), - (86.9177718832891 / FREQUENCY_RATE), - (87.0332005312085 / FREQUENCY_RATE), - (87.1489361702128 / FREQUENCY_RATE), - (87.2649800266312 / FREQUENCY_RATE), - (87.3813333333333 / FREQUENCY_RATE), - (87.497997329773 / FREQUENCY_RATE), - (87.6149732620321 / FREQUENCY_RATE), - (87.7322623828648 / FREQUENCY_RATE), - (87.8498659517426 / FREQUENCY_RATE), - (87.9677852348993 / FREQUENCY_RATE), - (88.0860215053763 / FREQUENCY_RATE), - (88.2045760430686 / FREQUENCY_RATE), - (88.3234501347709 / FREQUENCY_RATE), - (88.442645074224 / FREQUENCY_RATE), - (88.5621621621622 / FREQUENCY_RATE), - (88.68200270636 / FREQUENCY_RATE), - (88.8021680216802 / FREQUENCY_RATE), - (88.9226594301221 / FREQUENCY_RATE), - (89.0434782608696 / FREQUENCY_RATE), - (89.1646258503401 / FREQUENCY_RATE), - (89.2861035422343 / FREQUENCY_RATE), - (89.4079126875853 / FREQUENCY_RATE), - (89.5300546448087 / FREQUENCY_RATE), - (89.6525307797538 / FREQUENCY_RATE), - (89.7753424657534 / FREQUENCY_RATE), - (89.8984910836763 / FREQUENCY_RATE), - (90.021978021978 / FREQUENCY_RATE), - (90.1458046767538 / FREQUENCY_RATE), - (90.2699724517906 / FREQUENCY_RATE), - (90.3944827586207 / FREQUENCY_RATE), - (90.5193370165746 / FREQUENCY_RATE), - (90.6445366528354 / FREQUENCY_RATE), - (90.7700831024931 / FREQUENCY_RATE), - (90.8959778085992 / FREQUENCY_RATE), - (91.0222222222222 / FREQUENCY_RATE), - (91.1488178025035 / FREQUENCY_RATE), - (91.2757660167131 / FREQUENCY_RATE), - (91.4030683403068 / FREQUENCY_RATE), - (91.5307262569833 / FREQUENCY_RATE), - (91.6587412587413 / FREQUENCY_RATE), - (91.7871148459384 / FREQUENCY_RATE), - (91.9158485273492 / FREQUENCY_RATE), - (92.0449438202247 / FREQUENCY_RATE), - (92.1744022503516 / FREQUENCY_RATE), - (92.3042253521127 / FREQUENCY_RATE), - (92.4344146685472 / FREQUENCY_RATE), - (92.5649717514124 / FREQUENCY_RATE), - (92.6958981612447 / FREQUENCY_RATE), - (92.8271954674221 / FREQUENCY_RATE), - (92.958865248227 / FREQUENCY_RATE), - (93.0909090909091 / FREQUENCY_RATE), - (93.2233285917497 / FREQUENCY_RATE), - (93.3561253561254 / FREQUENCY_RATE), - (93.4893009985735 / FREQUENCY_RATE), - (93.6228571428572 / FREQUENCY_RATE), - (93.7567954220315 / FREQUENCY_RATE), - (93.89111747851 / FREQUENCY_RATE), - (94.025824964132 / FREQUENCY_RATE), - (94.1609195402299 / FREQUENCY_RATE), - (94.2964028776978 / FREQUENCY_RATE), - (94.4322766570605 / FREQUENCY_RATE), - (94.5685425685426 / FREQUENCY_RATE), - (94.7052023121387 / FREQUENCY_RATE), - (94.8422575976845 / FREQUENCY_RATE), - (94.9797101449275 / FREQUENCY_RATE), - (95.1175616835994 / FREQUENCY_RATE), - (95.2558139534884 / FREQUENCY_RATE), - (95.3944687045124 / FREQUENCY_RATE), - (95.533527696793 / FREQUENCY_RATE), - (95.6729927007299 / FREQUENCY_RATE), - (95.812865497076 / FREQUENCY_RATE), - (95.9531478770132 / FREQUENCY_RATE), - (96.0938416422287 / FREQUENCY_RATE), - (96.2349486049927 / FREQUENCY_RATE), - (96.3764705882353 / FREQUENCY_RATE), - (96.5184094256259 / FREQUENCY_RATE), - (96.6607669616519 / FREQUENCY_RATE), - (96.8035450516987 / FREQUENCY_RATE), - (96.9467455621302 / FREQUENCY_RATE), - (97.0903703703704 / FREQUENCY_RATE), - (97.2344213649852 / FREQUENCY_RATE), - (97.3789004457652 / FREQUENCY_RATE), - (97.5238095238095 / FREQUENCY_RATE), - (97.6691505216095 / FREQUENCY_RATE), - (97.8149253731343 / FREQUENCY_RATE), - (97.9611360239163 / FREQUENCY_RATE), - (98.1077844311377 / FREQUENCY_RATE), - (98.2548725637181 / FREQUENCY_RATE), - (98.4024024024024 / FREQUENCY_RATE), - (98.5503759398496 / FREQUENCY_RATE), - (98.6987951807229 / FREQUENCY_RATE), - (98.8476621417798 / FREQUENCY_RATE), - (98.9969788519637 / FREQUENCY_RATE), - (99.1467473524962 / FREQUENCY_RATE), - (99.2969696969697 / FREQUENCY_RATE), - (99.4476479514416 / FREQUENCY_RATE), - (99.5987841945289 / FREQUENCY_RATE), - (99.7503805175038 / FREQUENCY_RATE), - (99.9024390243902 / FREQUENCY_RATE), - (100.054961832061 / FREQUENCY_RATE), - (100.207951070336 / FREQUENCY_RATE), - (100.361408882083 / FREQUENCY_RATE), - (100.515337423313 / FREQUENCY_RATE), - (100.669738863287 / FREQUENCY_RATE), - (100.824615384615 / FREQUENCY_RATE), - (100.979969183359 / FREQUENCY_RATE), - (101.135802469136 / FREQUENCY_RATE), - (101.292117465224 / FREQUENCY_RATE), - (101.448916408669 / FREQUENCY_RATE), - (101.606201550388 / FREQUENCY_RATE), - (101.76397515528 / FREQUENCY_RATE), - (101.922239502333 / FREQUENCY_RATE), - (102.080996884735 / FREQUENCY_RATE), - (102.240249609984 / FREQUENCY_RATE), - (102.4 / FREQUENCY_RATE), - (102.560250391236 / FREQUENCY_RATE), - (102.721003134796 / FREQUENCY_RATE), - (102.882260596546 / FREQUENCY_RATE), - (103.044025157233 / FREQUENCY_RATE), - (103.206299212598 / FREQUENCY_RATE), - (103.369085173502 / FREQUENCY_RATE), - (103.532385466035 / FREQUENCY_RATE), - (103.696202531646 / FREQUENCY_RATE), - (103.860538827258 / FREQUENCY_RATE), - (104.025396825397 / FREQUENCY_RATE), - (104.190779014308 / FREQUENCY_RATE), - (104.356687898089 / FREQUENCY_RATE), - (104.52312599681 / FREQUENCY_RATE), - (104.690095846645 / FREQUENCY_RATE), - (104.8576 / FREQUENCY_RATE), - (105.025641025641 / FREQUENCY_RATE), - (105.194221508828 / FREQUENCY_RATE), - (105.363344051447 / FREQUENCY_RATE), - (105.533011272142 / FREQUENCY_RATE), - (105.703225806452 / FREQUENCY_RATE), - (105.873990306947 / FREQUENCY_RATE), - (106.045307443366 / FREQUENCY_RATE), - (106.217179902755 / FREQUENCY_RATE), - (106.38961038961 / FREQUENCY_RATE), - (106.562601626016 / FREQUENCY_RATE), - (106.736156351792 / FREQUENCY_RATE), - (106.910277324633 / FREQUENCY_RATE), - (107.084967320261 / FREQUENCY_RATE), - (107.26022913257 / FREQUENCY_RATE), - (107.436065573771 / FREQUENCY_RATE), - (107.612479474548 / FREQUENCY_RATE), - (107.789473684211 / FREQUENCY_RATE), - (107.96705107084 / FREQUENCY_RATE), - (108.145214521452 / FREQUENCY_RATE), - (108.323966942149 / FREQUENCY_RATE), - (108.503311258278 / FREQUENCY_RATE), - (108.683250414594 / FREQUENCY_RATE), - (108.863787375415 / FREQUENCY_RATE), - (109.044925124792 / FREQUENCY_RATE), - (109.226666666667 / FREQUENCY_RATE), - (109.409015025042 / FREQUENCY_RATE), - (109.591973244147 / FREQUENCY_RATE), - (109.77554438861 / FREQUENCY_RATE), - (109.959731543624 / FREQUENCY_RATE), - (110.144537815126 / FREQUENCY_RATE), - (110.329966329966 / FREQUENCY_RATE), - (110.516020236088 / FREQUENCY_RATE), - (110.702702702703 / FREQUENCY_RATE), - (110.890016920474 / FREQUENCY_RATE), - (111.077966101695 / FREQUENCY_RATE), - (111.266553480475 / FREQUENCY_RATE), - (111.455782312925 / FREQUENCY_RATE), - (111.645655877342 / FREQUENCY_RATE), - (111.836177474403 / FREQUENCY_RATE), - (112.02735042735 / FREQUENCY_RATE), - (112.219178082192 / FREQUENCY_RATE), - (112.41166380789 / FREQUENCY_RATE), - (112.604810996564 / FREQUENCY_RATE), - (112.798623063683 / FREQUENCY_RATE), - (112.993103448276 / FREQUENCY_RATE), - (113.188255613126 / FREQUENCY_RATE), - (113.384083044983 / FREQUENCY_RATE), - (113.580589254766 / FREQUENCY_RATE), - (113.777777777778 / FREQUENCY_RATE), - (113.975652173913 / FREQUENCY_RATE), - (114.174216027875 / FREQUENCY_RATE), - (114.373472949389 / FREQUENCY_RATE), - (114.573426573427 / FREQUENCY_RATE), - (114.77408056042 / FREQUENCY_RATE), - (114.975438596491 / FREQUENCY_RATE), - (115.177504393673 / FREQUENCY_RATE), - (115.380281690141 / FREQUENCY_RATE), - (115.583774250441 / FREQUENCY_RATE), - (115.787985865724 / FREQUENCY_RATE), - (115.992920353982 / FREQUENCY_RATE), - (116.198581560284 / FREQUENCY_RATE), - (116.404973357016 / FREQUENCY_RATE), - (116.612099644128 / FREQUENCY_RATE), - (116.819964349376 / FREQUENCY_RATE), - (117.028571428571 / FREQUENCY_RATE), - (117.237924865832 / FREQUENCY_RATE), - (117.448028673835 / FREQUENCY_RATE), - (117.658886894075 / FREQUENCY_RATE), - (117.870503597122 / FREQUENCY_RATE), - (118.082882882883 / FREQUENCY_RATE), - (118.296028880866 / FREQUENCY_RATE), - (118.509945750452 / FREQUENCY_RATE), - (118.724637681159 / FREQUENCY_RATE), - (118.940108892922 / FREQUENCY_RATE), - (119.156363636364 / FREQUENCY_RATE), - (119.373406193078 / FREQUENCY_RATE), - (119.591240875912 / FREQUENCY_RATE), - (119.80987202925 / FREQUENCY_RATE), - (120.029304029304 / FREQUENCY_RATE), - (120.249541284404 / FREQUENCY_RATE), - (120.470588235294 / FREQUENCY_RATE), - (120.692449355433 / FREQUENCY_RATE), - (120.915129151292 / FREQUENCY_RATE), - (121.138632162662 / FREQUENCY_RATE), - (121.362962962963 / FREQUENCY_RATE), - (121.588126159555 / FREQUENCY_RATE), - (121.814126394052 / FREQUENCY_RATE), - (122.040968342644 / FREQUENCY_RATE), - (122.268656716418 / FREQUENCY_RATE), - (122.497196261682 / FREQUENCY_RATE), - (122.7265917603 / FREQUENCY_RATE), - (122.956848030019 / FREQUENCY_RATE), - (123.187969924812 / FREQUENCY_RATE), - (123.419962335217 / FREQUENCY_RATE), - (123.652830188679 / FREQUENCY_RATE), - (123.886578449906 / FREQUENCY_RATE), - (124.121212121212 / FREQUENCY_RATE), - (124.356736242884 / FREQUENCY_RATE), - (124.593155893536 / FREQUENCY_RATE), - (124.830476190476 / FREQUENCY_RATE), - (125.068702290076 / FREQUENCY_RATE), - (125.307839388145 / FREQUENCY_RATE), - (125.547892720307 / FREQUENCY_RATE), - (125.78886756238 / FREQUENCY_RATE), - (126.030769230769 / FREQUENCY_RATE), - (126.273603082852 / FREQUENCY_RATE), - (126.517374517375 / FREQUENCY_RATE), - (126.762088974855 / FREQUENCY_RATE), - (127.007751937985 / FREQUENCY_RATE), - (127.254368932039 / FREQUENCY_RATE), - (127.501945525292 / FREQUENCY_RATE), - (127.750487329435 / FREQUENCY_RATE), - (128 / FREQUENCY_RATE), - (128.250489236791 / FREQUENCY_RATE), - (128.501960784314 / FREQUENCY_RATE), - (128.75442043222 / FREQUENCY_RATE), - (129.007874015748 / FREQUENCY_RATE), - (129.262327416174 / FREQUENCY_RATE), - (129.517786561265 / FREQUENCY_RATE), - (129.774257425743 / FREQUENCY_RATE), - (130.031746031746 / FREQUENCY_RATE), - (130.290258449304 / FREQUENCY_RATE), - (130.549800796813 / FREQUENCY_RATE), - (130.810379241517 / FREQUENCY_RATE), - (131.072 / FREQUENCY_RATE), - (131.334669338677 / FREQUENCY_RATE), - (131.598393574297 / FREQUENCY_RATE), - (131.863179074447 / FREQUENCY_RATE), - (132.129032258065 / FREQUENCY_RATE), - (132.39595959596 / FREQUENCY_RATE), - (132.663967611336 / FREQUENCY_RATE), - (132.933062880325 / FREQUENCY_RATE), - (133.20325203252 / FREQUENCY_RATE), - (133.474541751527 / FREQUENCY_RATE), - (133.74693877551 / FREQUENCY_RATE), - (134.020449897751 / FREQUENCY_RATE), - (134.295081967213 / FREQUENCY_RATE), - (134.570841889117 / FREQUENCY_RATE), - (134.847736625514 / FREQUENCY_RATE), - (135.125773195876 / FREQUENCY_RATE), - (135.404958677686 / FREQUENCY_RATE), - (135.685300207039 / FREQUENCY_RATE), - (135.966804979253 / FREQUENCY_RATE), - (136.24948024948 / FREQUENCY_RATE), - (136.533333333333 / FREQUENCY_RATE), - (136.818371607516 / FREQUENCY_RATE), - (137.10460251046 / FREQUENCY_RATE), - (137.392033542977 / FREQUENCY_RATE), - (137.680672268908 / FREQUENCY_RATE), - (137.970526315789 / FREQUENCY_RATE), - (138.261603375527 / FREQUENCY_RATE), - (138.553911205074 / FREQUENCY_RATE), - (138.847457627119 / FREQUENCY_RATE), - (139.142250530786 / FREQUENCY_RATE), - (139.43829787234 / FREQUENCY_RATE), - (139.735607675906 / FREQUENCY_RATE), - (140.034188034188 / FREQUENCY_RATE), - (140.334047109208 / FREQUENCY_RATE), - (140.635193133047 / FREQUENCY_RATE), - (140.937634408602 / FREQUENCY_RATE), - (141.241379310345 / FREQUENCY_RATE), - (141.546436285097 / FREQUENCY_RATE), - (141.852813852814 / FREQUENCY_RATE), - (142.160520607375 / FREQUENCY_RATE), - (142.469565217391 / FREQUENCY_RATE), - (142.779956427015 / FREQUENCY_RATE), - (143.091703056769 / FREQUENCY_RATE), - (143.404814004376 / FREQUENCY_RATE), - (143.719298245614 / FREQUENCY_RATE), - (144.035164835165 / FREQUENCY_RATE), - (144.352422907489 / FREQUENCY_RATE), - (144.671081677704 / FREQUENCY_RATE), - (144.991150442478 / FREQUENCY_RATE), - (145.312638580931 / FREQUENCY_RATE), - (145.635555555556 / FREQUENCY_RATE), - (145.95991091314 / FREQUENCY_RATE), - (146.285714285714 / FREQUENCY_RATE), - (146.612975391499 / FREQUENCY_RATE), - (146.941704035874 / FREQUENCY_RATE), - (147.27191011236 / FREQUENCY_RATE), - (147.603603603604 / FREQUENCY_RATE), - (147.936794582393 / FREQUENCY_RATE), - (148.27149321267 / FREQUENCY_RATE), - (148.607709750567 / FREQUENCY_RATE), - (148.945454545455 / FREQUENCY_RATE), - (149.284738041002 / FREQUENCY_RATE), - (149.625570776256 / FREQUENCY_RATE), - (149.967963386728 / FREQUENCY_RATE), - (150.311926605505 / FREQUENCY_RATE), - (150.657471264368 / FREQUENCY_RATE), - (151.004608294931 / FREQUENCY_RATE), - (151.353348729792 / FREQUENCY_RATE), - (151.703703703704 / FREQUENCY_RATE), - (152.055684454756 / FREQUENCY_RATE), - (152.409302325581 / FREQUENCY_RATE), - (152.764568764569 / FREQUENCY_RATE), - (153.121495327103 / FREQUENCY_RATE), - (153.480093676815 / FREQUENCY_RATE), - (153.840375586854 / FREQUENCY_RATE), - (154.202352941176 / FREQUENCY_RATE), - (154.566037735849 / FREQUENCY_RATE), - (154.931442080378 / FREQUENCY_RATE), - (155.298578199052 / FREQUENCY_RATE), - (155.667458432304 / FREQUENCY_RATE), - (156.038095238095 / FREQUENCY_RATE), - (156.410501193317 / FREQUENCY_RATE), - (156.784688995215 / FREQUENCY_RATE), - (157.16067146283 / FREQUENCY_RATE), - (157.538461538462 / FREQUENCY_RATE), - (157.918072289157 / FREQUENCY_RATE), - (158.299516908213 / FREQUENCY_RATE), - (158.682808716707 / FREQUENCY_RATE), - (159.067961165049 / FREQUENCY_RATE), - (159.45498783455 / FREQUENCY_RATE), - (159.843902439024 / FREQUENCY_RATE), - (160.234718826406 / FREQUENCY_RATE), - (160.627450980392 / FREQUENCY_RATE), - (161.022113022113 / FREQUENCY_RATE), - (161.418719211823 / FREQUENCY_RATE), - (161.817283950617 / FREQUENCY_RATE), - (162.217821782178 / FREQUENCY_RATE), - (162.620347394541 / FREQUENCY_RATE), - (163.024875621891 / FREQUENCY_RATE), - (163.431421446384 / FREQUENCY_RATE), - (163.84 / FREQUENCY_RATE), - (164.250626566416 / FREQUENCY_RATE), - (164.663316582915 / FREQUENCY_RATE), - (165.078085642317 / FREQUENCY_RATE), - (165.49494949495 / FREQUENCY_RATE), - (165.913924050633 / FREQUENCY_RATE), - (166.335025380711 / FREQUENCY_RATE), - (166.758269720102 / FREQUENCY_RATE), - (167.183673469388 / FREQUENCY_RATE), - (167.611253196931 / FREQUENCY_RATE), - (168.041025641026 / FREQUENCY_RATE), - (168.473007712082 / FREQUENCY_RATE), - (168.907216494845 / FREQUENCY_RATE), - (169.343669250646 / FREQUENCY_RATE), - (169.782383419689 / FREQUENCY_RATE), - (170.223376623377 / FREQUENCY_RATE), - (170.666666666667 / FREQUENCY_RATE), - (171.11227154047 / FREQUENCY_RATE), - (171.560209424084 / FREQUENCY_RATE), - (172.010498687664 / FREQUENCY_RATE), - (172.463157894737 / FREQUENCY_RATE), - (172.918205804749 / FREQUENCY_RATE), - (173.375661375661 / FREQUENCY_RATE), - (173.835543766578 / FREQUENCY_RATE), - (174.297872340426 / FREQUENCY_RATE), - (174.762666666667 / FREQUENCY_RATE), - (175.229946524064 / FREQUENCY_RATE), - (175.699731903485 / FREQUENCY_RATE), - (176.172043010753 / FREQUENCY_RATE), - (176.646900269542 / FREQUENCY_RATE), - (177.124324324324 / FREQUENCY_RATE), - (177.60433604336 / FREQUENCY_RATE), - (178.086956521739 / FREQUENCY_RATE), - (178.572207084469 / FREQUENCY_RATE), - (179.060109289618 / FREQUENCY_RATE), - (179.550684931507 / FREQUENCY_RATE), - (180.043956043956 / FREQUENCY_RATE), - (180.539944903581 / FREQUENCY_RATE), - (181.038674033149 / FREQUENCY_RATE), - (181.540166204986 / FREQUENCY_RATE), - (182.044444444444 / FREQUENCY_RATE), - (182.551532033426 / FREQUENCY_RATE), - (183.061452513966 / FREQUENCY_RATE), - (183.574229691877 / FREQUENCY_RATE), - (184.089887640449 / FREQUENCY_RATE), - (184.608450704225 / FREQUENCY_RATE), - (185.129943502825 / FREQUENCY_RATE), - (185.654390934844 / FREQUENCY_RATE), - (186.181818181818 / FREQUENCY_RATE), - (186.712250712251 / FREQUENCY_RATE), - (187.245714285714 / FREQUENCY_RATE), - (187.78223495702 / FREQUENCY_RATE), - (188.32183908046 / FREQUENCY_RATE), - (188.864553314121 / FREQUENCY_RATE), - (189.410404624277 / FREQUENCY_RATE), - (189.959420289855 / FREQUENCY_RATE), - (190.511627906977 / FREQUENCY_RATE), - (191.067055393586 / FREQUENCY_RATE), - (191.625730994152 / FREQUENCY_RATE), - (192.187683284457 / FREQUENCY_RATE), - (192.752941176471 / FREQUENCY_RATE), - (193.321533923304 / FREQUENCY_RATE), - (193.89349112426 / FREQUENCY_RATE), - (194.46884272997 / FREQUENCY_RATE), - (195.047619047619 / FREQUENCY_RATE), - (195.629850746269 / FREQUENCY_RATE), - (196.215568862275 / FREQUENCY_RATE), - (196.804804804805 / FREQUENCY_RATE), - (197.397590361446 / FREQUENCY_RATE), - (197.993957703928 / FREQUENCY_RATE), - (198.593939393939 / FREQUENCY_RATE), - (199.197568389058 / FREQUENCY_RATE), - (199.804878048781 / FREQUENCY_RATE), - (200.415902140673 / FREQUENCY_RATE), - (201.030674846626 / FREQUENCY_RATE), - (201.649230769231 / FREQUENCY_RATE), - (202.271604938272 / FREQUENCY_RATE), - (202.897832817337 / FREQUENCY_RATE), - (203.527950310559 / FREQUENCY_RATE), - (204.16199376947 / FREQUENCY_RATE), - (204.8 / FREQUENCY_RATE), - (205.442006269592 / FREQUENCY_RATE), - (206.088050314465 / FREQUENCY_RATE), - (206.738170347003 / FREQUENCY_RATE), - (207.392405063291 / FREQUENCY_RATE), - (208.050793650794 / FREQUENCY_RATE), - (208.713375796178 / FREQUENCY_RATE), - (209.380191693291 / FREQUENCY_RATE), - (210.051282051282 / FREQUENCY_RATE), - (210.726688102894 / FREQUENCY_RATE), - (211.406451612903 / FREQUENCY_RATE), - (212.090614886731 / FREQUENCY_RATE), - (212.779220779221 / FREQUENCY_RATE), - (213.472312703583 / FREQUENCY_RATE), - (214.169934640523 / FREQUENCY_RATE), - (214.872131147541 / FREQUENCY_RATE), - (215.578947368421 / FREQUENCY_RATE), - (216.290429042904 / FREQUENCY_RATE), - (217.006622516556 / FREQUENCY_RATE), - (217.727574750831 / FREQUENCY_RATE), - (218.453333333333 / FREQUENCY_RATE), - (219.183946488294 / FREQUENCY_RATE), - (219.919463087248 / FREQUENCY_RATE), - (220.659932659933 / FREQUENCY_RATE), - (221.405405405405 / FREQUENCY_RATE), - (222.15593220339 / FREQUENCY_RATE), - (222.91156462585 / FREQUENCY_RATE), - (223.672354948805 / FREQUENCY_RATE), - (224.438356164384 / FREQUENCY_RATE), - (225.209621993127 / FREQUENCY_RATE), - (225.986206896552 / FREQUENCY_RATE), - (226.768166089965 / FREQUENCY_RATE), - (227.555555555556 / FREQUENCY_RATE), - (228.348432055749 / FREQUENCY_RATE), - (229.146853146853 / FREQUENCY_RATE), - (229.950877192982 / FREQUENCY_RATE), - (230.760563380282 / FREQUENCY_RATE), - (231.575971731449 / FREQUENCY_RATE), - (232.397163120567 / FREQUENCY_RATE), - (233.224199288256 / FREQUENCY_RATE), - (234.057142857143 / FREQUENCY_RATE), - (234.89605734767 / FREQUENCY_RATE), - (235.741007194245 / FREQUENCY_RATE), - (236.592057761733 / FREQUENCY_RATE), - (237.449275362319 / FREQUENCY_RATE), - (238.312727272727 / FREQUENCY_RATE), - (239.182481751825 / FREQUENCY_RATE), - (240.058608058608 / FREQUENCY_RATE), - (240.941176470588 / FREQUENCY_RATE), - (241.830258302583 / FREQUENCY_RATE), - (242.725925925926 / FREQUENCY_RATE), - (243.628252788104 / FREQUENCY_RATE), - (244.537313432836 / FREQUENCY_RATE), - (245.453183520599 / FREQUENCY_RATE), - (246.375939849624 / FREQUENCY_RATE), - (247.305660377358 / FREQUENCY_RATE), - (248.242424242424 / FREQUENCY_RATE), - (249.186311787072 / FREQUENCY_RATE), - (250.137404580153 / FREQUENCY_RATE), - (251.095785440613 / FREQUENCY_RATE), - (252.061538461538 / FREQUENCY_RATE), - (253.034749034749 / FREQUENCY_RATE), - (254.015503875969 / FREQUENCY_RATE), - (255.003891050584 / FREQUENCY_RATE), - (256 / FREQUENCY_RATE), - (257.003921568627 / FREQUENCY_RATE), - (258.015748031496 / FREQUENCY_RATE), - (259.03557312253 / FREQUENCY_RATE), - (260.063492063492 / FREQUENCY_RATE), - (261.099601593625 / FREQUENCY_RATE), - (262.144 / FREQUENCY_RATE), - (263.196787148594 / FREQUENCY_RATE), - (264.258064516129 / FREQUENCY_RATE), - (265.327935222672 / FREQUENCY_RATE), - (266.406504065041 / FREQUENCY_RATE), - (267.49387755102 / FREQUENCY_RATE), - (268.590163934426 / FREQUENCY_RATE), - (269.695473251029 / FREQUENCY_RATE), - (270.809917355372 / FREQUENCY_RATE), - (271.933609958506 / FREQUENCY_RATE), - (273.066666666667 / FREQUENCY_RATE), - (274.20920502092 / FREQUENCY_RATE), - (275.361344537815 / FREQUENCY_RATE), - (276.523206751055 / FREQUENCY_RATE), - (277.694915254237 / FREQUENCY_RATE), - (278.876595744681 / FREQUENCY_RATE), - (280.068376068376 / FREQUENCY_RATE), - (281.270386266094 / FREQUENCY_RATE), - (282.48275862069 / FREQUENCY_RATE), - (283.705627705628 / FREQUENCY_RATE), - (284.939130434783 / FREQUENCY_RATE), - (286.183406113537 / FREQUENCY_RATE), - (287.438596491228 / FREQUENCY_RATE), - (288.704845814978 / FREQUENCY_RATE), - (289.982300884956 / FREQUENCY_RATE), - (291.271111111111 / FREQUENCY_RATE), - (292.571428571429 / FREQUENCY_RATE), - (293.883408071749 / FREQUENCY_RATE), - (295.207207207207 / FREQUENCY_RATE), - (296.542986425339 / FREQUENCY_RATE), - (297.890909090909 / FREQUENCY_RATE), - (299.251141552511 / FREQUENCY_RATE), - (300.623853211009 / FREQUENCY_RATE), - (302.009216589862 / FREQUENCY_RATE), - (303.407407407407 / FREQUENCY_RATE), - (304.818604651163 / FREQUENCY_RATE), - (306.242990654206 / FREQUENCY_RATE), - (307.680751173709 / FREQUENCY_RATE), - (309.132075471698 / FREQUENCY_RATE), - (310.597156398104 / FREQUENCY_RATE), - (312.07619047619 / FREQUENCY_RATE), - (313.569377990431 / FREQUENCY_RATE), - (315.076923076923 / FREQUENCY_RATE), - (316.599033816425 / FREQUENCY_RATE), - (318.135922330097 / FREQUENCY_RATE), - (319.687804878049 / FREQUENCY_RATE), - (321.254901960784 / FREQUENCY_RATE), - (322.837438423645 / FREQUENCY_RATE), - (324.435643564356 / FREQUENCY_RATE), - (326.049751243781 / FREQUENCY_RATE), - (327.68 / FREQUENCY_RATE), - (329.326633165829 / FREQUENCY_RATE), - (330.989898989899 / FREQUENCY_RATE), - (332.670050761421 / FREQUENCY_RATE), - (334.367346938775 / FREQUENCY_RATE), - (336.082051282051 / FREQUENCY_RATE), - (337.814432989691 / FREQUENCY_RATE), - (339.564766839378 / FREQUENCY_RATE), - (341.333333333333 / FREQUENCY_RATE), - (343.120418848168 / FREQUENCY_RATE), - (344.926315789474 / FREQUENCY_RATE), - (346.751322751323 / FREQUENCY_RATE), - (348.595744680851 / FREQUENCY_RATE), - (350.459893048128 / FREQUENCY_RATE), - (352.344086021505 / FREQUENCY_RATE), - (354.248648648649 / FREQUENCY_RATE), - (356.173913043478 / FREQUENCY_RATE), - (358.120218579235 / FREQUENCY_RATE), - (360.087912087912 / FREQUENCY_RATE), - (362.077348066298 / FREQUENCY_RATE), - (364.088888888889 / FREQUENCY_RATE), - (366.122905027933 / FREQUENCY_RATE), - (368.179775280899 / FREQUENCY_RATE), - (370.25988700565 / FREQUENCY_RATE), - (372.363636363636 / FREQUENCY_RATE), - (374.491428571429 / FREQUENCY_RATE), - (376.64367816092 / FREQUENCY_RATE), - (378.820809248555 / FREQUENCY_RATE), - (381.023255813953 / FREQUENCY_RATE), - (383.251461988304 / FREQUENCY_RATE), - (385.505882352941 / FREQUENCY_RATE), - (387.786982248521 / FREQUENCY_RATE), - (390.095238095238 / FREQUENCY_RATE), - (392.431137724551 / FREQUENCY_RATE), - (394.795180722892 / FREQUENCY_RATE), - (397.187878787879 / FREQUENCY_RATE), - (399.609756097561 / FREQUENCY_RATE), - (402.061349693252 / FREQUENCY_RATE), - (404.543209876543 / FREQUENCY_RATE), - (407.055900621118 / FREQUENCY_RATE), - (409.6 / FREQUENCY_RATE), - (412.176100628931 / FREQUENCY_RATE), - (414.784810126582 / FREQUENCY_RATE), - (417.426751592357 / FREQUENCY_RATE), - (420.102564102564 / FREQUENCY_RATE), - (422.812903225807 / FREQUENCY_RATE), - (425.558441558442 / FREQUENCY_RATE), - (428.339869281046 / FREQUENCY_RATE), - (431.157894736842 / FREQUENCY_RATE), - (434.013245033113 / FREQUENCY_RATE), - (436.906666666667 / FREQUENCY_RATE), - (439.838926174497 / FREQUENCY_RATE), - (442.810810810811 / FREQUENCY_RATE), - (445.823129251701 / FREQUENCY_RATE), - (448.876712328767 / FREQUENCY_RATE), - (451.972413793103 / FREQUENCY_RATE), - (455.111111111111 / FREQUENCY_RATE), - (458.293706293706 / FREQUENCY_RATE), - (461.521126760563 / FREQUENCY_RATE), - (464.794326241135 / FREQUENCY_RATE), - (468.114285714286 / FREQUENCY_RATE), - (471.482014388489 / FREQUENCY_RATE), - (474.898550724638 / FREQUENCY_RATE), - (478.36496350365 / FREQUENCY_RATE), - (481.882352941176 / FREQUENCY_RATE), - (485.451851851852 / FREQUENCY_RATE), - (489.074626865672 / FREQUENCY_RATE), - (492.751879699248 / FREQUENCY_RATE), - (496.484848484849 / FREQUENCY_RATE), - (500.274809160305 / FREQUENCY_RATE), - (504.123076923077 / FREQUENCY_RATE), - (508.031007751938 / FREQUENCY_RATE), - (512 / FREQUENCY_RATE), - (516.031496062992 / FREQUENCY_RATE), - (520.126984126984 / FREQUENCY_RATE), - (524.288 / FREQUENCY_RATE), - (528.516129032258 / FREQUENCY_RATE), - (532.813008130081 / FREQUENCY_RATE), - (537.180327868852 / FREQUENCY_RATE), - (541.619834710744 / FREQUENCY_RATE), - (546.133333333333 / FREQUENCY_RATE), - (550.72268907563 / FREQUENCY_RATE), - (555.389830508475 / FREQUENCY_RATE), - (560.136752136752 / FREQUENCY_RATE), - (564.965517241379 / FREQUENCY_RATE), - (569.878260869565 / FREQUENCY_RATE), - (574.877192982456 / FREQUENCY_RATE), - (579.964601769912 / FREQUENCY_RATE), - (585.142857142857 / FREQUENCY_RATE), - (590.414414414414 / FREQUENCY_RATE), - (595.781818181818 / FREQUENCY_RATE), - (601.247706422018 / FREQUENCY_RATE), - (606.814814814815 / FREQUENCY_RATE), - (612.485981308411 / FREQUENCY_RATE), - (618.264150943396 / FREQUENCY_RATE), - (624.152380952381 / FREQUENCY_RATE), - (630.153846153846 / FREQUENCY_RATE), - (636.271844660194 / FREQUENCY_RATE), - (642.509803921569 / FREQUENCY_RATE), - (648.871287128713 / FREQUENCY_RATE), - (655.36 / FREQUENCY_RATE), - (661.979797979798 / FREQUENCY_RATE), - (668.734693877551 / FREQUENCY_RATE), - (675.628865979381 / FREQUENCY_RATE), - (682.666666666667 / FREQUENCY_RATE), - (689.852631578947 / FREQUENCY_RATE), - (697.191489361702 / FREQUENCY_RATE), - (704.688172043011 / FREQUENCY_RATE), - (712.347826086956 / FREQUENCY_RATE), - (720.175824175824 / FREQUENCY_RATE), - (728.177777777778 / FREQUENCY_RATE), - (736.359550561798 / FREQUENCY_RATE), - (744.727272727273 / FREQUENCY_RATE), - (753.287356321839 / FREQUENCY_RATE), - (762.046511627907 / FREQUENCY_RATE), - (771.011764705882 / FREQUENCY_RATE), - (780.190476190476 / FREQUENCY_RATE), - (789.590361445783 / FREQUENCY_RATE), - (799.219512195122 / FREQUENCY_RATE), - (809.086419753086 / FREQUENCY_RATE), - (819.2 / FREQUENCY_RATE), - (829.569620253165 / FREQUENCY_RATE), - (840.205128205128 / FREQUENCY_RATE), - (851.116883116883 / FREQUENCY_RATE), - (862.315789473684 / FREQUENCY_RATE), - (873.813333333333 / FREQUENCY_RATE), - (885.621621621622 / FREQUENCY_RATE), - (897.753424657534 / FREQUENCY_RATE), - (910.222222222222 / FREQUENCY_RATE), - (923.042253521127 / FREQUENCY_RATE), - (936.228571428571 / FREQUENCY_RATE), - (949.797101449275 / FREQUENCY_RATE), - (963.764705882353 / FREQUENCY_RATE), - (978.149253731343 / FREQUENCY_RATE), - (992.969696969697 / FREQUENCY_RATE), - (1008.24615384615 / FREQUENCY_RATE), - (1024 / FREQUENCY_RATE), - (1040.25396825397 / FREQUENCY_RATE), - (1057.03225806452 / FREQUENCY_RATE), - (1074.36065573771 / FREQUENCY_RATE), - (1092.26666666667 / FREQUENCY_RATE), - (1110.77966101695 / FREQUENCY_RATE), - (1129.93103448276 / FREQUENCY_RATE), - (1149.75438596491 / FREQUENCY_RATE), - (1170.28571428571 / FREQUENCY_RATE), - (1191.56363636364 / FREQUENCY_RATE), - (1213.62962962963 / FREQUENCY_RATE), - (1236.52830188679 / FREQUENCY_RATE), - (1260.30769230769 / FREQUENCY_RATE), - (1285.01960784314 / FREQUENCY_RATE), - (1310.72 / FREQUENCY_RATE), - (1337.4693877551 / FREQUENCY_RATE), - (1365.33333333333 / FREQUENCY_RATE), - (1394.3829787234 / FREQUENCY_RATE), - (1424.69565217391 / FREQUENCY_RATE), - (1456.35555555556 / FREQUENCY_RATE), - (1489.45454545455 / FREQUENCY_RATE), - (1524.09302325581 / FREQUENCY_RATE), - (1560.38095238095 / FREQUENCY_RATE), - (1598.43902439024 / FREQUENCY_RATE), - (1638.4 / FREQUENCY_RATE), - (1680.41025641026 / FREQUENCY_RATE), - (1724.63157894737 / FREQUENCY_RATE), - (1771.24324324324 / FREQUENCY_RATE), - (1820.44444444444 / FREQUENCY_RATE), - (1872.45714285714 / FREQUENCY_RATE), - (1927.52941176471 / FREQUENCY_RATE), - (1985.93939393939 / FREQUENCY_RATE), - (2048 / FREQUENCY_RATE), - (2114.06451612903 / FREQUENCY_RATE), - (2184.53333333333 / FREQUENCY_RATE), - (2259.86206896552 / FREQUENCY_RATE), - (2340.57142857143 / FREQUENCY_RATE), - (2427.25925925926 / FREQUENCY_RATE), - (2520.61538461538 / FREQUENCY_RATE), - (2621.44 / FREQUENCY_RATE), - (2730.66666666667 / FREQUENCY_RATE), - (2849.39130434783 / FREQUENCY_RATE), - (2978.90909090909 / FREQUENCY_RATE), - (3120.7619047619 / FREQUENCY_RATE), - (3276.8 / FREQUENCY_RATE), - (3449.26315789474 / FREQUENCY_RATE), - (3640.88888888889 / FREQUENCY_RATE), - (3855.05882352941 / FREQUENCY_RATE), - (4096 / FREQUENCY_RATE), - (4369.06666666667 / FREQUENCY_RATE), - (4681.14285714286 / FREQUENCY_RATE), - (5041.23076923077 / FREQUENCY_RATE), - (5461.33333333333 / FREQUENCY_RATE), - (5957.81818181818 / FREQUENCY_RATE), - (6553.6 / FREQUENCY_RATE), - (7281.77777777778 / FREQUENCY_RATE), - (8192 / FREQUENCY_RATE), - (9362.28571428571 / FREQUENCY_RATE), - (10922.6666666667 / FREQUENCY_RATE), - (13107.2 / FREQUENCY_RATE), - (16384 / FREQUENCY_RATE), - (21845.3333333333 / FREQUENCY_RATE), - (32768 / FREQUENCY_RATE), - (65536 / FREQUENCY_RATE), +const fixed16_16 freqTable[2048] = { + float_to_fp16_16(32 / FREQUENCY_RATE), + float_to_fp16_16(32.0156326331216 / FREQUENCY_RATE), + float_to_fp16_16(32.0312805474096 / FREQUENCY_RATE), + float_to_fp16_16(32.0469437652812 / FREQUENCY_RATE), + float_to_fp16_16(32.0626223091976 / FREQUENCY_RATE), + float_to_fp16_16(32.0783162016642 / FREQUENCY_RATE), + float_to_fp16_16(32.0940254652302 / FREQUENCY_RATE), + float_to_fp16_16(32.109750122489 / FREQUENCY_RATE), + float_to_fp16_16(32.1254901960784 / FREQUENCY_RATE), + float_to_fp16_16(32.1412457086807 / FREQUENCY_RATE), + float_to_fp16_16(32.1570166830226 / FREQUENCY_RATE), + float_to_fp16_16(32.1728031418753 / FREQUENCY_RATE), + float_to_fp16_16(32.188605108055 / FREQUENCY_RATE), + float_to_fp16_16(32.2044226044226 / FREQUENCY_RATE), + float_to_fp16_16(32.220255653884 / FREQUENCY_RATE), + float_to_fp16_16(32.2361042793901 / FREQUENCY_RATE), + float_to_fp16_16(32.251968503937 / FREQUENCY_RATE), + float_to_fp16_16(32.2678483505662 / FREQUENCY_RATE), + float_to_fp16_16(32.2837438423645 / FREQUENCY_RATE), + float_to_fp16_16(32.2996550024643 / FREQUENCY_RATE), + float_to_fp16_16(32.3155818540434 / FREQUENCY_RATE), + float_to_fp16_16(32.3315244203256 / FREQUENCY_RATE), + float_to_fp16_16(32.3474827245805 / FREQUENCY_RATE), + float_to_fp16_16(32.3634567901235 / FREQUENCY_RATE), + float_to_fp16_16(32.3794466403162 / FREQUENCY_RATE), + float_to_fp16_16(32.3954522985665 / FREQUENCY_RATE), + float_to_fp16_16(32.4114737883284 / FREQUENCY_RATE), + float_to_fp16_16(32.4275111331024 / FREQUENCY_RATE), + float_to_fp16_16(32.4435643564356 / FREQUENCY_RATE), + float_to_fp16_16(32.4596334819217 / FREQUENCY_RATE), + float_to_fp16_16(32.4757185332012 / FREQUENCY_RATE), + float_to_fp16_16(32.4918195339613 / FREQUENCY_RATE), + float_to_fp16_16(32.5079365079365 / FREQUENCY_RATE), + float_to_fp16_16(32.5240694789082 / FREQUENCY_RATE), + float_to_fp16_16(32.5402184707051 / FREQUENCY_RATE), + float_to_fp16_16(32.5563835072032 / FREQUENCY_RATE), + float_to_fp16_16(32.572564612326 / FREQUENCY_RATE), + float_to_fp16_16(32.5887618100448 / FREQUENCY_RATE), + float_to_fp16_16(32.6049751243781 / FREQUENCY_RATE), + float_to_fp16_16(32.6212045793927 / FREQUENCY_RATE), + float_to_fp16_16(32.6374501992032 / FREQUENCY_RATE), + float_to_fp16_16(32.6537120079721 / FREQUENCY_RATE), + float_to_fp16_16(32.6699900299103 / FREQUENCY_RATE), + float_to_fp16_16(32.6862842892768 / FREQUENCY_RATE), + float_to_fp16_16(32.7025948103792 / FREQUENCY_RATE), + float_to_fp16_16(32.7189216175736 / FREQUENCY_RATE), + float_to_fp16_16(32.7352647352647 / FREQUENCY_RATE), + float_to_fp16_16(32.751624187906 / FREQUENCY_RATE), + float_to_fp16_16(32.768 / FREQUENCY_RATE), + float_to_fp16_16(32.784392196098 / FREQUENCY_RATE), + float_to_fp16_16(32.8008008008008 / FREQUENCY_RATE), + float_to_fp16_16(32.8172258387581 / FREQUENCY_RATE), + float_to_fp16_16(32.8336673346693 / FREQUENCY_RATE), + float_to_fp16_16(32.8501253132832 / FREQUENCY_RATE), + float_to_fp16_16(32.8665997993982 / FREQUENCY_RATE), + float_to_fp16_16(32.8830908178625 / FREQUENCY_RATE), + float_to_fp16_16(32.8995983935743 / FREQUENCY_RATE), + float_to_fp16_16(32.9161225514817 / FREQUENCY_RATE), + float_to_fp16_16(32.9326633165829 / FREQUENCY_RATE), + float_to_fp16_16(32.9492207139266 / FREQUENCY_RATE), + float_to_fp16_16(32.9657947686117 / FREQUENCY_RATE), + float_to_fp16_16(32.9823855057876 / FREQUENCY_RATE), + float_to_fp16_16(32.9989929506546 / FREQUENCY_RATE), + float_to_fp16_16(33.0156171284635 / FREQUENCY_RATE), + float_to_fp16_16(33.0322580645161 / FREQUENCY_RATE), + float_to_fp16_16(33.0489157841654 / FREQUENCY_RATE), + float_to_fp16_16(33.0655903128153 / FREQUENCY_RATE), + float_to_fp16_16(33.0822816759213 / FREQUENCY_RATE), + float_to_fp16_16(33.0989898989899 / FREQUENCY_RATE), + float_to_fp16_16(33.1157150075796 / FREQUENCY_RATE), + float_to_fp16_16(33.1324570273003 / FREQUENCY_RATE), + float_to_fp16_16(33.1492159838139 / FREQUENCY_RATE), + float_to_fp16_16(33.165991902834 / FREQUENCY_RATE), + float_to_fp16_16(33.1827848101266 / FREQUENCY_RATE), + float_to_fp16_16(33.1995947315096 / FREQUENCY_RATE), + float_to_fp16_16(33.2164216928535 / FREQUENCY_RATE), + float_to_fp16_16(33.2332657200811 / FREQUENCY_RATE), + float_to_fp16_16(33.2501268391679 / FREQUENCY_RATE), + float_to_fp16_16(33.2670050761421 / FREQUENCY_RATE), + float_to_fp16_16(33.2839004570848 / FREQUENCY_RATE), + float_to_fp16_16(33.3008130081301 / FREQUENCY_RATE), + float_to_fp16_16(33.3177427554652 / FREQUENCY_RATE), + float_to_fp16_16(33.3346897253306 / FREQUENCY_RATE), + float_to_fp16_16(33.3516539440204 / FREQUENCY_RATE), + float_to_fp16_16(33.3686354378819 / FREQUENCY_RATE), + float_to_fp16_16(33.3856342333164 / FREQUENCY_RATE), + float_to_fp16_16(33.4026503567788 / FREQUENCY_RATE), + float_to_fp16_16(33.4196838347782 / FREQUENCY_RATE), + float_to_fp16_16(33.4367346938776 / FREQUENCY_RATE), + float_to_fp16_16(33.4538029606942 / FREQUENCY_RATE), + float_to_fp16_16(33.4708886618999 / FREQUENCY_RATE), + float_to_fp16_16(33.4879918242207 / FREQUENCY_RATE), + float_to_fp16_16(33.5051124744376 / FREQUENCY_RATE), + float_to_fp16_16(33.5222506393862 / FREQUENCY_RATE), + float_to_fp16_16(33.539406345957 / FREQUENCY_RATE), + float_to_fp16_16(33.5565796210957 / FREQUENCY_RATE), + float_to_fp16_16(33.5737704918033 / FREQUENCY_RATE), + float_to_fp16_16(33.5909789851358 / FREQUENCY_RATE), + float_to_fp16_16(33.6082051282051 / FREQUENCY_RATE), + float_to_fp16_16(33.6254489481786 / FREQUENCY_RATE), + float_to_fp16_16(33.6427104722793 / FREQUENCY_RATE), + float_to_fp16_16(33.6599897277863 / FREQUENCY_RATE), + float_to_fp16_16(33.6772867420349 / FREQUENCY_RATE), + float_to_fp16_16(33.6946015424164 / FREQUENCY_RATE), + float_to_fp16_16(33.7119341563786 / FREQUENCY_RATE), + float_to_fp16_16(33.7292846114256 / FREQUENCY_RATE), + float_to_fp16_16(33.7466529351184 / FREQUENCY_RATE), + float_to_fp16_16(33.7640391550747 / FREQUENCY_RATE), + float_to_fp16_16(33.7814432989691 / FREQUENCY_RATE), + float_to_fp16_16(33.7988653945333 / FREQUENCY_RATE), + float_to_fp16_16(33.8163054695562 / FREQUENCY_RATE), + float_to_fp16_16(33.8337635518844 / FREQUENCY_RATE), + float_to_fp16_16(33.8512396694215 / FREQUENCY_RATE), + float_to_fp16_16(33.8687338501292 / FREQUENCY_RATE), + float_to_fp16_16(33.8862461220269 / FREQUENCY_RATE), + float_to_fp16_16(33.9037765131919 / FREQUENCY_RATE), + float_to_fp16_16(33.9213250517598 / FREQUENCY_RATE), + float_to_fp16_16(33.9388917659244 / FREQUENCY_RATE), + float_to_fp16_16(33.9564766839378 / FREQUENCY_RATE), + float_to_fp16_16(33.9740798341109 / FREQUENCY_RATE), + float_to_fp16_16(33.9917012448133 / FREQUENCY_RATE), + float_to_fp16_16(34.0093409444733 / FREQUENCY_RATE), + float_to_fp16_16(34.0269989615784 / FREQUENCY_RATE), + float_to_fp16_16(34.0446753246753 / FREQUENCY_RATE), + float_to_fp16_16(34.0623700623701 / FREQUENCY_RATE), + float_to_fp16_16(34.0800832033281 / FREQUENCY_RATE), + float_to_fp16_16(34.0978147762747 / FREQUENCY_RATE), + float_to_fp16_16(34.1155648099948 / FREQUENCY_RATE), + float_to_fp16_16(34.1333333333333 / FREQUENCY_RATE), + float_to_fp16_16(34.1511203751954 / FREQUENCY_RATE), + float_to_fp16_16(34.1689259645464 / FREQUENCY_RATE), + float_to_fp16_16(34.1867501304121 / FREQUENCY_RATE), + float_to_fp16_16(34.2045929018789 / FREQUENCY_RATE), + float_to_fp16_16(34.222454308094 / FREQUENCY_RATE), + float_to_fp16_16(34.2403343782654 / FREQUENCY_RATE), + float_to_fp16_16(34.2582331416623 / FREQUENCY_RATE), + float_to_fp16_16(34.2761506276151 / FREQUENCY_RATE), + float_to_fp16_16(34.2940868655154 / FREQUENCY_RATE), + float_to_fp16_16(34.3120418848168 / FREQUENCY_RATE), + float_to_fp16_16(34.330015715034 / FREQUENCY_RATE), + float_to_fp16_16(34.3480083857442 / FREQUENCY_RATE), + float_to_fp16_16(34.3660199265863 / FREQUENCY_RATE), + float_to_fp16_16(34.3840503672613 / FREQUENCY_RATE), + float_to_fp16_16(34.4020997375328 / FREQUENCY_RATE), + float_to_fp16_16(34.4201680672269 / FREQUENCY_RATE), + float_to_fp16_16(34.4382553862323 / FREQUENCY_RATE), + float_to_fp16_16(34.4563617245005 / FREQUENCY_RATE), + float_to_fp16_16(34.4744871120463 / FREQUENCY_RATE), + float_to_fp16_16(34.4926315789474 / FREQUENCY_RATE), + float_to_fp16_16(34.5107951553449 / FREQUENCY_RATE), + float_to_fp16_16(34.5289778714436 / FREQUENCY_RATE), + float_to_fp16_16(34.5471797575119 / FREQUENCY_RATE), + float_to_fp16_16(34.5654008438819 / FREQUENCY_RATE), + float_to_fp16_16(34.5836411609499 / FREQUENCY_RATE), + float_to_fp16_16(34.6019007391763 / FREQUENCY_RATE), + float_to_fp16_16(34.6201796090861 / FREQUENCY_RATE), + float_to_fp16_16(34.6384778012685 / FREQUENCY_RATE), + float_to_fp16_16(34.6567953463776 / FREQUENCY_RATE), + float_to_fp16_16(34.6751322751323 / FREQUENCY_RATE), + float_to_fp16_16(34.6934886183166 / FREQUENCY_RATE), + float_to_fp16_16(34.7118644067797 / FREQUENCY_RATE), + float_to_fp16_16(34.7302596714361 / FREQUENCY_RATE), + float_to_fp16_16(34.7486744432662 / FREQUENCY_RATE), + float_to_fp16_16(34.7671087533156 / FREQUENCY_RATE), + float_to_fp16_16(34.7855626326964 / FREQUENCY_RATE), + float_to_fp16_16(34.8040361125863 / FREQUENCY_RATE), + float_to_fp16_16(34.8225292242295 / FREQUENCY_RATE), + float_to_fp16_16(34.8410419989367 / FREQUENCY_RATE), + float_to_fp16_16(34.8595744680851 / FREQUENCY_RATE), + float_to_fp16_16(34.8781266631187 / FREQUENCY_RATE), + float_to_fp16_16(34.8966986155485 / FREQUENCY_RATE), + float_to_fp16_16(34.9152903569526 / FREQUENCY_RATE), + float_to_fp16_16(34.9339019189765 / FREQUENCY_RATE), + float_to_fp16_16(34.9525333333333 / FREQUENCY_RATE), + float_to_fp16_16(34.9711846318036 / FREQUENCY_RATE), + float_to_fp16_16(34.989855846236 / FREQUENCY_RATE), + float_to_fp16_16(35.008547008547 / FREQUENCY_RATE), + float_to_fp16_16(35.0272581507215 / FREQUENCY_RATE), + float_to_fp16_16(35.0459893048128 / FREQUENCY_RATE), + float_to_fp16_16(35.0647405029427 / FREQUENCY_RATE), + float_to_fp16_16(35.0835117773019 / FREQUENCY_RATE), + float_to_fp16_16(35.10230316015 / FREQUENCY_RATE), + float_to_fp16_16(35.1211146838156 / FREQUENCY_RATE), + float_to_fp16_16(35.1399463806971 / FREQUENCY_RATE), + float_to_fp16_16(35.1587982832618 / FREQUENCY_RATE), + float_to_fp16_16(35.1776704240472 / FREQUENCY_RATE), + float_to_fp16_16(35.1965628356606 / FREQUENCY_RATE), + float_to_fp16_16(35.2154755507792 / FREQUENCY_RATE), + float_to_fp16_16(35.2344086021505 / FREQUENCY_RATE), + float_to_fp16_16(35.2533620225928 / FREQUENCY_RATE), + float_to_fp16_16(35.2723358449946 / FREQUENCY_RATE), + float_to_fp16_16(35.2913301023156 / FREQUENCY_RATE), + float_to_fp16_16(35.3103448275862 / FREQUENCY_RATE), + float_to_fp16_16(35.3293800539084 / FREQUENCY_RATE), + float_to_fp16_16(35.3484358144552 / FREQUENCY_RATE), + float_to_fp16_16(35.3675121424717 / FREQUENCY_RATE), + float_to_fp16_16(35.3866090712743 / FREQUENCY_RATE), + float_to_fp16_16(35.4057266342518 / FREQUENCY_RATE), + float_to_fp16_16(35.4248648648649 / FREQUENCY_RATE), + float_to_fp16_16(35.4440237966468 / FREQUENCY_RATE), + float_to_fp16_16(35.4632034632035 / FREQUENCY_RATE), + float_to_fp16_16(35.4824038982133 / FREQUENCY_RATE), + float_to_fp16_16(35.501625135428 / FREQUENCY_RATE), + float_to_fp16_16(35.5208672086721 / FREQUENCY_RATE), + float_to_fp16_16(35.5401301518438 / FREQUENCY_RATE), + float_to_fp16_16(35.5594139989148 / FREQUENCY_RATE), + float_to_fp16_16(35.5787187839305 / FREQUENCY_RATE), + float_to_fp16_16(35.5980445410103 / FREQUENCY_RATE), + float_to_fp16_16(35.6173913043478 / FREQUENCY_RATE), + float_to_fp16_16(35.636759108211 / FREQUENCY_RATE), + float_to_fp16_16(35.6561479869423 / FREQUENCY_RATE), + float_to_fp16_16(35.6755579749592 / FREQUENCY_RATE), + float_to_fp16_16(35.6949891067538 / FREQUENCY_RATE), + float_to_fp16_16(35.7144414168937 / FREQUENCY_RATE), + float_to_fp16_16(35.7339149400218 / FREQUENCY_RATE), + float_to_fp16_16(35.7534097108565 / FREQUENCY_RATE), + float_to_fp16_16(35.7729257641921 / FREQUENCY_RATE), + float_to_fp16_16(35.792463134899 / FREQUENCY_RATE), + float_to_fp16_16(35.8120218579235 / FREQUENCY_RATE), + float_to_fp16_16(35.8316019682887 / FREQUENCY_RATE), + float_to_fp16_16(35.8512035010941 / FREQUENCY_RATE), + float_to_fp16_16(35.8708264915161 / FREQUENCY_RATE), + float_to_fp16_16(35.8904709748083 / FREQUENCY_RATE), + float_to_fp16_16(35.9101369863014 / FREQUENCY_RATE), + float_to_fp16_16(35.9298245614035 / FREQUENCY_RATE), + float_to_fp16_16(35.9495337356007 / FREQUENCY_RATE), + float_to_fp16_16(35.9692645444566 / FREQUENCY_RATE), + float_to_fp16_16(35.9890170236134 / FREQUENCY_RATE), + float_to_fp16_16(36.0087912087912 / FREQUENCY_RATE), + float_to_fp16_16(36.0285871357889 / FREQUENCY_RATE), + float_to_fp16_16(36.048404840484 / FREQUENCY_RATE), + float_to_fp16_16(36.0682443588332 / FREQUENCY_RATE), + float_to_fp16_16(36.0881057268722 / FREQUENCY_RATE), + float_to_fp16_16(36.1079889807162 / FREQUENCY_RATE), + float_to_fp16_16(36.1278941565601 / FREQUENCY_RATE), + float_to_fp16_16(36.1478212906784 / FREQUENCY_RATE), + float_to_fp16_16(36.167770419426 / FREQUENCY_RATE), + float_to_fp16_16(36.187741579238 / FREQUENCY_RATE), + float_to_fp16_16(36.2077348066298 / FREQUENCY_RATE), + float_to_fp16_16(36.2277501381979 / FREQUENCY_RATE), + float_to_fp16_16(36.2477876106195 / FREQUENCY_RATE), + float_to_fp16_16(36.267847260653 / FREQUENCY_RATE), + float_to_fp16_16(36.2879291251384 / FREQUENCY_RATE), + float_to_fp16_16(36.3080332409972 / FREQUENCY_RATE), + float_to_fp16_16(36.3281596452328 / FREQUENCY_RATE), + float_to_fp16_16(36.3483083749307 / FREQUENCY_RATE), + float_to_fp16_16(36.3684794672586 / FREQUENCY_RATE), + float_to_fp16_16(36.388672959467 / FREQUENCY_RATE), + float_to_fp16_16(36.4088888888889 / FREQUENCY_RATE), + float_to_fp16_16(36.4291272929405 / FREQUENCY_RATE), + float_to_fp16_16(36.4493882091212 / FREQUENCY_RATE), + float_to_fp16_16(36.4696716750139 / FREQUENCY_RATE), + float_to_fp16_16(36.4899777282851 / FREQUENCY_RATE), + float_to_fp16_16(36.5103064066852 / FREQUENCY_RATE), + float_to_fp16_16(36.5306577480491 / FREQUENCY_RATE), + float_to_fp16_16(36.5510317902956 / FREQUENCY_RATE), + float_to_fp16_16(36.5714285714286 / FREQUENCY_RATE), + float_to_fp16_16(36.5918481295366 / FREQUENCY_RATE), + float_to_fp16_16(36.6122905027933 / FREQUENCY_RATE), + float_to_fp16_16(36.6327557294578 / FREQUENCY_RATE), + float_to_fp16_16(36.6532438478747 / FREQUENCY_RATE), + float_to_fp16_16(36.6737548964745 / FREQUENCY_RATE), + float_to_fp16_16(36.6942889137738 / FREQUENCY_RATE), + float_to_fp16_16(36.7148459383753 / FREQUENCY_RATE), + float_to_fp16_16(36.7354260089686 / FREQUENCY_RATE), + float_to_fp16_16(36.7560291643298 / FREQUENCY_RATE), + float_to_fp16_16(36.7766554433221 / FREQUENCY_RATE), + float_to_fp16_16(36.7973048848961 / FREQUENCY_RATE), + float_to_fp16_16(36.8179775280899 / FREQUENCY_RATE), + float_to_fp16_16(36.8386734120292 / FREQUENCY_RATE), + float_to_fp16_16(36.859392575928 / FREQUENCY_RATE), + float_to_fp16_16(36.8801350590884 / FREQUENCY_RATE), + float_to_fp16_16(36.9009009009009 / FREQUENCY_RATE), + float_to_fp16_16(36.9216901408451 / FREQUENCY_RATE), + float_to_fp16_16(36.9425028184893 / FREQUENCY_RATE), + float_to_fp16_16(36.9633389734913 / FREQUENCY_RATE), + float_to_fp16_16(36.9841986455982 / FREQUENCY_RATE), + float_to_fp16_16(37.0050818746471 / FREQUENCY_RATE), + float_to_fp16_16(37.025988700565 / FREQUENCY_RATE), + float_to_fp16_16(37.0469191633691 / FREQUENCY_RATE), + float_to_fp16_16(37.0678733031674 / FREQUENCY_RATE), + float_to_fp16_16(37.0888511601585 / FREQUENCY_RATE), + float_to_fp16_16(37.1098527746319 / FREQUENCY_RATE), + float_to_fp16_16(37.1308781869688 / FREQUENCY_RATE), + float_to_fp16_16(37.1519274376417 / FREQUENCY_RATE), + float_to_fp16_16(37.173000567215 / FREQUENCY_RATE), + float_to_fp16_16(37.1940976163451 / FREQUENCY_RATE), + float_to_fp16_16(37.2152186257808 / FREQUENCY_RATE), + float_to_fp16_16(37.2363636363636 / FREQUENCY_RATE), + float_to_fp16_16(37.2575326890279 / FREQUENCY_RATE), + float_to_fp16_16(37.2787258248009 / FREQUENCY_RATE), + float_to_fp16_16(37.2999430848036 / FREQUENCY_RATE), + float_to_fp16_16(37.3211845102506 / FREQUENCY_RATE), + float_to_fp16_16(37.3424501424501 / FREQUENCY_RATE), + float_to_fp16_16(37.363740022805 / FREQUENCY_RATE), + float_to_fp16_16(37.3850541928123 / FREQUENCY_RATE), + float_to_fp16_16(37.4063926940639 / FREQUENCY_RATE), + float_to_fp16_16(37.4277555682467 / FREQUENCY_RATE), + float_to_fp16_16(37.4491428571429 / FREQUENCY_RATE), + float_to_fp16_16(37.4705546026301 / FREQUENCY_RATE), + float_to_fp16_16(37.4919908466819 / FREQUENCY_RATE), + float_to_fp16_16(37.5134516313681 / FREQUENCY_RATE), + float_to_fp16_16(37.5349369988545 / FREQUENCY_RATE), + float_to_fp16_16(37.556446991404 / FREQUENCY_RATE), + float_to_fp16_16(37.5779816513761 / FREQUENCY_RATE), + float_to_fp16_16(37.5995410212278 / FREQUENCY_RATE), + float_to_fp16_16(37.6211251435132 / FREQUENCY_RATE), + float_to_fp16_16(37.6427340608845 / FREQUENCY_RATE), + float_to_fp16_16(37.664367816092 / FREQUENCY_RATE), + float_to_fp16_16(37.6860264519839 / FREQUENCY_RATE), + float_to_fp16_16(37.7077100115075 / FREQUENCY_RATE), + float_to_fp16_16(37.7294185377087 / FREQUENCY_RATE), + float_to_fp16_16(37.7511520737327 / FREQUENCY_RATE), + float_to_fp16_16(37.7729106628242 / FREQUENCY_RATE), + float_to_fp16_16(37.7946943483276 / FREQUENCY_RATE), + float_to_fp16_16(37.8165031736872 / FREQUENCY_RATE), + float_to_fp16_16(37.838337182448 / FREQUENCY_RATE), + float_to_fp16_16(37.8601964182553 / FREQUENCY_RATE), + float_to_fp16_16(37.8820809248555 / FREQUENCY_RATE), + float_to_fp16_16(37.903990746096 / FREQUENCY_RATE), + float_to_fp16_16(37.9259259259259 / FREQUENCY_RATE), + float_to_fp16_16(37.9478865083961 / FREQUENCY_RATE), + float_to_fp16_16(37.9698725376593 / FREQUENCY_RATE), + float_to_fp16_16(37.991884057971 / FREQUENCY_RATE), + float_to_fp16_16(38.0139211136891 / FREQUENCY_RATE), + float_to_fp16_16(38.0359837492745 / FREQUENCY_RATE), + float_to_fp16_16(38.0580720092915 / FREQUENCY_RATE), + float_to_fp16_16(38.0801859384079 / FREQUENCY_RATE), + float_to_fp16_16(38.1023255813953 / FREQUENCY_RATE), + float_to_fp16_16(38.1244909831297 / FREQUENCY_RATE), + float_to_fp16_16(38.1466821885914 / FREQUENCY_RATE), + float_to_fp16_16(38.1688992428655 / FREQUENCY_RATE), + float_to_fp16_16(38.1911421911422 / FREQUENCY_RATE), + float_to_fp16_16(38.2134110787172 / FREQUENCY_RATE), + float_to_fp16_16(38.2357059509918 / FREQUENCY_RATE), + float_to_fp16_16(38.2580268534734 / FREQUENCY_RATE), + float_to_fp16_16(38.2803738317757 / FREQUENCY_RATE), + float_to_fp16_16(38.3027469316189 / FREQUENCY_RATE), + float_to_fp16_16(38.3251461988304 / FREQUENCY_RATE), + float_to_fp16_16(38.3475716793446 / FREQUENCY_RATE), + float_to_fp16_16(38.3700234192037 / FREQUENCY_RATE), + float_to_fp16_16(38.3925014645577 / FREQUENCY_RATE), + float_to_fp16_16(38.4150058616647 / FREQUENCY_RATE), + float_to_fp16_16(38.4375366568915 / FREQUENCY_RATE), + float_to_fp16_16(38.4600938967136 / FREQUENCY_RATE), + float_to_fp16_16(38.4826776277158 / FREQUENCY_RATE), + float_to_fp16_16(38.5052878965922 / FREQUENCY_RATE), + float_to_fp16_16(38.527924750147 / FREQUENCY_RATE), + float_to_fp16_16(38.5505882352941 / FREQUENCY_RATE), + float_to_fp16_16(38.5732783990583 / FREQUENCY_RATE), + float_to_fp16_16(38.5959952885748 / FREQUENCY_RATE), + float_to_fp16_16(38.6187389510902 / FREQUENCY_RATE), + float_to_fp16_16(38.6415094339623 / FREQUENCY_RATE), + float_to_fp16_16(38.6643067846608 / FREQUENCY_RATE), + float_to_fp16_16(38.6871310507674 / FREQUENCY_RATE), + float_to_fp16_16(38.7099822799764 / FREQUENCY_RATE), + float_to_fp16_16(38.7328605200946 / FREQUENCY_RATE), + float_to_fp16_16(38.755765819042 / FREQUENCY_RATE), + float_to_fp16_16(38.7786982248521 / FREQUENCY_RATE), + float_to_fp16_16(38.801657785672 / FREQUENCY_RATE), + float_to_fp16_16(38.824644549763 / FREQUENCY_RATE), + float_to_fp16_16(38.8476585655009 / FREQUENCY_RATE), + float_to_fp16_16(38.870699881376 / FREQUENCY_RATE), + float_to_fp16_16(38.8937685459941 / FREQUENCY_RATE), + float_to_fp16_16(38.916864608076 / FREQUENCY_RATE), + float_to_fp16_16(38.9399881164587 / FREQUENCY_RATE), + float_to_fp16_16(38.9631391200951 / FREQUENCY_RATE), + float_to_fp16_16(38.9863176680547 / FREQUENCY_RATE), + float_to_fp16_16(39.0095238095238 / FREQUENCY_RATE), + float_to_fp16_16(39.0327575938058 / FREQUENCY_RATE), + float_to_fp16_16(39.0560190703218 / FREQUENCY_RATE), + float_to_fp16_16(39.0793082886106 / FREQUENCY_RATE), + float_to_fp16_16(39.1026252983294 / FREQUENCY_RATE), + float_to_fp16_16(39.1259701492537 / FREQUENCY_RATE), + float_to_fp16_16(39.1493428912784 / FREQUENCY_RATE), + float_to_fp16_16(39.1727435744172 / FREQUENCY_RATE), + float_to_fp16_16(39.1961722488038 / FREQUENCY_RATE), + float_to_fp16_16(39.2196289646918 / FREQUENCY_RATE), + float_to_fp16_16(39.2431137724551 / FREQUENCY_RATE), + float_to_fp16_16(39.2666267225884 / FREQUENCY_RATE), + float_to_fp16_16(39.2901678657074 / FREQUENCY_RATE), + float_to_fp16_16(39.3137372525495 / FREQUENCY_RATE), + float_to_fp16_16(39.3373349339736 / FREQUENCY_RATE), + float_to_fp16_16(39.360960960961 / FREQUENCY_RATE), + float_to_fp16_16(39.3846153846154 / FREQUENCY_RATE), + float_to_fp16_16(39.4082982561636 / FREQUENCY_RATE), + float_to_fp16_16(39.4320096269555 / FREQUENCY_RATE), + float_to_fp16_16(39.4557495484648 / FREQUENCY_RATE), + float_to_fp16_16(39.4795180722892 / FREQUENCY_RATE), + float_to_fp16_16(39.5033152501507 / FREQUENCY_RATE), + float_to_fp16_16(39.5271411338963 / FREQUENCY_RATE), + float_to_fp16_16(39.5509957754979 / FREQUENCY_RATE), + float_to_fp16_16(39.5748792270531 / FREQUENCY_RATE), + float_to_fp16_16(39.5987915407855 / FREQUENCY_RATE), + float_to_fp16_16(39.6227327690447 / FREQUENCY_RATE), + float_to_fp16_16(39.6467029643073 / FREQUENCY_RATE), + float_to_fp16_16(39.6707021791768 / FREQUENCY_RATE), + float_to_fp16_16(39.694730466384 / FREQUENCY_RATE), + float_to_fp16_16(39.7187878787879 / FREQUENCY_RATE), + float_to_fp16_16(39.7428744693754 / FREQUENCY_RATE), + float_to_fp16_16(39.7669902912621 / FREQUENCY_RATE), + float_to_fp16_16(39.7911353976928 / FREQUENCY_RATE), + float_to_fp16_16(39.8153098420413 / FREQUENCY_RATE), + float_to_fp16_16(39.8395136778115 / FREQUENCY_RATE), + float_to_fp16_16(39.8637469586375 / FREQUENCY_RATE), + float_to_fp16_16(39.8880097382836 / FREQUENCY_RATE), + float_to_fp16_16(39.9123020706455 / FREQUENCY_RATE), + float_to_fp16_16(39.9366240097502 / FREQUENCY_RATE), + float_to_fp16_16(39.9609756097561 / FREQUENCY_RATE), + float_to_fp16_16(39.9853569249542 / FREQUENCY_RATE), + float_to_fp16_16(40.009768009768 / FREQUENCY_RATE), + float_to_fp16_16(40.0342089187538 / FREQUENCY_RATE), + float_to_fp16_16(40.0586797066015 / FREQUENCY_RATE), + float_to_fp16_16(40.0831804281346 / FREQUENCY_RATE), + float_to_fp16_16(40.1077111383109 / FREQUENCY_RATE), + float_to_fp16_16(40.1322718922229 / FREQUENCY_RATE), + float_to_fp16_16(40.156862745098 / FREQUENCY_RATE), + float_to_fp16_16(40.1814837522992 / FREQUENCY_RATE), + float_to_fp16_16(40.2061349693252 / FREQUENCY_RATE), + float_to_fp16_16(40.2308164518109 / FREQUENCY_RATE), + float_to_fp16_16(40.2555282555283 / FREQUENCY_RATE), + float_to_fp16_16(40.280270436386 / FREQUENCY_RATE), + float_to_fp16_16(40.3050430504305 / FREQUENCY_RATE), + float_to_fp16_16(40.3298461538462 / FREQUENCY_RATE), + float_to_fp16_16(40.3546798029557 / FREQUENCY_RATE), + float_to_fp16_16(40.3795440542206 / FREQUENCY_RATE), + float_to_fp16_16(40.4044389642417 / FREQUENCY_RATE), + float_to_fp16_16(40.4293645897594 / FREQUENCY_RATE), + float_to_fp16_16(40.4543209876543 / FREQUENCY_RATE), + float_to_fp16_16(40.4793082149475 / FREQUENCY_RATE), + float_to_fp16_16(40.504326328801 / FREQUENCY_RATE), + float_to_fp16_16(40.5293753865182 / FREQUENCY_RATE), + float_to_fp16_16(40.5544554455446 / FREQUENCY_RATE), + float_to_fp16_16(40.5795665634675 / FREQUENCY_RATE), + float_to_fp16_16(40.6047087980174 / FREQUENCY_RATE), + float_to_fp16_16(40.6298822070676 / FREQUENCY_RATE), + float_to_fp16_16(40.6550868486352 / FREQUENCY_RATE), + float_to_fp16_16(40.6803227808814 / FREQUENCY_RATE), + float_to_fp16_16(40.7055900621118 / FREQUENCY_RATE), + float_to_fp16_16(40.7308887507769 / FREQUENCY_RATE), + float_to_fp16_16(40.7562189054726 / FREQUENCY_RATE), + float_to_fp16_16(40.7815805849409 / FREQUENCY_RATE), + float_to_fp16_16(40.8069738480697 / FREQUENCY_RATE), + float_to_fp16_16(40.8323987538941 / FREQUENCY_RATE), + float_to_fp16_16(40.857855361596 / FREQUENCY_RATE), + float_to_fp16_16(40.8833437305053 / FREQUENCY_RATE), + float_to_fp16_16(40.9088639200999 / FREQUENCY_RATE), + float_to_fp16_16(40.9344159900062 / FREQUENCY_RATE), + float_to_fp16_16(40.96 / FREQUENCY_RATE), + float_to_fp16_16(40.9856160100063 / FREQUENCY_RATE), + float_to_fp16_16(41.0112640801001 / FREQUENCY_RATE), + float_to_fp16_16(41.0369442705072 / FREQUENCY_RATE), + float_to_fp16_16(41.062656641604 / FREQUENCY_RATE), + float_to_fp16_16(41.0884012539185 / FREQUENCY_RATE), + float_to_fp16_16(41.1141781681305 / FREQUENCY_RATE), + float_to_fp16_16(41.1399874450722 / FREQUENCY_RATE), + float_to_fp16_16(41.1658291457287 / FREQUENCY_RATE), + float_to_fp16_16(41.1917033312382 / FREQUENCY_RATE), + float_to_fp16_16(41.2176100628931 / FREQUENCY_RATE), + float_to_fp16_16(41.2435494021397 / FREQUENCY_RATE), + float_to_fp16_16(41.2695214105793 / FREQUENCY_RATE), + float_to_fp16_16(41.2955261499685 / FREQUENCY_RATE), + float_to_fp16_16(41.3215636822194 / FREQUENCY_RATE), + float_to_fp16_16(41.3476340694006 / FREQUENCY_RATE), + float_to_fp16_16(41.3737373737374 / FREQUENCY_RATE), + float_to_fp16_16(41.3998736576121 / FREQUENCY_RATE), + float_to_fp16_16(41.4260429835651 / FREQUENCY_RATE), + float_to_fp16_16(41.4522454142948 / FREQUENCY_RATE), + float_to_fp16_16(41.4784810126582 / FREQUENCY_RATE), + float_to_fp16_16(41.504749841672 / FREQUENCY_RATE), + float_to_fp16_16(41.531051964512 / FREQUENCY_RATE), + float_to_fp16_16(41.5573874445149 / FREQUENCY_RATE), + float_to_fp16_16(41.5837563451777 / FREQUENCY_RATE), + float_to_fp16_16(41.6101587301587 / FREQUENCY_RATE), + float_to_fp16_16(41.6365946632783 / FREQUENCY_RATE), + float_to_fp16_16(41.6630642085188 / FREQUENCY_RATE), + float_to_fp16_16(41.6895674300254 / FREQUENCY_RATE), + float_to_fp16_16(41.7161043921069 / FREQUENCY_RATE), + float_to_fp16_16(41.7426751592357 / FREQUENCY_RATE), + float_to_fp16_16(41.7692797960484 / FREQUENCY_RATE), + float_to_fp16_16(41.7959183673469 / FREQUENCY_RATE), + float_to_fp16_16(41.8225909380983 / FREQUENCY_RATE), + float_to_fp16_16(41.8492975734355 / FREQUENCY_RATE), + float_to_fp16_16(41.8760383386582 / FREQUENCY_RATE), + float_to_fp16_16(41.9028132992327 / FREQUENCY_RATE), + float_to_fp16_16(41.9296225207934 / FREQUENCY_RATE), + float_to_fp16_16(41.9564660691421 / FREQUENCY_RATE), + float_to_fp16_16(41.9833440102498 / FREQUENCY_RATE), + float_to_fp16_16(42.0102564102564 / FREQUENCY_RATE), + float_to_fp16_16(42.0372033354715 / FREQUENCY_RATE), + float_to_fp16_16(42.0641848523748 / FREQUENCY_RATE), + float_to_fp16_16(42.0912010276172 / FREQUENCY_RATE), + float_to_fp16_16(42.1182519280206 / FREQUENCY_RATE), + float_to_fp16_16(42.1453376205788 / FREQUENCY_RATE), + float_to_fp16_16(42.1724581724582 / FREQUENCY_RATE), + float_to_fp16_16(42.1996136509981 / FREQUENCY_RATE), + float_to_fp16_16(42.2268041237113 / FREQUENCY_RATE), + float_to_fp16_16(42.254029658285 / FREQUENCY_RATE), + float_to_fp16_16(42.2812903225807 / FREQUENCY_RATE), + float_to_fp16_16(42.3085861846352 / FREQUENCY_RATE), + float_to_fp16_16(42.3359173126615 / FREQUENCY_RATE), + float_to_fp16_16(42.3632837750485 / FREQUENCY_RATE), + float_to_fp16_16(42.3906856403622 / FREQUENCY_RATE), + float_to_fp16_16(42.4181229773463 / FREQUENCY_RATE), + float_to_fp16_16(42.4455958549223 / FREQUENCY_RATE), + float_to_fp16_16(42.4731043421905 / FREQUENCY_RATE), + float_to_fp16_16(42.5006485084306 / FREQUENCY_RATE), + float_to_fp16_16(42.5282284231019 / FREQUENCY_RATE), + float_to_fp16_16(42.5558441558442 / FREQUENCY_RATE), + float_to_fp16_16(42.5834957764782 / FREQUENCY_RATE), + float_to_fp16_16(42.6111833550065 / FREQUENCY_RATE), + float_to_fp16_16(42.6389069616135 / FREQUENCY_RATE), + float_to_fp16_16(42.6666666666667 / FREQUENCY_RATE), + float_to_fp16_16(42.6944625407166 / FREQUENCY_RATE), + float_to_fp16_16(42.722294654498 / FREQUENCY_RATE), + float_to_fp16_16(42.7501630789302 / FREQUENCY_RATE), + float_to_fp16_16(42.7780678851175 / FREQUENCY_RATE), + float_to_fp16_16(42.8060091443501 / FREQUENCY_RATE), + float_to_fp16_16(42.8339869281046 / FREQUENCY_RATE), + float_to_fp16_16(42.8620013080445 / FREQUENCY_RATE), + float_to_fp16_16(42.890052356021 / FREQUENCY_RATE), + float_to_fp16_16(42.9181401440733 / FREQUENCY_RATE), + float_to_fp16_16(42.9462647444299 / FREQUENCY_RATE), + float_to_fp16_16(42.9744262295082 / FREQUENCY_RATE), + float_to_fp16_16(43.002624671916 / FREQUENCY_RATE), + float_to_fp16_16(43.0308601444517 / FREQUENCY_RATE), + float_to_fp16_16(43.0591327201051 / FREQUENCY_RATE), + float_to_fp16_16(43.0874424720579 / FREQUENCY_RATE), + float_to_fp16_16(43.1157894736842 / FREQUENCY_RATE), + float_to_fp16_16(43.1441737985517 / FREQUENCY_RATE), + float_to_fp16_16(43.1725955204216 / FREQUENCY_RATE), + float_to_fp16_16(43.2010547132498 / FREQUENCY_RATE), + float_to_fp16_16(43.2295514511873 / FREQUENCY_RATE), + float_to_fp16_16(43.2580858085809 / FREQUENCY_RATE), + float_to_fp16_16(43.2866578599736 / FREQUENCY_RATE), + float_to_fp16_16(43.3152676801057 / FREQUENCY_RATE), + float_to_fp16_16(43.3439153439153 / FREQUENCY_RATE), + float_to_fp16_16(43.3726009265387 / FREQUENCY_RATE), + float_to_fp16_16(43.4013245033113 / FREQUENCY_RATE), + float_to_fp16_16(43.4300861497681 / FREQUENCY_RATE), + float_to_fp16_16(43.4588859416446 / FREQUENCY_RATE), + float_to_fp16_16(43.4877239548772 / FREQUENCY_RATE), + float_to_fp16_16(43.5166002656043 / FREQUENCY_RATE), + float_to_fp16_16(43.5455149501661 / FREQUENCY_RATE), + float_to_fp16_16(43.5744680851064 / FREQUENCY_RATE), + float_to_fp16_16(43.6034597471723 / FREQUENCY_RATE), + float_to_fp16_16(43.6324900133156 / FREQUENCY_RATE), + float_to_fp16_16(43.6615589606929 / FREQUENCY_RATE), + float_to_fp16_16(43.6906666666667 / FREQUENCY_RATE), + float_to_fp16_16(43.7198132088059 / FREQUENCY_RATE), + float_to_fp16_16(43.7489986648865 / FREQUENCY_RATE), + float_to_fp16_16(43.7782231128925 / FREQUENCY_RATE), + float_to_fp16_16(43.807486631016 / FREQUENCY_RATE), + float_to_fp16_16(43.8367892976589 / FREQUENCY_RATE), + float_to_fp16_16(43.8661311914324 / FREQUENCY_RATE), + float_to_fp16_16(43.8955123911587 / FREQUENCY_RATE), + float_to_fp16_16(43.9249329758713 / FREQUENCY_RATE), + float_to_fp16_16(43.9543930248156 / FREQUENCY_RATE), + float_to_fp16_16(43.9838926174497 / FREQUENCY_RATE), + float_to_fp16_16(44.0134318334453 / FREQUENCY_RATE), + float_to_fp16_16(44.0430107526882 / FREQUENCY_RATE), + float_to_fp16_16(44.0726294552791 / FREQUENCY_RATE), + float_to_fp16_16(44.1022880215343 / FREQUENCY_RATE), + float_to_fp16_16(44.1319865319865 / FREQUENCY_RATE), + float_to_fp16_16(44.1617250673855 / FREQUENCY_RATE), + float_to_fp16_16(44.1915037086986 / FREQUENCY_RATE), + float_to_fp16_16(44.221322537112 / FREQUENCY_RATE), + float_to_fp16_16(44.2511816340311 / FREQUENCY_RATE), + float_to_fp16_16(44.2810810810811 / FREQUENCY_RATE), + float_to_fp16_16(44.3110209601082 / FREQUENCY_RATE), + float_to_fp16_16(44.34100135318 / FREQUENCY_RATE), + float_to_fp16_16(44.3710223425863 / FREQUENCY_RATE), + float_to_fp16_16(44.4010840108401 / FREQUENCY_RATE), + float_to_fp16_16(44.431186440678 / FREQUENCY_RATE), + float_to_fp16_16(44.4613297150611 / FREQUENCY_RATE), + float_to_fp16_16(44.4915139171758 / FREQUENCY_RATE), + float_to_fp16_16(44.5217391304348 / FREQUENCY_RATE), + float_to_fp16_16(44.5520054384772 / FREQUENCY_RATE), + float_to_fp16_16(44.5823129251701 / FREQUENCY_RATE), + float_to_fp16_16(44.6126616746086 / FREQUENCY_RATE), + float_to_fp16_16(44.6430517711172 / FREQUENCY_RATE), + float_to_fp16_16(44.6734832992502 / FREQUENCY_RATE), + float_to_fp16_16(44.7039563437926 / FREQUENCY_RATE), + float_to_fp16_16(44.7344709897611 / FREQUENCY_RATE), + float_to_fp16_16(44.7650273224044 / FREQUENCY_RATE), + float_to_fp16_16(44.7956254272044 / FREQUENCY_RATE), + float_to_fp16_16(44.8262653898769 / FREQUENCY_RATE), + float_to_fp16_16(44.8569472963724 / FREQUENCY_RATE), + float_to_fp16_16(44.8876712328767 / FREQUENCY_RATE), + float_to_fp16_16(44.9184372858122 / FREQUENCY_RATE), + float_to_fp16_16(44.9492455418381 / FREQUENCY_RATE), + float_to_fp16_16(44.9800960878518 / FREQUENCY_RATE), + float_to_fp16_16(45.010989010989 / FREQUENCY_RATE), + float_to_fp16_16(45.0419243986254 / FREQUENCY_RATE), + float_to_fp16_16(45.0729023383769 / FREQUENCY_RATE), + float_to_fp16_16(45.1039229181005 / FREQUENCY_RATE), + float_to_fp16_16(45.1349862258953 / FREQUENCY_RATE), + float_to_fp16_16(45.1660923501034 / FREQUENCY_RATE), + float_to_fp16_16(45.1972413793103 / FREQUENCY_RATE), + float_to_fp16_16(45.2284334023465 / FREQUENCY_RATE), + float_to_fp16_16(45.2596685082873 / FREQUENCY_RATE), + float_to_fp16_16(45.2909467864547 / FREQUENCY_RATE), + float_to_fp16_16(45.3222683264177 / FREQUENCY_RATE), + float_to_fp16_16(45.3536332179931 / FREQUENCY_RATE), + float_to_fp16_16(45.3850415512465 / FREQUENCY_RATE), + float_to_fp16_16(45.4164934164934 / FREQUENCY_RATE), + float_to_fp16_16(45.4479889042996 / FREQUENCY_RATE), + float_to_fp16_16(45.4795281054823 / FREQUENCY_RATE), + float_to_fp16_16(45.5111111111111 / FREQUENCY_RATE), + float_to_fp16_16(45.5427380125087 / FREQUENCY_RATE), + float_to_fp16_16(45.5744089012517 / FREQUENCY_RATE), + float_to_fp16_16(45.6061238691719 / FREQUENCY_RATE), + float_to_fp16_16(45.6378830083566 / FREQUENCY_RATE), + float_to_fp16_16(45.6696864111498 / FREQUENCY_RATE), + float_to_fp16_16(45.7015341701534 / FREQUENCY_RATE), + float_to_fp16_16(45.7334263782275 / FREQUENCY_RATE), + float_to_fp16_16(45.7653631284916 / FREQUENCY_RATE), + float_to_fp16_16(45.7973445143256 / FREQUENCY_RATE), + float_to_fp16_16(45.8293706293706 / FREQUENCY_RATE), + float_to_fp16_16(45.8614415675297 / FREQUENCY_RATE), + float_to_fp16_16(45.8935574229692 / FREQUENCY_RATE), + float_to_fp16_16(45.9257182901191 / FREQUENCY_RATE), + float_to_fp16_16(45.9579242636746 / FREQUENCY_RATE), + float_to_fp16_16(45.9901754385965 / FREQUENCY_RATE), + float_to_fp16_16(46.0224719101124 / FREQUENCY_RATE), + float_to_fp16_16(46.0548137737175 / FREQUENCY_RATE), + float_to_fp16_16(46.0872011251758 / FREQUENCY_RATE), + float_to_fp16_16(46.1196340605208 / FREQUENCY_RATE), + float_to_fp16_16(46.1521126760563 / FREQUENCY_RATE), + float_to_fp16_16(46.184637068358 / FREQUENCY_RATE), + float_to_fp16_16(46.2172073342736 / FREQUENCY_RATE), + float_to_fp16_16(46.2498235709245 / FREQUENCY_RATE), + float_to_fp16_16(46.2824858757062 / FREQUENCY_RATE), + float_to_fp16_16(46.3151943462898 / FREQUENCY_RATE), + float_to_fp16_16(46.3479490806223 / FREQUENCY_RATE), + float_to_fp16_16(46.3807501769285 / FREQUENCY_RATE), + float_to_fp16_16(46.4135977337111 / FREQUENCY_RATE), + float_to_fp16_16(46.446491849752 / FREQUENCY_RATE), + float_to_fp16_16(46.4794326241135 / FREQUENCY_RATE), + float_to_fp16_16(46.5124201561391 / FREQUENCY_RATE), + float_to_fp16_16(46.5454545454545 / FREQUENCY_RATE), + float_to_fp16_16(46.5785358919687 / FREQUENCY_RATE), + float_to_fp16_16(46.6116642958748 / FREQUENCY_RATE), + float_to_fp16_16(46.6448398576513 / FREQUENCY_RATE), + float_to_fp16_16(46.6780626780627 / FREQUENCY_RATE), + float_to_fp16_16(46.7113328581611 / FREQUENCY_RATE), + float_to_fp16_16(46.7446504992867 / FREQUENCY_RATE), + float_to_fp16_16(46.7780157030692 / FREQUENCY_RATE), + float_to_fp16_16(46.8114285714286 / FREQUENCY_RATE), + float_to_fp16_16(46.8448892065761 / FREQUENCY_RATE), + float_to_fp16_16(46.8783977110157 / FREQUENCY_RATE), + float_to_fp16_16(46.9119541875447 / FREQUENCY_RATE), + float_to_fp16_16(46.945558739255 / FREQUENCY_RATE), + float_to_fp16_16(46.9792114695341 / FREQUENCY_RATE), + float_to_fp16_16(47.012912482066 / FREQUENCY_RATE), + float_to_fp16_16(47.0466618808327 / FREQUENCY_RATE), + float_to_fp16_16(47.0804597701149 / FREQUENCY_RATE), + float_to_fp16_16(47.1143062544932 / FREQUENCY_RATE), + float_to_fp16_16(47.1482014388489 / FREQUENCY_RATE), + float_to_fp16_16(47.1821454283657 / FREQUENCY_RATE), + float_to_fp16_16(47.2161383285303 / FREQUENCY_RATE), + float_to_fp16_16(47.2501802451334 / FREQUENCY_RATE), + float_to_fp16_16(47.2842712842713 / FREQUENCY_RATE), + float_to_fp16_16(47.3184115523466 / FREQUENCY_RATE), + float_to_fp16_16(47.3526011560694 / FREQUENCY_RATE), + float_to_fp16_16(47.3868402024584 / FREQUENCY_RATE), + float_to_fp16_16(47.4211287988423 / FREQUENCY_RATE), + float_to_fp16_16(47.4554670528602 / FREQUENCY_RATE), + float_to_fp16_16(47.4898550724638 / FREQUENCY_RATE), + float_to_fp16_16(47.5242929659173 / FREQUENCY_RATE), + float_to_fp16_16(47.5587808417997 / FREQUENCY_RATE), + float_to_fp16_16(47.5933188090051 / FREQUENCY_RATE), + float_to_fp16_16(47.6279069767442 / FREQUENCY_RATE), + float_to_fp16_16(47.6625454545455 / FREQUENCY_RATE), + float_to_fp16_16(47.6972343522562 / FREQUENCY_RATE), + float_to_fp16_16(47.7319737800437 / FREQUENCY_RATE), + float_to_fp16_16(47.7667638483965 / FREQUENCY_RATE), + float_to_fp16_16(47.8016046681255 / FREQUENCY_RATE), + float_to_fp16_16(47.836496350365 / FREQUENCY_RATE), + float_to_fp16_16(47.8714390065741 / FREQUENCY_RATE), + float_to_fp16_16(47.906432748538 / FREQUENCY_RATE), + float_to_fp16_16(47.9414776883687 / FREQUENCY_RATE), + float_to_fp16_16(47.9765739385066 / FREQUENCY_RATE), + float_to_fp16_16(48.0117216117216 / FREQUENCY_RATE), + float_to_fp16_16(48.0469208211144 / FREQUENCY_RATE), + float_to_fp16_16(48.0821716801174 / FREQUENCY_RATE), + float_to_fp16_16(48.1174743024963 / FREQUENCY_RATE), + float_to_fp16_16(48.1528288023512 / FREQUENCY_RATE), + float_to_fp16_16(48.1882352941176 / FREQUENCY_RATE), + float_to_fp16_16(48.2236938925681 / FREQUENCY_RATE), + float_to_fp16_16(48.259204712813 / FREQUENCY_RATE), + float_to_fp16_16(48.2947678703021 / FREQUENCY_RATE), + float_to_fp16_16(48.330383480826 / FREQUENCY_RATE), + float_to_fp16_16(48.3660516605166 / FREQUENCY_RATE), + float_to_fp16_16(48.4017725258493 / FREQUENCY_RATE), + float_to_fp16_16(48.4375461936438 / FREQUENCY_RATE), + float_to_fp16_16(48.4733727810651 / FREQUENCY_RATE), + float_to_fp16_16(48.5092524056255 / FREQUENCY_RATE), + float_to_fp16_16(48.5451851851852 / FREQUENCY_RATE), + float_to_fp16_16(48.581171237954 / FREQUENCY_RATE), + float_to_fp16_16(48.6172106824926 / FREQUENCY_RATE), + float_to_fp16_16(48.6533036377134 / FREQUENCY_RATE), + float_to_fp16_16(48.6894502228826 / FREQUENCY_RATE), + float_to_fp16_16(48.7256505576208 / FREQUENCY_RATE), + float_to_fp16_16(48.7619047619048 / FREQUENCY_RATE), + float_to_fp16_16(48.7982129560685 / FREQUENCY_RATE), + float_to_fp16_16(48.8345752608048 / FREQUENCY_RATE), + float_to_fp16_16(48.8709917971663 / FREQUENCY_RATE), + float_to_fp16_16(48.9074626865672 / FREQUENCY_RATE), + float_to_fp16_16(48.9439880507842 / FREQUENCY_RATE), + float_to_fp16_16(48.9805680119582 / FREQUENCY_RATE), + float_to_fp16_16(49.0172026925954 / FREQUENCY_RATE), + float_to_fp16_16(49.0538922155689 / FREQUENCY_RATE), + float_to_fp16_16(49.0906367041199 / FREQUENCY_RATE), + float_to_fp16_16(49.1274362818591 / FREQUENCY_RATE), + float_to_fp16_16(49.1642910727682 / FREQUENCY_RATE), + float_to_fp16_16(49.2012012012012 / FREQUENCY_RATE), + float_to_fp16_16(49.2381667918858 / FREQUENCY_RATE), + float_to_fp16_16(49.2751879699248 / FREQUENCY_RATE), + float_to_fp16_16(49.3122648607976 / FREQUENCY_RATE), + float_to_fp16_16(49.3493975903615 / FREQUENCY_RATE), + float_to_fp16_16(49.3865862848531 / FREQUENCY_RATE), + float_to_fp16_16(49.4238310708899 / FREQUENCY_RATE), + float_to_fp16_16(49.4611320754717 / FREQUENCY_RATE), + float_to_fp16_16(49.4984894259819 / FREQUENCY_RATE), + float_to_fp16_16(49.535903250189 / FREQUENCY_RATE), + float_to_fp16_16(49.5733736762481 / FREQUENCY_RATE), + float_to_fp16_16(49.6109008327025 / FREQUENCY_RATE), + float_to_fp16_16(49.6484848484849 / FREQUENCY_RATE), + float_to_fp16_16(49.6861258529189 / FREQUENCY_RATE), + float_to_fp16_16(49.7238239757208 / FREQUENCY_RATE), + float_to_fp16_16(49.7615793470008 / FREQUENCY_RATE), + float_to_fp16_16(49.7993920972644 / FREQUENCY_RATE), + float_to_fp16_16(49.8372623574145 / FREQUENCY_RATE), + float_to_fp16_16(49.8751902587519 / FREQUENCY_RATE), + float_to_fp16_16(49.9131759329779 / FREQUENCY_RATE), + float_to_fp16_16(49.9512195121951 / FREQUENCY_RATE), + float_to_fp16_16(49.9893211289092 / FREQUENCY_RATE), + float_to_fp16_16(50.0274809160305 / FREQUENCY_RATE), + float_to_fp16_16(50.0656990068755 / FREQUENCY_RATE), + float_to_fp16_16(50.1039755351682 / FREQUENCY_RATE), + float_to_fp16_16(50.1423106350421 / FREQUENCY_RATE), + float_to_fp16_16(50.1807044410413 / FREQUENCY_RATE), + float_to_fp16_16(50.2191570881226 / FREQUENCY_RATE), + float_to_fp16_16(50.2576687116564 / FREQUENCY_RATE), + float_to_fp16_16(50.296239447429 / FREQUENCY_RATE), + float_to_fp16_16(50.3348694316436 / FREQUENCY_RATE), + float_to_fp16_16(50.3735588009224 / FREQUENCY_RATE), + float_to_fp16_16(50.4123076923077 / FREQUENCY_RATE), + float_to_fp16_16(50.451116243264 / FREQUENCY_RATE), + float_to_fp16_16(50.4899845916795 / FREQUENCY_RATE), + float_to_fp16_16(50.5289128758674 / FREQUENCY_RATE), + float_to_fp16_16(50.5679012345679 / FREQUENCY_RATE), + float_to_fp16_16(50.6069498069498 / FREQUENCY_RATE), + float_to_fp16_16(50.6460587326121 / FREQUENCY_RATE), + float_to_fp16_16(50.6852281515855 / FREQUENCY_RATE), + float_to_fp16_16(50.7244582043344 / FREQUENCY_RATE), + float_to_fp16_16(50.7637490317583 / FREQUENCY_RATE), + float_to_fp16_16(50.8031007751938 / FREQUENCY_RATE), + float_to_fp16_16(50.8425135764158 / FREQUENCY_RATE), + float_to_fp16_16(50.8819875776397 / FREQUENCY_RATE), + float_to_fp16_16(50.9215229215229 / FREQUENCY_RATE), + float_to_fp16_16(50.9611197511664 / FREQUENCY_RATE), + float_to_fp16_16(51.0007782101167 / FREQUENCY_RATE), + float_to_fp16_16(51.0404984423676 / FREQUENCY_RATE), + float_to_fp16_16(51.0802805923617 / FREQUENCY_RATE), + float_to_fp16_16(51.1201248049922 / FREQUENCY_RATE), + float_to_fp16_16(51.160031225605 / FREQUENCY_RATE), + float_to_fp16_16(51.2 / FREQUENCY_RATE), + float_to_fp16_16(51.2400312744331 / FREQUENCY_RATE), + float_to_fp16_16(51.2801251956182 / FREQUENCY_RATE), + float_to_fp16_16(51.3202819107283 / FREQUENCY_RATE), + float_to_fp16_16(51.3605015673981 / FREQUENCY_RATE), + float_to_fp16_16(51.4007843137255 / FREQUENCY_RATE), + float_to_fp16_16(51.4411302982732 / FREQUENCY_RATE), + float_to_fp16_16(51.4815396700707 / FREQUENCY_RATE), + float_to_fp16_16(51.5220125786164 / FREQUENCY_RATE), + float_to_fp16_16(51.5625491738788 / FREQUENCY_RATE), + float_to_fp16_16(51.6031496062992 / FREQUENCY_RATE), + float_to_fp16_16(51.6438140267928 / FREQUENCY_RATE), + float_to_fp16_16(51.6845425867508 / FREQUENCY_RATE), + float_to_fp16_16(51.7253354380426 / FREQUENCY_RATE), + float_to_fp16_16(51.7661927330174 / FREQUENCY_RATE), + float_to_fp16_16(51.8071146245059 / FREQUENCY_RATE), + float_to_fp16_16(51.8481012658228 / FREQUENCY_RATE), + float_to_fp16_16(51.889152810768 / FREQUENCY_RATE), + float_to_fp16_16(51.9302694136292 / FREQUENCY_RATE), + float_to_fp16_16(51.9714512291832 / FREQUENCY_RATE), + float_to_fp16_16(52.0126984126984 / FREQUENCY_RATE), + float_to_fp16_16(52.0540111199365 / FREQUENCY_RATE), + float_to_fp16_16(52.0953895071542 / FREQUENCY_RATE), + float_to_fp16_16(52.1368337311058 / FREQUENCY_RATE), + float_to_fp16_16(52.1783439490446 / FREQUENCY_RATE), + float_to_fp16_16(52.2199203187251 / FREQUENCY_RATE), + float_to_fp16_16(52.2615629984051 / FREQUENCY_RATE), + float_to_fp16_16(52.3032721468476 / FREQUENCY_RATE), + float_to_fp16_16(52.3450479233227 / FREQUENCY_RATE), + float_to_fp16_16(52.3868904876099 / FREQUENCY_RATE), + float_to_fp16_16(52.4288 / FREQUENCY_RATE), + float_to_fp16_16(52.470776621297 / FREQUENCY_RATE), + float_to_fp16_16(52.5128205128205 / FREQUENCY_RATE), + float_to_fp16_16(52.5549318364074 / FREQUENCY_RATE), + float_to_fp16_16(52.5971107544141 / FREQUENCY_RATE), + float_to_fp16_16(52.6393574297189 / FREQUENCY_RATE), + float_to_fp16_16(52.6816720257235 / FREQUENCY_RATE), + float_to_fp16_16(52.7240547063556 / FREQUENCY_RATE), + float_to_fp16_16(52.7665056360709 / FREQUENCY_RATE), + float_to_fp16_16(52.809024979855 / FREQUENCY_RATE), + float_to_fp16_16(52.8516129032258 / FREQUENCY_RATE), + float_to_fp16_16(52.8942695722357 / FREQUENCY_RATE), + float_to_fp16_16(52.9369951534734 / FREQUENCY_RATE), + float_to_fp16_16(52.9797898140663 / FREQUENCY_RATE), + float_to_fp16_16(53.0226537216829 / FREQUENCY_RATE), + float_to_fp16_16(53.0655870445344 / FREQUENCY_RATE), + float_to_fp16_16(53.1085899513776 / FREQUENCY_RATE), + float_to_fp16_16(53.1516626115166 / FREQUENCY_RATE), + float_to_fp16_16(53.1948051948052 / FREQUENCY_RATE), + float_to_fp16_16(53.2380178716491 / FREQUENCY_RATE), + float_to_fp16_16(53.2813008130081 / FREQUENCY_RATE), + float_to_fp16_16(53.3246541903987 / FREQUENCY_RATE), + float_to_fp16_16(53.3680781758958 / FREQUENCY_RATE), + float_to_fp16_16(53.4115729421353 / FREQUENCY_RATE), + float_to_fp16_16(53.4551386623165 / FREQUENCY_RATE), + float_to_fp16_16(53.4987755102041 / FREQUENCY_RATE), + float_to_fp16_16(53.5424836601307 / FREQUENCY_RATE), + float_to_fp16_16(53.5862632869992 / FREQUENCY_RATE), + float_to_fp16_16(53.6301145662848 / FREQUENCY_RATE), + float_to_fp16_16(53.6740376740377 / FREQUENCY_RATE), + float_to_fp16_16(53.7180327868852 / FREQUENCY_RATE), + float_to_fp16_16(53.7621000820345 / FREQUENCY_RATE), + float_to_fp16_16(53.8062397372742 / FREQUENCY_RATE), + float_to_fp16_16(53.8504519309778 / FREQUENCY_RATE), + float_to_fp16_16(53.8947368421053 / FREQUENCY_RATE), + float_to_fp16_16(53.9390946502058 / FREQUENCY_RATE), + float_to_fp16_16(53.9835255354201 / FREQUENCY_RATE), + float_to_fp16_16(54.0280296784831 / FREQUENCY_RATE), + float_to_fp16_16(54.0726072607261 / FREQUENCY_RATE), + float_to_fp16_16(54.1172584640793 / FREQUENCY_RATE), + float_to_fp16_16(54.1619834710744 / FREQUENCY_RATE), + float_to_fp16_16(54.206782464847 / FREQUENCY_RATE), + float_to_fp16_16(54.2516556291391 / FREQUENCY_RATE), + float_to_fp16_16(54.2966031483016 / FREQUENCY_RATE), + float_to_fp16_16(54.3416252072969 / FREQUENCY_RATE), + float_to_fp16_16(54.3867219917012 / FREQUENCY_RATE), + float_to_fp16_16(54.4318936877076 / FREQUENCY_RATE), + float_to_fp16_16(54.477140482128 / FREQUENCY_RATE), + float_to_fp16_16(54.522462562396 / FREQUENCY_RATE), + float_to_fp16_16(54.5678601165695 / FREQUENCY_RATE), + float_to_fp16_16(54.6133333333333 / FREQUENCY_RATE), + float_to_fp16_16(54.6588824020017 / FREQUENCY_RATE), + float_to_fp16_16(54.7045075125209 / FREQUENCY_RATE), + float_to_fp16_16(54.750208855472 / FREQUENCY_RATE), + float_to_fp16_16(54.7959866220736 / FREQUENCY_RATE), + float_to_fp16_16(54.8418410041841 / FREQUENCY_RATE), + float_to_fp16_16(54.8877721943049 / FREQUENCY_RATE), + float_to_fp16_16(54.9337803855826 / FREQUENCY_RATE), + float_to_fp16_16(54.9798657718121 / FREQUENCY_RATE), + float_to_fp16_16(55.0260285474391 / FREQUENCY_RATE), + float_to_fp16_16(55.072268907563 / FREQUENCY_RATE), + float_to_fp16_16(55.1185870479394 / FREQUENCY_RATE), + float_to_fp16_16(55.1649831649832 / FREQUENCY_RATE), + float_to_fp16_16(55.2114574557709 / FREQUENCY_RATE), + float_to_fp16_16(55.2580101180438 / FREQUENCY_RATE), + float_to_fp16_16(55.304641350211 / FREQUENCY_RATE), + float_to_fp16_16(55.3513513513514 / FREQUENCY_RATE), + float_to_fp16_16(55.3981403212172 / FREQUENCY_RATE), + float_to_fp16_16(55.4450084602369 / FREQUENCY_RATE), + float_to_fp16_16(55.4919559695174 / FREQUENCY_RATE), + float_to_fp16_16(55.5389830508475 / FREQUENCY_RATE), + float_to_fp16_16(55.5860899067006 / FREQUENCY_RATE), + float_to_fp16_16(55.6332767402377 / FREQUENCY_RATE), + float_to_fp16_16(55.6805437553101 / FREQUENCY_RATE), + float_to_fp16_16(55.7278911564626 / FREQUENCY_RATE), + float_to_fp16_16(55.7753191489362 / FREQUENCY_RATE), + float_to_fp16_16(55.8228279386712 / FREQUENCY_RATE), + float_to_fp16_16(55.8704177323103 / FREQUENCY_RATE), + float_to_fp16_16(55.9180887372014 / FREQUENCY_RATE), + float_to_fp16_16(55.9658411614005 / FREQUENCY_RATE), + float_to_fp16_16(56.0136752136752 / FREQUENCY_RATE), + float_to_fp16_16(56.0615911035073 / FREQUENCY_RATE), + float_to_fp16_16(56.1095890410959 / FREQUENCY_RATE), + float_to_fp16_16(56.1576692373608 / FREQUENCY_RATE), + float_to_fp16_16(56.2058319039451 / FREQUENCY_RATE), + float_to_fp16_16(56.2540772532189 / FREQUENCY_RATE), + float_to_fp16_16(56.3024054982818 / FREQUENCY_RATE), + float_to_fp16_16(56.3508168529665 / FREQUENCY_RATE), + float_to_fp16_16(56.3993115318417 / FREQUENCY_RATE), + float_to_fp16_16(56.4478897502153 / FREQUENCY_RATE), + float_to_fp16_16(56.4965517241379 / FREQUENCY_RATE), + float_to_fp16_16(56.5452976704055 / FREQUENCY_RATE), + float_to_fp16_16(56.594127806563 / FREQUENCY_RATE), + float_to_fp16_16(56.6430423509075 / FREQUENCY_RATE), + float_to_fp16_16(56.6920415224914 / FREQUENCY_RATE), + float_to_fp16_16(56.7411255411255 / FREQUENCY_RATE), + float_to_fp16_16(56.790294627383 / FREQUENCY_RATE), + float_to_fp16_16(56.8395490026019 / FREQUENCY_RATE), + float_to_fp16_16(56.8888888888889 / FREQUENCY_RATE), + float_to_fp16_16(56.9383145091225 / FREQUENCY_RATE), + float_to_fp16_16(56.9878260869565 / FREQUENCY_RATE), + float_to_fp16_16(57.0374238468233 / FREQUENCY_RATE), + float_to_fp16_16(57.0871080139373 / FREQUENCY_RATE), + float_to_fp16_16(57.1368788142982 / FREQUENCY_RATE), + float_to_fp16_16(57.1867364746946 / FREQUENCY_RATE), + float_to_fp16_16(57.2366812227074 / FREQUENCY_RATE), + float_to_fp16_16(57.2867132867133 / FREQUENCY_RATE), + float_to_fp16_16(57.336832895888 / FREQUENCY_RATE), + float_to_fp16_16(57.3870402802102 / FREQUENCY_RATE), + float_to_fp16_16(57.4373356704645 / FREQUENCY_RATE), + float_to_fp16_16(57.4877192982456 / FREQUENCY_RATE), + float_to_fp16_16(57.5381913959614 / FREQUENCY_RATE), + float_to_fp16_16(57.5887521968366 / FREQUENCY_RATE), + float_to_fp16_16(57.6394019349165 / FREQUENCY_RATE), + float_to_fp16_16(57.6901408450704 / FREQUENCY_RATE), + float_to_fp16_16(57.7409691629956 / FREQUENCY_RATE), + float_to_fp16_16(57.7918871252205 / FREQUENCY_RATE), + float_to_fp16_16(57.8428949691086 / FREQUENCY_RATE), + float_to_fp16_16(57.8939929328622 / FREQUENCY_RATE), + float_to_fp16_16(57.9451812555261 / FREQUENCY_RATE), + float_to_fp16_16(57.9964601769912 / FREQUENCY_RATE), + float_to_fp16_16(58.0478299379982 / FREQUENCY_RATE), + float_to_fp16_16(58.0992907801418 / FREQUENCY_RATE), + float_to_fp16_16(58.150842945874 / FREQUENCY_RATE), + float_to_fp16_16(58.202486678508 / FREQUENCY_RATE), + float_to_fp16_16(58.2542222222222 / FREQUENCY_RATE), + float_to_fp16_16(58.3060498220641 / FREQUENCY_RATE), + float_to_fp16_16(58.3579697239537 / FREQUENCY_RATE), + float_to_fp16_16(58.4099821746881 / FREQUENCY_RATE), + float_to_fp16_16(58.4620874219447 / FREQUENCY_RATE), + float_to_fp16_16(58.5142857142857 / FREQUENCY_RATE), + float_to_fp16_16(58.5665773011618 / FREQUENCY_RATE), + float_to_fp16_16(58.6189624329159 / FREQUENCY_RATE), + float_to_fp16_16(58.6714413607878 / FREQUENCY_RATE), + float_to_fp16_16(58.7240143369176 / FREQUENCY_RATE), + float_to_fp16_16(58.7766816143498 / FREQUENCY_RATE), + float_to_fp16_16(58.8294434470377 / FREQUENCY_RATE), + float_to_fp16_16(58.8823000898473 / FREQUENCY_RATE), + float_to_fp16_16(58.9352517985612 / FREQUENCY_RATE), + float_to_fp16_16(58.988298829883 / FREQUENCY_RATE), + float_to_fp16_16(59.0414414414414 / FREQUENCY_RATE), + float_to_fp16_16(59.0946798917944 / FREQUENCY_RATE), + float_to_fp16_16(59.1480144404332 / FREQUENCY_RATE), + float_to_fp16_16(59.2014453477868 / FREQUENCY_RATE), + float_to_fp16_16(59.254972875226 / FREQUENCY_RATE), + float_to_fp16_16(59.3085972850679 / FREQUENCY_RATE), + float_to_fp16_16(59.3623188405797 / FREQUENCY_RATE), + float_to_fp16_16(59.4161378059837 / FREQUENCY_RATE), + float_to_fp16_16(59.470054446461 / FREQUENCY_RATE), + float_to_fp16_16(59.5240690281562 / FREQUENCY_RATE), + float_to_fp16_16(59.5781818181818 / FREQUENCY_RATE), + float_to_fp16_16(59.6323930846224 / FREQUENCY_RATE), + float_to_fp16_16(59.6867030965392 / FREQUENCY_RATE), + float_to_fp16_16(59.7411121239745 / FREQUENCY_RATE), + float_to_fp16_16(59.7956204379562 / FREQUENCY_RATE), + float_to_fp16_16(59.8502283105023 / FREQUENCY_RATE), + float_to_fp16_16(59.9049360146252 / FREQUENCY_RATE), + float_to_fp16_16(59.9597438243367 / FREQUENCY_RATE), + float_to_fp16_16(60.014652014652 / FREQUENCY_RATE), + float_to_fp16_16(60.0696608615949 / FREQUENCY_RATE), + float_to_fp16_16(60.1247706422018 / FREQUENCY_RATE), + float_to_fp16_16(60.1799816345271 / FREQUENCY_RATE), + float_to_fp16_16(60.2352941176471 / FREQUENCY_RATE), + float_to_fp16_16(60.2907083716651 / FREQUENCY_RATE), + float_to_fp16_16(60.3462246777164 / FREQUENCY_RATE), + float_to_fp16_16(60.4018433179724 / FREQUENCY_RATE), + float_to_fp16_16(60.4575645756458 / FREQUENCY_RATE), + float_to_fp16_16(60.5133887349954 / FREQUENCY_RATE), + float_to_fp16_16(60.5693160813309 / FREQUENCY_RATE), + float_to_fp16_16(60.6253469010176 / FREQUENCY_RATE), + float_to_fp16_16(60.6814814814815 / FREQUENCY_RATE), + float_to_fp16_16(60.7377201112141 / FREQUENCY_RATE), + float_to_fp16_16(60.7940630797774 / FREQUENCY_RATE), + float_to_fp16_16(60.8505106778087 / FREQUENCY_RATE), + float_to_fp16_16(60.907063197026 / FREQUENCY_RATE), + float_to_fp16_16(60.9637209302326 / FREQUENCY_RATE), + float_to_fp16_16(61.0204841713222 / FREQUENCY_RATE), + float_to_fp16_16(61.0773532152843 / FREQUENCY_RATE), + float_to_fp16_16(61.134328358209 / FREQUENCY_RATE), + float_to_fp16_16(61.1914098972923 / FREQUENCY_RATE), + float_to_fp16_16(61.2485981308411 / FREQUENCY_RATE), + float_to_fp16_16(61.3058933582788 / FREQUENCY_RATE), + float_to_fp16_16(61.3632958801498 / FREQUENCY_RATE), + float_to_fp16_16(61.4208059981256 / FREQUENCY_RATE), + float_to_fp16_16(61.4784240150094 / FREQUENCY_RATE), + float_to_fp16_16(61.5361502347418 / FREQUENCY_RATE), + float_to_fp16_16(61.593984962406 / FREQUENCY_RATE), + float_to_fp16_16(61.6519285042333 / FREQUENCY_RATE), + float_to_fp16_16(61.7099811676083 / FREQUENCY_RATE), + float_to_fp16_16(61.7681432610745 / FREQUENCY_RATE), + float_to_fp16_16(61.8264150943396 / FREQUENCY_RATE), + float_to_fp16_16(61.8847969782814 / FREQUENCY_RATE), + float_to_fp16_16(61.9432892249527 / FREQUENCY_RATE), + float_to_fp16_16(62.0018921475875 / FREQUENCY_RATE), + float_to_fp16_16(62.0606060606061 / FREQUENCY_RATE), + float_to_fp16_16(62.1194312796209 / FREQUENCY_RATE), + float_to_fp16_16(62.1783681214421 / FREQUENCY_RATE), + float_to_fp16_16(62.2374169040836 / FREQUENCY_RATE), + float_to_fp16_16(62.2965779467681 / FREQUENCY_RATE), + float_to_fp16_16(62.3558515699334 / FREQUENCY_RATE), + float_to_fp16_16(62.4152380952381 / FREQUENCY_RATE), + float_to_fp16_16(62.4747378455672 / FREQUENCY_RATE), + float_to_fp16_16(62.5343511450382 / FREQUENCY_RATE), + float_to_fp16_16(62.5940783190067 / FREQUENCY_RATE), + float_to_fp16_16(62.6539196940727 / FREQUENCY_RATE), + float_to_fp16_16(62.7138755980861 / FREQUENCY_RATE), + float_to_fp16_16(62.7739463601533 / FREQUENCY_RATE), + float_to_fp16_16(62.8341323106424 / FREQUENCY_RATE), + float_to_fp16_16(62.89443378119 / FREQUENCY_RATE), + float_to_fp16_16(62.954851104707 / FREQUENCY_RATE), + float_to_fp16_16(63.0153846153846 / FREQUENCY_RATE), + float_to_fp16_16(63.0760346487007 / FREQUENCY_RATE), + float_to_fp16_16(63.1368015414258 / FREQUENCY_RATE), + float_to_fp16_16(63.1976856316297 / FREQUENCY_RATE), + float_to_fp16_16(63.2586872586873 / FREQUENCY_RATE), + float_to_fp16_16(63.319806763285 / FREQUENCY_RATE), + float_to_fp16_16(63.3810444874275 / FREQUENCY_RATE), + float_to_fp16_16(63.4424007744434 / FREQUENCY_RATE), + float_to_fp16_16(63.5038759689923 / FREQUENCY_RATE), + float_to_fp16_16(63.5654704170708 / FREQUENCY_RATE), + float_to_fp16_16(63.6271844660194 / FREQUENCY_RATE), + float_to_fp16_16(63.6890184645287 / FREQUENCY_RATE), + float_to_fp16_16(63.7509727626459 / FREQUENCY_RATE), + float_to_fp16_16(63.8130477117819 / FREQUENCY_RATE), + float_to_fp16_16(63.8752436647174 / FREQUENCY_RATE), + float_to_fp16_16(63.9375609756098 / FREQUENCY_RATE), + float_to_fp16_16(64 / FREQUENCY_RATE), + float_to_fp16_16(64.0625610948192 / FREQUENCY_RATE), + float_to_fp16_16(64.1252446183953 / FREQUENCY_RATE), + float_to_fp16_16(64.1880509304603 / FREQUENCY_RATE), + float_to_fp16_16(64.2509803921569 / FREQUENCY_RATE), + float_to_fp16_16(64.3140333660451 / FREQUENCY_RATE), + float_to_fp16_16(64.37721021611 / FREQUENCY_RATE), + float_to_fp16_16(64.440511307768 / FREQUENCY_RATE), + float_to_fp16_16(64.503937007874 / FREQUENCY_RATE), + float_to_fp16_16(64.5674876847291 / FREQUENCY_RATE), + float_to_fp16_16(64.6311637080868 / FREQUENCY_RATE), + float_to_fp16_16(64.6949654491609 / FREQUENCY_RATE), + float_to_fp16_16(64.7588932806324 / FREQUENCY_RATE), + float_to_fp16_16(64.8229475766568 / FREQUENCY_RATE), + float_to_fp16_16(64.8871287128713 / FREQUENCY_RATE), + float_to_fp16_16(64.9514370664024 / FREQUENCY_RATE), + float_to_fp16_16(65.015873015873 / FREQUENCY_RATE), + float_to_fp16_16(65.0804369414101 / FREQUENCY_RATE), + float_to_fp16_16(65.1451292246521 / FREQUENCY_RATE), + float_to_fp16_16(65.2099502487562 / FREQUENCY_RATE), + float_to_fp16_16(65.2749003984064 / FREQUENCY_RATE), + float_to_fp16_16(65.3399800598205 / FREQUENCY_RATE), + float_to_fp16_16(65.4051896207585 / FREQUENCY_RATE), + float_to_fp16_16(65.4705294705295 / FREQUENCY_RATE), + float_to_fp16_16(65.536 / FREQUENCY_RATE), + float_to_fp16_16(65.6016016016016 / FREQUENCY_RATE), + float_to_fp16_16(65.6673346693387 / FREQUENCY_RATE), + float_to_fp16_16(65.7331995987964 / FREQUENCY_RATE), + float_to_fp16_16(65.7991967871486 / FREQUENCY_RATE), + float_to_fp16_16(65.8653266331658 / FREQUENCY_RATE), + float_to_fp16_16(65.9315895372234 / FREQUENCY_RATE), + float_to_fp16_16(65.9979859013092 / FREQUENCY_RATE), + float_to_fp16_16(66.0645161290323 / FREQUENCY_RATE), + float_to_fp16_16(66.1311806256307 / FREQUENCY_RATE), + float_to_fp16_16(66.1979797979798 / FREQUENCY_RATE), + float_to_fp16_16(66.2649140546006 / FREQUENCY_RATE), + float_to_fp16_16(66.331983805668 / FREQUENCY_RATE), + float_to_fp16_16(66.3991894630193 / FREQUENCY_RATE), + float_to_fp16_16(66.4665314401623 / FREQUENCY_RATE), + float_to_fp16_16(66.5340101522843 / FREQUENCY_RATE), + float_to_fp16_16(66.6016260162602 / FREQUENCY_RATE), + float_to_fp16_16(66.6693794506612 / FREQUENCY_RATE), + float_to_fp16_16(66.7372708757637 / FREQUENCY_RATE), + float_to_fp16_16(66.8053007135576 / FREQUENCY_RATE), + float_to_fp16_16(66.8734693877551 / FREQUENCY_RATE), + float_to_fp16_16(66.9417773237998 / FREQUENCY_RATE), + float_to_fp16_16(67.0102249488753 / FREQUENCY_RATE), + float_to_fp16_16(67.078812691914 / FREQUENCY_RATE), + float_to_fp16_16(67.1475409836066 / FREQUENCY_RATE), + float_to_fp16_16(67.2164102564103 / FREQUENCY_RATE), + float_to_fp16_16(67.2854209445585 / FREQUENCY_RATE), + float_to_fp16_16(67.3545734840699 / FREQUENCY_RATE), + float_to_fp16_16(67.4238683127572 / FREQUENCY_RATE), + float_to_fp16_16(67.4933058702369 / FREQUENCY_RATE), + float_to_fp16_16(67.5628865979382 / FREQUENCY_RATE), + float_to_fp16_16(67.6326109391125 / FREQUENCY_RATE), + float_to_fp16_16(67.702479338843 / FREQUENCY_RATE), + float_to_fp16_16(67.7724922440538 / FREQUENCY_RATE), + float_to_fp16_16(67.8426501035197 / FREQUENCY_RATE), + float_to_fp16_16(67.9129533678757 / FREQUENCY_RATE), + float_to_fp16_16(67.9834024896266 / FREQUENCY_RATE), + float_to_fp16_16(68.0539979231568 / FREQUENCY_RATE), + float_to_fp16_16(68.1247401247401 / FREQUENCY_RATE), + float_to_fp16_16(68.1956295525494 / FREQUENCY_RATE), + float_to_fp16_16(68.2666666666667 / FREQUENCY_RATE), + float_to_fp16_16(68.3378519290928 / FREQUENCY_RATE), + float_to_fp16_16(68.4091858037578 / FREQUENCY_RATE), + float_to_fp16_16(68.4806687565308 / FREQUENCY_RATE), + float_to_fp16_16(68.5523012552301 / FREQUENCY_RATE), + float_to_fp16_16(68.6240837696335 / FREQUENCY_RATE), + float_to_fp16_16(68.6960167714885 / FREQUENCY_RATE), + float_to_fp16_16(68.7681007345226 / FREQUENCY_RATE), + float_to_fp16_16(68.8403361344538 / FREQUENCY_RATE), + float_to_fp16_16(68.9127234490011 / FREQUENCY_RATE), + float_to_fp16_16(68.9852631578947 / FREQUENCY_RATE), + float_to_fp16_16(69.0579557428872 / FREQUENCY_RATE), + float_to_fp16_16(69.1308016877637 / FREQUENCY_RATE), + float_to_fp16_16(69.2038014783527 / FREQUENCY_RATE), + float_to_fp16_16(69.276955602537 / FREQUENCY_RATE), + float_to_fp16_16(69.3502645502646 / FREQUENCY_RATE), + float_to_fp16_16(69.4237288135593 / FREQUENCY_RATE), + float_to_fp16_16(69.4973488865324 / FREQUENCY_RATE), + float_to_fp16_16(69.5711252653928 / FREQUENCY_RATE), + float_to_fp16_16(69.6450584484591 / FREQUENCY_RATE), + float_to_fp16_16(69.7191489361702 / FREQUENCY_RATE), + float_to_fp16_16(69.7933972310969 / FREQUENCY_RATE), + float_to_fp16_16(69.8678038379531 / FREQUENCY_RATE), + float_to_fp16_16(69.9423692636073 / FREQUENCY_RATE), + float_to_fp16_16(70.017094017094 / FREQUENCY_RATE), + float_to_fp16_16(70.0919786096257 / FREQUENCY_RATE), + float_to_fp16_16(70.1670235546039 / FREQUENCY_RATE), + float_to_fp16_16(70.2422293676313 / FREQUENCY_RATE), + float_to_fp16_16(70.3175965665236 / FREQUENCY_RATE), + float_to_fp16_16(70.3931256713212 / FREQUENCY_RATE), + float_to_fp16_16(70.4688172043011 / FREQUENCY_RATE), + float_to_fp16_16(70.5446716899892 / FREQUENCY_RATE), + float_to_fp16_16(70.6206896551724 / FREQUENCY_RATE), + float_to_fp16_16(70.6968716289105 / FREQUENCY_RATE), + float_to_fp16_16(70.7732181425486 / FREQUENCY_RATE), + float_to_fp16_16(70.8497297297297 / FREQUENCY_RATE), + float_to_fp16_16(70.9264069264069 / FREQUENCY_RATE), + float_to_fp16_16(71.0032502708559 / FREQUENCY_RATE), + float_to_fp16_16(71.0802603036876 / FREQUENCY_RATE), + float_to_fp16_16(71.157437567861 / FREQUENCY_RATE), + float_to_fp16_16(71.2347826086957 / FREQUENCY_RATE), + float_to_fp16_16(71.3122959738847 / FREQUENCY_RATE), + float_to_fp16_16(71.3899782135076 / FREQUENCY_RATE), + float_to_fp16_16(71.4678298800436 / FREQUENCY_RATE), + float_to_fp16_16(71.5458515283843 / FREQUENCY_RATE), + float_to_fp16_16(71.624043715847 / FREQUENCY_RATE), + float_to_fp16_16(71.7024070021882 / FREQUENCY_RATE), + float_to_fp16_16(71.7809419496166 / FREQUENCY_RATE), + float_to_fp16_16(71.859649122807 / FREQUENCY_RATE), + float_to_fp16_16(71.9385290889133 / FREQUENCY_RATE), + float_to_fp16_16(72.0175824175824 / FREQUENCY_RATE), + float_to_fp16_16(72.0968096809681 / FREQUENCY_RATE), + float_to_fp16_16(72.1762114537445 / FREQUENCY_RATE), + float_to_fp16_16(72.2557883131202 / FREQUENCY_RATE), + float_to_fp16_16(72.3355408388521 / FREQUENCY_RATE), + float_to_fp16_16(72.4154696132597 / FREQUENCY_RATE), + float_to_fp16_16(72.4955752212389 / FREQUENCY_RATE), + float_to_fp16_16(72.5758582502769 / FREQUENCY_RATE), + float_to_fp16_16(72.6563192904656 / FREQUENCY_RATE), + float_to_fp16_16(72.7369589345172 / FREQUENCY_RATE), + float_to_fp16_16(72.8177777777778 / FREQUENCY_RATE), + float_to_fp16_16(72.8987764182425 / FREQUENCY_RATE), + float_to_fp16_16(72.9799554565702 / FREQUENCY_RATE), + float_to_fp16_16(73.0613154960981 / FREQUENCY_RATE), + float_to_fp16_16(73.1428571428571 / FREQUENCY_RATE), + float_to_fp16_16(73.2245810055866 / FREQUENCY_RATE), + float_to_fp16_16(73.3064876957494 / FREQUENCY_RATE), + float_to_fp16_16(73.3885778275476 / FREQUENCY_RATE), + float_to_fp16_16(73.4708520179372 / FREQUENCY_RATE), + float_to_fp16_16(73.5533108866442 / FREQUENCY_RATE), + float_to_fp16_16(73.6359550561798 / FREQUENCY_RATE), + float_to_fp16_16(73.718785151856 / FREQUENCY_RATE), + float_to_fp16_16(73.8018018018018 / FREQUENCY_RATE), + float_to_fp16_16(73.8850056369786 / FREQUENCY_RATE), + float_to_fp16_16(73.9683972911964 / FREQUENCY_RATE), + float_to_fp16_16(74.0519774011299 / FREQUENCY_RATE), + float_to_fp16_16(74.1357466063348 / FREQUENCY_RATE), + float_to_fp16_16(74.2197055492639 / FREQUENCY_RATE), + float_to_fp16_16(74.3038548752835 / FREQUENCY_RATE), + float_to_fp16_16(74.3881952326901 / FREQUENCY_RATE), + float_to_fp16_16(74.4727272727273 / FREQUENCY_RATE), + float_to_fp16_16(74.5574516496018 / FREQUENCY_RATE), + float_to_fp16_16(74.6423690205011 / FREQUENCY_RATE), + float_to_fp16_16(74.72748004561 / FREQUENCY_RATE), + float_to_fp16_16(74.8127853881279 / FREQUENCY_RATE), + float_to_fp16_16(74.8982857142857 / FREQUENCY_RATE), + float_to_fp16_16(74.9839816933639 / FREQUENCY_RATE), + float_to_fp16_16(75.0698739977091 / FREQUENCY_RATE), + float_to_fp16_16(75.1559633027523 / FREQUENCY_RATE), + float_to_fp16_16(75.2422502870264 / FREQUENCY_RATE), + float_to_fp16_16(75.3287356321839 / FREQUENCY_RATE), + float_to_fp16_16(75.415420023015 / FREQUENCY_RATE), + float_to_fp16_16(75.5023041474654 / FREQUENCY_RATE), + float_to_fp16_16(75.5893886966551 / FREQUENCY_RATE), + float_to_fp16_16(75.6766743648961 / FREQUENCY_RATE), + float_to_fp16_16(75.764161849711 / FREQUENCY_RATE), + float_to_fp16_16(75.8518518518518 / FREQUENCY_RATE), + float_to_fp16_16(75.9397450753187 / FREQUENCY_RATE), + float_to_fp16_16(76.0278422273782 / FREQUENCY_RATE), + float_to_fp16_16(76.116144018583 / FREQUENCY_RATE), + float_to_fp16_16(76.2046511627907 / FREQUENCY_RATE), + float_to_fp16_16(76.2933643771828 / FREQUENCY_RATE), + float_to_fp16_16(76.3822843822844 / FREQUENCY_RATE), + float_to_fp16_16(76.4714119019837 / FREQUENCY_RATE), + float_to_fp16_16(76.5607476635514 / FREQUENCY_RATE), + float_to_fp16_16(76.6502923976608 / FREQUENCY_RATE), + float_to_fp16_16(76.7400468384075 / FREQUENCY_RATE), + float_to_fp16_16(76.8300117233294 / FREQUENCY_RATE), + float_to_fp16_16(76.9201877934272 / FREQUENCY_RATE), + float_to_fp16_16(77.0105757931845 / FREQUENCY_RATE), + float_to_fp16_16(77.1011764705882 / FREQUENCY_RATE), + float_to_fp16_16(77.1919905771496 / FREQUENCY_RATE), + float_to_fp16_16(77.2830188679245 / FREQUENCY_RATE), + float_to_fp16_16(77.3742621015348 / FREQUENCY_RATE), + float_to_fp16_16(77.4657210401891 / FREQUENCY_RATE), + float_to_fp16_16(77.5573964497041 / FREQUENCY_RATE), + float_to_fp16_16(77.6492890995261 / FREQUENCY_RATE), + float_to_fp16_16(77.7413997627521 / FREQUENCY_RATE), + float_to_fp16_16(77.833729216152 / FREQUENCY_RATE), + float_to_fp16_16(77.9262782401902 / FREQUENCY_RATE), + float_to_fp16_16(78.0190476190476 / FREQUENCY_RATE), + float_to_fp16_16(78.1120381406436 / FREQUENCY_RATE), + float_to_fp16_16(78.2052505966587 / FREQUENCY_RATE), + float_to_fp16_16(78.2986857825568 / FREQUENCY_RATE), + float_to_fp16_16(78.3923444976077 / FREQUENCY_RATE), + float_to_fp16_16(78.4862275449102 / FREQUENCY_RATE), + float_to_fp16_16(78.5803357314149 / FREQUENCY_RATE), + float_to_fp16_16(78.6746698679472 / FREQUENCY_RATE), + float_to_fp16_16(78.7692307692308 / FREQUENCY_RATE), + float_to_fp16_16(78.864019253911 / FREQUENCY_RATE), + float_to_fp16_16(78.9590361445783 / FREQUENCY_RATE), + float_to_fp16_16(79.0542822677925 / FREQUENCY_RATE), + float_to_fp16_16(79.1497584541063 / FREQUENCY_RATE), + float_to_fp16_16(79.2454655380895 / FREQUENCY_RATE), + float_to_fp16_16(79.3414043583535 / FREQUENCY_RATE), + float_to_fp16_16(79.4375757575758 / FREQUENCY_RATE), + float_to_fp16_16(79.5339805825243 / FREQUENCY_RATE), + float_to_fp16_16(79.6306196840826 / FREQUENCY_RATE), + float_to_fp16_16(79.7274939172749 / FREQUENCY_RATE), + float_to_fp16_16(79.8246041412911 / FREQUENCY_RATE), + float_to_fp16_16(79.9219512195122 / FREQUENCY_RATE), + float_to_fp16_16(80.019536019536 / FREQUENCY_RATE), + float_to_fp16_16(80.1173594132029 / FREQUENCY_RATE), + float_to_fp16_16(80.2154222766218 / FREQUENCY_RATE), + float_to_fp16_16(80.3137254901961 / FREQUENCY_RATE), + float_to_fp16_16(80.4122699386503 / FREQUENCY_RATE), + float_to_fp16_16(80.5110565110565 / FREQUENCY_RATE), + float_to_fp16_16(80.610086100861 / FREQUENCY_RATE), + float_to_fp16_16(80.7093596059113 / FREQUENCY_RATE), + float_to_fp16_16(80.8088779284834 / FREQUENCY_RATE), + float_to_fp16_16(80.9086419753086 / FREQUENCY_RATE), + float_to_fp16_16(81.008652657602 / FREQUENCY_RATE), + float_to_fp16_16(81.1089108910891 / FREQUENCY_RATE), + float_to_fp16_16(81.2094175960347 / FREQUENCY_RATE), + float_to_fp16_16(81.3101736972705 / FREQUENCY_RATE), + float_to_fp16_16(81.4111801242236 / FREQUENCY_RATE), + float_to_fp16_16(81.5124378109453 / FREQUENCY_RATE), + float_to_fp16_16(81.6139476961395 / FREQUENCY_RATE), + float_to_fp16_16(81.715710723192 / FREQUENCY_RATE), + float_to_fp16_16(81.8177278401998 / FREQUENCY_RATE), + float_to_fp16_16(81.92 / FREQUENCY_RATE), + float_to_fp16_16(82.0225281602002 / FREQUENCY_RATE), + float_to_fp16_16(82.125313283208 / FREQUENCY_RATE), + float_to_fp16_16(82.228356336261 / FREQUENCY_RATE), + float_to_fp16_16(82.3316582914573 / FREQUENCY_RATE), + float_to_fp16_16(82.4352201257862 / FREQUENCY_RATE), + float_to_fp16_16(82.5390428211587 / FREQUENCY_RATE), + float_to_fp16_16(82.6431273644388 / FREQUENCY_RATE), + float_to_fp16_16(82.7474747474748 / FREQUENCY_RATE), + float_to_fp16_16(82.8520859671302 / FREQUENCY_RATE), + float_to_fp16_16(82.9569620253165 / FREQUENCY_RATE), + float_to_fp16_16(83.0621039290241 / FREQUENCY_RATE), + float_to_fp16_16(83.1675126903553 / FREQUENCY_RATE), + float_to_fp16_16(83.2731893265565 / FREQUENCY_RATE), + float_to_fp16_16(83.3791348600509 / FREQUENCY_RATE), + float_to_fp16_16(83.4853503184713 / FREQUENCY_RATE), + float_to_fp16_16(83.5918367346939 / FREQUENCY_RATE), + float_to_fp16_16(83.698595146871 / FREQUENCY_RATE), + float_to_fp16_16(83.8056265984655 / FREQUENCY_RATE), + float_to_fp16_16(83.9129321382842 / FREQUENCY_RATE), + float_to_fp16_16(84.0205128205128 / FREQUENCY_RATE), + float_to_fp16_16(84.1283697047497 / FREQUENCY_RATE), + float_to_fp16_16(84.2365038560411 / FREQUENCY_RATE), + float_to_fp16_16(84.3449163449163 / FREQUENCY_RATE), + float_to_fp16_16(84.4536082474227 / FREQUENCY_RATE), + float_to_fp16_16(84.5625806451613 / FREQUENCY_RATE), + float_to_fp16_16(84.671834625323 / FREQUENCY_RATE), + float_to_fp16_16(84.7813712807245 / FREQUENCY_RATE), + float_to_fp16_16(84.8911917098446 / FREQUENCY_RATE), + float_to_fp16_16(85.0012970168612 / FREQUENCY_RATE), + float_to_fp16_16(85.1116883116883 / FREQUENCY_RATE), + float_to_fp16_16(85.222366710013 / FREQUENCY_RATE), + float_to_fp16_16(85.3333333333333 / FREQUENCY_RATE), + float_to_fp16_16(85.4445893089961 / FREQUENCY_RATE), + float_to_fp16_16(85.556135770235 / FREQUENCY_RATE), + float_to_fp16_16(85.6679738562091 / FREQUENCY_RATE), + float_to_fp16_16(85.7801047120419 / FREQUENCY_RATE), + float_to_fp16_16(85.8925294888598 / FREQUENCY_RATE), + float_to_fp16_16(86.005249343832 / FREQUENCY_RATE), + float_to_fp16_16(86.1182654402102 / FREQUENCY_RATE), + float_to_fp16_16(86.2315789473684 / FREQUENCY_RATE), + float_to_fp16_16(86.3451910408432 / FREQUENCY_RATE), + float_to_fp16_16(86.4591029023747 / FREQUENCY_RATE), + float_to_fp16_16(86.5733157199472 / FREQUENCY_RATE), + float_to_fp16_16(86.6878306878307 / FREQUENCY_RATE), + float_to_fp16_16(86.8026490066225 / FREQUENCY_RATE), + float_to_fp16_16(86.9177718832891 / FREQUENCY_RATE), + float_to_fp16_16(87.0332005312085 / FREQUENCY_RATE), + float_to_fp16_16(87.1489361702128 / FREQUENCY_RATE), + float_to_fp16_16(87.2649800266312 / FREQUENCY_RATE), + float_to_fp16_16(87.3813333333333 / FREQUENCY_RATE), + float_to_fp16_16(87.497997329773 / FREQUENCY_RATE), + float_to_fp16_16(87.6149732620321 / FREQUENCY_RATE), + float_to_fp16_16(87.7322623828648 / FREQUENCY_RATE), + float_to_fp16_16(87.8498659517426 / FREQUENCY_RATE), + float_to_fp16_16(87.9677852348993 / FREQUENCY_RATE), + float_to_fp16_16(88.0860215053763 / FREQUENCY_RATE), + float_to_fp16_16(88.2045760430686 / FREQUENCY_RATE), + float_to_fp16_16(88.3234501347709 / FREQUENCY_RATE), + float_to_fp16_16(88.442645074224 / FREQUENCY_RATE), + float_to_fp16_16(88.5621621621622 / FREQUENCY_RATE), + float_to_fp16_16(88.68200270636 / FREQUENCY_RATE), + float_to_fp16_16(88.8021680216802 / FREQUENCY_RATE), + float_to_fp16_16(88.9226594301221 / FREQUENCY_RATE), + float_to_fp16_16(89.0434782608696 / FREQUENCY_RATE), + float_to_fp16_16(89.1646258503401 / FREQUENCY_RATE), + float_to_fp16_16(89.2861035422343 / FREQUENCY_RATE), + float_to_fp16_16(89.4079126875853 / FREQUENCY_RATE), + float_to_fp16_16(89.5300546448087 / FREQUENCY_RATE), + float_to_fp16_16(89.6525307797538 / FREQUENCY_RATE), + float_to_fp16_16(89.7753424657534 / FREQUENCY_RATE), + float_to_fp16_16(89.8984910836763 / FREQUENCY_RATE), + float_to_fp16_16(90.021978021978 / FREQUENCY_RATE), + float_to_fp16_16(90.1458046767538 / FREQUENCY_RATE), + float_to_fp16_16(90.2699724517906 / FREQUENCY_RATE), + float_to_fp16_16(90.3944827586207 / FREQUENCY_RATE), + float_to_fp16_16(90.5193370165746 / FREQUENCY_RATE), + float_to_fp16_16(90.6445366528354 / FREQUENCY_RATE), + float_to_fp16_16(90.7700831024931 / FREQUENCY_RATE), + float_to_fp16_16(90.8959778085992 / FREQUENCY_RATE), + float_to_fp16_16(91.0222222222222 / FREQUENCY_RATE), + float_to_fp16_16(91.1488178025035 / FREQUENCY_RATE), + float_to_fp16_16(91.2757660167131 / FREQUENCY_RATE), + float_to_fp16_16(91.4030683403068 / FREQUENCY_RATE), + float_to_fp16_16(91.5307262569833 / FREQUENCY_RATE), + float_to_fp16_16(91.6587412587413 / FREQUENCY_RATE), + float_to_fp16_16(91.7871148459384 / FREQUENCY_RATE), + float_to_fp16_16(91.9158485273492 / FREQUENCY_RATE), + float_to_fp16_16(92.0449438202247 / FREQUENCY_RATE), + float_to_fp16_16(92.1744022503516 / FREQUENCY_RATE), + float_to_fp16_16(92.3042253521127 / FREQUENCY_RATE), + float_to_fp16_16(92.4344146685472 / FREQUENCY_RATE), + float_to_fp16_16(92.5649717514124 / FREQUENCY_RATE), + float_to_fp16_16(92.6958981612447 / FREQUENCY_RATE), + float_to_fp16_16(92.8271954674221 / FREQUENCY_RATE), + float_to_fp16_16(92.958865248227 / FREQUENCY_RATE), + float_to_fp16_16(93.0909090909091 / FREQUENCY_RATE), + float_to_fp16_16(93.2233285917497 / FREQUENCY_RATE), + float_to_fp16_16(93.3561253561254 / FREQUENCY_RATE), + float_to_fp16_16(93.4893009985735 / FREQUENCY_RATE), + float_to_fp16_16(93.6228571428572 / FREQUENCY_RATE), + float_to_fp16_16(93.7567954220315 / FREQUENCY_RATE), + float_to_fp16_16(93.89111747851 / FREQUENCY_RATE), + float_to_fp16_16(94.025824964132 / FREQUENCY_RATE), + float_to_fp16_16(94.1609195402299 / FREQUENCY_RATE), + float_to_fp16_16(94.2964028776978 / FREQUENCY_RATE), + float_to_fp16_16(94.4322766570605 / FREQUENCY_RATE), + float_to_fp16_16(94.5685425685426 / FREQUENCY_RATE), + float_to_fp16_16(94.7052023121387 / FREQUENCY_RATE), + float_to_fp16_16(94.8422575976845 / FREQUENCY_RATE), + float_to_fp16_16(94.9797101449275 / FREQUENCY_RATE), + float_to_fp16_16(95.1175616835994 / FREQUENCY_RATE), + float_to_fp16_16(95.2558139534884 / FREQUENCY_RATE), + float_to_fp16_16(95.3944687045124 / FREQUENCY_RATE), + float_to_fp16_16(95.533527696793 / FREQUENCY_RATE), + float_to_fp16_16(95.6729927007299 / FREQUENCY_RATE), + float_to_fp16_16(95.812865497076 / FREQUENCY_RATE), + float_to_fp16_16(95.9531478770132 / FREQUENCY_RATE), + float_to_fp16_16(96.0938416422287 / FREQUENCY_RATE), + float_to_fp16_16(96.2349486049927 / FREQUENCY_RATE), + float_to_fp16_16(96.3764705882353 / FREQUENCY_RATE), + float_to_fp16_16(96.5184094256259 / FREQUENCY_RATE), + float_to_fp16_16(96.6607669616519 / FREQUENCY_RATE), + float_to_fp16_16(96.8035450516987 / FREQUENCY_RATE), + float_to_fp16_16(96.9467455621302 / FREQUENCY_RATE), + float_to_fp16_16(97.0903703703704 / FREQUENCY_RATE), + float_to_fp16_16(97.2344213649852 / FREQUENCY_RATE), + float_to_fp16_16(97.3789004457652 / FREQUENCY_RATE), + float_to_fp16_16(97.5238095238095 / FREQUENCY_RATE), + float_to_fp16_16(97.6691505216095 / FREQUENCY_RATE), + float_to_fp16_16(97.8149253731343 / FREQUENCY_RATE), + float_to_fp16_16(97.9611360239163 / FREQUENCY_RATE), + float_to_fp16_16(98.1077844311377 / FREQUENCY_RATE), + float_to_fp16_16(98.2548725637181 / FREQUENCY_RATE), + float_to_fp16_16(98.4024024024024 / FREQUENCY_RATE), + float_to_fp16_16(98.5503759398496 / FREQUENCY_RATE), + float_to_fp16_16(98.6987951807229 / FREQUENCY_RATE), + float_to_fp16_16(98.8476621417798 / FREQUENCY_RATE), + float_to_fp16_16(98.9969788519637 / FREQUENCY_RATE), + float_to_fp16_16(99.1467473524962 / FREQUENCY_RATE), + float_to_fp16_16(99.2969696969697 / FREQUENCY_RATE), + float_to_fp16_16(99.4476479514416 / FREQUENCY_RATE), + float_to_fp16_16(99.5987841945289 / FREQUENCY_RATE), + float_to_fp16_16(99.7503805175038 / FREQUENCY_RATE), + float_to_fp16_16(99.9024390243902 / FREQUENCY_RATE), + float_to_fp16_16(100.054961832061 / FREQUENCY_RATE), + float_to_fp16_16(100.207951070336 / FREQUENCY_RATE), + float_to_fp16_16(100.361408882083 / FREQUENCY_RATE), + float_to_fp16_16(100.515337423313 / FREQUENCY_RATE), + float_to_fp16_16(100.669738863287 / FREQUENCY_RATE), + float_to_fp16_16(100.824615384615 / FREQUENCY_RATE), + float_to_fp16_16(100.979969183359 / FREQUENCY_RATE), + float_to_fp16_16(101.135802469136 / FREQUENCY_RATE), + float_to_fp16_16(101.292117465224 / FREQUENCY_RATE), + float_to_fp16_16(101.448916408669 / FREQUENCY_RATE), + float_to_fp16_16(101.606201550388 / FREQUENCY_RATE), + float_to_fp16_16(101.76397515528 / FREQUENCY_RATE), + float_to_fp16_16(101.922239502333 / FREQUENCY_RATE), + float_to_fp16_16(102.080996884735 / FREQUENCY_RATE), + float_to_fp16_16(102.240249609984 / FREQUENCY_RATE), + float_to_fp16_16(102.4 / FREQUENCY_RATE), + float_to_fp16_16(102.560250391236 / FREQUENCY_RATE), + float_to_fp16_16(102.721003134796 / FREQUENCY_RATE), + float_to_fp16_16(102.882260596546 / FREQUENCY_RATE), + float_to_fp16_16(103.044025157233 / FREQUENCY_RATE), + float_to_fp16_16(103.206299212598 / FREQUENCY_RATE), + float_to_fp16_16(103.369085173502 / FREQUENCY_RATE), + float_to_fp16_16(103.532385466035 / FREQUENCY_RATE), + float_to_fp16_16(103.696202531646 / FREQUENCY_RATE), + float_to_fp16_16(103.860538827258 / FREQUENCY_RATE), + float_to_fp16_16(104.025396825397 / FREQUENCY_RATE), + float_to_fp16_16(104.190779014308 / FREQUENCY_RATE), + float_to_fp16_16(104.356687898089 / FREQUENCY_RATE), + float_to_fp16_16(104.52312599681 / FREQUENCY_RATE), + float_to_fp16_16(104.690095846645 / FREQUENCY_RATE), + float_to_fp16_16(104.8576 / FREQUENCY_RATE), + float_to_fp16_16(105.025641025641 / FREQUENCY_RATE), + float_to_fp16_16(105.194221508828 / FREQUENCY_RATE), + float_to_fp16_16(105.363344051447 / FREQUENCY_RATE), + float_to_fp16_16(105.533011272142 / FREQUENCY_RATE), + float_to_fp16_16(105.703225806452 / FREQUENCY_RATE), + float_to_fp16_16(105.873990306947 / FREQUENCY_RATE), + float_to_fp16_16(106.045307443366 / FREQUENCY_RATE), + float_to_fp16_16(106.217179902755 / FREQUENCY_RATE), + float_to_fp16_16(106.38961038961 / FREQUENCY_RATE), + float_to_fp16_16(106.562601626016 / FREQUENCY_RATE), + float_to_fp16_16(106.736156351792 / FREQUENCY_RATE), + float_to_fp16_16(106.910277324633 / FREQUENCY_RATE), + float_to_fp16_16(107.084967320261 / FREQUENCY_RATE), + float_to_fp16_16(107.26022913257 / FREQUENCY_RATE), + float_to_fp16_16(107.436065573771 / FREQUENCY_RATE), + float_to_fp16_16(107.612479474548 / FREQUENCY_RATE), + float_to_fp16_16(107.789473684211 / FREQUENCY_RATE), + float_to_fp16_16(107.96705107084 / FREQUENCY_RATE), + float_to_fp16_16(108.145214521452 / FREQUENCY_RATE), + float_to_fp16_16(108.323966942149 / FREQUENCY_RATE), + float_to_fp16_16(108.503311258278 / FREQUENCY_RATE), + float_to_fp16_16(108.683250414594 / FREQUENCY_RATE), + float_to_fp16_16(108.863787375415 / FREQUENCY_RATE), + float_to_fp16_16(109.044925124792 / FREQUENCY_RATE), + float_to_fp16_16(109.226666666667 / FREQUENCY_RATE), + float_to_fp16_16(109.409015025042 / FREQUENCY_RATE), + float_to_fp16_16(109.591973244147 / FREQUENCY_RATE), + float_to_fp16_16(109.77554438861 / FREQUENCY_RATE), + float_to_fp16_16(109.959731543624 / FREQUENCY_RATE), + float_to_fp16_16(110.144537815126 / FREQUENCY_RATE), + float_to_fp16_16(110.329966329966 / FREQUENCY_RATE), + float_to_fp16_16(110.516020236088 / FREQUENCY_RATE), + float_to_fp16_16(110.702702702703 / FREQUENCY_RATE), + float_to_fp16_16(110.890016920474 / FREQUENCY_RATE), + float_to_fp16_16(111.077966101695 / FREQUENCY_RATE), + float_to_fp16_16(111.266553480475 / FREQUENCY_RATE), + float_to_fp16_16(111.455782312925 / FREQUENCY_RATE), + float_to_fp16_16(111.645655877342 / FREQUENCY_RATE), + float_to_fp16_16(111.836177474403 / FREQUENCY_RATE), + float_to_fp16_16(112.02735042735 / FREQUENCY_RATE), + float_to_fp16_16(112.219178082192 / FREQUENCY_RATE), + float_to_fp16_16(112.41166380789 / FREQUENCY_RATE), + float_to_fp16_16(112.604810996564 / FREQUENCY_RATE), + float_to_fp16_16(112.798623063683 / FREQUENCY_RATE), + float_to_fp16_16(112.993103448276 / FREQUENCY_RATE), + float_to_fp16_16(113.188255613126 / FREQUENCY_RATE), + float_to_fp16_16(113.384083044983 / FREQUENCY_RATE), + float_to_fp16_16(113.580589254766 / FREQUENCY_RATE), + float_to_fp16_16(113.777777777778 / FREQUENCY_RATE), + float_to_fp16_16(113.975652173913 / FREQUENCY_RATE), + float_to_fp16_16(114.174216027875 / FREQUENCY_RATE), + float_to_fp16_16(114.373472949389 / FREQUENCY_RATE), + float_to_fp16_16(114.573426573427 / FREQUENCY_RATE), + float_to_fp16_16(114.77408056042 / FREQUENCY_RATE), + float_to_fp16_16(114.975438596491 / FREQUENCY_RATE), + float_to_fp16_16(115.177504393673 / FREQUENCY_RATE), + float_to_fp16_16(115.380281690141 / FREQUENCY_RATE), + float_to_fp16_16(115.583774250441 / FREQUENCY_RATE), + float_to_fp16_16(115.787985865724 / FREQUENCY_RATE), + float_to_fp16_16(115.992920353982 / FREQUENCY_RATE), + float_to_fp16_16(116.198581560284 / FREQUENCY_RATE), + float_to_fp16_16(116.404973357016 / FREQUENCY_RATE), + float_to_fp16_16(116.612099644128 / FREQUENCY_RATE), + float_to_fp16_16(116.819964349376 / FREQUENCY_RATE), + float_to_fp16_16(117.028571428571 / FREQUENCY_RATE), + float_to_fp16_16(117.237924865832 / FREQUENCY_RATE), + float_to_fp16_16(117.448028673835 / FREQUENCY_RATE), + float_to_fp16_16(117.658886894075 / FREQUENCY_RATE), + float_to_fp16_16(117.870503597122 / FREQUENCY_RATE), + float_to_fp16_16(118.082882882883 / FREQUENCY_RATE), + float_to_fp16_16(118.296028880866 / FREQUENCY_RATE), + float_to_fp16_16(118.509945750452 / FREQUENCY_RATE), + float_to_fp16_16(118.724637681159 / FREQUENCY_RATE), + float_to_fp16_16(118.940108892922 / FREQUENCY_RATE), + float_to_fp16_16(119.156363636364 / FREQUENCY_RATE), + float_to_fp16_16(119.373406193078 / FREQUENCY_RATE), + float_to_fp16_16(119.591240875912 / FREQUENCY_RATE), + float_to_fp16_16(119.80987202925 / FREQUENCY_RATE), + float_to_fp16_16(120.029304029304 / FREQUENCY_RATE), + float_to_fp16_16(120.249541284404 / FREQUENCY_RATE), + float_to_fp16_16(120.470588235294 / FREQUENCY_RATE), + float_to_fp16_16(120.692449355433 / FREQUENCY_RATE), + float_to_fp16_16(120.915129151292 / FREQUENCY_RATE), + float_to_fp16_16(121.138632162662 / FREQUENCY_RATE), + float_to_fp16_16(121.362962962963 / FREQUENCY_RATE), + float_to_fp16_16(121.588126159555 / FREQUENCY_RATE), + float_to_fp16_16(121.814126394052 / FREQUENCY_RATE), + float_to_fp16_16(122.040968342644 / FREQUENCY_RATE), + float_to_fp16_16(122.268656716418 / FREQUENCY_RATE), + float_to_fp16_16(122.497196261682 / FREQUENCY_RATE), + float_to_fp16_16(122.7265917603 / FREQUENCY_RATE), + float_to_fp16_16(122.956848030019 / FREQUENCY_RATE), + float_to_fp16_16(123.187969924812 / FREQUENCY_RATE), + float_to_fp16_16(123.419962335217 / FREQUENCY_RATE), + float_to_fp16_16(123.652830188679 / FREQUENCY_RATE), + float_to_fp16_16(123.886578449906 / FREQUENCY_RATE), + float_to_fp16_16(124.121212121212 / FREQUENCY_RATE), + float_to_fp16_16(124.356736242884 / FREQUENCY_RATE), + float_to_fp16_16(124.593155893536 / FREQUENCY_RATE), + float_to_fp16_16(124.830476190476 / FREQUENCY_RATE), + float_to_fp16_16(125.068702290076 / FREQUENCY_RATE), + float_to_fp16_16(125.307839388145 / FREQUENCY_RATE), + float_to_fp16_16(125.547892720307 / FREQUENCY_RATE), + float_to_fp16_16(125.78886756238 / FREQUENCY_RATE), + float_to_fp16_16(126.030769230769 / FREQUENCY_RATE), + float_to_fp16_16(126.273603082852 / FREQUENCY_RATE), + float_to_fp16_16(126.517374517375 / FREQUENCY_RATE), + float_to_fp16_16(126.762088974855 / FREQUENCY_RATE), + float_to_fp16_16(127.007751937985 / FREQUENCY_RATE), + float_to_fp16_16(127.254368932039 / FREQUENCY_RATE), + float_to_fp16_16(127.501945525292 / FREQUENCY_RATE), + float_to_fp16_16(127.750487329435 / FREQUENCY_RATE), + float_to_fp16_16(128 / FREQUENCY_RATE), + float_to_fp16_16(128.250489236791 / FREQUENCY_RATE), + float_to_fp16_16(128.501960784314 / FREQUENCY_RATE), + float_to_fp16_16(128.75442043222 / FREQUENCY_RATE), + float_to_fp16_16(129.007874015748 / FREQUENCY_RATE), + float_to_fp16_16(129.262327416174 / FREQUENCY_RATE), + float_to_fp16_16(129.517786561265 / FREQUENCY_RATE), + float_to_fp16_16(129.774257425743 / FREQUENCY_RATE), + float_to_fp16_16(130.031746031746 / FREQUENCY_RATE), + float_to_fp16_16(130.290258449304 / FREQUENCY_RATE), + float_to_fp16_16(130.549800796813 / FREQUENCY_RATE), + float_to_fp16_16(130.810379241517 / FREQUENCY_RATE), + float_to_fp16_16(131.072 / FREQUENCY_RATE), + float_to_fp16_16(131.334669338677 / FREQUENCY_RATE), + float_to_fp16_16(131.598393574297 / FREQUENCY_RATE), + float_to_fp16_16(131.863179074447 / FREQUENCY_RATE), + float_to_fp16_16(132.129032258065 / FREQUENCY_RATE), + float_to_fp16_16(132.39595959596 / FREQUENCY_RATE), + float_to_fp16_16(132.663967611336 / FREQUENCY_RATE), + float_to_fp16_16(132.933062880325 / FREQUENCY_RATE), + float_to_fp16_16(133.20325203252 / FREQUENCY_RATE), + float_to_fp16_16(133.474541751527 / FREQUENCY_RATE), + float_to_fp16_16(133.74693877551 / FREQUENCY_RATE), + float_to_fp16_16(134.020449897751 / FREQUENCY_RATE), + float_to_fp16_16(134.295081967213 / FREQUENCY_RATE), + float_to_fp16_16(134.570841889117 / FREQUENCY_RATE), + float_to_fp16_16(134.847736625514 / FREQUENCY_RATE), + float_to_fp16_16(135.125773195876 / FREQUENCY_RATE), + float_to_fp16_16(135.404958677686 / FREQUENCY_RATE), + float_to_fp16_16(135.685300207039 / FREQUENCY_RATE), + float_to_fp16_16(135.966804979253 / FREQUENCY_RATE), + float_to_fp16_16(136.24948024948 / FREQUENCY_RATE), + float_to_fp16_16(136.533333333333 / FREQUENCY_RATE), + float_to_fp16_16(136.818371607516 / FREQUENCY_RATE), + float_to_fp16_16(137.10460251046 / FREQUENCY_RATE), + float_to_fp16_16(137.392033542977 / FREQUENCY_RATE), + float_to_fp16_16(137.680672268908 / FREQUENCY_RATE), + float_to_fp16_16(137.970526315789 / FREQUENCY_RATE), + float_to_fp16_16(138.261603375527 / FREQUENCY_RATE), + float_to_fp16_16(138.553911205074 / FREQUENCY_RATE), + float_to_fp16_16(138.847457627119 / FREQUENCY_RATE), + float_to_fp16_16(139.142250530786 / FREQUENCY_RATE), + float_to_fp16_16(139.43829787234 / FREQUENCY_RATE), + float_to_fp16_16(139.735607675906 / FREQUENCY_RATE), + float_to_fp16_16(140.034188034188 / FREQUENCY_RATE), + float_to_fp16_16(140.334047109208 / FREQUENCY_RATE), + float_to_fp16_16(140.635193133047 / FREQUENCY_RATE), + float_to_fp16_16(140.937634408602 / FREQUENCY_RATE), + float_to_fp16_16(141.241379310345 / FREQUENCY_RATE), + float_to_fp16_16(141.546436285097 / FREQUENCY_RATE), + float_to_fp16_16(141.852813852814 / FREQUENCY_RATE), + float_to_fp16_16(142.160520607375 / FREQUENCY_RATE), + float_to_fp16_16(142.469565217391 / FREQUENCY_RATE), + float_to_fp16_16(142.779956427015 / FREQUENCY_RATE), + float_to_fp16_16(143.091703056769 / FREQUENCY_RATE), + float_to_fp16_16(143.404814004376 / FREQUENCY_RATE), + float_to_fp16_16(143.719298245614 / FREQUENCY_RATE), + float_to_fp16_16(144.035164835165 / FREQUENCY_RATE), + float_to_fp16_16(144.352422907489 / FREQUENCY_RATE), + float_to_fp16_16(144.671081677704 / FREQUENCY_RATE), + float_to_fp16_16(144.991150442478 / FREQUENCY_RATE), + float_to_fp16_16(145.312638580931 / FREQUENCY_RATE), + float_to_fp16_16(145.635555555556 / FREQUENCY_RATE), + float_to_fp16_16(145.95991091314 / FREQUENCY_RATE), + float_to_fp16_16(146.285714285714 / FREQUENCY_RATE), + float_to_fp16_16(146.612975391499 / FREQUENCY_RATE), + float_to_fp16_16(146.941704035874 / FREQUENCY_RATE), + float_to_fp16_16(147.27191011236 / FREQUENCY_RATE), + float_to_fp16_16(147.603603603604 / FREQUENCY_RATE), + float_to_fp16_16(147.936794582393 / FREQUENCY_RATE), + float_to_fp16_16(148.27149321267 / FREQUENCY_RATE), + float_to_fp16_16(148.607709750567 / FREQUENCY_RATE), + float_to_fp16_16(148.945454545455 / FREQUENCY_RATE), + float_to_fp16_16(149.284738041002 / FREQUENCY_RATE), + float_to_fp16_16(149.625570776256 / FREQUENCY_RATE), + float_to_fp16_16(149.967963386728 / FREQUENCY_RATE), + float_to_fp16_16(150.311926605505 / FREQUENCY_RATE), + float_to_fp16_16(150.657471264368 / FREQUENCY_RATE), + float_to_fp16_16(151.004608294931 / FREQUENCY_RATE), + float_to_fp16_16(151.353348729792 / FREQUENCY_RATE), + float_to_fp16_16(151.703703703704 / FREQUENCY_RATE), + float_to_fp16_16(152.055684454756 / FREQUENCY_RATE), + float_to_fp16_16(152.409302325581 / FREQUENCY_RATE), + float_to_fp16_16(152.764568764569 / FREQUENCY_RATE), + float_to_fp16_16(153.121495327103 / FREQUENCY_RATE), + float_to_fp16_16(153.480093676815 / FREQUENCY_RATE), + float_to_fp16_16(153.840375586854 / FREQUENCY_RATE), + float_to_fp16_16(154.202352941176 / FREQUENCY_RATE), + float_to_fp16_16(154.566037735849 / FREQUENCY_RATE), + float_to_fp16_16(154.931442080378 / FREQUENCY_RATE), + float_to_fp16_16(155.298578199052 / FREQUENCY_RATE), + float_to_fp16_16(155.667458432304 / FREQUENCY_RATE), + float_to_fp16_16(156.038095238095 / FREQUENCY_RATE), + float_to_fp16_16(156.410501193317 / FREQUENCY_RATE), + float_to_fp16_16(156.784688995215 / FREQUENCY_RATE), + float_to_fp16_16(157.16067146283 / FREQUENCY_RATE), + float_to_fp16_16(157.538461538462 / FREQUENCY_RATE), + float_to_fp16_16(157.918072289157 / FREQUENCY_RATE), + float_to_fp16_16(158.299516908213 / FREQUENCY_RATE), + float_to_fp16_16(158.682808716707 / FREQUENCY_RATE), + float_to_fp16_16(159.067961165049 / FREQUENCY_RATE), + float_to_fp16_16(159.45498783455 / FREQUENCY_RATE), + float_to_fp16_16(159.843902439024 / FREQUENCY_RATE), + float_to_fp16_16(160.234718826406 / FREQUENCY_RATE), + float_to_fp16_16(160.627450980392 / FREQUENCY_RATE), + float_to_fp16_16(161.022113022113 / FREQUENCY_RATE), + float_to_fp16_16(161.418719211823 / FREQUENCY_RATE), + float_to_fp16_16(161.817283950617 / FREQUENCY_RATE), + float_to_fp16_16(162.217821782178 / FREQUENCY_RATE), + float_to_fp16_16(162.620347394541 / FREQUENCY_RATE), + float_to_fp16_16(163.024875621891 / FREQUENCY_RATE), + float_to_fp16_16(163.431421446384 / FREQUENCY_RATE), + float_to_fp16_16(163.84 / FREQUENCY_RATE), + float_to_fp16_16(164.250626566416 / FREQUENCY_RATE), + float_to_fp16_16(164.663316582915 / FREQUENCY_RATE), + float_to_fp16_16(165.078085642317 / FREQUENCY_RATE), + float_to_fp16_16(165.49494949495 / FREQUENCY_RATE), + float_to_fp16_16(165.913924050633 / FREQUENCY_RATE), + float_to_fp16_16(166.335025380711 / FREQUENCY_RATE), + float_to_fp16_16(166.758269720102 / FREQUENCY_RATE), + float_to_fp16_16(167.183673469388 / FREQUENCY_RATE), + float_to_fp16_16(167.611253196931 / FREQUENCY_RATE), + float_to_fp16_16(168.041025641026 / FREQUENCY_RATE), + float_to_fp16_16(168.473007712082 / FREQUENCY_RATE), + float_to_fp16_16(168.907216494845 / FREQUENCY_RATE), + float_to_fp16_16(169.343669250646 / FREQUENCY_RATE), + float_to_fp16_16(169.782383419689 / FREQUENCY_RATE), + float_to_fp16_16(170.223376623377 / FREQUENCY_RATE), + float_to_fp16_16(170.666666666667 / FREQUENCY_RATE), + float_to_fp16_16(171.11227154047 / FREQUENCY_RATE), + float_to_fp16_16(171.560209424084 / FREQUENCY_RATE), + float_to_fp16_16(172.010498687664 / FREQUENCY_RATE), + float_to_fp16_16(172.463157894737 / FREQUENCY_RATE), + float_to_fp16_16(172.918205804749 / FREQUENCY_RATE), + float_to_fp16_16(173.375661375661 / FREQUENCY_RATE), + float_to_fp16_16(173.835543766578 / FREQUENCY_RATE), + float_to_fp16_16(174.297872340426 / FREQUENCY_RATE), + float_to_fp16_16(174.762666666667 / FREQUENCY_RATE), + float_to_fp16_16(175.229946524064 / FREQUENCY_RATE), + float_to_fp16_16(175.699731903485 / FREQUENCY_RATE), + float_to_fp16_16(176.172043010753 / FREQUENCY_RATE), + float_to_fp16_16(176.646900269542 / FREQUENCY_RATE), + float_to_fp16_16(177.124324324324 / FREQUENCY_RATE), + float_to_fp16_16(177.60433604336 / FREQUENCY_RATE), + float_to_fp16_16(178.086956521739 / FREQUENCY_RATE), + float_to_fp16_16(178.572207084469 / FREQUENCY_RATE), + float_to_fp16_16(179.060109289618 / FREQUENCY_RATE), + float_to_fp16_16(179.550684931507 / FREQUENCY_RATE), + float_to_fp16_16(180.043956043956 / FREQUENCY_RATE), + float_to_fp16_16(180.539944903581 / FREQUENCY_RATE), + float_to_fp16_16(181.038674033149 / FREQUENCY_RATE), + float_to_fp16_16(181.540166204986 / FREQUENCY_RATE), + float_to_fp16_16(182.044444444444 / FREQUENCY_RATE), + float_to_fp16_16(182.551532033426 / FREQUENCY_RATE), + float_to_fp16_16(183.061452513966 / FREQUENCY_RATE), + float_to_fp16_16(183.574229691877 / FREQUENCY_RATE), + float_to_fp16_16(184.089887640449 / FREQUENCY_RATE), + float_to_fp16_16(184.608450704225 / FREQUENCY_RATE), + float_to_fp16_16(185.129943502825 / FREQUENCY_RATE), + float_to_fp16_16(185.654390934844 / FREQUENCY_RATE), + float_to_fp16_16(186.181818181818 / FREQUENCY_RATE), + float_to_fp16_16(186.712250712251 / FREQUENCY_RATE), + float_to_fp16_16(187.245714285714 / FREQUENCY_RATE), + float_to_fp16_16(187.78223495702 / FREQUENCY_RATE), + float_to_fp16_16(188.32183908046 / FREQUENCY_RATE), + float_to_fp16_16(188.864553314121 / FREQUENCY_RATE), + float_to_fp16_16(189.410404624277 / FREQUENCY_RATE), + float_to_fp16_16(189.959420289855 / FREQUENCY_RATE), + float_to_fp16_16(190.511627906977 / FREQUENCY_RATE), + float_to_fp16_16(191.067055393586 / FREQUENCY_RATE), + float_to_fp16_16(191.625730994152 / FREQUENCY_RATE), + float_to_fp16_16(192.187683284457 / FREQUENCY_RATE), + float_to_fp16_16(192.752941176471 / FREQUENCY_RATE), + float_to_fp16_16(193.321533923304 / FREQUENCY_RATE), + float_to_fp16_16(193.89349112426 / FREQUENCY_RATE), + float_to_fp16_16(194.46884272997 / FREQUENCY_RATE), + float_to_fp16_16(195.047619047619 / FREQUENCY_RATE), + float_to_fp16_16(195.629850746269 / FREQUENCY_RATE), + float_to_fp16_16(196.215568862275 / FREQUENCY_RATE), + float_to_fp16_16(196.804804804805 / FREQUENCY_RATE), + float_to_fp16_16(197.397590361446 / FREQUENCY_RATE), + float_to_fp16_16(197.993957703928 / FREQUENCY_RATE), + float_to_fp16_16(198.593939393939 / FREQUENCY_RATE), + float_to_fp16_16(199.197568389058 / FREQUENCY_RATE), + float_to_fp16_16(199.804878048781 / FREQUENCY_RATE), + float_to_fp16_16(200.415902140673 / FREQUENCY_RATE), + float_to_fp16_16(201.030674846626 / FREQUENCY_RATE), + float_to_fp16_16(201.649230769231 / FREQUENCY_RATE), + float_to_fp16_16(202.271604938272 / FREQUENCY_RATE), + float_to_fp16_16(202.897832817337 / FREQUENCY_RATE), + float_to_fp16_16(203.527950310559 / FREQUENCY_RATE), + float_to_fp16_16(204.16199376947 / FREQUENCY_RATE), + float_to_fp16_16(204.8 / FREQUENCY_RATE), + float_to_fp16_16(205.442006269592 / FREQUENCY_RATE), + float_to_fp16_16(206.088050314465 / FREQUENCY_RATE), + float_to_fp16_16(206.738170347003 / FREQUENCY_RATE), + float_to_fp16_16(207.392405063291 / FREQUENCY_RATE), + float_to_fp16_16(208.050793650794 / FREQUENCY_RATE), + float_to_fp16_16(208.713375796178 / FREQUENCY_RATE), + float_to_fp16_16(209.380191693291 / FREQUENCY_RATE), + float_to_fp16_16(210.051282051282 / FREQUENCY_RATE), + float_to_fp16_16(210.726688102894 / FREQUENCY_RATE), + float_to_fp16_16(211.406451612903 / FREQUENCY_RATE), + float_to_fp16_16(212.090614886731 / FREQUENCY_RATE), + float_to_fp16_16(212.779220779221 / FREQUENCY_RATE), + float_to_fp16_16(213.472312703583 / FREQUENCY_RATE), + float_to_fp16_16(214.169934640523 / FREQUENCY_RATE), + float_to_fp16_16(214.872131147541 / FREQUENCY_RATE), + float_to_fp16_16(215.578947368421 / FREQUENCY_RATE), + float_to_fp16_16(216.290429042904 / FREQUENCY_RATE), + float_to_fp16_16(217.006622516556 / FREQUENCY_RATE), + float_to_fp16_16(217.727574750831 / FREQUENCY_RATE), + float_to_fp16_16(218.453333333333 / FREQUENCY_RATE), + float_to_fp16_16(219.183946488294 / FREQUENCY_RATE), + float_to_fp16_16(219.919463087248 / FREQUENCY_RATE), + float_to_fp16_16(220.659932659933 / FREQUENCY_RATE), + float_to_fp16_16(221.405405405405 / FREQUENCY_RATE), + float_to_fp16_16(222.15593220339 / FREQUENCY_RATE), + float_to_fp16_16(222.91156462585 / FREQUENCY_RATE), + float_to_fp16_16(223.672354948805 / FREQUENCY_RATE), + float_to_fp16_16(224.438356164384 / FREQUENCY_RATE), + float_to_fp16_16(225.209621993127 / FREQUENCY_RATE), + float_to_fp16_16(225.986206896552 / FREQUENCY_RATE), + float_to_fp16_16(226.768166089965 / FREQUENCY_RATE), + float_to_fp16_16(227.555555555556 / FREQUENCY_RATE), + float_to_fp16_16(228.348432055749 / FREQUENCY_RATE), + float_to_fp16_16(229.146853146853 / FREQUENCY_RATE), + float_to_fp16_16(229.950877192982 / FREQUENCY_RATE), + float_to_fp16_16(230.760563380282 / FREQUENCY_RATE), + float_to_fp16_16(231.575971731449 / FREQUENCY_RATE), + float_to_fp16_16(232.397163120567 / FREQUENCY_RATE), + float_to_fp16_16(233.224199288256 / FREQUENCY_RATE), + float_to_fp16_16(234.057142857143 / FREQUENCY_RATE), + float_to_fp16_16(234.89605734767 / FREQUENCY_RATE), + float_to_fp16_16(235.741007194245 / FREQUENCY_RATE), + float_to_fp16_16(236.592057761733 / FREQUENCY_RATE), + float_to_fp16_16(237.449275362319 / FREQUENCY_RATE), + float_to_fp16_16(238.312727272727 / FREQUENCY_RATE), + float_to_fp16_16(239.182481751825 / FREQUENCY_RATE), + float_to_fp16_16(240.058608058608 / FREQUENCY_RATE), + float_to_fp16_16(240.941176470588 / FREQUENCY_RATE), + float_to_fp16_16(241.830258302583 / FREQUENCY_RATE), + float_to_fp16_16(242.725925925926 / FREQUENCY_RATE), + float_to_fp16_16(243.628252788104 / FREQUENCY_RATE), + float_to_fp16_16(244.537313432836 / FREQUENCY_RATE), + float_to_fp16_16(245.453183520599 / FREQUENCY_RATE), + float_to_fp16_16(246.375939849624 / FREQUENCY_RATE), + float_to_fp16_16(247.305660377358 / FREQUENCY_RATE), + float_to_fp16_16(248.242424242424 / FREQUENCY_RATE), + float_to_fp16_16(249.186311787072 / FREQUENCY_RATE), + float_to_fp16_16(250.137404580153 / FREQUENCY_RATE), + float_to_fp16_16(251.095785440613 / FREQUENCY_RATE), + float_to_fp16_16(252.061538461538 / FREQUENCY_RATE), + float_to_fp16_16(253.034749034749 / FREQUENCY_RATE), + float_to_fp16_16(254.015503875969 / FREQUENCY_RATE), + float_to_fp16_16(255.003891050584 / FREQUENCY_RATE), + float_to_fp16_16(256 / FREQUENCY_RATE), + float_to_fp16_16(257.003921568627 / FREQUENCY_RATE), + float_to_fp16_16(258.015748031496 / FREQUENCY_RATE), + float_to_fp16_16(259.03557312253 / FREQUENCY_RATE), + float_to_fp16_16(260.063492063492 / FREQUENCY_RATE), + float_to_fp16_16(261.099601593625 / FREQUENCY_RATE), + float_to_fp16_16(262.144 / FREQUENCY_RATE), + float_to_fp16_16(263.196787148594 / FREQUENCY_RATE), + float_to_fp16_16(264.258064516129 / FREQUENCY_RATE), + float_to_fp16_16(265.327935222672 / FREQUENCY_RATE), + float_to_fp16_16(266.406504065041 / FREQUENCY_RATE), + float_to_fp16_16(267.49387755102 / FREQUENCY_RATE), + float_to_fp16_16(268.590163934426 / FREQUENCY_RATE), + float_to_fp16_16(269.695473251029 / FREQUENCY_RATE), + float_to_fp16_16(270.809917355372 / FREQUENCY_RATE), + float_to_fp16_16(271.933609958506 / FREQUENCY_RATE), + float_to_fp16_16(273.066666666667 / FREQUENCY_RATE), + float_to_fp16_16(274.20920502092 / FREQUENCY_RATE), + float_to_fp16_16(275.361344537815 / FREQUENCY_RATE), + float_to_fp16_16(276.523206751055 / FREQUENCY_RATE), + float_to_fp16_16(277.694915254237 / FREQUENCY_RATE), + float_to_fp16_16(278.876595744681 / FREQUENCY_RATE), + float_to_fp16_16(280.068376068376 / FREQUENCY_RATE), + float_to_fp16_16(281.270386266094 / FREQUENCY_RATE), + float_to_fp16_16(282.48275862069 / FREQUENCY_RATE), + float_to_fp16_16(283.705627705628 / FREQUENCY_RATE), + float_to_fp16_16(284.939130434783 / FREQUENCY_RATE), + float_to_fp16_16(286.183406113537 / FREQUENCY_RATE), + float_to_fp16_16(287.438596491228 / FREQUENCY_RATE), + float_to_fp16_16(288.704845814978 / FREQUENCY_RATE), + float_to_fp16_16(289.982300884956 / FREQUENCY_RATE), + float_to_fp16_16(291.271111111111 / FREQUENCY_RATE), + float_to_fp16_16(292.571428571429 / FREQUENCY_RATE), + float_to_fp16_16(293.883408071749 / FREQUENCY_RATE), + float_to_fp16_16(295.207207207207 / FREQUENCY_RATE), + float_to_fp16_16(296.542986425339 / FREQUENCY_RATE), + float_to_fp16_16(297.890909090909 / FREQUENCY_RATE), + float_to_fp16_16(299.251141552511 / FREQUENCY_RATE), + float_to_fp16_16(300.623853211009 / FREQUENCY_RATE), + float_to_fp16_16(302.009216589862 / FREQUENCY_RATE), + float_to_fp16_16(303.407407407407 / FREQUENCY_RATE), + float_to_fp16_16(304.818604651163 / FREQUENCY_RATE), + float_to_fp16_16(306.242990654206 / FREQUENCY_RATE), + float_to_fp16_16(307.680751173709 / FREQUENCY_RATE), + float_to_fp16_16(309.132075471698 / FREQUENCY_RATE), + float_to_fp16_16(310.597156398104 / FREQUENCY_RATE), + float_to_fp16_16(312.07619047619 / FREQUENCY_RATE), + float_to_fp16_16(313.569377990431 / FREQUENCY_RATE), + float_to_fp16_16(315.076923076923 / FREQUENCY_RATE), + float_to_fp16_16(316.599033816425 / FREQUENCY_RATE), + float_to_fp16_16(318.135922330097 / FREQUENCY_RATE), + float_to_fp16_16(319.687804878049 / FREQUENCY_RATE), + float_to_fp16_16(321.254901960784 / FREQUENCY_RATE), + float_to_fp16_16(322.837438423645 / FREQUENCY_RATE), + float_to_fp16_16(324.435643564356 / FREQUENCY_RATE), + float_to_fp16_16(326.049751243781 / FREQUENCY_RATE), + float_to_fp16_16(327.68 / FREQUENCY_RATE), + float_to_fp16_16(329.326633165829 / FREQUENCY_RATE), + float_to_fp16_16(330.989898989899 / FREQUENCY_RATE), + float_to_fp16_16(332.670050761421 / FREQUENCY_RATE), + float_to_fp16_16(334.367346938775 / FREQUENCY_RATE), + float_to_fp16_16(336.082051282051 / FREQUENCY_RATE), + float_to_fp16_16(337.814432989691 / FREQUENCY_RATE), + float_to_fp16_16(339.564766839378 / FREQUENCY_RATE), + float_to_fp16_16(341.333333333333 / FREQUENCY_RATE), + float_to_fp16_16(343.120418848168 / FREQUENCY_RATE), + float_to_fp16_16(344.926315789474 / FREQUENCY_RATE), + float_to_fp16_16(346.751322751323 / FREQUENCY_RATE), + float_to_fp16_16(348.595744680851 / FREQUENCY_RATE), + float_to_fp16_16(350.459893048128 / FREQUENCY_RATE), + float_to_fp16_16(352.344086021505 / FREQUENCY_RATE), + float_to_fp16_16(354.248648648649 / FREQUENCY_RATE), + float_to_fp16_16(356.173913043478 / FREQUENCY_RATE), + float_to_fp16_16(358.120218579235 / FREQUENCY_RATE), + float_to_fp16_16(360.087912087912 / FREQUENCY_RATE), + float_to_fp16_16(362.077348066298 / FREQUENCY_RATE), + float_to_fp16_16(364.088888888889 / FREQUENCY_RATE), + float_to_fp16_16(366.122905027933 / FREQUENCY_RATE), + float_to_fp16_16(368.179775280899 / FREQUENCY_RATE), + float_to_fp16_16(370.25988700565 / FREQUENCY_RATE), + float_to_fp16_16(372.363636363636 / FREQUENCY_RATE), + float_to_fp16_16(374.491428571429 / FREQUENCY_RATE), + float_to_fp16_16(376.64367816092 / FREQUENCY_RATE), + float_to_fp16_16(378.820809248555 / FREQUENCY_RATE), + float_to_fp16_16(381.023255813953 / FREQUENCY_RATE), + float_to_fp16_16(383.251461988304 / FREQUENCY_RATE), + float_to_fp16_16(385.505882352941 / FREQUENCY_RATE), + float_to_fp16_16(387.786982248521 / FREQUENCY_RATE), + float_to_fp16_16(390.095238095238 / FREQUENCY_RATE), + float_to_fp16_16(392.431137724551 / FREQUENCY_RATE), + float_to_fp16_16(394.795180722892 / FREQUENCY_RATE), + float_to_fp16_16(397.187878787879 / FREQUENCY_RATE), + float_to_fp16_16(399.609756097561 / FREQUENCY_RATE), + float_to_fp16_16(402.061349693252 / FREQUENCY_RATE), + float_to_fp16_16(404.543209876543 / FREQUENCY_RATE), + float_to_fp16_16(407.055900621118 / FREQUENCY_RATE), + float_to_fp16_16(409.6 / FREQUENCY_RATE), + float_to_fp16_16(412.176100628931 / FREQUENCY_RATE), + float_to_fp16_16(414.784810126582 / FREQUENCY_RATE), + float_to_fp16_16(417.426751592357 / FREQUENCY_RATE), + float_to_fp16_16(420.102564102564 / FREQUENCY_RATE), + float_to_fp16_16(422.812903225807 / FREQUENCY_RATE), + float_to_fp16_16(425.558441558442 / FREQUENCY_RATE), + float_to_fp16_16(428.339869281046 / FREQUENCY_RATE), + float_to_fp16_16(431.157894736842 / FREQUENCY_RATE), + float_to_fp16_16(434.013245033113 / FREQUENCY_RATE), + float_to_fp16_16(436.906666666667 / FREQUENCY_RATE), + float_to_fp16_16(439.838926174497 / FREQUENCY_RATE), + float_to_fp16_16(442.810810810811 / FREQUENCY_RATE), + float_to_fp16_16(445.823129251701 / FREQUENCY_RATE), + float_to_fp16_16(448.876712328767 / FREQUENCY_RATE), + float_to_fp16_16(451.972413793103 / FREQUENCY_RATE), + float_to_fp16_16(455.111111111111 / FREQUENCY_RATE), + float_to_fp16_16(458.293706293706 / FREQUENCY_RATE), + float_to_fp16_16(461.521126760563 / FREQUENCY_RATE), + float_to_fp16_16(464.794326241135 / FREQUENCY_RATE), + float_to_fp16_16(468.114285714286 / FREQUENCY_RATE), + float_to_fp16_16(471.482014388489 / FREQUENCY_RATE), + float_to_fp16_16(474.898550724638 / FREQUENCY_RATE), + float_to_fp16_16(478.36496350365 / FREQUENCY_RATE), + float_to_fp16_16(481.882352941176 / FREQUENCY_RATE), + float_to_fp16_16(485.451851851852 / FREQUENCY_RATE), + float_to_fp16_16(489.074626865672 / FREQUENCY_RATE), + float_to_fp16_16(492.751879699248 / FREQUENCY_RATE), + float_to_fp16_16(496.484848484849 / FREQUENCY_RATE), + float_to_fp16_16(500.274809160305 / FREQUENCY_RATE), + float_to_fp16_16(504.123076923077 / FREQUENCY_RATE), + float_to_fp16_16(508.031007751938 / FREQUENCY_RATE), + float_to_fp16_16(512 / FREQUENCY_RATE), + float_to_fp16_16(516.031496062992 / FREQUENCY_RATE), + float_to_fp16_16(520.126984126984 / FREQUENCY_RATE), + float_to_fp16_16(524.288 / FREQUENCY_RATE), + float_to_fp16_16(528.516129032258 / FREQUENCY_RATE), + float_to_fp16_16(532.813008130081 / FREQUENCY_RATE), + float_to_fp16_16(537.180327868852 / FREQUENCY_RATE), + float_to_fp16_16(541.619834710744 / FREQUENCY_RATE), + float_to_fp16_16(546.133333333333 / FREQUENCY_RATE), + float_to_fp16_16(550.72268907563 / FREQUENCY_RATE), + float_to_fp16_16(555.389830508475 / FREQUENCY_RATE), + float_to_fp16_16(560.136752136752 / FREQUENCY_RATE), + float_to_fp16_16(564.965517241379 / FREQUENCY_RATE), + float_to_fp16_16(569.878260869565 / FREQUENCY_RATE), + float_to_fp16_16(574.877192982456 / FREQUENCY_RATE), + float_to_fp16_16(579.964601769912 / FREQUENCY_RATE), + float_to_fp16_16(585.142857142857 / FREQUENCY_RATE), + float_to_fp16_16(590.414414414414 / FREQUENCY_RATE), + float_to_fp16_16(595.781818181818 / FREQUENCY_RATE), + float_to_fp16_16(601.247706422018 / FREQUENCY_RATE), + float_to_fp16_16(606.814814814815 / FREQUENCY_RATE), + float_to_fp16_16(612.485981308411 / FREQUENCY_RATE), + float_to_fp16_16(618.264150943396 / FREQUENCY_RATE), + float_to_fp16_16(624.152380952381 / FREQUENCY_RATE), + float_to_fp16_16(630.153846153846 / FREQUENCY_RATE), + float_to_fp16_16(636.271844660194 / FREQUENCY_RATE), + float_to_fp16_16(642.509803921569 / FREQUENCY_RATE), + float_to_fp16_16(648.871287128713 / FREQUENCY_RATE), + float_to_fp16_16(655.36 / FREQUENCY_RATE), + float_to_fp16_16(661.979797979798 / FREQUENCY_RATE), + float_to_fp16_16(668.734693877551 / FREQUENCY_RATE), + float_to_fp16_16(675.628865979381 / FREQUENCY_RATE), + float_to_fp16_16(682.666666666667 / FREQUENCY_RATE), + float_to_fp16_16(689.852631578947 / FREQUENCY_RATE), + float_to_fp16_16(697.191489361702 / FREQUENCY_RATE), + float_to_fp16_16(704.688172043011 / FREQUENCY_RATE), + float_to_fp16_16(712.347826086956 / FREQUENCY_RATE), + float_to_fp16_16(720.175824175824 / FREQUENCY_RATE), + float_to_fp16_16(728.177777777778 / FREQUENCY_RATE), + float_to_fp16_16(736.359550561798 / FREQUENCY_RATE), + float_to_fp16_16(744.727272727273 / FREQUENCY_RATE), + float_to_fp16_16(753.287356321839 / FREQUENCY_RATE), + float_to_fp16_16(762.046511627907 / FREQUENCY_RATE), + float_to_fp16_16(771.011764705882 / FREQUENCY_RATE), + float_to_fp16_16(780.190476190476 / FREQUENCY_RATE), + float_to_fp16_16(789.590361445783 / FREQUENCY_RATE), + float_to_fp16_16(799.219512195122 / FREQUENCY_RATE), + float_to_fp16_16(809.086419753086 / FREQUENCY_RATE), + float_to_fp16_16(819.2 / FREQUENCY_RATE), + float_to_fp16_16(829.569620253165 / FREQUENCY_RATE), + float_to_fp16_16(840.205128205128 / FREQUENCY_RATE), + float_to_fp16_16(851.116883116883 / FREQUENCY_RATE), + float_to_fp16_16(862.315789473684 / FREQUENCY_RATE), + float_to_fp16_16(873.813333333333 / FREQUENCY_RATE), + float_to_fp16_16(885.621621621622 / FREQUENCY_RATE), + float_to_fp16_16(897.753424657534 / FREQUENCY_RATE), + float_to_fp16_16(910.222222222222 / FREQUENCY_RATE), + float_to_fp16_16(923.042253521127 / FREQUENCY_RATE), + float_to_fp16_16(936.228571428571 / FREQUENCY_RATE), + float_to_fp16_16(949.797101449275 / FREQUENCY_RATE), + float_to_fp16_16(963.764705882353 / FREQUENCY_RATE), + float_to_fp16_16(978.149253731343 / FREQUENCY_RATE), + float_to_fp16_16(992.969696969697 / FREQUENCY_RATE), + float_to_fp16_16(1008.24615384615 / FREQUENCY_RATE), + float_to_fp16_16(1024 / FREQUENCY_RATE), + float_to_fp16_16(1040.25396825397 / FREQUENCY_RATE), + float_to_fp16_16(1057.03225806452 / FREQUENCY_RATE), + float_to_fp16_16(1074.36065573771 / FREQUENCY_RATE), + float_to_fp16_16(1092.26666666667 / FREQUENCY_RATE), + float_to_fp16_16(1110.77966101695 / FREQUENCY_RATE), + float_to_fp16_16(1129.93103448276 / FREQUENCY_RATE), + float_to_fp16_16(1149.75438596491 / FREQUENCY_RATE), + float_to_fp16_16(1170.28571428571 / FREQUENCY_RATE), + float_to_fp16_16(1191.56363636364 / FREQUENCY_RATE), + float_to_fp16_16(1213.62962962963 / FREQUENCY_RATE), + float_to_fp16_16(1236.52830188679 / FREQUENCY_RATE), + float_to_fp16_16(1260.30769230769 / FREQUENCY_RATE), + float_to_fp16_16(1285.01960784314 / FREQUENCY_RATE), + float_to_fp16_16(1310.72 / FREQUENCY_RATE), + float_to_fp16_16(1337.4693877551 / FREQUENCY_RATE), + float_to_fp16_16(1365.33333333333 / FREQUENCY_RATE), + float_to_fp16_16(1394.3829787234 / FREQUENCY_RATE), + float_to_fp16_16(1424.69565217391 / FREQUENCY_RATE), + float_to_fp16_16(1456.35555555556 / FREQUENCY_RATE), + float_to_fp16_16(1489.45454545455 / FREQUENCY_RATE), + float_to_fp16_16(1524.09302325581 / FREQUENCY_RATE), + float_to_fp16_16(1560.38095238095 / FREQUENCY_RATE), + float_to_fp16_16(1598.43902439024 / FREQUENCY_RATE), + float_to_fp16_16(1638.4 / FREQUENCY_RATE), + float_to_fp16_16(1680.41025641026 / FREQUENCY_RATE), + float_to_fp16_16(1724.63157894737 / FREQUENCY_RATE), + float_to_fp16_16(1771.24324324324 / FREQUENCY_RATE), + float_to_fp16_16(1820.44444444444 / FREQUENCY_RATE), + float_to_fp16_16(1872.45714285714 / FREQUENCY_RATE), + float_to_fp16_16(1927.52941176471 / FREQUENCY_RATE), + float_to_fp16_16(1985.93939393939 / FREQUENCY_RATE), + float_to_fp16_16(2048 / FREQUENCY_RATE), + float_to_fp16_16(2114.06451612903 / FREQUENCY_RATE), + float_to_fp16_16(2184.53333333333 / FREQUENCY_RATE), + float_to_fp16_16(2259.86206896552 / FREQUENCY_RATE), + float_to_fp16_16(2340.57142857143 / FREQUENCY_RATE), + float_to_fp16_16(2427.25925925926 / FREQUENCY_RATE), + float_to_fp16_16(2520.61538461538 / FREQUENCY_RATE), + float_to_fp16_16(2621.44 / FREQUENCY_RATE), + float_to_fp16_16(2730.66666666667 / FREQUENCY_RATE), + float_to_fp16_16(2849.39130434783 / FREQUENCY_RATE), + float_to_fp16_16(2978.90909090909 / FREQUENCY_RATE), + float_to_fp16_16(3120.7619047619 / FREQUENCY_RATE), + float_to_fp16_16(3276.8 / FREQUENCY_RATE), + float_to_fp16_16(3449.26315789474 / FREQUENCY_RATE), + float_to_fp16_16(3640.88888888889 / FREQUENCY_RATE), + float_to_fp16_16(3855.05882352941 / FREQUENCY_RATE), + float_to_fp16_16(4096 / FREQUENCY_RATE), + float_to_fp16_16(4369.06666666667 / FREQUENCY_RATE), + float_to_fp16_16(4681.14285714286 / FREQUENCY_RATE), + float_to_fp16_16(5041.23076923077 / FREQUENCY_RATE), + float_to_fp16_16(5461.33333333333 / FREQUENCY_RATE), + float_to_fp16_16(5957.81818181818 / FREQUENCY_RATE), + float_to_fp16_16(6553.6 / FREQUENCY_RATE), + float_to_fp16_16(7281.77777777778 / FREQUENCY_RATE), + float_to_fp16_16(8192 / FREQUENCY_RATE), + float_to_fp16_16(9362.28571428571 / FREQUENCY_RATE), + float_to_fp16_16(10922.6666666667 / FREQUENCY_RATE), + float_to_fp16_16(13107.2 / FREQUENCY_RATE), + float_to_fp16_16(16384 / FREQUENCY_RATE), + float_to_fp16_16(21845.3333333333 / FREQUENCY_RATE), + float_to_fp16_16(32768 / FREQUENCY_RATE), + float_to_fp16_16(65536 / FREQUENCY_RATE), }; -const float freqTableNSE[256] = { - (524288 / SAMPLE_RATE), - (262144 / SAMPLE_RATE), - (131072 / SAMPLE_RATE), - (87381.3333333333 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (52428.8 / SAMPLE_RATE), - (43690.6666666667 / SAMPLE_RATE), - (37449.1428571429 / SAMPLE_RATE), - (524288 / SAMPLE_RATE), - (262144 / SAMPLE_RATE), - (131072 / SAMPLE_RATE), - (87381.3333333333 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (52428.8 / SAMPLE_RATE), - (43690.6666666667 / SAMPLE_RATE), - (37449.1428571429 / SAMPLE_RATE), - (262144 / SAMPLE_RATE), - (131072 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (43690.6666666667 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (26214.4 / SAMPLE_RATE), - (21845.3333333333 / SAMPLE_RATE), - (18724.5714285714 / SAMPLE_RATE), - (262144 / SAMPLE_RATE), - (131072 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (43690.6666666667 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (26214.4 / SAMPLE_RATE), - (21845.3333333333 / SAMPLE_RATE), - (18724.5714285714 / SAMPLE_RATE), - (131072 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (21845.3333333333 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (13107.2 / SAMPLE_RATE), - (10922.6666666667 / SAMPLE_RATE), - (9362.28571428571 / SAMPLE_RATE), - (131072 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (21845.3333333333 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (13107.2 / SAMPLE_RATE), - (10922.6666666667 / SAMPLE_RATE), - (9362.28571428571 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (10922.6666666667 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (6553.6 / SAMPLE_RATE), - (5461.33333333333 / SAMPLE_RATE), - (4681.14285714286 / SAMPLE_RATE), - (65536 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (10922.6666666667 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (6553.6 / SAMPLE_RATE), - (5461.33333333333 / SAMPLE_RATE), - (4681.14285714286 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (5461.33333333333 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (3276.8 / SAMPLE_RATE), - (2730.66666666667 / SAMPLE_RATE), - (2340.57142857143 / SAMPLE_RATE), - (32768 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (5461.33333333333 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (3276.8 / SAMPLE_RATE), - (2730.66666666667 / SAMPLE_RATE), - (2340.57142857143 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (2730.66666666667 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1638.4 / SAMPLE_RATE), - (1365.33333333333 / SAMPLE_RATE), - (1170.28571428571 / SAMPLE_RATE), - (16384 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (2730.66666666667 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1638.4 / SAMPLE_RATE), - (1365.33333333333 / SAMPLE_RATE), - (1170.28571428571 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1365.33333333333 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (819.2 / SAMPLE_RATE), - (682.666666666667 / SAMPLE_RATE), - (585.142857142857 / SAMPLE_RATE), - (8192 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1365.33333333333 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (819.2 / SAMPLE_RATE), - (682.666666666667 / SAMPLE_RATE), - (585.142857142857 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (682.666666666667 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (409.6 / SAMPLE_RATE), - (341.333333333333 / SAMPLE_RATE), - (292.571428571429 / SAMPLE_RATE), - (4096 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (682.666666666667 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (409.6 / SAMPLE_RATE), - (341.333333333333 / SAMPLE_RATE), - (292.571428571429 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (341.333333333333 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (204.8 / SAMPLE_RATE), - (170.666666666667 / SAMPLE_RATE), - (146.285714285714 / SAMPLE_RATE), - (2048 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (341.333333333333 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (204.8 / SAMPLE_RATE), - (170.666666666667 / SAMPLE_RATE), - (146.285714285714 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (170.666666666667 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (102.4 / SAMPLE_RATE), - (85.3333333333333 / SAMPLE_RATE), - (73.1428571428571 / SAMPLE_RATE), - (1024 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (170.666666666667 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (102.4 / SAMPLE_RATE), - (85.3333333333333 / SAMPLE_RATE), - (73.1428571428571 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (85.3333333333333 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (51.2 / SAMPLE_RATE), - (42.6666666666667 / SAMPLE_RATE), - (36.5714285714286 / SAMPLE_RATE), - (512 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (85.3333333333333 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (51.2 / SAMPLE_RATE), - (42.6666666666667 / SAMPLE_RATE), - (36.5714285714286 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (42.6666666666667 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (25.6 / SAMPLE_RATE), - (21.3333333333333 / SAMPLE_RATE), - (18.2857142857143 / SAMPLE_RATE), - (256 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (42.6666666666667 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (25.6 / SAMPLE_RATE), - (21.3333333333333 / SAMPLE_RATE), - (18.2857142857143 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (21.3333333333333 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (12.8 / SAMPLE_RATE), - (10.6666666666667 / SAMPLE_RATE), - (9.14285714285714 / SAMPLE_RATE), - (128 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (21.3333333333333 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (12.8 / SAMPLE_RATE), - (10.6666666666667 / SAMPLE_RATE), - (9.14285714285714 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (10.6666666666667 / SAMPLE_RATE), - (8 / SAMPLE_RATE), - (6.4 / SAMPLE_RATE), - (5.33333333333333 / SAMPLE_RATE), - (4.57142857142857 / SAMPLE_RATE), - (64 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (10.6666666666667 / SAMPLE_RATE), - (8 / SAMPLE_RATE), - (6.4 / SAMPLE_RATE), - (5.33333333333333 / SAMPLE_RATE), - (4.57142857142857 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (8 / SAMPLE_RATE), - (5.33333333333333 / SAMPLE_RATE), - (4 / SAMPLE_RATE), - (3.2 / SAMPLE_RATE), - (2.66666666666667 / SAMPLE_RATE), - (2.28571428571429 / SAMPLE_RATE), - (32 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (8 / SAMPLE_RATE), - (5.33333333333333 / SAMPLE_RATE), - (4 / SAMPLE_RATE), - (3.2 / SAMPLE_RATE), - (2.66666666666667 / SAMPLE_RATE), - (2.28571428571429 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (8 / SAMPLE_RATE), - (4 / SAMPLE_RATE), - (2.66666666666667 / SAMPLE_RATE), - (2 / SAMPLE_RATE), - (1.6 / SAMPLE_RATE), - (1.33333333333333 / SAMPLE_RATE), - (1.14285714285714 / SAMPLE_RATE), - (16 / SAMPLE_RATE), - (8 / SAMPLE_RATE), - (4 / SAMPLE_RATE), - (2.66666666666667 / SAMPLE_RATE), - (2 / SAMPLE_RATE), - (1.6 / SAMPLE_RATE), - (1.33333333333333 / SAMPLE_RATE), - (1.14285714285714 / SAMPLE_RATE), +const fixed16_16 freqTableNSE[256] = { + float_to_fp16_16(524288 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(52428.8 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), + float_to_fp16_16(524288 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(52428.8 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(26214.4 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), + float_to_fp16_16(262144 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(26214.4 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(13107.2 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), + float_to_fp16_16(131072 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(13107.2 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(6553.6 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), + float_to_fp16_16(65536 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(6553.6 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(3276.8 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), + float_to_fp16_16(32768 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(3276.8 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1638.4 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), + float_to_fp16_16(16384 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1638.4 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(819.2 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(585.142857142857 / SAMPLE_RATE), + float_to_fp16_16(8192 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(819.2 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(585.142857142857 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(409.6 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(292.571428571429 / SAMPLE_RATE), + float_to_fp16_16(4096 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(682.666666666667 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(409.6 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(292.571428571429 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(204.8 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(146.285714285714 / SAMPLE_RATE), + float_to_fp16_16(2048 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(341.333333333333 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(204.8 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(146.285714285714 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(102.4 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), + float_to_fp16_16(1024 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(170.666666666667 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(102.4 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(51.2 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), + float_to_fp16_16(512 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(51.2 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(25.6 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), + float_to_fp16_16(256 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(25.6 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(12.8 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), + float_to_fp16_16(128 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(12.8 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(6.4 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), + float_to_fp16_16(64 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(6.4 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(3.2 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), + float_to_fp16_16(32 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(3.2 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2 / SAMPLE_RATE), + float_to_fp16_16(1.6 / SAMPLE_RATE), + float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), + float_to_fp16_16(16 / SAMPLE_RATE), + float_to_fp16_16(8 / SAMPLE_RATE), + float_to_fp16_16(4 / SAMPLE_RATE), + float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), + float_to_fp16_16(2 / SAMPLE_RATE), + float_to_fp16_16(1.6 / SAMPLE_RATE), + float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), + float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), }; #endif diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 6cc12e1fd1..257bb7b2e4 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -377,9 +377,12 @@ void VBlankIntrWait(void) REG_DISPSTAT &= ~INTR_FLAG_VBLANK; \ }) - bool frameAvailable = TRUE; - bool frameDrawn = false; - static int frames_skipped = 0; + if (headless) { + REG_VCOUNT = DISPLAY_HEIGHT + 1; + HANDLE_VBLANK_INTRS(); + return; + } + if (isRunning) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); @@ -411,6 +414,9 @@ s16 convertedAudio[4096]; void Platform_QueueAudio(const float *data, uint32_t bytesCount) { + if (headless) { + return; + } u32 length = bytesCount / sizeof(float); for (u32 i = 0; i < length; i++) { diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 3823bcf830..96639a1c0e 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -3,14 +3,15 @@ #include "platform/shared/audio/cgb_tables.h" static struct AudioCGB gb; -static float soundChannelPos[4]; -static const float *PU1Table; -static const float *PU2Table; +static fixed16_16 soundChannelPos[4]; +static const fixed16_16 *PU1Table; +static const fixed16_16 *PU2Table; static u32 apuFrame; static u8 apuCycle; static u32 sampleRate; static u16 lfsrMax[2]; -float ch4Samples; +fixed16_16 ch4Samples; +fixed16_16 volScale[16]; void cgb_audio_init(u32 rate) { @@ -39,7 +40,9 @@ void cgb_audio_init(u32 rate) gb.ch4LFSR[1] = 0x80; lfsrMax[0] = 0x8000; lfsrMax[1] = 0x80; - ch4Samples = 0.0f; + ch4Samples = 0; + for (int i = 0; i < 16; i++) + volScale[i] = u32_to_fp16_16(i) / 15; } void cgb_set_sweep(u8 sweep) @@ -52,8 +55,8 @@ void cgb_set_sweep(u8 sweep) void cgb_set_wavram() { for (u8 wavi = 0; wavi < 0x10; wavi++) { - gb.WAVRAM[(wavi << 1)] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) / 7.5f - 1.0f; - gb.WAVRAM[(wavi << 1) + 1] = (((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) / 7.5f - 1.0f; + gb.WAVRAM[(wavi << 1)] = float_to_fp16_16((((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) / 7.5f - 1.0f); + gb.WAVRAM[(wavi << 1) + 1] = float_to_fp16_16((((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) / 7.5f - 1.0f); } } @@ -101,10 +104,15 @@ void cgb_trigger_note(u8 channel) } } -#include +// #include +// #include + +double timeSpentAcc = 0; +int calls = 0; void cgb_audio_generate(u16 samplesPerFrame) { + // clock_t begin = clock(); float *outBuffer = gb.outBuffer; switch (REG_NR11 & 0xC0) { case 0x00: @@ -198,32 +206,32 @@ void cgb_audio_generate(u16 samplesPerFrame) soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF]; soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF]; soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF]; - while (soundChannelPos[0] >= (32)) - soundChannelPos[0] -= (32); - while (soundChannelPos[1] >= (32)) - soundChannelPos[1] -= (32); - while (soundChannelPos[2] >= (32)) - soundChannelPos[2] -= (32); - float outputL = 0; - float outputR = 0; + while (soundChannelPos[0] >= u32_to_fp16_16(32)) + soundChannelPos[0] -= u32_to_fp16_16(32); + while (soundChannelPos[1] >= u32_to_fp16_16(32)) + soundChannelPos[1] -= u32_to_fp16_16(32); + while (soundChannelPos[2] >= u32_to_fp16_16(32)) + soundChannelPos[2] -= u32_to_fp16_16(32); + fixed16_16 outputL = 0; + fixed16_16 outputR = 0; if (REG_NR52 & 0x80) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if (REG_NR51 & 0x10) - outputL += (gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])]); + outputL += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); if (REG_NR51 & 0x01) - outputR += (gb.Vol[0] * PU1Table[(int)(soundChannelPos[0])]); + outputR += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); } if ((gb.DAC[1]) && (REG_NR52 & 0x02)) { if (REG_NR51 & 0x20) - outputL += (gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])]); + outputL += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); if (REG_NR51 & 0x02) - outputR += (gb.Vol[1] * PU2Table[(int)(soundChannelPos[1])]); + outputR += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); } if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) { if (REG_NR51 & 0x40) - outputL += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f; + outputL += (gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] >> 2); if (REG_NR51 & 0x04) - outputR += gb.Vol[2] * gb.WAVRAM[(int)(soundChannelPos[2])] / 4.0f; + outputR += (gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] >> 2); } if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); @@ -235,7 +243,7 @@ void cgb_audio_generate(u16 samplesPerFrame) ch4Out--; } int avgDiv = 1; - while (ch4Samples >= 1) { + while (ch4Samples >= u32_to_fp16_16(1)) { avgDiv++; bool8 lfsrCarry = 0; if (gb.ch4LFSR[lfsrMode] & 2) @@ -250,9 +258,9 @@ void cgb_audio_generate(u16 samplesPerFrame) } else { ch4Out--; } - ch4Samples -= 1; + ch4Samples -= u32_to_fp16_16(1); } - float sample = ch4Out; + fixed16_16 sample = u32_to_fp16_16(ch4Out); if (avgDiv > 1) sample /= avgDiv; if (REG_NR51 & 0x80) @@ -261,9 +269,16 @@ void cgb_audio_generate(u16 samplesPerFrame) outputR += (gb.Vol[3] * sample / 15); } } - outBuffer[0] = outputL * 0.25f; - outBuffer[1] = outputR * 0.25f; + outBuffer[0] = fp16_16_to_float(outputL >> 2); + outBuffer[1] = fp16_16_to_float(outputR >> 2); } + // clock_t end = clock(); + // double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + // calls++; + // timeSpentAcc += time_spent; + // if ((calls % 60) == 0) { + // printf("Time spent: %f, avg: %f\n", time_spent, timeSpentAcc / calls); + // } } float *cgb_get_buffer() { return gb.outBuffer; } From 058046e90abdb4b8fc7803286063fd563cbd146d Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 21 Feb 2026 15:26:22 +0000 Subject: [PATCH 19/51] less float --- src/platform/shared/audio/cgb_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 96639a1c0e..04953dec1f 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -55,8 +55,8 @@ void cgb_set_sweep(u8 sweep) void cgb_set_wavram() { for (u8 wavi = 0; wavi < 0x10; wavi++) { - gb.WAVRAM[(wavi << 1)] = float_to_fp16_16((((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) / 7.5f - 1.0f); - gb.WAVRAM[(wavi << 1) + 1] = float_to_fp16_16((((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) / 7.5f - 1.0f); + gb.WAVRAM[(wavi << 1)] = (u32_to_fp16_16(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) * 2) / 15 - u32_to_fp16_16(1); + gb.WAVRAM[(wavi << 1) + 1] = (u32_to_fp16_16(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) * 2) / 15 - u32_to_fp16_16(1); } } From 6381aba01ed6b180dbfad01172ce8baf6e94a208 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 21 Feb 2026 17:23:11 +0000 Subject: [PATCH 20/51] whole pipeline in s16 --- include/lib/m4a/m4a_internal.h | 2 +- include/platform/platform.h | 2 +- include/platform/shared/audio/cgb_audio.h | 4 +- src/platform/pret_sdl/sdl2.c | 4 +- src/platform/ps2/ps2.c | 20 ++------- src/platform/shared/audio/cgb_audio.c | 12 ++--- src/platform/shared/audio/m4a_sound_mixer.c | 49 +++++++++++++-------- src/platform/win32/win32.c | 2 +- 8 files changed, 46 insertions(+), 49 deletions(-) diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index dec6699065..126513842e 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -272,7 +272,7 @@ struct SoundMixerState { #else // TODO: let's not make this float, they are slow // on older systems - float pcmBuffer[PCM_DMA_BUF_SIZE * 2]; + fixed16_16 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; #endif }; diff --git a/include/platform/platform.h b/include/platform/platform.h index 504c23586d..7acab1b241 100644 --- a/include/platform/platform.h +++ b/include/platform/platform.h @@ -21,6 +21,6 @@ extern void Platform_RLFree(unsigned char *dest); extern void Platform_LZDecompressUnsafe(unsigned char *src, unsigned char *dest); extern void Platform_RLDecompressUnsafe(unsigned char *src, unsigned char *dest); -extern void Platform_QueueAudio(const float *data, u32 numBytes); +extern void Platform_QueueAudio(const s16 *data, u32 numBytes); #endif // GUARD_SA2_PLATFORM_H diff --git a/include/platform/shared/audio/cgb_audio.h b/include/platform/shared/audio/cgb_audio.h index 5efce08e29..f2fa7ba54b 100644 --- a/include/platform/shared/audio/cgb_audio.h +++ b/include/platform/shared/audio/cgb_audio.h @@ -20,7 +20,7 @@ struct AudioCGB { bool8 DAC[4]; fixed16_16 WAVRAM[32]; u16 ch4LFSR[2]; - float outBuffer[PCM_DMA_BUF_SIZE * 2]; + fixed16_16 outBuffer[PCM_DMA_BUF_SIZE * 2]; }; void cgb_audio_init(u32 rate); @@ -31,6 +31,6 @@ void cgb_set_length(u8 channel, u8 length); void cgb_set_envelope(u8 channel, u8 envelope); void cgb_trigger_note(u8 channel); void cgb_audio_generate(u16 samplesPerFrame); -float *cgb_get_buffer(); +fixed16_16 *cgb_get_buffer(); #endif diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index eba3546218..a5dfacb3af 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -336,7 +336,7 @@ int main(int argc, char **argv) SDL_memset(&want, 0, sizeof(want)); /* or SDL_zero(want) */ want.freq = 48000; - want.format = AUDIO_F32; + want.format = AUDIO_S16; want.channels = 2; want.samples = (want.freq / 60); cgb_audio_init(want.freq); @@ -627,7 +627,7 @@ static u16 PollJoystickButtons(void) u32 fullScreenFlags = 0; static SDL_DisplayMode sdlDispMode = { 0 }; -void Platform_QueueAudio(const float *data, uint32_t bytesCount) +void Platform_QueueAudio(const s16 *data, uint32_t bytesCount) { if (headless) { return; diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 257bb7b2e4..83d8060fa3 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -141,7 +141,7 @@ static void AudioPlay(const uint8_t *buf, size_t len) void VideoInit(void) { if (vid_mode == NULL) { - vid_mode = &vid_modes[3]; // Standard def 480p + vid_mode = &vid_modes[1]; // Standard def 480p } else { if (use_hires) { gsKit_hires_deinit_global(gsGlobal); @@ -412,26 +412,12 @@ void Platform_StoreSaveFile(void) { StoreSaveFile(); } s16 convertedAudio[4096]; -void Platform_QueueAudio(const float *data, uint32_t bytesCount) +void Platform_QueueAudio(const s16 *data, uint32_t bytesCount) { if (headless) { return; } - u32 length = bytesCount / sizeof(float); - - for (u32 i = 0; i < length; i++) { - float sample = data[i]; - - if (sample > 1.0f) - sample = 1.0f; - else if (sample < -1.0f) - sample = -1.0f; - - // Convert to s16 - convertedAudio[i] = (int16_t)(sample * 32767.0f + (sample >= 0 ? 0.5f : -0.5f)); - } - - AudioPlay((uint8_t *)convertedAudio, length * sizeof(u16)); + AudioPlay((uint8_t *)data, bytesCount); } u16 Platform_GetKeyInput(void) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 04953dec1f..aca7c36dff 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -113,7 +113,7 @@ int calls = 0; void cgb_audio_generate(u16 samplesPerFrame) { // clock_t begin = clock(); - float *outBuffer = gb.outBuffer; + fixed16_16 *outBuffer = gb.outBuffer; switch (REG_NR11 & 0xC0) { case 0x00: PU1Table = PU0; @@ -264,13 +264,13 @@ void cgb_audio_generate(u16 samplesPerFrame) if (avgDiv > 1) sample /= avgDiv; if (REG_NR51 & 0x80) - outputL += (gb.Vol[3] * sample / 15); + outputL += (sample * volScale[gb.Vol[3]]) >> 16; if (REG_NR51 & 0x08) - outputR += (gb.Vol[3] * sample / 15); + outputR += (sample * volScale[gb.Vol[3]]) >> 16; } } - outBuffer[0] = fp16_16_to_float(outputL >> 2); - outBuffer[1] = fp16_16_to_float(outputR >> 2); + outBuffer[0] = (outputL >> 2); + outBuffer[1] = (outputR >> 2); } // clock_t end = clock(); // double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; @@ -281,4 +281,4 @@ void cgb_audio_generate(u16 samplesPerFrame) // } } -float *cgb_get_buffer() { return gb.outBuffer; } +fixed16_16 *cgb_get_buffer() { return gb.outBuffer; } diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index 6482d6382f..dc4d59f01e 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -5,9 +5,9 @@ #include "platform/platform.h" #include "platform/shared/audio/cgb_audio.h" -static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, float *pcmBuffer, +static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed16_16 *pcmBuffer, u16 samplesPerFrame, float sampleRateReciprocal); -static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, float *pcmBuffer, u8 dmaCounter, +static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed16_16 *pcmBuffer, u8 dmaCounter, u16 maxBufSize); static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav); static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track); @@ -25,7 +25,7 @@ static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track); #define FLOOR_DIV_POW2(a, b) ((a) > 0 ? (a) / (b) : (((a) + 1 - (b)) / (b))) #endif -static float audioBuffer[PCM_DMA_BUF_SIZE]; +static s16 audioBuffer[PCM_DMA_BUF_SIZE]; static struct SoundMixerState sSoundInfo = { 0 }; struct SoundMixerState *SOUND_INFO_PTR = &sSoundInfo; @@ -57,7 +57,7 @@ void SoundMain(void) mixer->CgbSound(); s32 samplesPerFrame = mixer->samplesPerFrame; - float *pcmBuffer = mixer->pcmBuffer; + fixed16_16 *pcmBuffer = mixer->pcmBuffer; s32 dmaCounter = mixer->dmaCounter; if (dmaCounter > 1) { @@ -68,7 +68,7 @@ void SoundMain(void) cgb_audio_generate(samplesPerFrame); } -static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, float *pcmBuffer, u8 dmaCounter, +static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed16_16 *pcmBuffer, u8 dmaCounter, u16 maxBufSize) { u32 reverb = mixer->reverb; @@ -76,8 +76,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa // The vanilla reverb effect outputs a mono sound from four sources: // - L/R channels as they were mixer->framesPerDmaCycle frames ago // - L/R channels as they were (mixer->framesPerDmaCycle - 1) frames ago - float *tmp1 = pcmBuffer; - float *tmp2; + fixed16_16 *tmp1 = pcmBuffer; + fixed16_16 *tmp2; if (dmaCounter == 2) { tmp2 = mixer->pcmBuffer; } else { @@ -85,8 +85,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa } u16 i = 0; do { - float s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1]; - s *= ((float)reverb / 512.0f); + fixed16_16 s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1]; + s = (s * reverb) >> 9; tmp1[0] = tmp1[1] = s; tmp1 += 2; tmp2 += 2; @@ -95,7 +95,7 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa // memset(pcmBuffer, 0, samplesPerFrame); // memset(pcmBuffer + maxBufSize, 0, samplesPerFrame); for (int i = 0; i < samplesPerFrame; i++) { - float *dst = &pcmBuffer[i * 2]; + fixed16_16 *dst = &pcmBuffer[i * 2]; dst[1] = dst[0] = 0.0f; } } @@ -228,7 +228,7 @@ static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav } } -static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, float *pcmBuffer, +static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed16_16 *pcmBuffer, u16 samplesPerFrame, float sampleRateReciprocal) { /*, [[[]]]) {*/ u8 v = chan->data.sound.envelopeVol * (mixer->masterVol + 1) / 16U; @@ -250,8 +250,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { s8 c = *(current++); - pcmBuffer[1] += (c * envR) / 32768.0f; - pcmBuffer[0] += (c * envL) / 32768.0f; + pcmBuffer[1] += ((s32)c * envR) << 1; + pcmBuffer[0] += ((s32)c * envL) << 1; if (--samplesLeftInWav == 0) { samplesLeftInWav = loopLen; if (loopLen != 0) { @@ -278,8 +278,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour // and the next sample. Also cancel out the 9.23 stuff float sample = (finePos * m) + b; - pcmBuffer[1] += (sample * envR) / 32768.0f; - pcmBuffer[0] += (sample * envL) / 32768.0f; + pcmBuffer[1] += ((s32)sample * envR) << 1; + pcmBuffer[0] += ((s32)sample * envL) << 1; finePos += romSamplesPerOutputSample; u32 newCoarsePos = finePos; @@ -908,8 +908,8 @@ void m4aSoundVSync(void) struct SoundMixerState *mixer = SOUND_INFO_PTR; if (mixer->lockStatus - ID_NUMBER <= 1) { s32 samplesPerFrame = mixer->samplesPerFrame * 2; - float *m4aBuffer = mixer->pcmBuffer; - float *cgbBuffer = cgb_get_buffer(); + fixed16_16 *m4aBuffer = mixer->pcmBuffer; + fixed16_16 *cgbBuffer = cgb_get_buffer(); s32 dmaCounter = mixer->dmaCounter; if (dmaCounter > 1) { @@ -917,10 +917,21 @@ void m4aSoundVSync(void) } for (u32 i = 0; i < samplesPerFrame; i++) { - audioBuffer[i] = m4aBuffer[i] + cgbBuffer[i]; + // Sample is fixed 16.16 with a value of -1 to 1 + fixed16_16 sample = (m4aBuffer[i] + cgbBuffer[i]); + // Prevent distorting + if (sample > u32_to_fp16_16(1)) + sample = u32_to_fp16_16(1); + if (sample < -u32_to_fp16_16(1)) { + sample = -u32_to_fp16_16(1); + } + // 1 in 16.16 format is 65536 + // so >> 1 will convert to the + // size expected for s16 audio + audioBuffer[i] = sample >> 1; } - Platform_QueueAudio(audioBuffer, samplesPerFrame * sizeof(float)); + Platform_QueueAudio(audioBuffer, samplesPerFrame * sizeof(s16)); if ((s8)(--mixer->dmaCounter) <= 0) mixer->dmaCounter = mixer->framesPerDmaCycle; } diff --git a/src/platform/win32/win32.c b/src/platform/win32/win32.c index 60d375dfb8..1072b707cb 100644 --- a/src/platform/win32/win32.c +++ b/src/platform/win32/win32.c @@ -449,4 +449,4 @@ void *Platform_malloc(size_t numBytes) { return HeapAlloc(GetProcessHeap(), HEAP void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } -void Platform_QueueAudio(const float *data, u32 numBytes) { } +void Platform_QueueAudio(const float *s16, u32 numBytes) { } From 21575d4e7b222d8b878251ca97b60a2aa3ee0b68 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sat, 21 Feb 2026 17:57:35 +0000 Subject: [PATCH 21/51] convert final mixer value to fixed 16 --- include/lib/m4a/m4a_internal.h | 2 +- src/platform/shared/audio/m4a_sound_mixer.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 126513842e..832dd2000c 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -212,7 +212,7 @@ struct MixerSource { u8 padding5; u32 ct; - float fw; + fixed16_16 fw; u32 freq; } sound; diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index dc4d59f01e..66b944aa23 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -266,8 +266,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour chan->data.sound.ct = samplesLeftInWav; chan->current = current; } else { - float finePos = chan->data.sound.fw; - float romSamplesPerOutputSample = chan->data.sound.freq * sampleRateReciprocal; + fixed16_16 finePos = chan->data.sound.fw; + fixed16_16 romSamplesPerOutputSample = float_to_fp16_16(chan->data.sound.freq * sampleRateReciprocal); s16 b = current[0]; s16 m = current[1] - b; @@ -276,15 +276,15 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { // Use linear interpolation to calculate a value between the current sample in the wav // and the next sample. Also cancel out the 9.23 stuff - float sample = (finePos * m) + b; + s32 sample = fp16_16_to_u32(finePos * m) + b; - pcmBuffer[1] += ((s32)sample * envR) << 1; - pcmBuffer[0] += ((s32)sample * envL) << 1; + pcmBuffer[1] += (sample * envR) << 1; + pcmBuffer[0] += (sample * envL) << 1; finePos += romSamplesPerOutputSample; - u32 newCoarsePos = finePos; + u32 newCoarsePos = fp16_16_to_u32(finePos); if (newCoarsePos != 0) { - finePos -= (int)finePos; + finePos = fp16_16_fractional_part(finePos); samplesLeftInWav -= newCoarsePos; if (samplesLeftInWav <= 0) { if (loopLen != 0) { From e6739b59935013d6dd58ff4accc04deb79a93faa Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 22 Feb 2026 00:58:06 +0000 Subject: [PATCH 22/51] fix audio issue due to overflow --- src/platform/shared/audio/cgb_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index aca7c36dff..7fcfb3a547 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -264,9 +264,9 @@ void cgb_audio_generate(u16 samplesPerFrame) if (avgDiv > 1) sample /= avgDiv; if (REG_NR51 & 0x80) - outputL += (sample * volScale[gb.Vol[3]]) >> 16; + outputL += ((s64)sample * volScale[gb.Vol[3]]) >> 16; if (REG_NR51 & 0x08) - outputR += (sample * volScale[gb.Vol[3]]) >> 16; + outputR += ((s64)sample * volScale[gb.Vol[3]]) >> 16; } } outBuffer[0] = (outputL >> 2); From ffb1a20b8ce72415e6a99459abdd50ff6a87d502 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 22 Feb 2026 01:50:06 +0000 Subject: [PATCH 23/51] more precision in cgb audio --- include/lib/m4a/m4a_internal.h | 2 + include/platform/shared/audio/cgb_tables.h | 4098 ++++++++++---------- src/platform/pret_sdl/sdl2.c | 4 +- src/platform/shared/audio/cgb_audio.c | 33 +- 4 files changed, 2069 insertions(+), 2068 deletions(-) diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 832dd2000c..247823a98c 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -120,6 +120,8 @@ typedef s32 fixed8_24; #define fp16_16_fractional_part(value) ((value)&0xFFFF) #define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) +#define u32_to_fp8_24(value) ((value) << 24) +#define fp8_24_to_u32(value) ((value) >> 24) #define fp8_24_to_float(value) (float)((value) / 16777216.0) diff --git a/include/platform/shared/audio/cgb_tables.h b/include/platform/shared/audio/cgb_tables.h index 202807cf50..e071661b42 100644 --- a/include/platform/shared/audio/cgb_tables.h +++ b/include/platform/shared/audio/cgb_tables.h @@ -48,2055 +48,2055 @@ const fixed16_16 PU3[32] int16_t WAV[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; -const fixed16_16 freqTable[2048] = { - float_to_fp16_16(32 / FREQUENCY_RATE), - float_to_fp16_16(32.0156326331216 / FREQUENCY_RATE), - float_to_fp16_16(32.0312805474096 / FREQUENCY_RATE), - float_to_fp16_16(32.0469437652812 / FREQUENCY_RATE), - float_to_fp16_16(32.0626223091976 / FREQUENCY_RATE), - float_to_fp16_16(32.0783162016642 / FREQUENCY_RATE), - float_to_fp16_16(32.0940254652302 / FREQUENCY_RATE), - float_to_fp16_16(32.109750122489 / FREQUENCY_RATE), - float_to_fp16_16(32.1254901960784 / FREQUENCY_RATE), - float_to_fp16_16(32.1412457086807 / FREQUENCY_RATE), - float_to_fp16_16(32.1570166830226 / FREQUENCY_RATE), - float_to_fp16_16(32.1728031418753 / FREQUENCY_RATE), - float_to_fp16_16(32.188605108055 / FREQUENCY_RATE), - float_to_fp16_16(32.2044226044226 / FREQUENCY_RATE), - float_to_fp16_16(32.220255653884 / FREQUENCY_RATE), - float_to_fp16_16(32.2361042793901 / FREQUENCY_RATE), - float_to_fp16_16(32.251968503937 / FREQUENCY_RATE), - float_to_fp16_16(32.2678483505662 / FREQUENCY_RATE), - float_to_fp16_16(32.2837438423645 / FREQUENCY_RATE), - float_to_fp16_16(32.2996550024643 / FREQUENCY_RATE), - float_to_fp16_16(32.3155818540434 / FREQUENCY_RATE), - float_to_fp16_16(32.3315244203256 / FREQUENCY_RATE), - float_to_fp16_16(32.3474827245805 / FREQUENCY_RATE), - float_to_fp16_16(32.3634567901235 / FREQUENCY_RATE), - float_to_fp16_16(32.3794466403162 / FREQUENCY_RATE), - float_to_fp16_16(32.3954522985665 / FREQUENCY_RATE), - float_to_fp16_16(32.4114737883284 / FREQUENCY_RATE), - float_to_fp16_16(32.4275111331024 / FREQUENCY_RATE), - float_to_fp16_16(32.4435643564356 / FREQUENCY_RATE), - float_to_fp16_16(32.4596334819217 / FREQUENCY_RATE), - float_to_fp16_16(32.4757185332012 / FREQUENCY_RATE), - float_to_fp16_16(32.4918195339613 / FREQUENCY_RATE), - float_to_fp16_16(32.5079365079365 / FREQUENCY_RATE), - float_to_fp16_16(32.5240694789082 / FREQUENCY_RATE), - float_to_fp16_16(32.5402184707051 / FREQUENCY_RATE), - float_to_fp16_16(32.5563835072032 / FREQUENCY_RATE), - float_to_fp16_16(32.572564612326 / FREQUENCY_RATE), - float_to_fp16_16(32.5887618100448 / FREQUENCY_RATE), - float_to_fp16_16(32.6049751243781 / FREQUENCY_RATE), - float_to_fp16_16(32.6212045793927 / FREQUENCY_RATE), - float_to_fp16_16(32.6374501992032 / FREQUENCY_RATE), - float_to_fp16_16(32.6537120079721 / FREQUENCY_RATE), - float_to_fp16_16(32.6699900299103 / FREQUENCY_RATE), - float_to_fp16_16(32.6862842892768 / FREQUENCY_RATE), - float_to_fp16_16(32.7025948103792 / FREQUENCY_RATE), - float_to_fp16_16(32.7189216175736 / FREQUENCY_RATE), - float_to_fp16_16(32.7352647352647 / FREQUENCY_RATE), - float_to_fp16_16(32.751624187906 / FREQUENCY_RATE), - float_to_fp16_16(32.768 / FREQUENCY_RATE), - float_to_fp16_16(32.784392196098 / FREQUENCY_RATE), - float_to_fp16_16(32.8008008008008 / FREQUENCY_RATE), - float_to_fp16_16(32.8172258387581 / FREQUENCY_RATE), - float_to_fp16_16(32.8336673346693 / FREQUENCY_RATE), - float_to_fp16_16(32.8501253132832 / FREQUENCY_RATE), - float_to_fp16_16(32.8665997993982 / FREQUENCY_RATE), - float_to_fp16_16(32.8830908178625 / FREQUENCY_RATE), - float_to_fp16_16(32.8995983935743 / FREQUENCY_RATE), - float_to_fp16_16(32.9161225514817 / FREQUENCY_RATE), - float_to_fp16_16(32.9326633165829 / FREQUENCY_RATE), - float_to_fp16_16(32.9492207139266 / FREQUENCY_RATE), - float_to_fp16_16(32.9657947686117 / FREQUENCY_RATE), - float_to_fp16_16(32.9823855057876 / FREQUENCY_RATE), - float_to_fp16_16(32.9989929506546 / FREQUENCY_RATE), - float_to_fp16_16(33.0156171284635 / FREQUENCY_RATE), - float_to_fp16_16(33.0322580645161 / FREQUENCY_RATE), - float_to_fp16_16(33.0489157841654 / FREQUENCY_RATE), - float_to_fp16_16(33.0655903128153 / FREQUENCY_RATE), - float_to_fp16_16(33.0822816759213 / FREQUENCY_RATE), - float_to_fp16_16(33.0989898989899 / FREQUENCY_RATE), - float_to_fp16_16(33.1157150075796 / FREQUENCY_RATE), - float_to_fp16_16(33.1324570273003 / FREQUENCY_RATE), - float_to_fp16_16(33.1492159838139 / FREQUENCY_RATE), - float_to_fp16_16(33.165991902834 / FREQUENCY_RATE), - float_to_fp16_16(33.1827848101266 / FREQUENCY_RATE), - float_to_fp16_16(33.1995947315096 / FREQUENCY_RATE), - float_to_fp16_16(33.2164216928535 / FREQUENCY_RATE), - float_to_fp16_16(33.2332657200811 / FREQUENCY_RATE), - float_to_fp16_16(33.2501268391679 / FREQUENCY_RATE), - float_to_fp16_16(33.2670050761421 / FREQUENCY_RATE), - float_to_fp16_16(33.2839004570848 / FREQUENCY_RATE), - float_to_fp16_16(33.3008130081301 / FREQUENCY_RATE), - float_to_fp16_16(33.3177427554652 / FREQUENCY_RATE), - float_to_fp16_16(33.3346897253306 / FREQUENCY_RATE), - float_to_fp16_16(33.3516539440204 / FREQUENCY_RATE), - float_to_fp16_16(33.3686354378819 / FREQUENCY_RATE), - float_to_fp16_16(33.3856342333164 / FREQUENCY_RATE), - float_to_fp16_16(33.4026503567788 / FREQUENCY_RATE), - float_to_fp16_16(33.4196838347782 / FREQUENCY_RATE), - float_to_fp16_16(33.4367346938776 / FREQUENCY_RATE), - float_to_fp16_16(33.4538029606942 / FREQUENCY_RATE), - float_to_fp16_16(33.4708886618999 / FREQUENCY_RATE), - float_to_fp16_16(33.4879918242207 / FREQUENCY_RATE), - float_to_fp16_16(33.5051124744376 / FREQUENCY_RATE), - float_to_fp16_16(33.5222506393862 / FREQUENCY_RATE), - float_to_fp16_16(33.539406345957 / FREQUENCY_RATE), - float_to_fp16_16(33.5565796210957 / FREQUENCY_RATE), - float_to_fp16_16(33.5737704918033 / FREQUENCY_RATE), - float_to_fp16_16(33.5909789851358 / FREQUENCY_RATE), - float_to_fp16_16(33.6082051282051 / FREQUENCY_RATE), - float_to_fp16_16(33.6254489481786 / FREQUENCY_RATE), - float_to_fp16_16(33.6427104722793 / FREQUENCY_RATE), - float_to_fp16_16(33.6599897277863 / FREQUENCY_RATE), - float_to_fp16_16(33.6772867420349 / FREQUENCY_RATE), - float_to_fp16_16(33.6946015424164 / FREQUENCY_RATE), - float_to_fp16_16(33.7119341563786 / FREQUENCY_RATE), - float_to_fp16_16(33.7292846114256 / FREQUENCY_RATE), - float_to_fp16_16(33.7466529351184 / FREQUENCY_RATE), - float_to_fp16_16(33.7640391550747 / FREQUENCY_RATE), - float_to_fp16_16(33.7814432989691 / FREQUENCY_RATE), - float_to_fp16_16(33.7988653945333 / FREQUENCY_RATE), - float_to_fp16_16(33.8163054695562 / FREQUENCY_RATE), - float_to_fp16_16(33.8337635518844 / FREQUENCY_RATE), - float_to_fp16_16(33.8512396694215 / FREQUENCY_RATE), - float_to_fp16_16(33.8687338501292 / FREQUENCY_RATE), - float_to_fp16_16(33.8862461220269 / FREQUENCY_RATE), - float_to_fp16_16(33.9037765131919 / FREQUENCY_RATE), - float_to_fp16_16(33.9213250517598 / FREQUENCY_RATE), - float_to_fp16_16(33.9388917659244 / FREQUENCY_RATE), - float_to_fp16_16(33.9564766839378 / FREQUENCY_RATE), - float_to_fp16_16(33.9740798341109 / FREQUENCY_RATE), - float_to_fp16_16(33.9917012448133 / FREQUENCY_RATE), - float_to_fp16_16(34.0093409444733 / FREQUENCY_RATE), - float_to_fp16_16(34.0269989615784 / FREQUENCY_RATE), - float_to_fp16_16(34.0446753246753 / FREQUENCY_RATE), - float_to_fp16_16(34.0623700623701 / FREQUENCY_RATE), - float_to_fp16_16(34.0800832033281 / FREQUENCY_RATE), - float_to_fp16_16(34.0978147762747 / FREQUENCY_RATE), - float_to_fp16_16(34.1155648099948 / FREQUENCY_RATE), - float_to_fp16_16(34.1333333333333 / FREQUENCY_RATE), - float_to_fp16_16(34.1511203751954 / FREQUENCY_RATE), - float_to_fp16_16(34.1689259645464 / FREQUENCY_RATE), - float_to_fp16_16(34.1867501304121 / FREQUENCY_RATE), - float_to_fp16_16(34.2045929018789 / FREQUENCY_RATE), - float_to_fp16_16(34.222454308094 / FREQUENCY_RATE), - float_to_fp16_16(34.2403343782654 / FREQUENCY_RATE), - float_to_fp16_16(34.2582331416623 / FREQUENCY_RATE), - float_to_fp16_16(34.2761506276151 / FREQUENCY_RATE), - float_to_fp16_16(34.2940868655154 / FREQUENCY_RATE), - float_to_fp16_16(34.3120418848168 / FREQUENCY_RATE), - float_to_fp16_16(34.330015715034 / FREQUENCY_RATE), - float_to_fp16_16(34.3480083857442 / FREQUENCY_RATE), - float_to_fp16_16(34.3660199265863 / FREQUENCY_RATE), - float_to_fp16_16(34.3840503672613 / FREQUENCY_RATE), - float_to_fp16_16(34.4020997375328 / FREQUENCY_RATE), - float_to_fp16_16(34.4201680672269 / FREQUENCY_RATE), - float_to_fp16_16(34.4382553862323 / FREQUENCY_RATE), - float_to_fp16_16(34.4563617245005 / FREQUENCY_RATE), - float_to_fp16_16(34.4744871120463 / FREQUENCY_RATE), - float_to_fp16_16(34.4926315789474 / FREQUENCY_RATE), - float_to_fp16_16(34.5107951553449 / FREQUENCY_RATE), - float_to_fp16_16(34.5289778714436 / FREQUENCY_RATE), - float_to_fp16_16(34.5471797575119 / FREQUENCY_RATE), - float_to_fp16_16(34.5654008438819 / FREQUENCY_RATE), - float_to_fp16_16(34.5836411609499 / FREQUENCY_RATE), - float_to_fp16_16(34.6019007391763 / FREQUENCY_RATE), - float_to_fp16_16(34.6201796090861 / FREQUENCY_RATE), - float_to_fp16_16(34.6384778012685 / FREQUENCY_RATE), - float_to_fp16_16(34.6567953463776 / FREQUENCY_RATE), - float_to_fp16_16(34.6751322751323 / FREQUENCY_RATE), - float_to_fp16_16(34.6934886183166 / FREQUENCY_RATE), - float_to_fp16_16(34.7118644067797 / FREQUENCY_RATE), - float_to_fp16_16(34.7302596714361 / FREQUENCY_RATE), - float_to_fp16_16(34.7486744432662 / FREQUENCY_RATE), - float_to_fp16_16(34.7671087533156 / FREQUENCY_RATE), - float_to_fp16_16(34.7855626326964 / FREQUENCY_RATE), - float_to_fp16_16(34.8040361125863 / FREQUENCY_RATE), - float_to_fp16_16(34.8225292242295 / FREQUENCY_RATE), - float_to_fp16_16(34.8410419989367 / FREQUENCY_RATE), - float_to_fp16_16(34.8595744680851 / FREQUENCY_RATE), - float_to_fp16_16(34.8781266631187 / FREQUENCY_RATE), - float_to_fp16_16(34.8966986155485 / FREQUENCY_RATE), - float_to_fp16_16(34.9152903569526 / FREQUENCY_RATE), - float_to_fp16_16(34.9339019189765 / FREQUENCY_RATE), - float_to_fp16_16(34.9525333333333 / FREQUENCY_RATE), - float_to_fp16_16(34.9711846318036 / FREQUENCY_RATE), - float_to_fp16_16(34.989855846236 / FREQUENCY_RATE), - float_to_fp16_16(35.008547008547 / FREQUENCY_RATE), - float_to_fp16_16(35.0272581507215 / FREQUENCY_RATE), - float_to_fp16_16(35.0459893048128 / FREQUENCY_RATE), - float_to_fp16_16(35.0647405029427 / FREQUENCY_RATE), - float_to_fp16_16(35.0835117773019 / FREQUENCY_RATE), - float_to_fp16_16(35.10230316015 / FREQUENCY_RATE), - float_to_fp16_16(35.1211146838156 / FREQUENCY_RATE), - float_to_fp16_16(35.1399463806971 / FREQUENCY_RATE), - float_to_fp16_16(35.1587982832618 / FREQUENCY_RATE), - float_to_fp16_16(35.1776704240472 / FREQUENCY_RATE), - float_to_fp16_16(35.1965628356606 / FREQUENCY_RATE), - float_to_fp16_16(35.2154755507792 / FREQUENCY_RATE), - float_to_fp16_16(35.2344086021505 / FREQUENCY_RATE), - float_to_fp16_16(35.2533620225928 / FREQUENCY_RATE), - float_to_fp16_16(35.2723358449946 / FREQUENCY_RATE), - float_to_fp16_16(35.2913301023156 / FREQUENCY_RATE), - float_to_fp16_16(35.3103448275862 / FREQUENCY_RATE), - float_to_fp16_16(35.3293800539084 / FREQUENCY_RATE), - float_to_fp16_16(35.3484358144552 / FREQUENCY_RATE), - float_to_fp16_16(35.3675121424717 / FREQUENCY_RATE), - float_to_fp16_16(35.3866090712743 / FREQUENCY_RATE), - float_to_fp16_16(35.4057266342518 / FREQUENCY_RATE), - float_to_fp16_16(35.4248648648649 / FREQUENCY_RATE), - float_to_fp16_16(35.4440237966468 / FREQUENCY_RATE), - float_to_fp16_16(35.4632034632035 / FREQUENCY_RATE), - float_to_fp16_16(35.4824038982133 / FREQUENCY_RATE), - float_to_fp16_16(35.501625135428 / FREQUENCY_RATE), - float_to_fp16_16(35.5208672086721 / FREQUENCY_RATE), - float_to_fp16_16(35.5401301518438 / FREQUENCY_RATE), - float_to_fp16_16(35.5594139989148 / FREQUENCY_RATE), - float_to_fp16_16(35.5787187839305 / FREQUENCY_RATE), - float_to_fp16_16(35.5980445410103 / FREQUENCY_RATE), - float_to_fp16_16(35.6173913043478 / FREQUENCY_RATE), - float_to_fp16_16(35.636759108211 / FREQUENCY_RATE), - float_to_fp16_16(35.6561479869423 / FREQUENCY_RATE), - float_to_fp16_16(35.6755579749592 / FREQUENCY_RATE), - float_to_fp16_16(35.6949891067538 / FREQUENCY_RATE), - float_to_fp16_16(35.7144414168937 / FREQUENCY_RATE), - float_to_fp16_16(35.7339149400218 / FREQUENCY_RATE), - float_to_fp16_16(35.7534097108565 / FREQUENCY_RATE), - float_to_fp16_16(35.7729257641921 / FREQUENCY_RATE), - float_to_fp16_16(35.792463134899 / FREQUENCY_RATE), - float_to_fp16_16(35.8120218579235 / FREQUENCY_RATE), - float_to_fp16_16(35.8316019682887 / FREQUENCY_RATE), - float_to_fp16_16(35.8512035010941 / FREQUENCY_RATE), - float_to_fp16_16(35.8708264915161 / FREQUENCY_RATE), - float_to_fp16_16(35.8904709748083 / FREQUENCY_RATE), - float_to_fp16_16(35.9101369863014 / FREQUENCY_RATE), - float_to_fp16_16(35.9298245614035 / FREQUENCY_RATE), - float_to_fp16_16(35.9495337356007 / FREQUENCY_RATE), - float_to_fp16_16(35.9692645444566 / FREQUENCY_RATE), - float_to_fp16_16(35.9890170236134 / FREQUENCY_RATE), - float_to_fp16_16(36.0087912087912 / FREQUENCY_RATE), - float_to_fp16_16(36.0285871357889 / FREQUENCY_RATE), - float_to_fp16_16(36.048404840484 / FREQUENCY_RATE), - float_to_fp16_16(36.0682443588332 / FREQUENCY_RATE), - float_to_fp16_16(36.0881057268722 / FREQUENCY_RATE), - float_to_fp16_16(36.1079889807162 / FREQUENCY_RATE), - float_to_fp16_16(36.1278941565601 / FREQUENCY_RATE), - float_to_fp16_16(36.1478212906784 / FREQUENCY_RATE), - float_to_fp16_16(36.167770419426 / FREQUENCY_RATE), - float_to_fp16_16(36.187741579238 / FREQUENCY_RATE), - float_to_fp16_16(36.2077348066298 / FREQUENCY_RATE), - float_to_fp16_16(36.2277501381979 / FREQUENCY_RATE), - float_to_fp16_16(36.2477876106195 / FREQUENCY_RATE), - float_to_fp16_16(36.267847260653 / FREQUENCY_RATE), - float_to_fp16_16(36.2879291251384 / FREQUENCY_RATE), - float_to_fp16_16(36.3080332409972 / FREQUENCY_RATE), - float_to_fp16_16(36.3281596452328 / FREQUENCY_RATE), - float_to_fp16_16(36.3483083749307 / FREQUENCY_RATE), - float_to_fp16_16(36.3684794672586 / FREQUENCY_RATE), - float_to_fp16_16(36.388672959467 / FREQUENCY_RATE), - float_to_fp16_16(36.4088888888889 / FREQUENCY_RATE), - float_to_fp16_16(36.4291272929405 / FREQUENCY_RATE), - float_to_fp16_16(36.4493882091212 / FREQUENCY_RATE), - float_to_fp16_16(36.4696716750139 / FREQUENCY_RATE), - float_to_fp16_16(36.4899777282851 / FREQUENCY_RATE), - float_to_fp16_16(36.5103064066852 / FREQUENCY_RATE), - float_to_fp16_16(36.5306577480491 / FREQUENCY_RATE), - float_to_fp16_16(36.5510317902956 / FREQUENCY_RATE), - float_to_fp16_16(36.5714285714286 / FREQUENCY_RATE), - float_to_fp16_16(36.5918481295366 / FREQUENCY_RATE), - float_to_fp16_16(36.6122905027933 / FREQUENCY_RATE), - float_to_fp16_16(36.6327557294578 / FREQUENCY_RATE), - float_to_fp16_16(36.6532438478747 / FREQUENCY_RATE), - float_to_fp16_16(36.6737548964745 / FREQUENCY_RATE), - float_to_fp16_16(36.6942889137738 / FREQUENCY_RATE), - float_to_fp16_16(36.7148459383753 / FREQUENCY_RATE), - float_to_fp16_16(36.7354260089686 / FREQUENCY_RATE), - float_to_fp16_16(36.7560291643298 / FREQUENCY_RATE), - float_to_fp16_16(36.7766554433221 / FREQUENCY_RATE), - float_to_fp16_16(36.7973048848961 / FREQUENCY_RATE), - float_to_fp16_16(36.8179775280899 / FREQUENCY_RATE), - float_to_fp16_16(36.8386734120292 / FREQUENCY_RATE), - float_to_fp16_16(36.859392575928 / FREQUENCY_RATE), - float_to_fp16_16(36.8801350590884 / FREQUENCY_RATE), - float_to_fp16_16(36.9009009009009 / FREQUENCY_RATE), - float_to_fp16_16(36.9216901408451 / FREQUENCY_RATE), - float_to_fp16_16(36.9425028184893 / FREQUENCY_RATE), - float_to_fp16_16(36.9633389734913 / FREQUENCY_RATE), - float_to_fp16_16(36.9841986455982 / FREQUENCY_RATE), - float_to_fp16_16(37.0050818746471 / FREQUENCY_RATE), - float_to_fp16_16(37.025988700565 / FREQUENCY_RATE), - float_to_fp16_16(37.0469191633691 / FREQUENCY_RATE), - float_to_fp16_16(37.0678733031674 / FREQUENCY_RATE), - float_to_fp16_16(37.0888511601585 / FREQUENCY_RATE), - float_to_fp16_16(37.1098527746319 / FREQUENCY_RATE), - float_to_fp16_16(37.1308781869688 / FREQUENCY_RATE), - float_to_fp16_16(37.1519274376417 / FREQUENCY_RATE), - float_to_fp16_16(37.173000567215 / FREQUENCY_RATE), - float_to_fp16_16(37.1940976163451 / FREQUENCY_RATE), - float_to_fp16_16(37.2152186257808 / FREQUENCY_RATE), - float_to_fp16_16(37.2363636363636 / FREQUENCY_RATE), - float_to_fp16_16(37.2575326890279 / FREQUENCY_RATE), - float_to_fp16_16(37.2787258248009 / FREQUENCY_RATE), - float_to_fp16_16(37.2999430848036 / FREQUENCY_RATE), - float_to_fp16_16(37.3211845102506 / FREQUENCY_RATE), - float_to_fp16_16(37.3424501424501 / FREQUENCY_RATE), - float_to_fp16_16(37.363740022805 / FREQUENCY_RATE), - float_to_fp16_16(37.3850541928123 / FREQUENCY_RATE), - float_to_fp16_16(37.4063926940639 / FREQUENCY_RATE), - float_to_fp16_16(37.4277555682467 / FREQUENCY_RATE), - float_to_fp16_16(37.4491428571429 / FREQUENCY_RATE), - float_to_fp16_16(37.4705546026301 / FREQUENCY_RATE), - float_to_fp16_16(37.4919908466819 / FREQUENCY_RATE), - float_to_fp16_16(37.5134516313681 / FREQUENCY_RATE), - float_to_fp16_16(37.5349369988545 / FREQUENCY_RATE), - float_to_fp16_16(37.556446991404 / FREQUENCY_RATE), - float_to_fp16_16(37.5779816513761 / FREQUENCY_RATE), - float_to_fp16_16(37.5995410212278 / FREQUENCY_RATE), - float_to_fp16_16(37.6211251435132 / FREQUENCY_RATE), - float_to_fp16_16(37.6427340608845 / FREQUENCY_RATE), - float_to_fp16_16(37.664367816092 / FREQUENCY_RATE), - float_to_fp16_16(37.6860264519839 / FREQUENCY_RATE), - float_to_fp16_16(37.7077100115075 / FREQUENCY_RATE), - float_to_fp16_16(37.7294185377087 / FREQUENCY_RATE), - float_to_fp16_16(37.7511520737327 / FREQUENCY_RATE), - float_to_fp16_16(37.7729106628242 / FREQUENCY_RATE), - float_to_fp16_16(37.7946943483276 / FREQUENCY_RATE), - float_to_fp16_16(37.8165031736872 / FREQUENCY_RATE), - float_to_fp16_16(37.838337182448 / FREQUENCY_RATE), - float_to_fp16_16(37.8601964182553 / FREQUENCY_RATE), - float_to_fp16_16(37.8820809248555 / FREQUENCY_RATE), - float_to_fp16_16(37.903990746096 / FREQUENCY_RATE), - float_to_fp16_16(37.9259259259259 / FREQUENCY_RATE), - float_to_fp16_16(37.9478865083961 / FREQUENCY_RATE), - float_to_fp16_16(37.9698725376593 / FREQUENCY_RATE), - float_to_fp16_16(37.991884057971 / FREQUENCY_RATE), - float_to_fp16_16(38.0139211136891 / FREQUENCY_RATE), - float_to_fp16_16(38.0359837492745 / FREQUENCY_RATE), - float_to_fp16_16(38.0580720092915 / FREQUENCY_RATE), - float_to_fp16_16(38.0801859384079 / FREQUENCY_RATE), - float_to_fp16_16(38.1023255813953 / FREQUENCY_RATE), - float_to_fp16_16(38.1244909831297 / FREQUENCY_RATE), - float_to_fp16_16(38.1466821885914 / FREQUENCY_RATE), - float_to_fp16_16(38.1688992428655 / FREQUENCY_RATE), - float_to_fp16_16(38.1911421911422 / FREQUENCY_RATE), - float_to_fp16_16(38.2134110787172 / FREQUENCY_RATE), - float_to_fp16_16(38.2357059509918 / FREQUENCY_RATE), - float_to_fp16_16(38.2580268534734 / FREQUENCY_RATE), - float_to_fp16_16(38.2803738317757 / FREQUENCY_RATE), - float_to_fp16_16(38.3027469316189 / FREQUENCY_RATE), - float_to_fp16_16(38.3251461988304 / FREQUENCY_RATE), - float_to_fp16_16(38.3475716793446 / FREQUENCY_RATE), - float_to_fp16_16(38.3700234192037 / FREQUENCY_RATE), - float_to_fp16_16(38.3925014645577 / FREQUENCY_RATE), - float_to_fp16_16(38.4150058616647 / FREQUENCY_RATE), - float_to_fp16_16(38.4375366568915 / FREQUENCY_RATE), - float_to_fp16_16(38.4600938967136 / FREQUENCY_RATE), - float_to_fp16_16(38.4826776277158 / FREQUENCY_RATE), - float_to_fp16_16(38.5052878965922 / FREQUENCY_RATE), - float_to_fp16_16(38.527924750147 / FREQUENCY_RATE), - float_to_fp16_16(38.5505882352941 / FREQUENCY_RATE), - float_to_fp16_16(38.5732783990583 / FREQUENCY_RATE), - float_to_fp16_16(38.5959952885748 / FREQUENCY_RATE), - float_to_fp16_16(38.6187389510902 / FREQUENCY_RATE), - float_to_fp16_16(38.6415094339623 / FREQUENCY_RATE), - float_to_fp16_16(38.6643067846608 / FREQUENCY_RATE), - float_to_fp16_16(38.6871310507674 / FREQUENCY_RATE), - float_to_fp16_16(38.7099822799764 / FREQUENCY_RATE), - float_to_fp16_16(38.7328605200946 / FREQUENCY_RATE), - float_to_fp16_16(38.755765819042 / FREQUENCY_RATE), - float_to_fp16_16(38.7786982248521 / FREQUENCY_RATE), - float_to_fp16_16(38.801657785672 / FREQUENCY_RATE), - float_to_fp16_16(38.824644549763 / FREQUENCY_RATE), - float_to_fp16_16(38.8476585655009 / FREQUENCY_RATE), - float_to_fp16_16(38.870699881376 / FREQUENCY_RATE), - float_to_fp16_16(38.8937685459941 / FREQUENCY_RATE), - float_to_fp16_16(38.916864608076 / FREQUENCY_RATE), - float_to_fp16_16(38.9399881164587 / FREQUENCY_RATE), - float_to_fp16_16(38.9631391200951 / FREQUENCY_RATE), - float_to_fp16_16(38.9863176680547 / FREQUENCY_RATE), - float_to_fp16_16(39.0095238095238 / FREQUENCY_RATE), - float_to_fp16_16(39.0327575938058 / FREQUENCY_RATE), - float_to_fp16_16(39.0560190703218 / FREQUENCY_RATE), - float_to_fp16_16(39.0793082886106 / FREQUENCY_RATE), - float_to_fp16_16(39.1026252983294 / FREQUENCY_RATE), - float_to_fp16_16(39.1259701492537 / FREQUENCY_RATE), - float_to_fp16_16(39.1493428912784 / FREQUENCY_RATE), - float_to_fp16_16(39.1727435744172 / FREQUENCY_RATE), - float_to_fp16_16(39.1961722488038 / FREQUENCY_RATE), - float_to_fp16_16(39.2196289646918 / FREQUENCY_RATE), - float_to_fp16_16(39.2431137724551 / FREQUENCY_RATE), - float_to_fp16_16(39.2666267225884 / FREQUENCY_RATE), - float_to_fp16_16(39.2901678657074 / FREQUENCY_RATE), - float_to_fp16_16(39.3137372525495 / FREQUENCY_RATE), - float_to_fp16_16(39.3373349339736 / FREQUENCY_RATE), - float_to_fp16_16(39.360960960961 / FREQUENCY_RATE), - float_to_fp16_16(39.3846153846154 / FREQUENCY_RATE), - float_to_fp16_16(39.4082982561636 / FREQUENCY_RATE), - float_to_fp16_16(39.4320096269555 / FREQUENCY_RATE), - float_to_fp16_16(39.4557495484648 / FREQUENCY_RATE), - float_to_fp16_16(39.4795180722892 / FREQUENCY_RATE), - float_to_fp16_16(39.5033152501507 / FREQUENCY_RATE), - float_to_fp16_16(39.5271411338963 / FREQUENCY_RATE), - float_to_fp16_16(39.5509957754979 / FREQUENCY_RATE), - float_to_fp16_16(39.5748792270531 / FREQUENCY_RATE), - float_to_fp16_16(39.5987915407855 / FREQUENCY_RATE), - float_to_fp16_16(39.6227327690447 / FREQUENCY_RATE), - float_to_fp16_16(39.6467029643073 / FREQUENCY_RATE), - float_to_fp16_16(39.6707021791768 / FREQUENCY_RATE), - float_to_fp16_16(39.694730466384 / FREQUENCY_RATE), - float_to_fp16_16(39.7187878787879 / FREQUENCY_RATE), - float_to_fp16_16(39.7428744693754 / FREQUENCY_RATE), - float_to_fp16_16(39.7669902912621 / FREQUENCY_RATE), - float_to_fp16_16(39.7911353976928 / FREQUENCY_RATE), - float_to_fp16_16(39.8153098420413 / FREQUENCY_RATE), - float_to_fp16_16(39.8395136778115 / FREQUENCY_RATE), - float_to_fp16_16(39.8637469586375 / FREQUENCY_RATE), - float_to_fp16_16(39.8880097382836 / FREQUENCY_RATE), - float_to_fp16_16(39.9123020706455 / FREQUENCY_RATE), - float_to_fp16_16(39.9366240097502 / FREQUENCY_RATE), - float_to_fp16_16(39.9609756097561 / FREQUENCY_RATE), - float_to_fp16_16(39.9853569249542 / FREQUENCY_RATE), - float_to_fp16_16(40.009768009768 / FREQUENCY_RATE), - float_to_fp16_16(40.0342089187538 / FREQUENCY_RATE), - float_to_fp16_16(40.0586797066015 / FREQUENCY_RATE), - float_to_fp16_16(40.0831804281346 / FREQUENCY_RATE), - float_to_fp16_16(40.1077111383109 / FREQUENCY_RATE), - float_to_fp16_16(40.1322718922229 / FREQUENCY_RATE), - float_to_fp16_16(40.156862745098 / FREQUENCY_RATE), - float_to_fp16_16(40.1814837522992 / FREQUENCY_RATE), - float_to_fp16_16(40.2061349693252 / FREQUENCY_RATE), - float_to_fp16_16(40.2308164518109 / FREQUENCY_RATE), - float_to_fp16_16(40.2555282555283 / FREQUENCY_RATE), - float_to_fp16_16(40.280270436386 / FREQUENCY_RATE), - float_to_fp16_16(40.3050430504305 / FREQUENCY_RATE), - float_to_fp16_16(40.3298461538462 / FREQUENCY_RATE), - float_to_fp16_16(40.3546798029557 / FREQUENCY_RATE), - float_to_fp16_16(40.3795440542206 / FREQUENCY_RATE), - float_to_fp16_16(40.4044389642417 / FREQUENCY_RATE), - float_to_fp16_16(40.4293645897594 / FREQUENCY_RATE), - float_to_fp16_16(40.4543209876543 / FREQUENCY_RATE), - float_to_fp16_16(40.4793082149475 / FREQUENCY_RATE), - float_to_fp16_16(40.504326328801 / FREQUENCY_RATE), - float_to_fp16_16(40.5293753865182 / FREQUENCY_RATE), - float_to_fp16_16(40.5544554455446 / FREQUENCY_RATE), - float_to_fp16_16(40.5795665634675 / FREQUENCY_RATE), - float_to_fp16_16(40.6047087980174 / FREQUENCY_RATE), - float_to_fp16_16(40.6298822070676 / FREQUENCY_RATE), - float_to_fp16_16(40.6550868486352 / FREQUENCY_RATE), - float_to_fp16_16(40.6803227808814 / FREQUENCY_RATE), - float_to_fp16_16(40.7055900621118 / FREQUENCY_RATE), - float_to_fp16_16(40.7308887507769 / FREQUENCY_RATE), - float_to_fp16_16(40.7562189054726 / FREQUENCY_RATE), - float_to_fp16_16(40.7815805849409 / FREQUENCY_RATE), - float_to_fp16_16(40.8069738480697 / FREQUENCY_RATE), - float_to_fp16_16(40.8323987538941 / FREQUENCY_RATE), - float_to_fp16_16(40.857855361596 / FREQUENCY_RATE), - float_to_fp16_16(40.8833437305053 / FREQUENCY_RATE), - float_to_fp16_16(40.9088639200999 / FREQUENCY_RATE), - float_to_fp16_16(40.9344159900062 / FREQUENCY_RATE), - float_to_fp16_16(40.96 / FREQUENCY_RATE), - float_to_fp16_16(40.9856160100063 / FREQUENCY_RATE), - float_to_fp16_16(41.0112640801001 / FREQUENCY_RATE), - float_to_fp16_16(41.0369442705072 / FREQUENCY_RATE), - float_to_fp16_16(41.062656641604 / FREQUENCY_RATE), - float_to_fp16_16(41.0884012539185 / FREQUENCY_RATE), - float_to_fp16_16(41.1141781681305 / FREQUENCY_RATE), - float_to_fp16_16(41.1399874450722 / FREQUENCY_RATE), - float_to_fp16_16(41.1658291457287 / FREQUENCY_RATE), - float_to_fp16_16(41.1917033312382 / FREQUENCY_RATE), - float_to_fp16_16(41.2176100628931 / FREQUENCY_RATE), - float_to_fp16_16(41.2435494021397 / FREQUENCY_RATE), - float_to_fp16_16(41.2695214105793 / FREQUENCY_RATE), - float_to_fp16_16(41.2955261499685 / FREQUENCY_RATE), - float_to_fp16_16(41.3215636822194 / FREQUENCY_RATE), - float_to_fp16_16(41.3476340694006 / FREQUENCY_RATE), - float_to_fp16_16(41.3737373737374 / FREQUENCY_RATE), - float_to_fp16_16(41.3998736576121 / FREQUENCY_RATE), - float_to_fp16_16(41.4260429835651 / FREQUENCY_RATE), - float_to_fp16_16(41.4522454142948 / FREQUENCY_RATE), - float_to_fp16_16(41.4784810126582 / FREQUENCY_RATE), - float_to_fp16_16(41.504749841672 / FREQUENCY_RATE), - float_to_fp16_16(41.531051964512 / FREQUENCY_RATE), - float_to_fp16_16(41.5573874445149 / FREQUENCY_RATE), - float_to_fp16_16(41.5837563451777 / FREQUENCY_RATE), - float_to_fp16_16(41.6101587301587 / FREQUENCY_RATE), - float_to_fp16_16(41.6365946632783 / FREQUENCY_RATE), - float_to_fp16_16(41.6630642085188 / FREQUENCY_RATE), - float_to_fp16_16(41.6895674300254 / FREQUENCY_RATE), - float_to_fp16_16(41.7161043921069 / FREQUENCY_RATE), - float_to_fp16_16(41.7426751592357 / FREQUENCY_RATE), - float_to_fp16_16(41.7692797960484 / FREQUENCY_RATE), - float_to_fp16_16(41.7959183673469 / FREQUENCY_RATE), - float_to_fp16_16(41.8225909380983 / FREQUENCY_RATE), - float_to_fp16_16(41.8492975734355 / FREQUENCY_RATE), - float_to_fp16_16(41.8760383386582 / FREQUENCY_RATE), - float_to_fp16_16(41.9028132992327 / FREQUENCY_RATE), - float_to_fp16_16(41.9296225207934 / FREQUENCY_RATE), - float_to_fp16_16(41.9564660691421 / FREQUENCY_RATE), - float_to_fp16_16(41.9833440102498 / FREQUENCY_RATE), - float_to_fp16_16(42.0102564102564 / FREQUENCY_RATE), - float_to_fp16_16(42.0372033354715 / FREQUENCY_RATE), - float_to_fp16_16(42.0641848523748 / FREQUENCY_RATE), - float_to_fp16_16(42.0912010276172 / FREQUENCY_RATE), - float_to_fp16_16(42.1182519280206 / FREQUENCY_RATE), - float_to_fp16_16(42.1453376205788 / FREQUENCY_RATE), - float_to_fp16_16(42.1724581724582 / FREQUENCY_RATE), - float_to_fp16_16(42.1996136509981 / FREQUENCY_RATE), - float_to_fp16_16(42.2268041237113 / FREQUENCY_RATE), - float_to_fp16_16(42.254029658285 / FREQUENCY_RATE), - float_to_fp16_16(42.2812903225807 / FREQUENCY_RATE), - float_to_fp16_16(42.3085861846352 / FREQUENCY_RATE), - float_to_fp16_16(42.3359173126615 / FREQUENCY_RATE), - float_to_fp16_16(42.3632837750485 / FREQUENCY_RATE), - float_to_fp16_16(42.3906856403622 / FREQUENCY_RATE), - float_to_fp16_16(42.4181229773463 / FREQUENCY_RATE), - float_to_fp16_16(42.4455958549223 / FREQUENCY_RATE), - float_to_fp16_16(42.4731043421905 / FREQUENCY_RATE), - float_to_fp16_16(42.5006485084306 / FREQUENCY_RATE), - float_to_fp16_16(42.5282284231019 / FREQUENCY_RATE), - float_to_fp16_16(42.5558441558442 / FREQUENCY_RATE), - float_to_fp16_16(42.5834957764782 / FREQUENCY_RATE), - float_to_fp16_16(42.6111833550065 / FREQUENCY_RATE), - float_to_fp16_16(42.6389069616135 / FREQUENCY_RATE), - float_to_fp16_16(42.6666666666667 / FREQUENCY_RATE), - float_to_fp16_16(42.6944625407166 / FREQUENCY_RATE), - float_to_fp16_16(42.722294654498 / FREQUENCY_RATE), - float_to_fp16_16(42.7501630789302 / FREQUENCY_RATE), - float_to_fp16_16(42.7780678851175 / FREQUENCY_RATE), - float_to_fp16_16(42.8060091443501 / FREQUENCY_RATE), - float_to_fp16_16(42.8339869281046 / FREQUENCY_RATE), - float_to_fp16_16(42.8620013080445 / FREQUENCY_RATE), - float_to_fp16_16(42.890052356021 / FREQUENCY_RATE), - float_to_fp16_16(42.9181401440733 / FREQUENCY_RATE), - float_to_fp16_16(42.9462647444299 / FREQUENCY_RATE), - float_to_fp16_16(42.9744262295082 / FREQUENCY_RATE), - float_to_fp16_16(43.002624671916 / FREQUENCY_RATE), - float_to_fp16_16(43.0308601444517 / FREQUENCY_RATE), - float_to_fp16_16(43.0591327201051 / FREQUENCY_RATE), - float_to_fp16_16(43.0874424720579 / FREQUENCY_RATE), - float_to_fp16_16(43.1157894736842 / FREQUENCY_RATE), - float_to_fp16_16(43.1441737985517 / FREQUENCY_RATE), - float_to_fp16_16(43.1725955204216 / FREQUENCY_RATE), - float_to_fp16_16(43.2010547132498 / FREQUENCY_RATE), - float_to_fp16_16(43.2295514511873 / FREQUENCY_RATE), - float_to_fp16_16(43.2580858085809 / FREQUENCY_RATE), - float_to_fp16_16(43.2866578599736 / FREQUENCY_RATE), - float_to_fp16_16(43.3152676801057 / FREQUENCY_RATE), - float_to_fp16_16(43.3439153439153 / FREQUENCY_RATE), - float_to_fp16_16(43.3726009265387 / FREQUENCY_RATE), - float_to_fp16_16(43.4013245033113 / FREQUENCY_RATE), - float_to_fp16_16(43.4300861497681 / FREQUENCY_RATE), - float_to_fp16_16(43.4588859416446 / FREQUENCY_RATE), - float_to_fp16_16(43.4877239548772 / FREQUENCY_RATE), - float_to_fp16_16(43.5166002656043 / FREQUENCY_RATE), - float_to_fp16_16(43.5455149501661 / FREQUENCY_RATE), - float_to_fp16_16(43.5744680851064 / FREQUENCY_RATE), - float_to_fp16_16(43.6034597471723 / FREQUENCY_RATE), - float_to_fp16_16(43.6324900133156 / FREQUENCY_RATE), - float_to_fp16_16(43.6615589606929 / FREQUENCY_RATE), - float_to_fp16_16(43.6906666666667 / FREQUENCY_RATE), - float_to_fp16_16(43.7198132088059 / FREQUENCY_RATE), - float_to_fp16_16(43.7489986648865 / FREQUENCY_RATE), - float_to_fp16_16(43.7782231128925 / FREQUENCY_RATE), - float_to_fp16_16(43.807486631016 / FREQUENCY_RATE), - float_to_fp16_16(43.8367892976589 / FREQUENCY_RATE), - float_to_fp16_16(43.8661311914324 / FREQUENCY_RATE), - float_to_fp16_16(43.8955123911587 / FREQUENCY_RATE), - float_to_fp16_16(43.9249329758713 / FREQUENCY_RATE), - float_to_fp16_16(43.9543930248156 / FREQUENCY_RATE), - float_to_fp16_16(43.9838926174497 / FREQUENCY_RATE), - float_to_fp16_16(44.0134318334453 / FREQUENCY_RATE), - float_to_fp16_16(44.0430107526882 / FREQUENCY_RATE), - float_to_fp16_16(44.0726294552791 / FREQUENCY_RATE), - float_to_fp16_16(44.1022880215343 / FREQUENCY_RATE), - float_to_fp16_16(44.1319865319865 / FREQUENCY_RATE), - float_to_fp16_16(44.1617250673855 / FREQUENCY_RATE), - float_to_fp16_16(44.1915037086986 / FREQUENCY_RATE), - float_to_fp16_16(44.221322537112 / FREQUENCY_RATE), - float_to_fp16_16(44.2511816340311 / FREQUENCY_RATE), - float_to_fp16_16(44.2810810810811 / FREQUENCY_RATE), - float_to_fp16_16(44.3110209601082 / FREQUENCY_RATE), - float_to_fp16_16(44.34100135318 / FREQUENCY_RATE), - float_to_fp16_16(44.3710223425863 / FREQUENCY_RATE), - float_to_fp16_16(44.4010840108401 / FREQUENCY_RATE), - float_to_fp16_16(44.431186440678 / FREQUENCY_RATE), - float_to_fp16_16(44.4613297150611 / FREQUENCY_RATE), - float_to_fp16_16(44.4915139171758 / FREQUENCY_RATE), - float_to_fp16_16(44.5217391304348 / FREQUENCY_RATE), - float_to_fp16_16(44.5520054384772 / FREQUENCY_RATE), - float_to_fp16_16(44.5823129251701 / FREQUENCY_RATE), - float_to_fp16_16(44.6126616746086 / FREQUENCY_RATE), - float_to_fp16_16(44.6430517711172 / FREQUENCY_RATE), - float_to_fp16_16(44.6734832992502 / FREQUENCY_RATE), - float_to_fp16_16(44.7039563437926 / FREQUENCY_RATE), - float_to_fp16_16(44.7344709897611 / FREQUENCY_RATE), - float_to_fp16_16(44.7650273224044 / FREQUENCY_RATE), - float_to_fp16_16(44.7956254272044 / FREQUENCY_RATE), - float_to_fp16_16(44.8262653898769 / FREQUENCY_RATE), - float_to_fp16_16(44.8569472963724 / FREQUENCY_RATE), - float_to_fp16_16(44.8876712328767 / FREQUENCY_RATE), - float_to_fp16_16(44.9184372858122 / FREQUENCY_RATE), - float_to_fp16_16(44.9492455418381 / FREQUENCY_RATE), - float_to_fp16_16(44.9800960878518 / FREQUENCY_RATE), - float_to_fp16_16(45.010989010989 / FREQUENCY_RATE), - float_to_fp16_16(45.0419243986254 / FREQUENCY_RATE), - float_to_fp16_16(45.0729023383769 / FREQUENCY_RATE), - float_to_fp16_16(45.1039229181005 / FREQUENCY_RATE), - float_to_fp16_16(45.1349862258953 / FREQUENCY_RATE), - float_to_fp16_16(45.1660923501034 / FREQUENCY_RATE), - float_to_fp16_16(45.1972413793103 / FREQUENCY_RATE), - float_to_fp16_16(45.2284334023465 / FREQUENCY_RATE), - float_to_fp16_16(45.2596685082873 / FREQUENCY_RATE), - float_to_fp16_16(45.2909467864547 / FREQUENCY_RATE), - float_to_fp16_16(45.3222683264177 / FREQUENCY_RATE), - float_to_fp16_16(45.3536332179931 / FREQUENCY_RATE), - float_to_fp16_16(45.3850415512465 / FREQUENCY_RATE), - float_to_fp16_16(45.4164934164934 / FREQUENCY_RATE), - float_to_fp16_16(45.4479889042996 / FREQUENCY_RATE), - float_to_fp16_16(45.4795281054823 / FREQUENCY_RATE), - float_to_fp16_16(45.5111111111111 / FREQUENCY_RATE), - float_to_fp16_16(45.5427380125087 / FREQUENCY_RATE), - float_to_fp16_16(45.5744089012517 / FREQUENCY_RATE), - float_to_fp16_16(45.6061238691719 / FREQUENCY_RATE), - float_to_fp16_16(45.6378830083566 / FREQUENCY_RATE), - float_to_fp16_16(45.6696864111498 / FREQUENCY_RATE), - float_to_fp16_16(45.7015341701534 / FREQUENCY_RATE), - float_to_fp16_16(45.7334263782275 / FREQUENCY_RATE), - float_to_fp16_16(45.7653631284916 / FREQUENCY_RATE), - float_to_fp16_16(45.7973445143256 / FREQUENCY_RATE), - float_to_fp16_16(45.8293706293706 / FREQUENCY_RATE), - float_to_fp16_16(45.8614415675297 / FREQUENCY_RATE), - float_to_fp16_16(45.8935574229692 / FREQUENCY_RATE), - float_to_fp16_16(45.9257182901191 / FREQUENCY_RATE), - float_to_fp16_16(45.9579242636746 / FREQUENCY_RATE), - float_to_fp16_16(45.9901754385965 / FREQUENCY_RATE), - float_to_fp16_16(46.0224719101124 / FREQUENCY_RATE), - float_to_fp16_16(46.0548137737175 / FREQUENCY_RATE), - float_to_fp16_16(46.0872011251758 / FREQUENCY_RATE), - float_to_fp16_16(46.1196340605208 / FREQUENCY_RATE), - float_to_fp16_16(46.1521126760563 / FREQUENCY_RATE), - float_to_fp16_16(46.184637068358 / FREQUENCY_RATE), - float_to_fp16_16(46.2172073342736 / FREQUENCY_RATE), - float_to_fp16_16(46.2498235709245 / FREQUENCY_RATE), - float_to_fp16_16(46.2824858757062 / FREQUENCY_RATE), - float_to_fp16_16(46.3151943462898 / FREQUENCY_RATE), - float_to_fp16_16(46.3479490806223 / FREQUENCY_RATE), - float_to_fp16_16(46.3807501769285 / FREQUENCY_RATE), - float_to_fp16_16(46.4135977337111 / FREQUENCY_RATE), - float_to_fp16_16(46.446491849752 / FREQUENCY_RATE), - float_to_fp16_16(46.4794326241135 / FREQUENCY_RATE), - float_to_fp16_16(46.5124201561391 / FREQUENCY_RATE), - float_to_fp16_16(46.5454545454545 / FREQUENCY_RATE), - float_to_fp16_16(46.5785358919687 / FREQUENCY_RATE), - float_to_fp16_16(46.6116642958748 / FREQUENCY_RATE), - float_to_fp16_16(46.6448398576513 / FREQUENCY_RATE), - float_to_fp16_16(46.6780626780627 / FREQUENCY_RATE), - float_to_fp16_16(46.7113328581611 / FREQUENCY_RATE), - float_to_fp16_16(46.7446504992867 / FREQUENCY_RATE), - float_to_fp16_16(46.7780157030692 / FREQUENCY_RATE), - float_to_fp16_16(46.8114285714286 / FREQUENCY_RATE), - float_to_fp16_16(46.8448892065761 / FREQUENCY_RATE), - float_to_fp16_16(46.8783977110157 / FREQUENCY_RATE), - float_to_fp16_16(46.9119541875447 / FREQUENCY_RATE), - float_to_fp16_16(46.945558739255 / FREQUENCY_RATE), - float_to_fp16_16(46.9792114695341 / FREQUENCY_RATE), - float_to_fp16_16(47.012912482066 / FREQUENCY_RATE), - float_to_fp16_16(47.0466618808327 / FREQUENCY_RATE), - float_to_fp16_16(47.0804597701149 / FREQUENCY_RATE), - float_to_fp16_16(47.1143062544932 / FREQUENCY_RATE), - float_to_fp16_16(47.1482014388489 / FREQUENCY_RATE), - float_to_fp16_16(47.1821454283657 / FREQUENCY_RATE), - float_to_fp16_16(47.2161383285303 / FREQUENCY_RATE), - float_to_fp16_16(47.2501802451334 / FREQUENCY_RATE), - float_to_fp16_16(47.2842712842713 / FREQUENCY_RATE), - float_to_fp16_16(47.3184115523466 / FREQUENCY_RATE), - float_to_fp16_16(47.3526011560694 / FREQUENCY_RATE), - float_to_fp16_16(47.3868402024584 / FREQUENCY_RATE), - float_to_fp16_16(47.4211287988423 / FREQUENCY_RATE), - float_to_fp16_16(47.4554670528602 / FREQUENCY_RATE), - float_to_fp16_16(47.4898550724638 / FREQUENCY_RATE), - float_to_fp16_16(47.5242929659173 / FREQUENCY_RATE), - float_to_fp16_16(47.5587808417997 / FREQUENCY_RATE), - float_to_fp16_16(47.5933188090051 / FREQUENCY_RATE), - float_to_fp16_16(47.6279069767442 / FREQUENCY_RATE), - float_to_fp16_16(47.6625454545455 / FREQUENCY_RATE), - float_to_fp16_16(47.6972343522562 / FREQUENCY_RATE), - float_to_fp16_16(47.7319737800437 / FREQUENCY_RATE), - float_to_fp16_16(47.7667638483965 / FREQUENCY_RATE), - float_to_fp16_16(47.8016046681255 / FREQUENCY_RATE), - float_to_fp16_16(47.836496350365 / FREQUENCY_RATE), - float_to_fp16_16(47.8714390065741 / FREQUENCY_RATE), - float_to_fp16_16(47.906432748538 / FREQUENCY_RATE), - float_to_fp16_16(47.9414776883687 / FREQUENCY_RATE), - float_to_fp16_16(47.9765739385066 / FREQUENCY_RATE), - float_to_fp16_16(48.0117216117216 / FREQUENCY_RATE), - float_to_fp16_16(48.0469208211144 / FREQUENCY_RATE), - float_to_fp16_16(48.0821716801174 / FREQUENCY_RATE), - float_to_fp16_16(48.1174743024963 / FREQUENCY_RATE), - float_to_fp16_16(48.1528288023512 / FREQUENCY_RATE), - float_to_fp16_16(48.1882352941176 / FREQUENCY_RATE), - float_to_fp16_16(48.2236938925681 / FREQUENCY_RATE), - float_to_fp16_16(48.259204712813 / FREQUENCY_RATE), - float_to_fp16_16(48.2947678703021 / FREQUENCY_RATE), - float_to_fp16_16(48.330383480826 / FREQUENCY_RATE), - float_to_fp16_16(48.3660516605166 / FREQUENCY_RATE), - float_to_fp16_16(48.4017725258493 / FREQUENCY_RATE), - float_to_fp16_16(48.4375461936438 / FREQUENCY_RATE), - float_to_fp16_16(48.4733727810651 / FREQUENCY_RATE), - float_to_fp16_16(48.5092524056255 / FREQUENCY_RATE), - float_to_fp16_16(48.5451851851852 / FREQUENCY_RATE), - float_to_fp16_16(48.581171237954 / FREQUENCY_RATE), - float_to_fp16_16(48.6172106824926 / FREQUENCY_RATE), - float_to_fp16_16(48.6533036377134 / FREQUENCY_RATE), - float_to_fp16_16(48.6894502228826 / FREQUENCY_RATE), - float_to_fp16_16(48.7256505576208 / FREQUENCY_RATE), - float_to_fp16_16(48.7619047619048 / FREQUENCY_RATE), - float_to_fp16_16(48.7982129560685 / FREQUENCY_RATE), - float_to_fp16_16(48.8345752608048 / FREQUENCY_RATE), - float_to_fp16_16(48.8709917971663 / FREQUENCY_RATE), - float_to_fp16_16(48.9074626865672 / FREQUENCY_RATE), - float_to_fp16_16(48.9439880507842 / FREQUENCY_RATE), - float_to_fp16_16(48.9805680119582 / FREQUENCY_RATE), - float_to_fp16_16(49.0172026925954 / FREQUENCY_RATE), - float_to_fp16_16(49.0538922155689 / FREQUENCY_RATE), - float_to_fp16_16(49.0906367041199 / FREQUENCY_RATE), - float_to_fp16_16(49.1274362818591 / FREQUENCY_RATE), - float_to_fp16_16(49.1642910727682 / FREQUENCY_RATE), - float_to_fp16_16(49.2012012012012 / FREQUENCY_RATE), - float_to_fp16_16(49.2381667918858 / FREQUENCY_RATE), - float_to_fp16_16(49.2751879699248 / FREQUENCY_RATE), - float_to_fp16_16(49.3122648607976 / FREQUENCY_RATE), - float_to_fp16_16(49.3493975903615 / FREQUENCY_RATE), - float_to_fp16_16(49.3865862848531 / FREQUENCY_RATE), - float_to_fp16_16(49.4238310708899 / FREQUENCY_RATE), - float_to_fp16_16(49.4611320754717 / FREQUENCY_RATE), - float_to_fp16_16(49.4984894259819 / FREQUENCY_RATE), - float_to_fp16_16(49.535903250189 / FREQUENCY_RATE), - float_to_fp16_16(49.5733736762481 / FREQUENCY_RATE), - float_to_fp16_16(49.6109008327025 / FREQUENCY_RATE), - float_to_fp16_16(49.6484848484849 / FREQUENCY_RATE), - float_to_fp16_16(49.6861258529189 / FREQUENCY_RATE), - float_to_fp16_16(49.7238239757208 / FREQUENCY_RATE), - float_to_fp16_16(49.7615793470008 / FREQUENCY_RATE), - float_to_fp16_16(49.7993920972644 / FREQUENCY_RATE), - float_to_fp16_16(49.8372623574145 / FREQUENCY_RATE), - float_to_fp16_16(49.8751902587519 / FREQUENCY_RATE), - float_to_fp16_16(49.9131759329779 / FREQUENCY_RATE), - float_to_fp16_16(49.9512195121951 / FREQUENCY_RATE), - float_to_fp16_16(49.9893211289092 / FREQUENCY_RATE), - float_to_fp16_16(50.0274809160305 / FREQUENCY_RATE), - float_to_fp16_16(50.0656990068755 / FREQUENCY_RATE), - float_to_fp16_16(50.1039755351682 / FREQUENCY_RATE), - float_to_fp16_16(50.1423106350421 / FREQUENCY_RATE), - float_to_fp16_16(50.1807044410413 / FREQUENCY_RATE), - float_to_fp16_16(50.2191570881226 / FREQUENCY_RATE), - float_to_fp16_16(50.2576687116564 / FREQUENCY_RATE), - float_to_fp16_16(50.296239447429 / FREQUENCY_RATE), - float_to_fp16_16(50.3348694316436 / FREQUENCY_RATE), - float_to_fp16_16(50.3735588009224 / FREQUENCY_RATE), - float_to_fp16_16(50.4123076923077 / FREQUENCY_RATE), - float_to_fp16_16(50.451116243264 / FREQUENCY_RATE), - float_to_fp16_16(50.4899845916795 / FREQUENCY_RATE), - float_to_fp16_16(50.5289128758674 / FREQUENCY_RATE), - float_to_fp16_16(50.5679012345679 / FREQUENCY_RATE), - float_to_fp16_16(50.6069498069498 / FREQUENCY_RATE), - float_to_fp16_16(50.6460587326121 / FREQUENCY_RATE), - float_to_fp16_16(50.6852281515855 / FREQUENCY_RATE), - float_to_fp16_16(50.7244582043344 / FREQUENCY_RATE), - float_to_fp16_16(50.7637490317583 / FREQUENCY_RATE), - float_to_fp16_16(50.8031007751938 / FREQUENCY_RATE), - float_to_fp16_16(50.8425135764158 / FREQUENCY_RATE), - float_to_fp16_16(50.8819875776397 / FREQUENCY_RATE), - float_to_fp16_16(50.9215229215229 / FREQUENCY_RATE), - float_to_fp16_16(50.9611197511664 / FREQUENCY_RATE), - float_to_fp16_16(51.0007782101167 / FREQUENCY_RATE), - float_to_fp16_16(51.0404984423676 / FREQUENCY_RATE), - float_to_fp16_16(51.0802805923617 / FREQUENCY_RATE), - float_to_fp16_16(51.1201248049922 / FREQUENCY_RATE), - float_to_fp16_16(51.160031225605 / FREQUENCY_RATE), - float_to_fp16_16(51.2 / FREQUENCY_RATE), - float_to_fp16_16(51.2400312744331 / FREQUENCY_RATE), - float_to_fp16_16(51.2801251956182 / FREQUENCY_RATE), - float_to_fp16_16(51.3202819107283 / FREQUENCY_RATE), - float_to_fp16_16(51.3605015673981 / FREQUENCY_RATE), - float_to_fp16_16(51.4007843137255 / FREQUENCY_RATE), - float_to_fp16_16(51.4411302982732 / FREQUENCY_RATE), - float_to_fp16_16(51.4815396700707 / FREQUENCY_RATE), - float_to_fp16_16(51.5220125786164 / FREQUENCY_RATE), - float_to_fp16_16(51.5625491738788 / FREQUENCY_RATE), - float_to_fp16_16(51.6031496062992 / FREQUENCY_RATE), - float_to_fp16_16(51.6438140267928 / FREQUENCY_RATE), - float_to_fp16_16(51.6845425867508 / FREQUENCY_RATE), - float_to_fp16_16(51.7253354380426 / FREQUENCY_RATE), - float_to_fp16_16(51.7661927330174 / FREQUENCY_RATE), - float_to_fp16_16(51.8071146245059 / FREQUENCY_RATE), - float_to_fp16_16(51.8481012658228 / FREQUENCY_RATE), - float_to_fp16_16(51.889152810768 / FREQUENCY_RATE), - float_to_fp16_16(51.9302694136292 / FREQUENCY_RATE), - float_to_fp16_16(51.9714512291832 / FREQUENCY_RATE), - float_to_fp16_16(52.0126984126984 / FREQUENCY_RATE), - float_to_fp16_16(52.0540111199365 / FREQUENCY_RATE), - float_to_fp16_16(52.0953895071542 / FREQUENCY_RATE), - float_to_fp16_16(52.1368337311058 / FREQUENCY_RATE), - float_to_fp16_16(52.1783439490446 / FREQUENCY_RATE), - float_to_fp16_16(52.2199203187251 / FREQUENCY_RATE), - float_to_fp16_16(52.2615629984051 / FREQUENCY_RATE), - float_to_fp16_16(52.3032721468476 / FREQUENCY_RATE), - float_to_fp16_16(52.3450479233227 / FREQUENCY_RATE), - float_to_fp16_16(52.3868904876099 / FREQUENCY_RATE), - float_to_fp16_16(52.4288 / FREQUENCY_RATE), - float_to_fp16_16(52.470776621297 / FREQUENCY_RATE), - float_to_fp16_16(52.5128205128205 / FREQUENCY_RATE), - float_to_fp16_16(52.5549318364074 / FREQUENCY_RATE), - float_to_fp16_16(52.5971107544141 / FREQUENCY_RATE), - float_to_fp16_16(52.6393574297189 / FREQUENCY_RATE), - float_to_fp16_16(52.6816720257235 / FREQUENCY_RATE), - float_to_fp16_16(52.7240547063556 / FREQUENCY_RATE), - float_to_fp16_16(52.7665056360709 / FREQUENCY_RATE), - float_to_fp16_16(52.809024979855 / FREQUENCY_RATE), - float_to_fp16_16(52.8516129032258 / FREQUENCY_RATE), - float_to_fp16_16(52.8942695722357 / FREQUENCY_RATE), - float_to_fp16_16(52.9369951534734 / FREQUENCY_RATE), - float_to_fp16_16(52.9797898140663 / FREQUENCY_RATE), - float_to_fp16_16(53.0226537216829 / FREQUENCY_RATE), - float_to_fp16_16(53.0655870445344 / FREQUENCY_RATE), - float_to_fp16_16(53.1085899513776 / FREQUENCY_RATE), - float_to_fp16_16(53.1516626115166 / FREQUENCY_RATE), - float_to_fp16_16(53.1948051948052 / FREQUENCY_RATE), - float_to_fp16_16(53.2380178716491 / FREQUENCY_RATE), - float_to_fp16_16(53.2813008130081 / FREQUENCY_RATE), - float_to_fp16_16(53.3246541903987 / FREQUENCY_RATE), - float_to_fp16_16(53.3680781758958 / FREQUENCY_RATE), - float_to_fp16_16(53.4115729421353 / FREQUENCY_RATE), - float_to_fp16_16(53.4551386623165 / FREQUENCY_RATE), - float_to_fp16_16(53.4987755102041 / FREQUENCY_RATE), - float_to_fp16_16(53.5424836601307 / FREQUENCY_RATE), - float_to_fp16_16(53.5862632869992 / FREQUENCY_RATE), - float_to_fp16_16(53.6301145662848 / FREQUENCY_RATE), - float_to_fp16_16(53.6740376740377 / FREQUENCY_RATE), - float_to_fp16_16(53.7180327868852 / FREQUENCY_RATE), - float_to_fp16_16(53.7621000820345 / FREQUENCY_RATE), - float_to_fp16_16(53.8062397372742 / FREQUENCY_RATE), - float_to_fp16_16(53.8504519309778 / FREQUENCY_RATE), - float_to_fp16_16(53.8947368421053 / FREQUENCY_RATE), - float_to_fp16_16(53.9390946502058 / FREQUENCY_RATE), - float_to_fp16_16(53.9835255354201 / FREQUENCY_RATE), - float_to_fp16_16(54.0280296784831 / FREQUENCY_RATE), - float_to_fp16_16(54.0726072607261 / FREQUENCY_RATE), - float_to_fp16_16(54.1172584640793 / FREQUENCY_RATE), - float_to_fp16_16(54.1619834710744 / FREQUENCY_RATE), - float_to_fp16_16(54.206782464847 / FREQUENCY_RATE), - float_to_fp16_16(54.2516556291391 / FREQUENCY_RATE), - float_to_fp16_16(54.2966031483016 / FREQUENCY_RATE), - float_to_fp16_16(54.3416252072969 / FREQUENCY_RATE), - float_to_fp16_16(54.3867219917012 / FREQUENCY_RATE), - float_to_fp16_16(54.4318936877076 / FREQUENCY_RATE), - float_to_fp16_16(54.477140482128 / FREQUENCY_RATE), - float_to_fp16_16(54.522462562396 / FREQUENCY_RATE), - float_to_fp16_16(54.5678601165695 / FREQUENCY_RATE), - float_to_fp16_16(54.6133333333333 / FREQUENCY_RATE), - float_to_fp16_16(54.6588824020017 / FREQUENCY_RATE), - float_to_fp16_16(54.7045075125209 / FREQUENCY_RATE), - float_to_fp16_16(54.750208855472 / FREQUENCY_RATE), - float_to_fp16_16(54.7959866220736 / FREQUENCY_RATE), - float_to_fp16_16(54.8418410041841 / FREQUENCY_RATE), - float_to_fp16_16(54.8877721943049 / FREQUENCY_RATE), - float_to_fp16_16(54.9337803855826 / FREQUENCY_RATE), - float_to_fp16_16(54.9798657718121 / FREQUENCY_RATE), - float_to_fp16_16(55.0260285474391 / FREQUENCY_RATE), - float_to_fp16_16(55.072268907563 / FREQUENCY_RATE), - float_to_fp16_16(55.1185870479394 / FREQUENCY_RATE), - float_to_fp16_16(55.1649831649832 / FREQUENCY_RATE), - float_to_fp16_16(55.2114574557709 / FREQUENCY_RATE), - float_to_fp16_16(55.2580101180438 / FREQUENCY_RATE), - float_to_fp16_16(55.304641350211 / FREQUENCY_RATE), - float_to_fp16_16(55.3513513513514 / FREQUENCY_RATE), - float_to_fp16_16(55.3981403212172 / FREQUENCY_RATE), - float_to_fp16_16(55.4450084602369 / FREQUENCY_RATE), - float_to_fp16_16(55.4919559695174 / FREQUENCY_RATE), - float_to_fp16_16(55.5389830508475 / FREQUENCY_RATE), - float_to_fp16_16(55.5860899067006 / FREQUENCY_RATE), - float_to_fp16_16(55.6332767402377 / FREQUENCY_RATE), - float_to_fp16_16(55.6805437553101 / FREQUENCY_RATE), - float_to_fp16_16(55.7278911564626 / FREQUENCY_RATE), - float_to_fp16_16(55.7753191489362 / FREQUENCY_RATE), - float_to_fp16_16(55.8228279386712 / FREQUENCY_RATE), - float_to_fp16_16(55.8704177323103 / FREQUENCY_RATE), - float_to_fp16_16(55.9180887372014 / FREQUENCY_RATE), - float_to_fp16_16(55.9658411614005 / FREQUENCY_RATE), - float_to_fp16_16(56.0136752136752 / FREQUENCY_RATE), - float_to_fp16_16(56.0615911035073 / FREQUENCY_RATE), - float_to_fp16_16(56.1095890410959 / FREQUENCY_RATE), - float_to_fp16_16(56.1576692373608 / FREQUENCY_RATE), - float_to_fp16_16(56.2058319039451 / FREQUENCY_RATE), - float_to_fp16_16(56.2540772532189 / FREQUENCY_RATE), - float_to_fp16_16(56.3024054982818 / FREQUENCY_RATE), - float_to_fp16_16(56.3508168529665 / FREQUENCY_RATE), - float_to_fp16_16(56.3993115318417 / FREQUENCY_RATE), - float_to_fp16_16(56.4478897502153 / FREQUENCY_RATE), - float_to_fp16_16(56.4965517241379 / FREQUENCY_RATE), - float_to_fp16_16(56.5452976704055 / FREQUENCY_RATE), - float_to_fp16_16(56.594127806563 / FREQUENCY_RATE), - float_to_fp16_16(56.6430423509075 / FREQUENCY_RATE), - float_to_fp16_16(56.6920415224914 / FREQUENCY_RATE), - float_to_fp16_16(56.7411255411255 / FREQUENCY_RATE), - float_to_fp16_16(56.790294627383 / FREQUENCY_RATE), - float_to_fp16_16(56.8395490026019 / FREQUENCY_RATE), - float_to_fp16_16(56.8888888888889 / FREQUENCY_RATE), - float_to_fp16_16(56.9383145091225 / FREQUENCY_RATE), - float_to_fp16_16(56.9878260869565 / FREQUENCY_RATE), - float_to_fp16_16(57.0374238468233 / FREQUENCY_RATE), - float_to_fp16_16(57.0871080139373 / FREQUENCY_RATE), - float_to_fp16_16(57.1368788142982 / FREQUENCY_RATE), - float_to_fp16_16(57.1867364746946 / FREQUENCY_RATE), - float_to_fp16_16(57.2366812227074 / FREQUENCY_RATE), - float_to_fp16_16(57.2867132867133 / FREQUENCY_RATE), - float_to_fp16_16(57.336832895888 / FREQUENCY_RATE), - float_to_fp16_16(57.3870402802102 / FREQUENCY_RATE), - float_to_fp16_16(57.4373356704645 / FREQUENCY_RATE), - float_to_fp16_16(57.4877192982456 / FREQUENCY_RATE), - float_to_fp16_16(57.5381913959614 / FREQUENCY_RATE), - float_to_fp16_16(57.5887521968366 / FREQUENCY_RATE), - float_to_fp16_16(57.6394019349165 / FREQUENCY_RATE), - float_to_fp16_16(57.6901408450704 / FREQUENCY_RATE), - float_to_fp16_16(57.7409691629956 / FREQUENCY_RATE), - float_to_fp16_16(57.7918871252205 / FREQUENCY_RATE), - float_to_fp16_16(57.8428949691086 / FREQUENCY_RATE), - float_to_fp16_16(57.8939929328622 / FREQUENCY_RATE), - float_to_fp16_16(57.9451812555261 / FREQUENCY_RATE), - float_to_fp16_16(57.9964601769912 / FREQUENCY_RATE), - float_to_fp16_16(58.0478299379982 / FREQUENCY_RATE), - float_to_fp16_16(58.0992907801418 / FREQUENCY_RATE), - float_to_fp16_16(58.150842945874 / FREQUENCY_RATE), - float_to_fp16_16(58.202486678508 / FREQUENCY_RATE), - float_to_fp16_16(58.2542222222222 / FREQUENCY_RATE), - float_to_fp16_16(58.3060498220641 / FREQUENCY_RATE), - float_to_fp16_16(58.3579697239537 / FREQUENCY_RATE), - float_to_fp16_16(58.4099821746881 / FREQUENCY_RATE), - float_to_fp16_16(58.4620874219447 / FREQUENCY_RATE), - float_to_fp16_16(58.5142857142857 / FREQUENCY_RATE), - float_to_fp16_16(58.5665773011618 / FREQUENCY_RATE), - float_to_fp16_16(58.6189624329159 / FREQUENCY_RATE), - float_to_fp16_16(58.6714413607878 / FREQUENCY_RATE), - float_to_fp16_16(58.7240143369176 / FREQUENCY_RATE), - float_to_fp16_16(58.7766816143498 / FREQUENCY_RATE), - float_to_fp16_16(58.8294434470377 / FREQUENCY_RATE), - float_to_fp16_16(58.8823000898473 / FREQUENCY_RATE), - float_to_fp16_16(58.9352517985612 / FREQUENCY_RATE), - float_to_fp16_16(58.988298829883 / FREQUENCY_RATE), - float_to_fp16_16(59.0414414414414 / FREQUENCY_RATE), - float_to_fp16_16(59.0946798917944 / FREQUENCY_RATE), - float_to_fp16_16(59.1480144404332 / FREQUENCY_RATE), - float_to_fp16_16(59.2014453477868 / FREQUENCY_RATE), - float_to_fp16_16(59.254972875226 / FREQUENCY_RATE), - float_to_fp16_16(59.3085972850679 / FREQUENCY_RATE), - float_to_fp16_16(59.3623188405797 / FREQUENCY_RATE), - float_to_fp16_16(59.4161378059837 / FREQUENCY_RATE), - float_to_fp16_16(59.470054446461 / FREQUENCY_RATE), - float_to_fp16_16(59.5240690281562 / FREQUENCY_RATE), - float_to_fp16_16(59.5781818181818 / FREQUENCY_RATE), - float_to_fp16_16(59.6323930846224 / FREQUENCY_RATE), - float_to_fp16_16(59.6867030965392 / FREQUENCY_RATE), - float_to_fp16_16(59.7411121239745 / FREQUENCY_RATE), - float_to_fp16_16(59.7956204379562 / FREQUENCY_RATE), - float_to_fp16_16(59.8502283105023 / FREQUENCY_RATE), - float_to_fp16_16(59.9049360146252 / FREQUENCY_RATE), - float_to_fp16_16(59.9597438243367 / FREQUENCY_RATE), - float_to_fp16_16(60.014652014652 / FREQUENCY_RATE), - float_to_fp16_16(60.0696608615949 / FREQUENCY_RATE), - float_to_fp16_16(60.1247706422018 / FREQUENCY_RATE), - float_to_fp16_16(60.1799816345271 / FREQUENCY_RATE), - float_to_fp16_16(60.2352941176471 / FREQUENCY_RATE), - float_to_fp16_16(60.2907083716651 / FREQUENCY_RATE), - float_to_fp16_16(60.3462246777164 / FREQUENCY_RATE), - float_to_fp16_16(60.4018433179724 / FREQUENCY_RATE), - float_to_fp16_16(60.4575645756458 / FREQUENCY_RATE), - float_to_fp16_16(60.5133887349954 / FREQUENCY_RATE), - float_to_fp16_16(60.5693160813309 / FREQUENCY_RATE), - float_to_fp16_16(60.6253469010176 / FREQUENCY_RATE), - float_to_fp16_16(60.6814814814815 / FREQUENCY_RATE), - float_to_fp16_16(60.7377201112141 / FREQUENCY_RATE), - float_to_fp16_16(60.7940630797774 / FREQUENCY_RATE), - float_to_fp16_16(60.8505106778087 / FREQUENCY_RATE), - float_to_fp16_16(60.907063197026 / FREQUENCY_RATE), - float_to_fp16_16(60.9637209302326 / FREQUENCY_RATE), - float_to_fp16_16(61.0204841713222 / FREQUENCY_RATE), - float_to_fp16_16(61.0773532152843 / FREQUENCY_RATE), - float_to_fp16_16(61.134328358209 / FREQUENCY_RATE), - float_to_fp16_16(61.1914098972923 / FREQUENCY_RATE), - float_to_fp16_16(61.2485981308411 / FREQUENCY_RATE), - float_to_fp16_16(61.3058933582788 / FREQUENCY_RATE), - float_to_fp16_16(61.3632958801498 / FREQUENCY_RATE), - float_to_fp16_16(61.4208059981256 / FREQUENCY_RATE), - float_to_fp16_16(61.4784240150094 / FREQUENCY_RATE), - float_to_fp16_16(61.5361502347418 / FREQUENCY_RATE), - float_to_fp16_16(61.593984962406 / FREQUENCY_RATE), - float_to_fp16_16(61.6519285042333 / FREQUENCY_RATE), - float_to_fp16_16(61.7099811676083 / FREQUENCY_RATE), - float_to_fp16_16(61.7681432610745 / FREQUENCY_RATE), - float_to_fp16_16(61.8264150943396 / FREQUENCY_RATE), - float_to_fp16_16(61.8847969782814 / FREQUENCY_RATE), - float_to_fp16_16(61.9432892249527 / FREQUENCY_RATE), - float_to_fp16_16(62.0018921475875 / FREQUENCY_RATE), - float_to_fp16_16(62.0606060606061 / FREQUENCY_RATE), - float_to_fp16_16(62.1194312796209 / FREQUENCY_RATE), - float_to_fp16_16(62.1783681214421 / FREQUENCY_RATE), - float_to_fp16_16(62.2374169040836 / FREQUENCY_RATE), - float_to_fp16_16(62.2965779467681 / FREQUENCY_RATE), - float_to_fp16_16(62.3558515699334 / FREQUENCY_RATE), - float_to_fp16_16(62.4152380952381 / FREQUENCY_RATE), - float_to_fp16_16(62.4747378455672 / FREQUENCY_RATE), - float_to_fp16_16(62.5343511450382 / FREQUENCY_RATE), - float_to_fp16_16(62.5940783190067 / FREQUENCY_RATE), - float_to_fp16_16(62.6539196940727 / FREQUENCY_RATE), - float_to_fp16_16(62.7138755980861 / FREQUENCY_RATE), - float_to_fp16_16(62.7739463601533 / FREQUENCY_RATE), - float_to_fp16_16(62.8341323106424 / FREQUENCY_RATE), - float_to_fp16_16(62.89443378119 / FREQUENCY_RATE), - float_to_fp16_16(62.954851104707 / FREQUENCY_RATE), - float_to_fp16_16(63.0153846153846 / FREQUENCY_RATE), - float_to_fp16_16(63.0760346487007 / FREQUENCY_RATE), - float_to_fp16_16(63.1368015414258 / FREQUENCY_RATE), - float_to_fp16_16(63.1976856316297 / FREQUENCY_RATE), - float_to_fp16_16(63.2586872586873 / FREQUENCY_RATE), - float_to_fp16_16(63.319806763285 / FREQUENCY_RATE), - float_to_fp16_16(63.3810444874275 / FREQUENCY_RATE), - float_to_fp16_16(63.4424007744434 / FREQUENCY_RATE), - float_to_fp16_16(63.5038759689923 / FREQUENCY_RATE), - float_to_fp16_16(63.5654704170708 / FREQUENCY_RATE), - float_to_fp16_16(63.6271844660194 / FREQUENCY_RATE), - float_to_fp16_16(63.6890184645287 / FREQUENCY_RATE), - float_to_fp16_16(63.7509727626459 / FREQUENCY_RATE), - float_to_fp16_16(63.8130477117819 / FREQUENCY_RATE), - float_to_fp16_16(63.8752436647174 / FREQUENCY_RATE), - float_to_fp16_16(63.9375609756098 / FREQUENCY_RATE), - float_to_fp16_16(64 / FREQUENCY_RATE), - float_to_fp16_16(64.0625610948192 / FREQUENCY_RATE), - float_to_fp16_16(64.1252446183953 / FREQUENCY_RATE), - float_to_fp16_16(64.1880509304603 / FREQUENCY_RATE), - float_to_fp16_16(64.2509803921569 / FREQUENCY_RATE), - float_to_fp16_16(64.3140333660451 / FREQUENCY_RATE), - float_to_fp16_16(64.37721021611 / FREQUENCY_RATE), - float_to_fp16_16(64.440511307768 / FREQUENCY_RATE), - float_to_fp16_16(64.503937007874 / FREQUENCY_RATE), - float_to_fp16_16(64.5674876847291 / FREQUENCY_RATE), - float_to_fp16_16(64.6311637080868 / FREQUENCY_RATE), - float_to_fp16_16(64.6949654491609 / FREQUENCY_RATE), - float_to_fp16_16(64.7588932806324 / FREQUENCY_RATE), - float_to_fp16_16(64.8229475766568 / FREQUENCY_RATE), - float_to_fp16_16(64.8871287128713 / FREQUENCY_RATE), - float_to_fp16_16(64.9514370664024 / FREQUENCY_RATE), - float_to_fp16_16(65.015873015873 / FREQUENCY_RATE), - float_to_fp16_16(65.0804369414101 / FREQUENCY_RATE), - float_to_fp16_16(65.1451292246521 / FREQUENCY_RATE), - float_to_fp16_16(65.2099502487562 / FREQUENCY_RATE), - float_to_fp16_16(65.2749003984064 / FREQUENCY_RATE), - float_to_fp16_16(65.3399800598205 / FREQUENCY_RATE), - float_to_fp16_16(65.4051896207585 / FREQUENCY_RATE), - float_to_fp16_16(65.4705294705295 / FREQUENCY_RATE), - float_to_fp16_16(65.536 / FREQUENCY_RATE), - float_to_fp16_16(65.6016016016016 / FREQUENCY_RATE), - float_to_fp16_16(65.6673346693387 / FREQUENCY_RATE), - float_to_fp16_16(65.7331995987964 / FREQUENCY_RATE), - float_to_fp16_16(65.7991967871486 / FREQUENCY_RATE), - float_to_fp16_16(65.8653266331658 / FREQUENCY_RATE), - float_to_fp16_16(65.9315895372234 / FREQUENCY_RATE), - float_to_fp16_16(65.9979859013092 / FREQUENCY_RATE), - float_to_fp16_16(66.0645161290323 / FREQUENCY_RATE), - float_to_fp16_16(66.1311806256307 / FREQUENCY_RATE), - float_to_fp16_16(66.1979797979798 / FREQUENCY_RATE), - float_to_fp16_16(66.2649140546006 / FREQUENCY_RATE), - float_to_fp16_16(66.331983805668 / FREQUENCY_RATE), - float_to_fp16_16(66.3991894630193 / FREQUENCY_RATE), - float_to_fp16_16(66.4665314401623 / FREQUENCY_RATE), - float_to_fp16_16(66.5340101522843 / FREQUENCY_RATE), - float_to_fp16_16(66.6016260162602 / FREQUENCY_RATE), - float_to_fp16_16(66.6693794506612 / FREQUENCY_RATE), - float_to_fp16_16(66.7372708757637 / FREQUENCY_RATE), - float_to_fp16_16(66.8053007135576 / FREQUENCY_RATE), - float_to_fp16_16(66.8734693877551 / FREQUENCY_RATE), - float_to_fp16_16(66.9417773237998 / FREQUENCY_RATE), - float_to_fp16_16(67.0102249488753 / FREQUENCY_RATE), - float_to_fp16_16(67.078812691914 / FREQUENCY_RATE), - float_to_fp16_16(67.1475409836066 / FREQUENCY_RATE), - float_to_fp16_16(67.2164102564103 / FREQUENCY_RATE), - float_to_fp16_16(67.2854209445585 / FREQUENCY_RATE), - float_to_fp16_16(67.3545734840699 / FREQUENCY_RATE), - float_to_fp16_16(67.4238683127572 / FREQUENCY_RATE), - float_to_fp16_16(67.4933058702369 / FREQUENCY_RATE), - float_to_fp16_16(67.5628865979382 / FREQUENCY_RATE), - float_to_fp16_16(67.6326109391125 / FREQUENCY_RATE), - float_to_fp16_16(67.702479338843 / FREQUENCY_RATE), - float_to_fp16_16(67.7724922440538 / FREQUENCY_RATE), - float_to_fp16_16(67.8426501035197 / FREQUENCY_RATE), - float_to_fp16_16(67.9129533678757 / FREQUENCY_RATE), - float_to_fp16_16(67.9834024896266 / FREQUENCY_RATE), - float_to_fp16_16(68.0539979231568 / FREQUENCY_RATE), - float_to_fp16_16(68.1247401247401 / FREQUENCY_RATE), - float_to_fp16_16(68.1956295525494 / FREQUENCY_RATE), - float_to_fp16_16(68.2666666666667 / FREQUENCY_RATE), - float_to_fp16_16(68.3378519290928 / FREQUENCY_RATE), - float_to_fp16_16(68.4091858037578 / FREQUENCY_RATE), - float_to_fp16_16(68.4806687565308 / FREQUENCY_RATE), - float_to_fp16_16(68.5523012552301 / FREQUENCY_RATE), - float_to_fp16_16(68.6240837696335 / FREQUENCY_RATE), - float_to_fp16_16(68.6960167714885 / FREQUENCY_RATE), - float_to_fp16_16(68.7681007345226 / FREQUENCY_RATE), - float_to_fp16_16(68.8403361344538 / FREQUENCY_RATE), - float_to_fp16_16(68.9127234490011 / FREQUENCY_RATE), - float_to_fp16_16(68.9852631578947 / FREQUENCY_RATE), - float_to_fp16_16(69.0579557428872 / FREQUENCY_RATE), - float_to_fp16_16(69.1308016877637 / FREQUENCY_RATE), - float_to_fp16_16(69.2038014783527 / FREQUENCY_RATE), - float_to_fp16_16(69.276955602537 / FREQUENCY_RATE), - float_to_fp16_16(69.3502645502646 / FREQUENCY_RATE), - float_to_fp16_16(69.4237288135593 / FREQUENCY_RATE), - float_to_fp16_16(69.4973488865324 / FREQUENCY_RATE), - float_to_fp16_16(69.5711252653928 / FREQUENCY_RATE), - float_to_fp16_16(69.6450584484591 / FREQUENCY_RATE), - float_to_fp16_16(69.7191489361702 / FREQUENCY_RATE), - float_to_fp16_16(69.7933972310969 / FREQUENCY_RATE), - float_to_fp16_16(69.8678038379531 / FREQUENCY_RATE), - float_to_fp16_16(69.9423692636073 / FREQUENCY_RATE), - float_to_fp16_16(70.017094017094 / FREQUENCY_RATE), - float_to_fp16_16(70.0919786096257 / FREQUENCY_RATE), - float_to_fp16_16(70.1670235546039 / FREQUENCY_RATE), - float_to_fp16_16(70.2422293676313 / FREQUENCY_RATE), - float_to_fp16_16(70.3175965665236 / FREQUENCY_RATE), - float_to_fp16_16(70.3931256713212 / FREQUENCY_RATE), - float_to_fp16_16(70.4688172043011 / FREQUENCY_RATE), - float_to_fp16_16(70.5446716899892 / FREQUENCY_RATE), - float_to_fp16_16(70.6206896551724 / FREQUENCY_RATE), - float_to_fp16_16(70.6968716289105 / FREQUENCY_RATE), - float_to_fp16_16(70.7732181425486 / FREQUENCY_RATE), - float_to_fp16_16(70.8497297297297 / FREQUENCY_RATE), - float_to_fp16_16(70.9264069264069 / FREQUENCY_RATE), - float_to_fp16_16(71.0032502708559 / FREQUENCY_RATE), - float_to_fp16_16(71.0802603036876 / FREQUENCY_RATE), - float_to_fp16_16(71.157437567861 / FREQUENCY_RATE), - float_to_fp16_16(71.2347826086957 / FREQUENCY_RATE), - float_to_fp16_16(71.3122959738847 / FREQUENCY_RATE), - float_to_fp16_16(71.3899782135076 / FREQUENCY_RATE), - float_to_fp16_16(71.4678298800436 / FREQUENCY_RATE), - float_to_fp16_16(71.5458515283843 / FREQUENCY_RATE), - float_to_fp16_16(71.624043715847 / FREQUENCY_RATE), - float_to_fp16_16(71.7024070021882 / FREQUENCY_RATE), - float_to_fp16_16(71.7809419496166 / FREQUENCY_RATE), - float_to_fp16_16(71.859649122807 / FREQUENCY_RATE), - float_to_fp16_16(71.9385290889133 / FREQUENCY_RATE), - float_to_fp16_16(72.0175824175824 / FREQUENCY_RATE), - float_to_fp16_16(72.0968096809681 / FREQUENCY_RATE), - float_to_fp16_16(72.1762114537445 / FREQUENCY_RATE), - float_to_fp16_16(72.2557883131202 / FREQUENCY_RATE), - float_to_fp16_16(72.3355408388521 / FREQUENCY_RATE), - float_to_fp16_16(72.4154696132597 / FREQUENCY_RATE), - float_to_fp16_16(72.4955752212389 / FREQUENCY_RATE), - float_to_fp16_16(72.5758582502769 / FREQUENCY_RATE), - float_to_fp16_16(72.6563192904656 / FREQUENCY_RATE), - float_to_fp16_16(72.7369589345172 / FREQUENCY_RATE), - float_to_fp16_16(72.8177777777778 / FREQUENCY_RATE), - float_to_fp16_16(72.8987764182425 / FREQUENCY_RATE), - float_to_fp16_16(72.9799554565702 / FREQUENCY_RATE), - float_to_fp16_16(73.0613154960981 / FREQUENCY_RATE), - float_to_fp16_16(73.1428571428571 / FREQUENCY_RATE), - float_to_fp16_16(73.2245810055866 / FREQUENCY_RATE), - float_to_fp16_16(73.3064876957494 / FREQUENCY_RATE), - float_to_fp16_16(73.3885778275476 / FREQUENCY_RATE), - float_to_fp16_16(73.4708520179372 / FREQUENCY_RATE), - float_to_fp16_16(73.5533108866442 / FREQUENCY_RATE), - float_to_fp16_16(73.6359550561798 / FREQUENCY_RATE), - float_to_fp16_16(73.718785151856 / FREQUENCY_RATE), - float_to_fp16_16(73.8018018018018 / FREQUENCY_RATE), - float_to_fp16_16(73.8850056369786 / FREQUENCY_RATE), - float_to_fp16_16(73.9683972911964 / FREQUENCY_RATE), - float_to_fp16_16(74.0519774011299 / FREQUENCY_RATE), - float_to_fp16_16(74.1357466063348 / FREQUENCY_RATE), - float_to_fp16_16(74.2197055492639 / FREQUENCY_RATE), - float_to_fp16_16(74.3038548752835 / FREQUENCY_RATE), - float_to_fp16_16(74.3881952326901 / FREQUENCY_RATE), - float_to_fp16_16(74.4727272727273 / FREQUENCY_RATE), - float_to_fp16_16(74.5574516496018 / FREQUENCY_RATE), - float_to_fp16_16(74.6423690205011 / FREQUENCY_RATE), - float_to_fp16_16(74.72748004561 / FREQUENCY_RATE), - float_to_fp16_16(74.8127853881279 / FREQUENCY_RATE), - float_to_fp16_16(74.8982857142857 / FREQUENCY_RATE), - float_to_fp16_16(74.9839816933639 / FREQUENCY_RATE), - float_to_fp16_16(75.0698739977091 / FREQUENCY_RATE), - float_to_fp16_16(75.1559633027523 / FREQUENCY_RATE), - float_to_fp16_16(75.2422502870264 / FREQUENCY_RATE), - float_to_fp16_16(75.3287356321839 / FREQUENCY_RATE), - float_to_fp16_16(75.415420023015 / FREQUENCY_RATE), - float_to_fp16_16(75.5023041474654 / FREQUENCY_RATE), - float_to_fp16_16(75.5893886966551 / FREQUENCY_RATE), - float_to_fp16_16(75.6766743648961 / FREQUENCY_RATE), - float_to_fp16_16(75.764161849711 / FREQUENCY_RATE), - float_to_fp16_16(75.8518518518518 / FREQUENCY_RATE), - float_to_fp16_16(75.9397450753187 / FREQUENCY_RATE), - float_to_fp16_16(76.0278422273782 / FREQUENCY_RATE), - float_to_fp16_16(76.116144018583 / FREQUENCY_RATE), - float_to_fp16_16(76.2046511627907 / FREQUENCY_RATE), - float_to_fp16_16(76.2933643771828 / FREQUENCY_RATE), - float_to_fp16_16(76.3822843822844 / FREQUENCY_RATE), - float_to_fp16_16(76.4714119019837 / FREQUENCY_RATE), - float_to_fp16_16(76.5607476635514 / FREQUENCY_RATE), - float_to_fp16_16(76.6502923976608 / FREQUENCY_RATE), - float_to_fp16_16(76.7400468384075 / FREQUENCY_RATE), - float_to_fp16_16(76.8300117233294 / FREQUENCY_RATE), - float_to_fp16_16(76.9201877934272 / FREQUENCY_RATE), - float_to_fp16_16(77.0105757931845 / FREQUENCY_RATE), - float_to_fp16_16(77.1011764705882 / FREQUENCY_RATE), - float_to_fp16_16(77.1919905771496 / FREQUENCY_RATE), - float_to_fp16_16(77.2830188679245 / FREQUENCY_RATE), - float_to_fp16_16(77.3742621015348 / FREQUENCY_RATE), - float_to_fp16_16(77.4657210401891 / FREQUENCY_RATE), - float_to_fp16_16(77.5573964497041 / FREQUENCY_RATE), - float_to_fp16_16(77.6492890995261 / FREQUENCY_RATE), - float_to_fp16_16(77.7413997627521 / FREQUENCY_RATE), - float_to_fp16_16(77.833729216152 / FREQUENCY_RATE), - float_to_fp16_16(77.9262782401902 / FREQUENCY_RATE), - float_to_fp16_16(78.0190476190476 / FREQUENCY_RATE), - float_to_fp16_16(78.1120381406436 / FREQUENCY_RATE), - float_to_fp16_16(78.2052505966587 / FREQUENCY_RATE), - float_to_fp16_16(78.2986857825568 / FREQUENCY_RATE), - float_to_fp16_16(78.3923444976077 / FREQUENCY_RATE), - float_to_fp16_16(78.4862275449102 / FREQUENCY_RATE), - float_to_fp16_16(78.5803357314149 / FREQUENCY_RATE), - float_to_fp16_16(78.6746698679472 / FREQUENCY_RATE), - float_to_fp16_16(78.7692307692308 / FREQUENCY_RATE), - float_to_fp16_16(78.864019253911 / FREQUENCY_RATE), - float_to_fp16_16(78.9590361445783 / FREQUENCY_RATE), - float_to_fp16_16(79.0542822677925 / FREQUENCY_RATE), - float_to_fp16_16(79.1497584541063 / FREQUENCY_RATE), - float_to_fp16_16(79.2454655380895 / FREQUENCY_RATE), - float_to_fp16_16(79.3414043583535 / FREQUENCY_RATE), - float_to_fp16_16(79.4375757575758 / FREQUENCY_RATE), - float_to_fp16_16(79.5339805825243 / FREQUENCY_RATE), - float_to_fp16_16(79.6306196840826 / FREQUENCY_RATE), - float_to_fp16_16(79.7274939172749 / FREQUENCY_RATE), - float_to_fp16_16(79.8246041412911 / FREQUENCY_RATE), - float_to_fp16_16(79.9219512195122 / FREQUENCY_RATE), - float_to_fp16_16(80.019536019536 / FREQUENCY_RATE), - float_to_fp16_16(80.1173594132029 / FREQUENCY_RATE), - float_to_fp16_16(80.2154222766218 / FREQUENCY_RATE), - float_to_fp16_16(80.3137254901961 / FREQUENCY_RATE), - float_to_fp16_16(80.4122699386503 / FREQUENCY_RATE), - float_to_fp16_16(80.5110565110565 / FREQUENCY_RATE), - float_to_fp16_16(80.610086100861 / FREQUENCY_RATE), - float_to_fp16_16(80.7093596059113 / FREQUENCY_RATE), - float_to_fp16_16(80.8088779284834 / FREQUENCY_RATE), - float_to_fp16_16(80.9086419753086 / FREQUENCY_RATE), - float_to_fp16_16(81.008652657602 / FREQUENCY_RATE), - float_to_fp16_16(81.1089108910891 / FREQUENCY_RATE), - float_to_fp16_16(81.2094175960347 / FREQUENCY_RATE), - float_to_fp16_16(81.3101736972705 / FREQUENCY_RATE), - float_to_fp16_16(81.4111801242236 / FREQUENCY_RATE), - float_to_fp16_16(81.5124378109453 / FREQUENCY_RATE), - float_to_fp16_16(81.6139476961395 / FREQUENCY_RATE), - float_to_fp16_16(81.715710723192 / FREQUENCY_RATE), - float_to_fp16_16(81.8177278401998 / FREQUENCY_RATE), - float_to_fp16_16(81.92 / FREQUENCY_RATE), - float_to_fp16_16(82.0225281602002 / FREQUENCY_RATE), - float_to_fp16_16(82.125313283208 / FREQUENCY_RATE), - float_to_fp16_16(82.228356336261 / FREQUENCY_RATE), - float_to_fp16_16(82.3316582914573 / FREQUENCY_RATE), - float_to_fp16_16(82.4352201257862 / FREQUENCY_RATE), - float_to_fp16_16(82.5390428211587 / FREQUENCY_RATE), - float_to_fp16_16(82.6431273644388 / FREQUENCY_RATE), - float_to_fp16_16(82.7474747474748 / FREQUENCY_RATE), - float_to_fp16_16(82.8520859671302 / FREQUENCY_RATE), - float_to_fp16_16(82.9569620253165 / FREQUENCY_RATE), - float_to_fp16_16(83.0621039290241 / FREQUENCY_RATE), - float_to_fp16_16(83.1675126903553 / FREQUENCY_RATE), - float_to_fp16_16(83.2731893265565 / FREQUENCY_RATE), - float_to_fp16_16(83.3791348600509 / FREQUENCY_RATE), - float_to_fp16_16(83.4853503184713 / FREQUENCY_RATE), - float_to_fp16_16(83.5918367346939 / FREQUENCY_RATE), - float_to_fp16_16(83.698595146871 / FREQUENCY_RATE), - float_to_fp16_16(83.8056265984655 / FREQUENCY_RATE), - float_to_fp16_16(83.9129321382842 / FREQUENCY_RATE), - float_to_fp16_16(84.0205128205128 / FREQUENCY_RATE), - float_to_fp16_16(84.1283697047497 / FREQUENCY_RATE), - float_to_fp16_16(84.2365038560411 / FREQUENCY_RATE), - float_to_fp16_16(84.3449163449163 / FREQUENCY_RATE), - float_to_fp16_16(84.4536082474227 / FREQUENCY_RATE), - float_to_fp16_16(84.5625806451613 / FREQUENCY_RATE), - float_to_fp16_16(84.671834625323 / FREQUENCY_RATE), - float_to_fp16_16(84.7813712807245 / FREQUENCY_RATE), - float_to_fp16_16(84.8911917098446 / FREQUENCY_RATE), - float_to_fp16_16(85.0012970168612 / FREQUENCY_RATE), - float_to_fp16_16(85.1116883116883 / FREQUENCY_RATE), - float_to_fp16_16(85.222366710013 / FREQUENCY_RATE), - float_to_fp16_16(85.3333333333333 / FREQUENCY_RATE), - float_to_fp16_16(85.4445893089961 / FREQUENCY_RATE), - float_to_fp16_16(85.556135770235 / FREQUENCY_RATE), - float_to_fp16_16(85.6679738562091 / FREQUENCY_RATE), - float_to_fp16_16(85.7801047120419 / FREQUENCY_RATE), - float_to_fp16_16(85.8925294888598 / FREQUENCY_RATE), - float_to_fp16_16(86.005249343832 / FREQUENCY_RATE), - float_to_fp16_16(86.1182654402102 / FREQUENCY_RATE), - float_to_fp16_16(86.2315789473684 / FREQUENCY_RATE), - float_to_fp16_16(86.3451910408432 / FREQUENCY_RATE), - float_to_fp16_16(86.4591029023747 / FREQUENCY_RATE), - float_to_fp16_16(86.5733157199472 / FREQUENCY_RATE), - float_to_fp16_16(86.6878306878307 / FREQUENCY_RATE), - float_to_fp16_16(86.8026490066225 / FREQUENCY_RATE), - float_to_fp16_16(86.9177718832891 / FREQUENCY_RATE), - float_to_fp16_16(87.0332005312085 / FREQUENCY_RATE), - float_to_fp16_16(87.1489361702128 / FREQUENCY_RATE), - float_to_fp16_16(87.2649800266312 / FREQUENCY_RATE), - float_to_fp16_16(87.3813333333333 / FREQUENCY_RATE), - float_to_fp16_16(87.497997329773 / FREQUENCY_RATE), - float_to_fp16_16(87.6149732620321 / FREQUENCY_RATE), - float_to_fp16_16(87.7322623828648 / FREQUENCY_RATE), - float_to_fp16_16(87.8498659517426 / FREQUENCY_RATE), - float_to_fp16_16(87.9677852348993 / FREQUENCY_RATE), - float_to_fp16_16(88.0860215053763 / FREQUENCY_RATE), - float_to_fp16_16(88.2045760430686 / FREQUENCY_RATE), - float_to_fp16_16(88.3234501347709 / FREQUENCY_RATE), - float_to_fp16_16(88.442645074224 / FREQUENCY_RATE), - float_to_fp16_16(88.5621621621622 / FREQUENCY_RATE), - float_to_fp16_16(88.68200270636 / FREQUENCY_RATE), - float_to_fp16_16(88.8021680216802 / FREQUENCY_RATE), - float_to_fp16_16(88.9226594301221 / FREQUENCY_RATE), - float_to_fp16_16(89.0434782608696 / FREQUENCY_RATE), - float_to_fp16_16(89.1646258503401 / FREQUENCY_RATE), - float_to_fp16_16(89.2861035422343 / FREQUENCY_RATE), - float_to_fp16_16(89.4079126875853 / FREQUENCY_RATE), - float_to_fp16_16(89.5300546448087 / FREQUENCY_RATE), - float_to_fp16_16(89.6525307797538 / FREQUENCY_RATE), - float_to_fp16_16(89.7753424657534 / FREQUENCY_RATE), - float_to_fp16_16(89.8984910836763 / FREQUENCY_RATE), - float_to_fp16_16(90.021978021978 / FREQUENCY_RATE), - float_to_fp16_16(90.1458046767538 / FREQUENCY_RATE), - float_to_fp16_16(90.2699724517906 / FREQUENCY_RATE), - float_to_fp16_16(90.3944827586207 / FREQUENCY_RATE), - float_to_fp16_16(90.5193370165746 / FREQUENCY_RATE), - float_to_fp16_16(90.6445366528354 / FREQUENCY_RATE), - float_to_fp16_16(90.7700831024931 / FREQUENCY_RATE), - float_to_fp16_16(90.8959778085992 / FREQUENCY_RATE), - float_to_fp16_16(91.0222222222222 / FREQUENCY_RATE), - float_to_fp16_16(91.1488178025035 / FREQUENCY_RATE), - float_to_fp16_16(91.2757660167131 / FREQUENCY_RATE), - float_to_fp16_16(91.4030683403068 / FREQUENCY_RATE), - float_to_fp16_16(91.5307262569833 / FREQUENCY_RATE), - float_to_fp16_16(91.6587412587413 / FREQUENCY_RATE), - float_to_fp16_16(91.7871148459384 / FREQUENCY_RATE), - float_to_fp16_16(91.9158485273492 / FREQUENCY_RATE), - float_to_fp16_16(92.0449438202247 / FREQUENCY_RATE), - float_to_fp16_16(92.1744022503516 / FREQUENCY_RATE), - float_to_fp16_16(92.3042253521127 / FREQUENCY_RATE), - float_to_fp16_16(92.4344146685472 / FREQUENCY_RATE), - float_to_fp16_16(92.5649717514124 / FREQUENCY_RATE), - float_to_fp16_16(92.6958981612447 / FREQUENCY_RATE), - float_to_fp16_16(92.8271954674221 / FREQUENCY_RATE), - float_to_fp16_16(92.958865248227 / FREQUENCY_RATE), - float_to_fp16_16(93.0909090909091 / FREQUENCY_RATE), - float_to_fp16_16(93.2233285917497 / FREQUENCY_RATE), - float_to_fp16_16(93.3561253561254 / FREQUENCY_RATE), - float_to_fp16_16(93.4893009985735 / FREQUENCY_RATE), - float_to_fp16_16(93.6228571428572 / FREQUENCY_RATE), - float_to_fp16_16(93.7567954220315 / FREQUENCY_RATE), - float_to_fp16_16(93.89111747851 / FREQUENCY_RATE), - float_to_fp16_16(94.025824964132 / FREQUENCY_RATE), - float_to_fp16_16(94.1609195402299 / FREQUENCY_RATE), - float_to_fp16_16(94.2964028776978 / FREQUENCY_RATE), - float_to_fp16_16(94.4322766570605 / FREQUENCY_RATE), - float_to_fp16_16(94.5685425685426 / FREQUENCY_RATE), - float_to_fp16_16(94.7052023121387 / FREQUENCY_RATE), - float_to_fp16_16(94.8422575976845 / FREQUENCY_RATE), - float_to_fp16_16(94.9797101449275 / FREQUENCY_RATE), - float_to_fp16_16(95.1175616835994 / FREQUENCY_RATE), - float_to_fp16_16(95.2558139534884 / FREQUENCY_RATE), - float_to_fp16_16(95.3944687045124 / FREQUENCY_RATE), - float_to_fp16_16(95.533527696793 / FREQUENCY_RATE), - float_to_fp16_16(95.6729927007299 / FREQUENCY_RATE), - float_to_fp16_16(95.812865497076 / FREQUENCY_RATE), - float_to_fp16_16(95.9531478770132 / FREQUENCY_RATE), - float_to_fp16_16(96.0938416422287 / FREQUENCY_RATE), - float_to_fp16_16(96.2349486049927 / FREQUENCY_RATE), - float_to_fp16_16(96.3764705882353 / FREQUENCY_RATE), - float_to_fp16_16(96.5184094256259 / FREQUENCY_RATE), - float_to_fp16_16(96.6607669616519 / FREQUENCY_RATE), - float_to_fp16_16(96.8035450516987 / FREQUENCY_RATE), - float_to_fp16_16(96.9467455621302 / FREQUENCY_RATE), - float_to_fp16_16(97.0903703703704 / FREQUENCY_RATE), - float_to_fp16_16(97.2344213649852 / FREQUENCY_RATE), - float_to_fp16_16(97.3789004457652 / FREQUENCY_RATE), - float_to_fp16_16(97.5238095238095 / FREQUENCY_RATE), - float_to_fp16_16(97.6691505216095 / FREQUENCY_RATE), - float_to_fp16_16(97.8149253731343 / FREQUENCY_RATE), - float_to_fp16_16(97.9611360239163 / FREQUENCY_RATE), - float_to_fp16_16(98.1077844311377 / FREQUENCY_RATE), - float_to_fp16_16(98.2548725637181 / FREQUENCY_RATE), - float_to_fp16_16(98.4024024024024 / FREQUENCY_RATE), - float_to_fp16_16(98.5503759398496 / FREQUENCY_RATE), - float_to_fp16_16(98.6987951807229 / FREQUENCY_RATE), - float_to_fp16_16(98.8476621417798 / FREQUENCY_RATE), - float_to_fp16_16(98.9969788519637 / FREQUENCY_RATE), - float_to_fp16_16(99.1467473524962 / FREQUENCY_RATE), - float_to_fp16_16(99.2969696969697 / FREQUENCY_RATE), - float_to_fp16_16(99.4476479514416 / FREQUENCY_RATE), - float_to_fp16_16(99.5987841945289 / FREQUENCY_RATE), - float_to_fp16_16(99.7503805175038 / FREQUENCY_RATE), - float_to_fp16_16(99.9024390243902 / FREQUENCY_RATE), - float_to_fp16_16(100.054961832061 / FREQUENCY_RATE), - float_to_fp16_16(100.207951070336 / FREQUENCY_RATE), - float_to_fp16_16(100.361408882083 / FREQUENCY_RATE), - float_to_fp16_16(100.515337423313 / FREQUENCY_RATE), - float_to_fp16_16(100.669738863287 / FREQUENCY_RATE), - float_to_fp16_16(100.824615384615 / FREQUENCY_RATE), - float_to_fp16_16(100.979969183359 / FREQUENCY_RATE), - float_to_fp16_16(101.135802469136 / FREQUENCY_RATE), - float_to_fp16_16(101.292117465224 / FREQUENCY_RATE), - float_to_fp16_16(101.448916408669 / FREQUENCY_RATE), - float_to_fp16_16(101.606201550388 / FREQUENCY_RATE), - float_to_fp16_16(101.76397515528 / FREQUENCY_RATE), - float_to_fp16_16(101.922239502333 / FREQUENCY_RATE), - float_to_fp16_16(102.080996884735 / FREQUENCY_RATE), - float_to_fp16_16(102.240249609984 / FREQUENCY_RATE), - float_to_fp16_16(102.4 / FREQUENCY_RATE), - float_to_fp16_16(102.560250391236 / FREQUENCY_RATE), - float_to_fp16_16(102.721003134796 / FREQUENCY_RATE), - float_to_fp16_16(102.882260596546 / FREQUENCY_RATE), - float_to_fp16_16(103.044025157233 / FREQUENCY_RATE), - float_to_fp16_16(103.206299212598 / FREQUENCY_RATE), - float_to_fp16_16(103.369085173502 / FREQUENCY_RATE), - float_to_fp16_16(103.532385466035 / FREQUENCY_RATE), - float_to_fp16_16(103.696202531646 / FREQUENCY_RATE), - float_to_fp16_16(103.860538827258 / FREQUENCY_RATE), - float_to_fp16_16(104.025396825397 / FREQUENCY_RATE), - float_to_fp16_16(104.190779014308 / FREQUENCY_RATE), - float_to_fp16_16(104.356687898089 / FREQUENCY_RATE), - float_to_fp16_16(104.52312599681 / FREQUENCY_RATE), - float_to_fp16_16(104.690095846645 / FREQUENCY_RATE), - float_to_fp16_16(104.8576 / FREQUENCY_RATE), - float_to_fp16_16(105.025641025641 / FREQUENCY_RATE), - float_to_fp16_16(105.194221508828 / FREQUENCY_RATE), - float_to_fp16_16(105.363344051447 / FREQUENCY_RATE), - float_to_fp16_16(105.533011272142 / FREQUENCY_RATE), - float_to_fp16_16(105.703225806452 / FREQUENCY_RATE), - float_to_fp16_16(105.873990306947 / FREQUENCY_RATE), - float_to_fp16_16(106.045307443366 / FREQUENCY_RATE), - float_to_fp16_16(106.217179902755 / FREQUENCY_RATE), - float_to_fp16_16(106.38961038961 / FREQUENCY_RATE), - float_to_fp16_16(106.562601626016 / FREQUENCY_RATE), - float_to_fp16_16(106.736156351792 / FREQUENCY_RATE), - float_to_fp16_16(106.910277324633 / FREQUENCY_RATE), - float_to_fp16_16(107.084967320261 / FREQUENCY_RATE), - float_to_fp16_16(107.26022913257 / FREQUENCY_RATE), - float_to_fp16_16(107.436065573771 / FREQUENCY_RATE), - float_to_fp16_16(107.612479474548 / FREQUENCY_RATE), - float_to_fp16_16(107.789473684211 / FREQUENCY_RATE), - float_to_fp16_16(107.96705107084 / FREQUENCY_RATE), - float_to_fp16_16(108.145214521452 / FREQUENCY_RATE), - float_to_fp16_16(108.323966942149 / FREQUENCY_RATE), - float_to_fp16_16(108.503311258278 / FREQUENCY_RATE), - float_to_fp16_16(108.683250414594 / FREQUENCY_RATE), - float_to_fp16_16(108.863787375415 / FREQUENCY_RATE), - float_to_fp16_16(109.044925124792 / FREQUENCY_RATE), - float_to_fp16_16(109.226666666667 / FREQUENCY_RATE), - float_to_fp16_16(109.409015025042 / FREQUENCY_RATE), - float_to_fp16_16(109.591973244147 / FREQUENCY_RATE), - float_to_fp16_16(109.77554438861 / FREQUENCY_RATE), - float_to_fp16_16(109.959731543624 / FREQUENCY_RATE), - float_to_fp16_16(110.144537815126 / FREQUENCY_RATE), - float_to_fp16_16(110.329966329966 / FREQUENCY_RATE), - float_to_fp16_16(110.516020236088 / FREQUENCY_RATE), - float_to_fp16_16(110.702702702703 / FREQUENCY_RATE), - float_to_fp16_16(110.890016920474 / FREQUENCY_RATE), - float_to_fp16_16(111.077966101695 / FREQUENCY_RATE), - float_to_fp16_16(111.266553480475 / FREQUENCY_RATE), - float_to_fp16_16(111.455782312925 / FREQUENCY_RATE), - float_to_fp16_16(111.645655877342 / FREQUENCY_RATE), - float_to_fp16_16(111.836177474403 / FREQUENCY_RATE), - float_to_fp16_16(112.02735042735 / FREQUENCY_RATE), - float_to_fp16_16(112.219178082192 / FREQUENCY_RATE), - float_to_fp16_16(112.41166380789 / FREQUENCY_RATE), - float_to_fp16_16(112.604810996564 / FREQUENCY_RATE), - float_to_fp16_16(112.798623063683 / FREQUENCY_RATE), - float_to_fp16_16(112.993103448276 / FREQUENCY_RATE), - float_to_fp16_16(113.188255613126 / FREQUENCY_RATE), - float_to_fp16_16(113.384083044983 / FREQUENCY_RATE), - float_to_fp16_16(113.580589254766 / FREQUENCY_RATE), - float_to_fp16_16(113.777777777778 / FREQUENCY_RATE), - float_to_fp16_16(113.975652173913 / FREQUENCY_RATE), - float_to_fp16_16(114.174216027875 / FREQUENCY_RATE), - float_to_fp16_16(114.373472949389 / FREQUENCY_RATE), - float_to_fp16_16(114.573426573427 / FREQUENCY_RATE), - float_to_fp16_16(114.77408056042 / FREQUENCY_RATE), - float_to_fp16_16(114.975438596491 / FREQUENCY_RATE), - float_to_fp16_16(115.177504393673 / FREQUENCY_RATE), - float_to_fp16_16(115.380281690141 / FREQUENCY_RATE), - float_to_fp16_16(115.583774250441 / FREQUENCY_RATE), - float_to_fp16_16(115.787985865724 / FREQUENCY_RATE), - float_to_fp16_16(115.992920353982 / FREQUENCY_RATE), - float_to_fp16_16(116.198581560284 / FREQUENCY_RATE), - float_to_fp16_16(116.404973357016 / FREQUENCY_RATE), - float_to_fp16_16(116.612099644128 / FREQUENCY_RATE), - float_to_fp16_16(116.819964349376 / FREQUENCY_RATE), - float_to_fp16_16(117.028571428571 / FREQUENCY_RATE), - float_to_fp16_16(117.237924865832 / FREQUENCY_RATE), - float_to_fp16_16(117.448028673835 / FREQUENCY_RATE), - float_to_fp16_16(117.658886894075 / FREQUENCY_RATE), - float_to_fp16_16(117.870503597122 / FREQUENCY_RATE), - float_to_fp16_16(118.082882882883 / FREQUENCY_RATE), - float_to_fp16_16(118.296028880866 / FREQUENCY_RATE), - float_to_fp16_16(118.509945750452 / FREQUENCY_RATE), - float_to_fp16_16(118.724637681159 / FREQUENCY_RATE), - float_to_fp16_16(118.940108892922 / FREQUENCY_RATE), - float_to_fp16_16(119.156363636364 / FREQUENCY_RATE), - float_to_fp16_16(119.373406193078 / FREQUENCY_RATE), - float_to_fp16_16(119.591240875912 / FREQUENCY_RATE), - float_to_fp16_16(119.80987202925 / FREQUENCY_RATE), - float_to_fp16_16(120.029304029304 / FREQUENCY_RATE), - float_to_fp16_16(120.249541284404 / FREQUENCY_RATE), - float_to_fp16_16(120.470588235294 / FREQUENCY_RATE), - float_to_fp16_16(120.692449355433 / FREQUENCY_RATE), - float_to_fp16_16(120.915129151292 / FREQUENCY_RATE), - float_to_fp16_16(121.138632162662 / FREQUENCY_RATE), - float_to_fp16_16(121.362962962963 / FREQUENCY_RATE), - float_to_fp16_16(121.588126159555 / FREQUENCY_RATE), - float_to_fp16_16(121.814126394052 / FREQUENCY_RATE), - float_to_fp16_16(122.040968342644 / FREQUENCY_RATE), - float_to_fp16_16(122.268656716418 / FREQUENCY_RATE), - float_to_fp16_16(122.497196261682 / FREQUENCY_RATE), - float_to_fp16_16(122.7265917603 / FREQUENCY_RATE), - float_to_fp16_16(122.956848030019 / FREQUENCY_RATE), - float_to_fp16_16(123.187969924812 / FREQUENCY_RATE), - float_to_fp16_16(123.419962335217 / FREQUENCY_RATE), - float_to_fp16_16(123.652830188679 / FREQUENCY_RATE), - float_to_fp16_16(123.886578449906 / FREQUENCY_RATE), - float_to_fp16_16(124.121212121212 / FREQUENCY_RATE), - float_to_fp16_16(124.356736242884 / FREQUENCY_RATE), - float_to_fp16_16(124.593155893536 / FREQUENCY_RATE), - float_to_fp16_16(124.830476190476 / FREQUENCY_RATE), - float_to_fp16_16(125.068702290076 / FREQUENCY_RATE), - float_to_fp16_16(125.307839388145 / FREQUENCY_RATE), - float_to_fp16_16(125.547892720307 / FREQUENCY_RATE), - float_to_fp16_16(125.78886756238 / FREQUENCY_RATE), - float_to_fp16_16(126.030769230769 / FREQUENCY_RATE), - float_to_fp16_16(126.273603082852 / FREQUENCY_RATE), - float_to_fp16_16(126.517374517375 / FREQUENCY_RATE), - float_to_fp16_16(126.762088974855 / FREQUENCY_RATE), - float_to_fp16_16(127.007751937985 / FREQUENCY_RATE), - float_to_fp16_16(127.254368932039 / FREQUENCY_RATE), - float_to_fp16_16(127.501945525292 / FREQUENCY_RATE), - float_to_fp16_16(127.750487329435 / FREQUENCY_RATE), - float_to_fp16_16(128 / FREQUENCY_RATE), - float_to_fp16_16(128.250489236791 / FREQUENCY_RATE), - float_to_fp16_16(128.501960784314 / FREQUENCY_RATE), - float_to_fp16_16(128.75442043222 / FREQUENCY_RATE), - float_to_fp16_16(129.007874015748 / FREQUENCY_RATE), - float_to_fp16_16(129.262327416174 / FREQUENCY_RATE), - float_to_fp16_16(129.517786561265 / FREQUENCY_RATE), - float_to_fp16_16(129.774257425743 / FREQUENCY_RATE), - float_to_fp16_16(130.031746031746 / FREQUENCY_RATE), - float_to_fp16_16(130.290258449304 / FREQUENCY_RATE), - float_to_fp16_16(130.549800796813 / FREQUENCY_RATE), - float_to_fp16_16(130.810379241517 / FREQUENCY_RATE), - float_to_fp16_16(131.072 / FREQUENCY_RATE), - float_to_fp16_16(131.334669338677 / FREQUENCY_RATE), - float_to_fp16_16(131.598393574297 / FREQUENCY_RATE), - float_to_fp16_16(131.863179074447 / FREQUENCY_RATE), - float_to_fp16_16(132.129032258065 / FREQUENCY_RATE), - float_to_fp16_16(132.39595959596 / FREQUENCY_RATE), - float_to_fp16_16(132.663967611336 / FREQUENCY_RATE), - float_to_fp16_16(132.933062880325 / FREQUENCY_RATE), - float_to_fp16_16(133.20325203252 / FREQUENCY_RATE), - float_to_fp16_16(133.474541751527 / FREQUENCY_RATE), - float_to_fp16_16(133.74693877551 / FREQUENCY_RATE), - float_to_fp16_16(134.020449897751 / FREQUENCY_RATE), - float_to_fp16_16(134.295081967213 / FREQUENCY_RATE), - float_to_fp16_16(134.570841889117 / FREQUENCY_RATE), - float_to_fp16_16(134.847736625514 / FREQUENCY_RATE), - float_to_fp16_16(135.125773195876 / FREQUENCY_RATE), - float_to_fp16_16(135.404958677686 / FREQUENCY_RATE), - float_to_fp16_16(135.685300207039 / FREQUENCY_RATE), - float_to_fp16_16(135.966804979253 / FREQUENCY_RATE), - float_to_fp16_16(136.24948024948 / FREQUENCY_RATE), - float_to_fp16_16(136.533333333333 / FREQUENCY_RATE), - float_to_fp16_16(136.818371607516 / FREQUENCY_RATE), - float_to_fp16_16(137.10460251046 / FREQUENCY_RATE), - float_to_fp16_16(137.392033542977 / FREQUENCY_RATE), - float_to_fp16_16(137.680672268908 / FREQUENCY_RATE), - float_to_fp16_16(137.970526315789 / FREQUENCY_RATE), - float_to_fp16_16(138.261603375527 / FREQUENCY_RATE), - float_to_fp16_16(138.553911205074 / FREQUENCY_RATE), - float_to_fp16_16(138.847457627119 / FREQUENCY_RATE), - float_to_fp16_16(139.142250530786 / FREQUENCY_RATE), - float_to_fp16_16(139.43829787234 / FREQUENCY_RATE), - float_to_fp16_16(139.735607675906 / FREQUENCY_RATE), - float_to_fp16_16(140.034188034188 / FREQUENCY_RATE), - float_to_fp16_16(140.334047109208 / FREQUENCY_RATE), - float_to_fp16_16(140.635193133047 / FREQUENCY_RATE), - float_to_fp16_16(140.937634408602 / FREQUENCY_RATE), - float_to_fp16_16(141.241379310345 / FREQUENCY_RATE), - float_to_fp16_16(141.546436285097 / FREQUENCY_RATE), - float_to_fp16_16(141.852813852814 / FREQUENCY_RATE), - float_to_fp16_16(142.160520607375 / FREQUENCY_RATE), - float_to_fp16_16(142.469565217391 / FREQUENCY_RATE), - float_to_fp16_16(142.779956427015 / FREQUENCY_RATE), - float_to_fp16_16(143.091703056769 / FREQUENCY_RATE), - float_to_fp16_16(143.404814004376 / FREQUENCY_RATE), - float_to_fp16_16(143.719298245614 / FREQUENCY_RATE), - float_to_fp16_16(144.035164835165 / FREQUENCY_RATE), - float_to_fp16_16(144.352422907489 / FREQUENCY_RATE), - float_to_fp16_16(144.671081677704 / FREQUENCY_RATE), - float_to_fp16_16(144.991150442478 / FREQUENCY_RATE), - float_to_fp16_16(145.312638580931 / FREQUENCY_RATE), - float_to_fp16_16(145.635555555556 / FREQUENCY_RATE), - float_to_fp16_16(145.95991091314 / FREQUENCY_RATE), - float_to_fp16_16(146.285714285714 / FREQUENCY_RATE), - float_to_fp16_16(146.612975391499 / FREQUENCY_RATE), - float_to_fp16_16(146.941704035874 / FREQUENCY_RATE), - float_to_fp16_16(147.27191011236 / FREQUENCY_RATE), - float_to_fp16_16(147.603603603604 / FREQUENCY_RATE), - float_to_fp16_16(147.936794582393 / FREQUENCY_RATE), - float_to_fp16_16(148.27149321267 / FREQUENCY_RATE), - float_to_fp16_16(148.607709750567 / FREQUENCY_RATE), - float_to_fp16_16(148.945454545455 / FREQUENCY_RATE), - float_to_fp16_16(149.284738041002 / FREQUENCY_RATE), - float_to_fp16_16(149.625570776256 / FREQUENCY_RATE), - float_to_fp16_16(149.967963386728 / FREQUENCY_RATE), - float_to_fp16_16(150.311926605505 / FREQUENCY_RATE), - float_to_fp16_16(150.657471264368 / FREQUENCY_RATE), - float_to_fp16_16(151.004608294931 / FREQUENCY_RATE), - float_to_fp16_16(151.353348729792 / FREQUENCY_RATE), - float_to_fp16_16(151.703703703704 / FREQUENCY_RATE), - float_to_fp16_16(152.055684454756 / FREQUENCY_RATE), - float_to_fp16_16(152.409302325581 / FREQUENCY_RATE), - float_to_fp16_16(152.764568764569 / FREQUENCY_RATE), - float_to_fp16_16(153.121495327103 / FREQUENCY_RATE), - float_to_fp16_16(153.480093676815 / FREQUENCY_RATE), - float_to_fp16_16(153.840375586854 / FREQUENCY_RATE), - float_to_fp16_16(154.202352941176 / FREQUENCY_RATE), - float_to_fp16_16(154.566037735849 / FREQUENCY_RATE), - float_to_fp16_16(154.931442080378 / FREQUENCY_RATE), - float_to_fp16_16(155.298578199052 / FREQUENCY_RATE), - float_to_fp16_16(155.667458432304 / FREQUENCY_RATE), - float_to_fp16_16(156.038095238095 / FREQUENCY_RATE), - float_to_fp16_16(156.410501193317 / FREQUENCY_RATE), - float_to_fp16_16(156.784688995215 / FREQUENCY_RATE), - float_to_fp16_16(157.16067146283 / FREQUENCY_RATE), - float_to_fp16_16(157.538461538462 / FREQUENCY_RATE), - float_to_fp16_16(157.918072289157 / FREQUENCY_RATE), - float_to_fp16_16(158.299516908213 / FREQUENCY_RATE), - float_to_fp16_16(158.682808716707 / FREQUENCY_RATE), - float_to_fp16_16(159.067961165049 / FREQUENCY_RATE), - float_to_fp16_16(159.45498783455 / FREQUENCY_RATE), - float_to_fp16_16(159.843902439024 / FREQUENCY_RATE), - float_to_fp16_16(160.234718826406 / FREQUENCY_RATE), - float_to_fp16_16(160.627450980392 / FREQUENCY_RATE), - float_to_fp16_16(161.022113022113 / FREQUENCY_RATE), - float_to_fp16_16(161.418719211823 / FREQUENCY_RATE), - float_to_fp16_16(161.817283950617 / FREQUENCY_RATE), - float_to_fp16_16(162.217821782178 / FREQUENCY_RATE), - float_to_fp16_16(162.620347394541 / FREQUENCY_RATE), - float_to_fp16_16(163.024875621891 / FREQUENCY_RATE), - float_to_fp16_16(163.431421446384 / FREQUENCY_RATE), - float_to_fp16_16(163.84 / FREQUENCY_RATE), - float_to_fp16_16(164.250626566416 / FREQUENCY_RATE), - float_to_fp16_16(164.663316582915 / FREQUENCY_RATE), - float_to_fp16_16(165.078085642317 / FREQUENCY_RATE), - float_to_fp16_16(165.49494949495 / FREQUENCY_RATE), - float_to_fp16_16(165.913924050633 / FREQUENCY_RATE), - float_to_fp16_16(166.335025380711 / FREQUENCY_RATE), - float_to_fp16_16(166.758269720102 / FREQUENCY_RATE), - float_to_fp16_16(167.183673469388 / FREQUENCY_RATE), - float_to_fp16_16(167.611253196931 / FREQUENCY_RATE), - float_to_fp16_16(168.041025641026 / FREQUENCY_RATE), - float_to_fp16_16(168.473007712082 / FREQUENCY_RATE), - float_to_fp16_16(168.907216494845 / FREQUENCY_RATE), - float_to_fp16_16(169.343669250646 / FREQUENCY_RATE), - float_to_fp16_16(169.782383419689 / FREQUENCY_RATE), - float_to_fp16_16(170.223376623377 / FREQUENCY_RATE), - float_to_fp16_16(170.666666666667 / FREQUENCY_RATE), - float_to_fp16_16(171.11227154047 / FREQUENCY_RATE), - float_to_fp16_16(171.560209424084 / FREQUENCY_RATE), - float_to_fp16_16(172.010498687664 / FREQUENCY_RATE), - float_to_fp16_16(172.463157894737 / FREQUENCY_RATE), - float_to_fp16_16(172.918205804749 / FREQUENCY_RATE), - float_to_fp16_16(173.375661375661 / FREQUENCY_RATE), - float_to_fp16_16(173.835543766578 / FREQUENCY_RATE), - float_to_fp16_16(174.297872340426 / FREQUENCY_RATE), - float_to_fp16_16(174.762666666667 / FREQUENCY_RATE), - float_to_fp16_16(175.229946524064 / FREQUENCY_RATE), - float_to_fp16_16(175.699731903485 / FREQUENCY_RATE), - float_to_fp16_16(176.172043010753 / FREQUENCY_RATE), - float_to_fp16_16(176.646900269542 / FREQUENCY_RATE), - float_to_fp16_16(177.124324324324 / FREQUENCY_RATE), - float_to_fp16_16(177.60433604336 / FREQUENCY_RATE), - float_to_fp16_16(178.086956521739 / FREQUENCY_RATE), - float_to_fp16_16(178.572207084469 / FREQUENCY_RATE), - float_to_fp16_16(179.060109289618 / FREQUENCY_RATE), - float_to_fp16_16(179.550684931507 / FREQUENCY_RATE), - float_to_fp16_16(180.043956043956 / FREQUENCY_RATE), - float_to_fp16_16(180.539944903581 / FREQUENCY_RATE), - float_to_fp16_16(181.038674033149 / FREQUENCY_RATE), - float_to_fp16_16(181.540166204986 / FREQUENCY_RATE), - float_to_fp16_16(182.044444444444 / FREQUENCY_RATE), - float_to_fp16_16(182.551532033426 / FREQUENCY_RATE), - float_to_fp16_16(183.061452513966 / FREQUENCY_RATE), - float_to_fp16_16(183.574229691877 / FREQUENCY_RATE), - float_to_fp16_16(184.089887640449 / FREQUENCY_RATE), - float_to_fp16_16(184.608450704225 / FREQUENCY_RATE), - float_to_fp16_16(185.129943502825 / FREQUENCY_RATE), - float_to_fp16_16(185.654390934844 / FREQUENCY_RATE), - float_to_fp16_16(186.181818181818 / FREQUENCY_RATE), - float_to_fp16_16(186.712250712251 / FREQUENCY_RATE), - float_to_fp16_16(187.245714285714 / FREQUENCY_RATE), - float_to_fp16_16(187.78223495702 / FREQUENCY_RATE), - float_to_fp16_16(188.32183908046 / FREQUENCY_RATE), - float_to_fp16_16(188.864553314121 / FREQUENCY_RATE), - float_to_fp16_16(189.410404624277 / FREQUENCY_RATE), - float_to_fp16_16(189.959420289855 / FREQUENCY_RATE), - float_to_fp16_16(190.511627906977 / FREQUENCY_RATE), - float_to_fp16_16(191.067055393586 / FREQUENCY_RATE), - float_to_fp16_16(191.625730994152 / FREQUENCY_RATE), - float_to_fp16_16(192.187683284457 / FREQUENCY_RATE), - float_to_fp16_16(192.752941176471 / FREQUENCY_RATE), - float_to_fp16_16(193.321533923304 / FREQUENCY_RATE), - float_to_fp16_16(193.89349112426 / FREQUENCY_RATE), - float_to_fp16_16(194.46884272997 / FREQUENCY_RATE), - float_to_fp16_16(195.047619047619 / FREQUENCY_RATE), - float_to_fp16_16(195.629850746269 / FREQUENCY_RATE), - float_to_fp16_16(196.215568862275 / FREQUENCY_RATE), - float_to_fp16_16(196.804804804805 / FREQUENCY_RATE), - float_to_fp16_16(197.397590361446 / FREQUENCY_RATE), - float_to_fp16_16(197.993957703928 / FREQUENCY_RATE), - float_to_fp16_16(198.593939393939 / FREQUENCY_RATE), - float_to_fp16_16(199.197568389058 / FREQUENCY_RATE), - float_to_fp16_16(199.804878048781 / FREQUENCY_RATE), - float_to_fp16_16(200.415902140673 / FREQUENCY_RATE), - float_to_fp16_16(201.030674846626 / FREQUENCY_RATE), - float_to_fp16_16(201.649230769231 / FREQUENCY_RATE), - float_to_fp16_16(202.271604938272 / FREQUENCY_RATE), - float_to_fp16_16(202.897832817337 / FREQUENCY_RATE), - float_to_fp16_16(203.527950310559 / FREQUENCY_RATE), - float_to_fp16_16(204.16199376947 / FREQUENCY_RATE), - float_to_fp16_16(204.8 / FREQUENCY_RATE), - float_to_fp16_16(205.442006269592 / FREQUENCY_RATE), - float_to_fp16_16(206.088050314465 / FREQUENCY_RATE), - float_to_fp16_16(206.738170347003 / FREQUENCY_RATE), - float_to_fp16_16(207.392405063291 / FREQUENCY_RATE), - float_to_fp16_16(208.050793650794 / FREQUENCY_RATE), - float_to_fp16_16(208.713375796178 / FREQUENCY_RATE), - float_to_fp16_16(209.380191693291 / FREQUENCY_RATE), - float_to_fp16_16(210.051282051282 / FREQUENCY_RATE), - float_to_fp16_16(210.726688102894 / FREQUENCY_RATE), - float_to_fp16_16(211.406451612903 / FREQUENCY_RATE), - float_to_fp16_16(212.090614886731 / FREQUENCY_RATE), - float_to_fp16_16(212.779220779221 / FREQUENCY_RATE), - float_to_fp16_16(213.472312703583 / FREQUENCY_RATE), - float_to_fp16_16(214.169934640523 / FREQUENCY_RATE), - float_to_fp16_16(214.872131147541 / FREQUENCY_RATE), - float_to_fp16_16(215.578947368421 / FREQUENCY_RATE), - float_to_fp16_16(216.290429042904 / FREQUENCY_RATE), - float_to_fp16_16(217.006622516556 / FREQUENCY_RATE), - float_to_fp16_16(217.727574750831 / FREQUENCY_RATE), - float_to_fp16_16(218.453333333333 / FREQUENCY_RATE), - float_to_fp16_16(219.183946488294 / FREQUENCY_RATE), - float_to_fp16_16(219.919463087248 / FREQUENCY_RATE), - float_to_fp16_16(220.659932659933 / FREQUENCY_RATE), - float_to_fp16_16(221.405405405405 / FREQUENCY_RATE), - float_to_fp16_16(222.15593220339 / FREQUENCY_RATE), - float_to_fp16_16(222.91156462585 / FREQUENCY_RATE), - float_to_fp16_16(223.672354948805 / FREQUENCY_RATE), - float_to_fp16_16(224.438356164384 / FREQUENCY_RATE), - float_to_fp16_16(225.209621993127 / FREQUENCY_RATE), - float_to_fp16_16(225.986206896552 / FREQUENCY_RATE), - float_to_fp16_16(226.768166089965 / FREQUENCY_RATE), - float_to_fp16_16(227.555555555556 / FREQUENCY_RATE), - float_to_fp16_16(228.348432055749 / FREQUENCY_RATE), - float_to_fp16_16(229.146853146853 / FREQUENCY_RATE), - float_to_fp16_16(229.950877192982 / FREQUENCY_RATE), - float_to_fp16_16(230.760563380282 / FREQUENCY_RATE), - float_to_fp16_16(231.575971731449 / FREQUENCY_RATE), - float_to_fp16_16(232.397163120567 / FREQUENCY_RATE), - float_to_fp16_16(233.224199288256 / FREQUENCY_RATE), - float_to_fp16_16(234.057142857143 / FREQUENCY_RATE), - float_to_fp16_16(234.89605734767 / FREQUENCY_RATE), - float_to_fp16_16(235.741007194245 / FREQUENCY_RATE), - float_to_fp16_16(236.592057761733 / FREQUENCY_RATE), - float_to_fp16_16(237.449275362319 / FREQUENCY_RATE), - float_to_fp16_16(238.312727272727 / FREQUENCY_RATE), - float_to_fp16_16(239.182481751825 / FREQUENCY_RATE), - float_to_fp16_16(240.058608058608 / FREQUENCY_RATE), - float_to_fp16_16(240.941176470588 / FREQUENCY_RATE), - float_to_fp16_16(241.830258302583 / FREQUENCY_RATE), - float_to_fp16_16(242.725925925926 / FREQUENCY_RATE), - float_to_fp16_16(243.628252788104 / FREQUENCY_RATE), - float_to_fp16_16(244.537313432836 / FREQUENCY_RATE), - float_to_fp16_16(245.453183520599 / FREQUENCY_RATE), - float_to_fp16_16(246.375939849624 / FREQUENCY_RATE), - float_to_fp16_16(247.305660377358 / FREQUENCY_RATE), - float_to_fp16_16(248.242424242424 / FREQUENCY_RATE), - float_to_fp16_16(249.186311787072 / FREQUENCY_RATE), - float_to_fp16_16(250.137404580153 / FREQUENCY_RATE), - float_to_fp16_16(251.095785440613 / FREQUENCY_RATE), - float_to_fp16_16(252.061538461538 / FREQUENCY_RATE), - float_to_fp16_16(253.034749034749 / FREQUENCY_RATE), - float_to_fp16_16(254.015503875969 / FREQUENCY_RATE), - float_to_fp16_16(255.003891050584 / FREQUENCY_RATE), - float_to_fp16_16(256 / FREQUENCY_RATE), - float_to_fp16_16(257.003921568627 / FREQUENCY_RATE), - float_to_fp16_16(258.015748031496 / FREQUENCY_RATE), - float_to_fp16_16(259.03557312253 / FREQUENCY_RATE), - float_to_fp16_16(260.063492063492 / FREQUENCY_RATE), - float_to_fp16_16(261.099601593625 / FREQUENCY_RATE), - float_to_fp16_16(262.144 / FREQUENCY_RATE), - float_to_fp16_16(263.196787148594 / FREQUENCY_RATE), - float_to_fp16_16(264.258064516129 / FREQUENCY_RATE), - float_to_fp16_16(265.327935222672 / FREQUENCY_RATE), - float_to_fp16_16(266.406504065041 / FREQUENCY_RATE), - float_to_fp16_16(267.49387755102 / FREQUENCY_RATE), - float_to_fp16_16(268.590163934426 / FREQUENCY_RATE), - float_to_fp16_16(269.695473251029 / FREQUENCY_RATE), - float_to_fp16_16(270.809917355372 / FREQUENCY_RATE), - float_to_fp16_16(271.933609958506 / FREQUENCY_RATE), - float_to_fp16_16(273.066666666667 / FREQUENCY_RATE), - float_to_fp16_16(274.20920502092 / FREQUENCY_RATE), - float_to_fp16_16(275.361344537815 / FREQUENCY_RATE), - float_to_fp16_16(276.523206751055 / FREQUENCY_RATE), - float_to_fp16_16(277.694915254237 / FREQUENCY_RATE), - float_to_fp16_16(278.876595744681 / FREQUENCY_RATE), - float_to_fp16_16(280.068376068376 / FREQUENCY_RATE), - float_to_fp16_16(281.270386266094 / FREQUENCY_RATE), - float_to_fp16_16(282.48275862069 / FREQUENCY_RATE), - float_to_fp16_16(283.705627705628 / FREQUENCY_RATE), - float_to_fp16_16(284.939130434783 / FREQUENCY_RATE), - float_to_fp16_16(286.183406113537 / FREQUENCY_RATE), - float_to_fp16_16(287.438596491228 / FREQUENCY_RATE), - float_to_fp16_16(288.704845814978 / FREQUENCY_RATE), - float_to_fp16_16(289.982300884956 / FREQUENCY_RATE), - float_to_fp16_16(291.271111111111 / FREQUENCY_RATE), - float_to_fp16_16(292.571428571429 / FREQUENCY_RATE), - float_to_fp16_16(293.883408071749 / FREQUENCY_RATE), - float_to_fp16_16(295.207207207207 / FREQUENCY_RATE), - float_to_fp16_16(296.542986425339 / FREQUENCY_RATE), - float_to_fp16_16(297.890909090909 / FREQUENCY_RATE), - float_to_fp16_16(299.251141552511 / FREQUENCY_RATE), - float_to_fp16_16(300.623853211009 / FREQUENCY_RATE), - float_to_fp16_16(302.009216589862 / FREQUENCY_RATE), - float_to_fp16_16(303.407407407407 / FREQUENCY_RATE), - float_to_fp16_16(304.818604651163 / FREQUENCY_RATE), - float_to_fp16_16(306.242990654206 / FREQUENCY_RATE), - float_to_fp16_16(307.680751173709 / FREQUENCY_RATE), - float_to_fp16_16(309.132075471698 / FREQUENCY_RATE), - float_to_fp16_16(310.597156398104 / FREQUENCY_RATE), - float_to_fp16_16(312.07619047619 / FREQUENCY_RATE), - float_to_fp16_16(313.569377990431 / FREQUENCY_RATE), - float_to_fp16_16(315.076923076923 / FREQUENCY_RATE), - float_to_fp16_16(316.599033816425 / FREQUENCY_RATE), - float_to_fp16_16(318.135922330097 / FREQUENCY_RATE), - float_to_fp16_16(319.687804878049 / FREQUENCY_RATE), - float_to_fp16_16(321.254901960784 / FREQUENCY_RATE), - float_to_fp16_16(322.837438423645 / FREQUENCY_RATE), - float_to_fp16_16(324.435643564356 / FREQUENCY_RATE), - float_to_fp16_16(326.049751243781 / FREQUENCY_RATE), - float_to_fp16_16(327.68 / FREQUENCY_RATE), - float_to_fp16_16(329.326633165829 / FREQUENCY_RATE), - float_to_fp16_16(330.989898989899 / FREQUENCY_RATE), - float_to_fp16_16(332.670050761421 / FREQUENCY_RATE), - float_to_fp16_16(334.367346938775 / FREQUENCY_RATE), - float_to_fp16_16(336.082051282051 / FREQUENCY_RATE), - float_to_fp16_16(337.814432989691 / FREQUENCY_RATE), - float_to_fp16_16(339.564766839378 / FREQUENCY_RATE), - float_to_fp16_16(341.333333333333 / FREQUENCY_RATE), - float_to_fp16_16(343.120418848168 / FREQUENCY_RATE), - float_to_fp16_16(344.926315789474 / FREQUENCY_RATE), - float_to_fp16_16(346.751322751323 / FREQUENCY_RATE), - float_to_fp16_16(348.595744680851 / FREQUENCY_RATE), - float_to_fp16_16(350.459893048128 / FREQUENCY_RATE), - float_to_fp16_16(352.344086021505 / FREQUENCY_RATE), - float_to_fp16_16(354.248648648649 / FREQUENCY_RATE), - float_to_fp16_16(356.173913043478 / FREQUENCY_RATE), - float_to_fp16_16(358.120218579235 / FREQUENCY_RATE), - float_to_fp16_16(360.087912087912 / FREQUENCY_RATE), - float_to_fp16_16(362.077348066298 / FREQUENCY_RATE), - float_to_fp16_16(364.088888888889 / FREQUENCY_RATE), - float_to_fp16_16(366.122905027933 / FREQUENCY_RATE), - float_to_fp16_16(368.179775280899 / FREQUENCY_RATE), - float_to_fp16_16(370.25988700565 / FREQUENCY_RATE), - float_to_fp16_16(372.363636363636 / FREQUENCY_RATE), - float_to_fp16_16(374.491428571429 / FREQUENCY_RATE), - float_to_fp16_16(376.64367816092 / FREQUENCY_RATE), - float_to_fp16_16(378.820809248555 / FREQUENCY_RATE), - float_to_fp16_16(381.023255813953 / FREQUENCY_RATE), - float_to_fp16_16(383.251461988304 / FREQUENCY_RATE), - float_to_fp16_16(385.505882352941 / FREQUENCY_RATE), - float_to_fp16_16(387.786982248521 / FREQUENCY_RATE), - float_to_fp16_16(390.095238095238 / FREQUENCY_RATE), - float_to_fp16_16(392.431137724551 / FREQUENCY_RATE), - float_to_fp16_16(394.795180722892 / FREQUENCY_RATE), - float_to_fp16_16(397.187878787879 / FREQUENCY_RATE), - float_to_fp16_16(399.609756097561 / FREQUENCY_RATE), - float_to_fp16_16(402.061349693252 / FREQUENCY_RATE), - float_to_fp16_16(404.543209876543 / FREQUENCY_RATE), - float_to_fp16_16(407.055900621118 / FREQUENCY_RATE), - float_to_fp16_16(409.6 / FREQUENCY_RATE), - float_to_fp16_16(412.176100628931 / FREQUENCY_RATE), - float_to_fp16_16(414.784810126582 / FREQUENCY_RATE), - float_to_fp16_16(417.426751592357 / FREQUENCY_RATE), - float_to_fp16_16(420.102564102564 / FREQUENCY_RATE), - float_to_fp16_16(422.812903225807 / FREQUENCY_RATE), - float_to_fp16_16(425.558441558442 / FREQUENCY_RATE), - float_to_fp16_16(428.339869281046 / FREQUENCY_RATE), - float_to_fp16_16(431.157894736842 / FREQUENCY_RATE), - float_to_fp16_16(434.013245033113 / FREQUENCY_RATE), - float_to_fp16_16(436.906666666667 / FREQUENCY_RATE), - float_to_fp16_16(439.838926174497 / FREQUENCY_RATE), - float_to_fp16_16(442.810810810811 / FREQUENCY_RATE), - float_to_fp16_16(445.823129251701 / FREQUENCY_RATE), - float_to_fp16_16(448.876712328767 / FREQUENCY_RATE), - float_to_fp16_16(451.972413793103 / FREQUENCY_RATE), - float_to_fp16_16(455.111111111111 / FREQUENCY_RATE), - float_to_fp16_16(458.293706293706 / FREQUENCY_RATE), - float_to_fp16_16(461.521126760563 / FREQUENCY_RATE), - float_to_fp16_16(464.794326241135 / FREQUENCY_RATE), - float_to_fp16_16(468.114285714286 / FREQUENCY_RATE), - float_to_fp16_16(471.482014388489 / FREQUENCY_RATE), - float_to_fp16_16(474.898550724638 / FREQUENCY_RATE), - float_to_fp16_16(478.36496350365 / FREQUENCY_RATE), - float_to_fp16_16(481.882352941176 / FREQUENCY_RATE), - float_to_fp16_16(485.451851851852 / FREQUENCY_RATE), - float_to_fp16_16(489.074626865672 / FREQUENCY_RATE), - float_to_fp16_16(492.751879699248 / FREQUENCY_RATE), - float_to_fp16_16(496.484848484849 / FREQUENCY_RATE), - float_to_fp16_16(500.274809160305 / FREQUENCY_RATE), - float_to_fp16_16(504.123076923077 / FREQUENCY_RATE), - float_to_fp16_16(508.031007751938 / FREQUENCY_RATE), - float_to_fp16_16(512 / FREQUENCY_RATE), - float_to_fp16_16(516.031496062992 / FREQUENCY_RATE), - float_to_fp16_16(520.126984126984 / FREQUENCY_RATE), - float_to_fp16_16(524.288 / FREQUENCY_RATE), - float_to_fp16_16(528.516129032258 / FREQUENCY_RATE), - float_to_fp16_16(532.813008130081 / FREQUENCY_RATE), - float_to_fp16_16(537.180327868852 / FREQUENCY_RATE), - float_to_fp16_16(541.619834710744 / FREQUENCY_RATE), - float_to_fp16_16(546.133333333333 / FREQUENCY_RATE), - float_to_fp16_16(550.72268907563 / FREQUENCY_RATE), - float_to_fp16_16(555.389830508475 / FREQUENCY_RATE), - float_to_fp16_16(560.136752136752 / FREQUENCY_RATE), - float_to_fp16_16(564.965517241379 / FREQUENCY_RATE), - float_to_fp16_16(569.878260869565 / FREQUENCY_RATE), - float_to_fp16_16(574.877192982456 / FREQUENCY_RATE), - float_to_fp16_16(579.964601769912 / FREQUENCY_RATE), - float_to_fp16_16(585.142857142857 / FREQUENCY_RATE), - float_to_fp16_16(590.414414414414 / FREQUENCY_RATE), - float_to_fp16_16(595.781818181818 / FREQUENCY_RATE), - float_to_fp16_16(601.247706422018 / FREQUENCY_RATE), - float_to_fp16_16(606.814814814815 / FREQUENCY_RATE), - float_to_fp16_16(612.485981308411 / FREQUENCY_RATE), - float_to_fp16_16(618.264150943396 / FREQUENCY_RATE), - float_to_fp16_16(624.152380952381 / FREQUENCY_RATE), - float_to_fp16_16(630.153846153846 / FREQUENCY_RATE), - float_to_fp16_16(636.271844660194 / FREQUENCY_RATE), - float_to_fp16_16(642.509803921569 / FREQUENCY_RATE), - float_to_fp16_16(648.871287128713 / FREQUENCY_RATE), - float_to_fp16_16(655.36 / FREQUENCY_RATE), - float_to_fp16_16(661.979797979798 / FREQUENCY_RATE), - float_to_fp16_16(668.734693877551 / FREQUENCY_RATE), - float_to_fp16_16(675.628865979381 / FREQUENCY_RATE), - float_to_fp16_16(682.666666666667 / FREQUENCY_RATE), - float_to_fp16_16(689.852631578947 / FREQUENCY_RATE), - float_to_fp16_16(697.191489361702 / FREQUENCY_RATE), - float_to_fp16_16(704.688172043011 / FREQUENCY_RATE), - float_to_fp16_16(712.347826086956 / FREQUENCY_RATE), - float_to_fp16_16(720.175824175824 / FREQUENCY_RATE), - float_to_fp16_16(728.177777777778 / FREQUENCY_RATE), - float_to_fp16_16(736.359550561798 / FREQUENCY_RATE), - float_to_fp16_16(744.727272727273 / FREQUENCY_RATE), - float_to_fp16_16(753.287356321839 / FREQUENCY_RATE), - float_to_fp16_16(762.046511627907 / FREQUENCY_RATE), - float_to_fp16_16(771.011764705882 / FREQUENCY_RATE), - float_to_fp16_16(780.190476190476 / FREQUENCY_RATE), - float_to_fp16_16(789.590361445783 / FREQUENCY_RATE), - float_to_fp16_16(799.219512195122 / FREQUENCY_RATE), - float_to_fp16_16(809.086419753086 / FREQUENCY_RATE), - float_to_fp16_16(819.2 / FREQUENCY_RATE), - float_to_fp16_16(829.569620253165 / FREQUENCY_RATE), - float_to_fp16_16(840.205128205128 / FREQUENCY_RATE), - float_to_fp16_16(851.116883116883 / FREQUENCY_RATE), - float_to_fp16_16(862.315789473684 / FREQUENCY_RATE), - float_to_fp16_16(873.813333333333 / FREQUENCY_RATE), - float_to_fp16_16(885.621621621622 / FREQUENCY_RATE), - float_to_fp16_16(897.753424657534 / FREQUENCY_RATE), - float_to_fp16_16(910.222222222222 / FREQUENCY_RATE), - float_to_fp16_16(923.042253521127 / FREQUENCY_RATE), - float_to_fp16_16(936.228571428571 / FREQUENCY_RATE), - float_to_fp16_16(949.797101449275 / FREQUENCY_RATE), - float_to_fp16_16(963.764705882353 / FREQUENCY_RATE), - float_to_fp16_16(978.149253731343 / FREQUENCY_RATE), - float_to_fp16_16(992.969696969697 / FREQUENCY_RATE), - float_to_fp16_16(1008.24615384615 / FREQUENCY_RATE), - float_to_fp16_16(1024 / FREQUENCY_RATE), - float_to_fp16_16(1040.25396825397 / FREQUENCY_RATE), - float_to_fp16_16(1057.03225806452 / FREQUENCY_RATE), - float_to_fp16_16(1074.36065573771 / FREQUENCY_RATE), - float_to_fp16_16(1092.26666666667 / FREQUENCY_RATE), - float_to_fp16_16(1110.77966101695 / FREQUENCY_RATE), - float_to_fp16_16(1129.93103448276 / FREQUENCY_RATE), - float_to_fp16_16(1149.75438596491 / FREQUENCY_RATE), - float_to_fp16_16(1170.28571428571 / FREQUENCY_RATE), - float_to_fp16_16(1191.56363636364 / FREQUENCY_RATE), - float_to_fp16_16(1213.62962962963 / FREQUENCY_RATE), - float_to_fp16_16(1236.52830188679 / FREQUENCY_RATE), - float_to_fp16_16(1260.30769230769 / FREQUENCY_RATE), - float_to_fp16_16(1285.01960784314 / FREQUENCY_RATE), - float_to_fp16_16(1310.72 / FREQUENCY_RATE), - float_to_fp16_16(1337.4693877551 / FREQUENCY_RATE), - float_to_fp16_16(1365.33333333333 / FREQUENCY_RATE), - float_to_fp16_16(1394.3829787234 / FREQUENCY_RATE), - float_to_fp16_16(1424.69565217391 / FREQUENCY_RATE), - float_to_fp16_16(1456.35555555556 / FREQUENCY_RATE), - float_to_fp16_16(1489.45454545455 / FREQUENCY_RATE), - float_to_fp16_16(1524.09302325581 / FREQUENCY_RATE), - float_to_fp16_16(1560.38095238095 / FREQUENCY_RATE), - float_to_fp16_16(1598.43902439024 / FREQUENCY_RATE), - float_to_fp16_16(1638.4 / FREQUENCY_RATE), - float_to_fp16_16(1680.41025641026 / FREQUENCY_RATE), - float_to_fp16_16(1724.63157894737 / FREQUENCY_RATE), - float_to_fp16_16(1771.24324324324 / FREQUENCY_RATE), - float_to_fp16_16(1820.44444444444 / FREQUENCY_RATE), - float_to_fp16_16(1872.45714285714 / FREQUENCY_RATE), - float_to_fp16_16(1927.52941176471 / FREQUENCY_RATE), - float_to_fp16_16(1985.93939393939 / FREQUENCY_RATE), - float_to_fp16_16(2048 / FREQUENCY_RATE), - float_to_fp16_16(2114.06451612903 / FREQUENCY_RATE), - float_to_fp16_16(2184.53333333333 / FREQUENCY_RATE), - float_to_fp16_16(2259.86206896552 / FREQUENCY_RATE), - float_to_fp16_16(2340.57142857143 / FREQUENCY_RATE), - float_to_fp16_16(2427.25925925926 / FREQUENCY_RATE), - float_to_fp16_16(2520.61538461538 / FREQUENCY_RATE), - float_to_fp16_16(2621.44 / FREQUENCY_RATE), - float_to_fp16_16(2730.66666666667 / FREQUENCY_RATE), - float_to_fp16_16(2849.39130434783 / FREQUENCY_RATE), - float_to_fp16_16(2978.90909090909 / FREQUENCY_RATE), - float_to_fp16_16(3120.7619047619 / FREQUENCY_RATE), - float_to_fp16_16(3276.8 / FREQUENCY_RATE), - float_to_fp16_16(3449.26315789474 / FREQUENCY_RATE), - float_to_fp16_16(3640.88888888889 / FREQUENCY_RATE), - float_to_fp16_16(3855.05882352941 / FREQUENCY_RATE), - float_to_fp16_16(4096 / FREQUENCY_RATE), - float_to_fp16_16(4369.06666666667 / FREQUENCY_RATE), - float_to_fp16_16(4681.14285714286 / FREQUENCY_RATE), - float_to_fp16_16(5041.23076923077 / FREQUENCY_RATE), - float_to_fp16_16(5461.33333333333 / FREQUENCY_RATE), - float_to_fp16_16(5957.81818181818 / FREQUENCY_RATE), - float_to_fp16_16(6553.6 / FREQUENCY_RATE), - float_to_fp16_16(7281.77777777778 / FREQUENCY_RATE), - float_to_fp16_16(8192 / FREQUENCY_RATE), - float_to_fp16_16(9362.28571428571 / FREQUENCY_RATE), - float_to_fp16_16(10922.6666666667 / FREQUENCY_RATE), - float_to_fp16_16(13107.2 / FREQUENCY_RATE), - float_to_fp16_16(16384 / FREQUENCY_RATE), - float_to_fp16_16(21845.3333333333 / FREQUENCY_RATE), - float_to_fp16_16(32768 / FREQUENCY_RATE), - float_to_fp16_16(65536 / FREQUENCY_RATE), +const fixed8_24 freqTable[2048] = { + float_to_fp8_24(32 / FREQUENCY_RATE), + float_to_fp8_24(32.0156326331216 / FREQUENCY_RATE), + float_to_fp8_24(32.0312805474096 / FREQUENCY_RATE), + float_to_fp8_24(32.0469437652812 / FREQUENCY_RATE), + float_to_fp8_24(32.0626223091976 / FREQUENCY_RATE), + float_to_fp8_24(32.0783162016642 / FREQUENCY_RATE), + float_to_fp8_24(32.0940254652302 / FREQUENCY_RATE), + float_to_fp8_24(32.109750122489 / FREQUENCY_RATE), + float_to_fp8_24(32.1254901960784 / FREQUENCY_RATE), + float_to_fp8_24(32.1412457086807 / FREQUENCY_RATE), + float_to_fp8_24(32.1570166830226 / FREQUENCY_RATE), + float_to_fp8_24(32.1728031418753 / FREQUENCY_RATE), + float_to_fp8_24(32.188605108055 / FREQUENCY_RATE), + float_to_fp8_24(32.2044226044226 / FREQUENCY_RATE), + float_to_fp8_24(32.220255653884 / FREQUENCY_RATE), + float_to_fp8_24(32.2361042793901 / FREQUENCY_RATE), + float_to_fp8_24(32.251968503937 / FREQUENCY_RATE), + float_to_fp8_24(32.2678483505662 / FREQUENCY_RATE), + float_to_fp8_24(32.2837438423645 / FREQUENCY_RATE), + float_to_fp8_24(32.2996550024643 / FREQUENCY_RATE), + float_to_fp8_24(32.3155818540434 / FREQUENCY_RATE), + float_to_fp8_24(32.3315244203256 / FREQUENCY_RATE), + float_to_fp8_24(32.3474827245805 / FREQUENCY_RATE), + float_to_fp8_24(32.3634567901235 / FREQUENCY_RATE), + float_to_fp8_24(32.3794466403162 / FREQUENCY_RATE), + float_to_fp8_24(32.3954522985665 / FREQUENCY_RATE), + float_to_fp8_24(32.4114737883284 / FREQUENCY_RATE), + float_to_fp8_24(32.4275111331024 / FREQUENCY_RATE), + float_to_fp8_24(32.4435643564356 / FREQUENCY_RATE), + float_to_fp8_24(32.4596334819217 / FREQUENCY_RATE), + float_to_fp8_24(32.4757185332012 / FREQUENCY_RATE), + float_to_fp8_24(32.4918195339613 / FREQUENCY_RATE), + float_to_fp8_24(32.5079365079365 / FREQUENCY_RATE), + float_to_fp8_24(32.5240694789082 / FREQUENCY_RATE), + float_to_fp8_24(32.5402184707051 / FREQUENCY_RATE), + float_to_fp8_24(32.5563835072032 / FREQUENCY_RATE), + float_to_fp8_24(32.572564612326 / FREQUENCY_RATE), + float_to_fp8_24(32.5887618100448 / FREQUENCY_RATE), + float_to_fp8_24(32.6049751243781 / FREQUENCY_RATE), + float_to_fp8_24(32.6212045793927 / FREQUENCY_RATE), + float_to_fp8_24(32.6374501992032 / FREQUENCY_RATE), + float_to_fp8_24(32.6537120079721 / FREQUENCY_RATE), + float_to_fp8_24(32.6699900299103 / FREQUENCY_RATE), + float_to_fp8_24(32.6862842892768 / FREQUENCY_RATE), + float_to_fp8_24(32.7025948103792 / FREQUENCY_RATE), + float_to_fp8_24(32.7189216175736 / FREQUENCY_RATE), + float_to_fp8_24(32.7352647352647 / FREQUENCY_RATE), + float_to_fp8_24(32.751624187906 / FREQUENCY_RATE), + float_to_fp8_24(32.768 / FREQUENCY_RATE), + float_to_fp8_24(32.784392196098 / FREQUENCY_RATE), + float_to_fp8_24(32.8008008008008 / FREQUENCY_RATE), + float_to_fp8_24(32.8172258387581 / FREQUENCY_RATE), + float_to_fp8_24(32.8336673346693 / FREQUENCY_RATE), + float_to_fp8_24(32.8501253132832 / FREQUENCY_RATE), + float_to_fp8_24(32.8665997993982 / FREQUENCY_RATE), + float_to_fp8_24(32.8830908178625 / FREQUENCY_RATE), + float_to_fp8_24(32.8995983935743 / FREQUENCY_RATE), + float_to_fp8_24(32.9161225514817 / FREQUENCY_RATE), + float_to_fp8_24(32.9326633165829 / FREQUENCY_RATE), + float_to_fp8_24(32.9492207139266 / FREQUENCY_RATE), + float_to_fp8_24(32.9657947686117 / FREQUENCY_RATE), + float_to_fp8_24(32.9823855057876 / FREQUENCY_RATE), + float_to_fp8_24(32.9989929506546 / FREQUENCY_RATE), + float_to_fp8_24(33.0156171284635 / FREQUENCY_RATE), + float_to_fp8_24(33.0322580645161 / FREQUENCY_RATE), + float_to_fp8_24(33.0489157841654 / FREQUENCY_RATE), + float_to_fp8_24(33.0655903128153 / FREQUENCY_RATE), + float_to_fp8_24(33.0822816759213 / FREQUENCY_RATE), + float_to_fp8_24(33.0989898989899 / FREQUENCY_RATE), + float_to_fp8_24(33.1157150075796 / FREQUENCY_RATE), + float_to_fp8_24(33.1324570273003 / FREQUENCY_RATE), + float_to_fp8_24(33.1492159838139 / FREQUENCY_RATE), + float_to_fp8_24(33.165991902834 / FREQUENCY_RATE), + float_to_fp8_24(33.1827848101266 / FREQUENCY_RATE), + float_to_fp8_24(33.1995947315096 / FREQUENCY_RATE), + float_to_fp8_24(33.2164216928535 / FREQUENCY_RATE), + float_to_fp8_24(33.2332657200811 / FREQUENCY_RATE), + float_to_fp8_24(33.2501268391679 / FREQUENCY_RATE), + float_to_fp8_24(33.2670050761421 / FREQUENCY_RATE), + float_to_fp8_24(33.2839004570848 / FREQUENCY_RATE), + float_to_fp8_24(33.3008130081301 / FREQUENCY_RATE), + float_to_fp8_24(33.3177427554652 / FREQUENCY_RATE), + float_to_fp8_24(33.3346897253306 / FREQUENCY_RATE), + float_to_fp8_24(33.3516539440204 / FREQUENCY_RATE), + float_to_fp8_24(33.3686354378819 / FREQUENCY_RATE), + float_to_fp8_24(33.3856342333164 / FREQUENCY_RATE), + float_to_fp8_24(33.4026503567788 / FREQUENCY_RATE), + float_to_fp8_24(33.4196838347782 / FREQUENCY_RATE), + float_to_fp8_24(33.4367346938776 / FREQUENCY_RATE), + float_to_fp8_24(33.4538029606942 / FREQUENCY_RATE), + float_to_fp8_24(33.4708886618999 / FREQUENCY_RATE), + float_to_fp8_24(33.4879918242207 / FREQUENCY_RATE), + float_to_fp8_24(33.5051124744376 / FREQUENCY_RATE), + float_to_fp8_24(33.5222506393862 / FREQUENCY_RATE), + float_to_fp8_24(33.539406345957 / FREQUENCY_RATE), + float_to_fp8_24(33.5565796210957 / FREQUENCY_RATE), + float_to_fp8_24(33.5737704918033 / FREQUENCY_RATE), + float_to_fp8_24(33.5909789851358 / FREQUENCY_RATE), + float_to_fp8_24(33.6082051282051 / FREQUENCY_RATE), + float_to_fp8_24(33.6254489481786 / FREQUENCY_RATE), + float_to_fp8_24(33.6427104722793 / FREQUENCY_RATE), + float_to_fp8_24(33.6599897277863 / FREQUENCY_RATE), + float_to_fp8_24(33.6772867420349 / FREQUENCY_RATE), + float_to_fp8_24(33.6946015424164 / FREQUENCY_RATE), + float_to_fp8_24(33.7119341563786 / FREQUENCY_RATE), + float_to_fp8_24(33.7292846114256 / FREQUENCY_RATE), + float_to_fp8_24(33.7466529351184 / FREQUENCY_RATE), + float_to_fp8_24(33.7640391550747 / FREQUENCY_RATE), + float_to_fp8_24(33.7814432989691 / FREQUENCY_RATE), + float_to_fp8_24(33.7988653945333 / FREQUENCY_RATE), + float_to_fp8_24(33.8163054695562 / FREQUENCY_RATE), + float_to_fp8_24(33.8337635518844 / FREQUENCY_RATE), + float_to_fp8_24(33.8512396694215 / FREQUENCY_RATE), + float_to_fp8_24(33.8687338501292 / FREQUENCY_RATE), + float_to_fp8_24(33.8862461220269 / FREQUENCY_RATE), + float_to_fp8_24(33.9037765131919 / FREQUENCY_RATE), + float_to_fp8_24(33.9213250517598 / FREQUENCY_RATE), + float_to_fp8_24(33.9388917659244 / FREQUENCY_RATE), + float_to_fp8_24(33.9564766839378 / FREQUENCY_RATE), + float_to_fp8_24(33.9740798341109 / FREQUENCY_RATE), + float_to_fp8_24(33.9917012448133 / FREQUENCY_RATE), + float_to_fp8_24(34.0093409444733 / FREQUENCY_RATE), + float_to_fp8_24(34.0269989615784 / FREQUENCY_RATE), + float_to_fp8_24(34.0446753246753 / FREQUENCY_RATE), + float_to_fp8_24(34.0623700623701 / FREQUENCY_RATE), + float_to_fp8_24(34.0800832033281 / FREQUENCY_RATE), + float_to_fp8_24(34.0978147762747 / FREQUENCY_RATE), + float_to_fp8_24(34.1155648099948 / FREQUENCY_RATE), + float_to_fp8_24(34.1333333333333 / FREQUENCY_RATE), + float_to_fp8_24(34.1511203751954 / FREQUENCY_RATE), + float_to_fp8_24(34.1689259645464 / FREQUENCY_RATE), + float_to_fp8_24(34.1867501304121 / FREQUENCY_RATE), + float_to_fp8_24(34.2045929018789 / FREQUENCY_RATE), + float_to_fp8_24(34.222454308094 / FREQUENCY_RATE), + float_to_fp8_24(34.2403343782654 / FREQUENCY_RATE), + float_to_fp8_24(34.2582331416623 / FREQUENCY_RATE), + float_to_fp8_24(34.2761506276151 / FREQUENCY_RATE), + float_to_fp8_24(34.2940868655154 / FREQUENCY_RATE), + float_to_fp8_24(34.3120418848168 / FREQUENCY_RATE), + float_to_fp8_24(34.330015715034 / FREQUENCY_RATE), + float_to_fp8_24(34.3480083857442 / FREQUENCY_RATE), + float_to_fp8_24(34.3660199265863 / FREQUENCY_RATE), + float_to_fp8_24(34.3840503672613 / FREQUENCY_RATE), + float_to_fp8_24(34.4020997375328 / FREQUENCY_RATE), + float_to_fp8_24(34.4201680672269 / FREQUENCY_RATE), + float_to_fp8_24(34.4382553862323 / FREQUENCY_RATE), + float_to_fp8_24(34.4563617245005 / FREQUENCY_RATE), + float_to_fp8_24(34.4744871120463 / FREQUENCY_RATE), + float_to_fp8_24(34.4926315789474 / FREQUENCY_RATE), + float_to_fp8_24(34.5107951553449 / FREQUENCY_RATE), + float_to_fp8_24(34.5289778714436 / FREQUENCY_RATE), + float_to_fp8_24(34.5471797575119 / FREQUENCY_RATE), + float_to_fp8_24(34.5654008438819 / FREQUENCY_RATE), + float_to_fp8_24(34.5836411609499 / FREQUENCY_RATE), + float_to_fp8_24(34.6019007391763 / FREQUENCY_RATE), + float_to_fp8_24(34.6201796090861 / FREQUENCY_RATE), + float_to_fp8_24(34.6384778012685 / FREQUENCY_RATE), + float_to_fp8_24(34.6567953463776 / FREQUENCY_RATE), + float_to_fp8_24(34.6751322751323 / FREQUENCY_RATE), + float_to_fp8_24(34.6934886183166 / FREQUENCY_RATE), + float_to_fp8_24(34.7118644067797 / FREQUENCY_RATE), + float_to_fp8_24(34.7302596714361 / FREQUENCY_RATE), + float_to_fp8_24(34.7486744432662 / FREQUENCY_RATE), + float_to_fp8_24(34.7671087533156 / FREQUENCY_RATE), + float_to_fp8_24(34.7855626326964 / FREQUENCY_RATE), + float_to_fp8_24(34.8040361125863 / FREQUENCY_RATE), + float_to_fp8_24(34.8225292242295 / FREQUENCY_RATE), + float_to_fp8_24(34.8410419989367 / FREQUENCY_RATE), + float_to_fp8_24(34.8595744680851 / FREQUENCY_RATE), + float_to_fp8_24(34.8781266631187 / FREQUENCY_RATE), + float_to_fp8_24(34.8966986155485 / FREQUENCY_RATE), + float_to_fp8_24(34.9152903569526 / FREQUENCY_RATE), + float_to_fp8_24(34.9339019189765 / FREQUENCY_RATE), + float_to_fp8_24(34.9525333333333 / FREQUENCY_RATE), + float_to_fp8_24(34.9711846318036 / FREQUENCY_RATE), + float_to_fp8_24(34.989855846236 / FREQUENCY_RATE), + float_to_fp8_24(35.008547008547 / FREQUENCY_RATE), + float_to_fp8_24(35.0272581507215 / FREQUENCY_RATE), + float_to_fp8_24(35.0459893048128 / FREQUENCY_RATE), + float_to_fp8_24(35.0647405029427 / FREQUENCY_RATE), + float_to_fp8_24(35.0835117773019 / FREQUENCY_RATE), + float_to_fp8_24(35.10230316015 / FREQUENCY_RATE), + float_to_fp8_24(35.1211146838156 / FREQUENCY_RATE), + float_to_fp8_24(35.1399463806971 / FREQUENCY_RATE), + float_to_fp8_24(35.1587982832618 / FREQUENCY_RATE), + float_to_fp8_24(35.1776704240472 / FREQUENCY_RATE), + float_to_fp8_24(35.1965628356606 / FREQUENCY_RATE), + float_to_fp8_24(35.2154755507792 / FREQUENCY_RATE), + float_to_fp8_24(35.2344086021505 / FREQUENCY_RATE), + float_to_fp8_24(35.2533620225928 / FREQUENCY_RATE), + float_to_fp8_24(35.2723358449946 / FREQUENCY_RATE), + float_to_fp8_24(35.2913301023156 / FREQUENCY_RATE), + float_to_fp8_24(35.3103448275862 / FREQUENCY_RATE), + float_to_fp8_24(35.3293800539084 / FREQUENCY_RATE), + float_to_fp8_24(35.3484358144552 / FREQUENCY_RATE), + float_to_fp8_24(35.3675121424717 / FREQUENCY_RATE), + float_to_fp8_24(35.3866090712743 / FREQUENCY_RATE), + float_to_fp8_24(35.4057266342518 / FREQUENCY_RATE), + float_to_fp8_24(35.4248648648649 / FREQUENCY_RATE), + float_to_fp8_24(35.4440237966468 / FREQUENCY_RATE), + float_to_fp8_24(35.4632034632035 / FREQUENCY_RATE), + float_to_fp8_24(35.4824038982133 / FREQUENCY_RATE), + float_to_fp8_24(35.501625135428 / FREQUENCY_RATE), + float_to_fp8_24(35.5208672086721 / FREQUENCY_RATE), + float_to_fp8_24(35.5401301518438 / FREQUENCY_RATE), + float_to_fp8_24(35.5594139989148 / FREQUENCY_RATE), + float_to_fp8_24(35.5787187839305 / FREQUENCY_RATE), + float_to_fp8_24(35.5980445410103 / FREQUENCY_RATE), + float_to_fp8_24(35.6173913043478 / FREQUENCY_RATE), + float_to_fp8_24(35.636759108211 / FREQUENCY_RATE), + float_to_fp8_24(35.6561479869423 / FREQUENCY_RATE), + float_to_fp8_24(35.6755579749592 / FREQUENCY_RATE), + float_to_fp8_24(35.6949891067538 / FREQUENCY_RATE), + float_to_fp8_24(35.7144414168937 / FREQUENCY_RATE), + float_to_fp8_24(35.7339149400218 / FREQUENCY_RATE), + float_to_fp8_24(35.7534097108565 / FREQUENCY_RATE), + float_to_fp8_24(35.7729257641921 / FREQUENCY_RATE), + float_to_fp8_24(35.792463134899 / FREQUENCY_RATE), + float_to_fp8_24(35.8120218579235 / FREQUENCY_RATE), + float_to_fp8_24(35.8316019682887 / FREQUENCY_RATE), + float_to_fp8_24(35.8512035010941 / FREQUENCY_RATE), + float_to_fp8_24(35.8708264915161 / FREQUENCY_RATE), + float_to_fp8_24(35.8904709748083 / FREQUENCY_RATE), + float_to_fp8_24(35.9101369863014 / FREQUENCY_RATE), + float_to_fp8_24(35.9298245614035 / FREQUENCY_RATE), + float_to_fp8_24(35.9495337356007 / FREQUENCY_RATE), + float_to_fp8_24(35.9692645444566 / FREQUENCY_RATE), + float_to_fp8_24(35.9890170236134 / FREQUENCY_RATE), + float_to_fp8_24(36.0087912087912 / FREQUENCY_RATE), + float_to_fp8_24(36.0285871357889 / FREQUENCY_RATE), + float_to_fp8_24(36.048404840484 / FREQUENCY_RATE), + float_to_fp8_24(36.0682443588332 / FREQUENCY_RATE), + float_to_fp8_24(36.0881057268722 / FREQUENCY_RATE), + float_to_fp8_24(36.1079889807162 / FREQUENCY_RATE), + float_to_fp8_24(36.1278941565601 / FREQUENCY_RATE), + float_to_fp8_24(36.1478212906784 / FREQUENCY_RATE), + float_to_fp8_24(36.167770419426 / FREQUENCY_RATE), + float_to_fp8_24(36.187741579238 / FREQUENCY_RATE), + float_to_fp8_24(36.2077348066298 / FREQUENCY_RATE), + float_to_fp8_24(36.2277501381979 / FREQUENCY_RATE), + float_to_fp8_24(36.2477876106195 / FREQUENCY_RATE), + float_to_fp8_24(36.267847260653 / FREQUENCY_RATE), + float_to_fp8_24(36.2879291251384 / FREQUENCY_RATE), + float_to_fp8_24(36.3080332409972 / FREQUENCY_RATE), + float_to_fp8_24(36.3281596452328 / FREQUENCY_RATE), + float_to_fp8_24(36.3483083749307 / FREQUENCY_RATE), + float_to_fp8_24(36.3684794672586 / FREQUENCY_RATE), + float_to_fp8_24(36.388672959467 / FREQUENCY_RATE), + float_to_fp8_24(36.4088888888889 / FREQUENCY_RATE), + float_to_fp8_24(36.4291272929405 / FREQUENCY_RATE), + float_to_fp8_24(36.4493882091212 / FREQUENCY_RATE), + float_to_fp8_24(36.4696716750139 / FREQUENCY_RATE), + float_to_fp8_24(36.4899777282851 / FREQUENCY_RATE), + float_to_fp8_24(36.5103064066852 / FREQUENCY_RATE), + float_to_fp8_24(36.5306577480491 / FREQUENCY_RATE), + float_to_fp8_24(36.5510317902956 / FREQUENCY_RATE), + float_to_fp8_24(36.5714285714286 / FREQUENCY_RATE), + float_to_fp8_24(36.5918481295366 / FREQUENCY_RATE), + float_to_fp8_24(36.6122905027933 / FREQUENCY_RATE), + float_to_fp8_24(36.6327557294578 / FREQUENCY_RATE), + float_to_fp8_24(36.6532438478747 / FREQUENCY_RATE), + float_to_fp8_24(36.6737548964745 / FREQUENCY_RATE), + float_to_fp8_24(36.6942889137738 / FREQUENCY_RATE), + float_to_fp8_24(36.7148459383753 / FREQUENCY_RATE), + float_to_fp8_24(36.7354260089686 / FREQUENCY_RATE), + float_to_fp8_24(36.7560291643298 / FREQUENCY_RATE), + float_to_fp8_24(36.7766554433221 / FREQUENCY_RATE), + float_to_fp8_24(36.7973048848961 / FREQUENCY_RATE), + float_to_fp8_24(36.8179775280899 / FREQUENCY_RATE), + float_to_fp8_24(36.8386734120292 / FREQUENCY_RATE), + float_to_fp8_24(36.859392575928 / FREQUENCY_RATE), + float_to_fp8_24(36.8801350590884 / FREQUENCY_RATE), + float_to_fp8_24(36.9009009009009 / FREQUENCY_RATE), + float_to_fp8_24(36.9216901408451 / FREQUENCY_RATE), + float_to_fp8_24(36.9425028184893 / FREQUENCY_RATE), + float_to_fp8_24(36.9633389734913 / FREQUENCY_RATE), + float_to_fp8_24(36.9841986455982 / FREQUENCY_RATE), + float_to_fp8_24(37.0050818746471 / FREQUENCY_RATE), + float_to_fp8_24(37.025988700565 / FREQUENCY_RATE), + float_to_fp8_24(37.0469191633691 / FREQUENCY_RATE), + float_to_fp8_24(37.0678733031674 / FREQUENCY_RATE), + float_to_fp8_24(37.0888511601585 / FREQUENCY_RATE), + float_to_fp8_24(37.1098527746319 / FREQUENCY_RATE), + float_to_fp8_24(37.1308781869688 / FREQUENCY_RATE), + float_to_fp8_24(37.1519274376417 / FREQUENCY_RATE), + float_to_fp8_24(37.173000567215 / FREQUENCY_RATE), + float_to_fp8_24(37.1940976163451 / FREQUENCY_RATE), + float_to_fp8_24(37.2152186257808 / FREQUENCY_RATE), + float_to_fp8_24(37.2363636363636 / FREQUENCY_RATE), + float_to_fp8_24(37.2575326890279 / FREQUENCY_RATE), + float_to_fp8_24(37.2787258248009 / FREQUENCY_RATE), + float_to_fp8_24(37.2999430848036 / FREQUENCY_RATE), + float_to_fp8_24(37.3211845102506 / FREQUENCY_RATE), + float_to_fp8_24(37.3424501424501 / FREQUENCY_RATE), + float_to_fp8_24(37.363740022805 / FREQUENCY_RATE), + float_to_fp8_24(37.3850541928123 / FREQUENCY_RATE), + float_to_fp8_24(37.4063926940639 / FREQUENCY_RATE), + float_to_fp8_24(37.4277555682467 / FREQUENCY_RATE), + float_to_fp8_24(37.4491428571429 / FREQUENCY_RATE), + float_to_fp8_24(37.4705546026301 / FREQUENCY_RATE), + float_to_fp8_24(37.4919908466819 / FREQUENCY_RATE), + float_to_fp8_24(37.5134516313681 / FREQUENCY_RATE), + float_to_fp8_24(37.5349369988545 / FREQUENCY_RATE), + float_to_fp8_24(37.556446991404 / FREQUENCY_RATE), + float_to_fp8_24(37.5779816513761 / FREQUENCY_RATE), + float_to_fp8_24(37.5995410212278 / FREQUENCY_RATE), + float_to_fp8_24(37.6211251435132 / FREQUENCY_RATE), + float_to_fp8_24(37.6427340608845 / FREQUENCY_RATE), + float_to_fp8_24(37.664367816092 / FREQUENCY_RATE), + float_to_fp8_24(37.6860264519839 / FREQUENCY_RATE), + float_to_fp8_24(37.7077100115075 / FREQUENCY_RATE), + float_to_fp8_24(37.7294185377087 / FREQUENCY_RATE), + float_to_fp8_24(37.7511520737327 / FREQUENCY_RATE), + float_to_fp8_24(37.7729106628242 / FREQUENCY_RATE), + float_to_fp8_24(37.7946943483276 / FREQUENCY_RATE), + float_to_fp8_24(37.8165031736872 / FREQUENCY_RATE), + float_to_fp8_24(37.838337182448 / FREQUENCY_RATE), + float_to_fp8_24(37.8601964182553 / FREQUENCY_RATE), + float_to_fp8_24(37.8820809248555 / FREQUENCY_RATE), + float_to_fp8_24(37.903990746096 / FREQUENCY_RATE), + float_to_fp8_24(37.9259259259259 / FREQUENCY_RATE), + float_to_fp8_24(37.9478865083961 / FREQUENCY_RATE), + float_to_fp8_24(37.9698725376593 / FREQUENCY_RATE), + float_to_fp8_24(37.991884057971 / FREQUENCY_RATE), + float_to_fp8_24(38.0139211136891 / FREQUENCY_RATE), + float_to_fp8_24(38.0359837492745 / FREQUENCY_RATE), + float_to_fp8_24(38.0580720092915 / FREQUENCY_RATE), + float_to_fp8_24(38.0801859384079 / FREQUENCY_RATE), + float_to_fp8_24(38.1023255813953 / FREQUENCY_RATE), + float_to_fp8_24(38.1244909831297 / FREQUENCY_RATE), + float_to_fp8_24(38.1466821885914 / FREQUENCY_RATE), + float_to_fp8_24(38.1688992428655 / FREQUENCY_RATE), + float_to_fp8_24(38.1911421911422 / FREQUENCY_RATE), + float_to_fp8_24(38.2134110787172 / FREQUENCY_RATE), + float_to_fp8_24(38.2357059509918 / FREQUENCY_RATE), + float_to_fp8_24(38.2580268534734 / FREQUENCY_RATE), + float_to_fp8_24(38.2803738317757 / FREQUENCY_RATE), + float_to_fp8_24(38.3027469316189 / FREQUENCY_RATE), + float_to_fp8_24(38.3251461988304 / FREQUENCY_RATE), + float_to_fp8_24(38.3475716793446 / FREQUENCY_RATE), + float_to_fp8_24(38.3700234192037 / FREQUENCY_RATE), + float_to_fp8_24(38.3925014645577 / FREQUENCY_RATE), + float_to_fp8_24(38.4150058616647 / FREQUENCY_RATE), + float_to_fp8_24(38.4375366568915 / FREQUENCY_RATE), + float_to_fp8_24(38.4600938967136 / FREQUENCY_RATE), + float_to_fp8_24(38.4826776277158 / FREQUENCY_RATE), + float_to_fp8_24(38.5052878965922 / FREQUENCY_RATE), + float_to_fp8_24(38.527924750147 / FREQUENCY_RATE), + float_to_fp8_24(38.5505882352941 / FREQUENCY_RATE), + float_to_fp8_24(38.5732783990583 / FREQUENCY_RATE), + float_to_fp8_24(38.5959952885748 / FREQUENCY_RATE), + float_to_fp8_24(38.6187389510902 / FREQUENCY_RATE), + float_to_fp8_24(38.6415094339623 / FREQUENCY_RATE), + float_to_fp8_24(38.6643067846608 / FREQUENCY_RATE), + float_to_fp8_24(38.6871310507674 / FREQUENCY_RATE), + float_to_fp8_24(38.7099822799764 / FREQUENCY_RATE), + float_to_fp8_24(38.7328605200946 / FREQUENCY_RATE), + float_to_fp8_24(38.755765819042 / FREQUENCY_RATE), + float_to_fp8_24(38.7786982248521 / FREQUENCY_RATE), + float_to_fp8_24(38.801657785672 / FREQUENCY_RATE), + float_to_fp8_24(38.824644549763 / FREQUENCY_RATE), + float_to_fp8_24(38.8476585655009 / FREQUENCY_RATE), + float_to_fp8_24(38.870699881376 / FREQUENCY_RATE), + float_to_fp8_24(38.8937685459941 / FREQUENCY_RATE), + float_to_fp8_24(38.916864608076 / FREQUENCY_RATE), + float_to_fp8_24(38.9399881164587 / FREQUENCY_RATE), + float_to_fp8_24(38.9631391200951 / FREQUENCY_RATE), + float_to_fp8_24(38.9863176680547 / FREQUENCY_RATE), + float_to_fp8_24(39.0095238095238 / FREQUENCY_RATE), + float_to_fp8_24(39.0327575938058 / FREQUENCY_RATE), + float_to_fp8_24(39.0560190703218 / FREQUENCY_RATE), + float_to_fp8_24(39.0793082886106 / FREQUENCY_RATE), + float_to_fp8_24(39.1026252983294 / FREQUENCY_RATE), + float_to_fp8_24(39.1259701492537 / FREQUENCY_RATE), + float_to_fp8_24(39.1493428912784 / FREQUENCY_RATE), + float_to_fp8_24(39.1727435744172 / FREQUENCY_RATE), + float_to_fp8_24(39.1961722488038 / FREQUENCY_RATE), + float_to_fp8_24(39.2196289646918 / FREQUENCY_RATE), + float_to_fp8_24(39.2431137724551 / FREQUENCY_RATE), + float_to_fp8_24(39.2666267225884 / FREQUENCY_RATE), + float_to_fp8_24(39.2901678657074 / FREQUENCY_RATE), + float_to_fp8_24(39.3137372525495 / FREQUENCY_RATE), + float_to_fp8_24(39.3373349339736 / FREQUENCY_RATE), + float_to_fp8_24(39.360960960961 / FREQUENCY_RATE), + float_to_fp8_24(39.3846153846154 / FREQUENCY_RATE), + float_to_fp8_24(39.4082982561636 / FREQUENCY_RATE), + float_to_fp8_24(39.4320096269555 / FREQUENCY_RATE), + float_to_fp8_24(39.4557495484648 / FREQUENCY_RATE), + float_to_fp8_24(39.4795180722892 / FREQUENCY_RATE), + float_to_fp8_24(39.5033152501507 / FREQUENCY_RATE), + float_to_fp8_24(39.5271411338963 / FREQUENCY_RATE), + float_to_fp8_24(39.5509957754979 / FREQUENCY_RATE), + float_to_fp8_24(39.5748792270531 / FREQUENCY_RATE), + float_to_fp8_24(39.5987915407855 / FREQUENCY_RATE), + float_to_fp8_24(39.6227327690447 / FREQUENCY_RATE), + float_to_fp8_24(39.6467029643073 / FREQUENCY_RATE), + float_to_fp8_24(39.6707021791768 / FREQUENCY_RATE), + float_to_fp8_24(39.694730466384 / FREQUENCY_RATE), + float_to_fp8_24(39.7187878787879 / FREQUENCY_RATE), + float_to_fp8_24(39.7428744693754 / FREQUENCY_RATE), + float_to_fp8_24(39.7669902912621 / FREQUENCY_RATE), + float_to_fp8_24(39.7911353976928 / FREQUENCY_RATE), + float_to_fp8_24(39.8153098420413 / FREQUENCY_RATE), + float_to_fp8_24(39.8395136778115 / FREQUENCY_RATE), + float_to_fp8_24(39.8637469586375 / FREQUENCY_RATE), + float_to_fp8_24(39.8880097382836 / FREQUENCY_RATE), + float_to_fp8_24(39.9123020706455 / FREQUENCY_RATE), + float_to_fp8_24(39.9366240097502 / FREQUENCY_RATE), + float_to_fp8_24(39.9609756097561 / FREQUENCY_RATE), + float_to_fp8_24(39.9853569249542 / FREQUENCY_RATE), + float_to_fp8_24(40.009768009768 / FREQUENCY_RATE), + float_to_fp8_24(40.0342089187538 / FREQUENCY_RATE), + float_to_fp8_24(40.0586797066015 / FREQUENCY_RATE), + float_to_fp8_24(40.0831804281346 / FREQUENCY_RATE), + float_to_fp8_24(40.1077111383109 / FREQUENCY_RATE), + float_to_fp8_24(40.1322718922229 / FREQUENCY_RATE), + float_to_fp8_24(40.156862745098 / FREQUENCY_RATE), + float_to_fp8_24(40.1814837522992 / FREQUENCY_RATE), + float_to_fp8_24(40.2061349693252 / FREQUENCY_RATE), + float_to_fp8_24(40.2308164518109 / FREQUENCY_RATE), + float_to_fp8_24(40.2555282555283 / FREQUENCY_RATE), + float_to_fp8_24(40.280270436386 / FREQUENCY_RATE), + float_to_fp8_24(40.3050430504305 / FREQUENCY_RATE), + float_to_fp8_24(40.3298461538462 / FREQUENCY_RATE), + float_to_fp8_24(40.3546798029557 / FREQUENCY_RATE), + float_to_fp8_24(40.3795440542206 / FREQUENCY_RATE), + float_to_fp8_24(40.4044389642417 / FREQUENCY_RATE), + float_to_fp8_24(40.4293645897594 / FREQUENCY_RATE), + float_to_fp8_24(40.4543209876543 / FREQUENCY_RATE), + float_to_fp8_24(40.4793082149475 / FREQUENCY_RATE), + float_to_fp8_24(40.504326328801 / FREQUENCY_RATE), + float_to_fp8_24(40.5293753865182 / FREQUENCY_RATE), + float_to_fp8_24(40.5544554455446 / FREQUENCY_RATE), + float_to_fp8_24(40.5795665634675 / FREQUENCY_RATE), + float_to_fp8_24(40.6047087980174 / FREQUENCY_RATE), + float_to_fp8_24(40.6298822070676 / FREQUENCY_RATE), + float_to_fp8_24(40.6550868486352 / FREQUENCY_RATE), + float_to_fp8_24(40.6803227808814 / FREQUENCY_RATE), + float_to_fp8_24(40.7055900621118 / FREQUENCY_RATE), + float_to_fp8_24(40.7308887507769 / FREQUENCY_RATE), + float_to_fp8_24(40.7562189054726 / FREQUENCY_RATE), + float_to_fp8_24(40.7815805849409 / FREQUENCY_RATE), + float_to_fp8_24(40.8069738480697 / FREQUENCY_RATE), + float_to_fp8_24(40.8323987538941 / FREQUENCY_RATE), + float_to_fp8_24(40.857855361596 / FREQUENCY_RATE), + float_to_fp8_24(40.8833437305053 / FREQUENCY_RATE), + float_to_fp8_24(40.9088639200999 / FREQUENCY_RATE), + float_to_fp8_24(40.9344159900062 / FREQUENCY_RATE), + float_to_fp8_24(40.96 / FREQUENCY_RATE), + float_to_fp8_24(40.9856160100063 / FREQUENCY_RATE), + float_to_fp8_24(41.0112640801001 / FREQUENCY_RATE), + float_to_fp8_24(41.0369442705072 / FREQUENCY_RATE), + float_to_fp8_24(41.062656641604 / FREQUENCY_RATE), + float_to_fp8_24(41.0884012539185 / FREQUENCY_RATE), + float_to_fp8_24(41.1141781681305 / FREQUENCY_RATE), + float_to_fp8_24(41.1399874450722 / FREQUENCY_RATE), + float_to_fp8_24(41.1658291457287 / FREQUENCY_RATE), + float_to_fp8_24(41.1917033312382 / FREQUENCY_RATE), + float_to_fp8_24(41.2176100628931 / FREQUENCY_RATE), + float_to_fp8_24(41.2435494021397 / FREQUENCY_RATE), + float_to_fp8_24(41.2695214105793 / FREQUENCY_RATE), + float_to_fp8_24(41.2955261499685 / FREQUENCY_RATE), + float_to_fp8_24(41.3215636822194 / FREQUENCY_RATE), + float_to_fp8_24(41.3476340694006 / FREQUENCY_RATE), + float_to_fp8_24(41.3737373737374 / FREQUENCY_RATE), + float_to_fp8_24(41.3998736576121 / FREQUENCY_RATE), + float_to_fp8_24(41.4260429835651 / FREQUENCY_RATE), + float_to_fp8_24(41.4522454142948 / FREQUENCY_RATE), + float_to_fp8_24(41.4784810126582 / FREQUENCY_RATE), + float_to_fp8_24(41.504749841672 / FREQUENCY_RATE), + float_to_fp8_24(41.531051964512 / FREQUENCY_RATE), + float_to_fp8_24(41.5573874445149 / FREQUENCY_RATE), + float_to_fp8_24(41.5837563451777 / FREQUENCY_RATE), + float_to_fp8_24(41.6101587301587 / FREQUENCY_RATE), + float_to_fp8_24(41.6365946632783 / FREQUENCY_RATE), + float_to_fp8_24(41.6630642085188 / FREQUENCY_RATE), + float_to_fp8_24(41.6895674300254 / FREQUENCY_RATE), + float_to_fp8_24(41.7161043921069 / FREQUENCY_RATE), + float_to_fp8_24(41.7426751592357 / FREQUENCY_RATE), + float_to_fp8_24(41.7692797960484 / FREQUENCY_RATE), + float_to_fp8_24(41.7959183673469 / FREQUENCY_RATE), + float_to_fp8_24(41.8225909380983 / FREQUENCY_RATE), + float_to_fp8_24(41.8492975734355 / FREQUENCY_RATE), + float_to_fp8_24(41.8760383386582 / FREQUENCY_RATE), + float_to_fp8_24(41.9028132992327 / FREQUENCY_RATE), + float_to_fp8_24(41.9296225207934 / FREQUENCY_RATE), + float_to_fp8_24(41.9564660691421 / FREQUENCY_RATE), + float_to_fp8_24(41.9833440102498 / FREQUENCY_RATE), + float_to_fp8_24(42.0102564102564 / FREQUENCY_RATE), + float_to_fp8_24(42.0372033354715 / FREQUENCY_RATE), + float_to_fp8_24(42.0641848523748 / FREQUENCY_RATE), + float_to_fp8_24(42.0912010276172 / FREQUENCY_RATE), + float_to_fp8_24(42.1182519280206 / FREQUENCY_RATE), + float_to_fp8_24(42.1453376205788 / FREQUENCY_RATE), + float_to_fp8_24(42.1724581724582 / FREQUENCY_RATE), + float_to_fp8_24(42.1996136509981 / FREQUENCY_RATE), + float_to_fp8_24(42.2268041237113 / FREQUENCY_RATE), + float_to_fp8_24(42.254029658285 / FREQUENCY_RATE), + float_to_fp8_24(42.2812903225807 / FREQUENCY_RATE), + float_to_fp8_24(42.3085861846352 / FREQUENCY_RATE), + float_to_fp8_24(42.3359173126615 / FREQUENCY_RATE), + float_to_fp8_24(42.3632837750485 / FREQUENCY_RATE), + float_to_fp8_24(42.3906856403622 / FREQUENCY_RATE), + float_to_fp8_24(42.4181229773463 / FREQUENCY_RATE), + float_to_fp8_24(42.4455958549223 / FREQUENCY_RATE), + float_to_fp8_24(42.4731043421905 / FREQUENCY_RATE), + float_to_fp8_24(42.5006485084306 / FREQUENCY_RATE), + float_to_fp8_24(42.5282284231019 / FREQUENCY_RATE), + float_to_fp8_24(42.5558441558442 / FREQUENCY_RATE), + float_to_fp8_24(42.5834957764782 / FREQUENCY_RATE), + float_to_fp8_24(42.6111833550065 / FREQUENCY_RATE), + float_to_fp8_24(42.6389069616135 / FREQUENCY_RATE), + float_to_fp8_24(42.6666666666667 / FREQUENCY_RATE), + float_to_fp8_24(42.6944625407166 / FREQUENCY_RATE), + float_to_fp8_24(42.722294654498 / FREQUENCY_RATE), + float_to_fp8_24(42.7501630789302 / FREQUENCY_RATE), + float_to_fp8_24(42.7780678851175 / FREQUENCY_RATE), + float_to_fp8_24(42.8060091443501 / FREQUENCY_RATE), + float_to_fp8_24(42.8339869281046 / FREQUENCY_RATE), + float_to_fp8_24(42.8620013080445 / FREQUENCY_RATE), + float_to_fp8_24(42.890052356021 / FREQUENCY_RATE), + float_to_fp8_24(42.9181401440733 / FREQUENCY_RATE), + float_to_fp8_24(42.9462647444299 / FREQUENCY_RATE), + float_to_fp8_24(42.9744262295082 / FREQUENCY_RATE), + float_to_fp8_24(43.002624671916 / FREQUENCY_RATE), + float_to_fp8_24(43.0308601444517 / FREQUENCY_RATE), + float_to_fp8_24(43.0591327201051 / FREQUENCY_RATE), + float_to_fp8_24(43.0874424720579 / FREQUENCY_RATE), + float_to_fp8_24(43.1157894736842 / FREQUENCY_RATE), + float_to_fp8_24(43.1441737985517 / FREQUENCY_RATE), + float_to_fp8_24(43.1725955204216 / FREQUENCY_RATE), + float_to_fp8_24(43.2010547132498 / FREQUENCY_RATE), + float_to_fp8_24(43.2295514511873 / FREQUENCY_RATE), + float_to_fp8_24(43.2580858085809 / FREQUENCY_RATE), + float_to_fp8_24(43.2866578599736 / FREQUENCY_RATE), + float_to_fp8_24(43.3152676801057 / FREQUENCY_RATE), + float_to_fp8_24(43.3439153439153 / FREQUENCY_RATE), + float_to_fp8_24(43.3726009265387 / FREQUENCY_RATE), + float_to_fp8_24(43.4013245033113 / FREQUENCY_RATE), + float_to_fp8_24(43.4300861497681 / FREQUENCY_RATE), + float_to_fp8_24(43.4588859416446 / FREQUENCY_RATE), + float_to_fp8_24(43.4877239548772 / FREQUENCY_RATE), + float_to_fp8_24(43.5166002656043 / FREQUENCY_RATE), + float_to_fp8_24(43.5455149501661 / FREQUENCY_RATE), + float_to_fp8_24(43.5744680851064 / FREQUENCY_RATE), + float_to_fp8_24(43.6034597471723 / FREQUENCY_RATE), + float_to_fp8_24(43.6324900133156 / FREQUENCY_RATE), + float_to_fp8_24(43.6615589606929 / FREQUENCY_RATE), + float_to_fp8_24(43.6906666666667 / FREQUENCY_RATE), + float_to_fp8_24(43.7198132088059 / FREQUENCY_RATE), + float_to_fp8_24(43.7489986648865 / FREQUENCY_RATE), + float_to_fp8_24(43.7782231128925 / FREQUENCY_RATE), + float_to_fp8_24(43.807486631016 / FREQUENCY_RATE), + float_to_fp8_24(43.8367892976589 / FREQUENCY_RATE), + float_to_fp8_24(43.8661311914324 / FREQUENCY_RATE), + float_to_fp8_24(43.8955123911587 / FREQUENCY_RATE), + float_to_fp8_24(43.9249329758713 / FREQUENCY_RATE), + float_to_fp8_24(43.9543930248156 / FREQUENCY_RATE), + float_to_fp8_24(43.9838926174497 / FREQUENCY_RATE), + float_to_fp8_24(44.0134318334453 / FREQUENCY_RATE), + float_to_fp8_24(44.0430107526882 / FREQUENCY_RATE), + float_to_fp8_24(44.0726294552791 / FREQUENCY_RATE), + float_to_fp8_24(44.1022880215343 / FREQUENCY_RATE), + float_to_fp8_24(44.1319865319865 / FREQUENCY_RATE), + float_to_fp8_24(44.1617250673855 / FREQUENCY_RATE), + float_to_fp8_24(44.1915037086986 / FREQUENCY_RATE), + float_to_fp8_24(44.221322537112 / FREQUENCY_RATE), + float_to_fp8_24(44.2511816340311 / FREQUENCY_RATE), + float_to_fp8_24(44.2810810810811 / FREQUENCY_RATE), + float_to_fp8_24(44.3110209601082 / FREQUENCY_RATE), + float_to_fp8_24(44.34100135318 / FREQUENCY_RATE), + float_to_fp8_24(44.3710223425863 / FREQUENCY_RATE), + float_to_fp8_24(44.4010840108401 / FREQUENCY_RATE), + float_to_fp8_24(44.431186440678 / FREQUENCY_RATE), + float_to_fp8_24(44.4613297150611 / FREQUENCY_RATE), + float_to_fp8_24(44.4915139171758 / FREQUENCY_RATE), + float_to_fp8_24(44.5217391304348 / FREQUENCY_RATE), + float_to_fp8_24(44.5520054384772 / FREQUENCY_RATE), + float_to_fp8_24(44.5823129251701 / FREQUENCY_RATE), + float_to_fp8_24(44.6126616746086 / FREQUENCY_RATE), + float_to_fp8_24(44.6430517711172 / FREQUENCY_RATE), + float_to_fp8_24(44.6734832992502 / FREQUENCY_RATE), + float_to_fp8_24(44.7039563437926 / FREQUENCY_RATE), + float_to_fp8_24(44.7344709897611 / FREQUENCY_RATE), + float_to_fp8_24(44.7650273224044 / FREQUENCY_RATE), + float_to_fp8_24(44.7956254272044 / FREQUENCY_RATE), + float_to_fp8_24(44.8262653898769 / FREQUENCY_RATE), + float_to_fp8_24(44.8569472963724 / FREQUENCY_RATE), + float_to_fp8_24(44.8876712328767 / FREQUENCY_RATE), + float_to_fp8_24(44.9184372858122 / FREQUENCY_RATE), + float_to_fp8_24(44.9492455418381 / FREQUENCY_RATE), + float_to_fp8_24(44.9800960878518 / FREQUENCY_RATE), + float_to_fp8_24(45.010989010989 / FREQUENCY_RATE), + float_to_fp8_24(45.0419243986254 / FREQUENCY_RATE), + float_to_fp8_24(45.0729023383769 / FREQUENCY_RATE), + float_to_fp8_24(45.1039229181005 / FREQUENCY_RATE), + float_to_fp8_24(45.1349862258953 / FREQUENCY_RATE), + float_to_fp8_24(45.1660923501034 / FREQUENCY_RATE), + float_to_fp8_24(45.1972413793103 / FREQUENCY_RATE), + float_to_fp8_24(45.2284334023465 / FREQUENCY_RATE), + float_to_fp8_24(45.2596685082873 / FREQUENCY_RATE), + float_to_fp8_24(45.2909467864547 / FREQUENCY_RATE), + float_to_fp8_24(45.3222683264177 / FREQUENCY_RATE), + float_to_fp8_24(45.3536332179931 / FREQUENCY_RATE), + float_to_fp8_24(45.3850415512465 / FREQUENCY_RATE), + float_to_fp8_24(45.4164934164934 / FREQUENCY_RATE), + float_to_fp8_24(45.4479889042996 / FREQUENCY_RATE), + float_to_fp8_24(45.4795281054823 / FREQUENCY_RATE), + float_to_fp8_24(45.5111111111111 / FREQUENCY_RATE), + float_to_fp8_24(45.5427380125087 / FREQUENCY_RATE), + float_to_fp8_24(45.5744089012517 / FREQUENCY_RATE), + float_to_fp8_24(45.6061238691719 / FREQUENCY_RATE), + float_to_fp8_24(45.6378830083566 / FREQUENCY_RATE), + float_to_fp8_24(45.6696864111498 / FREQUENCY_RATE), + float_to_fp8_24(45.7015341701534 / FREQUENCY_RATE), + float_to_fp8_24(45.7334263782275 / FREQUENCY_RATE), + float_to_fp8_24(45.7653631284916 / FREQUENCY_RATE), + float_to_fp8_24(45.7973445143256 / FREQUENCY_RATE), + float_to_fp8_24(45.8293706293706 / FREQUENCY_RATE), + float_to_fp8_24(45.8614415675297 / FREQUENCY_RATE), + float_to_fp8_24(45.8935574229692 / FREQUENCY_RATE), + float_to_fp8_24(45.9257182901191 / FREQUENCY_RATE), + float_to_fp8_24(45.9579242636746 / FREQUENCY_RATE), + float_to_fp8_24(45.9901754385965 / FREQUENCY_RATE), + float_to_fp8_24(46.0224719101124 / FREQUENCY_RATE), + float_to_fp8_24(46.0548137737175 / FREQUENCY_RATE), + float_to_fp8_24(46.0872011251758 / FREQUENCY_RATE), + float_to_fp8_24(46.1196340605208 / FREQUENCY_RATE), + float_to_fp8_24(46.1521126760563 / FREQUENCY_RATE), + float_to_fp8_24(46.184637068358 / FREQUENCY_RATE), + float_to_fp8_24(46.2172073342736 / FREQUENCY_RATE), + float_to_fp8_24(46.2498235709245 / FREQUENCY_RATE), + float_to_fp8_24(46.2824858757062 / FREQUENCY_RATE), + float_to_fp8_24(46.3151943462898 / FREQUENCY_RATE), + float_to_fp8_24(46.3479490806223 / FREQUENCY_RATE), + float_to_fp8_24(46.3807501769285 / FREQUENCY_RATE), + float_to_fp8_24(46.4135977337111 / FREQUENCY_RATE), + float_to_fp8_24(46.446491849752 / FREQUENCY_RATE), + float_to_fp8_24(46.4794326241135 / FREQUENCY_RATE), + float_to_fp8_24(46.5124201561391 / FREQUENCY_RATE), + float_to_fp8_24(46.5454545454545 / FREQUENCY_RATE), + float_to_fp8_24(46.5785358919687 / FREQUENCY_RATE), + float_to_fp8_24(46.6116642958748 / FREQUENCY_RATE), + float_to_fp8_24(46.6448398576513 / FREQUENCY_RATE), + float_to_fp8_24(46.6780626780627 / FREQUENCY_RATE), + float_to_fp8_24(46.7113328581611 / FREQUENCY_RATE), + float_to_fp8_24(46.7446504992867 / FREQUENCY_RATE), + float_to_fp8_24(46.7780157030692 / FREQUENCY_RATE), + float_to_fp8_24(46.8114285714286 / FREQUENCY_RATE), + float_to_fp8_24(46.8448892065761 / FREQUENCY_RATE), + float_to_fp8_24(46.8783977110157 / FREQUENCY_RATE), + float_to_fp8_24(46.9119541875447 / FREQUENCY_RATE), + float_to_fp8_24(46.945558739255 / FREQUENCY_RATE), + float_to_fp8_24(46.9792114695341 / FREQUENCY_RATE), + float_to_fp8_24(47.012912482066 / FREQUENCY_RATE), + float_to_fp8_24(47.0466618808327 / FREQUENCY_RATE), + float_to_fp8_24(47.0804597701149 / FREQUENCY_RATE), + float_to_fp8_24(47.1143062544932 / FREQUENCY_RATE), + float_to_fp8_24(47.1482014388489 / FREQUENCY_RATE), + float_to_fp8_24(47.1821454283657 / FREQUENCY_RATE), + float_to_fp8_24(47.2161383285303 / FREQUENCY_RATE), + float_to_fp8_24(47.2501802451334 / FREQUENCY_RATE), + float_to_fp8_24(47.2842712842713 / FREQUENCY_RATE), + float_to_fp8_24(47.3184115523466 / FREQUENCY_RATE), + float_to_fp8_24(47.3526011560694 / FREQUENCY_RATE), + float_to_fp8_24(47.3868402024584 / FREQUENCY_RATE), + float_to_fp8_24(47.4211287988423 / FREQUENCY_RATE), + float_to_fp8_24(47.4554670528602 / FREQUENCY_RATE), + float_to_fp8_24(47.4898550724638 / FREQUENCY_RATE), + float_to_fp8_24(47.5242929659173 / FREQUENCY_RATE), + float_to_fp8_24(47.5587808417997 / FREQUENCY_RATE), + float_to_fp8_24(47.5933188090051 / FREQUENCY_RATE), + float_to_fp8_24(47.6279069767442 / FREQUENCY_RATE), + float_to_fp8_24(47.6625454545455 / FREQUENCY_RATE), + float_to_fp8_24(47.6972343522562 / FREQUENCY_RATE), + float_to_fp8_24(47.7319737800437 / FREQUENCY_RATE), + float_to_fp8_24(47.7667638483965 / FREQUENCY_RATE), + float_to_fp8_24(47.8016046681255 / FREQUENCY_RATE), + float_to_fp8_24(47.836496350365 / FREQUENCY_RATE), + float_to_fp8_24(47.8714390065741 / FREQUENCY_RATE), + float_to_fp8_24(47.906432748538 / FREQUENCY_RATE), + float_to_fp8_24(47.9414776883687 / FREQUENCY_RATE), + float_to_fp8_24(47.9765739385066 / FREQUENCY_RATE), + float_to_fp8_24(48.0117216117216 / FREQUENCY_RATE), + float_to_fp8_24(48.0469208211144 / FREQUENCY_RATE), + float_to_fp8_24(48.0821716801174 / FREQUENCY_RATE), + float_to_fp8_24(48.1174743024963 / FREQUENCY_RATE), + float_to_fp8_24(48.1528288023512 / FREQUENCY_RATE), + float_to_fp8_24(48.1882352941176 / FREQUENCY_RATE), + float_to_fp8_24(48.2236938925681 / FREQUENCY_RATE), + float_to_fp8_24(48.259204712813 / FREQUENCY_RATE), + float_to_fp8_24(48.2947678703021 / FREQUENCY_RATE), + float_to_fp8_24(48.330383480826 / FREQUENCY_RATE), + float_to_fp8_24(48.3660516605166 / FREQUENCY_RATE), + float_to_fp8_24(48.4017725258493 / FREQUENCY_RATE), + float_to_fp8_24(48.4375461936438 / FREQUENCY_RATE), + float_to_fp8_24(48.4733727810651 / FREQUENCY_RATE), + float_to_fp8_24(48.5092524056255 / FREQUENCY_RATE), + float_to_fp8_24(48.5451851851852 / FREQUENCY_RATE), + float_to_fp8_24(48.581171237954 / FREQUENCY_RATE), + float_to_fp8_24(48.6172106824926 / FREQUENCY_RATE), + float_to_fp8_24(48.6533036377134 / FREQUENCY_RATE), + float_to_fp8_24(48.6894502228826 / FREQUENCY_RATE), + float_to_fp8_24(48.7256505576208 / FREQUENCY_RATE), + float_to_fp8_24(48.7619047619048 / FREQUENCY_RATE), + float_to_fp8_24(48.7982129560685 / FREQUENCY_RATE), + float_to_fp8_24(48.8345752608048 / FREQUENCY_RATE), + float_to_fp8_24(48.8709917971663 / FREQUENCY_RATE), + float_to_fp8_24(48.9074626865672 / FREQUENCY_RATE), + float_to_fp8_24(48.9439880507842 / FREQUENCY_RATE), + float_to_fp8_24(48.9805680119582 / FREQUENCY_RATE), + float_to_fp8_24(49.0172026925954 / FREQUENCY_RATE), + float_to_fp8_24(49.0538922155689 / FREQUENCY_RATE), + float_to_fp8_24(49.0906367041199 / FREQUENCY_RATE), + float_to_fp8_24(49.1274362818591 / FREQUENCY_RATE), + float_to_fp8_24(49.1642910727682 / FREQUENCY_RATE), + float_to_fp8_24(49.2012012012012 / FREQUENCY_RATE), + float_to_fp8_24(49.2381667918858 / FREQUENCY_RATE), + float_to_fp8_24(49.2751879699248 / FREQUENCY_RATE), + float_to_fp8_24(49.3122648607976 / FREQUENCY_RATE), + float_to_fp8_24(49.3493975903615 / FREQUENCY_RATE), + float_to_fp8_24(49.3865862848531 / FREQUENCY_RATE), + float_to_fp8_24(49.4238310708899 / FREQUENCY_RATE), + float_to_fp8_24(49.4611320754717 / FREQUENCY_RATE), + float_to_fp8_24(49.4984894259819 / FREQUENCY_RATE), + float_to_fp8_24(49.535903250189 / FREQUENCY_RATE), + float_to_fp8_24(49.5733736762481 / FREQUENCY_RATE), + float_to_fp8_24(49.6109008327025 / FREQUENCY_RATE), + float_to_fp8_24(49.6484848484849 / FREQUENCY_RATE), + float_to_fp8_24(49.6861258529189 / FREQUENCY_RATE), + float_to_fp8_24(49.7238239757208 / FREQUENCY_RATE), + float_to_fp8_24(49.7615793470008 / FREQUENCY_RATE), + float_to_fp8_24(49.7993920972644 / FREQUENCY_RATE), + float_to_fp8_24(49.8372623574145 / FREQUENCY_RATE), + float_to_fp8_24(49.8751902587519 / FREQUENCY_RATE), + float_to_fp8_24(49.9131759329779 / FREQUENCY_RATE), + float_to_fp8_24(49.9512195121951 / FREQUENCY_RATE), + float_to_fp8_24(49.9893211289092 / FREQUENCY_RATE), + float_to_fp8_24(50.0274809160305 / FREQUENCY_RATE), + float_to_fp8_24(50.0656990068755 / FREQUENCY_RATE), + float_to_fp8_24(50.1039755351682 / FREQUENCY_RATE), + float_to_fp8_24(50.1423106350421 / FREQUENCY_RATE), + float_to_fp8_24(50.1807044410413 / FREQUENCY_RATE), + float_to_fp8_24(50.2191570881226 / FREQUENCY_RATE), + float_to_fp8_24(50.2576687116564 / FREQUENCY_RATE), + float_to_fp8_24(50.296239447429 / FREQUENCY_RATE), + float_to_fp8_24(50.3348694316436 / FREQUENCY_RATE), + float_to_fp8_24(50.3735588009224 / FREQUENCY_RATE), + float_to_fp8_24(50.4123076923077 / FREQUENCY_RATE), + float_to_fp8_24(50.451116243264 / FREQUENCY_RATE), + float_to_fp8_24(50.4899845916795 / FREQUENCY_RATE), + float_to_fp8_24(50.5289128758674 / FREQUENCY_RATE), + float_to_fp8_24(50.5679012345679 / FREQUENCY_RATE), + float_to_fp8_24(50.6069498069498 / FREQUENCY_RATE), + float_to_fp8_24(50.6460587326121 / FREQUENCY_RATE), + float_to_fp8_24(50.6852281515855 / FREQUENCY_RATE), + float_to_fp8_24(50.7244582043344 / FREQUENCY_RATE), + float_to_fp8_24(50.7637490317583 / FREQUENCY_RATE), + float_to_fp8_24(50.8031007751938 / FREQUENCY_RATE), + float_to_fp8_24(50.8425135764158 / FREQUENCY_RATE), + float_to_fp8_24(50.8819875776397 / FREQUENCY_RATE), + float_to_fp8_24(50.9215229215229 / FREQUENCY_RATE), + float_to_fp8_24(50.9611197511664 / FREQUENCY_RATE), + float_to_fp8_24(51.0007782101167 / FREQUENCY_RATE), + float_to_fp8_24(51.0404984423676 / FREQUENCY_RATE), + float_to_fp8_24(51.0802805923617 / FREQUENCY_RATE), + float_to_fp8_24(51.1201248049922 / FREQUENCY_RATE), + float_to_fp8_24(51.160031225605 / FREQUENCY_RATE), + float_to_fp8_24(51.2 / FREQUENCY_RATE), + float_to_fp8_24(51.2400312744331 / FREQUENCY_RATE), + float_to_fp8_24(51.2801251956182 / FREQUENCY_RATE), + float_to_fp8_24(51.3202819107283 / FREQUENCY_RATE), + float_to_fp8_24(51.3605015673981 / FREQUENCY_RATE), + float_to_fp8_24(51.4007843137255 / FREQUENCY_RATE), + float_to_fp8_24(51.4411302982732 / FREQUENCY_RATE), + float_to_fp8_24(51.4815396700707 / FREQUENCY_RATE), + float_to_fp8_24(51.5220125786164 / FREQUENCY_RATE), + float_to_fp8_24(51.5625491738788 / FREQUENCY_RATE), + float_to_fp8_24(51.6031496062992 / FREQUENCY_RATE), + float_to_fp8_24(51.6438140267928 / FREQUENCY_RATE), + float_to_fp8_24(51.6845425867508 / FREQUENCY_RATE), + float_to_fp8_24(51.7253354380426 / FREQUENCY_RATE), + float_to_fp8_24(51.7661927330174 / FREQUENCY_RATE), + float_to_fp8_24(51.8071146245059 / FREQUENCY_RATE), + float_to_fp8_24(51.8481012658228 / FREQUENCY_RATE), + float_to_fp8_24(51.889152810768 / FREQUENCY_RATE), + float_to_fp8_24(51.9302694136292 / FREQUENCY_RATE), + float_to_fp8_24(51.9714512291832 / FREQUENCY_RATE), + float_to_fp8_24(52.0126984126984 / FREQUENCY_RATE), + float_to_fp8_24(52.0540111199365 / FREQUENCY_RATE), + float_to_fp8_24(52.0953895071542 / FREQUENCY_RATE), + float_to_fp8_24(52.1368337311058 / FREQUENCY_RATE), + float_to_fp8_24(52.1783439490446 / FREQUENCY_RATE), + float_to_fp8_24(52.2199203187251 / FREQUENCY_RATE), + float_to_fp8_24(52.2615629984051 / FREQUENCY_RATE), + float_to_fp8_24(52.3032721468476 / FREQUENCY_RATE), + float_to_fp8_24(52.3450479233227 / FREQUENCY_RATE), + float_to_fp8_24(52.3868904876099 / FREQUENCY_RATE), + float_to_fp8_24(52.4288 / FREQUENCY_RATE), + float_to_fp8_24(52.470776621297 / FREQUENCY_RATE), + float_to_fp8_24(52.5128205128205 / FREQUENCY_RATE), + float_to_fp8_24(52.5549318364074 / FREQUENCY_RATE), + float_to_fp8_24(52.5971107544141 / FREQUENCY_RATE), + float_to_fp8_24(52.6393574297189 / FREQUENCY_RATE), + float_to_fp8_24(52.6816720257235 / FREQUENCY_RATE), + float_to_fp8_24(52.7240547063556 / FREQUENCY_RATE), + float_to_fp8_24(52.7665056360709 / FREQUENCY_RATE), + float_to_fp8_24(52.809024979855 / FREQUENCY_RATE), + float_to_fp8_24(52.8516129032258 / FREQUENCY_RATE), + float_to_fp8_24(52.8942695722357 / FREQUENCY_RATE), + float_to_fp8_24(52.9369951534734 / FREQUENCY_RATE), + float_to_fp8_24(52.9797898140663 / FREQUENCY_RATE), + float_to_fp8_24(53.0226537216829 / FREQUENCY_RATE), + float_to_fp8_24(53.0655870445344 / FREQUENCY_RATE), + float_to_fp8_24(53.1085899513776 / FREQUENCY_RATE), + float_to_fp8_24(53.1516626115166 / FREQUENCY_RATE), + float_to_fp8_24(53.1948051948052 / FREQUENCY_RATE), + float_to_fp8_24(53.2380178716491 / FREQUENCY_RATE), + float_to_fp8_24(53.2813008130081 / FREQUENCY_RATE), + float_to_fp8_24(53.3246541903987 / FREQUENCY_RATE), + float_to_fp8_24(53.3680781758958 / FREQUENCY_RATE), + float_to_fp8_24(53.4115729421353 / FREQUENCY_RATE), + float_to_fp8_24(53.4551386623165 / FREQUENCY_RATE), + float_to_fp8_24(53.4987755102041 / FREQUENCY_RATE), + float_to_fp8_24(53.5424836601307 / FREQUENCY_RATE), + float_to_fp8_24(53.5862632869992 / FREQUENCY_RATE), + float_to_fp8_24(53.6301145662848 / FREQUENCY_RATE), + float_to_fp8_24(53.6740376740377 / FREQUENCY_RATE), + float_to_fp8_24(53.7180327868852 / FREQUENCY_RATE), + float_to_fp8_24(53.7621000820345 / FREQUENCY_RATE), + float_to_fp8_24(53.8062397372742 / FREQUENCY_RATE), + float_to_fp8_24(53.8504519309778 / FREQUENCY_RATE), + float_to_fp8_24(53.8947368421053 / FREQUENCY_RATE), + float_to_fp8_24(53.9390946502058 / FREQUENCY_RATE), + float_to_fp8_24(53.9835255354201 / FREQUENCY_RATE), + float_to_fp8_24(54.0280296784831 / FREQUENCY_RATE), + float_to_fp8_24(54.0726072607261 / FREQUENCY_RATE), + float_to_fp8_24(54.1172584640793 / FREQUENCY_RATE), + float_to_fp8_24(54.1619834710744 / FREQUENCY_RATE), + float_to_fp8_24(54.206782464847 / FREQUENCY_RATE), + float_to_fp8_24(54.2516556291391 / FREQUENCY_RATE), + float_to_fp8_24(54.2966031483016 / FREQUENCY_RATE), + float_to_fp8_24(54.3416252072969 / FREQUENCY_RATE), + float_to_fp8_24(54.3867219917012 / FREQUENCY_RATE), + float_to_fp8_24(54.4318936877076 / FREQUENCY_RATE), + float_to_fp8_24(54.477140482128 / FREQUENCY_RATE), + float_to_fp8_24(54.522462562396 / FREQUENCY_RATE), + float_to_fp8_24(54.5678601165695 / FREQUENCY_RATE), + float_to_fp8_24(54.6133333333333 / FREQUENCY_RATE), + float_to_fp8_24(54.6588824020017 / FREQUENCY_RATE), + float_to_fp8_24(54.7045075125209 / FREQUENCY_RATE), + float_to_fp8_24(54.750208855472 / FREQUENCY_RATE), + float_to_fp8_24(54.7959866220736 / FREQUENCY_RATE), + float_to_fp8_24(54.8418410041841 / FREQUENCY_RATE), + float_to_fp8_24(54.8877721943049 / FREQUENCY_RATE), + float_to_fp8_24(54.9337803855826 / FREQUENCY_RATE), + float_to_fp8_24(54.9798657718121 / FREQUENCY_RATE), + float_to_fp8_24(55.0260285474391 / FREQUENCY_RATE), + float_to_fp8_24(55.072268907563 / FREQUENCY_RATE), + float_to_fp8_24(55.1185870479394 / FREQUENCY_RATE), + float_to_fp8_24(55.1649831649832 / FREQUENCY_RATE), + float_to_fp8_24(55.2114574557709 / FREQUENCY_RATE), + float_to_fp8_24(55.2580101180438 / FREQUENCY_RATE), + float_to_fp8_24(55.304641350211 / FREQUENCY_RATE), + float_to_fp8_24(55.3513513513514 / FREQUENCY_RATE), + float_to_fp8_24(55.3981403212172 / FREQUENCY_RATE), + float_to_fp8_24(55.4450084602369 / FREQUENCY_RATE), + float_to_fp8_24(55.4919559695174 / FREQUENCY_RATE), + float_to_fp8_24(55.5389830508475 / FREQUENCY_RATE), + float_to_fp8_24(55.5860899067006 / FREQUENCY_RATE), + float_to_fp8_24(55.6332767402377 / FREQUENCY_RATE), + float_to_fp8_24(55.6805437553101 / FREQUENCY_RATE), + float_to_fp8_24(55.7278911564626 / FREQUENCY_RATE), + float_to_fp8_24(55.7753191489362 / FREQUENCY_RATE), + float_to_fp8_24(55.8228279386712 / FREQUENCY_RATE), + float_to_fp8_24(55.8704177323103 / FREQUENCY_RATE), + float_to_fp8_24(55.9180887372014 / FREQUENCY_RATE), + float_to_fp8_24(55.9658411614005 / FREQUENCY_RATE), + float_to_fp8_24(56.0136752136752 / FREQUENCY_RATE), + float_to_fp8_24(56.0615911035073 / FREQUENCY_RATE), + float_to_fp8_24(56.1095890410959 / FREQUENCY_RATE), + float_to_fp8_24(56.1576692373608 / FREQUENCY_RATE), + float_to_fp8_24(56.2058319039451 / FREQUENCY_RATE), + float_to_fp8_24(56.2540772532189 / FREQUENCY_RATE), + float_to_fp8_24(56.3024054982818 / FREQUENCY_RATE), + float_to_fp8_24(56.3508168529665 / FREQUENCY_RATE), + float_to_fp8_24(56.3993115318417 / FREQUENCY_RATE), + float_to_fp8_24(56.4478897502153 / FREQUENCY_RATE), + float_to_fp8_24(56.4965517241379 / FREQUENCY_RATE), + float_to_fp8_24(56.5452976704055 / FREQUENCY_RATE), + float_to_fp8_24(56.594127806563 / FREQUENCY_RATE), + float_to_fp8_24(56.6430423509075 / FREQUENCY_RATE), + float_to_fp8_24(56.6920415224914 / FREQUENCY_RATE), + float_to_fp8_24(56.7411255411255 / FREQUENCY_RATE), + float_to_fp8_24(56.790294627383 / FREQUENCY_RATE), + float_to_fp8_24(56.8395490026019 / FREQUENCY_RATE), + float_to_fp8_24(56.8888888888889 / FREQUENCY_RATE), + float_to_fp8_24(56.9383145091225 / FREQUENCY_RATE), + float_to_fp8_24(56.9878260869565 / FREQUENCY_RATE), + float_to_fp8_24(57.0374238468233 / FREQUENCY_RATE), + float_to_fp8_24(57.0871080139373 / FREQUENCY_RATE), + float_to_fp8_24(57.1368788142982 / FREQUENCY_RATE), + float_to_fp8_24(57.1867364746946 / FREQUENCY_RATE), + float_to_fp8_24(57.2366812227074 / FREQUENCY_RATE), + float_to_fp8_24(57.2867132867133 / FREQUENCY_RATE), + float_to_fp8_24(57.336832895888 / FREQUENCY_RATE), + float_to_fp8_24(57.3870402802102 / FREQUENCY_RATE), + float_to_fp8_24(57.4373356704645 / FREQUENCY_RATE), + float_to_fp8_24(57.4877192982456 / FREQUENCY_RATE), + float_to_fp8_24(57.5381913959614 / FREQUENCY_RATE), + float_to_fp8_24(57.5887521968366 / FREQUENCY_RATE), + float_to_fp8_24(57.6394019349165 / FREQUENCY_RATE), + float_to_fp8_24(57.6901408450704 / FREQUENCY_RATE), + float_to_fp8_24(57.7409691629956 / FREQUENCY_RATE), + float_to_fp8_24(57.7918871252205 / FREQUENCY_RATE), + float_to_fp8_24(57.8428949691086 / FREQUENCY_RATE), + float_to_fp8_24(57.8939929328622 / FREQUENCY_RATE), + float_to_fp8_24(57.9451812555261 / FREQUENCY_RATE), + float_to_fp8_24(57.9964601769912 / FREQUENCY_RATE), + float_to_fp8_24(58.0478299379982 / FREQUENCY_RATE), + float_to_fp8_24(58.0992907801418 / FREQUENCY_RATE), + float_to_fp8_24(58.150842945874 / FREQUENCY_RATE), + float_to_fp8_24(58.202486678508 / FREQUENCY_RATE), + float_to_fp8_24(58.2542222222222 / FREQUENCY_RATE), + float_to_fp8_24(58.3060498220641 / FREQUENCY_RATE), + float_to_fp8_24(58.3579697239537 / FREQUENCY_RATE), + float_to_fp8_24(58.4099821746881 / FREQUENCY_RATE), + float_to_fp8_24(58.4620874219447 / FREQUENCY_RATE), + float_to_fp8_24(58.5142857142857 / FREQUENCY_RATE), + float_to_fp8_24(58.5665773011618 / FREQUENCY_RATE), + float_to_fp8_24(58.6189624329159 / FREQUENCY_RATE), + float_to_fp8_24(58.6714413607878 / FREQUENCY_RATE), + float_to_fp8_24(58.7240143369176 / FREQUENCY_RATE), + float_to_fp8_24(58.7766816143498 / FREQUENCY_RATE), + float_to_fp8_24(58.8294434470377 / FREQUENCY_RATE), + float_to_fp8_24(58.8823000898473 / FREQUENCY_RATE), + float_to_fp8_24(58.9352517985612 / FREQUENCY_RATE), + float_to_fp8_24(58.988298829883 / FREQUENCY_RATE), + float_to_fp8_24(59.0414414414414 / FREQUENCY_RATE), + float_to_fp8_24(59.0946798917944 / FREQUENCY_RATE), + float_to_fp8_24(59.1480144404332 / FREQUENCY_RATE), + float_to_fp8_24(59.2014453477868 / FREQUENCY_RATE), + float_to_fp8_24(59.254972875226 / FREQUENCY_RATE), + float_to_fp8_24(59.3085972850679 / FREQUENCY_RATE), + float_to_fp8_24(59.3623188405797 / FREQUENCY_RATE), + float_to_fp8_24(59.4161378059837 / FREQUENCY_RATE), + float_to_fp8_24(59.470054446461 / FREQUENCY_RATE), + float_to_fp8_24(59.5240690281562 / FREQUENCY_RATE), + float_to_fp8_24(59.5781818181818 / FREQUENCY_RATE), + float_to_fp8_24(59.6323930846224 / FREQUENCY_RATE), + float_to_fp8_24(59.6867030965392 / FREQUENCY_RATE), + float_to_fp8_24(59.7411121239745 / FREQUENCY_RATE), + float_to_fp8_24(59.7956204379562 / FREQUENCY_RATE), + float_to_fp8_24(59.8502283105023 / FREQUENCY_RATE), + float_to_fp8_24(59.9049360146252 / FREQUENCY_RATE), + float_to_fp8_24(59.9597438243367 / FREQUENCY_RATE), + float_to_fp8_24(60.014652014652 / FREQUENCY_RATE), + float_to_fp8_24(60.0696608615949 / FREQUENCY_RATE), + float_to_fp8_24(60.1247706422018 / FREQUENCY_RATE), + float_to_fp8_24(60.1799816345271 / FREQUENCY_RATE), + float_to_fp8_24(60.2352941176471 / FREQUENCY_RATE), + float_to_fp8_24(60.2907083716651 / FREQUENCY_RATE), + float_to_fp8_24(60.3462246777164 / FREQUENCY_RATE), + float_to_fp8_24(60.4018433179724 / FREQUENCY_RATE), + float_to_fp8_24(60.4575645756458 / FREQUENCY_RATE), + float_to_fp8_24(60.5133887349954 / FREQUENCY_RATE), + float_to_fp8_24(60.5693160813309 / FREQUENCY_RATE), + float_to_fp8_24(60.6253469010176 / FREQUENCY_RATE), + float_to_fp8_24(60.6814814814815 / FREQUENCY_RATE), + float_to_fp8_24(60.7377201112141 / FREQUENCY_RATE), + float_to_fp8_24(60.7940630797774 / FREQUENCY_RATE), + float_to_fp8_24(60.8505106778087 / FREQUENCY_RATE), + float_to_fp8_24(60.907063197026 / FREQUENCY_RATE), + float_to_fp8_24(60.9637209302326 / FREQUENCY_RATE), + float_to_fp8_24(61.0204841713222 / FREQUENCY_RATE), + float_to_fp8_24(61.0773532152843 / FREQUENCY_RATE), + float_to_fp8_24(61.134328358209 / FREQUENCY_RATE), + float_to_fp8_24(61.1914098972923 / FREQUENCY_RATE), + float_to_fp8_24(61.2485981308411 / FREQUENCY_RATE), + float_to_fp8_24(61.3058933582788 / FREQUENCY_RATE), + float_to_fp8_24(61.3632958801498 / FREQUENCY_RATE), + float_to_fp8_24(61.4208059981256 / FREQUENCY_RATE), + float_to_fp8_24(61.4784240150094 / FREQUENCY_RATE), + float_to_fp8_24(61.5361502347418 / FREQUENCY_RATE), + float_to_fp8_24(61.593984962406 / FREQUENCY_RATE), + float_to_fp8_24(61.6519285042333 / FREQUENCY_RATE), + float_to_fp8_24(61.7099811676083 / FREQUENCY_RATE), + float_to_fp8_24(61.7681432610745 / FREQUENCY_RATE), + float_to_fp8_24(61.8264150943396 / FREQUENCY_RATE), + float_to_fp8_24(61.8847969782814 / FREQUENCY_RATE), + float_to_fp8_24(61.9432892249527 / FREQUENCY_RATE), + float_to_fp8_24(62.0018921475875 / FREQUENCY_RATE), + float_to_fp8_24(62.0606060606061 / FREQUENCY_RATE), + float_to_fp8_24(62.1194312796209 / FREQUENCY_RATE), + float_to_fp8_24(62.1783681214421 / FREQUENCY_RATE), + float_to_fp8_24(62.2374169040836 / FREQUENCY_RATE), + float_to_fp8_24(62.2965779467681 / FREQUENCY_RATE), + float_to_fp8_24(62.3558515699334 / FREQUENCY_RATE), + float_to_fp8_24(62.4152380952381 / FREQUENCY_RATE), + float_to_fp8_24(62.4747378455672 / FREQUENCY_RATE), + float_to_fp8_24(62.5343511450382 / FREQUENCY_RATE), + float_to_fp8_24(62.5940783190067 / FREQUENCY_RATE), + float_to_fp8_24(62.6539196940727 / FREQUENCY_RATE), + float_to_fp8_24(62.7138755980861 / FREQUENCY_RATE), + float_to_fp8_24(62.7739463601533 / FREQUENCY_RATE), + float_to_fp8_24(62.8341323106424 / FREQUENCY_RATE), + float_to_fp8_24(62.89443378119 / FREQUENCY_RATE), + float_to_fp8_24(62.954851104707 / FREQUENCY_RATE), + float_to_fp8_24(63.0153846153846 / FREQUENCY_RATE), + float_to_fp8_24(63.0760346487007 / FREQUENCY_RATE), + float_to_fp8_24(63.1368015414258 / FREQUENCY_RATE), + float_to_fp8_24(63.1976856316297 / FREQUENCY_RATE), + float_to_fp8_24(63.2586872586873 / FREQUENCY_RATE), + float_to_fp8_24(63.319806763285 / FREQUENCY_RATE), + float_to_fp8_24(63.3810444874275 / FREQUENCY_RATE), + float_to_fp8_24(63.4424007744434 / FREQUENCY_RATE), + float_to_fp8_24(63.5038759689923 / FREQUENCY_RATE), + float_to_fp8_24(63.5654704170708 / FREQUENCY_RATE), + float_to_fp8_24(63.6271844660194 / FREQUENCY_RATE), + float_to_fp8_24(63.6890184645287 / FREQUENCY_RATE), + float_to_fp8_24(63.7509727626459 / FREQUENCY_RATE), + float_to_fp8_24(63.8130477117819 / FREQUENCY_RATE), + float_to_fp8_24(63.8752436647174 / FREQUENCY_RATE), + float_to_fp8_24(63.9375609756098 / FREQUENCY_RATE), + float_to_fp8_24(64 / FREQUENCY_RATE), + float_to_fp8_24(64.0625610948192 / FREQUENCY_RATE), + float_to_fp8_24(64.1252446183953 / FREQUENCY_RATE), + float_to_fp8_24(64.1880509304603 / FREQUENCY_RATE), + float_to_fp8_24(64.2509803921569 / FREQUENCY_RATE), + float_to_fp8_24(64.3140333660451 / FREQUENCY_RATE), + float_to_fp8_24(64.37721021611 / FREQUENCY_RATE), + float_to_fp8_24(64.440511307768 / FREQUENCY_RATE), + float_to_fp8_24(64.503937007874 / FREQUENCY_RATE), + float_to_fp8_24(64.5674876847291 / FREQUENCY_RATE), + float_to_fp8_24(64.6311637080868 / FREQUENCY_RATE), + float_to_fp8_24(64.6949654491609 / FREQUENCY_RATE), + float_to_fp8_24(64.7588932806324 / FREQUENCY_RATE), + float_to_fp8_24(64.8229475766568 / FREQUENCY_RATE), + float_to_fp8_24(64.8871287128713 / FREQUENCY_RATE), + float_to_fp8_24(64.9514370664024 / FREQUENCY_RATE), + float_to_fp8_24(65.015873015873 / FREQUENCY_RATE), + float_to_fp8_24(65.0804369414101 / FREQUENCY_RATE), + float_to_fp8_24(65.1451292246521 / FREQUENCY_RATE), + float_to_fp8_24(65.2099502487562 / FREQUENCY_RATE), + float_to_fp8_24(65.2749003984064 / FREQUENCY_RATE), + float_to_fp8_24(65.3399800598205 / FREQUENCY_RATE), + float_to_fp8_24(65.4051896207585 / FREQUENCY_RATE), + float_to_fp8_24(65.4705294705295 / FREQUENCY_RATE), + float_to_fp8_24(65.536 / FREQUENCY_RATE), + float_to_fp8_24(65.6016016016016 / FREQUENCY_RATE), + float_to_fp8_24(65.6673346693387 / FREQUENCY_RATE), + float_to_fp8_24(65.7331995987964 / FREQUENCY_RATE), + float_to_fp8_24(65.7991967871486 / FREQUENCY_RATE), + float_to_fp8_24(65.8653266331658 / FREQUENCY_RATE), + float_to_fp8_24(65.9315895372234 / FREQUENCY_RATE), + float_to_fp8_24(65.9979859013092 / FREQUENCY_RATE), + float_to_fp8_24(66.0645161290323 / FREQUENCY_RATE), + float_to_fp8_24(66.1311806256307 / FREQUENCY_RATE), + float_to_fp8_24(66.1979797979798 / FREQUENCY_RATE), + float_to_fp8_24(66.2649140546006 / FREQUENCY_RATE), + float_to_fp8_24(66.331983805668 / FREQUENCY_RATE), + float_to_fp8_24(66.3991894630193 / FREQUENCY_RATE), + float_to_fp8_24(66.4665314401623 / FREQUENCY_RATE), + float_to_fp8_24(66.5340101522843 / FREQUENCY_RATE), + float_to_fp8_24(66.6016260162602 / FREQUENCY_RATE), + float_to_fp8_24(66.6693794506612 / FREQUENCY_RATE), + float_to_fp8_24(66.7372708757637 / FREQUENCY_RATE), + float_to_fp8_24(66.8053007135576 / FREQUENCY_RATE), + float_to_fp8_24(66.8734693877551 / FREQUENCY_RATE), + float_to_fp8_24(66.9417773237998 / FREQUENCY_RATE), + float_to_fp8_24(67.0102249488753 / FREQUENCY_RATE), + float_to_fp8_24(67.078812691914 / FREQUENCY_RATE), + float_to_fp8_24(67.1475409836066 / FREQUENCY_RATE), + float_to_fp8_24(67.2164102564103 / FREQUENCY_RATE), + float_to_fp8_24(67.2854209445585 / FREQUENCY_RATE), + float_to_fp8_24(67.3545734840699 / FREQUENCY_RATE), + float_to_fp8_24(67.4238683127572 / FREQUENCY_RATE), + float_to_fp8_24(67.4933058702369 / FREQUENCY_RATE), + float_to_fp8_24(67.5628865979382 / FREQUENCY_RATE), + float_to_fp8_24(67.6326109391125 / FREQUENCY_RATE), + float_to_fp8_24(67.702479338843 / FREQUENCY_RATE), + float_to_fp8_24(67.7724922440538 / FREQUENCY_RATE), + float_to_fp8_24(67.8426501035197 / FREQUENCY_RATE), + float_to_fp8_24(67.9129533678757 / FREQUENCY_RATE), + float_to_fp8_24(67.9834024896266 / FREQUENCY_RATE), + float_to_fp8_24(68.0539979231568 / FREQUENCY_RATE), + float_to_fp8_24(68.1247401247401 / FREQUENCY_RATE), + float_to_fp8_24(68.1956295525494 / FREQUENCY_RATE), + float_to_fp8_24(68.2666666666667 / FREQUENCY_RATE), + float_to_fp8_24(68.3378519290928 / FREQUENCY_RATE), + float_to_fp8_24(68.4091858037578 / FREQUENCY_RATE), + float_to_fp8_24(68.4806687565308 / FREQUENCY_RATE), + float_to_fp8_24(68.5523012552301 / FREQUENCY_RATE), + float_to_fp8_24(68.6240837696335 / FREQUENCY_RATE), + float_to_fp8_24(68.6960167714885 / FREQUENCY_RATE), + float_to_fp8_24(68.7681007345226 / FREQUENCY_RATE), + float_to_fp8_24(68.8403361344538 / FREQUENCY_RATE), + float_to_fp8_24(68.9127234490011 / FREQUENCY_RATE), + float_to_fp8_24(68.9852631578947 / FREQUENCY_RATE), + float_to_fp8_24(69.0579557428872 / FREQUENCY_RATE), + float_to_fp8_24(69.1308016877637 / FREQUENCY_RATE), + float_to_fp8_24(69.2038014783527 / FREQUENCY_RATE), + float_to_fp8_24(69.276955602537 / FREQUENCY_RATE), + float_to_fp8_24(69.3502645502646 / FREQUENCY_RATE), + float_to_fp8_24(69.4237288135593 / FREQUENCY_RATE), + float_to_fp8_24(69.4973488865324 / FREQUENCY_RATE), + float_to_fp8_24(69.5711252653928 / FREQUENCY_RATE), + float_to_fp8_24(69.6450584484591 / FREQUENCY_RATE), + float_to_fp8_24(69.7191489361702 / FREQUENCY_RATE), + float_to_fp8_24(69.7933972310969 / FREQUENCY_RATE), + float_to_fp8_24(69.8678038379531 / FREQUENCY_RATE), + float_to_fp8_24(69.9423692636073 / FREQUENCY_RATE), + float_to_fp8_24(70.017094017094 / FREQUENCY_RATE), + float_to_fp8_24(70.0919786096257 / FREQUENCY_RATE), + float_to_fp8_24(70.1670235546039 / FREQUENCY_RATE), + float_to_fp8_24(70.2422293676313 / FREQUENCY_RATE), + float_to_fp8_24(70.3175965665236 / FREQUENCY_RATE), + float_to_fp8_24(70.3931256713212 / FREQUENCY_RATE), + float_to_fp8_24(70.4688172043011 / FREQUENCY_RATE), + float_to_fp8_24(70.5446716899892 / FREQUENCY_RATE), + float_to_fp8_24(70.6206896551724 / FREQUENCY_RATE), + float_to_fp8_24(70.6968716289105 / FREQUENCY_RATE), + float_to_fp8_24(70.7732181425486 / FREQUENCY_RATE), + float_to_fp8_24(70.8497297297297 / FREQUENCY_RATE), + float_to_fp8_24(70.9264069264069 / FREQUENCY_RATE), + float_to_fp8_24(71.0032502708559 / FREQUENCY_RATE), + float_to_fp8_24(71.0802603036876 / FREQUENCY_RATE), + float_to_fp8_24(71.157437567861 / FREQUENCY_RATE), + float_to_fp8_24(71.2347826086957 / FREQUENCY_RATE), + float_to_fp8_24(71.3122959738847 / FREQUENCY_RATE), + float_to_fp8_24(71.3899782135076 / FREQUENCY_RATE), + float_to_fp8_24(71.4678298800436 / FREQUENCY_RATE), + float_to_fp8_24(71.5458515283843 / FREQUENCY_RATE), + float_to_fp8_24(71.624043715847 / FREQUENCY_RATE), + float_to_fp8_24(71.7024070021882 / FREQUENCY_RATE), + float_to_fp8_24(71.7809419496166 / FREQUENCY_RATE), + float_to_fp8_24(71.859649122807 / FREQUENCY_RATE), + float_to_fp8_24(71.9385290889133 / FREQUENCY_RATE), + float_to_fp8_24(72.0175824175824 / FREQUENCY_RATE), + float_to_fp8_24(72.0968096809681 / FREQUENCY_RATE), + float_to_fp8_24(72.1762114537445 / FREQUENCY_RATE), + float_to_fp8_24(72.2557883131202 / FREQUENCY_RATE), + float_to_fp8_24(72.3355408388521 / FREQUENCY_RATE), + float_to_fp8_24(72.4154696132597 / FREQUENCY_RATE), + float_to_fp8_24(72.4955752212389 / FREQUENCY_RATE), + float_to_fp8_24(72.5758582502769 / FREQUENCY_RATE), + float_to_fp8_24(72.6563192904656 / FREQUENCY_RATE), + float_to_fp8_24(72.7369589345172 / FREQUENCY_RATE), + float_to_fp8_24(72.8177777777778 / FREQUENCY_RATE), + float_to_fp8_24(72.8987764182425 / FREQUENCY_RATE), + float_to_fp8_24(72.9799554565702 / FREQUENCY_RATE), + float_to_fp8_24(73.0613154960981 / FREQUENCY_RATE), + float_to_fp8_24(73.1428571428571 / FREQUENCY_RATE), + float_to_fp8_24(73.2245810055866 / FREQUENCY_RATE), + float_to_fp8_24(73.3064876957494 / FREQUENCY_RATE), + float_to_fp8_24(73.3885778275476 / FREQUENCY_RATE), + float_to_fp8_24(73.4708520179372 / FREQUENCY_RATE), + float_to_fp8_24(73.5533108866442 / FREQUENCY_RATE), + float_to_fp8_24(73.6359550561798 / FREQUENCY_RATE), + float_to_fp8_24(73.718785151856 / FREQUENCY_RATE), + float_to_fp8_24(73.8018018018018 / FREQUENCY_RATE), + float_to_fp8_24(73.8850056369786 / FREQUENCY_RATE), + float_to_fp8_24(73.9683972911964 / FREQUENCY_RATE), + float_to_fp8_24(74.0519774011299 / FREQUENCY_RATE), + float_to_fp8_24(74.1357466063348 / FREQUENCY_RATE), + float_to_fp8_24(74.2197055492639 / FREQUENCY_RATE), + float_to_fp8_24(74.3038548752835 / FREQUENCY_RATE), + float_to_fp8_24(74.3881952326901 / FREQUENCY_RATE), + float_to_fp8_24(74.4727272727273 / FREQUENCY_RATE), + float_to_fp8_24(74.5574516496018 / FREQUENCY_RATE), + float_to_fp8_24(74.6423690205011 / FREQUENCY_RATE), + float_to_fp8_24(74.72748004561 / FREQUENCY_RATE), + float_to_fp8_24(74.8127853881279 / FREQUENCY_RATE), + float_to_fp8_24(74.8982857142857 / FREQUENCY_RATE), + float_to_fp8_24(74.9839816933639 / FREQUENCY_RATE), + float_to_fp8_24(75.0698739977091 / FREQUENCY_RATE), + float_to_fp8_24(75.1559633027523 / FREQUENCY_RATE), + float_to_fp8_24(75.2422502870264 / FREQUENCY_RATE), + float_to_fp8_24(75.3287356321839 / FREQUENCY_RATE), + float_to_fp8_24(75.415420023015 / FREQUENCY_RATE), + float_to_fp8_24(75.5023041474654 / FREQUENCY_RATE), + float_to_fp8_24(75.5893886966551 / FREQUENCY_RATE), + float_to_fp8_24(75.6766743648961 / FREQUENCY_RATE), + float_to_fp8_24(75.764161849711 / FREQUENCY_RATE), + float_to_fp8_24(75.8518518518518 / FREQUENCY_RATE), + float_to_fp8_24(75.9397450753187 / FREQUENCY_RATE), + float_to_fp8_24(76.0278422273782 / FREQUENCY_RATE), + float_to_fp8_24(76.116144018583 / FREQUENCY_RATE), + float_to_fp8_24(76.2046511627907 / FREQUENCY_RATE), + float_to_fp8_24(76.2933643771828 / FREQUENCY_RATE), + float_to_fp8_24(76.3822843822844 / FREQUENCY_RATE), + float_to_fp8_24(76.4714119019837 / FREQUENCY_RATE), + float_to_fp8_24(76.5607476635514 / FREQUENCY_RATE), + float_to_fp8_24(76.6502923976608 / FREQUENCY_RATE), + float_to_fp8_24(76.7400468384075 / FREQUENCY_RATE), + float_to_fp8_24(76.8300117233294 / FREQUENCY_RATE), + float_to_fp8_24(76.9201877934272 / FREQUENCY_RATE), + float_to_fp8_24(77.0105757931845 / FREQUENCY_RATE), + float_to_fp8_24(77.1011764705882 / FREQUENCY_RATE), + float_to_fp8_24(77.1919905771496 / FREQUENCY_RATE), + float_to_fp8_24(77.2830188679245 / FREQUENCY_RATE), + float_to_fp8_24(77.3742621015348 / FREQUENCY_RATE), + float_to_fp8_24(77.4657210401891 / FREQUENCY_RATE), + float_to_fp8_24(77.5573964497041 / FREQUENCY_RATE), + float_to_fp8_24(77.6492890995261 / FREQUENCY_RATE), + float_to_fp8_24(77.7413997627521 / FREQUENCY_RATE), + float_to_fp8_24(77.833729216152 / FREQUENCY_RATE), + float_to_fp8_24(77.9262782401902 / FREQUENCY_RATE), + float_to_fp8_24(78.0190476190476 / FREQUENCY_RATE), + float_to_fp8_24(78.1120381406436 / FREQUENCY_RATE), + float_to_fp8_24(78.2052505966587 / FREQUENCY_RATE), + float_to_fp8_24(78.2986857825568 / FREQUENCY_RATE), + float_to_fp8_24(78.3923444976077 / FREQUENCY_RATE), + float_to_fp8_24(78.4862275449102 / FREQUENCY_RATE), + float_to_fp8_24(78.5803357314149 / FREQUENCY_RATE), + float_to_fp8_24(78.6746698679472 / FREQUENCY_RATE), + float_to_fp8_24(78.7692307692308 / FREQUENCY_RATE), + float_to_fp8_24(78.864019253911 / FREQUENCY_RATE), + float_to_fp8_24(78.9590361445783 / FREQUENCY_RATE), + float_to_fp8_24(79.0542822677925 / FREQUENCY_RATE), + float_to_fp8_24(79.1497584541063 / FREQUENCY_RATE), + float_to_fp8_24(79.2454655380895 / FREQUENCY_RATE), + float_to_fp8_24(79.3414043583535 / FREQUENCY_RATE), + float_to_fp8_24(79.4375757575758 / FREQUENCY_RATE), + float_to_fp8_24(79.5339805825243 / FREQUENCY_RATE), + float_to_fp8_24(79.6306196840826 / FREQUENCY_RATE), + float_to_fp8_24(79.7274939172749 / FREQUENCY_RATE), + float_to_fp8_24(79.8246041412911 / FREQUENCY_RATE), + float_to_fp8_24(79.9219512195122 / FREQUENCY_RATE), + float_to_fp8_24(80.019536019536 / FREQUENCY_RATE), + float_to_fp8_24(80.1173594132029 / FREQUENCY_RATE), + float_to_fp8_24(80.2154222766218 / FREQUENCY_RATE), + float_to_fp8_24(80.3137254901961 / FREQUENCY_RATE), + float_to_fp8_24(80.4122699386503 / FREQUENCY_RATE), + float_to_fp8_24(80.5110565110565 / FREQUENCY_RATE), + float_to_fp8_24(80.610086100861 / FREQUENCY_RATE), + float_to_fp8_24(80.7093596059113 / FREQUENCY_RATE), + float_to_fp8_24(80.8088779284834 / FREQUENCY_RATE), + float_to_fp8_24(80.9086419753086 / FREQUENCY_RATE), + float_to_fp8_24(81.008652657602 / FREQUENCY_RATE), + float_to_fp8_24(81.1089108910891 / FREQUENCY_RATE), + float_to_fp8_24(81.2094175960347 / FREQUENCY_RATE), + float_to_fp8_24(81.3101736972705 / FREQUENCY_RATE), + float_to_fp8_24(81.4111801242236 / FREQUENCY_RATE), + float_to_fp8_24(81.5124378109453 / FREQUENCY_RATE), + float_to_fp8_24(81.6139476961395 / FREQUENCY_RATE), + float_to_fp8_24(81.715710723192 / FREQUENCY_RATE), + float_to_fp8_24(81.8177278401998 / FREQUENCY_RATE), + float_to_fp8_24(81.92 / FREQUENCY_RATE), + float_to_fp8_24(82.0225281602002 / FREQUENCY_RATE), + float_to_fp8_24(82.125313283208 / FREQUENCY_RATE), + float_to_fp8_24(82.228356336261 / FREQUENCY_RATE), + float_to_fp8_24(82.3316582914573 / FREQUENCY_RATE), + float_to_fp8_24(82.4352201257862 / FREQUENCY_RATE), + float_to_fp8_24(82.5390428211587 / FREQUENCY_RATE), + float_to_fp8_24(82.6431273644388 / FREQUENCY_RATE), + float_to_fp8_24(82.7474747474748 / FREQUENCY_RATE), + float_to_fp8_24(82.8520859671302 / FREQUENCY_RATE), + float_to_fp8_24(82.9569620253165 / FREQUENCY_RATE), + float_to_fp8_24(83.0621039290241 / FREQUENCY_RATE), + float_to_fp8_24(83.1675126903553 / FREQUENCY_RATE), + float_to_fp8_24(83.2731893265565 / FREQUENCY_RATE), + float_to_fp8_24(83.3791348600509 / FREQUENCY_RATE), + float_to_fp8_24(83.4853503184713 / FREQUENCY_RATE), + float_to_fp8_24(83.5918367346939 / FREQUENCY_RATE), + float_to_fp8_24(83.698595146871 / FREQUENCY_RATE), + float_to_fp8_24(83.8056265984655 / FREQUENCY_RATE), + float_to_fp8_24(83.9129321382842 / FREQUENCY_RATE), + float_to_fp8_24(84.0205128205128 / FREQUENCY_RATE), + float_to_fp8_24(84.1283697047497 / FREQUENCY_RATE), + float_to_fp8_24(84.2365038560411 / FREQUENCY_RATE), + float_to_fp8_24(84.3449163449163 / FREQUENCY_RATE), + float_to_fp8_24(84.4536082474227 / FREQUENCY_RATE), + float_to_fp8_24(84.5625806451613 / FREQUENCY_RATE), + float_to_fp8_24(84.671834625323 / FREQUENCY_RATE), + float_to_fp8_24(84.7813712807245 / FREQUENCY_RATE), + float_to_fp8_24(84.8911917098446 / FREQUENCY_RATE), + float_to_fp8_24(85.0012970168612 / FREQUENCY_RATE), + float_to_fp8_24(85.1116883116883 / FREQUENCY_RATE), + float_to_fp8_24(85.222366710013 / FREQUENCY_RATE), + float_to_fp8_24(85.3333333333333 / FREQUENCY_RATE), + float_to_fp8_24(85.4445893089961 / FREQUENCY_RATE), + float_to_fp8_24(85.556135770235 / FREQUENCY_RATE), + float_to_fp8_24(85.6679738562091 / FREQUENCY_RATE), + float_to_fp8_24(85.7801047120419 / FREQUENCY_RATE), + float_to_fp8_24(85.8925294888598 / FREQUENCY_RATE), + float_to_fp8_24(86.005249343832 / FREQUENCY_RATE), + float_to_fp8_24(86.1182654402102 / FREQUENCY_RATE), + float_to_fp8_24(86.2315789473684 / FREQUENCY_RATE), + float_to_fp8_24(86.3451910408432 / FREQUENCY_RATE), + float_to_fp8_24(86.4591029023747 / FREQUENCY_RATE), + float_to_fp8_24(86.5733157199472 / FREQUENCY_RATE), + float_to_fp8_24(86.6878306878307 / FREQUENCY_RATE), + float_to_fp8_24(86.8026490066225 / FREQUENCY_RATE), + float_to_fp8_24(86.9177718832891 / FREQUENCY_RATE), + float_to_fp8_24(87.0332005312085 / FREQUENCY_RATE), + float_to_fp8_24(87.1489361702128 / FREQUENCY_RATE), + float_to_fp8_24(87.2649800266312 / FREQUENCY_RATE), + float_to_fp8_24(87.3813333333333 / FREQUENCY_RATE), + float_to_fp8_24(87.497997329773 / FREQUENCY_RATE), + float_to_fp8_24(87.6149732620321 / FREQUENCY_RATE), + float_to_fp8_24(87.7322623828648 / FREQUENCY_RATE), + float_to_fp8_24(87.8498659517426 / FREQUENCY_RATE), + float_to_fp8_24(87.9677852348993 / FREQUENCY_RATE), + float_to_fp8_24(88.0860215053763 / FREQUENCY_RATE), + float_to_fp8_24(88.2045760430686 / FREQUENCY_RATE), + float_to_fp8_24(88.3234501347709 / FREQUENCY_RATE), + float_to_fp8_24(88.442645074224 / FREQUENCY_RATE), + float_to_fp8_24(88.5621621621622 / FREQUENCY_RATE), + float_to_fp8_24(88.68200270636 / FREQUENCY_RATE), + float_to_fp8_24(88.8021680216802 / FREQUENCY_RATE), + float_to_fp8_24(88.9226594301221 / FREQUENCY_RATE), + float_to_fp8_24(89.0434782608696 / FREQUENCY_RATE), + float_to_fp8_24(89.1646258503401 / FREQUENCY_RATE), + float_to_fp8_24(89.2861035422343 / FREQUENCY_RATE), + float_to_fp8_24(89.4079126875853 / FREQUENCY_RATE), + float_to_fp8_24(89.5300546448087 / FREQUENCY_RATE), + float_to_fp8_24(89.6525307797538 / FREQUENCY_RATE), + float_to_fp8_24(89.7753424657534 / FREQUENCY_RATE), + float_to_fp8_24(89.8984910836763 / FREQUENCY_RATE), + float_to_fp8_24(90.021978021978 / FREQUENCY_RATE), + float_to_fp8_24(90.1458046767538 / FREQUENCY_RATE), + float_to_fp8_24(90.2699724517906 / FREQUENCY_RATE), + float_to_fp8_24(90.3944827586207 / FREQUENCY_RATE), + float_to_fp8_24(90.5193370165746 / FREQUENCY_RATE), + float_to_fp8_24(90.6445366528354 / FREQUENCY_RATE), + float_to_fp8_24(90.7700831024931 / FREQUENCY_RATE), + float_to_fp8_24(90.8959778085992 / FREQUENCY_RATE), + float_to_fp8_24(91.0222222222222 / FREQUENCY_RATE), + float_to_fp8_24(91.1488178025035 / FREQUENCY_RATE), + float_to_fp8_24(91.2757660167131 / FREQUENCY_RATE), + float_to_fp8_24(91.4030683403068 / FREQUENCY_RATE), + float_to_fp8_24(91.5307262569833 / FREQUENCY_RATE), + float_to_fp8_24(91.6587412587413 / FREQUENCY_RATE), + float_to_fp8_24(91.7871148459384 / FREQUENCY_RATE), + float_to_fp8_24(91.9158485273492 / FREQUENCY_RATE), + float_to_fp8_24(92.0449438202247 / FREQUENCY_RATE), + float_to_fp8_24(92.1744022503516 / FREQUENCY_RATE), + float_to_fp8_24(92.3042253521127 / FREQUENCY_RATE), + float_to_fp8_24(92.4344146685472 / FREQUENCY_RATE), + float_to_fp8_24(92.5649717514124 / FREQUENCY_RATE), + float_to_fp8_24(92.6958981612447 / FREQUENCY_RATE), + float_to_fp8_24(92.8271954674221 / FREQUENCY_RATE), + float_to_fp8_24(92.958865248227 / FREQUENCY_RATE), + float_to_fp8_24(93.0909090909091 / FREQUENCY_RATE), + float_to_fp8_24(93.2233285917497 / FREQUENCY_RATE), + float_to_fp8_24(93.3561253561254 / FREQUENCY_RATE), + float_to_fp8_24(93.4893009985735 / FREQUENCY_RATE), + float_to_fp8_24(93.6228571428572 / FREQUENCY_RATE), + float_to_fp8_24(93.7567954220315 / FREQUENCY_RATE), + float_to_fp8_24(93.89111747851 / FREQUENCY_RATE), + float_to_fp8_24(94.025824964132 / FREQUENCY_RATE), + float_to_fp8_24(94.1609195402299 / FREQUENCY_RATE), + float_to_fp8_24(94.2964028776978 / FREQUENCY_RATE), + float_to_fp8_24(94.4322766570605 / FREQUENCY_RATE), + float_to_fp8_24(94.5685425685426 / FREQUENCY_RATE), + float_to_fp8_24(94.7052023121387 / FREQUENCY_RATE), + float_to_fp8_24(94.8422575976845 / FREQUENCY_RATE), + float_to_fp8_24(94.9797101449275 / FREQUENCY_RATE), + float_to_fp8_24(95.1175616835994 / FREQUENCY_RATE), + float_to_fp8_24(95.2558139534884 / FREQUENCY_RATE), + float_to_fp8_24(95.3944687045124 / FREQUENCY_RATE), + float_to_fp8_24(95.533527696793 / FREQUENCY_RATE), + float_to_fp8_24(95.6729927007299 / FREQUENCY_RATE), + float_to_fp8_24(95.812865497076 / FREQUENCY_RATE), + float_to_fp8_24(95.9531478770132 / FREQUENCY_RATE), + float_to_fp8_24(96.0938416422287 / FREQUENCY_RATE), + float_to_fp8_24(96.2349486049927 / FREQUENCY_RATE), + float_to_fp8_24(96.3764705882353 / FREQUENCY_RATE), + float_to_fp8_24(96.5184094256259 / FREQUENCY_RATE), + float_to_fp8_24(96.6607669616519 / FREQUENCY_RATE), + float_to_fp8_24(96.8035450516987 / FREQUENCY_RATE), + float_to_fp8_24(96.9467455621302 / FREQUENCY_RATE), + float_to_fp8_24(97.0903703703704 / FREQUENCY_RATE), + float_to_fp8_24(97.2344213649852 / FREQUENCY_RATE), + float_to_fp8_24(97.3789004457652 / FREQUENCY_RATE), + float_to_fp8_24(97.5238095238095 / FREQUENCY_RATE), + float_to_fp8_24(97.6691505216095 / FREQUENCY_RATE), + float_to_fp8_24(97.8149253731343 / FREQUENCY_RATE), + float_to_fp8_24(97.9611360239163 / FREQUENCY_RATE), + float_to_fp8_24(98.1077844311377 / FREQUENCY_RATE), + float_to_fp8_24(98.2548725637181 / FREQUENCY_RATE), + float_to_fp8_24(98.4024024024024 / FREQUENCY_RATE), + float_to_fp8_24(98.5503759398496 / FREQUENCY_RATE), + float_to_fp8_24(98.6987951807229 / FREQUENCY_RATE), + float_to_fp8_24(98.8476621417798 / FREQUENCY_RATE), + float_to_fp8_24(98.9969788519637 / FREQUENCY_RATE), + float_to_fp8_24(99.1467473524962 / FREQUENCY_RATE), + float_to_fp8_24(99.2969696969697 / FREQUENCY_RATE), + float_to_fp8_24(99.4476479514416 / FREQUENCY_RATE), + float_to_fp8_24(99.5987841945289 / FREQUENCY_RATE), + float_to_fp8_24(99.7503805175038 / FREQUENCY_RATE), + float_to_fp8_24(99.9024390243902 / FREQUENCY_RATE), + float_to_fp8_24(100.054961832061 / FREQUENCY_RATE), + float_to_fp8_24(100.207951070336 / FREQUENCY_RATE), + float_to_fp8_24(100.361408882083 / FREQUENCY_RATE), + float_to_fp8_24(100.515337423313 / FREQUENCY_RATE), + float_to_fp8_24(100.669738863287 / FREQUENCY_RATE), + float_to_fp8_24(100.824615384615 / FREQUENCY_RATE), + float_to_fp8_24(100.979969183359 / FREQUENCY_RATE), + float_to_fp8_24(101.135802469136 / FREQUENCY_RATE), + float_to_fp8_24(101.292117465224 / FREQUENCY_RATE), + float_to_fp8_24(101.448916408669 / FREQUENCY_RATE), + float_to_fp8_24(101.606201550388 / FREQUENCY_RATE), + float_to_fp8_24(101.76397515528 / FREQUENCY_RATE), + float_to_fp8_24(101.922239502333 / FREQUENCY_RATE), + float_to_fp8_24(102.080996884735 / FREQUENCY_RATE), + float_to_fp8_24(102.240249609984 / FREQUENCY_RATE), + float_to_fp8_24(102.4 / FREQUENCY_RATE), + float_to_fp8_24(102.560250391236 / FREQUENCY_RATE), + float_to_fp8_24(102.721003134796 / FREQUENCY_RATE), + float_to_fp8_24(102.882260596546 / FREQUENCY_RATE), + float_to_fp8_24(103.044025157233 / FREQUENCY_RATE), + float_to_fp8_24(103.206299212598 / FREQUENCY_RATE), + float_to_fp8_24(103.369085173502 / FREQUENCY_RATE), + float_to_fp8_24(103.532385466035 / FREQUENCY_RATE), + float_to_fp8_24(103.696202531646 / FREQUENCY_RATE), + float_to_fp8_24(103.860538827258 / FREQUENCY_RATE), + float_to_fp8_24(104.025396825397 / FREQUENCY_RATE), + float_to_fp8_24(104.190779014308 / FREQUENCY_RATE), + float_to_fp8_24(104.356687898089 / FREQUENCY_RATE), + float_to_fp8_24(104.52312599681 / FREQUENCY_RATE), + float_to_fp8_24(104.690095846645 / FREQUENCY_RATE), + float_to_fp8_24(104.8576 / FREQUENCY_RATE), + float_to_fp8_24(105.025641025641 / FREQUENCY_RATE), + float_to_fp8_24(105.194221508828 / FREQUENCY_RATE), + float_to_fp8_24(105.363344051447 / FREQUENCY_RATE), + float_to_fp8_24(105.533011272142 / FREQUENCY_RATE), + float_to_fp8_24(105.703225806452 / FREQUENCY_RATE), + float_to_fp8_24(105.873990306947 / FREQUENCY_RATE), + float_to_fp8_24(106.045307443366 / FREQUENCY_RATE), + float_to_fp8_24(106.217179902755 / FREQUENCY_RATE), + float_to_fp8_24(106.38961038961 / FREQUENCY_RATE), + float_to_fp8_24(106.562601626016 / FREQUENCY_RATE), + float_to_fp8_24(106.736156351792 / FREQUENCY_RATE), + float_to_fp8_24(106.910277324633 / FREQUENCY_RATE), + float_to_fp8_24(107.084967320261 / FREQUENCY_RATE), + float_to_fp8_24(107.26022913257 / FREQUENCY_RATE), + float_to_fp8_24(107.436065573771 / FREQUENCY_RATE), + float_to_fp8_24(107.612479474548 / FREQUENCY_RATE), + float_to_fp8_24(107.789473684211 / FREQUENCY_RATE), + float_to_fp8_24(107.96705107084 / FREQUENCY_RATE), + float_to_fp8_24(108.145214521452 / FREQUENCY_RATE), + float_to_fp8_24(108.323966942149 / FREQUENCY_RATE), + float_to_fp8_24(108.503311258278 / FREQUENCY_RATE), + float_to_fp8_24(108.683250414594 / FREQUENCY_RATE), + float_to_fp8_24(108.863787375415 / FREQUENCY_RATE), + float_to_fp8_24(109.044925124792 / FREQUENCY_RATE), + float_to_fp8_24(109.226666666667 / FREQUENCY_RATE), + float_to_fp8_24(109.409015025042 / FREQUENCY_RATE), + float_to_fp8_24(109.591973244147 / FREQUENCY_RATE), + float_to_fp8_24(109.77554438861 / FREQUENCY_RATE), + float_to_fp8_24(109.959731543624 / FREQUENCY_RATE), + float_to_fp8_24(110.144537815126 / FREQUENCY_RATE), + float_to_fp8_24(110.329966329966 / FREQUENCY_RATE), + float_to_fp8_24(110.516020236088 / FREQUENCY_RATE), + float_to_fp8_24(110.702702702703 / FREQUENCY_RATE), + float_to_fp8_24(110.890016920474 / FREQUENCY_RATE), + float_to_fp8_24(111.077966101695 / FREQUENCY_RATE), + float_to_fp8_24(111.266553480475 / FREQUENCY_RATE), + float_to_fp8_24(111.455782312925 / FREQUENCY_RATE), + float_to_fp8_24(111.645655877342 / FREQUENCY_RATE), + float_to_fp8_24(111.836177474403 / FREQUENCY_RATE), + float_to_fp8_24(112.02735042735 / FREQUENCY_RATE), + float_to_fp8_24(112.219178082192 / FREQUENCY_RATE), + float_to_fp8_24(112.41166380789 / FREQUENCY_RATE), + float_to_fp8_24(112.604810996564 / FREQUENCY_RATE), + float_to_fp8_24(112.798623063683 / FREQUENCY_RATE), + float_to_fp8_24(112.993103448276 / FREQUENCY_RATE), + float_to_fp8_24(113.188255613126 / FREQUENCY_RATE), + float_to_fp8_24(113.384083044983 / FREQUENCY_RATE), + float_to_fp8_24(113.580589254766 / FREQUENCY_RATE), + float_to_fp8_24(113.777777777778 / FREQUENCY_RATE), + float_to_fp8_24(113.975652173913 / FREQUENCY_RATE), + float_to_fp8_24(114.174216027875 / FREQUENCY_RATE), + float_to_fp8_24(114.373472949389 / FREQUENCY_RATE), + float_to_fp8_24(114.573426573427 / FREQUENCY_RATE), + float_to_fp8_24(114.77408056042 / FREQUENCY_RATE), + float_to_fp8_24(114.975438596491 / FREQUENCY_RATE), + float_to_fp8_24(115.177504393673 / FREQUENCY_RATE), + float_to_fp8_24(115.380281690141 / FREQUENCY_RATE), + float_to_fp8_24(115.583774250441 / FREQUENCY_RATE), + float_to_fp8_24(115.787985865724 / FREQUENCY_RATE), + float_to_fp8_24(115.992920353982 / FREQUENCY_RATE), + float_to_fp8_24(116.198581560284 / FREQUENCY_RATE), + float_to_fp8_24(116.404973357016 / FREQUENCY_RATE), + float_to_fp8_24(116.612099644128 / FREQUENCY_RATE), + float_to_fp8_24(116.819964349376 / FREQUENCY_RATE), + float_to_fp8_24(117.028571428571 / FREQUENCY_RATE), + float_to_fp8_24(117.237924865832 / FREQUENCY_RATE), + float_to_fp8_24(117.448028673835 / FREQUENCY_RATE), + float_to_fp8_24(117.658886894075 / FREQUENCY_RATE), + float_to_fp8_24(117.870503597122 / FREQUENCY_RATE), + float_to_fp8_24(118.082882882883 / FREQUENCY_RATE), + float_to_fp8_24(118.296028880866 / FREQUENCY_RATE), + float_to_fp8_24(118.509945750452 / FREQUENCY_RATE), + float_to_fp8_24(118.724637681159 / FREQUENCY_RATE), + float_to_fp8_24(118.940108892922 / FREQUENCY_RATE), + float_to_fp8_24(119.156363636364 / FREQUENCY_RATE), + float_to_fp8_24(119.373406193078 / FREQUENCY_RATE), + float_to_fp8_24(119.591240875912 / FREQUENCY_RATE), + float_to_fp8_24(119.80987202925 / FREQUENCY_RATE), + float_to_fp8_24(120.029304029304 / FREQUENCY_RATE), + float_to_fp8_24(120.249541284404 / FREQUENCY_RATE), + float_to_fp8_24(120.470588235294 / FREQUENCY_RATE), + float_to_fp8_24(120.692449355433 / FREQUENCY_RATE), + float_to_fp8_24(120.915129151292 / FREQUENCY_RATE), + float_to_fp8_24(121.138632162662 / FREQUENCY_RATE), + float_to_fp8_24(121.362962962963 / FREQUENCY_RATE), + float_to_fp8_24(121.588126159555 / FREQUENCY_RATE), + float_to_fp8_24(121.814126394052 / FREQUENCY_RATE), + float_to_fp8_24(122.040968342644 / FREQUENCY_RATE), + float_to_fp8_24(122.268656716418 / FREQUENCY_RATE), + float_to_fp8_24(122.497196261682 / FREQUENCY_RATE), + float_to_fp8_24(122.7265917603 / FREQUENCY_RATE), + float_to_fp8_24(122.956848030019 / FREQUENCY_RATE), + float_to_fp8_24(123.187969924812 / FREQUENCY_RATE), + float_to_fp8_24(123.419962335217 / FREQUENCY_RATE), + float_to_fp8_24(123.652830188679 / FREQUENCY_RATE), + float_to_fp8_24(123.886578449906 / FREQUENCY_RATE), + float_to_fp8_24(124.121212121212 / FREQUENCY_RATE), + float_to_fp8_24(124.356736242884 / FREQUENCY_RATE), + float_to_fp8_24(124.593155893536 / FREQUENCY_RATE), + float_to_fp8_24(124.830476190476 / FREQUENCY_RATE), + float_to_fp8_24(125.068702290076 / FREQUENCY_RATE), + float_to_fp8_24(125.307839388145 / FREQUENCY_RATE), + float_to_fp8_24(125.547892720307 / FREQUENCY_RATE), + float_to_fp8_24(125.78886756238 / FREQUENCY_RATE), + float_to_fp8_24(126.030769230769 / FREQUENCY_RATE), + float_to_fp8_24(126.273603082852 / FREQUENCY_RATE), + float_to_fp8_24(126.517374517375 / FREQUENCY_RATE), + float_to_fp8_24(126.762088974855 / FREQUENCY_RATE), + float_to_fp8_24(127.007751937985 / FREQUENCY_RATE), + float_to_fp8_24(127.254368932039 / FREQUENCY_RATE), + float_to_fp8_24(127.501945525292 / FREQUENCY_RATE), + float_to_fp8_24(127.750487329435 / FREQUENCY_RATE), + float_to_fp8_24(128 / FREQUENCY_RATE), + float_to_fp8_24(128.250489236791 / FREQUENCY_RATE), + float_to_fp8_24(128.501960784314 / FREQUENCY_RATE), + float_to_fp8_24(128.75442043222 / FREQUENCY_RATE), + float_to_fp8_24(129.007874015748 / FREQUENCY_RATE), + float_to_fp8_24(129.262327416174 / FREQUENCY_RATE), + float_to_fp8_24(129.517786561265 / FREQUENCY_RATE), + float_to_fp8_24(129.774257425743 / FREQUENCY_RATE), + float_to_fp8_24(130.031746031746 / FREQUENCY_RATE), + float_to_fp8_24(130.290258449304 / FREQUENCY_RATE), + float_to_fp8_24(130.549800796813 / FREQUENCY_RATE), + float_to_fp8_24(130.810379241517 / FREQUENCY_RATE), + float_to_fp8_24(131.072 / FREQUENCY_RATE), + float_to_fp8_24(131.334669338677 / FREQUENCY_RATE), + float_to_fp8_24(131.598393574297 / FREQUENCY_RATE), + float_to_fp8_24(131.863179074447 / FREQUENCY_RATE), + float_to_fp8_24(132.129032258065 / FREQUENCY_RATE), + float_to_fp8_24(132.39595959596 / FREQUENCY_RATE), + float_to_fp8_24(132.663967611336 / FREQUENCY_RATE), + float_to_fp8_24(132.933062880325 / FREQUENCY_RATE), + float_to_fp8_24(133.20325203252 / FREQUENCY_RATE), + float_to_fp8_24(133.474541751527 / FREQUENCY_RATE), + float_to_fp8_24(133.74693877551 / FREQUENCY_RATE), + float_to_fp8_24(134.020449897751 / FREQUENCY_RATE), + float_to_fp8_24(134.295081967213 / FREQUENCY_RATE), + float_to_fp8_24(134.570841889117 / FREQUENCY_RATE), + float_to_fp8_24(134.847736625514 / FREQUENCY_RATE), + float_to_fp8_24(135.125773195876 / FREQUENCY_RATE), + float_to_fp8_24(135.404958677686 / FREQUENCY_RATE), + float_to_fp8_24(135.685300207039 / FREQUENCY_RATE), + float_to_fp8_24(135.966804979253 / FREQUENCY_RATE), + float_to_fp8_24(136.24948024948 / FREQUENCY_RATE), + float_to_fp8_24(136.533333333333 / FREQUENCY_RATE), + float_to_fp8_24(136.818371607516 / FREQUENCY_RATE), + float_to_fp8_24(137.10460251046 / FREQUENCY_RATE), + float_to_fp8_24(137.392033542977 / FREQUENCY_RATE), + float_to_fp8_24(137.680672268908 / FREQUENCY_RATE), + float_to_fp8_24(137.970526315789 / FREQUENCY_RATE), + float_to_fp8_24(138.261603375527 / FREQUENCY_RATE), + float_to_fp8_24(138.553911205074 / FREQUENCY_RATE), + float_to_fp8_24(138.847457627119 / FREQUENCY_RATE), + float_to_fp8_24(139.142250530786 / FREQUENCY_RATE), + float_to_fp8_24(139.43829787234 / FREQUENCY_RATE), + float_to_fp8_24(139.735607675906 / FREQUENCY_RATE), + float_to_fp8_24(140.034188034188 / FREQUENCY_RATE), + float_to_fp8_24(140.334047109208 / FREQUENCY_RATE), + float_to_fp8_24(140.635193133047 / FREQUENCY_RATE), + float_to_fp8_24(140.937634408602 / FREQUENCY_RATE), + float_to_fp8_24(141.241379310345 / FREQUENCY_RATE), + float_to_fp8_24(141.546436285097 / FREQUENCY_RATE), + float_to_fp8_24(141.852813852814 / FREQUENCY_RATE), + float_to_fp8_24(142.160520607375 / FREQUENCY_RATE), + float_to_fp8_24(142.469565217391 / FREQUENCY_RATE), + float_to_fp8_24(142.779956427015 / FREQUENCY_RATE), + float_to_fp8_24(143.091703056769 / FREQUENCY_RATE), + float_to_fp8_24(143.404814004376 / FREQUENCY_RATE), + float_to_fp8_24(143.719298245614 / FREQUENCY_RATE), + float_to_fp8_24(144.035164835165 / FREQUENCY_RATE), + float_to_fp8_24(144.352422907489 / FREQUENCY_RATE), + float_to_fp8_24(144.671081677704 / FREQUENCY_RATE), + float_to_fp8_24(144.991150442478 / FREQUENCY_RATE), + float_to_fp8_24(145.312638580931 / FREQUENCY_RATE), + float_to_fp8_24(145.635555555556 / FREQUENCY_RATE), + float_to_fp8_24(145.95991091314 / FREQUENCY_RATE), + float_to_fp8_24(146.285714285714 / FREQUENCY_RATE), + float_to_fp8_24(146.612975391499 / FREQUENCY_RATE), + float_to_fp8_24(146.941704035874 / FREQUENCY_RATE), + float_to_fp8_24(147.27191011236 / FREQUENCY_RATE), + float_to_fp8_24(147.603603603604 / FREQUENCY_RATE), + float_to_fp8_24(147.936794582393 / FREQUENCY_RATE), + float_to_fp8_24(148.27149321267 / FREQUENCY_RATE), + float_to_fp8_24(148.607709750567 / FREQUENCY_RATE), + float_to_fp8_24(148.945454545455 / FREQUENCY_RATE), + float_to_fp8_24(149.284738041002 / FREQUENCY_RATE), + float_to_fp8_24(149.625570776256 / FREQUENCY_RATE), + float_to_fp8_24(149.967963386728 / FREQUENCY_RATE), + float_to_fp8_24(150.311926605505 / FREQUENCY_RATE), + float_to_fp8_24(150.657471264368 / FREQUENCY_RATE), + float_to_fp8_24(151.004608294931 / FREQUENCY_RATE), + float_to_fp8_24(151.353348729792 / FREQUENCY_RATE), + float_to_fp8_24(151.703703703704 / FREQUENCY_RATE), + float_to_fp8_24(152.055684454756 / FREQUENCY_RATE), + float_to_fp8_24(152.409302325581 / FREQUENCY_RATE), + float_to_fp8_24(152.764568764569 / FREQUENCY_RATE), + float_to_fp8_24(153.121495327103 / FREQUENCY_RATE), + float_to_fp8_24(153.480093676815 / FREQUENCY_RATE), + float_to_fp8_24(153.840375586854 / FREQUENCY_RATE), + float_to_fp8_24(154.202352941176 / FREQUENCY_RATE), + float_to_fp8_24(154.566037735849 / FREQUENCY_RATE), + float_to_fp8_24(154.931442080378 / FREQUENCY_RATE), + float_to_fp8_24(155.298578199052 / FREQUENCY_RATE), + float_to_fp8_24(155.667458432304 / FREQUENCY_RATE), + float_to_fp8_24(156.038095238095 / FREQUENCY_RATE), + float_to_fp8_24(156.410501193317 / FREQUENCY_RATE), + float_to_fp8_24(156.784688995215 / FREQUENCY_RATE), + float_to_fp8_24(157.16067146283 / FREQUENCY_RATE), + float_to_fp8_24(157.538461538462 / FREQUENCY_RATE), + float_to_fp8_24(157.918072289157 / FREQUENCY_RATE), + float_to_fp8_24(158.299516908213 / FREQUENCY_RATE), + float_to_fp8_24(158.682808716707 / FREQUENCY_RATE), + float_to_fp8_24(159.067961165049 / FREQUENCY_RATE), + float_to_fp8_24(159.45498783455 / FREQUENCY_RATE), + float_to_fp8_24(159.843902439024 / FREQUENCY_RATE), + float_to_fp8_24(160.234718826406 / FREQUENCY_RATE), + float_to_fp8_24(160.627450980392 / FREQUENCY_RATE), + float_to_fp8_24(161.022113022113 / FREQUENCY_RATE), + float_to_fp8_24(161.418719211823 / FREQUENCY_RATE), + float_to_fp8_24(161.817283950617 / FREQUENCY_RATE), + float_to_fp8_24(162.217821782178 / FREQUENCY_RATE), + float_to_fp8_24(162.620347394541 / FREQUENCY_RATE), + float_to_fp8_24(163.024875621891 / FREQUENCY_RATE), + float_to_fp8_24(163.431421446384 / FREQUENCY_RATE), + float_to_fp8_24(163.84 / FREQUENCY_RATE), + float_to_fp8_24(164.250626566416 / FREQUENCY_RATE), + float_to_fp8_24(164.663316582915 / FREQUENCY_RATE), + float_to_fp8_24(165.078085642317 / FREQUENCY_RATE), + float_to_fp8_24(165.49494949495 / FREQUENCY_RATE), + float_to_fp8_24(165.913924050633 / FREQUENCY_RATE), + float_to_fp8_24(166.335025380711 / FREQUENCY_RATE), + float_to_fp8_24(166.758269720102 / FREQUENCY_RATE), + float_to_fp8_24(167.183673469388 / FREQUENCY_RATE), + float_to_fp8_24(167.611253196931 / FREQUENCY_RATE), + float_to_fp8_24(168.041025641026 / FREQUENCY_RATE), + float_to_fp8_24(168.473007712082 / FREQUENCY_RATE), + float_to_fp8_24(168.907216494845 / FREQUENCY_RATE), + float_to_fp8_24(169.343669250646 / FREQUENCY_RATE), + float_to_fp8_24(169.782383419689 / FREQUENCY_RATE), + float_to_fp8_24(170.223376623377 / FREQUENCY_RATE), + float_to_fp8_24(170.666666666667 / FREQUENCY_RATE), + float_to_fp8_24(171.11227154047 / FREQUENCY_RATE), + float_to_fp8_24(171.560209424084 / FREQUENCY_RATE), + float_to_fp8_24(172.010498687664 / FREQUENCY_RATE), + float_to_fp8_24(172.463157894737 / FREQUENCY_RATE), + float_to_fp8_24(172.918205804749 / FREQUENCY_RATE), + float_to_fp8_24(173.375661375661 / FREQUENCY_RATE), + float_to_fp8_24(173.835543766578 / FREQUENCY_RATE), + float_to_fp8_24(174.297872340426 / FREQUENCY_RATE), + float_to_fp8_24(174.762666666667 / FREQUENCY_RATE), + float_to_fp8_24(175.229946524064 / FREQUENCY_RATE), + float_to_fp8_24(175.699731903485 / FREQUENCY_RATE), + float_to_fp8_24(176.172043010753 / FREQUENCY_RATE), + float_to_fp8_24(176.646900269542 / FREQUENCY_RATE), + float_to_fp8_24(177.124324324324 / FREQUENCY_RATE), + float_to_fp8_24(177.60433604336 / FREQUENCY_RATE), + float_to_fp8_24(178.086956521739 / FREQUENCY_RATE), + float_to_fp8_24(178.572207084469 / FREQUENCY_RATE), + float_to_fp8_24(179.060109289618 / FREQUENCY_RATE), + float_to_fp8_24(179.550684931507 / FREQUENCY_RATE), + float_to_fp8_24(180.043956043956 / FREQUENCY_RATE), + float_to_fp8_24(180.539944903581 / FREQUENCY_RATE), + float_to_fp8_24(181.038674033149 / FREQUENCY_RATE), + float_to_fp8_24(181.540166204986 / FREQUENCY_RATE), + float_to_fp8_24(182.044444444444 / FREQUENCY_RATE), + float_to_fp8_24(182.551532033426 / FREQUENCY_RATE), + float_to_fp8_24(183.061452513966 / FREQUENCY_RATE), + float_to_fp8_24(183.574229691877 / FREQUENCY_RATE), + float_to_fp8_24(184.089887640449 / FREQUENCY_RATE), + float_to_fp8_24(184.608450704225 / FREQUENCY_RATE), + float_to_fp8_24(185.129943502825 / FREQUENCY_RATE), + float_to_fp8_24(185.654390934844 / FREQUENCY_RATE), + float_to_fp8_24(186.181818181818 / FREQUENCY_RATE), + float_to_fp8_24(186.712250712251 / FREQUENCY_RATE), + float_to_fp8_24(187.245714285714 / FREQUENCY_RATE), + float_to_fp8_24(187.78223495702 / FREQUENCY_RATE), + float_to_fp8_24(188.32183908046 / FREQUENCY_RATE), + float_to_fp8_24(188.864553314121 / FREQUENCY_RATE), + float_to_fp8_24(189.410404624277 / FREQUENCY_RATE), + float_to_fp8_24(189.959420289855 / FREQUENCY_RATE), + float_to_fp8_24(190.511627906977 / FREQUENCY_RATE), + float_to_fp8_24(191.067055393586 / FREQUENCY_RATE), + float_to_fp8_24(191.625730994152 / FREQUENCY_RATE), + float_to_fp8_24(192.187683284457 / FREQUENCY_RATE), + float_to_fp8_24(192.752941176471 / FREQUENCY_RATE), + float_to_fp8_24(193.321533923304 / FREQUENCY_RATE), + float_to_fp8_24(193.89349112426 / FREQUENCY_RATE), + float_to_fp8_24(194.46884272997 / FREQUENCY_RATE), + float_to_fp8_24(195.047619047619 / FREQUENCY_RATE), + float_to_fp8_24(195.629850746269 / FREQUENCY_RATE), + float_to_fp8_24(196.215568862275 / FREQUENCY_RATE), + float_to_fp8_24(196.804804804805 / FREQUENCY_RATE), + float_to_fp8_24(197.397590361446 / FREQUENCY_RATE), + float_to_fp8_24(197.993957703928 / FREQUENCY_RATE), + float_to_fp8_24(198.593939393939 / FREQUENCY_RATE), + float_to_fp8_24(199.197568389058 / FREQUENCY_RATE), + float_to_fp8_24(199.804878048781 / FREQUENCY_RATE), + float_to_fp8_24(200.415902140673 / FREQUENCY_RATE), + float_to_fp8_24(201.030674846626 / FREQUENCY_RATE), + float_to_fp8_24(201.649230769231 / FREQUENCY_RATE), + float_to_fp8_24(202.271604938272 / FREQUENCY_RATE), + float_to_fp8_24(202.897832817337 / FREQUENCY_RATE), + float_to_fp8_24(203.527950310559 / FREQUENCY_RATE), + float_to_fp8_24(204.16199376947 / FREQUENCY_RATE), + float_to_fp8_24(204.8 / FREQUENCY_RATE), + float_to_fp8_24(205.442006269592 / FREQUENCY_RATE), + float_to_fp8_24(206.088050314465 / FREQUENCY_RATE), + float_to_fp8_24(206.738170347003 / FREQUENCY_RATE), + float_to_fp8_24(207.392405063291 / FREQUENCY_RATE), + float_to_fp8_24(208.050793650794 / FREQUENCY_RATE), + float_to_fp8_24(208.713375796178 / FREQUENCY_RATE), + float_to_fp8_24(209.380191693291 / FREQUENCY_RATE), + float_to_fp8_24(210.051282051282 / FREQUENCY_RATE), + float_to_fp8_24(210.726688102894 / FREQUENCY_RATE), + float_to_fp8_24(211.406451612903 / FREQUENCY_RATE), + float_to_fp8_24(212.090614886731 / FREQUENCY_RATE), + float_to_fp8_24(212.779220779221 / FREQUENCY_RATE), + float_to_fp8_24(213.472312703583 / FREQUENCY_RATE), + float_to_fp8_24(214.169934640523 / FREQUENCY_RATE), + float_to_fp8_24(214.872131147541 / FREQUENCY_RATE), + float_to_fp8_24(215.578947368421 / FREQUENCY_RATE), + float_to_fp8_24(216.290429042904 / FREQUENCY_RATE), + float_to_fp8_24(217.006622516556 / FREQUENCY_RATE), + float_to_fp8_24(217.727574750831 / FREQUENCY_RATE), + float_to_fp8_24(218.453333333333 / FREQUENCY_RATE), + float_to_fp8_24(219.183946488294 / FREQUENCY_RATE), + float_to_fp8_24(219.919463087248 / FREQUENCY_RATE), + float_to_fp8_24(220.659932659933 / FREQUENCY_RATE), + float_to_fp8_24(221.405405405405 / FREQUENCY_RATE), + float_to_fp8_24(222.15593220339 / FREQUENCY_RATE), + float_to_fp8_24(222.91156462585 / FREQUENCY_RATE), + float_to_fp8_24(223.672354948805 / FREQUENCY_RATE), + float_to_fp8_24(224.438356164384 / FREQUENCY_RATE), + float_to_fp8_24(225.209621993127 / FREQUENCY_RATE), + float_to_fp8_24(225.986206896552 / FREQUENCY_RATE), + float_to_fp8_24(226.768166089965 / FREQUENCY_RATE), + float_to_fp8_24(227.555555555556 / FREQUENCY_RATE), + float_to_fp8_24(228.348432055749 / FREQUENCY_RATE), + float_to_fp8_24(229.146853146853 / FREQUENCY_RATE), + float_to_fp8_24(229.950877192982 / FREQUENCY_RATE), + float_to_fp8_24(230.760563380282 / FREQUENCY_RATE), + float_to_fp8_24(231.575971731449 / FREQUENCY_RATE), + float_to_fp8_24(232.397163120567 / FREQUENCY_RATE), + float_to_fp8_24(233.224199288256 / FREQUENCY_RATE), + float_to_fp8_24(234.057142857143 / FREQUENCY_RATE), + float_to_fp8_24(234.89605734767 / FREQUENCY_RATE), + float_to_fp8_24(235.741007194245 / FREQUENCY_RATE), + float_to_fp8_24(236.592057761733 / FREQUENCY_RATE), + float_to_fp8_24(237.449275362319 / FREQUENCY_RATE), + float_to_fp8_24(238.312727272727 / FREQUENCY_RATE), + float_to_fp8_24(239.182481751825 / FREQUENCY_RATE), + float_to_fp8_24(240.058608058608 / FREQUENCY_RATE), + float_to_fp8_24(240.941176470588 / FREQUENCY_RATE), + float_to_fp8_24(241.830258302583 / FREQUENCY_RATE), + float_to_fp8_24(242.725925925926 / FREQUENCY_RATE), + float_to_fp8_24(243.628252788104 / FREQUENCY_RATE), + float_to_fp8_24(244.537313432836 / FREQUENCY_RATE), + float_to_fp8_24(245.453183520599 / FREQUENCY_RATE), + float_to_fp8_24(246.375939849624 / FREQUENCY_RATE), + float_to_fp8_24(247.305660377358 / FREQUENCY_RATE), + float_to_fp8_24(248.242424242424 / FREQUENCY_RATE), + float_to_fp8_24(249.186311787072 / FREQUENCY_RATE), + float_to_fp8_24(250.137404580153 / FREQUENCY_RATE), + float_to_fp8_24(251.095785440613 / FREQUENCY_RATE), + float_to_fp8_24(252.061538461538 / FREQUENCY_RATE), + float_to_fp8_24(253.034749034749 / FREQUENCY_RATE), + float_to_fp8_24(254.015503875969 / FREQUENCY_RATE), + float_to_fp8_24(255.003891050584 / FREQUENCY_RATE), + float_to_fp8_24(256 / FREQUENCY_RATE), + float_to_fp8_24(257.003921568627 / FREQUENCY_RATE), + float_to_fp8_24(258.015748031496 / FREQUENCY_RATE), + float_to_fp8_24(259.03557312253 / FREQUENCY_RATE), + float_to_fp8_24(260.063492063492 / FREQUENCY_RATE), + float_to_fp8_24(261.099601593625 / FREQUENCY_RATE), + float_to_fp8_24(262.144 / FREQUENCY_RATE), + float_to_fp8_24(263.196787148594 / FREQUENCY_RATE), + float_to_fp8_24(264.258064516129 / FREQUENCY_RATE), + float_to_fp8_24(265.327935222672 / FREQUENCY_RATE), + float_to_fp8_24(266.406504065041 / FREQUENCY_RATE), + float_to_fp8_24(267.49387755102 / FREQUENCY_RATE), + float_to_fp8_24(268.590163934426 / FREQUENCY_RATE), + float_to_fp8_24(269.695473251029 / FREQUENCY_RATE), + float_to_fp8_24(270.809917355372 / FREQUENCY_RATE), + float_to_fp8_24(271.933609958506 / FREQUENCY_RATE), + float_to_fp8_24(273.066666666667 / FREQUENCY_RATE), + float_to_fp8_24(274.20920502092 / FREQUENCY_RATE), + float_to_fp8_24(275.361344537815 / FREQUENCY_RATE), + float_to_fp8_24(276.523206751055 / FREQUENCY_RATE), + float_to_fp8_24(277.694915254237 / FREQUENCY_RATE), + float_to_fp8_24(278.876595744681 / FREQUENCY_RATE), + float_to_fp8_24(280.068376068376 / FREQUENCY_RATE), + float_to_fp8_24(281.270386266094 / FREQUENCY_RATE), + float_to_fp8_24(282.48275862069 / FREQUENCY_RATE), + float_to_fp8_24(283.705627705628 / FREQUENCY_RATE), + float_to_fp8_24(284.939130434783 / FREQUENCY_RATE), + float_to_fp8_24(286.183406113537 / FREQUENCY_RATE), + float_to_fp8_24(287.438596491228 / FREQUENCY_RATE), + float_to_fp8_24(288.704845814978 / FREQUENCY_RATE), + float_to_fp8_24(289.982300884956 / FREQUENCY_RATE), + float_to_fp8_24(291.271111111111 / FREQUENCY_RATE), + float_to_fp8_24(292.571428571429 / FREQUENCY_RATE), + float_to_fp8_24(293.883408071749 / FREQUENCY_RATE), + float_to_fp8_24(295.207207207207 / FREQUENCY_RATE), + float_to_fp8_24(296.542986425339 / FREQUENCY_RATE), + float_to_fp8_24(297.890909090909 / FREQUENCY_RATE), + float_to_fp8_24(299.251141552511 / FREQUENCY_RATE), + float_to_fp8_24(300.623853211009 / FREQUENCY_RATE), + float_to_fp8_24(302.009216589862 / FREQUENCY_RATE), + float_to_fp8_24(303.407407407407 / FREQUENCY_RATE), + float_to_fp8_24(304.818604651163 / FREQUENCY_RATE), + float_to_fp8_24(306.242990654206 / FREQUENCY_RATE), + float_to_fp8_24(307.680751173709 / FREQUENCY_RATE), + float_to_fp8_24(309.132075471698 / FREQUENCY_RATE), + float_to_fp8_24(310.597156398104 / FREQUENCY_RATE), + float_to_fp8_24(312.07619047619 / FREQUENCY_RATE), + float_to_fp8_24(313.569377990431 / FREQUENCY_RATE), + float_to_fp8_24(315.076923076923 / FREQUENCY_RATE), + float_to_fp8_24(316.599033816425 / FREQUENCY_RATE), + float_to_fp8_24(318.135922330097 / FREQUENCY_RATE), + float_to_fp8_24(319.687804878049 / FREQUENCY_RATE), + float_to_fp8_24(321.254901960784 / FREQUENCY_RATE), + float_to_fp8_24(322.837438423645 / FREQUENCY_RATE), + float_to_fp8_24(324.435643564356 / FREQUENCY_RATE), + float_to_fp8_24(326.049751243781 / FREQUENCY_RATE), + float_to_fp8_24(327.68 / FREQUENCY_RATE), + float_to_fp8_24(329.326633165829 / FREQUENCY_RATE), + float_to_fp8_24(330.989898989899 / FREQUENCY_RATE), + float_to_fp8_24(332.670050761421 / FREQUENCY_RATE), + float_to_fp8_24(334.367346938775 / FREQUENCY_RATE), + float_to_fp8_24(336.082051282051 / FREQUENCY_RATE), + float_to_fp8_24(337.814432989691 / FREQUENCY_RATE), + float_to_fp8_24(339.564766839378 / FREQUENCY_RATE), + float_to_fp8_24(341.333333333333 / FREQUENCY_RATE), + float_to_fp8_24(343.120418848168 / FREQUENCY_RATE), + float_to_fp8_24(344.926315789474 / FREQUENCY_RATE), + float_to_fp8_24(346.751322751323 / FREQUENCY_RATE), + float_to_fp8_24(348.595744680851 / FREQUENCY_RATE), + float_to_fp8_24(350.459893048128 / FREQUENCY_RATE), + float_to_fp8_24(352.344086021505 / FREQUENCY_RATE), + float_to_fp8_24(354.248648648649 / FREQUENCY_RATE), + float_to_fp8_24(356.173913043478 / FREQUENCY_RATE), + float_to_fp8_24(358.120218579235 / FREQUENCY_RATE), + float_to_fp8_24(360.087912087912 / FREQUENCY_RATE), + float_to_fp8_24(362.077348066298 / FREQUENCY_RATE), + float_to_fp8_24(364.088888888889 / FREQUENCY_RATE), + float_to_fp8_24(366.122905027933 / FREQUENCY_RATE), + float_to_fp8_24(368.179775280899 / FREQUENCY_RATE), + float_to_fp8_24(370.25988700565 / FREQUENCY_RATE), + float_to_fp8_24(372.363636363636 / FREQUENCY_RATE), + float_to_fp8_24(374.491428571429 / FREQUENCY_RATE), + float_to_fp8_24(376.64367816092 / FREQUENCY_RATE), + float_to_fp8_24(378.820809248555 / FREQUENCY_RATE), + float_to_fp8_24(381.023255813953 / FREQUENCY_RATE), + float_to_fp8_24(383.251461988304 / FREQUENCY_RATE), + float_to_fp8_24(385.505882352941 / FREQUENCY_RATE), + float_to_fp8_24(387.786982248521 / FREQUENCY_RATE), + float_to_fp8_24(390.095238095238 / FREQUENCY_RATE), + float_to_fp8_24(392.431137724551 / FREQUENCY_RATE), + float_to_fp8_24(394.795180722892 / FREQUENCY_RATE), + float_to_fp8_24(397.187878787879 / FREQUENCY_RATE), + float_to_fp8_24(399.609756097561 / FREQUENCY_RATE), + float_to_fp8_24(402.061349693252 / FREQUENCY_RATE), + float_to_fp8_24(404.543209876543 / FREQUENCY_RATE), + float_to_fp8_24(407.055900621118 / FREQUENCY_RATE), + float_to_fp8_24(409.6 / FREQUENCY_RATE), + float_to_fp8_24(412.176100628931 / FREQUENCY_RATE), + float_to_fp8_24(414.784810126582 / FREQUENCY_RATE), + float_to_fp8_24(417.426751592357 / FREQUENCY_RATE), + float_to_fp8_24(420.102564102564 / FREQUENCY_RATE), + float_to_fp8_24(422.812903225807 / FREQUENCY_RATE), + float_to_fp8_24(425.558441558442 / FREQUENCY_RATE), + float_to_fp8_24(428.339869281046 / FREQUENCY_RATE), + float_to_fp8_24(431.157894736842 / FREQUENCY_RATE), + float_to_fp8_24(434.013245033113 / FREQUENCY_RATE), + float_to_fp8_24(436.906666666667 / FREQUENCY_RATE), + float_to_fp8_24(439.838926174497 / FREQUENCY_RATE), + float_to_fp8_24(442.810810810811 / FREQUENCY_RATE), + float_to_fp8_24(445.823129251701 / FREQUENCY_RATE), + float_to_fp8_24(448.876712328767 / FREQUENCY_RATE), + float_to_fp8_24(451.972413793103 / FREQUENCY_RATE), + float_to_fp8_24(455.111111111111 / FREQUENCY_RATE), + float_to_fp8_24(458.293706293706 / FREQUENCY_RATE), + float_to_fp8_24(461.521126760563 / FREQUENCY_RATE), + float_to_fp8_24(464.794326241135 / FREQUENCY_RATE), + float_to_fp8_24(468.114285714286 / FREQUENCY_RATE), + float_to_fp8_24(471.482014388489 / FREQUENCY_RATE), + float_to_fp8_24(474.898550724638 / FREQUENCY_RATE), + float_to_fp8_24(478.36496350365 / FREQUENCY_RATE), + float_to_fp8_24(481.882352941176 / FREQUENCY_RATE), + float_to_fp8_24(485.451851851852 / FREQUENCY_RATE), + float_to_fp8_24(489.074626865672 / FREQUENCY_RATE), + float_to_fp8_24(492.751879699248 / FREQUENCY_RATE), + float_to_fp8_24(496.484848484849 / FREQUENCY_RATE), + float_to_fp8_24(500.274809160305 / FREQUENCY_RATE), + float_to_fp8_24(504.123076923077 / FREQUENCY_RATE), + float_to_fp8_24(508.031007751938 / FREQUENCY_RATE), + float_to_fp8_24(512 / FREQUENCY_RATE), + float_to_fp8_24(516.031496062992 / FREQUENCY_RATE), + float_to_fp8_24(520.126984126984 / FREQUENCY_RATE), + float_to_fp8_24(524.288 / FREQUENCY_RATE), + float_to_fp8_24(528.516129032258 / FREQUENCY_RATE), + float_to_fp8_24(532.813008130081 / FREQUENCY_RATE), + float_to_fp8_24(537.180327868852 / FREQUENCY_RATE), + float_to_fp8_24(541.619834710744 / FREQUENCY_RATE), + float_to_fp8_24(546.133333333333 / FREQUENCY_RATE), + float_to_fp8_24(550.72268907563 / FREQUENCY_RATE), + float_to_fp8_24(555.389830508475 / FREQUENCY_RATE), + float_to_fp8_24(560.136752136752 / FREQUENCY_RATE), + float_to_fp8_24(564.965517241379 / FREQUENCY_RATE), + float_to_fp8_24(569.878260869565 / FREQUENCY_RATE), + float_to_fp8_24(574.877192982456 / FREQUENCY_RATE), + float_to_fp8_24(579.964601769912 / FREQUENCY_RATE), + float_to_fp8_24(585.142857142857 / FREQUENCY_RATE), + float_to_fp8_24(590.414414414414 / FREQUENCY_RATE), + float_to_fp8_24(595.781818181818 / FREQUENCY_RATE), + float_to_fp8_24(601.247706422018 / FREQUENCY_RATE), + float_to_fp8_24(606.814814814815 / FREQUENCY_RATE), + float_to_fp8_24(612.485981308411 / FREQUENCY_RATE), + float_to_fp8_24(618.264150943396 / FREQUENCY_RATE), + float_to_fp8_24(624.152380952381 / FREQUENCY_RATE), + float_to_fp8_24(630.153846153846 / FREQUENCY_RATE), + float_to_fp8_24(636.271844660194 / FREQUENCY_RATE), + float_to_fp8_24(642.509803921569 / FREQUENCY_RATE), + float_to_fp8_24(648.871287128713 / FREQUENCY_RATE), + float_to_fp8_24(655.36 / FREQUENCY_RATE), + float_to_fp8_24(661.979797979798 / FREQUENCY_RATE), + float_to_fp8_24(668.734693877551 / FREQUENCY_RATE), + float_to_fp8_24(675.628865979381 / FREQUENCY_RATE), + float_to_fp8_24(682.666666666667 / FREQUENCY_RATE), + float_to_fp8_24(689.852631578947 / FREQUENCY_RATE), + float_to_fp8_24(697.191489361702 / FREQUENCY_RATE), + float_to_fp8_24(704.688172043011 / FREQUENCY_RATE), + float_to_fp8_24(712.347826086956 / FREQUENCY_RATE), + float_to_fp8_24(720.175824175824 / FREQUENCY_RATE), + float_to_fp8_24(728.177777777778 / FREQUENCY_RATE), + float_to_fp8_24(736.359550561798 / FREQUENCY_RATE), + float_to_fp8_24(744.727272727273 / FREQUENCY_RATE), + float_to_fp8_24(753.287356321839 / FREQUENCY_RATE), + float_to_fp8_24(762.046511627907 / FREQUENCY_RATE), + float_to_fp8_24(771.011764705882 / FREQUENCY_RATE), + float_to_fp8_24(780.190476190476 / FREQUENCY_RATE), + float_to_fp8_24(789.590361445783 / FREQUENCY_RATE), + float_to_fp8_24(799.219512195122 / FREQUENCY_RATE), + float_to_fp8_24(809.086419753086 / FREQUENCY_RATE), + float_to_fp8_24(819.2 / FREQUENCY_RATE), + float_to_fp8_24(829.569620253165 / FREQUENCY_RATE), + float_to_fp8_24(840.205128205128 / FREQUENCY_RATE), + float_to_fp8_24(851.116883116883 / FREQUENCY_RATE), + float_to_fp8_24(862.315789473684 / FREQUENCY_RATE), + float_to_fp8_24(873.813333333333 / FREQUENCY_RATE), + float_to_fp8_24(885.621621621622 / FREQUENCY_RATE), + float_to_fp8_24(897.753424657534 / FREQUENCY_RATE), + float_to_fp8_24(910.222222222222 / FREQUENCY_RATE), + float_to_fp8_24(923.042253521127 / FREQUENCY_RATE), + float_to_fp8_24(936.228571428571 / FREQUENCY_RATE), + float_to_fp8_24(949.797101449275 / FREQUENCY_RATE), + float_to_fp8_24(963.764705882353 / FREQUENCY_RATE), + float_to_fp8_24(978.149253731343 / FREQUENCY_RATE), + float_to_fp8_24(992.969696969697 / FREQUENCY_RATE), + float_to_fp8_24(1008.24615384615 / FREQUENCY_RATE), + float_to_fp8_24(1024 / FREQUENCY_RATE), + float_to_fp8_24(1040.25396825397 / FREQUENCY_RATE), + float_to_fp8_24(1057.03225806452 / FREQUENCY_RATE), + float_to_fp8_24(1074.36065573771 / FREQUENCY_RATE), + float_to_fp8_24(1092.26666666667 / FREQUENCY_RATE), + float_to_fp8_24(1110.77966101695 / FREQUENCY_RATE), + float_to_fp8_24(1129.93103448276 / FREQUENCY_RATE), + float_to_fp8_24(1149.75438596491 / FREQUENCY_RATE), + float_to_fp8_24(1170.28571428571 / FREQUENCY_RATE), + float_to_fp8_24(1191.56363636364 / FREQUENCY_RATE), + float_to_fp8_24(1213.62962962963 / FREQUENCY_RATE), + float_to_fp8_24(1236.52830188679 / FREQUENCY_RATE), + float_to_fp8_24(1260.30769230769 / FREQUENCY_RATE), + float_to_fp8_24(1285.01960784314 / FREQUENCY_RATE), + float_to_fp8_24(1310.72 / FREQUENCY_RATE), + float_to_fp8_24(1337.4693877551 / FREQUENCY_RATE), + float_to_fp8_24(1365.33333333333 / FREQUENCY_RATE), + float_to_fp8_24(1394.3829787234 / FREQUENCY_RATE), + float_to_fp8_24(1424.69565217391 / FREQUENCY_RATE), + float_to_fp8_24(1456.35555555556 / FREQUENCY_RATE), + float_to_fp8_24(1489.45454545455 / FREQUENCY_RATE), + float_to_fp8_24(1524.09302325581 / FREQUENCY_RATE), + float_to_fp8_24(1560.38095238095 / FREQUENCY_RATE), + float_to_fp8_24(1598.43902439024 / FREQUENCY_RATE), + float_to_fp8_24(1638.4 / FREQUENCY_RATE), + float_to_fp8_24(1680.41025641026 / FREQUENCY_RATE), + float_to_fp8_24(1724.63157894737 / FREQUENCY_RATE), + float_to_fp8_24(1771.24324324324 / FREQUENCY_RATE), + float_to_fp8_24(1820.44444444444 / FREQUENCY_RATE), + float_to_fp8_24(1872.45714285714 / FREQUENCY_RATE), + float_to_fp8_24(1927.52941176471 / FREQUENCY_RATE), + float_to_fp8_24(1985.93939393939 / FREQUENCY_RATE), + float_to_fp8_24(2048 / FREQUENCY_RATE), + float_to_fp8_24(2114.06451612903 / FREQUENCY_RATE), + float_to_fp8_24(2184.53333333333 / FREQUENCY_RATE), + float_to_fp8_24(2259.86206896552 / FREQUENCY_RATE), + float_to_fp8_24(2340.57142857143 / FREQUENCY_RATE), + float_to_fp8_24(2427.25925925926 / FREQUENCY_RATE), + float_to_fp8_24(2520.61538461538 / FREQUENCY_RATE), + float_to_fp8_24(2621.44 / FREQUENCY_RATE), + float_to_fp8_24(2730.66666666667 / FREQUENCY_RATE), + float_to_fp8_24(2849.39130434783 / FREQUENCY_RATE), + float_to_fp8_24(2978.90909090909 / FREQUENCY_RATE), + float_to_fp8_24(3120.7619047619 / FREQUENCY_RATE), + float_to_fp8_24(3276.8 / FREQUENCY_RATE), + float_to_fp8_24(3449.26315789474 / FREQUENCY_RATE), + float_to_fp8_24(3640.88888888889 / FREQUENCY_RATE), + float_to_fp8_24(3855.05882352941 / FREQUENCY_RATE), + float_to_fp8_24(4096 / FREQUENCY_RATE), + float_to_fp8_24(4369.06666666667 / FREQUENCY_RATE), + float_to_fp8_24(4681.14285714286 / FREQUENCY_RATE), + float_to_fp8_24(5041.23076923077 / FREQUENCY_RATE), + float_to_fp8_24(5461.33333333333 / FREQUENCY_RATE), + float_to_fp8_24(5957.81818181818 / FREQUENCY_RATE), + float_to_fp8_24(6553.6 / FREQUENCY_RATE), + float_to_fp8_24(7281.77777777778 / FREQUENCY_RATE), + float_to_fp8_24(8192 / FREQUENCY_RATE), + float_to_fp8_24(9362.28571428571 / FREQUENCY_RATE), + float_to_fp8_24(10922.6666666667 / FREQUENCY_RATE), + float_to_fp8_24(13107.2 / FREQUENCY_RATE), + float_to_fp8_24(16384 / FREQUENCY_RATE), + float_to_fp8_24(21845.3333333333 / FREQUENCY_RATE), + float_to_fp8_24(32768 / FREQUENCY_RATE), + float_to_fp8_24(65536 / FREQUENCY_RATE), }; const fixed16_16 freqTableNSE[256] = { diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index a5dfacb3af..630eb28b54 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -344,8 +344,8 @@ int main(int argc, char **argv) if (SDL_OpenAudio(&want, 0) < 0) { SDL_Log("Failed to open audio: %s", SDL_GetError()); } else { - if (want.format != AUDIO_F32) /* we let this one thing change. */ - SDL_Log("We didn't get Float32 audio format."); + if (want.format != AUDIO_S16) /* we let this one thing change. */ + SDL_Log("We didn't get S16 audio format."); SDL_PauseAudio(0); } #endif diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 7fcfb3a547..b6662beea7 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -3,7 +3,7 @@ #include "platform/shared/audio/cgb_tables.h" static struct AudioCGB gb; -static fixed16_16 soundChannelPos[4]; +static fixed8_24 soundChannelPos[4]; static const fixed16_16 *PU1Table; static const fixed16_16 *PU2Table; static u32 apuFrame; @@ -32,7 +32,7 @@ void cgb_audio_init(u32 rate) gb.DAC[ch] = 0; soundChannelPos[ch] = 0; } - soundChannelPos[1] = 1; + soundChannelPos[1] = u32_to_fp8_24(1); PU1Table = PU0; PU2Table = PU0; sampleRate = rate; @@ -203,35 +203,34 @@ void cgb_audio_generate(u16 samplesPerFrame) } } // Sound generation loop - soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & 0x7FF]; - soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & 0x7FF]; - soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & 0x7FF]; - while (soundChannelPos[0] >= u32_to_fp16_16(32)) - soundChannelPos[0] -= u32_to_fp16_16(32); - while (soundChannelPos[1] >= u32_to_fp16_16(32)) - soundChannelPos[1] -= u32_to_fp16_16(32); - while (soundChannelPos[2] >= u32_to_fp16_16(32)) - soundChannelPos[2] -= u32_to_fp16_16(32); + soundChannelPos[0] += freqTable[REG_SOUND1CNT_X & (ARRAY_COUNT(freqTable) - 1)]; + soundChannelPos[1] += freqTable[REG_SOUND2CNT_H & (ARRAY_COUNT(freqTable) - 1)]; + soundChannelPos[2] += freqTable[REG_SOUND3CNT_X & (ARRAY_COUNT(freqTable) - 1)]; + + soundChannelPos[0] &= (u32_to_fp8_24(32)) - 1; + soundChannelPos[1] &= (u32_to_fp8_24(32)) - 1; + soundChannelPos[2] &= (u32_to_fp8_24(32)) - 1; + fixed16_16 outputL = 0; fixed16_16 outputR = 0; if (REG_NR52 & 0x80) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if (REG_NR51 & 0x10) - outputL += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); + outputL += (gb.Vol[0] * PU1Table[fp8_24_to_u32(soundChannelPos[0])]); if (REG_NR51 & 0x01) - outputR += (gb.Vol[0] * PU1Table[fp16_16_to_u32(soundChannelPos[0])]); + outputR += (gb.Vol[0] * PU1Table[fp8_24_to_u32(soundChannelPos[0])]); } if ((gb.DAC[1]) && (REG_NR52 & 0x02)) { if (REG_NR51 & 0x20) - outputL += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); + outputL += (gb.Vol[1] * PU2Table[fp8_24_to_u32(soundChannelPos[1])]); if (REG_NR51 & 0x02) - outputR += (gb.Vol[1] * PU2Table[fp16_16_to_u32(soundChannelPos[1])]); + outputR += (gb.Vol[1] * PU2Table[fp8_24_to_u32(soundChannelPos[1])]); } if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) { if (REG_NR51 & 0x40) - outputL += (gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] >> 2); + outputL += (gb.Vol[2] * gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2); if (REG_NR51 & 0x04) - outputR += (gb.Vol[2] * gb.WAVRAM[fp16_16_to_u32(soundChannelPos[2])] >> 2); + outputR += (gb.Vol[2] * gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2); } if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); From 98005f31e29a2a896a5462016b71462e045be053 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 22 Feb 2026 03:29:52 +0000 Subject: [PATCH 24/51] switch audio to 8.24, more performance improvements --- include/lib/m4a/m4a_internal.h | 36 +- include/platform/shared/audio/cgb_audio.h | 6 +- include/platform/shared/audio/cgb_tables.h | 586 ++++++++++---------- src/platform/shared/audio/cgb_audio.c | 50 +- src/platform/shared/audio/m4a_sound_mixer.c | 67 +-- 5 files changed, 359 insertions(+), 386 deletions(-) diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 247823a98c..241b4510ae 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -106,34 +106,14 @@ #define MAX_LINES 0 #endif -typedef s32 fixed16_16; +#if !PLATFORM_GBA typedef s32 fixed8_24; - -#define float_to_fp16_16(value) (fixed16_16)((value)*65536.0f) - -#define fp16_16_to_float(value) (float)((value) / 65536.0f) - -#define u32_to_fp16_16(value) ((value) << 16) - -#define fp16_16_to_u32(value) ((value) >> 16) - -#define fp16_16_fractional_part(value) ((value)&0xFFFF) - -#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0) -#define u32_to_fp8_24(value) ((value) << 24) -#define fp8_24_to_u32(value) ((value) >> 24) - -#define fp8_24_to_float(value) (float)((value) / 16777216.0) - +#define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0f) +#define u32_to_fp8_24(value) ((value) << 24) +#define fp8_24_to_u32(value) ((value) >> 24) +#define fp8_24_to_float(value) (float)((value) / 16777216.0f) #define fp8_24_fractional_part(value) ((value)&0xFFFFFF) - -#define fixed_div(numerator, denominator, bits) (((numerator * (1 << bits)) + (denominator / 2)) / denominator) - -#define address8(base, offset) *((u8 *)((u8 *)base + (offset))) - -#define address16(base, offset) *((u16 *)((u8 *)base + (offset))) - -#define address32(base, offset) *((u32 *)((u8 *)base + (offset))) +#endif struct MP2KTrack; struct MP2KPlayerState; @@ -214,7 +194,7 @@ struct MixerSource { u8 padding5; u32 ct; - fixed16_16 fw; + fixed8_24 fw; u32 freq; } sound; @@ -274,7 +254,7 @@ struct SoundMixerState { #else // TODO: let's not make this float, they are slow // on older systems - fixed16_16 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; + fixed8_24 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; #endif }; diff --git a/include/platform/shared/audio/cgb_audio.h b/include/platform/shared/audio/cgb_audio.h index f2fa7ba54b..8312e496ff 100644 --- a/include/platform/shared/audio/cgb_audio.h +++ b/include/platform/shared/audio/cgb_audio.h @@ -18,9 +18,9 @@ struct AudioCGB { u8 EnvCounterI[4]; bool8 EnvDir[4]; bool8 DAC[4]; - fixed16_16 WAVRAM[32]; + fixed8_24 WAVRAM[32]; u16 ch4LFSR[2]; - fixed16_16 outBuffer[PCM_DMA_BUF_SIZE * 2]; + fixed8_24 outBuffer[PCM_DMA_BUF_SIZE * 2]; }; void cgb_audio_init(u32 rate); @@ -31,6 +31,6 @@ void cgb_set_length(u8 channel, u8 length); void cgb_set_envelope(u8 channel, u8 envelope); void cgb_trigger_note(u8 channel); void cgb_audio_generate(u16 samplesPerFrame); -fixed16_16 *cgb_get_buffer(); +fixed8_24 *cgb_get_buffer(); #endif diff --git a/include/platform/shared/audio/cgb_tables.h b/include/platform/shared/audio/cgb_tables.h index e071661b42..3e5b56b385 100644 --- a/include/platform/shared/audio/cgb_tables.h +++ b/include/platform/shared/audio/cgb_tables.h @@ -6,45 +6,45 @@ #define SAMPLE_RATE 48000.0 #define FREQUENCY_RATE (SAMPLE_RATE / 32.0) -const fixed16_16 PU0[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed8_24 PU0[32] + = { float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15) }; -const fixed16_16 PU1[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed8_24 PU1[32] + = { float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15) }; -const fixed16_16 PU2[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed8_24 PU2[32] + = { float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15) }; -const fixed16_16 PU3[32] - = { float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), float_to_fp16_16(1.0 / 15), - float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15), float_to_fp16_16(-1.0 / 15) }; +const fixed8_24 PU3[32] + = { float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), float_to_fp8_24(1.0 / 15), + float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15), float_to_fp8_24(-1.0 / 15) }; int16_t WAV[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1 }; @@ -2099,263 +2099,263 @@ const fixed8_24 freqTable[2048] = { float_to_fp8_24(65536 / FREQUENCY_RATE), }; -const fixed16_16 freqTableNSE[256] = { - float_to_fp16_16(524288 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(52428.8 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), - float_to_fp16_16(524288 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(87381.3333333333 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(52428.8 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(37449.1428571429 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(26214.4 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), - float_to_fp16_16(262144 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(43690.6666666667 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(26214.4 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(18724.5714285714 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(13107.2 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), - float_to_fp16_16(131072 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(21845.3333333333 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(13107.2 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(9362.28571428571 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(6553.6 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), - float_to_fp16_16(65536 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(10922.6666666667 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(6553.6 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4681.14285714286 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(3276.8 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), - float_to_fp16_16(32768 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(5461.33333333333 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(3276.8 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2340.57142857143 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1638.4 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), - float_to_fp16_16(16384 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2730.66666666667 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1638.4 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1170.28571428571 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(819.2 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(585.142857142857 / SAMPLE_RATE), - float_to_fp16_16(8192 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1365.33333333333 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(819.2 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(585.142857142857 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(409.6 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(292.571428571429 / SAMPLE_RATE), - float_to_fp16_16(4096 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(682.666666666667 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(409.6 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(292.571428571429 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(204.8 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(146.285714285714 / SAMPLE_RATE), - float_to_fp16_16(2048 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(341.333333333333 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(204.8 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(146.285714285714 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(102.4 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), - float_to_fp16_16(1024 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(170.666666666667 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(102.4 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(73.1428571428571 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(51.2 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), - float_to_fp16_16(512 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(85.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(51.2 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(36.5714285714286 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(25.6 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), - float_to_fp16_16(256 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(42.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(25.6 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(18.2857142857143 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(12.8 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), - float_to_fp16_16(128 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(21.3333333333333 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(12.8 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(9.14285714285714 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(6.4 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), - float_to_fp16_16(64 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(10.6666666666667 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(6.4 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4.57142857142857 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(3.2 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), - float_to_fp16_16(32 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(5.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(3.2 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2.28571428571429 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2 / SAMPLE_RATE), - float_to_fp16_16(1.6 / SAMPLE_RATE), - float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), - float_to_fp16_16(16 / SAMPLE_RATE), - float_to_fp16_16(8 / SAMPLE_RATE), - float_to_fp16_16(4 / SAMPLE_RATE), - float_to_fp16_16(2.66666666666667 / SAMPLE_RATE), - float_to_fp16_16(2 / SAMPLE_RATE), - float_to_fp16_16(1.6 / SAMPLE_RATE), - float_to_fp16_16(1.33333333333333 / SAMPLE_RATE), - float_to_fp16_16(1.14285714285714 / SAMPLE_RATE), +const fixed8_24 freqTableNSE[256] = { + float_to_fp8_24(524288 / SAMPLE_RATE), + float_to_fp8_24(262144 / SAMPLE_RATE), + float_to_fp8_24(131072 / SAMPLE_RATE), + float_to_fp8_24(87381.3333333333 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(52428.8 / SAMPLE_RATE), + float_to_fp8_24(43690.6666666667 / SAMPLE_RATE), + float_to_fp8_24(37449.1428571429 / SAMPLE_RATE), + float_to_fp8_24(524288 / SAMPLE_RATE), + float_to_fp8_24(262144 / SAMPLE_RATE), + float_to_fp8_24(131072 / SAMPLE_RATE), + float_to_fp8_24(87381.3333333333 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(52428.8 / SAMPLE_RATE), + float_to_fp8_24(43690.6666666667 / SAMPLE_RATE), + float_to_fp8_24(37449.1428571429 / SAMPLE_RATE), + float_to_fp8_24(262144 / SAMPLE_RATE), + float_to_fp8_24(131072 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(43690.6666666667 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(26214.4 / SAMPLE_RATE), + float_to_fp8_24(21845.3333333333 / SAMPLE_RATE), + float_to_fp8_24(18724.5714285714 / SAMPLE_RATE), + float_to_fp8_24(262144 / SAMPLE_RATE), + float_to_fp8_24(131072 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(43690.6666666667 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(26214.4 / SAMPLE_RATE), + float_to_fp8_24(21845.3333333333 / SAMPLE_RATE), + float_to_fp8_24(18724.5714285714 / SAMPLE_RATE), + float_to_fp8_24(131072 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(21845.3333333333 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(13107.2 / SAMPLE_RATE), + float_to_fp8_24(10922.6666666667 / SAMPLE_RATE), + float_to_fp8_24(9362.28571428571 / SAMPLE_RATE), + float_to_fp8_24(131072 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(21845.3333333333 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(13107.2 / SAMPLE_RATE), + float_to_fp8_24(10922.6666666667 / SAMPLE_RATE), + float_to_fp8_24(9362.28571428571 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(10922.6666666667 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(6553.6 / SAMPLE_RATE), + float_to_fp8_24(5461.33333333333 / SAMPLE_RATE), + float_to_fp8_24(4681.14285714286 / SAMPLE_RATE), + float_to_fp8_24(65536 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(10922.6666666667 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(6553.6 / SAMPLE_RATE), + float_to_fp8_24(5461.33333333333 / SAMPLE_RATE), + float_to_fp8_24(4681.14285714286 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(5461.33333333333 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(3276.8 / SAMPLE_RATE), + float_to_fp8_24(2730.66666666667 / SAMPLE_RATE), + float_to_fp8_24(2340.57142857143 / SAMPLE_RATE), + float_to_fp8_24(32768 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(5461.33333333333 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(3276.8 / SAMPLE_RATE), + float_to_fp8_24(2730.66666666667 / SAMPLE_RATE), + float_to_fp8_24(2340.57142857143 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(2730.66666666667 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1638.4 / SAMPLE_RATE), + float_to_fp8_24(1365.33333333333 / SAMPLE_RATE), + float_to_fp8_24(1170.28571428571 / SAMPLE_RATE), + float_to_fp8_24(16384 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(2730.66666666667 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1638.4 / SAMPLE_RATE), + float_to_fp8_24(1365.33333333333 / SAMPLE_RATE), + float_to_fp8_24(1170.28571428571 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1365.33333333333 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(819.2 / SAMPLE_RATE), + float_to_fp8_24(682.666666666667 / SAMPLE_RATE), + float_to_fp8_24(585.142857142857 / SAMPLE_RATE), + float_to_fp8_24(8192 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1365.33333333333 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(819.2 / SAMPLE_RATE), + float_to_fp8_24(682.666666666667 / SAMPLE_RATE), + float_to_fp8_24(585.142857142857 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(682.666666666667 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(409.6 / SAMPLE_RATE), + float_to_fp8_24(341.333333333333 / SAMPLE_RATE), + float_to_fp8_24(292.571428571429 / SAMPLE_RATE), + float_to_fp8_24(4096 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(682.666666666667 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(409.6 / SAMPLE_RATE), + float_to_fp8_24(341.333333333333 / SAMPLE_RATE), + float_to_fp8_24(292.571428571429 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(341.333333333333 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(204.8 / SAMPLE_RATE), + float_to_fp8_24(170.666666666667 / SAMPLE_RATE), + float_to_fp8_24(146.285714285714 / SAMPLE_RATE), + float_to_fp8_24(2048 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(341.333333333333 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(204.8 / SAMPLE_RATE), + float_to_fp8_24(170.666666666667 / SAMPLE_RATE), + float_to_fp8_24(146.285714285714 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(170.666666666667 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(102.4 / SAMPLE_RATE), + float_to_fp8_24(85.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(73.1428571428571 / SAMPLE_RATE), + float_to_fp8_24(1024 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(170.666666666667 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(102.4 / SAMPLE_RATE), + float_to_fp8_24(85.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(73.1428571428571 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(85.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(51.2 / SAMPLE_RATE), + float_to_fp8_24(42.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(36.5714285714286 / SAMPLE_RATE), + float_to_fp8_24(512 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(85.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(51.2 / SAMPLE_RATE), + float_to_fp8_24(42.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(36.5714285714286 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(42.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(25.6 / SAMPLE_RATE), + float_to_fp8_24(21.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(18.2857142857143 / SAMPLE_RATE), + float_to_fp8_24(256 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(42.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(25.6 / SAMPLE_RATE), + float_to_fp8_24(21.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(18.2857142857143 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(21.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(12.8 / SAMPLE_RATE), + float_to_fp8_24(10.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(9.14285714285714 / SAMPLE_RATE), + float_to_fp8_24(128 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(21.3333333333333 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(12.8 / SAMPLE_RATE), + float_to_fp8_24(10.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(9.14285714285714 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(10.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(8 / SAMPLE_RATE), + float_to_fp8_24(6.4 / SAMPLE_RATE), + float_to_fp8_24(5.33333333333333 / SAMPLE_RATE), + float_to_fp8_24(4.57142857142857 / SAMPLE_RATE), + float_to_fp8_24(64 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(10.6666666666667 / SAMPLE_RATE), + float_to_fp8_24(8 / SAMPLE_RATE), + float_to_fp8_24(6.4 / SAMPLE_RATE), + float_to_fp8_24(5.33333333333333 / SAMPLE_RATE), + float_to_fp8_24(4.57142857142857 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(8 / SAMPLE_RATE), + float_to_fp8_24(5.33333333333333 / SAMPLE_RATE), + float_to_fp8_24(4 / SAMPLE_RATE), + float_to_fp8_24(3.2 / SAMPLE_RATE), + float_to_fp8_24(2.66666666666667 / SAMPLE_RATE), + float_to_fp8_24(2.28571428571429 / SAMPLE_RATE), + float_to_fp8_24(32 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(8 / SAMPLE_RATE), + float_to_fp8_24(5.33333333333333 / SAMPLE_RATE), + float_to_fp8_24(4 / SAMPLE_RATE), + float_to_fp8_24(3.2 / SAMPLE_RATE), + float_to_fp8_24(2.66666666666667 / SAMPLE_RATE), + float_to_fp8_24(2.28571428571429 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(8 / SAMPLE_RATE), + float_to_fp8_24(4 / SAMPLE_RATE), + float_to_fp8_24(2.66666666666667 / SAMPLE_RATE), + float_to_fp8_24(2 / SAMPLE_RATE), + float_to_fp8_24(1.6 / SAMPLE_RATE), + float_to_fp8_24(1.33333333333333 / SAMPLE_RATE), + float_to_fp8_24(1.14285714285714 / SAMPLE_RATE), + float_to_fp8_24(16 / SAMPLE_RATE), + float_to_fp8_24(8 / SAMPLE_RATE), + float_to_fp8_24(4 / SAMPLE_RATE), + float_to_fp8_24(2.66666666666667 / SAMPLE_RATE), + float_to_fp8_24(2 / SAMPLE_RATE), + float_to_fp8_24(1.6 / SAMPLE_RATE), + float_to_fp8_24(1.33333333333333 / SAMPLE_RATE), + float_to_fp8_24(1.14285714285714 / SAMPLE_RATE), }; #endif diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index b6662beea7..618bd5be80 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -4,14 +4,14 @@ static struct AudioCGB gb; static fixed8_24 soundChannelPos[4]; -static const fixed16_16 *PU1Table; -static const fixed16_16 *PU2Table; +static const fixed8_24 *PU1Table; +static const fixed8_24 *PU2Table; static u32 apuFrame; static u8 apuCycle; static u32 sampleRate; static u16 lfsrMax[2]; -fixed16_16 ch4Samples; -fixed16_16 volScale[16]; +fixed8_24 ch4Samples; +fixed8_24 volScale[16]; void cgb_audio_init(u32 rate) { @@ -42,7 +42,7 @@ void cgb_audio_init(u32 rate) lfsrMax[1] = 0x80; ch4Samples = 0; for (int i = 0; i < 16; i++) - volScale[i] = u32_to_fp16_16(i) / 15; + volScale[i] = u32_to_fp8_24(i) / 15; } void cgb_set_sweep(u8 sweep) @@ -55,8 +55,8 @@ void cgb_set_sweep(u8 sweep) void cgb_set_wavram() { for (u8 wavi = 0; wavi < 0x10; wavi++) { - gb.WAVRAM[(wavi << 1)] = (u32_to_fp16_16(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) * 2) / 15 - u32_to_fp16_16(1); - gb.WAVRAM[(wavi << 1) + 1] = (u32_to_fp16_16(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) * 2) / 15 - u32_to_fp16_16(1); + gb.WAVRAM[(wavi << 1)] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0xF0) >> 4) * 2) / 15 - u32_to_fp8_24(1); + gb.WAVRAM[(wavi << 1) + 1] = (u32_to_fp8_24(((*(REG_ADDR_WAVE_RAM0 + wavi)) & 0x0F)) * 2) / 15 - u32_to_fp8_24(1); } } @@ -104,16 +104,9 @@ void cgb_trigger_note(u8 channel) } } -// #include -// #include - -double timeSpentAcc = 0; -int calls = 0; - void cgb_audio_generate(u16 samplesPerFrame) { - // clock_t begin = clock(); - fixed16_16 *outBuffer = gb.outBuffer; + fixed8_24 *outBuffer = gb.outBuffer; switch (REG_NR11 & 0xC0) { case 0x00: PU1Table = PU0; @@ -211,8 +204,8 @@ void cgb_audio_generate(u16 samplesPerFrame) soundChannelPos[1] &= (u32_to_fp8_24(32)) - 1; soundChannelPos[2] &= (u32_to_fp8_24(32)) - 1; - fixed16_16 outputL = 0; - fixed16_16 outputR = 0; + fixed8_24 outputL = 0; + fixed8_24 outputR = 0; if (REG_NR52 & 0x80) { if ((gb.DAC[0]) && (REG_NR52 & 0x01)) { if (REG_NR51 & 0x10) @@ -234,7 +227,7 @@ void cgb_audio_generate(u16 samplesPerFrame) } if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); - ch4Samples += freqTableNSE[REG_SOUND4CNT_H & 0xFF]; + ch4Samples += freqTableNSE[REG_SOUND4CNT_H & (ARRAY_COUNT(freqTableNSE) - 1)]; int ch4Out = 0; if (gb.ch4LFSR[lfsrMode] & 1) { ch4Out++; @@ -242,7 +235,7 @@ void cgb_audio_generate(u16 samplesPerFrame) ch4Out--; } int avgDiv = 1; - while (ch4Samples >= u32_to_fp16_16(1)) { + while (ch4Samples >= u32_to_fp8_24(1)) { avgDiv++; bool8 lfsrCarry = 0; if (gb.ch4LFSR[lfsrMode] & 2) @@ -257,27 +250,22 @@ void cgb_audio_generate(u16 samplesPerFrame) } else { ch4Out--; } - ch4Samples -= u32_to_fp16_16(1); + ch4Samples -= u32_to_fp8_24(1); } - fixed16_16 sample = u32_to_fp16_16(ch4Out); + fixed8_24 sample = u32_to_fp8_24(ch4Out); if (avgDiv > 1) sample /= avgDiv; + + // Muliply by the sample and then shift to make 8.24 again if (REG_NR51 & 0x80) - outputL += ((s64)sample * volScale[gb.Vol[3]]) >> 16; + outputL += ((s64)sample * volScale[gb.Vol[3]]) >> 24; if (REG_NR51 & 0x08) - outputR += ((s64)sample * volScale[gb.Vol[3]]) >> 16; + outputR += ((s64)sample * volScale[gb.Vol[3]]) >> 24; } } outBuffer[0] = (outputL >> 2); outBuffer[1] = (outputR >> 2); } - // clock_t end = clock(); - // double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; - // calls++; - // timeSpentAcc += time_spent; - // if ((calls % 60) == 0) { - // printf("Time spent: %f, avg: %f\n", time_spent, timeSpentAcc / calls); - // } } -fixed16_16 *cgb_get_buffer() { return gb.outBuffer; } +fixed8_24 *cgb_get_buffer() { return gb.outBuffer; } diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index 66b944aa23..c487c0e562 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -5,9 +5,9 @@ #include "platform/platform.h" #include "platform/shared/audio/cgb_audio.h" -static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed16_16 *pcmBuffer, +static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed8_24 *pcmBuffer, u16 samplesPerFrame, float sampleRateReciprocal); -static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed16_16 *pcmBuffer, u8 dmaCounter, +static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed8_24 *pcmBuffer, u8 dmaCounter, u16 maxBufSize); static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav); static void ChnVolSetAsm(struct MixerSource *chan, struct MP2KTrack *track); @@ -57,7 +57,7 @@ void SoundMain(void) mixer->CgbSound(); s32 samplesPerFrame = mixer->samplesPerFrame; - fixed16_16 *pcmBuffer = mixer->pcmBuffer; + fixed8_24 *pcmBuffer = mixer->pcmBuffer; s32 dmaCounter = mixer->dmaCounter; if (dmaCounter > 1) { @@ -68,7 +68,7 @@ void SoundMain(void) cgb_audio_generate(samplesPerFrame); } -static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed16_16 *pcmBuffer, u8 dmaCounter, +static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 samplesPerFrame, fixed8_24 *pcmBuffer, u8 dmaCounter, u16 maxBufSize) { u32 reverb = mixer->reverb; @@ -76,8 +76,8 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa // The vanilla reverb effect outputs a mono sound from four sources: // - L/R channels as they were mixer->framesPerDmaCycle frames ago // - L/R channels as they were (mixer->framesPerDmaCycle - 1) frames ago - fixed16_16 *tmp1 = pcmBuffer; - fixed16_16 *tmp2; + fixed8_24 *tmp1 = pcmBuffer; + fixed8_24 *tmp2; if (dmaCounter == 2) { tmp2 = mixer->pcmBuffer; } else { @@ -85,7 +85,7 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa } u16 i = 0; do { - fixed16_16 s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1]; + fixed8_24 s = tmp1[0] + tmp1[1] + tmp2[0] + tmp2[1]; s = (s * reverb) >> 9; tmp1[0] = tmp1[1] = s; tmp1 += 2; @@ -95,7 +95,7 @@ static void SampleMixer(struct SoundMixerState *mixer, u32 scanlineLimit, u16 sa // memset(pcmBuffer, 0, samplesPerFrame); // memset(pcmBuffer + maxBufSize, 0, samplesPerFrame); for (int i = 0; i < samplesPerFrame; i++) { - fixed16_16 *dst = &pcmBuffer[i * 2]; + fixed8_24 *dst = &pcmBuffer[i * 2]; dst[1] = dst[0] = 0.0f; } } @@ -228,7 +228,7 @@ static inline bool32 TickEnvelope(struct MixerSource *chan, struct WaveData *wav } } -static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed16_16 *pcmBuffer, +static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSource *chan, struct WaveData *wav, fixed8_24 *pcmBuffer, u16 samplesPerFrame, float sampleRateReciprocal) { /*, [[[]]]) {*/ u8 v = chan->data.sound.envelopeVol * (mixer->masterVol + 1) / 16U; @@ -250,8 +250,11 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { s8 c = *(current++); - pcmBuffer[1] += ((s32)c * envR) << 1; - pcmBuffer[0] += ((s32)c * envL) << 1; + // Creates a value between -32768 and 32768 + // So shift by 9 to make this between -1 and 1 + // in 8.24 + pcmBuffer[1] += (c * envR) << 9; + pcmBuffer[0] += (c * envL) << 9; if (--samplesLeftInWav == 0) { samplesLeftInWav = loopLen; if (loopLen != 0) { @@ -266,8 +269,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour chan->data.sound.ct = samplesLeftInWav; chan->current = current; } else { - fixed16_16 finePos = chan->data.sound.fw; - fixed16_16 romSamplesPerOutputSample = float_to_fp16_16(chan->data.sound.freq * sampleRateReciprocal); + fixed8_24 finePos = chan->data.sound.fw; + fixed8_24 romSamplesPerOutputSample = float_to_fp8_24(chan->data.sound.freq * sampleRateReciprocal); s16 b = current[0]; s16 m = current[1] - b; @@ -276,15 +279,15 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { // Use linear interpolation to calculate a value between the current sample in the wav // and the next sample. Also cancel out the 9.23 stuff - s32 sample = fp16_16_to_u32(finePos * m) + b; + fixed8_24 sample = (((s64)finePos * m) + u32_to_fp8_24(b)) >> 15; - pcmBuffer[1] += (sample * envR) << 1; - pcmBuffer[0] += (sample * envL) << 1; + pcmBuffer[1] += (sample * envR); + pcmBuffer[0] += (sample * envL); finePos += romSamplesPerOutputSample; - u32 newCoarsePos = fp16_16_to_u32(finePos); + u32 newCoarsePos = fp8_24_to_u32(finePos); if (newCoarsePos != 0) { - finePos = fp16_16_fractional_part(finePos); + finePos = fp8_24_fractional_part(finePos); samplesLeftInWav -= newCoarsePos; if (samplesLeftInWav <= 0) { if (loopLen != 0) { @@ -908,8 +911,8 @@ void m4aSoundVSync(void) struct SoundMixerState *mixer = SOUND_INFO_PTR; if (mixer->lockStatus - ID_NUMBER <= 1) { s32 samplesPerFrame = mixer->samplesPerFrame * 2; - fixed16_16 *m4aBuffer = mixer->pcmBuffer; - fixed16_16 *cgbBuffer = cgb_get_buffer(); + fixed8_24 *m4aBuffer = mixer->pcmBuffer; + fixed8_24 *cgbBuffer = cgb_get_buffer(); s32 dmaCounter = mixer->dmaCounter; if (dmaCounter > 1) { @@ -917,18 +920,20 @@ void m4aSoundVSync(void) } for (u32 i = 0; i < samplesPerFrame; i++) { - // Sample is fixed 16.16 with a value of -1 to 1 - fixed16_16 sample = (m4aBuffer[i] + cgbBuffer[i]); - // Prevent distorting - if (sample > u32_to_fp16_16(1)) - sample = u32_to_fp16_16(1); - if (sample < -u32_to_fp16_16(1)) { - sample = -u32_to_fp16_16(1); + // Sample is fixed 8.24 with a value of -1 to 1 + fixed8_24 sample = (m4aBuffer[i] + cgbBuffer[i]); + // Clamp + if (sample > u32_to_fp8_24(1)) { + sample = u32_to_fp8_24(1); } - // 1 in 16.16 format is 65536 - // so >> 1 will convert to the - // size expected for s16 audio - audioBuffer[i] = sample >> 1; + if (sample < -u32_to_fp8_24(1)) { + sample = -u32_to_fp8_24(1); + } + // 1 in 8.24 format is 1 << 24 + // 32768 is size expected for s16 audio + // 32768 = 1 << 15 + // 24 - 15 = 9 + audioBuffer[i] = sample >> 9; } Platform_QueueAudio(audioBuffer, samplesPerFrame * sizeof(s16)); From edc3e58626aa566809c8593f92ba44f5587adc83 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 22 Feb 2026 03:31:35 +0000 Subject: [PATCH 25/51] remove comment --- include/lib/m4a/m4a_internal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 241b4510ae..567afbfc00 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -252,8 +252,6 @@ struct SoundMixerState { #if PLATFORM_GBA s8 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; #else - // TODO: let's not make this float, they are slow - // on older systems fixed8_24 pcmBuffer[PCM_DMA_BUF_SIZE * 2]; #endif }; From 7d55de1526a0451fec538db727c974d2c6863e66 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Sun, 22 Feb 2026 19:26:47 +0000 Subject: [PATCH 26/51] fix some affine backgrounds (special stage) --- src/platform/ps2/ps2.c | 2 +- src/platform/shared/video/gpsp_renderer.cc | 39 +++++++++++++++++----- src/sprite.c | 2 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 83d8060fa3..4a28e242a8 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -141,7 +141,7 @@ static void AudioPlay(const uint8_t *buf, size_t len) void VideoInit(void) { if (vid_mode == NULL) { - vid_mode = &vid_modes[1]; // Standard def 480p + vid_mode = &vid_modes[3]; // Standard def 480p } else { if (use_hires) { gsKit_hires_deinit_global(gsGlobal); diff --git a/src/platform/shared/video/gpsp_renderer.cc b/src/platform/shared/video/gpsp_renderer.cc index b4fe7bf8ea..4b8a231651 100644 --- a/src/platform/shared/video/gpsp_renderer.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -156,13 +156,36 @@ static inline s32 signext28(u32 value) return ret >> 4; } -void video_reload_counters() +static u32 prev_affine[4] = { 0, 0, 0, 0 }; + +static void video_reload_counters(bool vblank) { - /* This happens every Vblank */ - affine_reference_x[0] = signext28(read_ioreg32(REG_ADDR_BG2X_L)); - affine_reference_y[0] = signext28(read_ioreg32(REG_ADDR_BG2Y_L)); - affine_reference_x[1] = signext28(read_ioreg32(REG_ADDR_BG3X_L)); - affine_reference_y[1] = signext28(read_ioreg32(REG_ADDR_BG3Y_L)); + /* This happens every Vblank, and every scanline */ + u32 value; + + value = read_ioreg32(REG_ADDR_BG2X_L); + if (vblank || prev_affine[0] != value) { + affine_reference_x[0] = signext28(value); + prev_affine[0] = value; + } + + value = read_ioreg32(REG_ADDR_BG2Y_L); + if (vblank || prev_affine[1] != value) { + affine_reference_y[0] = signext28(value); + prev_affine[1] = value; + } + + value = read_ioreg32(REG_ADDR_BG3X_L); + if (vblank || prev_affine[2] != value) { + affine_reference_x[1] = signext28(value); + prev_affine[2] = value; + } + + value = read_ioreg32(REG_ADDR_BG3Y_L); + if (vblank || prev_affine[3] != value) { + affine_reference_y[1] = signext28(value); + prev_affine[3] = value; + } } // Renders non-affine tiled background layer. @@ -2256,7 +2279,7 @@ void gpsp_draw_frame(u16 *framebuf) if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) gIntrTable[INTR_INDEX_VCOUNT](); } - + video_reload_counters(false); update_scanline(); REG_DISPSTAT |= INTR_FLAG_HBLANK; @@ -2270,7 +2293,7 @@ void gpsp_draw_frame(u16 *framebuf) REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; } - video_reload_counters(); + video_reload_counters(true); } #endif diff --git a/src/sprite.c b/src/sprite.c index af67fc4363..f01948bd78 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -395,7 +395,7 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr // sp24 = s UnkSpriteStruct big; const SpriteOffset *dimensions = s->dimensions; -#if PORTABLE && (RENDERER != RENDERER_SOFTWARE) +#if PORTABLE && RENDERER != RENDERER_SOFTWARE_GPSP && RENDERER != RENDERER_SOFTWARE Platform_TransformSprite(s, transform); return; #endif From 0c7e81e7fc90c56528365568ba2b92a1ec86e168 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 23 Feb 2026 02:26:27 +0000 Subject: [PATCH 27/51] fix intro --- src/platform/shared/video/gpsp_renderer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/shared/video/gpsp_renderer.cc b/src/platform/shared/video/gpsp_renderer.cc index 4b8a231651..a5683a8c75 100644 --- a/src/platform/shared/video/gpsp_renderer.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -797,7 +797,7 @@ static void render_scanline_affine(u32 layer, u32 start, u32 end, void *scanline u32 map_size = (bg_control >> 14) & 0x03; // Char block base pointer - u32 base_block = (bg_control & BGCNT_SCREENBASE_MASK) >> 8; + u32 base_block = (bg_control >> 8) & 0x1F; u8 *map_base = BG_SCREEN_ADDR(base_block); // The tilemap base is selected via bgcnt (16KiB chunks) u32 tilecntrl = (bg_control >> 2) & 0x03; From a65475242ce7ad40c081701d3ea773b12ecedbb0 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 23 Feb 2026 23:30:52 +0000 Subject: [PATCH 28/51] more audio optimisation --- src/platform/shared/audio/cgb_audio.c | 42 +++++++++++---------- src/platform/shared/audio/m4a_sound_mixer.c | 15 ++++---- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 618bd5be80..035d18f176 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -234,27 +234,31 @@ void cgb_audio_generate(u16 samplesPerFrame) } else { ch4Out--; } - int avgDiv = 1; - while (ch4Samples >= u32_to_fp8_24(1)) { - avgDiv++; - bool8 lfsrCarry = 0; - if (gb.ch4LFSR[lfsrMode] & 2) - lfsrCarry ^= 1; - gb.ch4LFSR[lfsrMode] >>= 1; - if (gb.ch4LFSR[lfsrMode] & 2) - lfsrCarry ^= 1; - if (lfsrCarry) - gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode]; - if (gb.ch4LFSR[lfsrMode] & 1) { - ch4Out++; - } else { - ch4Out--; - } - ch4Samples -= u32_to_fp8_24(1); + int steps = fp8_24_to_u32(ch4Samples); + ch4Samples = fp8_24_fractional_part(ch4Samples); + + u16 lfsr = gb.ch4LFSR[lfsrMode]; + u16 lfsrMask = lfsrMax[lfsrMode]; + + for (int i = 0; i < steps; i++) { + // Comments to show what the bit + // manipulation here is representing + + // if (gb.ch4LFSR[lfsrMode] & 2) + u16 lfsrCarry = (lfsr >> 1) & 1; + lfsr >>= 1; + // if (gb.ch4LFSR[lfsrMode] & 2) + lfsrCarry ^= (lfsr >> 1) & 1; + // if (lfsrCarry) gb.ch4LFSR[lfsrMode] |= lfsrMax[lfsrMode]; + lfsr |= -lfsrCarry & lfsrMask; + // if (gb.ch4LFSR[lfsrMode] & 1) + ch4Out += (lfsr & 1) ? 1 : -1; } + gb.ch4LFSR[lfsrMode] = lfsr; + fixed8_24 sample = u32_to_fp8_24(ch4Out); - if (avgDiv > 1) - sample /= avgDiv; + if (steps > 0) + sample /= (steps + 1); // Muliply by the sample and then shift to make 8.24 again if (REG_NR51 & 0x80) diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index c487c0e562..d0bf1ba8b6 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -243,8 +243,9 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour } s32 samplesLeftInWav = chan->data.sound.ct; s8 *current = chan->current; - signed envR = chan->data.sound.envelopeVolR; - signed envL = chan->data.sound.envelopeVolL; + + fixed8_24 envR = chan->data.sound.envelopeVolR << 9; // (* 32768) + fixed8_24 envL = chan->data.sound.envelopeVolL << 9; if (chan->type & TONEDATA_TYPE_CGB) { for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { @@ -253,8 +254,8 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour // Creates a value between -32768 and 32768 // So shift by 9 to make this between -1 and 1 // in 8.24 - pcmBuffer[1] += (c * envR) << 9; - pcmBuffer[0] += (c * envL) << 9; + pcmBuffer[1] += (c * envR); + pcmBuffer[0] += (c * envL); if (--samplesLeftInWav == 0) { samplesLeftInWav = loopLen; if (loopLen != 0) { @@ -279,10 +280,10 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { // Use linear interpolation to calculate a value between the current sample in the wav // and the next sample. Also cancel out the 9.23 stuff - fixed8_24 sample = (((s64)finePos * m) + u32_to_fp8_24(b)) >> 15; + fixed8_24 sample = ((finePos * m) + u32_to_fp8_24(b)); - pcmBuffer[1] += (sample * envR); - pcmBuffer[0] += (sample * envL); + pcmBuffer[1] += ((s64)sample * envR) >> 24; + pcmBuffer[0] += ((s64)sample * envL) >> 24; finePos += romSamplesPerOutputSample; u32 newCoarsePos = fp8_24_to_u32(finePos); From de7335fd21166169e576d5b3c90cf34f684ecf31 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 24 Feb 2026 00:14:29 +0000 Subject: [PATCH 29/51] fix windows build, build remote volatile regs for portable platforms --- .devcontainer/Dockerfile | 2 +- .github/workflows/build.yml | 4 +- INSTALL.md | 2 +- Makefile | 5 +- include/gba/io_reg.h | 247 ++++++++++++++++++--------------- include/lib/m4a/m4a_internal.h | 2 - src/platform/shared/dma.c | 2 +- src/platform/shared/input.c | 2 +- 8 files changed, 141 insertions(+), 125 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a6b7c4b24d..f2b5a000f1 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -5,7 +5,7 @@ ARG VARIANT FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools + && apt-get -y install --no-install-recommends binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev build-essential clang-format-13 xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools WORKDIR /deps RUN git clone https://github.com/pret/agbcc.git && cd agbcc && ./build.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9455fbe23c..503efb933d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -187,7 +187,7 @@ jobs: - name: Install tools (Linux) if: ${{ matrix.os == 'ubuntu-22.04' }} run: | - sudo apt update && sudo apt install xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools + sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools - name: Install Tools (Macos) if: ${{ matrix.os == 'macos-15' }} @@ -223,7 +223,7 @@ jobs: - name: Install tools run: | - sudo apt update && sudo apt install xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools + sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools - name: Install SDL for win32 if: ${{ matrix.platform == 'sdl_win32' }} diff --git a/INSTALL.md b/INSTALL.md index 8315370fc2..4feb4b25fd 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -14,7 +14,7 @@ Install WSL (Ubuntu). Once installed, open this project in the WSL terminal and #### On Linux (including WSL) ``` sudo apt update -sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev gcc-mingw-w64 libarchive-tools +sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools ``` #### On MacOS diff --git a/Makefile b/Makefile index e07a3e3cca..c90069e059 100644 --- a/Makefile +++ b/Makefile @@ -559,9 +559,6 @@ ifeq ($(PLATFORM),gba) $(ROM): $(ELF) libagbsyscall $(OBJCOPY) -O binary --pad-to 0x8400000 $< $@ $(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent -else ifeq ($(PLATFORM),win32) -$(ROM): $(ELF) libagbsyscall - $(OBJCOPY) -O pei-x86-64 $< $@ else $(ROM): $(ELF) ifeq ($(PLATFORM),sdl) @@ -582,6 +579,8 @@ else ifeq ($(PLATFORM),ps2) @cp -r ps2/ntsc $(OBJ_DIR)/iso @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) @mkisofs -o $(ROM) $(OBJ_DIR)/iso/ +else + $(OBJCOPY) -O pei-x86-64 $< $@ endif endif diff --git a/include/gba/io_reg.h b/include/gba/io_reg.h index 2651423032..b829d1cf80 100644 --- a/include/gba/io_reg.h +++ b/include/gba/io_reg.h @@ -5,6 +5,25 @@ #include #endif +// these are not hardware registers on ports +// so there is no need to make re-read them +#if PORTABLE +typedef uint16_t reg_u16; +typedef uint32_t reg_u32; +typedef int16_t reg_s16; +typedef int32_t reg_s32; +typedef uint64_t reg_u64; +typedef winreg_t reg_wint; +#else +typedef volatile uint16_t reg_u16; +typedef volatile uint32_t reg_u32; +typedef volatile int16_t reg_s16; +typedef volatile int32_t reg_s32; +typedef volatile uint64_t reg_u64; +typedef volatile winreg_t reg_wint; +#endif + + #define IO_SIZE 0x400 #if !PORTABLE #define REG_BASE 0x4000000 // I/O register base address @@ -369,155 +388,155 @@ extern unsigned char REG_BASE[IO_SIZE]; // I/O registers -#define REG_DISPCNT (*(vu16 *)REG_ADDR_DISPCNT) -#define REG_DISPSTAT (*(vu16 *)REG_ADDR_DISPSTAT) -#define REG_VCOUNT (*(vu16 *)REG_ADDR_VCOUNT) -#define REG_BG0CNT (*(vu16 *)REG_ADDR_BG0CNT) -#define REG_BG1CNT (*(vu16 *)REG_ADDR_BG1CNT) -#define REG_BG2CNT (*(vu16 *)REG_ADDR_BG2CNT) -#define REG_BG3CNT (*(vu16 *)REG_ADDR_BG3CNT) -#define REG_BG0HOFS (*(vu16 *)REG_ADDR_BG0HOFS) -#define REG_BG0VOFS (*(vu16 *)REG_ADDR_BG0VOFS) -#define REG_BG1HOFS (*(vu16 *)REG_ADDR_BG1HOFS) -#define REG_BG1VOFS (*(vu16 *)REG_ADDR_BG1VOFS) -#define REG_BG2HOFS (*(vu16 *)REG_ADDR_BG2HOFS) -#define REG_BG2VOFS (*(vu16 *)REG_ADDR_BG2VOFS) -#define REG_BG3HOFS (*(vu16 *)REG_ADDR_BG3HOFS) -#define REG_BG3VOFS (*(vu16 *)REG_ADDR_BG3VOFS) -#define REG_BG2PA (*(vu16 *)REG_ADDR_BG2PA) -#define REG_BG2PB (*(vu16 *)REG_ADDR_BG2PB) -#define REG_BG2PC (*(vu16 *)REG_ADDR_BG2PC) -#define REG_BG2PD (*(vu16 *)REG_ADDR_BG2PD) -#define REG_BG2X (*(vu32 *)REG_ADDR_BG2X) -#define REG_BG2X_L (*(vu16 *)REG_ADDR_BG2X_L) -#define REG_BG2X_H (*(vu16 *)REG_ADDR_BG2X_H) -#define REG_BG2Y (*(vu32 *)REG_ADDR_BG2Y) -#define REG_BG2Y_L (*(vu16 *)REG_ADDR_BG2Y_L) -#define REG_BG2Y_H (*(vu16 *)REG_ADDR_BG2Y_H) -#define REG_BG3PA (*(vu16 *)REG_ADDR_BG3PA) -#define REG_BG3PB (*(vu16 *)REG_ADDR_BG3PB) -#define REG_BG3PC (*(vu16 *)REG_ADDR_BG3PC) -#define REG_BG3PD (*(vu16 *)REG_ADDR_BG3PD) -#define REG_BG3X (*(vu32 *)REG_ADDR_BG3X) -#define REG_BG3X_L (*(vu16 *)REG_ADDR_BG3X_L) -#define REG_BG3X_H (*(vu16 *)REG_ADDR_BG3X_H) -#define REG_BG3Y (*(vu32 *)REG_ADDR_BG3Y) -#define REG_BG3Y_L (*(vu16 *)REG_ADDR_BG3Y_L) -#define REG_BG3Y_H (*(vu16 *)REG_ADDR_BG3Y_H) -#define REG_WIN0H (*(volatile winreg_t *)REG_ADDR_WIN0H) -#define REG_WIN1H (*(volatile winreg_t *)REG_ADDR_WIN1H) -#define REG_WIN0V (*(volatile winreg_t *)REG_ADDR_WIN0V) -#define REG_WIN1V (*(volatile winreg_t *)REG_ADDR_WIN1V) -#define REG_WININ (*(volatile winreg_t *)REG_ADDR_WININ) -#define REG_WINOUT (*(volatile winreg_t *)REG_ADDR_WINOUT) -#define REG_MOSAIC (*(vu16 *)REG_ADDR_MOSAIC) -#define REG_BLDCNT (*(vu16 *)REG_ADDR_BLDCNT) -#define REG_BLDALPHA (*(vu16 *)REG_ADDR_BLDALPHA) -#define REG_BLDY (*(vu16 *)REG_ADDR_BLDY) - -#define REG_SOUND1CNT_L (*(vu16 *)REG_ADDR_SOUND1CNT_L) +#define REG_DISPCNT (*(reg_u16 *)REG_ADDR_DISPCNT) +#define REG_DISPSTAT (*(reg_u16 *)REG_ADDR_DISPSTAT) +#define REG_VCOUNT (*(reg_u16 *)REG_ADDR_VCOUNT) +#define REG_BG0CNT (*(reg_u16 *)REG_ADDR_BG0CNT) +#define REG_BG1CNT (*(reg_u16 *)REG_ADDR_BG1CNT) +#define REG_BG2CNT (*(reg_u16 *)REG_ADDR_BG2CNT) +#define REG_BG3CNT (*(reg_u16 *)REG_ADDR_BG3CNT) +#define REG_BG0HOFS (*(reg_u16 *)REG_ADDR_BG0HOFS) +#define REG_BG0VOFS (*(reg_u16 *)REG_ADDR_BG0VOFS) +#define REG_BG1HOFS (*(reg_u16 *)REG_ADDR_BG1HOFS) +#define REG_BG1VOFS (*(reg_u16 *)REG_ADDR_BG1VOFS) +#define REG_BG2HOFS (*(reg_u16 *)REG_ADDR_BG2HOFS) +#define REG_BG2VOFS (*(reg_u16 *)REG_ADDR_BG2VOFS) +#define REG_BG3HOFS (*(reg_u16 *)REG_ADDR_BG3HOFS) +#define REG_BG3VOFS (*(reg_u16 *)REG_ADDR_BG3VOFS) +#define REG_BG2PA (*(reg_u16 *)REG_ADDR_BG2PA) +#define REG_BG2PB (*(reg_u16 *)REG_ADDR_BG2PB) +#define REG_BG2PC (*(reg_u16 *)REG_ADDR_BG2PC) +#define REG_BG2PD (*(reg_u16 *)REG_ADDR_BG2PD) +#define REG_BG2X (*(reg_u32 *)REG_ADDR_BG2X) +#define REG_BG2X_L (*(reg_u16 *)REG_ADDR_BG2X_L) +#define REG_BG2X_H (*(reg_u16 *)REG_ADDR_BG2X_H) +#define REG_BG2Y (*(reg_u32 *)REG_ADDR_BG2Y) +#define REG_BG2Y_L (*(reg_u16 *)REG_ADDR_BG2Y_L) +#define REG_BG2Y_H (*(reg_u16 *)REG_ADDR_BG2Y_H) +#define REG_BG3PA (*(reg_u16 *)REG_ADDR_BG3PA) +#define REG_BG3PB (*(reg_u16 *)REG_ADDR_BG3PB) +#define REG_BG3PC (*(reg_u16 *)REG_ADDR_BG3PC) +#define REG_BG3PD (*(reg_u16 *)REG_ADDR_BG3PD) +#define REG_BG3X (*(reg_u32 *)REG_ADDR_BG3X) +#define REG_BG3X_L (*(reg_u16 *)REG_ADDR_BG3X_L) +#define REG_BG3X_H (*(reg_u16 *)REG_ADDR_BG3X_H) +#define REG_BG3Y (*(reg_u32 *)REG_ADDR_BG3Y) +#define REG_BG3Y_L (*(reg_u16 *)REG_ADDR_BG3Y_L) +#define REG_BG3Y_H (*(reg_u16 *)REG_ADDR_BG3Y_H) +#define REG_WIN0H (*(reg_wint *)REG_ADDR_WIN0H) +#define REG_WIN1H (*(reg_wint *)REG_ADDR_WIN1H) +#define REG_WIN0V (*(reg_wint *)REG_ADDR_WIN0V) +#define REG_WIN1V (*(reg_wint *)REG_ADDR_WIN1V) +#define REG_WININ (*(reg_wint *)REG_ADDR_WININ) +#define REG_WINOUT (*(reg_wint *)REG_ADDR_WINOUT) +#define REG_MOSAIC (*(reg_u16 *)REG_ADDR_MOSAIC) +#define REG_BLDCNT (*(reg_u16 *)REG_ADDR_BLDCNT) +#define REG_BLDALPHA (*(reg_u16 *)REG_ADDR_BLDALPHA) +#define REG_BLDY (*(reg_u16 *)REG_ADDR_BLDY) + +#define REG_SOUND1CNT_L (*(reg_u16 *)REG_ADDR_SOUND1CNT_L) #define REG_NR10 (*(vu8 *)REG_ADDR_NR10) -#define REG_SOUND1CNT_H (*(vu16 *)REG_ADDR_SOUND1CNT_H) +#define REG_SOUND1CNT_H (*(reg_u16 *)REG_ADDR_SOUND1CNT_H) #define REG_NR11 (*(vu8 *)REG_ADDR_NR11) #define REG_NR12 (*(vu8 *)REG_ADDR_NR12) -#define REG_SOUND1CNT_X (*(vu16 *)REG_ADDR_SOUND1CNT_X) +#define REG_SOUND1CNT_X (*(reg_u16 *)REG_ADDR_SOUND1CNT_X) #define REG_NR13 (*(vu8 *)REG_ADDR_NR13) #define REG_NR14 (*(vu8 *)REG_ADDR_NR14) -#define REG_SOUND2CNT_L (*(vu16 *)REG_ADDR_SOUND2CNT_L) +#define REG_SOUND2CNT_L (*(reg_u16 *)REG_ADDR_SOUND2CNT_L) #define REG_NR21 (*(vu8 *)REG_ADDR_NR21) #define REG_NR22 (*(vu8 *)REG_ADDR_NR22) -#define REG_SOUND2CNT_H (*(vu16 *)REG_ADDR_SOUND2CNT_H) +#define REG_SOUND2CNT_H (*(reg_u16 *)REG_ADDR_SOUND2CNT_H) #define REG_NR23 (*(vu8 *)REG_ADDR_NR23) #define REG_NR24 (*(vu8 *)REG_ADDR_NR24) -#define REG_SOUND3CNT_L (*(vu16 *)REG_ADDR_SOUND3CNT_L) +#define REG_SOUND3CNT_L (*(reg_u16 *)REG_ADDR_SOUND3CNT_L) #define REG_NR30 (*(vu8 *)REG_ADDR_NR30) -#define REG_SOUND3CNT_H (*(vu16 *)REG_ADDR_SOUND3CNT_H) +#define REG_SOUND3CNT_H (*(reg_u16 *)REG_ADDR_SOUND3CNT_H) #define REG_NR31 (*(vu8 *)REG_ADDR_NR31) #define REG_NR32 (*(vu8 *)REG_ADDR_NR32) -#define REG_SOUND3CNT_X (*(vu16 *)REG_ADDR_SOUND3CNT_X) +#define REG_SOUND3CNT_X (*(reg_u16 *)REG_ADDR_SOUND3CNT_X) #define REG_NR33 (*(vu8 *)REG_ADDR_NR33) #define REG_NR34 (*(vu8 *)REG_ADDR_NR34) -#define REG_SOUND4CNT_L (*(vu16 *)REG_ADDR_SOUND4CNT_L) +#define REG_SOUND4CNT_L (*(reg_u16 *)REG_ADDR_SOUND4CNT_L) #define REG_NR41 (*(vu8 *)REG_ADDR_NR41) #define REG_NR42 (*(vu8 *)REG_ADDR_NR42) -#define REG_SOUND4CNT_H (*(vu16 *)REG_ADDR_SOUND4CNT_H) +#define REG_SOUND4CNT_H (*(reg_u16 *)REG_ADDR_SOUND4CNT_H) #define REG_NR43 (*(vu8 *)REG_ADDR_NR43) #define REG_NR44 (*(vu8 *)REG_ADDR_NR44) -#define REG_SOUNDCNT_L (*(vu16 *)REG_ADDR_SOUNDCNT_L) +#define REG_SOUNDCNT_L (*(reg_u16 *)REG_ADDR_SOUNDCNT_L) #define REG_NR50 (*(vu8 *)REG_ADDR_NR50) #define REG_NR51 (*(vu8 *)REG_ADDR_NR51) -#define REG_SOUNDCNT_H (*(vu16 *)REG_ADDR_SOUNDCNT_H) -#define REG_SOUNDCNT_X (*(vu16 *)REG_ADDR_SOUNDCNT_X) +#define REG_SOUNDCNT_H (*(reg_u16 *)REG_ADDR_SOUNDCNT_H) +#define REG_SOUNDCNT_X (*(reg_u16 *)REG_ADDR_SOUNDCNT_X) #define REG_NR52 (*(vu8 *)REG_ADDR_NR52) -#define REG_SOUNDBIAS (*(vu16 *)REG_ADDR_SOUNDBIAS) +#define REG_SOUNDBIAS (*(reg_u16 *)REG_ADDR_SOUNDBIAS) #define REG_SOUNDBIAS_L (*(vu8 *)REG_ADDR_SOUNDBIAS_L) #define REG_SOUNDBIAS_H (*(vu8 *)REG_ADDR_SOUNDBIAS_H) -#define REG_WAVE_RAM0 (*(vu32 *)REG_ADDR_WAVE_RAM0) -#define REG_WAVE_RAM1 (*(vu32 *)REG_ADDR_WAVE_RAM1) -#define REG_WAVE_RAM2 (*(vu32 *)REG_ADDR_WAVE_RAM2) -#define REG_WAVE_RAM3 (*(vu32 *)REG_ADDR_WAVE_RAM3) -#define REG_FIFO_A (*(vu32 *)REG_ADDR_FIFO_A) -#define REG_FIFO_B (*(vu32 *)REG_ADDR_FIFO_B) +#define REG_WAVE_RAM0 (*(reg_u32 *)REG_ADDR_WAVE_RAM0) +#define REG_WAVE_RAM1 (*(reg_u32 *)REG_ADDR_WAVE_RAM1) +#define REG_WAVE_RAM2 (*(reg_u32 *)REG_ADDR_WAVE_RAM2) +#define REG_WAVE_RAM3 (*(reg_u32 *)REG_ADDR_WAVE_RAM3) +#define REG_FIFO_A (*(reg_u32 *)REG_ADDR_FIFO_A) +#define REG_FIFO_B (*(reg_u32 *)REG_ADDR_FIFO_B) #define REG_DMA0SAD (*(volatile uintptr_t *)REG_ADDR_DMA0SAD) #define REG_DMA0DAD (*(volatile uintptr_t *)REG_ADDR_DMA0DAD) -#define REG_DMA0CNT (*(vu32 *)REG_ADDR_DMA0CNT) -#define REG_DMA0CNT_L (*(vu16 *)REG_ADDR_DMA0CNT_L) -#define REG_DMA0CNT_H (*(vu16 *)REG_ADDR_DMA0CNT_H) +#define REG_DMA0CNT (*(reg_u32 *)REG_ADDR_DMA0CNT) +#define REG_DMA0CNT_L (*(reg_u16 *)REG_ADDR_DMA0CNT_L) +#define REG_DMA0CNT_H (*(reg_u16 *)REG_ADDR_DMA0CNT_H) #define REG_DMA1SAD (*(volatile uintptr_t *)REG_ADDR_DMA1SAD) #define REG_DMA1DAD (*(volatile uintptr_t *)REG_ADDR_DMA1DAD) -#define REG_DMA1CNT (*(vu32 *)REG_ADDR_DMA1CNT) -#define REG_DMA1CNT_L (*(vu16 *)REG_ADDR_DMA1CNT_L) -#define REG_DMA1CNT_H (*(vu16 *)REG_ADDR_DMA1CNT_H) +#define REG_DMA1CNT (*(reg_u32 *)REG_ADDR_DMA1CNT) +#define REG_DMA1CNT_L (*(reg_u16 *)REG_ADDR_DMA1CNT_L) +#define REG_DMA1CNT_H (*(reg_u16 *)REG_ADDR_DMA1CNT_H) #define REG_DMA2SAD (*(volatile uintptr_t *)REG_ADDR_DMA2SAD) #define REG_DMA2DAD (*(volatile uintptr_t *)REG_ADDR_DMA2DAD) -#define REG_DMA2CNT (*(vu32 *)REG_ADDR_DMA2CNT) -#define REG_DMA2CNT_L (*(vu16 *)REG_ADDR_DMA2CNT_L) -#define REG_DMA2CNT_H (*(vu16 *)REG_ADDR_DMA2CNT_H) +#define REG_DMA2CNT (*(reg_u32 *)REG_ADDR_DMA2CNT) +#define REG_DMA2CNT_L (*(reg_u16 *)REG_ADDR_DMA2CNT_L) +#define REG_DMA2CNT_H (*(reg_u16 *)REG_ADDR_DMA2CNT_H) #define REG_DMA3SAD (*(volatile uintptr_t *)REG_ADDR_DMA3SAD) #define REG_DMA3DAD (*(volatile uintptr_t *)REG_ADDR_DMA3DAD) -#define REG_DMA3CNT (*(vu32 *)REG_ADDR_DMA3CNT) -#define REG_DMA3CNT_L (*(vu16 *)REG_ADDR_DMA3CNT_L) -#define REG_DMA3CNT_H (*(vu16 *)REG_ADDR_DMA3CNT_H) - -#define REG_TMCNT(n) (*(vu16 *)(REG_ADDR_TMCNT + ((n) * 4))) -#define REG_TM0CNT (*(vu32 *)REG_ADDR_TM0CNT) -#define REG_TM0CNT_L (*(vu16 *)REG_ADDR_TM0CNT_L) -#define REG_TM0CNT_H (*(vu16 *)REG_ADDR_TM0CNT_H) -#define REG_TM1CNT (*(vu32 *)REG_ADDR_TM1CNT) -#define REG_TM1CNT_L (*(vu16 *)REG_ADDR_TM1CNT_L) -#define REG_TM1CNT_H (*(vu16 *)REG_ADDR_TM1CNT_H) -#define REG_TM2CNT (*(vu32 *)REG_ADDR_TM2CNT) -#define REG_TM2CNT_L (*(vu16 *)REG_ADDR_TM2CNT_L) -#define REG_TM2CNT_H (*(vu16 *)REG_ADDR_TM2CNT_H) -#define REG_TM3CNT (*(vu32 *)REG_ADDR_TM3CNT) -#define REG_TM3CNT_L (*(vu16 *)REG_ADDR_TM3CNT_L) -#define REG_TM3CNT_H (*(vu16 *)REG_ADDR_TM3CNT_H) - -#define REG_SIOCNT (*(vu16 *)REG_ADDR_SIOCNT) -#define REG_SIOCNT_32 (*(vu32 *)REG_ADDR_SIOCNT) -#define REG_SIODATA8 (*(vu16 *)REG_ADDR_SIODATA8) -#define REG_SIODATA32 (*(vu32 *)REG_ADDR_SIODATA32) -#define REG_SIOMLT_SEND (*(vu16 *)REG_ADDR_SIOMLT_SEND) -#define REG_SIOMLT_RECV (*(vu64 *)REG_ADDR_SIOMLT_RECV) -#define REG_SIOMULTI0 (*(vu16 *)REG_ADDR_SIOMULTI0) -#define REG_SIOMULTI1 (*(vu16 *)REG_ADDR_SIOMULTI1) -#define REG_SIOMULTI2 (*(vu16 *)REG_ADDR_SIOMULTI2) -#define REG_SIOMULTI3 (*(vu16 *)REG_ADDR_SIOMULTI3) - -#define REG_KEYINPUT (*(vu16 *)REG_ADDR_KEYINPUT) -#define REG_KEYCNT (*(vu16 *)REG_ADDR_KEYCNT) - -#define REG_RCNT (*(vu16 *)REG_ADDR_RCNT) - -#define REG_IME (*(vu16 *)REG_ADDR_IME) -#define REG_IE (*(vu16 *)REG_ADDR_IE) -#define REG_IF (*(vu16 *)REG_ADDR_IF) - -#define REG_WAITCNT (*(vu16 *)REG_ADDR_WAITCNT) +#define REG_DMA3CNT (*(reg_u32 *)REG_ADDR_DMA3CNT) +#define REG_DMA3CNT_L (*(reg_u16 *)REG_ADDR_DMA3CNT_L) +#define REG_DMA3CNT_H (*(reg_u16 *)REG_ADDR_DMA3CNT_H) + +#define REG_TMCNT(n) (*(reg_u16 *)(REG_ADDR_TMCNT + ((n) * 4))) +#define REG_TM0CNT (*(reg_u32 *)REG_ADDR_TM0CNT) +#define REG_TM0CNT_L (*(reg_u16 *)REG_ADDR_TM0CNT_L) +#define REG_TM0CNT_H (*(reg_u16 *)REG_ADDR_TM0CNT_H) +#define REG_TM1CNT (*(reg_u32 *)REG_ADDR_TM1CNT) +#define REG_TM1CNT_L (*(reg_u16 *)REG_ADDR_TM1CNT_L) +#define REG_TM1CNT_H (*(reg_u16 *)REG_ADDR_TM1CNT_H) +#define REG_TM2CNT (*(reg_u32 *)REG_ADDR_TM2CNT) +#define REG_TM2CNT_L (*(reg_u16 *)REG_ADDR_TM2CNT_L) +#define REG_TM2CNT_H (*(reg_u16 *)REG_ADDR_TM2CNT_H) +#define REG_TM3CNT (*(reg_u32 *)REG_ADDR_TM3CNT) +#define REG_TM3CNT_L (*(reg_u16 *)REG_ADDR_TM3CNT_L) +#define REG_TM3CNT_H (*(reg_u16 *)REG_ADDR_TM3CNT_H) + +#define REG_SIOCNT (*(reg_u16 *)REG_ADDR_SIOCNT) +#define REG_SIOCNT_32 (*(reg_u32 *)REG_ADDR_SIOCNT) +#define REG_SIODATA8 (*(reg_u16 *)REG_ADDR_SIODATA8) +#define REG_SIODATA32 (*(reg_u32 *)REG_ADDR_SIODATA32) +#define REG_SIOMLT_SEND (*(reg_u16 *)REG_ADDR_SIOMLT_SEND) +#define REG_SIOMLT_RECV (*(reg_u64 *)REG_ADDR_SIOMLT_RECV) +#define REG_SIOMULTI0 (*(reg_u16 *)REG_ADDR_SIOMULTI0) +#define REG_SIOMULTI1 (*(reg_u16 *)REG_ADDR_SIOMULTI1) +#define REG_SIOMULTI2 (*(reg_u16 *)REG_ADDR_SIOMULTI2) +#define REG_SIOMULTI3 (*(reg_u16 *)REG_ADDR_SIOMULTI3) + +#define REG_KEYINPUT (*(reg_u16 *)REG_ADDR_KEYINPUT) +#define REG_KEYCNT (*(reg_u16 *)REG_ADDR_KEYCNT) + +#define REG_RCNT (*(reg_u16 *)REG_ADDR_RCNT) + +#define REG_IME (*(reg_u16 *)REG_ADDR_IME) +#define REG_IE (*(reg_u16 *)REG_ADDR_IE) +#define REG_IF (*(reg_u16 *)REG_ADDR_IF) + +#define REG_WAITCNT (*(reg_u16 *)REG_ADDR_WAITCNT) // I/O register fields diff --git a/include/lib/m4a/m4a_internal.h b/include/lib/m4a/m4a_internal.h index 567afbfc00..cf90c7f8e7 100644 --- a/include/lib/m4a/m4a_internal.h +++ b/include/lib/m4a/m4a_internal.h @@ -106,14 +106,12 @@ #define MAX_LINES 0 #endif -#if !PLATFORM_GBA typedef s32 fixed8_24; #define float_to_fp8_24(value) (fixed8_24)((value)*16777216.0f) #define u32_to_fp8_24(value) ((value) << 24) #define fp8_24_to_u32(value) ((value) >> 24) #define fp8_24_to_float(value) (float)((value) / 16777216.0f) #define fp8_24_fractional_part(value) ((value)&0xFFFFFF) -#endif struct MP2KTrack; struct MP2KPlayerState; diff --git a/src/platform/shared/dma.c b/src/platform/shared/dma.c index d2f55e045f..a36e52ac2f 100644 --- a/src/platform/shared/dma.c +++ b/src/platform/shared/dma.c @@ -140,7 +140,7 @@ void DmaStop(int dmaNum) void DmaWait(int dmaNum) { - vu32 *ctrlRegs = ®_DMA0CNT; + vu32 *ctrlRegs = (vu32 *)®_DMA0CNT; #if !USE_NEW_DMA while (ctrlRegs[dmaNum * 3] & (DMA_ENABLE << 16)) ; diff --git a/src/platform/shared/input.c b/src/platform/shared/input.c index e8250ed040..c3f801c8b6 100644 --- a/src/platform/shared/input.c +++ b/src/platform/shared/input.c @@ -3,8 +3,8 @@ #include #include #include -#include "gba/io_reg.h" #include "gba/types.h" +#include "gba/io_reg.h" #include "platform/shared/input.h" #define STICK_THRESHOLD 0.5f From 002d7032c542afe9c4cc852187d7cd80597325cb Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 24 Feb 2026 00:30:57 +0000 Subject: [PATCH 30/51] pr cleanup --- include/config.h | 13 +++++-------- src/game/special_stage/world.c | 9 --------- src/platform/pret_sdl/sdl2.c | 3 ++- src/platform/shared/dma.c | 22 +++------------------- src/platform/shared/video/gpsp_renderer.cc | 2 +- src/platform/win32/win32.c | 2 +- src/sprite.c | 6 +++--- 7 files changed, 15 insertions(+), 42 deletions(-) diff --git a/include/config.h b/include/config.h index 86f6603b58..357b565809 100644 --- a/include/config.h +++ b/include/config.h @@ -39,19 +39,16 @@ #define TAS_TESTING_WIDESCREEN_HACK 1 -#define RENDERER_SOFTWARE 0 -#define RENDERER_OPENGL 1 -#define RENDERER_SOFTWARE_GPSP 2 -#define RENDERER_COUNT 3 +#define RENDERER_SOFTWARE 0 +#define RENDERER_OPENGL 1 +#define RENDERER_COUNT 2 #ifndef RENDERER -#if defined(__PSP__) || defined(__PS2__) -#define RENDERER RENDERER_SOFTWARE_GPSP -#elif PLATFORM_WIN32 && !PLATFORM_SDL +#if PLATFORM_WIN32 && !PLATFORM_SDL // TODO: Only win32 for now #define RENDERER RENDERER_OPENGL #else -#define RENDERER RENDERER_SOFTWARE_GPSP +#define RENDERER RENDERER_SOFTWARE #endif #endif diff --git a/src/game/special_stage/world.c b/src/game/special_stage/world.c index 947eb2d342..98f7e8e713 100644 --- a/src/game/special_stage/world.c +++ b/src/game/special_stage/world.c @@ -238,19 +238,10 @@ void sub_806EA04(void) temp5 = (i - stage->cameraHeight) * temp2 * 2; *unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PA - // HACK: in SDL we don't handle these PB and PD values properly -#if !PLATFORM_GBA && RENDERER == RENDERER_SOFTWARE - *unk1884++ = 0; -#else *unk1884++ = (Q_16_16_TO_INT(temp) * sin) >> 0x10; // BG2PB -#endif *unk1884++ = (Q_16_16_TO_INT(temp) * -sin) >> 0x10; // BG2PC -#if !PLATFORM_GBA && RENDERER == RENDERER_SOFTWARE - *unk1884++ = 0; -#else *unk1884++ = (Q_16_16_TO_INT(temp) * cos) >> 0x10; // BG2PD -#endif x = (Q_16_16_TO_INT(temp5) * sin) + (Q_16_16_TO_INT(temp4) * cos) + stage->q16CameraX; y = (Q_16_16_TO_INT(temp4) * -sin) + (Q_16_16_TO_INT(temp5) * cos) + stage->q16CameraY; diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 630eb28b54..22d5512f7d 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -2024,7 +2024,8 @@ void VramDraw(SDL_Texture *texture) void VDraw(SDL_Texture *texture) { -#if RENDERER == RENDERER_SOFTWARE_GPSP +// TODO: always use this renderer +#if TRUE { gpsp_draw_frame(gameImage); } diff --git a/src/platform/shared/dma.c b/src/platform/shared/dma.c index a36e52ac2f..24bf15f06f 100644 --- a/src/platform/shared/dma.c +++ b/src/platform/shared/dma.c @@ -1,26 +1,10 @@ #include -#include #include "global.h" #include "platform/shared/dma.h" -// safe unaligned access for MIPS -static inline void dma_copy32(void *dst, const void *src) -{ - u32 tmp; - memcpy(&tmp, src, 4); - memcpy(dst, &tmp, 4); -} - -static inline void dma_copy16(void *dst, const void *src) -{ - u16 tmp; - memcpy(&tmp, src, 2); - memcpy(dst, &tmp, 2); -} - struct DMATransfer DMAList[DMA_COUNT] = { 0 }; -void RunDMAs(DmaStartTypes type) +void RunDMAs(u32 type) { for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { struct DMATransfer *dma = &DMAList[dmaNum]; @@ -39,9 +23,9 @@ void RunDMAs(DmaStartTypes type) // printf("DMA%d src=%p, dest=%p, control=%d\n", dmaNum, dma->src, dma->dst, dma->control); for (int i = 0; i < dma->size; i++) { if ((dma->control) & DMA_32BIT) - dma_copy32(dma->dst, dma->src); + *dma->dst32 = *dma->src32; else - dma_copy16(dma->dst, dma->src); + *dma->dst16 = *dma->src16; // process destination pointer changes if (((dma->control) & DMA_DEST_MASK) == DMA_DEST_INC) { diff --git a/src/platform/shared/video/gpsp_renderer.cc b/src/platform/shared/video/gpsp_renderer.cc index a5683a8c75..255e8d18be 100644 --- a/src/platform/shared/video/gpsp_renderer.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -22,7 +22,7 @@ extern "C" { #include "config.h" } -#if RENDERER == RENDERER_SOFTWARE_GPSP +#if RENDERER == RENDERER_SOFTWARE #include #include diff --git a/src/platform/win32/win32.c b/src/platform/win32/win32.c index ec762f7f1d..6df7d1a4ef 100644 --- a/src/platform/win32/win32.c +++ b/src/platform/win32/win32.c @@ -473,4 +473,4 @@ void *Platform_realloc(void *ptr, size_t numBytes) } void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } -void Platform_QueueAudio(const float *s16, u32 numBytes) { } +void Platform_QueueAudio(const s16 *data, u32 numBytes) { } diff --git a/src/sprite.c b/src/sprite.c index f01948bd78..5246417024 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -9,7 +9,7 @@ #include "animation_commands.h" #include "platform/platform.h" -#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE_GPSP && RENDERER != RENDERER_SOFTWARE +#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE extern void Platform_DisplaySprite(Sprite *sprite, u8 oamPaletteNum); extern void Platform_TransformSprite(Sprite *sprite, SpriteTransform *transform); #endif @@ -395,7 +395,7 @@ NONMATCH("asm/non_matching/engine/TransformSprite.inc", void TransformSprite(Spr // sp24 = s UnkSpriteStruct big; const SpriteOffset *dimensions = s->dimensions; -#if PORTABLE && RENDERER != RENDERER_SOFTWARE_GPSP && RENDERER != RENDERER_SOFTWARE +#if PORTABLE && RENDERER != RENDERER_SOFTWARE Platform_TransformSprite(s, transform); return; #endif @@ -727,7 +727,7 @@ void DisplaySprite(Sprite *sprite) oam->split.paletteNum += sprite->palId; #endif -#if !PLATFORM_GBA && (RENDERER != RENDERER_SOFTWARE_GPSP && RENDERER != RENDERER_SOFTWARE) +#if !PLATFORM_GBA && RENDERER != RENDERER_SOFTWARE // TEMP // Quick hack for getting output in OpenGL test // The whole function call should be replaced by this! From 091545dc28c9d989a9e09374be127fd0fccf4bab Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 24 Feb 2026 00:32:59 +0000 Subject: [PATCH 31/51] more cleanup --- src/background.c | 4 ++-- src/core.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/background.c b/src/background.c index d6611bc897..aad7732c58 100644 --- a/src/background.c +++ b/src/background.c @@ -653,7 +653,7 @@ END_NONMATCH void UpdateBgAnimationTiles(Background *bg) { -#if (RENDERER != RENDERER_OPENGL) +#if (RENDERER == RENDERER_SOFTWARE) Tilemap *tilemap = gTilemapsRef[bg->tilemapId]; if (tilemap->animFrameCount > 0) { if (tilemap->animDelay <= ++bg->animDelayCounter) { @@ -875,7 +875,7 @@ NONMATCH("asm/non_matching/engine/sub_80039E4.inc", bool32 sub_80039E4(void)) return TRUE; #endif -#if (RENDERER != RENDERER_OPENGL) +#if (RENDERER == RENDERER_SOFTWARE) if (gBgSpritesCount != 0) { OamDataShort oam; s32 r5; diff --git a/src/core.c b/src/core.c index fc1f25a33a..fcbe848506 100644 --- a/src/core.c +++ b/src/core.c @@ -924,7 +924,7 @@ bool32 ProcessVramGraphicsCopyQueue(void) if ((graphics->src != 0) && (graphics->dest != 0)) #endif { -#if (RENDERER != RENDERER_OPENGL) +#if (RENDERER == RENDERER_SOFTWARE) DmaCopy16(3, (void *)(graphics->src + offset), (void *)(graphics->dest + offset), COPY_CHUNK_SIZE); #endif graphics->size -= COPY_CHUNK_SIZE; @@ -939,7 +939,7 @@ bool32 ProcessVramGraphicsCopyQueue(void) if ((graphics->src != 0) && (graphics->dest != 0)) #endif { -#if (RENDERER != RENDERER_OPENGL) +#if (RENDERER == RENDERER_SOFTWARE) DmaCopy16(3, (void *)(graphics->src + offset), (void *)(graphics->dest + offset), graphics->size); #endif } From 549ddf088d06d1c1ce232c132f5441addb0b2704 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 24 Feb 2026 18:50:32 +0000 Subject: [PATCH 32/51] clean up --- Makefile | 37 ++------ include/gba/io_reg.h | 48 +++++----- src/platform/pret_sdl/sdl2.c | 161 +++++++++++----------------------- src/platform/psp/psp_module.c | 40 --------- 4 files changed, 84 insertions(+), 202 deletions(-) delete mode 100644 src/platform/psp/psp_module.c diff --git a/Makefile b/Makefile index c90069e059..d8c3690c12 100644 --- a/Makefile +++ b/Makefile @@ -58,8 +58,6 @@ else ifeq ($(PLATFORM),psp) PSPSDK := $(PSPDEV)/psp/sdk export PATH := $(PSPDEV)/bin:$(PATH) PREFIX := psp- -else ifeq ($(PLATFORM),sdl_ps2) - PREFIX := mips64r5900el-ps2-elf- else ifeq ($(PLATFORM),ps2) PREFIX := mips64r5900el-ps2-elf- else @@ -135,10 +133,6 @@ else ifeq ($(PLATFORM),psp) ROM := EBOOT.PBP ELF := $(BUILD_NAME).psp.elf MAP := $(BUILD_NAME).psp.map -else ifeq ($(PLATFORM),sdl_ps2) -ROM := $(BUILD_NAME).$(PLATFORM).iso -ELF := $(ROM:.iso=.elf) -MAP := $(ROM:.iso=.map) else ifeq ($(PLATFORM),ps2) ROM := $(BUILD_NAME).$(PLATFORM).iso ELF := $(ROM:.iso=.elf) @@ -179,17 +173,15 @@ TILESETS_SUBDIR = graphics/tilesets/ ifeq ($(PLATFORM),gba) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),psp) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") -else ifeq ($(PLATFORM),sdl_ps2) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),ps2) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/pret_sdl/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") else ifeq ($(PLATFORM),sdl_win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),win32) -C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/psp/*" -not -path "*/platform/ps2/*") +C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/pret_sdl/*" -not -path "*/platform/ps2/*") else C_SRCS := $(shell find $(C_SUBDIR) -name "*.c") endif @@ -265,9 +257,6 @@ else else ifeq ($(PLATFORM),psp) CC1FLAGS += -G0 CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600 - else ifeq ($(PLATFORM),sdl_ps2) - CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math - CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/ports/include $(shell $(PS2SDK)/ports/bin/sdl2-config --cflags) else ifeq ($(PLATFORM),ps2) CC1FLAGS += -G0 -Wno-parentheses-equality -Wno-unused-value -ffast-math CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=0 -D PLATFORM_WIN32=0 -D_EE -D__PS2__ -I$(PS2SDK)/common/include -I$(PS2SDK)/ee/include -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include @@ -294,8 +283,6 @@ else ifeq ($(PLATFORM),psp) # -O3 for PSP (Allegrex MIPS, small D-cache) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer - else ifeq ($(PLATFORM),sdl_ps2) - CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else ifeq ($(PLATFORM),ps2) CC1FLAGS += -O3 -fomit-frame-pointer else @@ -339,8 +326,6 @@ else CPP := $(CC1) -E else ifeq ($(PLATFORM), psp) CPP := $(CC1) -E - else ifeq ($(PLATFORM), sdl_ps2) - ASFLAGS += -msingle-float else ifeq ($(PLATFORM), ps2) ASFLAGS += -msingle-float endif @@ -364,8 +349,6 @@ else ifeq ($(PLATFORM),sdl) # PSP else ifeq ($(PLATFORM),psp) MAP_FLAG := -Xlinker -Map= -else ifeq ($(PLATFORM),sdl_ps2) - MAP_FLAG := -Xlinker -Map= else ifeq ($(PLATFORM),ps2) MAP_FLAG := -Xlinker -Map= # Win32 @@ -380,8 +363,6 @@ else ifeq ($(PLATFORM),sdl) LIBS := $(shell sdl2-config --cflags --libs) else ifeq ($(PLATFORM),psp) LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128 -else ifeq ($(PLATFORM),sdl_ps2) - LIBS := -lSDL2 $(shell $(PS2SDK)/ports/bin/sdl2-config --libs) -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),ps2) LIBS := -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -lgskit -ldmakit -lps2_drivers -lmc -lpatches -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),sdl_win32) @@ -489,8 +470,6 @@ sdl: ; @$(MAKE) PLATFORM=sdl psp: ; @$(MAKE) PLATFORM=psp -sdl_ps2: ; @$(MAKE) PLATFORM=sdl_ps2 - ps2: ; @$(MAKE) PLATFORM=ps2 tas_sdl: ; @$(MAKE) sdl TAS_TESTING=1 @@ -559,6 +538,9 @@ ifeq ($(PLATFORM),gba) $(ROM): $(ELF) libagbsyscall $(OBJCOPY) -O binary --pad-to 0x8400000 $< $@ $(FIX) $@ -p -t"$(TITLE)" -c$(GAME_CODE) -m$(MAKER_CODE) -r$(GAME_REVISION) --silent +else ifeq ($(PLATFORM),win32) +$(ROM): $(ELF) libagbsyscall + $(OBJCOPY) -O pei-x86-64 $< $@ else $(ROM): $(ELF) ifeq ($(PLATFORM),sdl) @@ -569,11 +551,6 @@ else ifeq ($(PLATFORM),psp) psp-strip $< -o $(BUILD_NAME).psp_strip.elf pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL -rm -f $(BUILD_NAME).psp_strip.elf -else ifeq ($(PLATFORM),sdl_ps2) - @echo Creating $(ROM) from $(ELF) - @cp -r ps2/ntsc $(OBJ_DIR)/iso - @cp $< $(OBJ_DIR)/iso/$(PS2_GAME_CODE) - @mkisofs -o $(ROM) $(OBJ_DIR)/iso/ else ifeq ($(PLATFORM),ps2) @echo Creating $(ROM) from $(ELF) @cp -r ps2/ntsc $(OBJ_DIR)/iso diff --git a/include/gba/io_reg.h b/include/gba/io_reg.h index b829d1cf80..d1ab08dbbe 100644 --- a/include/gba/io_reg.h +++ b/include/gba/io_reg.h @@ -8,6 +8,7 @@ // these are not hardware registers on ports // so there is no need to make re-read them #if PORTABLE +typedef uint8_t reg_u8; typedef uint16_t reg_u16; typedef uint32_t reg_u32; typedef int16_t reg_s16; @@ -15,6 +16,7 @@ typedef int32_t reg_s32; typedef uint64_t reg_u64; typedef winreg_t reg_wint; #else +typedef volatile uint8_t reg_u8; typedef volatile uint16_t reg_u16; typedef volatile uint32_t reg_u32; typedef volatile int16_t reg_s16; @@ -435,42 +437,42 @@ extern unsigned char REG_BASE[IO_SIZE]; #define REG_BLDY (*(reg_u16 *)REG_ADDR_BLDY) #define REG_SOUND1CNT_L (*(reg_u16 *)REG_ADDR_SOUND1CNT_L) -#define REG_NR10 (*(vu8 *)REG_ADDR_NR10) +#define REG_NR10 (*(reg_u8 *)REG_ADDR_NR10) #define REG_SOUND1CNT_H (*(reg_u16 *)REG_ADDR_SOUND1CNT_H) -#define REG_NR11 (*(vu8 *)REG_ADDR_NR11) -#define REG_NR12 (*(vu8 *)REG_ADDR_NR12) +#define REG_NR11 (*(reg_u8 *)REG_ADDR_NR11) +#define REG_NR12 (*(reg_u8 *)REG_ADDR_NR12) #define REG_SOUND1CNT_X (*(reg_u16 *)REG_ADDR_SOUND1CNT_X) -#define REG_NR13 (*(vu8 *)REG_ADDR_NR13) -#define REG_NR14 (*(vu8 *)REG_ADDR_NR14) +#define REG_NR13 (*(reg_u8 *)REG_ADDR_NR13) +#define REG_NR14 (*(reg_u8 *)REG_ADDR_NR14) #define REG_SOUND2CNT_L (*(reg_u16 *)REG_ADDR_SOUND2CNT_L) -#define REG_NR21 (*(vu8 *)REG_ADDR_NR21) -#define REG_NR22 (*(vu8 *)REG_ADDR_NR22) +#define REG_NR21 (*(reg_u8 *)REG_ADDR_NR21) +#define REG_NR22 (*(reg_u8 *)REG_ADDR_NR22) #define REG_SOUND2CNT_H (*(reg_u16 *)REG_ADDR_SOUND2CNT_H) -#define REG_NR23 (*(vu8 *)REG_ADDR_NR23) -#define REG_NR24 (*(vu8 *)REG_ADDR_NR24) +#define REG_NR23 (*(reg_u8 *)REG_ADDR_NR23) +#define REG_NR24 (*(reg_u8 *)REG_ADDR_NR24) #define REG_SOUND3CNT_L (*(reg_u16 *)REG_ADDR_SOUND3CNT_L) -#define REG_NR30 (*(vu8 *)REG_ADDR_NR30) +#define REG_NR30 (*(reg_u8 *)REG_ADDR_NR30) #define REG_SOUND3CNT_H (*(reg_u16 *)REG_ADDR_SOUND3CNT_H) -#define REG_NR31 (*(vu8 *)REG_ADDR_NR31) -#define REG_NR32 (*(vu8 *)REG_ADDR_NR32) +#define REG_NR31 (*(reg_u8 *)REG_ADDR_NR31) +#define REG_NR32 (*(reg_u8 *)REG_ADDR_NR32) #define REG_SOUND3CNT_X (*(reg_u16 *)REG_ADDR_SOUND3CNT_X) -#define REG_NR33 (*(vu8 *)REG_ADDR_NR33) -#define REG_NR34 (*(vu8 *)REG_ADDR_NR34) +#define REG_NR33 (*(reg_u8 *)REG_ADDR_NR33) +#define REG_NR34 (*(reg_u8 *)REG_ADDR_NR34) #define REG_SOUND4CNT_L (*(reg_u16 *)REG_ADDR_SOUND4CNT_L) -#define REG_NR41 (*(vu8 *)REG_ADDR_NR41) -#define REG_NR42 (*(vu8 *)REG_ADDR_NR42) +#define REG_NR41 (*(reg_u8 *)REG_ADDR_NR41) +#define REG_NR42 (*(reg_u8 *)REG_ADDR_NR42) #define REG_SOUND4CNT_H (*(reg_u16 *)REG_ADDR_SOUND4CNT_H) -#define REG_NR43 (*(vu8 *)REG_ADDR_NR43) -#define REG_NR44 (*(vu8 *)REG_ADDR_NR44) +#define REG_NR43 (*(reg_u8 *)REG_ADDR_NR43) +#define REG_NR44 (*(reg_u8 *)REG_ADDR_NR44) #define REG_SOUNDCNT_L (*(reg_u16 *)REG_ADDR_SOUNDCNT_L) -#define REG_NR50 (*(vu8 *)REG_ADDR_NR50) -#define REG_NR51 (*(vu8 *)REG_ADDR_NR51) +#define REG_NR50 (*(reg_u8 *)REG_ADDR_NR50) +#define REG_NR51 (*(reg_u8 *)REG_ADDR_NR51) #define REG_SOUNDCNT_H (*(reg_u16 *)REG_ADDR_SOUNDCNT_H) #define REG_SOUNDCNT_X (*(reg_u16 *)REG_ADDR_SOUNDCNT_X) -#define REG_NR52 (*(vu8 *)REG_ADDR_NR52) +#define REG_NR52 (*(reg_u8 *)REG_ADDR_NR52) #define REG_SOUNDBIAS (*(reg_u16 *)REG_ADDR_SOUNDBIAS) -#define REG_SOUNDBIAS_L (*(vu8 *)REG_ADDR_SOUNDBIAS_L) -#define REG_SOUNDBIAS_H (*(vu8 *)REG_ADDR_SOUNDBIAS_H) +#define REG_SOUNDBIAS_L (*(reg_u8 *)REG_ADDR_SOUNDBIAS_L) +#define REG_SOUNDBIAS_H (*(reg_u8 *)REG_ADDR_SOUNDBIAS_H) #define REG_WAVE_RAM0 (*(reg_u32 *)REG_ADDR_WAVE_RAM0) #define REG_WAVE_RAM1 (*(reg_u32 *)REG_ADDR_WAVE_RAM1) #define REG_WAVE_RAM2 (*(reg_u32 *)REG_ADDR_WAVE_RAM2) diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 22d5512f7d..15a768b512 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -12,7 +12,9 @@ #ifdef __PSP__ #include -extern int setupPspCallbacks(void); +#include +#include +#include #endif #include @@ -98,7 +100,7 @@ bool paused = false; bool stepOneFrame = false; bool headless = false; -#if defined(__PSP__) || defined(__PS2__) +#ifdef __PSP__ static SDL_Joystick *joystick = NULL; #endif @@ -136,44 +138,41 @@ void *Platform_malloc(size_t numBytes) { return HeapAlloc(GetProcessHeap(), HEAP void Platform_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #endif -#ifdef __PS2__ -// TODO: clean these for what is needed -#include -#include -#include +#ifdef __PSP__ +PSP_MODULE_INFO("SonicAdvance2", 0, 1, 0); +PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU); +PSP_HEAP_SIZE_KB(-1024); -#include -#include -#include -#include -#include -#include +unsigned int sce_newlib_stack_size = 512 * 1024; -void reset_IOP() -{ - SifInitRpc(0); - while (!SifIopReset(NULL, 0)) { } // Comment this line if you want to "debug" through ps2link - while (!SifIopSync()) { } -} +extern bool isRunning; -static void prepare_IOP() +int exitCallback(int arg1, int arg2, void *common) { - reset_IOP(); - SifInitRpc(0); - sbv_patch_enable_lmb(); - sbv_patch_disable_prefix_check(); + (void)arg1; + (void)arg2; + (void)common; + isRunning = false; + return 0; } -static void init_drivers() +int callbackThread(SceSize args, void *argp) { - init_only_boot_ps2_filesystem_driver(); - init_memcard_driver(true); + (void)args; + (void)argp; + int cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL); + sceKernelRegisterExitCallback(cbid); + sceKernelSleepThreadCB(); + return 0; } -static void deinit_drivers() +int setupPspCallbacks(void) { - deinit_memcard_driver(true); - deinit_only_boot_ps2_filesystem_driver(); + int thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0); + if (thid >= 0) { + sceKernelStartThread(thid, 0, 0); + } + return thid; } #endif @@ -183,10 +182,6 @@ int main(int argc, char **argv) setupPspCallbacks(); #endif -#ifdef __PS2__ - prepare_IOP(); -#endif - const char *headlessEnv = getenv("HEADLESS"); if (headlessEnv && strcmp(headlessEnv, "true") == 0) { @@ -209,9 +204,7 @@ int main(int argc, char **argv) freopen("CON", "w", stdout); #endif -#ifndef __PS2__ ReadSaveFile("sa2.sav"); -#endif // Prevent the multiplayer screen from being drawn ( see core.c:EngineInit() ) REG_RCNT = 0x8000; @@ -231,7 +224,7 @@ int main(int argc, char **argv) return 1; } -#if defined(__PSP__) || defined(__PS2__) +#ifdef __PSP__ if (SDL_NumJoysticks() > 0) { joystick = SDL_JoystickOpen(0); } @@ -245,8 +238,6 @@ int main(int argc, char **argv) #ifdef __PSP__ sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 480, 272, SDL_WINDOW_SHOWN); -#elif defined(__PS2__) - sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 448, SDL_WINDOW_SHOWN); #else sdlWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, DISPLAY_WIDTH * videoScale, DISPLAY_HEIGHT * videoScale, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); @@ -278,8 +269,6 @@ int main(int argc, char **argv) sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); if (sdlRenderer == NULL) sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0); -#elif defined(__PS2__) - sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); #else sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC); #endif @@ -325,12 +314,6 @@ int main(int argc, char **argv) } #endif -#ifdef __PS2__ - SDL_SetTextureScaleMode(sdlTexture, SDL_ScaleModeLinear); - // For some reason we are WAY blown out on the PS2 - SDL_SetTextureColorMod(sdlTexture, 140, 140, 140); -#endif - #if ENABLE_AUDIO SDL_AudioSpec want; @@ -382,13 +365,9 @@ void VBlankIntrWait(void) bool frameAvailable = TRUE; bool frameDrawn = false; -#if defined(__PSP__) || defined(__PS2__) - static int frames_skipped = 0; -#define MAX_FRAME_SKIP 2 -#endif while (isRunning) { -#if !defined(__PS2__) && !defined(__PSP__) +#ifndef __PSP__ ProcessSDLEvents(); #endif @@ -418,18 +397,6 @@ void VBlankIntrWait(void) while (accumulator >= dt) { REG_KEYINPUT = KEYS_MASK ^ Platform_GetKeyInput(); if (frameAvailable) { -#if defined(__PSP__) || defined(__PS2__) - // frame skip: let game logic catch up when behind - if (accumulator >= dt * 2.0 && frames_skipped < MAX_FRAME_SKIP) { - frames_skipped++; - frameAvailable = FALSE; - HANDLE_VBLANK_INTRS(); - accumulator -= dt; - newFrameRequested = TRUE; - return; - } - frames_skipped = 0; -#endif VDraw(sdlTexture); frameAvailable = FALSE; frameDrawn = true; @@ -451,18 +418,9 @@ void VBlankIntrWait(void) // present #ifdef __PSP__ // manual blit since SDL_RenderSetLogicalSize doesn't work on psp - if (frameDrawn) { - SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &pspDestRect); - SDL_RenderPresent(sdlRenderer); - frameDrawn = false; - } else { - SDL_Delay(1); - } + SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &pspDestRect); + SDL_RenderPresent(sdlRenderer); #else -#ifdef __PS2__ - // Allow audio to play - DelayThread(800); -#endif SDL_RenderClear(sdlRenderer); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); @@ -535,6 +493,8 @@ static void CloseSaveFile() } } +static u16 keys; + // Key mappings #define KEY_A_BUTTON SDLK_c #define KEY_B_BUTTON SDLK_x @@ -557,24 +517,7 @@ static void CloseSaveFile() keys |= key; \ break; -static u16 keys; - -#if defined(__PSP__) || defined(__PS2__) - -#ifdef __PS2__ -#define BTN_TRIANGLE 12 -#define BTN_CIRCLE 13 -#define BTN_CROSS 14 -#define BTN_SQUARE 15 -#define BTN_LTRIGGER 10 -#define BTN_RTRIGGER 11 -#define BTN_DOWN 6 -#define BTN_LEFT 7 -#define BTN_UP 4 -#define BTN_RIGHT 5 -#define BTN_SELECT 0 -#define BTN_START 3 -#else +#ifdef __PSP__ #define BTN_TRIANGLE 0 #define BTN_CIRCLE 1 #define BTN_CROSS 2 @@ -587,41 +530,41 @@ static u16 keys; #define BTN_RIGHT 9 #define BTN_SELECT 10 #define BTN_START 11 -#endif static u16 PollJoystickButtons(void) { - u16 keys = 0; + u16 newKeys = 0; if (joystick == NULL) - return keys; + return newKeys; SDL_JoystickUpdate(); if (SDL_JoystickGetButton(joystick, BTN_CROSS)) - keys |= A_BUTTON; + newKeys |= A_BUTTON; if (SDL_JoystickGetButton(joystick, BTN_CIRCLE)) - keys |= B_BUTTON; + newKeys |= B_BUTTON; if (SDL_JoystickGetButton(joystick, BTN_SQUARE)) - keys |= B_BUTTON; // Square also B + newKeys |= B_BUTTON; // Square also B if (SDL_JoystickGetButton(joystick, BTN_START)) - keys |= START_BUTTON; + newKeys |= START_BUTTON; if (SDL_JoystickGetButton(joystick, BTN_SELECT)) - keys |= SELECT_BUTTON; + newKeys |= SELECT_BUTTON; if (SDL_JoystickGetButton(joystick, BTN_LTRIGGER)) - keys |= L_BUTTON; + newKeys |= L_BUTTON; if (SDL_JoystickGetButton(joystick, BTN_RTRIGGER)) - keys |= R_BUTTON; + newKeys |= R_BUTTON; if (SDL_JoystickGetButton(joystick, BTN_UP)) - keys |= DPAD_UP; + newKeys |= DPAD_UP; if (SDL_JoystickGetButton(joystick, BTN_DOWN)) - keys |= DPAD_DOWN; + newKeys |= DPAD_DOWN; if (SDL_JoystickGetButton(joystick, BTN_LEFT)) - keys |= DPAD_LEFT; + newKeys |= DPAD_LEFT; if (SDL_JoystickGetButton(joystick, BTN_RIGHT)) - keys |= DPAD_RIGHT; + newKeys |= DPAD_RIGHT; - return keys; + return newKeys; } + #endif u32 fullScreenFlags = 0; @@ -764,7 +707,7 @@ u16 Platform_GetKeyInput(void) return (gamepadKeys != 0) ? gamepadKeys : keys; #endif -#if defined(__PSP__) || defined(__PS2__) +#ifdef __PSP__ return keys | PollJoystickButtons(); #endif diff --git a/src/platform/psp/psp_module.c b/src/platform/psp/psp_module.c deleted file mode 100644 index 18040b1e17..0000000000 --- a/src/platform/psp/psp_module.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include - -PSP_MODULE_INFO("SonicAdvance2", 0, 1, 0); -PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU); -PSP_HEAP_SIZE_KB(-1024); - -unsigned int sce_newlib_stack_size = 512 * 1024; - -extern bool isRunning; - -int exitCallback(int arg1, int arg2, void *common) -{ - (void)arg1; - (void)arg2; - (void)common; - isRunning = false; - return 0; -} - -int callbackThread(SceSize args, void *argp) -{ - (void)args; - (void)argp; - int cbid = sceKernelCreateCallback("Exit Callback", exitCallback, NULL); - sceKernelRegisterExitCallback(cbid); - sceKernelSleepThreadCB(); - return 0; -} - -int setupPspCallbacks(void) -{ - int thid = sceKernelCreateThread("update_thread", callbackThread, 0x11, 0xFA0, 0, 0); - if (thid >= 0) { - sceKernelStartThread(thid, 0, 0); - } - return thid; -} From 8e5068f51427303e8753e350ef105d6062892c43 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 24 Feb 2026 19:00:51 +0000 Subject: [PATCH 33/51] more cleanup --- Makefile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Makefile b/Makefile index d8c3690c12..d37389b348 100644 --- a/Makefile +++ b/Makefile @@ -346,12 +346,7 @@ else ifeq ($(PLATFORM),sdl) else MAP_FLAG := -Xlinker -Map= endif -# PSP -else ifeq ($(PLATFORM),psp) - MAP_FLAG := -Xlinker -Map= -else ifeq ($(PLATFORM),ps2) - MAP_FLAG := -Xlinker -Map= -# Win32 +# Win32, PSP, PS2 else MAP_FLAG := -Xlinker -Map= endif From cef73e5e4eea86a0e15c3f3b473e60db34a839f5 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 25 Feb 2026 00:35:15 +0000 Subject: [PATCH 34/51] build fixes for psp, add ps2 to workflow --- .github/workflows/build.yml | 69 +++++++++++++++++++++--------------- Makefile | 11 +++--- src/platform/pret_sdl/sdl2.c | 10 ++---- src/platform/shared/dma.c | 2 +- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 503efb933d..751103520d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,39 +2,39 @@ name: CI on: push: - branches: [ main ] + branches: [main] pull_request: pull_request_target: jobs: format: - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ubuntu-22.04 steps: - name: Checkout PR - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} + if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} uses: actions/checkout@master with: ref: ${{ github.event.pull_request.head.sha }} - name: Checkout if: ${{ github.event_name == 'push' }} uses: actions/checkout@master - + - name: Install tools run: | sudo apt update && sudo apt install clang-format-13 - + - name: Check formatting run: | make check_format build-gba: - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ubuntu-22.04 name: Build GBA (USA) steps: - name: Checkout PR - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} + if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} uses: actions/checkout@master with: ref: ${{ github.event.pull_request.head.sha }} @@ -42,7 +42,7 @@ jobs: - name: Checkout if: ${{ github.event_name == 'push' }} uses: actions/checkout@master - + - name: Checkout gh-pages if: ${{ github.event_name == 'push' }} uses: actions/checkout@master @@ -120,17 +120,17 @@ jobs: cwd: "./gh-pages" add: "reports maps" message: ${{ env.REPORTS_COMMIT_MSG }} - + build-gba-variants: - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ubuntu-22.04 name: Build GBA (${{ matrix.variant }}) strategy: - matrix: + matrix: variant: ["europe", "japan", "japan_vc", "usa_beta"] steps: - name: Checkout PR - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} + if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} uses: actions/checkout@master with: ref: ${{ github.event.pull_request.head.sha }} @@ -138,7 +138,7 @@ jobs: - name: Checkout if: ${{ github.event_name == 'push' }} uses: actions/checkout@master - + - name: Checkout gh-pages if: ${{ github.event_name == 'push' }} uses: actions/checkout@master @@ -167,15 +167,15 @@ jobs: ports: strategy: - matrix: - platform: ["sdl", "sdl_win32", "win32"] + matrix: + platform: ["sdl", "sdl_win32", "win32", "ps2"] os: ["ubuntu-22.04", "macos-15"] - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ${{ matrix.os }} name: Build ${{ matrix.platform }} (${{ matrix.os }}) steps: - name: Checkout PR - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} + if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} uses: actions/checkout@master with: ref: ${{ github.event.pull_request.head.sha }} @@ -193,26 +193,39 @@ jobs: if: ${{ matrix.os == 'macos-15' }} run: | brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc - + - name: Install SDL for win32 if: ${{ matrix.platform == 'sdl_win32' }} run: | make SDL2.dll - + + # TODO: Don't install latest SDK, use a stable version + - name: Install PS2DEV + if: ${{ matrix.platform == 'ps2' }} + run: | + echo "PS2DEV=$HOME/ps2dev" >> "$GITHUB_ENV" + mkdir -p $PS2DEV + echo "PS2SDK=$PS2DEV/ps2sdk" >> "$GITHUB_ENV" + echo "GSKIT=$PS2DEV/gsKit" >> "$GITHUB_ENV" + echo "$PS2DEV/bin" >> "$GITHUB_PATH" + echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH" + curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz + tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV + - name: ${{ matrix.platform }} run: | make -j${nproc} ${{ matrix.platform }} test: strategy: - matrix: + matrix: platform: ["sdl"] - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ubuntu-22.04 name: TAS Test ${{ matrix.platform }} steps: - name: Checkout PR - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} + if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} uses: actions/checkout@master with: ref: ${{ github.event.pull_request.head.sha }} @@ -224,16 +237,16 @@ jobs: - name: Install tools run: | sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools - + - name: Install SDL for win32 if: ${{ matrix.platform == 'sdl_win32' }} run: | make SDL2.dll - + - name: Build ${{ matrix.platform }} run: | make -j${nproc} ${{ matrix.platform }} TAS_TESTING=1 - + - name: Run TAS timeout-minutes: 1 env: @@ -242,12 +255,12 @@ jobs: ./sa2.${{ matrix.platform }} level_editor: - if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} + if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ubuntu-22.04 name: Level editor (BriBaSA) steps: - name: Checkout PR - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} + if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} uses: actions/checkout@master with: ref: ${{ github.event.pull_request.head.sha }} @@ -259,7 +272,7 @@ jobs: - name: Install deps run: | sudo apt update && sudo apt install xorg-dev libsdl2-dev - + - name: Build run: | make -j${nproc} bribasa diff --git a/Makefile b/Makefile index d37389b348..a7429b953a 100644 --- a/Makefile +++ b/Makefile @@ -541,11 +541,12 @@ $(ROM): $(ELF) ifeq ($(PLATFORM),sdl) cp $< $@ else ifeq ($(PLATFORM),psp) - psp-fixup-imports $< - mksfoex 'Sonic Advance 2' PARAM.SFO - psp-strip $< -o $(BUILD_NAME).psp_strip.elf - pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL - -rm -f $(BUILD_NAME).psp_strip.elf + @echo Creating $(ROM) from $(ELF) + @psp-fixup-imports $< + @mksfoex 'Sonic Advance 2' PARAM.SFO + @psp-strip $< -o $(BUILD_NAME).psp_strip.elf + @pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL $(BUILD_NAME).psp_strip.elf NULL + @-rm -f $(BUILD_NAME).psp_strip.elf else ifeq ($(PLATFORM),ps2) @echo Creating $(ROM) from $(ELF) @cp -r ps2/ntsc $(OBJ_DIR)/iso diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 15a768b512..e645f09f8a 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -13,8 +13,7 @@ #ifdef __PSP__ #include #include -#include -#include +#include #endif #include @@ -102,11 +101,6 @@ bool headless = false; #ifdef __PSP__ static SDL_Joystick *joystick = NULL; -#endif - -#ifdef __PSP__ -#define PSP_SCREEN_W 480 -#define PSP_SCREEN_H 272 static SDL_Rect pspDestRect; #endif @@ -290,7 +284,7 @@ int main(int argc, char **argv) SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); #ifdef __PSP__ // SDL_RenderSetLogicalSize is broken on PSP, stretch to fill manually - pspDestRect = (SDL_Rect) { 0, 0, PSP_SCREEN_W, PSP_SCREEN_H }; + pspDestRect = (SDL_Rect) { 0, 0, GU_SCR_WIDTH, GU_SCR_HEIGHT }; #else SDL_RenderSetLogicalSize(sdlRenderer, DISPLAY_WIDTH, DISPLAY_HEIGHT); #endif diff --git a/src/platform/shared/dma.c b/src/platform/shared/dma.c index 24bf15f06f..343a27cac0 100644 --- a/src/platform/shared/dma.c +++ b/src/platform/shared/dma.c @@ -4,7 +4,7 @@ struct DMATransfer DMAList[DMA_COUNT] = { 0 }; -void RunDMAs(u32 type) +void RunDMAs(DmaStartTypes type) { for (int dmaNum = 0; dmaNum < DMA_COUNT; dmaNum++) { struct DMATransfer *dma = &DMAList[dmaNum]; From 34ebe9788b096e557b377e5e7df22dc20ebecb38 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 25 Feb 2026 00:39:40 +0000 Subject: [PATCH 35/51] fix pipeline, update readme --- .github/workflows/build.yml | 1 + README.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 751103520d..7b7931c5b4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -203,6 +203,7 @@ jobs: - name: Install PS2DEV if: ${{ matrix.platform == 'ps2' }} run: | + PS2DEV="$HOME/ps2dev" echo "PS2DEV=$HOME/ps2dev" >> "$GITHUB_ENV" mkdir -p $PS2DEV echo "PS2SDK=$PS2DEV/ps2sdk" >> "$GITHUB_ENV" diff --git a/README.md b/README.md index 1dd07df9fa..d0db121f66 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,8 @@ It can also build: * **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port) * **sa2.sdl_win32.exe** `make sdl_win32` (Windows SDL 64bit port) * :construction: **sa2.win32.exe** `make win32` (Win32 native port, not functional) -* **EBOOT.PBP** `make psp` (PlayStation Portable homebrew port, requires [PSPDEV](https://github.com/pspdev/pspdev)) +* **sa2.ps2.iso** `make ps2` (Playstation 2 port, requires [PS2DEV](https://github.com/ps2dev/ps2dev)) +* **EBOOT.PBP** `make psp` (PlayStation Portable port, requires [PSPDEV](https://github.com/pspdev/pspdev)) ## Current state From 1964dc8d78b989d367f0b196d76270eee9dd7af2 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 25 Feb 2026 13:15:31 +0000 Subject: [PATCH 36/51] fix ps2 build --- README.md | 2 +- src/platform/ps2/ps2.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d0db121f66..e980f96c49 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ It can also build: * **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port) * **sa2.sdl_win32.exe** `make sdl_win32` (Windows SDL 64bit port) * :construction: **sa2.win32.exe** `make win32` (Win32 native port, not functional) -* **sa2.ps2.iso** `make ps2` (Playstation 2 port, requires [PS2DEV](https://github.com/ps2dev/ps2dev)) +* **sa2.ps2.iso** `make ps2` (PlayStation 2 port, requires [PS2DEV](https://github.com/ps2dev/ps2dev)) * **EBOOT.PBP** `make psp` (PlayStation Portable port, requires [PSPDEV](https://github.com/pspdev/pspdev)) ## Current state diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index 4a28e242a8..a42ebdeccb 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -392,7 +392,10 @@ void VBlankIntrWait(void) HANDLE_VBLANK_INTRS(); if (use_hires) { - gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1); + gsKit_hires_sync(gsGlobal); + gsKit_hires_flip(gsGlobal); + // TODO: use once released on the SDK + // gsKit_hires_flip_ext(gsGlobal, GSFLIP_RATE_LIMIT_1); } else { gsKit_sync_flip(gsGlobal); gsKit_queue_exec(gsGlobal); From 55d7b6554b627d211da285a80ee2714b4f56fae7 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 25 Feb 2026 13:22:47 +0000 Subject: [PATCH 37/51] add missing deps --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7b7931c5b4..5f165da63e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -187,12 +187,12 @@ jobs: - name: Install tools (Linux) if: ${{ matrix.os == 'ubuntu-22.04' }} run: | - sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools + sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs - name: Install Tools (Macos) if: ${{ matrix.os == 'macos-15' }} run: | - brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc + brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc cdrtools - name: Install SDL for win32 if: ${{ matrix.platform == 'sdl_win32' }} From 2431c227344357eb845e5cafeb87141cfc9bef08 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 2 Mar 2026 01:32:00 +0000 Subject: [PATCH 38/51] fix background rendering, add deps for new requirements --- INSTALL.md | 4 +- include/platform/shared/video/gpsp_renderer.h | 7 +- src/game/game.c | 3 + src/game/stage/camera.c | 2 +- src/platform/pret_sdl/sdl2.c | 9 +-- src/platform/shared/video/gpsp_renderer.cc | 73 +++++++++++++++---- 6 files changed, 72 insertions(+), 26 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 4feb4b25fd..f1e6b997dd 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -14,13 +14,13 @@ Install WSL (Ubuntu). Once installed, open this project in the WSL terminal and #### On Linux (including WSL) ``` sudo apt update -sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools +sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs ``` #### On MacOS ``` -brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc +brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc cdrtools ``` ## Building diff --git a/include/platform/shared/video/gpsp_renderer.h b/include/platform/shared/video/gpsp_renderer.h index 5c15b3f7ea..3834bf8a4b 100644 --- a/include/platform/shared/video/gpsp_renderer.h +++ b/include/platform/shared/video/gpsp_renderer.h @@ -4,7 +4,7 @@ // shared color math for the gba ppu blend unit // used by both the normal (multi-pass) and fast (single-pass) software renderers -#include +#include "global.h" // bgr555 channel extraction #define getAlphaBit(x) (((x) >> 15) & 1) @@ -61,6 +61,11 @@ static inline uint16_t alphaBrightnessDecrease(uint16_t targetA, unsigned int ev return r | (g << 5) | (b << 10) | COLOR_OPAQUE; } +#define TILE_WIDTH 8 +#define VRAM_VIEW_WIDTH (32 * TILE_WIDTH) +#define VRAM_VIEW_HEIGHT (((VRAM_SIZE / TILE_SIZE_4BPP) / 32) * TILE_WIDTH) + extern void gpsp_draw_frame(uint16_t *framebuf); +extern void gpsp_draw_vram_view(uint16_t *framebuf); #endif // GUARD_SW_RENDERER_COMMON_H diff --git a/src/game/game.c b/src/game/game.c index ac141e67ac..9f10b4dfea 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -106,6 +106,9 @@ void GameInit(void) // GameStageStart(); #elif ENABLE_DECOMP_CREDITS + // gCurrentLevel = LEVEL_INDEX(ZONE_4, ACT_1); + // ApplyGameStageSettings(); + // GameStageStart(); CreateDecompCreditsScreen(hasProfile); #else if (gFlags & FLAGS_NO_FLASH_MEMORY) { diff --git a/src/game/stage/camera.c b/src/game/stage/camera.c index ebfc56a4d2..66f974ce92 100644 --- a/src/game/stage/camera.c +++ b/src/game/stage/camera.c @@ -941,7 +941,7 @@ NONMATCH("asm/non_matching/game/stage/background/StageBgUpdate_Zone2Acts12.inc", gFlags |= FLAGS_EXECUTE_HBLANK_COPY; gHBlankCopyTarget = (void *)REG_ADDR_BG3HOFS; - gHBlankCopySize = 4; + gHBlankCopySize = sizeof(u16) * 2; cursor = gBgOffsetsHBlankPrimary; dt = gStageTime * 0x18; diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index e645f09f8a..02636ac17b 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -1961,14 +1961,7 @@ void VramDraw(SDL_Texture *texture) void VDraw(SDL_Texture *texture) { -// TODO: always use this renderer -#if TRUE - { - gpsp_draw_frame(gameImage); - } -#else - DrawFrame(gameImage); -#endif + gpsp_draw_frame(gameImage); SDL_UpdateTexture(texture, NULL, gameImage, DISPLAY_WIDTH * sizeof(Uint16)); REG_VCOUNT = DISPLAY_HEIGHT + 1; // prep for being in VBlank period } diff --git a/src/platform/shared/video/gpsp_renderer.cc b/src/platform/shared/video/gpsp_renderer.cc index 255e8d18be..22cad8fede 100644 --- a/src/platform/shared/video/gpsp_renderer.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -50,6 +50,10 @@ extern "C" { u16 *gba_screen_pixels = NULL; +#if ENABLE_VRAM_VIEW +uint8_t vram_pal_id_buffer[(VRAM_VIEW_WIDTH / TILE_WIDTH) * (VRAM_VIEW_HEIGHT / TILE_WIDTH)]; +#endif + #define get_screen_pixels() gba_screen_pixels #define get_screen_pitch() GBA_SCREEN_PITCH @@ -363,13 +367,15 @@ static void render_scanline_text_fast(u32 layer, u32 start, u32 end, void *scanl second_ptr = map_ptr = map_base; if (map_size & 0x01) { // If background is 512 pixels wide + // HACK: for SA2 we need this logic disabled to enable >240 width + // background rendering, or some windowing stuff messes up if (hoffset >= 256) { // If we are rendering the right block, skip a whole charblock - hoffset -= 256; - map_ptr += ((map_width / 8) * 32); + // hoffset -= 256; + // map_ptr += ((map_width / 8) * 32); } else { // If we are rendering the left block, we might overrun into the right - second_ptr += ((map_width / 8) * 32); + // second_ptr += ((map_width / 8) * 32); } } else { hoffset %= 256; // Background is 256 pixels wide @@ -439,16 +445,26 @@ static void render_scanline_text_fast(u32 layer, u32 start, u32 end, void *scanl map_ptr = second_ptr; todraw = end / 8; - for (u32 i = 0; i < todraw; i++, dest_ptr += 8) { - u16 tile = eswap16(*map_ptr++); - if (tile & 0x400) // Tile horizontal flip - render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); - else - render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); - } - end -= todraw * 8; + while (todraw) { + // HACK: for sa2 if we are drawing more than 32 tiles then likely + // we need to wrap back to the start since this background probably + // isn't 512 wide + u8 section = MIN(todraw, 32); + for (u32 i = 0; i < section; i++, dest_ptr += 8) { + u16 tile = eswap16(*map_ptr++); + if (tile & 0x400) // Tile horizontal flip + render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); + else + render_tile_Nbpp(bg_comb, px_comb, dest_ptr, tile, tile_base, vflip_off, paltbl); + } + todraw -= section; + if (todraw) { + map_ptr = second_ptr; + } + } + // Finalize the tile rendering the left side of it (from 0 up to "end"). if (end) { u16 tile = eswap16(*map_ptr++); @@ -492,11 +508,11 @@ static void render_scanline_text_mosaic(u32 layer, u32 start, u32 end, void *sca if (map_size & 0x01) { // If background is 512 pixels wide if (hoffset >= 256) { // If we are rendering the right block, skip a whole charblock - hoffset -= 256; - map_ptr += ((map_width / 8) * 32); + // hoffset -= 256; + // map_ptr += ((map_width / 8) * 32); } else { // If we are rendering the left block, we might overrun into the right - second_ptr += ((map_width / 8) * 32); + // second_ptr += ((map_width / 8) * 32); } } else { hoffset %= 256; // Background is 256 pixels wide @@ -2296,4 +2312,33 @@ void gpsp_draw_frame(u16 *framebuf) video_reload_counters(true); } +void gpsp_draw_vram_view(u16 *buffer) +{ +#if ENABLE_VRAM_VIEW + for (int y = 0; y < VRAM_VIEW_HEIGHT / TILE_WIDTH; y++) { + for (int x = 0; x < VRAM_VIEW_WIDTH / TILE_WIDTH; x++) { + u16 tileId = y * (VRAM_VIEW_WIDTH / TILE_WIDTH) + x; + u16 *tileBase = &buffer[(y * VRAM_VIEW_WIDTH + x) * 8]; + + for (int ty = 0; ty < TILE_WIDTH; ty++) { + for (int tx = 0; tx < TILE_WIDTH; tx += 2) { + s32 tileIndex = ty * VRAM_VIEW_WIDTH + tx; + u16 *dest = &tileBase[tileIndex]; + + int i = (ty * TILE_WIDTH + tx) / 2; + u8 *colorPtr = &((u8 *)VRAM)[tileId * 0x20 + i]; + u8 colorId = colorPtr[0]; + u8 colA = (colorId & 0xF0) >> 4; + u8 colB = (colorId & 0x0F) >> 0; + + u8 paletteId = vram_pal_id_buffer[tileId]; + dest[0] = PLTT[paletteId * 16 + colB]; + dest[1] = PLTT[paletteId * 16 + colA]; + } + } + } + } +#endif +} + #endif From 0a9d66497f534f4d8b0dbc713cd654bf62448c57 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 2 Mar 2026 10:26:15 +0000 Subject: [PATCH 39/51] fix gpsp vram draw palettes --- src/platform/pret_sdl/sdl2.c | 2 +- src/platform/shared/video/gpsp_renderer.cc | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 02636ac17b..487e5cab66 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -1954,7 +1954,7 @@ void DrawVramView(Uint16 *buffer) void VramDraw(SDL_Texture *texture) { memset(vramBuffer, 0, sizeof(vramBuffer)); - DrawVramView(vramBuffer); + gpsp_draw_vram_view(vramBuffer); SDL_UpdateTexture(texture, NULL, vramBuffer, VRAM_VIEW_WIDTH * sizeof(Uint16)); } #endif diff --git a/src/platform/shared/video/gpsp_renderer.cc b/src/platform/shared/video/gpsp_renderer.cc index 22cad8fede..8cd1e0e8b5 100644 --- a/src/platform/shared/video/gpsp_renderer.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -283,6 +283,10 @@ static inline void render_tile_Nbpp(u32 bg_comb, u32 px_comb, dtype *dest_ptr, u if (tile & 0x800) tile_ptr += vertical_pixel_flip; +#if ENABLE_VRAM_VIEW + vram_pal_id_buffer[(tile & 0x3FF)] = (tile >> 12) & 0xF; +#endif + if (is8bpp) { for (u32 j = 0; j < 2; j++) { u32 tilepix = eswap32(((u32 *)tile_ptr)[hflip ? 1 - j : j]); @@ -1059,7 +1063,7 @@ static inline void render_obj_part_tile_Nbpp(u32 px_comb, dsttype *dest_ptr, u32 template static inline void render_obj_tile_Nbpp(u32 px_comb, dsttype *dest_ptr, u32 tile_offset, u16 palette, const u16 *pal) { - const u8 *tile_ptr = &VRAM[0x10000 + (tile_offset & 0x7FFF)]; + const u8 *tile_ptr = OBJ_VRAM0 + (tile_offset & (OBJ_VRAM0_SIZE - 1)); u32 px_attr = px_comb | palette | 0x100; // Combine flags + high palette bit if (is8bpp) { @@ -1086,6 +1090,9 @@ static inline void render_obj_tile_Nbpp(u32 px_comb, dsttype *dest_ptr, u32 tile dest_ptr += 4; } } else { +#if ENABLE_VRAM_VIEW + vram_pal_id_buffer[0x800 + (tile_offset >> 5)] = 16 + (palette >> 4); +#endif u32 tilepix = eswap32(*(u32 *)tile_ptr); if (tilepix) { // Can skip all pixels if the row is just transparent for (u32 i = 0; i < 8; i++, dest_ptr++) { @@ -1184,7 +1191,7 @@ static void render_object_mosaic(s32 delta_x, u32 cnt, stype *dst_ptr, u32 base_ if (!(i % mosh)) { // Load tile pixel color. u32 tile_offset = base_tile_offset + (offx / 8) * tile_size_off; - const u8 *tile_ptr = &VRAM[0x10000 + (tile_offset & 0x7FFF)]; + const u8 *tile_ptr = OBJ_VRAM0 + (tile_offset & (OBJ_VRAM0_SIZE - 1)); // Lookup for each mode and flip value. if (is8bpp) { From f88424bb8e38affcefa9ce32743c9cbb11a87726 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Mon, 2 Mar 2026 10:39:09 +0000 Subject: [PATCH 40/51] remove old renderer --- include/platform/shared/video/gpsp_renderer.h | 59 +- src/platform/pret_sdl/sdl2.c | 888 +----------------- src/platform/ps2/ps2.c | 6 - src/platform/shared/video/gpsp_renderer.cc | 2 +- 4 files changed, 5 insertions(+), 950 deletions(-) diff --git a/include/platform/shared/video/gpsp_renderer.h b/include/platform/shared/video/gpsp_renderer.h index 3834bf8a4b..086e22c70d 100644 --- a/include/platform/shared/video/gpsp_renderer.h +++ b/include/platform/shared/video/gpsp_renderer.h @@ -6,62 +6,9 @@ #include "global.h" -// bgr555 channel extraction -#define getAlphaBit(x) (((x) >> 15) & 1) -#define getRedChannel(x) (((x) >> 0) & 0x1F) -#define getGreenChannel(x) (((x) >> 5) & 0x1F) -#define getBlueChannel(x) (((x) >> 10) & 0x1F) -#define COLOR_OPAQUE 0x8000 - -static inline uint16_t alphaBlendColor(uint16_t targetA, uint16_t targetB, unsigned int eva, unsigned int evb) -{ - unsigned int r = ((getRedChannel(targetA) * eva) + (getRedChannel(targetB) * evb)) >> 4; - unsigned int g = ((getGreenChannel(targetA) * eva) + (getGreenChannel(targetB) * evb)) >> 4; - unsigned int b = ((getBlueChannel(targetA) * eva) + (getBlueChannel(targetB) * evb)) >> 4; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | COLOR_OPAQUE; -} - -static inline uint16_t alphaBrightnessIncrease(uint16_t targetA, unsigned int evy) -{ - unsigned int r = getRedChannel(targetA) + (31 - getRedChannel(targetA)) * evy / 16; - unsigned int g = getGreenChannel(targetA) + (31 - getGreenChannel(targetA)) * evy / 16; - unsigned int b = getBlueChannel(targetA) + (31 - getBlueChannel(targetA)) * evy / 16; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | COLOR_OPAQUE; -} - -static inline uint16_t alphaBrightnessDecrease(uint16_t targetA, unsigned int evy) -{ - unsigned int r = getRedChannel(targetA) - getRedChannel(targetA) * evy / 16; - unsigned int g = getGreenChannel(targetA) - getGreenChannel(targetA) * evy / 16; - unsigned int b = getBlueChannel(targetA) - getBlueChannel(targetA) * evy / 16; - - if (r > 31) - r = 31; - if (g > 31) - g = 31; - if (b > 31) - b = 31; - - return r | (g << 5) | (b << 10) | COLOR_OPAQUE; -} - -#define TILE_WIDTH 8 +#ifndef TILE_WIDTH +#define TILE_WIDTH 8 +#endif #define VRAM_VIEW_WIDTH (32 * TILE_WIDTH) #define VRAM_VIEW_HEIGHT (((VRAM_SIZE / TILE_SIZE_4BPP) / 32) * TILE_WIDTH) diff --git a/src/platform/pret_sdl/sdl2.c b/src/platform/pret_sdl/sdl2.c index 487e5cab66..b404a03b67 100644 --- a/src/platform/pret_sdl/sdl2.c +++ b/src/platform/pret_sdl/sdl2.c @@ -33,53 +33,12 @@ #include "platform/shared/audio/cgb_audio.h" #endif -#ifndef TILE_WIDTH -#define TILE_WIDTH 8 -#endif - -extern IntrFunc gIntrTable[16]; - -#if 0 -extern u16 INTR_CHECK; -extern void *INTR_VECTOR; -extern unsigned char REG_BASE[0x400]; -extern unsigned char PLTT[PLTT_SIZE]; -extern unsigned char VRAM_[VRAM_SIZE]; -extern unsigned char OAM[OAM_SIZE]; -extern unsigned char FLASH_BASE[131072]; -#endif -extern uint8_t EWRAM_START[EWRAM_SIZE]; -extern uint8_t IWRAM_START[IWRAM_SIZE]; -// TODO: REG_BASE needs to be u8, because of the address macro definitions -extern uint8_t REG_BASE[IO_SIZE]; -extern uint16_t PLTT[PLTT_SIZE / sizeof(uint16_t)]; -extern uint8_t VRAM[VRAM_SIZE]; -extern uint8_t OAM[OAM_SIZE]; -extern uint8_t FLASH_BASE[FLASH_ROM_SIZE_1M * SECTORS_PER_BANK]; ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * DISPLAY_HEIGHT]; + #if ENABLE_VRAM_VIEW -#define VRAM_VIEW_WIDTH (32 * TILE_WIDTH) -#define VRAM_VIEW_HEIGHT (((VRAM_SIZE / TILE_SIZE_4BPP) / 32) * TILE_WIDTH) uint16_t vramBuffer[VRAM_VIEW_WIDTH * VRAM_VIEW_HEIGHT]; -uint8_t vramPalIdBuffer[(VRAM_VIEW_WIDTH / TILE_WIDTH) * (VRAM_VIEW_HEIGHT / TILE_WIDTH)]; #endif -struct scanlineData { - uint16_t layers[4][DISPLAY_WIDTH]; - uint16_t spriteLayers[4][DISPLAY_WIDTH]; - uint16_t bgcnts[4]; - uint16_t winMask[DISPLAY_WIDTH]; - // priority bookkeeping - char bgtoprio[4]; // background to priority - char prioritySortedBgs[4][4]; - char prioritySortedBgsCount[4]; -}; - -struct bgPriority { - char priority; - char subPriority; -}; - SDL_Window *sdlWindow; SDL_Renderer *sdlRenderer; SDL_Texture *sdlTexture; @@ -123,8 +82,6 @@ static void ReadSaveFile(char *path); static void StoreSaveFile(void); static void CloseSaveFile(void); -static void UpdateInternalClock(void); - u16 Platform_GetKeyInput(void); #ifdef _WIN32 @@ -1107,850 +1064,7 @@ void SoftReset(u32 resetFlags) { } void SoftResetExram(u32 resetFlags) { } -static const uint16_t bgMapSizes[][2] = { - { 32, 32 }, - { 64, 32 }, - { 32, 64 }, - { 64, 64 }, -}; - -#define mosaicBGEffectX (REG_MOSAIC & 0xF) -#define mosaicBGEffectY ((REG_MOSAIC >> 4) & 0xF) -#define mosaicSpriteEffectX ((REG_MOSAIC >> 8) & 0xF) -#define mosaicSpriteEffectY ((REG_MOSAIC >> 12) & 0xF) -#define applyBGHorizontalMosaicEffect(x) (x - (x % (mosaicBGEffectX + 1))) -#define applyBGVerticalMosaicEffect(y) (y - (y % (mosaicBGEffectY + 1))) -#define applySpriteHorizontalMosaicEffect(x) (x - (x % (mosaicSpriteEffectX + 1))) -#define applySpriteVerticalMosaicEffect(y) (y - (y % (mosaicSpriteEffectY + 1))) - -static void RenderBGScanline(int bgNum, uint16_t control, uint16_t hoffs, uint16_t voffs, int lineNum, uint16_t *line) -{ - unsigned int charBaseBlock = (control >> 2) & 3; - unsigned int screenBaseBlock = (control & BGCNT_SCREENBASE_MASK) >> 8; - unsigned int is8bpp = (control >> 7) & 1; - - // Determine background dimensions from the control register - unsigned int mapWidth = bgMapSizes[control >> 14][0]; // in tiles - unsigned int mapPixelWidth = mapWidth << 3; - unsigned int mapPixelHeight = bgMapSizes[control >> 14][1] << 3; - unsigned int pixelWidthMask = mapPixelWidth - 1; - unsigned int pixelHeightMask = mapPixelHeight - 1; - - uint8_t *bgtiles = (uint8_t *)BG_CHAR_ADDR(charBaseBlock); - uint16_t *bgmap = (uint16_t *)BG_SCREEN_ADDR(screenBaseBlock); - uint16_t *pal = (uint16_t *)PLTT; - - // Apply vertical mosaic effect to the entire scanline if enabled - bool hasMosaic = control & BGCNT_MOSAIC; - if (hasMosaic) { - lineNum = applyBGVerticalMosaicEffect(lineNum); - } - - // GBA hardware masks scroll registers to 9 bits (0-511) - hoffs &= 0x1FF; - voffs &= 0x1FF; - - unsigned int yy = (lineNum + voffs) & pixelHeightMask; - unsigned int mapY = yy >> 3; - unsigned int tileY = yy & 7; - unsigned int mapRowBase = mapY * mapWidth; - - for (unsigned int x = 0; x < DISPLAY_WIDTH; x++) { - unsigned int xx; - - if (hasMosaic) { - xx = (applyBGHorizontalMosaicEffect(x) + hoffs) & pixelWidthMask; - } else { - xx = (x + hoffs) & pixelWidthMask; - } - - unsigned int mapX = xx >> 3; - unsigned int mapIndex = mapRowBase + mapX; - - uint16_t entry = bgmap[mapIndex]; - unsigned int tileNum = entry & 0x3FF; - unsigned int paletteNum = (entry >> 12) & 0xF; - #if ENABLE_VRAM_VIEW - vramPalIdBuffer[tileNum] = paletteNum; -#endif - - unsigned int tx = xx & 7; - unsigned int ty = tileY; - - if (entry & (1 << 10)) - tx = 7 - tx; - if (entry & (1 << 11)) - ty = 7 - ty; - - if (!is8bpp) { - uint32_t tileDataOffset = tileNum << 5; - uint32_t pixelByteOffset = (ty << 2) + (tx >> 1); - uint8_t pixelPair = bgtiles[tileDataOffset + pixelByteOffset]; - - uint8_t pixel = (tx & 1) ? (pixelPair >> 4) : (pixelPair & 0xF); - - if (pixel != 0) { - line[x] = pal[(paletteNum << 4) + pixel] | 0x8000; - } - } else { // 8 bits per pixel - uint32_t tileDataOffset = tileNum << 6; - uint32_t pixelByteOffset = (ty << 3) + tx; - uint8_t pixel = bgtiles[tileDataOffset + pixelByteOffset]; - - if (pixel != 0) { - line[x] = pal[pixel] | 0x8000; - } - } - } -} - -static inline uint32_t getBgX(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2X; - } else if (bgNumber == 3) { - return REG_BG3X; - } - - return 0; -} - -static inline uint32_t getBgY(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2Y; - } else if (bgNumber == 3) { - return REG_BG3Y; - } - - return 0; -} - -static inline uint16_t getBgPA(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PA; - } else if (bgNumber == 3) { - return REG_BG3PA; - } - return 0; -} - -static inline uint16_t getBgPB(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PB; - } else if (bgNumber == 3) { - return REG_BG3PB; - } - - return 0; -} - -static inline uint16_t getBgPC(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PC; - } else if (bgNumber == 3) { - return REG_BG3PC; - } - - return 0; -} - -static inline uint16_t getBgPD(int bgNumber) -{ - if (bgNumber == 2) { - return REG_BG2PD; - } else if (bgNumber == 3) { - return REG_BG3PD; - } - - return 0; -} - -static void RenderRotScaleBGScanline(int bgNum, uint16_t control, uint16_t x, uint16_t y, int lineNum, uint16_t *line) -{ - vBgCnt *bgcnt = (vBgCnt *)&control; - unsigned int charBaseBlock = bgcnt->charBaseBlock; - unsigned int screenBaseBlock = bgcnt->screenBaseBlock; - unsigned int mapWidth = 1 << (4 + (bgcnt->screenSize)); // number of tiles - - uint8_t *bgtiles = (uint8_t *)(VRAM + charBaseBlock * 0x4000); - uint8_t *bgmap = (uint8_t *)(VRAM + screenBaseBlock * 0x800); - uint16_t *pal = (uint16_t *)PLTT; - - if (control & BGCNT_MOSAIC) - lineNum = applyBGVerticalMosaicEffect(lineNum); - - s16 pa = getBgPA(bgNum); - s16 pb = getBgPB(bgNum); - s16 pc = getBgPC(bgNum); - s16 pd = getBgPD(bgNum); - - int sizeX = 128; - int sizeY = 128; - - switch (bgcnt->screenSize) { - case 0: - break; - case 1: - sizeX = sizeY = 256; - break; - case 2: - sizeX = sizeY = 512; - break; - case 3: - sizeX = sizeY = 1024; - break; - } - - int maskX = sizeX - 1; - int maskY = sizeY - 1; - - int yshift = ((control >> 14) & 3) + 4; - - /*int dx = pa & 0x7FFF; - if (pa & 0x8000) - dx |= 0xFFFF8000; - int dmx = pb & 0x7FFF; - if (pb & 0x8000) - dmx |= 0xFFFF8000; - int dy = pc & 0x7FFF; - if (pc & 0x8000) - dy |= 0xFFFF8000; - int dmy = pd & 0x7FFF; - if (pd & 0x8000) - dmy |= 0xFFFF8000;*/ - - s32 currentX = getBgX(bgNum); - s32 currentY = getBgY(bgNum); - - // sign extend 28 bit number - currentX = ((currentX & (1 << 27)) ? currentX | 0xF0000000 : currentX); - currentY = ((currentY & (1 << 27)) ? currentY | 0xF0000000 : currentY); - - currentX += lineNum * pb; - currentY += lineNum * pd; - - int realX = currentX; - int realY = currentY; - - if (bgcnt->areaOverflowMode) { - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int xxx = (realX >> 8) & maskX; - int yyy = (realY >> 8) & maskY; - - int tile = bgmap[(xxx >> 3) + ((yyy >> 3) << yshift)]; - - int tileX = xxx & 7; - int tileY = yyy & 7; - - uint8_t pixel = bgtiles[(tile << 6) + (tileY << 3) + tileX]; - - if (pixel != 0) { - line[x] = pal[pixel] | 0x8000; - } - - realX += pa; - realY += pc; - } - } else { - for (int x = 0; x < DISPLAY_WIDTH; x++) { - int xxx = (realX >> 8); - int yyy = (realY >> 8); - - if (xxx < 0 || yyy < 0 || xxx >= sizeX || yyy >= sizeY) { - // line[x] = 0x80000000; - } else { - int tile = bgmap[(xxx >> 3) + ((yyy >> 3) << yshift)]; - - int tileX = xxx & 7; - int tileY = yyy & 7; - - uint8_t pixel = bgtiles[(tile << 6) + (tileY << 3) + tileX]; - - if (pixel != 0) { - line[x] = pal[pixel] | 0x8000; - } - } - realX += pa; - realY += pc; - } - } - // the only way i could figure out how to get accurate mosaic on affine bgs - // luckily i dont think pokemon emerald uses mosaic on affine bgs - if (control & BGCNT_MOSAIC && mosaicBGEffectX > 0) { - for (int x = 0; x < DISPLAY_WIDTH; x++) { - uint16_t color = line[applyBGHorizontalMosaicEffect(x)]; - line[x] = color; - } - } -} - -const u8 spriteSizes[][2] = { - { 8, 16 }, - { 8, 32 }, - { 16, 32 }, - { 32, 64 }, -}; - -#define isbgEnabled(x) ((REG_DISPCNT >> 8) & 0xF) & (1 << x) - -// outputs the blended pixel in colorOutput, the prxxx are the bg priority and -// subpriority, pixelpos is pixel offset in scanline -static bool alphaBlendSelectTargetB(struct scanlineData *scanline, uint16_t *colorOutput, char prnum, char prsub, int pixelpos, - bool spriteBlendEnabled) -{ - // iterate trough every possible bg to blend with, starting from specified priorities - // from arguments - for (unsigned int blndprnum = prnum; blndprnum <= 3; blndprnum++) { - // check if sprite is available to blend with, if sprite blending is enabled - if (spriteBlendEnabled == true && getAlphaBit(scanline->spriteLayers[blndprnum][pixelpos]) == 1) { - *colorOutput = scanline->spriteLayers[blndprnum][pixelpos]; - return true; - } - - for (unsigned int blndprsub = prsub; blndprsub < scanline->prioritySortedBgsCount[blndprnum]; blndprsub++) { - char currLayer = scanline->prioritySortedBgs[blndprnum][blndprsub]; - if (getAlphaBit(scanline->layers[currLayer][pixelpos]) == 1 && REG_BLDCNT & (1 << (8 + currLayer)) && isbgEnabled(currLayer)) { - *colorOutput = scanline->layers[currLayer][pixelpos]; - return true; - } - // if we hit a non target layer we should bail - if (getAlphaBit(scanline->layers[currLayer][pixelpos]) == 1 && isbgEnabled(currLayer) && prnum != blndprnum) { - return false; - } - } - prsub = 0; // start from zero in the next iteration - } - // no background got hit, check if backdrop is enabled and return it if enabled - // otherwise fail - if (REG_BLDCNT & BLDCNT_TGT2_BD) { - *colorOutput = *(uint16_t *)PLTT; - return true; - } else { - return false; - } -} - -#define WINMASK_BG0 (1 << 0) -#define WINMASK_BG1 (1 << 1) -#define WINMASK_BG2 (1 << 2) -#define WINMASK_BG3 (1 << 3) -#define WINMASK_OBJ (1 << 4) -#define WINMASK_CLR (1 << 5) -#define WINMASK_WINOUT (1 << 6) - -// checks if window horizontal is in bounds and takes account WIN wraparound -static bool winCheckHorizontalBounds(u16 left, u16 right, u16 xpos) -{ - if (left > right) - return (xpos >= left || xpos < right); - else - return (xpos >= left && xpos < right); -} - -extern const u8 gOamShapesSizes[12][2]; - -// Parts of this code heavily borrowed from NanoboyAdvance. -static void DrawOamSprites(struct scanlineData *scanline, uint16_t vcount, bool windowsEnabled) -{ - int i; - unsigned int x; - unsigned int y; - void *objtiles = OBJ_VRAM0; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; - bool winShouldBlendPixel = true; - - int16_t matrix[2][2] = {}; - - if (!(REG_DISPCNT & (1 << 6))) { - puts("2-D OBJ Character mapping not supported."); - } - - for (i = OAM_ENTRY_COUNT - 1; i >= 0; i--) { - OamData *oam = &((OamData *)OAM)[i]; - unsigned int width; - unsigned int height; - uint16_t *pixels; - - bool isAffine = oam->split.affineMode & 1; - bool doubleSizeOrDisabled = (oam->split.affineMode >> 1) & 1; - - if (!(isAffine) && doubleSizeOrDisabled) // disable for non-affine - { - continue; - } - - s32 index = (oam->split.shape << 2) | oam->split.size; - width = gOamShapesSizes[index][0]; - height = gOamShapesSizes[index][1]; - - int half_width = width / 2; - int half_height = height / 2; - - int32_t x = oam->split.x; - int32_t y = oam->split.y; - -#if !EXTENDED_OAM - if (x >= DISPLAY_WIDTH) - x -= 512; - if (y >= DISPLAY_HEIGHT) - y -= 256; -#endif - - if (isAffine && doubleSizeOrDisabled) { - half_width *= 2; - half_height *= 2; - } - - int spriteTop = y; - int spriteBottom = y + (half_height * 2); - if ((int)vcount < spriteTop || (int)vcount >= spriteBottom) - continue; - - int spriteLeft = x; - int spriteRight = x + (half_width * 2); - if (spriteRight < 0 || spriteLeft >= DISPLAY_WIDTH) - continue; - - bool isSemiTransparent = (oam->split.objMode == 1); - bool isObjWin = (oam->split.objMode == 2); - - int rect_width = width; - int rect_height = height; - - if (isAffine) { - u8 matrixNum = oam->split.matrixNum * 4; - - OamData *oam1 = &((OamData *)OAM)[matrixNum]; - OamData *oam2 = &((OamData *)OAM)[matrixNum + 1]; - OamData *oam3 = &((OamData *)OAM)[matrixNum + 2]; - OamData *oam4 = &((OamData *)OAM)[matrixNum + 3]; - - matrix[0][0] = oam1->all.affineParam; - matrix[0][1] = oam2->all.affineParam; - matrix[1][0] = oam3->all.affineParam; - matrix[1][1] = oam4->all.affineParam; - - if (doubleSizeOrDisabled) { - rect_width *= 2; - rect_height *= 2; - } - } else { - matrix[0][0] = 0x100; - matrix[0][1] = 0; - matrix[1][0] = 0; - matrix[1][1] = 0x100; - } - - pixels = scanline->spriteLayers[oam->split.priority]; - x += half_width; - y += half_height; - - { - int local_y = (oam->split.mosaic == 1) ? applySpriteVerticalMosaicEffect(vcount) - y : vcount - y; - int number = oam->split.tileNum; - int palette = oam->split.paletteNum; - bool flipX = !isAffine && ((oam->split.matrixNum >> 3) & 1); - bool flipY = !isAffine && ((oam->split.matrixNum >> 4) & 1); - bool is8BPP = oam->split.bpp & 1; - - { - uint8_t *tiledata = (uint8_t *)objtiles; - uint16_t *sprpal = (uint16_t *)(PLTT + (0x200 / 2)); - for (int local_x = -half_width; local_x <= half_width; local_x++) { - int local_mosaicX; - int tex_x; - int tex_y; - - unsigned int global_x = local_x + x; - - if (global_x < 0 || global_x >= DISPLAY_WIDTH) - continue; - - if (oam->split.mosaic == 1) { - // mosaic effect has to be applied to global coordinates otherwise - // the mosaic will scroll - local_mosaicX = applySpriteHorizontalMosaicEffect(global_x) - x; - tex_x = ((matrix[0][0] * local_mosaicX + matrix[0][1] * local_y) >> 8) + (width / 2); - tex_y = ((matrix[1][0] * local_mosaicX + matrix[1][1] * local_y) >> 8) + (height / 2); - } else { - tex_x = ((matrix[0][0] * local_x + matrix[0][1] * local_y) >> 8) + (width / 2); - tex_y = ((matrix[1][0] * local_x + matrix[1][1] * local_y) >> 8) + (height / 2); - } - - /* Check if transformed coordinates are inside bounds. */ - - if (tex_x >= width || tex_y >= height || tex_x < 0 || tex_y < 0) - continue; - - if (flipX) - tex_x = width - tex_x - 1; - if (flipY) - tex_y = height - tex_y - 1; - - int tile_x = tex_x & 7; - int tile_y = tex_y & 7; - int block_x = tex_x >> 3; - int block_y = tex_y >> 3; - int block_offset = ((block_y * (REG_DISPCNT & 0x40 ? (width >> 3) : 16)) + block_x); - uint16_t pixel = 0; - - uint16_t *pixpal; - if (!is8BPP) { - int tileDataIndex = ((block_offset + oam->split.tileNum) << 5) + (tile_y << 2) + (tile_x >> 1); - pixel = tiledata[tileDataIndex]; - if (tile_x & 1) - pixel >>= 4; - else - pixel &= 0xF; - pixpal = sprpal + (oam->split.paletteNum << 4); -#if ENABLE_VRAM_VIEW - vramPalIdBuffer[0x800 + (tileDataIndex >> 5)] = 16 + oam->split.paletteNum; -#endif - } else { - pixel = tiledata[((block_offset * 2 + oam->split.tileNum) << 5) + (tile_y << 3) + tile_x]; - pixpal = sprpal; - } - - if (pixel != 0) { - uint16_t color = pixpal[pixel]; - - // if sprite mode is 2 then write to the window mask instead - if (isObjWin) { - if (scanline->winMask[global_x] & WINMASK_WINOUT) - scanline->winMask[global_x] = (REG_WINOUT >> 8) & 0x3F; - continue; - } - // this code runs if pixel is to be drawn - if (global_x < DISPLAY_WIDTH && global_x >= 0) { - // check if its enabled in the window (if window is enabled) - winShouldBlendPixel = (windowsEnabled == false || scanline->winMask[global_x] & WINMASK_CLR); - - // has to be separated from the blend mode switch statement - // because of OBJ semi transparancy feature - if ((blendMode == 1 && REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) || isSemiTransparent) { - uint16_t targetA = color; - uint16_t targetB = 0; - if (alphaBlendSelectTargetB(scanline, &targetB, oam->split.priority, 0, global_x, false)) { - color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); - } - } else if (REG_BLDCNT & BLDCNT_TGT1_OBJ && winShouldBlendPixel) { - switch (blendMode) { - case 2: - color = alphaBrightnessIncrease(color, REG_BLDY & 0x1F); - break; - case 3: - color = alphaBrightnessDecrease(color, REG_BLDY & 0x1F); - break; - } - } - - // write pixel to pixel framebuffer - pixels[global_x] = color | (1 << 15); - } - } - } - } - } - } -} - -static void DrawScanline(uint16_t *pixels, uint16_t vcount) -{ - unsigned int mode = REG_DISPCNT & 3; - unsigned char numOfBgs = (mode == 0 ? 4 : 3); - int bgnum, prnum; - static struct scanlineData scanline; - unsigned int blendMode = (REG_BLDCNT >> 6) & 3; - unsigned int xpos; - unsigned int enabledBgs = (REG_DISPCNT >> 8) & 0xF; - - // Only zero the layers that are actually enabled, - // instead of blindly zeroing all 4+4 layers (~8KB total) every scanline. - for (bgnum = 0; bgnum < numOfBgs; bgnum++) { - if (enabledBgs & (1 << bgnum)) - memset(scanline.layers[bgnum], 0, sizeof(scanline.layers[bgnum])); - } - if (REG_DISPCNT & DISPCNT_OBJ_ON) - memset(scanline.spriteLayers, 0, sizeof(scanline.spriteLayers)); - memset(scanline.prioritySortedBgsCount, 0, sizeof(scanline.prioritySortedBgsCount)); - - for (bgnum = 0; bgnum < numOfBgs; bgnum++) { - uint16_t bgcnt = *(uint16_t *)(REG_ADDR_BG0CNT + bgnum * 2); - uint16_t priority; - scanline.bgcnts[bgnum] = bgcnt; - scanline.bgtoprio[bgnum] = priority = (bgcnt & 3); - - char priorityCount = scanline.prioritySortedBgsCount[priority]; - scanline.prioritySortedBgs[priority][priorityCount] = bgnum; - scanline.prioritySortedBgsCount[priority]++; - } - - switch (mode) { - case 0: - // All backgrounds are text mode - for (bgnum = 3; bgnum >= 0; bgnum--) { - if (isbgEnabled(bgnum)) { - uint16_t bghoffs = *(uint16_t *)(REG_ADDR_BG0HOFS + bgnum * 4); - uint16_t bgvoffs = *(uint16_t *)(REG_ADDR_BG0VOFS + bgnum * 4); - - RenderBGScanline(bgnum, scanline.bgcnts[bgnum], bghoffs, bgvoffs, vcount, scanline.layers[bgnum]); - } - } - - break; - case 1: - // BG2 is affine - bgnum = 2; - if (isbgEnabled(bgnum)) { - RenderRotScaleBGScanline(bgnum, scanline.bgcnts[bgnum], REG_BG2X, REG_BG2Y, vcount, scanline.layers[bgnum]); - } - // BG0 and BG1 are text mode - for (bgnum = 1; bgnum >= 0; bgnum--) { - if (isbgEnabled(bgnum)) { - uint16_t bghoffs = *(uint16_t *)(REG_ADDR_BG0HOFS + bgnum * 4); - uint16_t bgvoffs = *(uint16_t *)(REG_ADDR_BG0VOFS + bgnum * 4); - - RenderBGScanline(bgnum, scanline.bgcnts[bgnum], bghoffs, bgvoffs, vcount, scanline.layers[bgnum]); - } - } - break; - default: - printf("Video mode %u is unsupported.\n", mode); - break; - } - - bool windowsEnabled = false; - u16 WIN0bottom, WIN0top, WIN0right, WIN0left; - u16 WIN1bottom, WIN1top, WIN1right, WIN1left; - bool WIN0enable, WIN1enable; - WIN0enable = false; - WIN1enable = false; - - // figure out if WIN0 masks on this scanline - if (REG_DISPCNT & DISPCNT_WIN0_ON) { - // acquire the window coordinates - - WIN0bottom = WIN_GET_HIGHER(REG_WIN0V); // y2; - WIN0top = WIN_GET_LOWER(REG_WIN0V); // y1; - WIN0right = WIN_GET_HIGHER(REG_WIN0H); // x2 - WIN0left = WIN_GET_LOWER(REG_WIN0H); // x1 - - // printf("%d, %d, %d, %d\n", WIN0bottom, WIN0top, WIN0right, WIN0left); - // figure out WIN Y wraparound and check bounds accordingly - if (WIN0top > WIN0bottom) { - if (vcount >= WIN0top || vcount < WIN0bottom) - WIN0enable = true; - } else { - if (vcount >= WIN0top && vcount < WIN0bottom) - WIN0enable = true; - } - - windowsEnabled = true; - } - // figure out if WIN1 masks on this scanline - if (REG_DISPCNT & DISPCNT_WIN1_ON) { - WIN1bottom = WIN_GET_HIGHER(REG_WIN1V); // y2; - WIN1top = WIN_GET_LOWER(REG_WIN1V); // y1; - WIN1right = WIN_GET_HIGHER(REG_WIN1H); // x2 - WIN1left = WIN_GET_LOWER(REG_WIN1H); // x1 - - if (WIN1top > WIN1bottom) { - if (vcount >= WIN1top || vcount < WIN1bottom) - WIN1enable = true; - } else { - if (vcount >= WIN1top && vcount < WIN1bottom) - WIN1enable = true; - } - - windowsEnabled = true; - } - // enable windows if OBJwin is enabled - if (REG_DISPCNT & DISPCNT_OBJWIN_ON && REG_DISPCNT & DISPCNT_OBJ_ON) { - windowsEnabled = true; - } - - // draw to pixel mask - if (windowsEnabled) { - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - // win0 checks - if (WIN0enable && winCheckHorizontalBounds(WIN0left, WIN0right, xpos)) - scanline.winMask[xpos] = REG_WININ & 0x3F; - // win1 checks - else if (WIN1enable && winCheckHorizontalBounds(WIN1left, WIN1right, xpos)) - scanline.winMask[xpos] = (REG_WININ >> 8) & 0x3F; - else - scanline.winMask[xpos] = (REG_WINOUT & 0x3F) | WINMASK_WINOUT; - } - } - - if (REG_DISPCNT & DISPCNT_OBJ_ON) - DrawOamSprites(&scanline, vcount, windowsEnabled); - - // iterate through every priority in order - if (blendMode == 0 && !windowsEnabled) { - for (prnum = 3; prnum >= 0; prnum--) { - for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { - char bgnum = scanline.prioritySortedBgs[prnum][prsub]; - if (isbgEnabled(bgnum)) { - uint16_t *src = scanline.layers[bgnum]; - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - uint16_t color = src[xpos]; - if (color & 0x8000) // alpha bit set = opaque - pixels[xpos] = color; - } - } - } - // draw sprites on current priority - if (REG_DISPCNT & DISPCNT_OBJ_ON) { - uint16_t *src = scanline.spriteLayers[prnum]; - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - if (src[xpos] & 0x8000) - pixels[xpos] = src[xpos]; - } - } - } - } else { - // FULL PATH: blending and/or windows are active - for (prnum = 3; prnum >= 0; prnum--) { - for (char prsub = scanline.prioritySortedBgsCount[prnum] - 1; prsub >= 0; prsub--) { - char bgnum = scanline.prioritySortedBgs[prnum][prsub]; - // if background is enabled then draw it - if (isbgEnabled(bgnum)) { - uint16_t *src = scanline.layers[bgnum]; - // copy all pixels to framebuffer - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - uint16_t color = src[xpos]; - bool winEffectEnable = true; - - if (!getAlphaBit(color)) - continue; // do nothing if alpha bit is not set - - if (windowsEnabled) { - winEffectEnable = ((scanline.winMask[xpos] & WINMASK_CLR) >> 5); - // if bg is disabled inside the window then do not draw the pixel - if (!(scanline.winMask[xpos] & 1 << bgnum)) - continue; - } - - // blending code - if (blendMode != 0 && REG_BLDCNT & (1 << bgnum) && winEffectEnable) { - uint16_t targetA = color; - uint16_t targetB = 0; - - switch (blendMode) { - case 1: { - char isSpriteBlendingEnabled = REG_BLDCNT & BLDCNT_TGT2_OBJ ? 1 : 0; - // find targetB and blend it - if (alphaBlendSelectTargetB(&scanline, &targetB, prnum, prsub + 1, xpos, isSpriteBlendingEnabled)) { - color = alphaBlendColor(targetA, targetB, REG_BLDALPHA & 0x1F, (REG_BLDALPHA >> 8) & 0x1F); - } - } break; - case 2: - color = alphaBrightnessIncrease(targetA, REG_BLDY & 0x1F); - break; - case 3: - color = alphaBrightnessDecrease(targetA, REG_BLDY & 0x1F); - break; - } - } - // write the pixel to scanline buffer output - pixels[xpos] = color; - } - } - } - // draw sprites on current priority - uint16_t *src = scanline.spriteLayers[prnum]; - for (xpos = 0; xpos < DISPLAY_WIDTH; xpos++) { - if (getAlphaBit(src[xpos])) { - // check if sprite pixel draws inside window - if (windowsEnabled && !(scanline.winMask[xpos] & WINMASK_OBJ)) - continue; - // draw the pixel - pixels[xpos] = src[xpos]; - } - } - } - } -} - -uint16_t *memsetu16(uint16_t *dst, uint16_t fill, size_t count) -{ - uint32_t fill32 = ((uint32_t)fill << 16) | fill; - uint32_t *dst32 = (uint32_t *)dst; - size_t pairs = count >> 1; - for (size_t i = 0; i < pairs; i++) { - dst32[i] = fill32; - } - if (count & 1) { - dst[count - 1] = fill; - } - return dst; -} - -static void DrawFrame(uint16_t *pixels) -{ - int i; - - for (i = 0; i < DISPLAY_HEIGHT; i++) { - uint16_t *scanline = &pixels[i * DISPLAY_WIDTH]; - - REG_VCOUNT = i; - if (((REG_DISPSTAT >> 8) & 0xFF) == REG_VCOUNT) { - REG_DISPSTAT |= INTR_FLAG_VCOUNT; - if (REG_DISPSTAT & DISPSTAT_VCOUNT_INTR) - gIntrTable[INTR_INDEX_VCOUNT](); - } - - // Render the backdrop color before each individual scanline. - // HBlank interrupt code could have changed it in between lines. - memsetu16(scanline, *(uint16_t *)PLTT, DISPLAY_WIDTH); - DrawScanline(scanline, i); - - REG_DISPSTAT |= INTR_FLAG_HBLANK; - - RunDMAs(DMA_HBLANK); - - if (REG_DISPSTAT & DISPSTAT_HBLANK_INTR) - gIntrTable[INTR_INDEX_HBLANK](); - - REG_DISPSTAT &= ~INTR_FLAG_HBLANK; - REG_DISPSTAT &= ~INTR_FLAG_VCOUNT; - } -} - -#if ENABLE_VRAM_VIEW -void DrawVramView(Uint16 *buffer) -{ - for (int y = 0; y < VRAM_VIEW_HEIGHT / TILE_WIDTH; y++) { - for (int x = 0; x < VRAM_VIEW_WIDTH / TILE_WIDTH; x++) { - u16 tileId = y * (VRAM_VIEW_WIDTH / TILE_WIDTH) + x; - u16 *tileBase = &buffer[(y * VRAM_VIEW_WIDTH + x) * 8]; - - for (int ty = 0; ty < TILE_WIDTH; ty++) { - for (int tx = 0; tx < TILE_WIDTH; tx += 2) { - s32 tileIndex = ty * VRAM_VIEW_WIDTH + tx; - u16 *dest = &tileBase[tileIndex]; - - int i = (ty * TILE_WIDTH + tx) / 2; - u8 *colorPtr = &((u8 *)VRAM)[tileId * 0x20 + i]; - u8 colorId = colorPtr[0]; - u8 colA = (colorId & 0xF0) >> 4; - u8 colB = (colorId & 0x0F) >> 0; - - u8 paletteId = vramPalIdBuffer[tileId]; - dest[0] = PLTT[paletteId * 16 + colB]; - dest[1] = PLTT[paletteId * 16 + colA]; - } - } - } - } -} - void VramDraw(SDL_Texture *texture) { memset(vramBuffer, 0, sizeof(vramBuffer)); diff --git a/src/platform/ps2/ps2.c b/src/platform/ps2/ps2.c index a42ebdeccb..a742f5b834 100644 --- a/src/platform/ps2/ps2.c +++ b/src/platform/ps2/ps2.c @@ -32,12 +32,6 @@ static GSGLOBAL *gsGlobal; static GSTEXTURE screen; -#ifndef TILE_WIDTH -#define TILE_WIDTH 8 -#endif - -extern IntrFunc gIntrTable[16]; - ALIGNED(256) uint16_t gameImage[DISPLAY_WIDTH * (DISPLAY_HEIGHT + 1)]; struct VidMode { diff --git a/src/platform/shared/video/gpsp_renderer.cc b/src/platform/shared/video/gpsp_renderer.cc index 8cd1e0e8b5..da8ac5e1d4 100644 --- a/src/platform/shared/video/gpsp_renderer.cc +++ b/src/platform/shared/video/gpsp_renderer.cc @@ -1,4 +1,4 @@ -/* gameplaySP - Modified to fit the SA2 codebase (FreshOllie - 2026) +/* gameplaySP - Modified to fit the SA2 codebase (freshollie - 2026) * * Copyright (C) 2006 Exophase * Copyright (C) 2023 David Guillen Fandos From 4b7a182f14b4dfe0afc1fc93e9da8779706b2b4a Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:18:38 +0000 Subject: [PATCH 41/51] add psp to CI --- .github/workflows/build.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5f165da63e..cbe30a2809 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -168,7 +168,7 @@ jobs: ports: strategy: matrix: - platform: ["sdl", "sdl_win32", "win32", "ps2"] + platform: ["sdl", "sdl_win32", "win32", "ps2", "psp"] os: ["ubuntu-22.04", "macos-15"] if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ${{ matrix.os }} @@ -211,7 +211,17 @@ jobs: echo "$PS2DEV/bin" >> "$GITHUB_PATH" echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH" curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz - tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV + tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEVs + + - name: Install PSPDEV + if: ${{ matrix.platform == 'psp' }} + run: | + PSPDEV="$HOME/pspdev" + echo "PSPDEV=$HOME/pspdev" >> "$GITHUB_ENV" + mkdir -p $PSPDEV + echo "$PSPDEV/bin" >> "$GITHUB_PATH" + curl -o pspdev-latest.tar.gz -LC - https://github.com/pspdev/pspdev/releases/download/v20260301/pspdev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest-x86_64.tar.gz + tar -xf pspdev-latest.tar.gz --strip-components 1 -C $PSPDEV - name: ${{ matrix.platform }} run: | From 260845d587c119f70428d945dc24d54af78bc4e6 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:25:52 +0000 Subject: [PATCH 42/51] fix --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cbe30a2809..81aedabadd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -211,7 +211,7 @@ jobs: echo "$PS2DEV/bin" >> "$GITHUB_PATH" echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH" curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz - tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEVs + tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV - name: Install PSPDEV if: ${{ matrix.platform == 'psp' }} From e81058b4af49441cdc511d03add4ae0b65ebf835 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:41:29 +0000 Subject: [PATCH 43/51] another fix --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81aedabadd..06e5c5a266 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -211,7 +211,7 @@ jobs: echo "$PS2DEV/bin" >> "$GITHUB_PATH" echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH" curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz - tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV + tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEVs - name: Install PSPDEV if: ${{ matrix.platform == 'psp' }} @@ -220,7 +220,7 @@ jobs: echo "PSPDEV=$HOME/pspdev" >> "$GITHUB_ENV" mkdir -p $PSPDEV echo "$PSPDEV/bin" >> "$GITHUB_PATH" - curl -o pspdev-latest.tar.gz -LC - https://github.com/pspdev/pspdev/releases/download/v20260301/pspdev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest-x86_64.tar.gz + curl -o pspdev-latest.tar.gz -LC - https://github.com/pspdev/pspdev/releases/download/v20260301/pspdev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo "macos-latest-arm64"; else echo "ubuntu-latest-x86_64"; fi).tar.gz tar -xf pspdev-latest.tar.gz --strip-components 1 -C $PSPDEV - name: ${{ matrix.platform }} From 6faa8b6f01c9634abb38ce9209a7c3a60485d824 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:43:27 +0000 Subject: [PATCH 44/51] again --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06e5c5a266..1c6db40051 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -211,7 +211,7 @@ jobs: echo "$PS2DEV/bin" >> "$GITHUB_PATH" echo "$PS2DEV/ee/bin" >> "$GITHUB_PATH" curl -o ps2dev-latest.tar.gz -LC - https://github.com/ps2dev/ps2dev/releases/download/latest/ps2dev-$(if [[ "$OSTYPE" == "darwin"* ]]; then echo macos; else echo ubuntu; fi)-latest.tar.gz - tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEVs + tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV - name: Install PSPDEV if: ${{ matrix.platform == 'psp' }} From 918c4b0ea33358194770f3c90d16e6ca3acbef06 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:45:57 +0000 Subject: [PATCH 45/51] ubuntu 24 --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c6db40051..060be66067 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: jobs: format: if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout PR if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} @@ -30,7 +30,7 @@ jobs: build-gba: if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 name: Build GBA (USA) steps: - name: Checkout PR @@ -123,7 +123,7 @@ jobs: build-gba-variants: if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 name: Build GBA (${{ matrix.variant }}) strategy: matrix: @@ -169,7 +169,7 @@ jobs: strategy: matrix: platform: ["sdl", "sdl_win32", "win32", "ps2", "psp"] - os: ["ubuntu-22.04", "macos-15"] + os: ["ubuntu-24.04", "macos-15"] if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ${{ matrix.os }} name: Build ${{ matrix.platform }} (${{ matrix.os }}) @@ -185,7 +185,7 @@ jobs: uses: actions/checkout@master - name: Install tools (Linux) - if: ${{ matrix.os == 'ubuntu-22.04' }} + if: ${{ matrix.os == 'ubuntu-24.04' }} run: | sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs @@ -232,7 +232,7 @@ jobs: matrix: platform: ["sdl"] if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 name: TAS Test ${{ matrix.platform }} steps: - name: Checkout PR @@ -267,7 +267,7 @@ jobs: level_editor: if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 name: Level editor (BriBaSA) steps: - name: Checkout PR From 6ba63b1e80b9390ea154c9239fa9cfb8098e4e59 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:50:57 +0000 Subject: [PATCH 46/51] more improve --- .github/workflows/build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 060be66067..e935819faf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: jobs: format: if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} - runs-on: ubuntu-24.04 + runs-on: ubuntu-22.04 steps: - name: Checkout PR if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target'}} @@ -126,6 +126,7 @@ jobs: runs-on: ubuntu-24.04 name: Build GBA (${{ matrix.variant }}) strategy: + fail-fast: false matrix: variant: ["europe", "japan", "japan_vc", "usa_beta"] steps: @@ -154,7 +155,7 @@ jobs: - name: Install tools run: | - sudo apt update && sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi + sudo apt update && sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev - name: Install agbcc run: | @@ -167,6 +168,7 @@ jobs: ports: strategy: + fail-fast: false matrix: platform: ["sdl", "sdl_win32", "win32", "ps2", "psp"] os: ["ubuntu-24.04", "macos-15"] @@ -187,7 +189,7 @@ jobs: - name: Install tools (Linux) if: ${{ matrix.os == 'ubuntu-24.04' }} run: | - sudo apt update && sudo apt install xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs + sudo apt update && sudo apt install xorg-dev libpng-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs - name: Install Tools (Macos) if: ${{ matrix.os == 'macos-15' }} From ea9717ac857549bac2a3e02252e24e55520cb6ad Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 00:55:49 +0000 Subject: [PATCH 47/51] final fix --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e935819faf..f73b868e44 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,7 +58,7 @@ jobs: - name: Install tools run: | - sudo apt update && sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi + sudo apt update && sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi libpng-dev python3 -m pip install gitpython - name: Install agbcc From 7e3d0114c5cdfe396a842a69442c746d164fa130 Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Tue, 3 Mar 2026 22:20:51 +0000 Subject: [PATCH 48/51] some cgb improvements --- src/platform/shared/audio/cgb_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 035d18f176..0f711d684d 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -221,9 +221,9 @@ void cgb_audio_generate(u16 samplesPerFrame) } if ((REG_NR30 & 0x80) && (REG_NR52 & 0x04)) { if (REG_NR51 & 0x40) - outputL += (gb.Vol[2] * gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2); + outputL += gb.Vol[2] * (gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2); if (REG_NR51 & 0x04) - outputR += (gb.Vol[2] * gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2); + outputR += gb.Vol[2] * (gb.WAVRAM[fp8_24_to_u32(soundChannelPos[2])] >> 2); } if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); From b45f296bf0219ad9073b08995fe7d6ddcce137fe Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 4 Mar 2026 01:37:18 +0000 Subject: [PATCH 49/51] fix clipping, more optimisations --- src/platform/shared/audio/cgb_audio.c | 16 ++++++++++------ src/platform/shared/audio/m4a_sound_mixer.c | 18 +++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/platform/shared/audio/cgb_audio.c b/src/platform/shared/audio/cgb_audio.c index 0f711d684d..03da55922a 100644 --- a/src/platform/shared/audio/cgb_audio.c +++ b/src/platform/shared/audio/cgb_audio.c @@ -12,6 +12,7 @@ static u32 sampleRate; static u16 lfsrMax[2]; fixed8_24 ch4Samples; fixed8_24 volScale[16]; +fixed8_24 ch4StepsScale[12]; void cgb_audio_init(u32 rate) { @@ -43,6 +44,9 @@ void cgb_audio_init(u32 rate) ch4Samples = 0; for (int i = 0; i < 16; i++) volScale[i] = u32_to_fp8_24(i) / 15; + + for (int i = 0; i < 12; i++) + ch4StepsScale[i] = u32_to_fp8_24(1) / (i + 1); } void cgb_set_sweep(u8 sweep) @@ -228,19 +232,19 @@ void cgb_audio_generate(u16 samplesPerFrame) if ((gb.DAC[3]) && (REG_NR52 & 0x08)) { bool32 lfsrMode = ((REG_NR43 & 0x08) == 8); ch4Samples += freqTableNSE[REG_SOUND4CNT_H & (ARRAY_COUNT(freqTableNSE) - 1)]; - int ch4Out = 0; + s8 ch4Out = 0; if (gb.ch4LFSR[lfsrMode] & 1) { ch4Out++; } else { ch4Out--; } - int steps = fp8_24_to_u32(ch4Samples); + u8 steps = fp8_24_to_u32(ch4Samples); ch4Samples = fp8_24_fractional_part(ch4Samples); u16 lfsr = gb.ch4LFSR[lfsrMode]; u16 lfsrMask = lfsrMax[lfsrMode]; - for (int i = 0; i < steps; i++) { + for (u8 i = 0; i < steps; i++) { // Comments to show what the bit // manipulation here is representing @@ -256,9 +260,9 @@ void cgb_audio_generate(u16 samplesPerFrame) } gb.ch4LFSR[lfsrMode] = lfsr; - fixed8_24 sample = u32_to_fp8_24(ch4Out); - if (steps > 0) - sample /= (steps + 1); + // NOTE: if we convert this to int before multiplying by volume + // the waves sound effect sounds better + fixed8_24 sample = ch4Out * ch4StepsScale[steps]; // Muliply by the sample and then shift to make 8.24 again if (REG_NR51 & 0x80) diff --git a/src/platform/shared/audio/m4a_sound_mixer.c b/src/platform/shared/audio/m4a_sound_mixer.c index d0bf1ba8b6..4f69bcde32 100644 --- a/src/platform/shared/audio/m4a_sound_mixer.c +++ b/src/platform/shared/audio/m4a_sound_mixer.c @@ -280,10 +280,10 @@ static inline void GenerateAudio(struct SoundMixerState *mixer, struct MixerSour for (u16 i = 0; i < samplesPerFrame; i++, pcmBuffer += 2) { // Use linear interpolation to calculate a value between the current sample in the wav // and the next sample. Also cancel out the 9.23 stuff - fixed8_24 sample = ((finePos * m) + u32_to_fp8_24(b)); + s32 sample = fp8_24_to_u32((s64)finePos * m) + b; - pcmBuffer[1] += ((s64)sample * envR) >> 24; - pcmBuffer[0] += ((s64)sample * envL) >> 24; + pcmBuffer[1] += (sample * envR); + pcmBuffer[0] += (sample * envL); finePos += romSamplesPerOutputSample; u32 newCoarsePos = fp8_24_to_u32(finePos); @@ -922,14 +922,10 @@ void m4aSoundVSync(void) for (u32 i = 0; i < samplesPerFrame; i++) { // Sample is fixed 8.24 with a value of -1 to 1 - fixed8_24 sample = (m4aBuffer[i] + cgbBuffer[i]); - // Clamp - if (sample > u32_to_fp8_24(1)) { - sample = u32_to_fp8_24(1); - } - if (sample < -u32_to_fp8_24(1)) { - sample = -u32_to_fp8_24(1); - } + // but when we add we divide by 8 to add some headroom + // and make the mix a much more managable volume + fixed8_24 sample = (m4aBuffer[i] + cgbBuffer[i]) >> 3; + // 1 in 8.24 format is 1 << 24 // 32768 is size expected for s16 audio // 32768 = 1 << 15 From cf74cded649114a36d5b6022bc6fb32c87d5a42b Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 4 Mar 2026 01:56:25 +0000 Subject: [PATCH 50/51] more clean up --- INSTALL.md | 36 +++++++++++++++++++++++++++++------- Makefile | 22 +++++++++++----------- README.md | 4 ++-- libagbsyscall/Makefile | 4 ---- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index f1e6b997dd..7ef8b028eb 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -12,16 +12,28 @@ Install WSL (Ubuntu). Once installed, open this project in the WSL terminal and ### Install system requirements #### On Linux (including WSL) -``` +```bash sudo apt update -sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools mkisofs -``` +sudo apt install build-essential binutils-arm-none-eabi gcc-arm-none-eabi libpng-dev xorg-dev libsdl2-dev g++-mingw-w64 gcc-mingw-w64 libarchive-tools +# Optional, if you want to compile for the PS2 you'll need +sudo apt install mkisofs +``` #### On MacOS +```bash +brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc + +# Optional, if you want to compile for the PS2 you'll need +brew install cdrtools ``` -brew install libpng sdl2 mingw-w64 arm-none-eabi-gcc cdrtools -``` + +#### PS2DEV and PSPDEV + +For compiling for the PSP or PS2, ensure that you install the required SDK + +- [PS2DEV](https://github.com/ps2dev/ps2dev) +- [PSPDEV](https://github.com/pspdev/pspdev) ## Building @@ -33,9 +45,9 @@ Run all commands in the same folder as this project. All outputs go into the sam **NOTE**: You can significantly speed up initial build times by passing the number of processes you wish to use for the build. For example `make -j4` with 4 being the number of cores -### PC port +### Ports -The PC port targets different platforms depending on where you are going to be playing it. +The codebase targets different platforms depending on where you are going to be playing it. #### For Windows @@ -54,6 +66,16 @@ Tip: On Linux and MacOS this can be opened with `wine sa2.sdl_win32.exe` 1. `sa2.sdl` will be created 1. Launch the game from the terminal with `./sa2.sdl` +#### For PSP + +1. Run `make sdl_psp` +1. `EBOOT.PBP` will be created + +#### For PS2 + +1. Run `make ps2` +1. `sa2.ps2.iso` will be created + ### GBA rom 1. Clone [agbcc](https://github.com/SAT-R/agbcc) repo into another folder diff --git a/Makefile b/Makefile index a7429b953a..6f7350d1ec 100644 --- a/Makefile +++ b/Makefile @@ -53,7 +53,7 @@ else ifeq ($(CPU_ARCH),i386) PREFIX := x86_64-w64-mingw32- endif # PSP -else ifeq ($(PLATFORM),psp) +else ifeq ($(PLATFORM),sdl_psp) PSPDEV ?= $(HOME)/pspdev PSPSDK := $(PSPDEV)/psp/sdk export PATH := $(PSPDEV)/bin:$(PATH) @@ -129,10 +129,10 @@ else ifeq ($(PLATFORM),sdl) ROM := $(BUILD_NAME).sdl ELF := $(ROM).elf MAP := $(ROM).map -else ifeq ($(PLATFORM),psp) +else ifeq ($(PLATFORM),sdl_psp) ROM := EBOOT.PBP -ELF := $(BUILD_NAME).psp.elf -MAP := $(BUILD_NAME).psp.map +ELF := $(BUILD_NAME).sdl_psp.elf +MAP := $(BUILD_NAME).sdl_psp.map else ifeq ($(PLATFORM),ps2) ROM := $(BUILD_NAME).$(PLATFORM).iso ELF := $(ROM:.iso=.elf) @@ -174,7 +174,7 @@ ifeq ($(PLATFORM),gba) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/*") else ifeq ($(PLATFORM),sdl) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") -else ifeq ($(PLATFORM),psp) +else ifeq ($(PLATFORM),sdl_psp) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/ps2/*") else ifeq ($(PLATFORM),ps2) C_SRCS := $(shell find $(C_SUBDIR) -name "*.c" -not -path "*/platform/win32/*" -not -path "*/platform/pret_sdl/*") @@ -254,7 +254,7 @@ else ifeq ($(PLATFORM),sdl) CC1FLAGS += -Wno-parentheses-equality -Wno-unused-value CPPFLAGS += -D TITLE_BAR=$(BUILD_NAME).$(PLATFORM) -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 $(shell sdl2-config --cflags) - else ifeq ($(PLATFORM),psp) + else ifeq ($(PLATFORM),sdl_psp) CC1FLAGS += -G0 CPPFLAGS += -D PLATFORM_GBA=0 -D PLATFORM_SDL=1 -D PLATFORM_WIN32=0 -D SDL_MAIN_HANDLED -I$(PSPDEV)/psp/include/SDL2 -I$(PSPDEV)/psp/include -I$(PSPSDK)/include -D_PSP_FW_VERSION=600 else ifeq ($(PLATFORM),ps2) @@ -280,7 +280,7 @@ ifeq ($(DEBUG),1) CC1FLAGS += -g3 -O0 CPPFLAGS += -D DEBUG=1 else - ifeq ($(PLATFORM),psp) + ifeq ($(PLATFORM),sdl_psp) # -O3 for PSP (Allegrex MIPS, small D-cache) CC1FLAGS += -O3 -funroll-loops -fomit-frame-pointer else ifeq ($(PLATFORM),ps2) @@ -324,7 +324,7 @@ else # for modern we are using a modern compiler # so instead of CPP we can use gcc -E to "preprocess only" CPP := $(CC1) -E - else ifeq ($(PLATFORM), psp) + else ifeq ($(PLATFORM), sdl_psp) CPP := $(CC1) -E else ifeq ($(PLATFORM), ps2) ASFLAGS += -msingle-float @@ -356,7 +356,7 @@ ifeq ($(PLATFORM),gba) LIBS := $(ROOT_DIR)/tools/agbcc/lib/libgcc.a $(ROOT_DIR)/tools/agbcc/lib/libc.a $(LIBABGSYSCALL_LIBS) else ifeq ($(PLATFORM),sdl) LIBS := $(shell sdl2-config --cflags --libs) -else ifeq ($(PLATFORM),psp) +else ifeq ($(PLATFORM),sdl_psp) LIBS := -L$(PSPDEV)/psp/lib -L$(PSPSDK)/lib -lSDL2 -lm -lGL -lpspvram -lpspaudio -lpspvfpu -lpspdisplay -lpspgu -lpspge -lpsphprm -lpspctrl -lpsppower -lpspdebug -lpspnet -lpspnet_apctl -Wl,-zmax-page-size=128 else ifeq ($(PLATFORM),ps2) LIBS := -T$(PS2SDK)/ee/startup/linkfile -L$(PS2SDK)/common/lib -L$(PS2SDK)/ee/lib -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -lgskit -ldmakit -lps2_drivers -lmc -lpatches -Wl,-zmax-page-size=128 @@ -463,7 +463,7 @@ europe: ; @$(MAKE) GAME_REGION=EUROPE sdl: ; @$(MAKE) PLATFORM=sdl -psp: ; @$(MAKE) PLATFORM=psp +sdl_psp: ; @$(MAKE) PLATFORM=sdl_psp ps2: ; @$(MAKE) PLATFORM=ps2 @@ -540,7 +540,7 @@ else $(ROM): $(ELF) ifeq ($(PLATFORM),sdl) cp $< $@ -else ifeq ($(PLATFORM),psp) +else ifeq ($(PLATFORM),sdl_psp) @echo Creating $(ROM) from $(ELF) @psp-fixup-imports $< @mksfoex 'Sonic Advance 2' PARAM.SFO diff --git a/README.md b/README.md index e980f96c49..dd287be80d 100644 --- a/README.md +++ b/README.md @@ -24,9 +24,9 @@ It builds the following ROMs: It can also build: * **sa2.sdl** `make sdl` (Linux/MacOS SDL 64bit port) * **sa2.sdl_win32.exe** `make sdl_win32` (Windows SDL 64bit port) -* :construction: **sa2.win32.exe** `make win32` (Win32 native port, not functional) +* :construction: **sa2.win32.exe** `make win32` (Win32 OpenGL port, not functional) * **sa2.ps2.iso** `make ps2` (PlayStation 2 port, requires [PS2DEV](https://github.com/ps2dev/ps2dev)) -* **EBOOT.PBP** `make psp` (PlayStation Portable port, requires [PSPDEV](https://github.com/pspdev/pspdev)) +* **EBOOT.PBP** `make sdl_psp` (PlayStation Portable SDL port, requires [PSPDEV](https://github.com/pspdev/pspdev)) ## Current state diff --git a/libagbsyscall/Makefile b/libagbsyscall/Makefile index 7f6c55693a..654a44e4bf 100644 --- a/libagbsyscall/Makefile +++ b/libagbsyscall/Makefile @@ -34,10 +34,6 @@ else ifeq ($(CPU_ARCH),i386) TOOLCHAIN := /usr/x86_64-w64-mingw32/ PREFIX := x86_64-w64-mingw32- endif -else ifeq ($(PLATFORM),psp) - PSPDEV ?= $(HOME)/pspdev - export PATH := $(PSPDEV)/bin:$(PATH) - PREFIX := psp- else ifneq ($(PLATFORM),sdl) $(error Unknown CPU architecture $(CPU_ARCH)) endif # (PLATFORM == gba) From 0dbfeab3a27b938028a3164bd82ca9093343e4dd Mon Sep 17 00:00:00 2001 From: Oliver Bell Date: Wed, 4 Mar 2026 01:57:06 +0000 Subject: [PATCH 51/51] fix ci --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f73b868e44..fa5e892cd1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -170,7 +170,7 @@ jobs: strategy: fail-fast: false matrix: - platform: ["sdl", "sdl_win32", "win32", "ps2", "psp"] + platform: ["sdl", "sdl_win32", "sdl_psp", "win32", "ps2"] os: ["ubuntu-24.04", "macos-15"] if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && !github.event.pull_request.head.repo.fork || github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.fork}} runs-on: ${{ matrix.os }} @@ -216,7 +216,7 @@ jobs: tar -xf ps2dev-latest.tar.gz --strip-components 1 -C $PS2DEV - name: Install PSPDEV - if: ${{ matrix.platform == 'psp' }} + if: ${{ matrix.platform == 'sdl_psp' }} run: | PSPDEV="$HOME/pspdev" echo "PSPDEV=$HOME/pspdev" >> "$GITHUB_ENV"