static void DoFun(int frameskip, int periodic_saves) { uint8 *gfx; int32 *sound; int32 ssize; static int fskipc = 0; static int opause = 0; //TODO peroidic saves, working on it right now if (periodic_saves && FCEUD_GetTime() % PERIODIC_SAVE_INTERVAL < 30){ FCEUI_SaveState(NULL, false); } #ifdef FRAMESKIP fskipc = (fskipc + 1) % (frameskip + 1); #endif if(NoWaiting) { gfx = 0; } FCEUI_Emulate(&gfx, &sound, &ssize, fskipc); FCEUD_Update(gfx, sound, ssize); if(opause!=FCEUI_EmulationPaused()) { opause=FCEUI_EmulationPaused(); SilenceSound(opause); } }
void PLAYBACK::toggleEmulationPause() { if (FCEUI_EmulationPaused()) unpauseEmulation(); else pauseEmulation(); }
void update_input() { usb_do_poll(); unsigned char pad[4]; memset(pad, 0, sizeof (char) * 4); for (int dwUser = 0; dwUser < 2; dwUser++) { get_controller_data(&Gamepads[dwUser], dwUser); if (!FCEUI_EmulationPaused()) { if (Gamepads[dwUser].s1_y > 13107) pad[dwUser] |= JOY_B; if (Gamepads[dwUser].s1_y < -13107) pad[dwUser] |= JOY_UP; if (Gamepads[dwUser].s1_x > 13107) pad[dwUser] |= JOY_RIGHT; if (Gamepads[dwUser].s1_x < -13107) pad[dwUser] |= JOY_LEFT; if (Gamepads[dwUser].up) pad[dwUser] |= JOY_UP; if (Gamepads[dwUser].down) pad[dwUser] |= JOY_DOWN; if (Gamepads[dwUser].left) pad[dwUser] |= JOY_LEFT; if (Gamepads[dwUser].right) pad[dwUser] |= JOY_RIGHT; if (Gamepads[dwUser].a) pad[dwUser] |= JOY_A; if (Gamepads[dwUser].b) pad[dwUser] |= JOY_B; if (Gamepads[dwUser].x) pad[dwUser] |= JOY_A; if (Gamepads[dwUser].y) pad[dwUser] |= JOY_B; if (Gamepads[dwUser].start) pad[dwUser] |= JOY_START; if (Gamepads[dwUser].select) pad[dwUser] |= JOY_SELECT; } } //------------------------------------------------------------------------------------- // Set input from all the gamepads //------------------------------------------------------------------------------------- powerpadbuf = pad[0] | pad[1] << 8; //| pad[2] << 16 | pad[3] << 24;; }
// returns true if user pressed OK, false if Cancel bool DoSymbolicDebugNaming(int offset, HWND parentHWND) { if (!FCEUI_EmulationPaused()) FCEUI_ToggleEmulationPause(); loadNameFiles(); if (DialogBoxParam(fceu_hInstance, MAKEINTRESOURCE(IDD_SYMBOLIC_DEBUG_NAMING), parentHWND, SymbolicNamingCallB, offset)) return true; return false; }
void FCEU_FDSInsert(void) { if (FCEUI_EmulationPaused()) EmulationPaused |= 2; if (FCEUMOV_Mode(MOVIEMODE_RECORD)) FCEUMOV_AddCommand(FCEUNPCMD_FDSINSERT); if (TotalSides == 0) { FCEU_DispMessage("Not FDS; can't eject disk.", 0); return; } if (InDisk == 255) { FCEU_DispMessage("Disk %d Side %s Inserted", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); InDisk = SelectDisk; } else {
// ------------------------------------------------------------------------------------------------- void GREENZONE::adjustUp() { int at = currFrameCounter - 1; // at = the frame above currFrameCounter // find how many consequent lag frames there are int num_frames_to_erase = 0; while (lagLog.getLagInfoAtFrame(at++) == LAGGED_YES) num_frames_to_erase++; if (num_frames_to_erase > 0) { bool markers_changed = false; // delete these frames of lag currMovieData.eraseRecords(currFrameCounter - 1, num_frames_to_erase); lagLog.eraseFrame(currFrameCounter - 1, num_frames_to_erase); if (taseditorConfig.bindMarkersToInput) { if (markersManager.eraseMarker(currFrameCounter - 1, num_frames_to_erase)) markers_changed = true; } // update movie data size, because Playback cursor must always be inside the movie // if movie length is less or equal to currFrame, pad it with empty frames if (((int)currMovieData.records.size() - 1) <= currFrameCounter) currMovieData.insertEmpty(-1, currFrameCounter - ((int)currMovieData.records.size() - 1)); // update Piano Roll (reduce it if needed) pianoRoll.updateLinesCount(); // register changes int first_input_changes = history.registerAdjustLag(currFrameCounter - 1, 0 - num_frames_to_erase); // if Input in the frame above currFrameCounter has changed then invalidate Greenzone (rewind 1 frame back) // also if the frame above currFrameCounter is lag frame then rewind 1 frame (invalidate Greenzone), because maybe this frame also needs lag removal if ((first_input_changes >= 0 && first_input_changes < currFrameCounter) || (lagLog.getLagInfoAtFrame(currFrameCounter - 1) != LAGGED_NO)) { // custom invalidation procedure, not retriggering LostPosition/PauseFrame invalidate(first_input_changes); bool emu_was_paused = (FCEUI_EmulationPaused() != 0); int saved_pause_frame = playback.getPauseFrame(); playback.ensurePlaybackIsInsideGreenzone(); if (saved_pause_frame >= 0) playback.startSeekingToFrame(saved_pause_frame); if (emu_was_paused) playback.pauseEmulation(); } else { // just invalidate Greenzone after currFrameCounter (this is necessary in order to force user to re-emulate everything after the point, because the lag log data after the currFrameCounter is now in unknown state and it should be collected again) invalidate(currFrameCounter); } if (markers_changed) selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true; } }
void HISTORY::update() { // Update undo_hint if (oldUndoHintPos != undoHintPos && oldUndoHintPos >= 0) pianoRoll.redrawRow(oldUndoHintPos); oldUndoHintPos = undoHintPos; oldShowUndoHint = showUndoHint; showUndoHint = false; if (undoHintPos >= 0) { if ((int)clock() < undoHintTimer) showUndoHint = true; else undoHintPos = -1; // finished hinting } if (oldShowUndoHint != showUndoHint) pianoRoll.redrawRow(undoHintPos); // When CPU is idle, compress items from time to time if (clock() > nextAutocompressTime) { if (FCEUI_EmulationPaused()) { // search for the first occurrence of an item containing non-compressed snapshot int real_pos; for (int i = historyTotalItems - 1; i >= 0; i--) { real_pos = (historyStartPos + i) % historySize; if (!snapshots[real_pos].isAlreadyCompressed()) { snapshots[real_pos].compressData(); break; } else if (bookmarkBackups[real_pos].notEmpty && bookmarkBackups[real_pos].snapshot.isAlreadyCompressed()) { bookmarkBackups[real_pos].snapshot.compressData(); break; } } } nextAutocompressTime = clock() + TIME_BETWEEN_AUTOCOMPRESSIONS; } }
// invalidate and restore playback void GREENZONE::invalidateAndUpdatePlayback(int after) { if (after >= 0) { if (after >= currMovieData.getNumRecords()) after = currMovieData.getNumRecords() - 1; // clear all savestates that became irrelevant for (int i = savestates.size() - 1; i > after; i--) clearSavestateOfFrame(i); if (greenzoneSize > after + 1 || currFrameCounter > after) { greenzoneSize = after + 1; FCEUMOV_IncrementRerecordCount(); // either set Playback cursor to be inside the Greenzone or run seeking to restore Playback cursor position if (currFrameCounter >= greenzoneSize) { if (playback.getPauseFrame() >= 0 && !FCEUI_EmulationPaused()) { // emulator was running, so continue seeking, but don't follow the Playback cursor playback.jump(playback.getPauseFrame(), false, true, false); } else { playback.setLastPosition(currFrameCounter); if (taseditorConfig.autoRestoreLastPlaybackPosition) // start seeking to the green arrow, but don't follow the Playback cursor playback.jump(playback.getLastPosition(), false, true, false); else playback.ensurePlaybackIsInsideGreenzone(); } } } } // redraw Piano Roll even if Greenzone didn't change pianoRoll.redraw(); bookmarks.redrawBookmarksList(); }
void GREENZONE::adjustDown() { int at = currFrameCounter - 1; bool markers_changed = false; // clone frame and insert lag currMovieData.cloneRegion(at, 1); lagLog.insertFrame(at, true, 1); if (taseditorConfig.bindMarkersToInput) { if (markersManager.insertEmpty(at, 1)) markers_changed = true; } // register changes int first_input_changes = history.registerAdjustLag(at, +1); // If Input in the frame above currFrameCounter has changed then invalidate Greenzone (rewind 1 frame back) // This should never actually happen, because we clone the frame, so the Input doesn't change // But the check should remain, in case we decide to insert blank frame instead of cloning if (first_input_changes >= 0 && first_input_changes < currFrameCounter) { // custom invalidation procedure, not retriggering LostPosition/PauseFrame invalidate(first_input_changes); bool emu_was_paused = (FCEUI_EmulationPaused() != 0); int saved_pause_frame = playback.getPauseFrame(); playback.ensurePlaybackIsInsideGreenzone(); if (saved_pause_frame >= 0) playback.startSeekingToFrame(saved_pause_frame); if (emu_was_paused) playback.pauseEmulation(); } else { // just invalidate Greenzone after currFrameCounter invalidate(currFrameCounter); } if (markers_changed) selection.mustFindCurrentMarker = playback.mustFindCurrentMarker = true; }
void FCEU_PutImage(void) { if(dosnapsave==2) //Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this? { char nameo[512]; strcpy(nameo,FCEUI_GetSnapshotAsName().c_str()); if (nameo[0]) { SaveSnapshot(nameo); FCEU_DispMessage("Snapshot Saved.",0); } dosnapsave=0; } if(GameInfo->type==GIT_NSF) { DrawNSF(XBuf); //Save snapshot after NSF screen is drawn. Why would we want to do it before? if(dosnapsave==1) { ReallySnap(); dosnapsave=0; } } else { //Save backbuffer before overlay stuff is written. if(!FCEUI_EmulationPaused()) memcpy(XBackBuf, XBuf, 256*256); //Some messages need to be displayed before the avi is dumped DrawMessage(true); #ifdef _S9XLUA_H // Lua gui should draw before the avi is dumped. FCEU_LuaGui(XBuf); #endif //Save snapshot if(dosnapsave==1) { ReallySnap(); dosnapsave=0; } if (!FCEUI_AviEnableHUDrecording()) snapAVI(); if(GameInfo->type==GIT_VSUNI) FCEU_VSUniDraw(XBuf); FCEU_DrawSaveStates(XBuf); FCEU_DrawMovies(XBuf); FCEU_DrawLagCounter(XBuf); FCEU_DrawNTSCControlBars(XBuf); FCEU_DrawRecordingStatus(XBuf); ShowFPS(); } if(FCEUD_ShouldDrawInputAids()) FCEU_DrawInput(XBuf); //Fancy input display code if(input_display) { extern uint32 JSAutoHeld; uint32 held; int controller, c, ci, color; int i, j; uint32 on = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0x90:0xA7; //Standard, or Gray depending on movie mode uint32 oni = 0xA0; //Color for immediate keyboard buttons uint32 blend = 0xB6; //Blend of immiate and last held buttons uint32 ahold = 0x87; //Auto hold uint32 off = 0xCF; uint8 *t = XBuf+(FSettings.LastSLine-9)*256 + 20; //mbg merge 7/17/06 changed t to uint8* if(input_display > 4) input_display = 4; for(controller = 0; controller < input_display; controller++, t += 56) { for(i = 0; i < 34;i++) for(j = 0; j <9 ; j++) t[i+j*256] = (t[i+j*256] & 0x30) | 0xC1; for(i = 3; i < 6; i++) for(j = 3; j< 6; j++) t[i+j*256] = 0xCF; c = cur_input_display >> (controller * 8); // This doesn't work in anything except windows for now. // It doesn't get set anywhere in other ports. #if defined(WIN32) && !defined(DINGUX) if (!oldInputDisplay) ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0:GetGamepadPressedImmediate() >> (controller * 8); else ci = 0; if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY)) held = (JSAutoHeld >> (controller * 8)); else held = 0; #else // Put other port info here ci = 0; held = 0; #endif //adelikat: I apologize to anyone who ever sifts through this color assignment //A if (held&1) { //If auto-hold if (!(ci&1) ) color = ahold; else color = (c&1) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&1) color = (ci&1) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&1) ? oni : off; } for(i=0; i < 4; i++) { for(j = 0; j < 4; j++) { if(i%3==0 && j %3 == 0) continue; t[30+4*256+i+j*256] = color; } } //B if (held&2) { //If auto-hold if (!(ci&2) ) color = ahold; else color = (c&2) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&2) color = (ci&2) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&2) ? oni : off; } for(i=0; i < 4; i++) { for(j = 0; j < 4; j++) { if(i%3==0 && j %3 == 0) continue; t[24+4*256+i+j*256] = color; } } //Select if (held&4) { //If auto-hold if (!(ci&4) ) color = ahold; else color = (c&4) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&4) color = (ci&4) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&4) ? oni : off; } for(i = 0; i < 4; i++) { t[11+5*256+i] = color; t[11+6*256+i] = color; } //Start if (held&8) { //If auto-hold if (!(ci&8) ) color = ahold; else color = (c&8) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&8) color = (ci&8) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&8) ? oni : off; } for(i = 0; i < 4; i++) { t[17+5*256+i] = color; t[17+6*256+i] = color; } //Up if (held&16) { //If auto-hold if (!(ci&16) ) color = ahold; else color = (c&16) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&16) color = (ci&16) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&16) ? oni : off; } for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { t[3+i+256*j] = color; } } //Down if (held&32) { //If auto-hold if (!(ci&32) ) color = ahold; else color = (c&32) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&32) color = (ci&32) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&32) ? oni : off; } for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { t[3+i+256*j+6*256] = color; } } //Left if (held&64) { //If auto-hold if (!(ci&64) ) color = ahold; else color = (c&64) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&64) color = (ci&64) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&64) ? oni : off; } for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { t[3*256+i+256*j] = color; } } //Right if (held&128) { //If auto-hold if (!(ci&128) ) color = ahold; else color = (c&128) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! } else { if (c&128) color = (ci&128) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors else color = (ci&128) ? oni : off; } for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { t[6+3*256+i+256*j] = color; } } }
/** * Update the video, audio, and input subsystems with the provided * video (XBuf) and audio (Buffer) information. */ void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) { extern int FCEUDnetplay; #ifdef CREATE_AVI if(LoggingEnabled == 2 || (eoptions&EO_NOTHROTTLE)) { if(LoggingEnabled == 2) { int16* MonoBuf = new int16[Count]; int n; for(n=0; n<Count; ++n) MonoBuf[n] = Buffer[n] & 0xFFFF; NESVideoLoggingAudio ( MonoBuf, FSettings.SndRate, 16, 1, Count ); delete [] MonoBuf; } Count /= 2; if(inited & 1) { if(Count > GetWriteSound()) Count = GetWriteSound(); if (!mutecapture) if(Count > 0 && Buffer) WriteSound(Buffer,Count); } if(inited & 2) FCEUD_UpdateInput(); if(XBuf && (inited & 4)) BlitScreen(XBuf); //SpeedThrottle(); return; } #endif int ocount = Count; // apply frame scaling to Count Count = (int)(Count / g_fpsScale); if(Count) { int32 can=GetWriteSound(); static int uflow=0; int32 tmpcan; // don't underflow when scaling fps if(can >= GetMaxSound() && g_fpsScale==1.0) uflow=1; /* Go into massive underflow mode. */ if(can > Count) can=Count; else uflow=0; #ifdef CREATE_AVI if (!mutecapture) #endif WriteSound(Buffer,can); //if(uflow) puts("Underflow"); tmpcan = GetWriteSound(); // don't underflow when scaling fps if(g_fpsScale>1.0 || ((tmpcan < Count*0.90) && !uflow)) { if(XBuf && (inited&4) && !(NoWaiting & 2)) BlitScreen(XBuf); Buffer+=can; Count-=can; if(Count) { if(NoWaiting) { can=GetWriteSound(); if(Count>can) Count=can; #ifdef CREATE_AVI if (!mutecapture) #endif WriteSound(Buffer,Count); } else { while(Count>0) { #ifdef CREATE_AVI if (!mutecapture) #endif WriteSound(Buffer,(Count<ocount) ? Count : ocount); Count -= ocount; } } } } //else puts("Skipped"); else if(!NoWaiting && FCEUDnetplay && (uflow || tmpcan >= (Count * 1.8))) { if(Count > tmpcan) Count=tmpcan; while(tmpcan > 0) { // printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan); #ifdef CREATE_AVI if (!mutecapture) #endif WriteSound(Buffer, (Count <= tmpcan)?Count : tmpcan); tmpcan -= Count; } } } else { if(!NoWaiting && (!(eoptions&EO_NOTHROTTLE) || FCEUI_EmulationPaused())) while (SpeedThrottle()) { FCEUD_UpdateInput(); } if(XBuf && (inited&4)) { BlitScreen(XBuf); } } FCEUD_UpdateInput(); //if(!Count && !NoWaiting && !(eoptions&EO_NOTHROTTLE)) // SpeedThrottle(); //if(XBuf && (inited&4)) //{ // BlitScreen(XBuf); //} //if(Count) // WriteSound(Buffer,Count,NoWaiting); //FCEUD_UpdateInput(); }
void PLAYBACK::update() { // controls: // update < and > buttons rewindButtonOldState = rewindButtonState; rewindButtonState = ((Button_GetState(hwndRewind) & BST_PUSHED) != 0 || mustRewindNow); if (rewindButtonState) { if (!rewindButtonOldState) { buttonHoldTimer = clock(); handleRewindFrame(); } else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock()) { handleRewindFrame(); } } forwardButtonOldState = forwardButtonState; forwardButtonState = (Button_GetState(hwndForward) & BST_PUSHED) != 0; if (forwardButtonState && !rewindButtonState) { if (!forwardButtonOldState) { buttonHoldTimer = clock(); handleForwardFrame(); } else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock()) { handleForwardFrame(); } } // update << and >> buttons rewindFullButtonOldState = rewindFullButtonState; rewindFullButtonState = ((Button_GetState(hwndRewindFull) & BST_PUSHED) != 0); if (rewindFullButtonState && !rewindButtonState && !forwardButtonState) { if (!rewindFullButtonOldState) { buttonHoldTimer = clock(); handleRewindFull(); } else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock()) { handleRewindFull(); } } forwardFullButtonOldState = forwardFullButtonState; forwardFullButtonState = (Button_GetState(hwndForwardFull) & BST_PUSHED) != 0; if (forwardFullButtonState && !rewindButtonState && !forwardButtonState && !rewindFullButtonState) { if (!forwardFullButtonOldState) { buttonHoldTimer = clock(); handleForwardFull(); } else if (buttonHoldTimer + BUTTON_HOLD_REPEAT_DELAY < clock()) { handleForwardFull(); } } // update the Playback cursor if (currFrameCounter != lastCursorPos) { // update gfx of the old and new rows pianoRoll.redrawRow(lastCursorPos); bookmarks.redrawChangedBookmarks(lastCursorPos); pianoRoll.redrawRow(currFrameCounter); bookmarks.redrawChangedBookmarks(currFrameCounter); lastCursorPos = currFrameCounter; // follow the Playback cursor, but in case of seeking don't follow it pianoRoll.followPlaybackCursorIfNeeded(false); //pianoRoll.updatePlaybackCursorPositionInPianoRoll(); // an unfinished experiment // enforce redrawing now UpdateWindow(pianoRoll.hwndList); // lazy update of "Playback's Marker text" int current_marker = markersManager.getMarkerAboveFrame(currFrameCounter); if (displayedMarkerNumber != current_marker) { markersManager.updateEditedMarkerNote(); displayedMarkerNumber = current_marker; redrawMarkerData(); mustFindCurrentMarker = false; } } // [non-lazy] update "Playback's Marker text" if needed if (mustFindCurrentMarker) { markersManager.updateEditedMarkerNote(); displayedMarkerNumber = markersManager.getMarkerAboveFrame(currFrameCounter); redrawMarkerData(); mustFindCurrentMarker = false; } // pause when seeking hits pause_frame if (pauseFrame && currFrameCounter + 1 >= pauseFrame) stopSeeking(); else if (currFrameCounter >= getLastPosition() && currFrameCounter >= currMovieData.getNumRecords() - 1 && mustAutopauseAtTheEnd && taseditorConfig.autopauseAtTheEndOfMovie && !isTaseditorRecording()) // pause at the end of the movie pauseEmulation(); // update flashing pauseframe if (oldPauseFrame != pauseFrame && oldPauseFrame) { // pause_frame was changed, clear old_pauseframe gfx pianoRoll.redrawRow(oldPauseFrame-1); bookmarks.redrawChangedBookmarks(oldPauseFrame-1); } oldPauseFrame = pauseFrame; oldStateOfShowPauseFrame = showPauseFrame; if (pauseFrame) { if (emuPausedState) showPauseFrame = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD_WHEN_PAUSED) & 1; else showPauseFrame = (int)(clock() / PAUSEFRAME_BLINKING_PERIOD_WHEN_SEEKING) & 1; } else showPauseFrame = false; if (oldStateOfShowPauseFrame != showPauseFrame) { // update pauseframe gfx pianoRoll.redrawRow(pauseFrame - 1); bookmarks.redrawChangedBookmarks(pauseFrame - 1); } // update seeking progressbar emuPausedOldState = emuPausedState; emuPausedState = (FCEUI_EmulationPaused() != 0); if (pauseFrame) { if (oldStateOfShowPauseFrame != showPauseFrame) // update progressbar from time to time // display seeking progress setProgressbar(currFrameCounter - seekingBeginningFrame, pauseFrame - seekingBeginningFrame); } else if (emuPausedOldState != emuPausedState) { // emulator got paused/unpaused externally if (emuPausedOldState && !emuPausedState) { // externally unpaused - show empty progressbar setProgressbar(0, 1); } else { // externally paused - progressbar should be full setProgressbar(1, 1); } } // prepare to stop at the end of the movie in case user unpauses emulator if (emuPausedState) { if (currFrameCounter < currMovieData.getNumRecords() - 1) mustAutopauseAtTheEnd = true; else mustAutopauseAtTheEnd = false; } // this little statement is very important for adequate work of the "green arrow" and "Restore last position" if (!emuPausedState) // when emulating, lost_position_frame becomes unstable (which means that it's probably not equal to the end of current segment anymore) lastPositionIsStable = false; }