diff --git a/snes9x.cpp b/snes9x.cpp index 4437a632..d551657d 100644 --- a/snes9x.cpp +++ b/snes9x.cpp @@ -491,6 +491,11 @@ char * S9xParseArgs (char **argv, int argc) if (!strcasecmp(argv[i], "-soundsync")) Settings.SoundSync = TRUE; + else if (!strcasecmp(argv[i], "-dynamicratecontrol")) + { + Settings.DynamicRateControl = TRUE; + Settings.DynamicRateLimit = 5; + } else if (!strcasecmp(argv[i], "-playbackrate")) { diff --git a/unix/configure b/unix/configure index 550fc473..c6c0c459 100755 --- a/unix/configure +++ b/unix/configure @@ -1,7 +1,7 @@ #! /bin/sh -# From configure.ac Revision: 1.59.2 . +# From configure.ac Revision: 1.60 . # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Snes9x 1.59.2. +# Generated by GNU Autoconf 2.69 for Snes9x 1.60. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -578,8 +578,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Snes9x' PACKAGE_TARNAME='snes9x' -PACKAGE_VERSION='1.59.2' -PACKAGE_STRING='Snes9x 1.59.2' +PACKAGE_VERSION='1.60' +PACKAGE_STRING='Snes9x 1.60' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1280,7 +1280,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Snes9x 1.59.2 to adapt to many kinds of systems. +\`configure' configures Snes9x 1.60 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1350,7 +1350,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Snes9x 1.59.2:";; + short | recursive ) echo "Configuration of Snes9x 1.60:";; esac cat <<\_ACEOF @@ -1468,7 +1468,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Snes9x configure 1.59.2 +Snes9x configure 1.60 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1871,7 +1871,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Snes9x $as_me 1.59.2, which was +It was created by Snes9x $as_me 1.60, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -6915,7 +6915,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Snes9x $as_me 1.59.2, which was +This file was extended by Snes9x $as_me 1.60, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6968,7 +6968,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Snes9x config.status 1.59.2 +Snes9x config.status 1.60 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/unix/unix.cpp b/unix/unix.cpp index bfc9bdfd..e4596cc2 100644 --- a/unix/unix.cpp +++ b/unix/unix.cpp @@ -753,8 +753,7 @@ void S9xSyncSpeed (void) #ifndef NOSOUND if (Settings.SoundSync) { - while (!S9xSyncSound()) - usleep(0); + return; } #endif @@ -1268,47 +1267,80 @@ static void ReadJoysticks (void) #endif -static void SoundTrigger (void) +void S9xSamplesAvailable(void *data) { #ifndef NOSOUND - S9xProcessSound(NULL); -#endif -} -static void InitTimer (void) -{ -#ifndef NOSOUND - struct itimerval timeout; -#endif - struct sigaction sa; + audio_buf_info info; + int samples_to_write; + int bytes_to_write; + int bytes_written; + static uint8 *sound_buffer = NULL; + static int sound_buffer_size = 0; -#ifdef USE_THREADS - if (unixSettings.ThreadSound) - { - pthread_mutex_init(&mutex, NULL); - pthread_create(&thread, NULL, S9xProcessSound, NULL); - return; - } -#endif - sa.sa_handler = (SIG_PF) SoundTrigger; + ioctl(so.sound_fd, SNDCTL_DSP_GETOSPACE, &info); -#ifdef SA_RESTART - sa.sa_flags = SA_RESTART; -#else - sa.sa_flags = 0; -#endif + if (Settings.DynamicRateControl) + { + S9xUpdateDynamicRate(info.bytes, so.fragment_size * 4); + } -#ifndef NOSOUND // FIXME: Kludge to get calltree running. Remove later. - sigemptyset(&sa.sa_mask); - sigaction(SIGALRM, &sa, NULL); + samples_to_write = S9xGetSampleCount(); - timeout.it_interval.tv_sec = 0; - timeout.it_interval.tv_usec = 10000; - timeout.it_value.tv_sec = 0; - timeout.it_value.tv_usec = 10000; - if (setitimer(ITIMER_REAL, &timeout, NULL) < 0) - perror("setitimer"); + if (Settings.DynamicRateControl && !Settings.SoundSync) + { + // Using rate control, we should always keep the emulator's sound buffers empty to + // maintain an accurate measurement. + if (samples_to_write > (info.bytes >> 1)) + { + S9xClearSamples(); + return; + } + } + + if (Settings.SoundSync && !Settings.TurboMode && !Settings.Mute) + { + while (info.bytes >> 1 < samples_to_write) + { + int usec_to_sleep = ((samples_to_write >> 1) - (info.bytes >> 2)) * 10000 / + (Settings.SoundPlaybackRate / 100); + usleep(usec_to_sleep > 0 ? usec_to_sleep : 0); + ioctl(so.sound_fd, SNDCTL_DSP_GETOSPACE, &info); + } + } + else + { + samples_to_write = MIN(info.bytes >> 1, samples_to_write) & ~1; + } + + if (samples_to_write < 0) + return; + + if (sound_buffer_size < samples_to_write * 2) + { + sound_buffer = (uint8 *)realloc(sound_buffer, samples_to_write * 2); + sound_buffer_size = samples_to_write * 2; + } + + S9xMixSamples(sound_buffer, samples_to_write); + + bytes_written = 0; + bytes_to_write = samples_to_write * 2; + + while (bytes_to_write > bytes_written) + { + int result; + + result = write(so.sound_fd, + ((char *)sound_buffer) + bytes_written, + bytes_to_write - bytes_written); + + if (result < 0) + break; + + bytes_written += result; + } #endif } @@ -1324,15 +1356,15 @@ bool8 S9xOpenSoundDevice (void) return (FALSE); } - J = log2(unixSettings.SoundFragmentSize) | (3 << 16); + J = log2(unixSettings.SoundFragmentSize) | (4 << 16); if (ioctl(so.sound_fd, SNDCTL_DSP_SETFRAGMENT, &J) == -1) return (FALSE); - J = K = Settings.SixteenBitSound ? AFMT_S16_NE : AFMT_U8; + J = K = AFMT_S16_NE; if (ioctl(so.sound_fd, SNDCTL_DSP_SETFMT, &J) == -1 || J != K) return (FALSE); - J = K = Settings.Stereo ? 1 : 0; + J = K = 1; if (ioctl(so.sound_fd, SNDCTL_DSP_STEREO, &J) == -1 || J != K) return (FALSE); @@ -1348,89 +1380,13 @@ bool8 S9xOpenSoundDevice (void) printf("fragment size: %d\n", J); #endif + S9xSetSamplesAvailableCallback(S9xSamplesAvailable, NULL); + return (TRUE); } #ifndef NOSOUND -static void * S9xProcessSound (void *) -{ - // If threads in use, this is to loop indefinitely. - // If not, this will be called by timer. - - audio_buf_info info; - if (!unixSettings.ThreadSound && (ioctl(so.sound_fd, SNDCTL_DSP_GETOSPACE, &info) == -1 || info.bytes < (int) so.fragment_size)) - return (NULL); - -#ifdef USE_THREADS - do - { -#endif - - int sample_count = so.fragment_size; - if (Settings.SixteenBitSound) - sample_count >>= 1; - -#ifdef USE_THREADS - if (unixSettings.ThreadSound) - pthread_mutex_lock(&mutex); - else -#endif - if (block_signal) - return (NULL); - - block_generate_sound = TRUE; - - if (so.samples_mixed_so_far < sample_count) - { - unsigned ofs = so.play_position + (Settings.SixteenBitSound ? (so.samples_mixed_so_far << 1) : so.samples_mixed_so_far); - S9xMixSamples(Buf + (ofs & SOUND_BUFFER_SIZE_MASK), sample_count - so.samples_mixed_so_far); - so.samples_mixed_so_far = sample_count; - } - - unsigned bytes_to_write = sample_count; - if (Settings.SixteenBitSound) - bytes_to_write <<= 1; - - unsigned byte_offset = so.play_position; - so.play_position += bytes_to_write; - so.play_position &= SOUND_BUFFER_SIZE_MASK; - -#ifdef USE_THREADS - if (unixSettings.ThreadSound) - pthread_mutex_unlock(&mutex); -#endif - - block_generate_sound = FALSE; - - for (;;) - { - int I = bytes_to_write; - if (byte_offset + I > SOUND_BUFFER_SIZE) - I = SOUND_BUFFER_SIZE - byte_offset; - if (I == 0) - break; - - I = write(so.sound_fd, (char *) Buf + byte_offset, I); - if (I > 0) - { - bytes_to_write -= I; - byte_offset += I; - byte_offset &= SOUND_BUFFER_SIZE_MASK; - } - else - if (I < 0 && errno != EINTR) - break; - } - - so.samples_mixed_so_far -= sample_count; - -#ifdef USE_THREADS - } while (unixSettings.ThreadSound); -#endif - - return (NULL); -} #endif @@ -1537,7 +1493,7 @@ int main (int argc, char **argv) exit(1); } - S9xInitSound(unixSettings.SoundBufferSize); + S9xInitSound(0); S9xSetSoundMute(TRUE); S9xReportControllers(); @@ -1714,7 +1670,6 @@ int main (int argc, char **argv) uint32 JoypadSkip = 0; #endif - InitTimer(); S9xSetSoundMute(FALSE); #ifdef NETPLAY_SUPPORT