Esempio n. 1
0
int
sound_write (const char *buffer, int frames)
{
  int rc;

  if (frames == 0)
    return sound_flush ();

  if (g_paused)
    return 0;

 restart:
  rc = snd_pcm_writei (handle, buffer, frames);
  if (rc == -EPIPE)
    {
      snd_pcm_prepare (handle);
      goto restart;
    }

  return rc;
}
Esempio n. 2
0
/* This is called at the end of each screen frame. It flushes the
   audio buffer and keeps control of the emulation speed. */
int vsync_do_vsync(struct video_canvas_s *c, int been_skipped)
{
    static unsigned long next_frame_start = 0;
    unsigned long network_hook_time = 0;

    /*
     * these are the counters to show how many frames are skipped
     * since the last vsync_display_speed
     */
    static int frame_counter = 0;
    static int skipped_frames = 0;

    /*
     * This are the frames which are skipped in a row
     */
    static int skipped_redraw = 0;

    /* Adjustment of frame output frequency. */
    static unsigned long adjust_start;
    static int frames_adjust;
    static signed long avg_sdelay, prev_sdelay;

    double sound_delay;
    int skip_next_frame;

    signed long delay;
    long frame_ticks_remainder, frame_ticks_integer, compval;

#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
    float refresh_cmp;
    int refresh_div;
#endif

#ifdef HAVE_NETWORK
    /* check if someone wants to connect remotely to the monitor */
    monitor_check_remote();
#endif

    vsync_frame_counter++;

    /*
     * process everything wich should be done before the synchronisation
     * e.g. OS/2: exit the programm if trigger_shutdown set
     */
    vsyncarch_presync();

    /* Run vsync jobs. */
    if (network_connected()) {
        network_hook_time = vsyncarch_gettime();
    }

    vsync_hook();

    if (network_connected()) {
        network_hook_time = vsyncarch_gettime() - network_hook_time;

        if (network_hook_time > (unsigned long)frame_ticks) {
            next_frame_start += network_hook_time;
            now += network_hook_time;
        }
    }

#ifdef DEBUG
    /* switch between recording and playback in history debug mode */
    debug_check_autoplay_mode();
#endif

    /*
     * Update display every two second (pc system time)
     * This has some reasons:
     *  - we have a better statistic in case of a fastly running emulator
     *  - we don't slow down fast emulations by updating this value
     *    too often (eg more then 10 times a second)
     *  - I don't want to have a value jumping around for example
     *    between 99% and 101% if the user chooses 100% (s.above)
     *  - We need some statistict to get an avarage number for the
     *    frame-rate without staticstics it would also jump around
     */
    frame_counter++;

    if (!speed_eval_suspended &&
            (signed long)(now - display_start) >= 2 * vsyncarch_freq) {
        display_speed(frame_counter - skipped_frames);
        display_start = now;
        frame_counter = 0;
        skipped_frames = 0;
    }

    if (been_skipped) {
        skipped_frames++;
    }

    /* Flush sound buffer, get delay in seconds. */
    sound_delay = sound_flush();

    /* Get current time, directly after getting the sound delay. */
    now = vsyncarch_gettime();

    /* Start afresh after pause in frame output. */
    if (speed_eval_suspended) {
        speed_eval_suspended = 0;

        speed_eval_prev_clk = maincpu_clk;

        display_start = now;
        frame_counter = 0;
        skipped_frames = 0;

        next_frame_start = now;
        skipped_redraw = 0;
    }

    /* Start afresh after "out of sync" cases. */
    if (sync_reset) {
        sync_reset = 0;

        adjust_start = now;
        frames_adjust = 0;
        avg_sdelay = 0;
        prev_sdelay = 0;

        frame_ticks = (frame_ticks_orig + frame_ticks) / 2;
    }


    /* This is the time between the start of the next frame and now. */
    delay = (signed long)(now - next_frame_start);
#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
    refresh_cmp = (float)(c->refreshrate / refresh_frequency);
    refresh_div = (int)(refresh_cmp + 0.5f);
    refresh_cmp /= (float)refresh_div;

    if ((timer_speed == 100) && (!warp_mode_enabled) &&
            vsyncarch_vbl_sync_enabled() &&
            (refresh_cmp <= 1.02f) && (refresh_cmp > 0.98f) &&
            (refresh_div == 1)) {
        vsyncarch_verticalblank(c, c->refreshrate, refresh_div);
        skip_next_frame = 0;
        skipped_redraw = 0;
    } else {
#endif
        /*
         * We sleep until the start of the next frame, if:
         *  - warp_mode is disabled
         *  - a limiting speed is given
         *  - we have not reached next_frame_start yet
         *
         * We could optimize by sleeping only if a frame is to be output.
         */
        /*log_debug("vsync_do_vsync: sound_delay=%f  frame_ticks=%d  delay=%d", sound_delay, frame_ticks, delay);*/
        if (!warp_mode_enabled && timer_speed && delay < 0) {
            vsyncarch_sleep(-delay);
        }
#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
        vsyncarch_prepare_vbl();
#endif
        /*
         * Check whether we should skip the next frame or not.
         * Allow delay of up to one frame before skipping frames.
         * Frames are skipped:
         *  - only if maximum skipped frames are not reached
         *  - if warp_mode enabled
         *  - if speed is not limited or we are too slow and
         *    refresh rate is automatic or fixed and needs correction
         *
         * Remark: The time_deviation should be the equivalent of two
         *         frames and must be scaled to make sure, that we
         *         don't start skipping frames before the CPU reaches 100%.
         *         If we are becoming faster a small deviation because of
         *         threading results in a frame rate correction suddenly.
         */
        frame_ticks_remainder = frame_ticks % 100;
        frame_ticks_integer = frame_ticks / 100;
        compval = frame_ticks_integer * 3 * timer_speed
                  + frame_ticks_remainder * 3 * timer_speed / 100;
        if (skipped_redraw < MAX_SKIPPED_FRAMES
                && (warp_mode_enabled
                    || (skipped_redraw < refresh_rate - 1)
                    || ((!timer_speed || delay > compval)
                        && !refresh_rate
                       )
                   )
           ) {
            skip_next_frame = 1;
            skipped_redraw++;
        } else {
            skip_next_frame = 0;
            skipped_redraw = 0;
        }
#if (defined(HAVE_OPENGL_SYNC)) && !defined(USE_SDLUI)
    }
#endif

    /*
     * Check whether the hardware can keep up.
     * Allow up to 0,25 second error before forcing a correction.
     */
    if ((signed long)(now - next_frame_start) >= vsyncarch_freq / 8) {
#if !defined(__OS2__) && !defined(DEBUG)
        if (!warp_mode_enabled && relative_speed) {
            log_warning(LOG_DEFAULT, "Your machine is too slow for current settings!");
        }
#endif
        vsync_sync_reset();
        next_frame_start = now;
    }

    /* Adjust frame output frequency to match sound speed.
       This only kicks in for cycle based sound and SOUND_ADJUST_EXACT. */
    if (frames_adjust < INT_MAX) {
        frames_adjust++;
    }

    /* Adjust audio-video sync */
    if (!network_connected()
            && (signed long)(now - adjust_start) >= vsyncarch_freq / 5) {
        signed long adjust;
        avg_sdelay /= frames_adjust;
        /* Account for both relative and absolute delay. */
        adjust = (avg_sdelay - prev_sdelay + avg_sdelay / 8) / frames_adjust;
        /* Maximum adjustment step 1%. */
        if (labs(adjust) > frame_ticks / 100) {
            adjust = adjust / labs(adjust) * frame_ticks / 100;
        }
        frame_ticks -= adjust;

        frames_adjust = 0;
        prev_sdelay = avg_sdelay;
        avg_sdelay = 0;

        adjust_start = now;
    } else {
        /* Actual sound delay is sound delay minus vsync delay. */
        signed long sdelay = (signed long)(sound_delay * vsyncarch_freq);
        avg_sdelay += sdelay;
    }

    next_frame_start += frame_ticks;

    vsyncarch_postsync();
#if 0
    FILE *fd = fopen("latencylog.txt", "a");
    fprintf(fd, "%d %ld %ld %lf\n",
            vsync_frame_counter, frame_ticks, delay, sound_delay * 1000000);
    fclose(fd);
#endif
    return skip_next_frame;
}
Esempio n. 3
0
/* This is called at the end of each screen frame.  It flushes the audio buffer
   and keeps control of the emulation speed.  */
int vsync_do_vsync(int been_skipped)
{
    static unsigned short frame_counter = USHRT_MAX;
    static unsigned short num_skipped_frames;
    static int skip_counter;
    int skip_next_frame = 0;

    vsync_hook();

    if (been_skipped) num_skipped_frames++;

    if (timer_speed != relative_speed) {
	frame_counter = USHRT_MAX;
        if (set_timer_speed(relative_speed) < 0) {
	    log_error(LOG_DEFAULT, "Trouble setting timers... giving up.");
            /* FIXME: Hm, maybe we should be smarter.  But this is should
               never happen.*/
	    exit(-1);
	}
    }

    if (warp_mode_enabled) {
        /* "Warp Mode".  Just skip as many frames as possible and do not
           limit the maximum speed at all.  */
        if (skip_counter < MAX_SKIPPED_FRAMES) {
            skip_next_frame = 1;
            skip_counter++;
        }
        else skip_counter = elapsed_frames = 0;
        sound_flush(0);
    }
    else
        if (refresh_rate != 0) {
            update_elapsed_frames(0); /* Fixed refresh rate.  */
            if (timer_speed && skip_counter >= elapsed_frames) timer_sleep();
            if (skip_counter < refresh_rate - 1) {
                skip_next_frame = 1;
                skip_counter++;
            }
            else skip_counter = elapsed_frames = 0;
            patch_timer(sound_flush(relative_speed));
        }
        else
        {
            /* Dynamically adjusted refresh rate.  */
            update_elapsed_frames(0);
            if (skip_counter >= elapsed_frames) {
                elapsed_frames = -1;
                timer_sleep();
                skip_counter = 0;
            }
            else
                if (skip_counter < MAX_SKIPPED_FRAMES) {
                    skip_next_frame = 1;
                    skip_counter++;
                }
                else skip_counter = elapsed_frames = 0;
            patch_timer(sound_flush(relative_speed));
        }

    if (frame_counter >= refresh_frequency * 2) {
        display_speed(frame_counter + 1 - num_skipped_frames);
	num_skipped_frames = 0;
	frame_counter = 0;
    } else
        frame_counter++;


    kbdbuf_flush();

#ifdef HAS_JOYSTICK
    joystick_update();
#endif

    return skip_next_frame;
}
Esempio n. 4
0
int vsync_do_vsync(struct video_canvas_s *canvas, int been_skipped)
{
    int skip_next_frame = 0;
    int frame_delay;
    int now, dopoll;

    /* this can happen in some rare cases; make sure emulation stops then */
    while (EmuPaused != 0) {
        ui_poll(1);
    }

    if (FullScreenMode != 0) {
        EmuWindowHasInputFocus = 1;
    } else {
        RO_Caret caret;

        Wimp_GetCaretPosition(&caret);

        /* This will be used by keyboard and joystick code */
        EmuWindowHasInputFocus = (canvas_for_handle(caret.WHandle) == NULL) ? 0 : 1;
    }

    now = OS_ReadMonotonicTime();

    if (warp_mode_enabled) {
        if (skip_counter < MaxSkippedFrames) {
            skip_next_frame = 1;
            skip_counter++;
        } else {
            skip_counter = 0;
        }
    } else if (refresh_rate != 0) {
        if (skip_counter < refresh_rate - 1) {
            skip_next_frame = 1;
            skip_counter++;
        } else {
            skip_counter = 0;
        }
    } else {
        /* Use NumberOfFrames+1 because this frame isn't counted yet */
        if ((VSYNC_TIME_DELTA(now, NumberOfFrames+1) < 0) && (skip_counter < MaxSkippedFrames)) {
            skip_next_frame = 1;
            skip_counter++;
        } else {
            skip_counter = 0;
        }
    }

    /* always pass the actual speed unless in reSID mode */
    frame_delay = sound_flush();

    if (frame_counter >= refresh_frequency * 2) {
        num_skipped_frames = 0;
        frame_counter = 0;
    } else {
        frame_counter++;
    }

    if (skip_next_frame == 0) {
        NumberOfRefreshes++;
    }

    vsync_hook();

    joystick();
    mousedrv_sync();

    NumberOfFrames += 1 - frame_delay;

    /* Speed limiter? Wait */
    if ((CurrentSpeedLimit != 0) && (warp_mode_enabled == 0)) {
        while (VSYNC_TIME_DELTA(now, NumberOfFrames) > 0) {
            now = OS_ReadMonotonicTime();
        }
    }
    LastFrame = now;

    if (speed_eval_suspended) {
        vsync_resync_speed();
        speed_eval_suspended = 0;
    } else {
        if ((now - LastSpeed) >= SpeedEvery) {
            int val;

            RelativeSpeed = (10000 * NumberOfFrames) / (FramesPerSecond * (now - LastSpeed));
            ui_display_speed(RelativeSpeed, (100 * NumberOfRefreshes) / (now - LastSpeed), 0);
            LastSpeed = now;
            NumberOfFrames = 0;
            NumberOfRefreshes = 0;
            resources_get_int("MachineVideoStandard", &val);
            FramesPerSecond = (val == MACHINE_SYNC_PAL) ? 50 : 60;
        }
    }

    dopoll = 0;
    if ((now - LastPoll) >= PollEvery) {
        dopoll = 1;
        LastPoll = now;
    }

    ui_poll(dopoll);

    video_full_screen_plot_status();

    kbdbuf_flush();

    return skip_next_frame;
}