bool ReGBA_SaveSettings(char *cfg_name, bool PerGame) { char fname[MAX_PATH + 1]; if (strlen(main_path) + strlen(cfg_name) + 5 /* / .cfg */ > MAX_PATH) { ReGBA_Trace("E: Somehow you hit the filename size limit :o\n"); return false; } sprintf(fname, "%s/%s.cfg", main_path, cfg_name); FILE_TAG_TYPE fd; ReGBA_ProgressInitialise(PerGame ? FILE_ACTION_SAVE_GAME_SETTINGS : FILE_ACTION_SAVE_GLOBAL_SETTINGS); FILE_OPEN(fd, fname, WRITE); if(FILE_CHECK_VALID(fd)) { Menu_SaveIterateRecurse(fd, PerGame ? MainMenu.AlternateVersion : &MainMenu); ReGBA_ProgressUpdate(1, 1); ReGBA_ProgressFinalise(); } else { ReGBA_Trace("E: Couldn't open file %s for writing.\n", fname); ReGBA_ProgressFinalise(); return false; } FILE_CLOSE(fd); return true; }
static void DefaultDisplayTitleFunction(struct Menu* ActiveMenu) { uint32_t TextWidth = GetRenderedWidth(ActiveMenu->Title); if (TextWidth <= GCW0_SCREEN_WIDTH - 2) print_string_outline(ActiveMenu->Title, COLOR_TITLE_TEXT, COLOR_TITLE_OUTLINE, (GCW0_SCREEN_WIDTH - TextWidth) / 2, 1); else ReGBA_Trace("W: Hid title '%s' from the menu due to it being too long", ActiveMenu->Title); }
static void DefaultDisplayValueFunction(struct MenuEntry* DrawnMenuEntry, struct MenuEntry* ActiveMenuEntry) { if (DrawnMenuEntry->Kind == KIND_OPTION || DrawnMenuEntry->Kind == KIND_DISPLAY) { char* Value; char Temp[21]; bool Error = false; if (DrawnMenuEntry->Kind == KIND_OPTION) { if (*(uint32_t*) DrawnMenuEntry->Target < DrawnMenuEntry->ChoiceCount) Value = DrawnMenuEntry->Choices[*(uint32_t*) DrawnMenuEntry->Target].Pretty; else { Value = "Out of bounds"; Error = true; } } else if (DrawnMenuEntry->Kind == KIND_DISPLAY) { switch (DrawnMenuEntry->DisplayType) { case TYPE_STRING: Value = (char*) DrawnMenuEntry->Target; break; case TYPE_INT32: sprintf(Temp, "%" PRIi32, *(int32_t*) DrawnMenuEntry->Target); Value = Temp; break; case TYPE_UINT32: sprintf(Temp, "%" PRIu32, *(uint32_t*) DrawnMenuEntry->Target); Value = Temp; break; case TYPE_INT64: print_i64(Temp, *(int64_t*) DrawnMenuEntry->Target); Value = Temp; break; case TYPE_UINT64: print_u64(Temp, *(uint64_t*) DrawnMenuEntry->Target); Value = Temp; break; default: Value = "Unknown type"; Error = true; break; } } uint32_t TextWidth = GetRenderedWidth(Value); if (TextWidth <= GCW0_SCREEN_WIDTH - 2) { bool IsActive = (DrawnMenuEntry == ActiveMenuEntry); uint16_t TextColor = Error ? COLOR_ERROR_TEXT : (IsActive ? COLOR_ACTIVE_TEXT : COLOR_INACTIVE_TEXT); uint16_t OutlineColor = Error ? COLOR_ERROR_OUTLINE : (IsActive ? COLOR_ACTIVE_OUTLINE : COLOR_INACTIVE_OUTLINE); print_string_outline(Value, TextColor, OutlineColor, GCW0_SCREEN_WIDTH - TextWidth - 1, GetRenderedHeight(" ") * (DrawnMenuEntry->Position + 2) + 1); } else ReGBA_Trace("W: Hid value '%s' from the menu due to it being too long", Value); } }
static void EnsureJoystick() { if (!JoystickInitialised) { JoystickInitialised = true; Joystick = SDL_JoystickOpen(0); if (Joystick == NULL) { ReGBA_Trace("I: Joystick #0 could not be opened"); } } }
static void DefaultLoadFunction(struct MenuEntry* ActiveMenuEntry, char* Value) { uint32_t i; for (i = 0; i < ActiveMenuEntry->ChoiceCount; i++) { if (strcasecmp(ActiveMenuEntry->Choices[i].Persistent, Value) == 0) { *(uint32_t*) ActiveMenuEntry->Target = i; return; } } ReGBA_Trace("W: Value '%s' for option '%s' not valid; ignored", Value, ActiveMenuEntry->PersistentName); }
static void DefaultDisplayNameFunction(struct MenuEntry* DrawnMenuEntry, struct MenuEntry* ActiveMenuEntry) { uint32_t TextWidth = GetRenderedWidth(DrawnMenuEntry->Name); if (TextWidth <= GCW0_SCREEN_WIDTH - 2) { bool IsActive = (DrawnMenuEntry == ActiveMenuEntry); uint16_t TextColor = IsActive ? COLOR_ACTIVE_TEXT : COLOR_INACTIVE_TEXT; uint16_t OutlineColor = IsActive ? COLOR_ACTIVE_OUTLINE : COLOR_INACTIVE_OUTLINE; print_string_outline(DrawnMenuEntry->Name, TextColor, OutlineColor, 1, GetRenderedHeight(" ") * (DrawnMenuEntry->Position + 2) + 1); } else ReGBA_Trace("W: Hid name '%s' from the menu due to it being too long", DrawnMenuEntry->Name); }
static enum OpenDingux_Buttons GrabButtons(struct Menu* ActiveMenu, char* Lines[4]) { enum OpenDingux_Buttons Buttons; // Wait for the buttons that triggered the action to be released. while (GetPressedOpenDinguxButtons() != 0) { DefaultDisplayBackgroundFunction(ActiveMenu); SDL_Flip(OutputSurface); usleep(5000); // for platforms that don't sync their flips } // Wait until a button is pressed. while ((Buttons = GetPressedOpenDinguxButtons()) == 0) { DefaultDisplayBackgroundFunction(ActiveMenu); uint32_t Line; for (Line = 0; Line < 4; Line++) { uint32_t TextWidth = GetRenderedWidth(Lines[Line]); if (TextWidth <= GCW0_SCREEN_WIDTH - 2) print_string_outline(Lines[Line], COLOR_ACTIVE_TEXT, COLOR_ACTIVE_OUTLINE, (GCW0_SCREEN_WIDTH - TextWidth) / 2, (GCW0_SCREEN_HEIGHT - GetRenderedHeight(" ") * 4) / 2 + GetRenderedHeight(" ") * Line); else ReGBA_Trace("E: '%s' doesn't fit the screen! Fix this, Nebuleon!", Lines[Line]); } SDL_Flip(OutputSurface); usleep(5000); // for platforms that don't sync their flips } // Accumulate buttons until they're all released. enum OpenDingux_Buttons ButtonTotal = Buttons; while ((Buttons = GetPressedOpenDinguxButtons()) != 0) { // a) If the old buttons are a strict subset of the new buttons, // add the new buttons. if ((Buttons | ButtonTotal) == Buttons) ButtonTotal |= Buttons; // b) If the new buttons are a strict subset of the old buttons, // do nothing. (The user is releasing the buttons to return.) else if ((Buttons | ButtonTotal) == ButtonTotal) ; // c) If the new buttons are on another path, replace the buttons // completely, for example, R+X turning into R+Y. else ButtonTotal = Buttons; DefaultDisplayBackgroundFunction(ActiveMenu); SDL_Flip(OutputSurface); usleep(5000); // for platforms that don't sync their flips } return ButtonTotal; }
static void DisplayHotkeyValue(struct MenuEntry* DrawnMenuEntry, struct MenuEntry* ActiveMenuEntry) { char Value[256]; GetButtonsText(*(uint32_t*) DrawnMenuEntry->Target, Value); uint32_t TextWidth = GetRenderedWidth(Value); if (TextWidth <= GCW0_SCREEN_WIDTH - 2) { bool IsActive = (DrawnMenuEntry == ActiveMenuEntry); uint16_t TextColor = IsActive ? COLOR_ACTIVE_TEXT : COLOR_INACTIVE_TEXT; uint16_t OutlineColor = IsActive ? COLOR_ACTIVE_OUTLINE : COLOR_INACTIVE_OUTLINE; print_string_outline(Value, TextColor, OutlineColor, GCW0_SCREEN_WIDTH - TextWidth - 1, GetRenderedHeight(" ") * (DrawnMenuEntry->Position + 2) + 1); } else ReGBA_Trace("W: Hid value '%s' from the menu due to it being too long", Value); }
void init_sdlaudio() { SDL_AudioSpec spec; spec.freq = OUTPUT_SOUND_FREQUENCY; spec.format = AUDIO_S16SYS; spec.channels = 2; spec.samples = AUDIO_OUTPUT_BUFFER_SIZE; spec.callback = feed_buffer; spec.userdata = NULL; if (SDL_OpenAudio(&spec, NULL) < 0) { ReGBA_Trace("E: Failed to open audio: %s", SDL_GetError()); return; } SDL_PauseAudio(0); }
static enum OpenDingux_Buttons GrabButton(struct Menu* ActiveMenu, char* Lines[4]) { enum OpenDingux_Buttons Buttons; // Wait for the buttons that triggered the action to be released. while (GetPressedOpenDinguxButtons() != 0) { DefaultDisplayBackgroundFunction(ActiveMenu); SDL_Flip(OutputSurface); usleep(5000); // for platforms that don't sync their flips } // Wait until a button is pressed. while ((Buttons = GetPressedOpenDinguxButtons()) == 0) { DefaultDisplayBackgroundFunction(ActiveMenu); uint32_t Line; for (Line = 0; Line < 4; Line++) { uint32_t TextWidth = GetRenderedWidth(Lines[Line]); if (TextWidth <= GCW0_SCREEN_WIDTH - 2) print_string_outline(Lines[Line], COLOR_ACTIVE_TEXT, COLOR_ACTIVE_OUTLINE, (GCW0_SCREEN_WIDTH - TextWidth) / 2, (GCW0_SCREEN_HEIGHT - GetRenderedHeight(" ") * 4) / 2 + GetRenderedHeight(" ") * Line); else ReGBA_Trace("E: '%s' doesn't fit the screen! Fix this, Nebuleon!", Lines[Line]); } SDL_Flip(OutputSurface); usleep(5000); // for platforms that don't sync their flips } // Accumulate buttons until they're all released. enum OpenDingux_Buttons ButtonTotal = Buttons; while ((Buttons = GetPressedOpenDinguxButtons()) != 0) { ButtonTotal |= Buttons; DefaultDisplayBackgroundFunction(ActiveMenu); SDL_Flip(OutputSurface); usleep(5000); // for platforms that don't sync their flips } return ButtonTotal; }
void ReGBA_LoadSettings(char *cfg_name, bool PerGame) { char fname[MAX_PATH + 1]; if (strlen(main_path) + strlen(cfg_name) + 5 /* / .cfg */ > MAX_PATH) { ReGBA_Trace("E: Somehow you hit the filename size limit :o\n"); return; } sprintf(fname, "%s/%s.cfg", main_path, cfg_name); FILE_TAG_TYPE fd; ReGBA_ProgressInitialise(PerGame ? FILE_ACTION_LOAD_GAME_SETTINGS : FILE_ACTION_LOAD_GLOBAL_SETTINGS); FILE_OPEN(fd, fname, READ); if(FILE_CHECK_VALID(fd)) { char line[257]; while(fgets(line, 256, fd)) { line[256] = '\0'; char* opt = NULL; char* arg = NULL; char* cur = line; // Find the start of the option name. while (*cur == ' ' || *cur == '\t') cur++; // Now find where it ends. while (*cur && !(*cur == ' ' || *cur == '\t' || *cur == '=')) { if (*cur == '#') continue; else if (opt == NULL) opt = cur; cur++; } if (opt == NULL) continue; bool WasEquals = *cur == '='; *cur++ = '\0'; if (!WasEquals) { // Skip all whitespace before =. while (*cur == ' ' || *cur == '\t') cur++; if (*cur != '=') continue; cur++; } // Find the start of the option argument. while (*cur == ' ' || *cur == '\t') cur++; // Now find where it ends. while (*cur) { if (*cur == '#') { *cur = '\0'; break; } else if (arg == NULL) arg = cur; cur++; } if (arg == NULL) continue; cur--; while (*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r') { *cur = '\0'; cur--; } struct MenuEntry* entry = Menu_FindByPersistentName(PerGame ? MainMenu.AlternateVersion : &MainMenu, opt); if (entry == NULL) { ReGBA_Trace("W: Option '%s' not found; ignored", opt); } else { MenuPersistenceFunction LoadFunction = entry->LoadFunction; if (LoadFunction == NULL) LoadFunction = &DefaultLoadFunction; (*LoadFunction)(entry, arg); } } ReGBA_ProgressUpdate(1, 1); } else { ReGBA_Trace("W: Couldn't open file %s for loading.\n", fname); } FixUpSettings(); ReGBA_ProgressFinalise(); }
signed int ReGBA_AudioUpdate() { u32 i, j; s16* audio_buff; s16 *dst_ptr, *dst_ptr1; u32 n = ds2_checkAudiobuff(); int ret; u8 WasInUnderrun = Stats.InSoundBufferUnderrun; Stats.InSoundBufferUnderrun = n == 0 && ReGBA_GetAudioSamplesAvailable() < AUDIO_LEN * 2; if (Stats.InSoundBufferUnderrun && !WasInUnderrun) Stats.SoundBufferUnderrunCount++; // On auto frameskip, sound buffers being full or empty determines // whether we're late. if (AUTO_SKIP) { if (n >= 2) { // We're in no hurry, because 2 buffers are still full. // Minimum skip 1 if(SKIP_RATE > 1) { #if defined TRACE || defined TRACE_FRAMESKIP ReGBA_Trace("I: Decreasing automatic frameskip: %u..%u", SKIP_RATE, SKIP_RATE - 1); #endif SKIP_RATE--; } } else { // Maximum skip 9 if(SKIP_RATE < 8) { #if defined TRACE || defined TRACE_FRAMESKIP ReGBA_Trace("I: Increasing automatic frameskip: %u..%u", SKIP_RATE, SKIP_RATE + 1); #endif SKIP_RATE++; } } } /* There must be AUDIO_LEN * 2 samples generated in order for the first * AUDIO_LEN to be valid. Some sound is generated in the past from the * future, and if the first AUDIO_LEN is grabbed before the core has had * time to generate all of it (at AUDIO_LEN * 2), the end may still be * silence, causing crackling. */ if (ReGBA_GetAudioSamplesAvailable() < AUDIO_LEN * 2) { // Generate more sound first, please! return -1; } // We have enough sound. Complete this update. if (game_fast_forward || temporary_fast_forward) { if (n >= AUDIO_BUFFER_COUNT) { // Drain the buffer down to a manageable size, then exit. // This needs to be high to avoid audible crackling/bubbling, // but not so high as to require all of the sound to be emitted. // gpSP synchronises on the sound, after all. -Neb, 2013-03-23 ReGBA_DiscardAudioSamples(ReGBA_GetAudioSamplesAvailable() - AUDIO_LEN); return 0; } } else { // Wait for at least one buffer to be free for audio. // Output assertion: The return value is between 0, inclusive, // and AUDIO_BUFFER_COUNT, inclusive, but can also be // 4294967295; that's (unsigned int) -1. (DSTWO SPECIFIC HACK) unsigned int n2; while ((n2 = ds2_checkAudiobuff()) >= AUDIO_BUFFER_COUNT && (int) n2 >= 0); } audio_buff = ds2_getAudiobuff(); if (audio_buff == NULL) { #if defined TRACE || defined TRACE_SOUND ReGBA_Trace("Recovered from the lack of a buffer"); #endif return -1; } dst_ptr = audio_buff; // left (stereo) dst_ptr1 = dst_ptr + (int) (AUDIO_LEN / OUTPUT_FREQUENCY_DIVISOR); // right (stereo) for(i= 0; i < AUDIO_LEN; i += OUTPUT_FREQUENCY_DIVISOR) { s16 Left = 0, Right = 0, LeftPart, RightPart; for (j = 0; j < OUTPUT_FREQUENCY_DIVISOR; j++) { ReGBA_LoadNextAudioSample(&LeftPart, &RightPart); if (LeftPart > 2047) LeftPart = 2047; else if (LeftPart < -2048) LeftPart = -2048; Left += LeftPart / OUTPUT_FREQUENCY_DIVISOR; if (RightPart > 2047) RightPart = 2047; else if (RightPart < -2048) RightPart = -2048; Right += RightPart / OUTPUT_FREQUENCY_DIVISOR; } *dst_ptr++ = Left << 4; *dst_ptr1++ = Right << 4; } if (game_fast_forward || temporary_fast_forward) { // Dampen the sound with the previous samples written // (or unitialised data if we just started the emulator) StartFastForwardedSound(audio_buff, &audio_buff[(int) (AUDIO_LEN / OUTPUT_FREQUENCY_DIVISOR)]); // Store the end for the next time EndFastForwardedSound(&audio_buff[(int) (AUDIO_LEN / OUTPUT_FREQUENCY_DIVISOR) - DAMPEN_SAMPLE_COUNT], &audio_buff[(int) (AUDIO_LEN / OUTPUT_FREQUENCY_DIVISOR) * 2 - DAMPEN_SAMPLE_COUNT]); } Stats.InSoundBufferUnderrun = 0; ds2_updateAudio(); return 0; }