Merge branch 'upstream' into libretro
authornotaz <notasas@gmail.com>
Sun, 25 Jan 2015 21:21:40 +0000 (23:21 +0200)
committernotaz <notasas@gmail.com>
Sun, 25 Jan 2015 21:21:40 +0000 (23:21 +0200)
38 files changed:
Makefile
Makefile.libretro
configure
frontend/libretro.c
frontend/main.c
frontend/menu.c
frontend/pandora/pcsx.pxml.templ
frontend/pandora/pcsx.sh
frontend/plugin.c
frontend/plugin_lib.c
libpcsxcore/cdriso.c
libpcsxcore/cdrom.c
libpcsxcore/memmap_win32.c
libpcsxcore/new_dynarec/emu_if.c
libpcsxcore/new_dynarec/pcsxmem.c
libpcsxcore/new_dynarec/pcsxmem.h
libpcsxcore/plugins.h
plugins/cdrcimg/cdrcimg.c
plugins/dfinput/main.c
plugins/dfsound/Makefile.c64p [new file with mode: 0644]
plugins/dfsound/adsr.c
plugins/dfsound/alsa.c
plugins/dfsound/arm_utils.S
plugins/dfsound/dma.c
plugins/dfsound/externals.h
plugins/dfsound/freeze.c
plugins/dfsound/oss.c
plugins/dfsound/registers.c
plugins/dfsound/reverb.c
plugins/dfsound/spu.c
plugins/dfsound/spu_c64x.c [new file with mode: 0644]
plugins/dfsound/spu_c64x.h [new file with mode: 0644]
plugins/dfsound/spu_c64x_dspcode.c [new file with mode: 0644]
plugins/dfsound/spu_config.h
plugins/dfsound/stdafx.h
plugins/dfsound/xa.c
plugins/gpulib/gpu.c
readme.txt

index 339fcd5..b23d33e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -83,6 +83,11 @@ plugins/dfsound/spu.o: plugins/dfsound/adsr.c plugins/dfsound/reverb.c \
 ifeq "$(ARCH)" "arm"
 OBJS += plugins/dfsound/arm_utils.o
 endif
+ifeq "$(HAVE_C64_TOOLS)" "1"
+plugins/dfsound/spu.o: CFLAGS += -DC64X_DSP
+plugins/dfsound/spu.o: plugins/dfsound/spu_c64x.c
+frontend/menu.o: CFLAGS += -DC64X_DSP
+endif
 ifneq ($(findstring oss,$(SOUND_DRIVERS)),)
 plugins/dfsound/out.o: CFLAGS += -DHAVE_OSS
 OBJS += plugins/dfsound/oss.o
@@ -288,7 +293,7 @@ endif
 ifeq "$(PLATFORM)" "pandora"
 PND_MAKE ?= $(HOME)/dev/pnd/src/pandora-libraries/testdata/scripts/pnd_make.sh
 
-rel: pcsx $(PLUGINS) \
+rel: pcsx plugins/dfsound/pcsxr_spu_area3.out $(PLUGINS) \
                frontend/pandora/pcsx.sh frontend/pandora/pcsx.pxml.templ frontend/pandora/pcsx.png \
                frontend/pandora/picorestore frontend/pandora/skin readme.txt COPYING
        rm -rf out
index ae95639..d566e23 100644 (file)
@@ -172,7 +172,9 @@ else
 endif
 
 CFLAGS += -fPIC
-ifneq ($(platform),qnx)
+ifeq ($(platform),win)
+       MAIN_LDLIBS += -lws2_32
+else ifneq ($(platform),qnx)
        LDLIBS += -lpthread
        MAIN_LDLIBS += -ldl
 endif
index e401902..4ffa3a2 100755 (executable)
--- a/configure
+++ b/configure
@@ -47,6 +47,7 @@ have_armv7=""
 have_arm_neon=""
 have_tslib=""
 have_gles=""
+have_c64x_dsp=""
 enable_dynarec="yes"
 need_sdl="no"
 need_xlib="no"
@@ -368,6 +369,16 @@ EOF
   compile_object "$@"
 }
 
+# see if we have c64_tools for TI C64x DSP
+check_c64_tools()
+{
+  cat > $TMPC <<EOF
+  #include <inc_libc64_mini.h>
+  int f() { return dsp_open(); }
+EOF
+  compile_object "$@"
+}
+
 MAIN_LDLIBS="$MAIN_LDLIBS -lz"
 check_zlib || fail "please install zlib (libz-dev)"
 
@@ -428,6 +439,9 @@ fi
 if [ -d /opt/vc/include -a -d /opt/vc/lib ]; then
   CFLAGS_GLES="$CFLAGS_GLES -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux"
   LDLIBS_GLES="$LDLIBS_GLES -L/opt/vc/lib"
+  if [ -f /opt/vc/lib/libbcm_host.so ]; then
+    LDLIBS_GLES="$LDLIBS_GLES -lbcm_host"
+  fi
   need_xlib="yes"
 fi
 
@@ -447,6 +461,10 @@ elif compile_binary $CFLAGS_GLES -lEGL -lGLESv1_CM $LDLIBS_GLES; then
   LDLIBS_GLES="-lEGL -lGLESv1_CM $LDLIBS_GLES"
 fi
 
+if check_c64_tools; then
+  have_c64x_dsp="yes"
+fi
+
 if [ "$have_gles" = "yes" ]; then
   plugins="$plugins plugins/gpu-gles/gpu_gles.so"
 fi
@@ -477,6 +495,7 @@ test "x$have_armv6" != "x" || have_armv6="no"
 test "x$have_armv7" != "x" || have_armv7="no"
 test "x$have_arm_neon" != "x" || have_arm_neon="no"
 test "x$have_gles" != "x" || have_gles="no"
+test "x$have_c64x_dsp" != "x" || have_c64x_dsp="no"
 
 echo "architecture        $ARCH"
 echo "platform            $platform"
@@ -488,8 +507,11 @@ echo "C compiler flags    $CFLAGS"
 echo "libraries           $MAIN_LDLIBS"
 echo "linker flags        $LDFLAGS$MAIN_LDFLAGS"
 echo "enable dynarec      $enable_dynarec"
-echo "ARMv7 optimizations $have_armv7"
-echo "enable ARM NEON     $have_arm_neon"
+if [ "$ARCH" = "arm" ]; then
+  echo "ARMv7 optimizations $have_armv7"
+  echo "enable ARM NEON     $have_arm_neon"
+  echo "TI C64x DSP support $have_c64x_dsp"
+fi
 echo "tslib support       $have_tslib"
 if [ "$platform" = "generic" ]; then
   echo "OpenGL ES output    $have_gles"
@@ -536,6 +558,9 @@ fi
 if [ "$drc_cache_base" = "yes" ]; then
   echo "DRC_CACHE_BASE = 1" >> $config_mak
 fi
+if [ "$have_c64x_dsp" = "yes" ]; then
+  echo "HAVE_C64_TOOLS = 1" >> $config_mak
+fi
 
 # use pandora's skin (for now)
 test -e skin || ln -s frontend/pandora/skin skin
index b636f49..38514b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) notaz, 2012
+ * (C) notaz, 2012,2014,2015
  *
  * This work is licensed under the terms of the GNU GPLv2 or later.
  * See the COPYING file in the top-level directory.
@@ -283,7 +283,7 @@ void retro_get_system_info(struct retro_system_info *info)
 {
        memset(info, 0, sizeof(*info));
        info->library_name = "PCSX-ReARMed";
-       info->library_version = "r20";
+       info->library_version = "r21";
        info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u";
        info->need_fullpath = true;
 }
@@ -602,7 +602,7 @@ static void extract_directory(char *buf, const char *path, size_t size)
    }
 }
 
-#ifdef __QNX__
+#if defined(__QNX__) || defined(_WIN32)
 /* Blackberry QNX doesn't have strcasestr */
 
 /*
index 426ef13..4c84803 100644 (file)
@@ -8,12 +8,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
-#include <dlfcn.h>
-#include <sys/stat.h>
-#include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
 #include <time.h>
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
 
 #include "main.h"
 #include "plugin.h"
@@ -141,7 +141,8 @@ void emu_set_default_config(void)
        spu_config.iXAPitch = 0;
        spu_config.iVolume = 768;
        spu_config.iTempo = 0;
-#if defined(__arm__) && !defined(__ARM_ARCH_7A__) /* XXX */
+       spu_config.iUseThread = 1; // no effect if only 1 core is detected
+#if defined(__arm__) && !defined(__ARM_ARCH_7A__) /* XXX GPH hack */
        spu_config.iUseReverb = 0;
        spu_config.iUseInterpolation = 0;
        spu_config.iTempo = 1;
@@ -452,6 +453,10 @@ void emu_core_ask_exit(void)
 }
 
 #ifndef NO_FRONTEND
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
 static void create_profile_dir(const char *directory) {
        char path[MAXPATHLEN];
 
@@ -766,7 +771,7 @@ int emu_save_state(int slot)
                return ret;
 
        ret = SaveState(fname);
-#ifndef __ARM_ARCH_7A__ /* XXX */
+#if defined(__arm__) && !defined(__ARM_ARCH_7A__) /* XXX GPH hack */
        sync();
 #endif
        SysPrintf("* %s \"%s\" [%d]\n",
@@ -968,7 +973,7 @@ static const int builtin_plugin_ids[] = {
 
 void *SysLoadLibrary(const char *lib) {
        const char *tmp = strrchr(lib, '/');
-       void *ret;
+       void *ret = NULL;
        int i;
 
        SysPrintf("plugin: %s\n", lib);
@@ -980,9 +985,14 @@ void *SysLoadLibrary(const char *lib) {
                                return (void *)(long)(PLUGIN_DL_BASE + builtin_plugin_ids[i]);
        }
 
+#ifndef _WIN32
        ret = dlopen(lib, RTLD_NOW);
        if (ret == NULL)
                SysMessage("dlopen: %s", dlerror());
+#else
+       /* no external plugin support, abi is no longer
+        * compatible with psemu/pcsx anyway */
+#endif
        return ret;
 }
 
@@ -992,11 +1002,19 @@ void *SysLoadSym(void *lib, const char *sym) {
        if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
                return plugin_link(plugid - PLUGIN_DL_BASE, sym);
 
+#ifndef _WIN32
        return dlsym(lib, sym);
+#else
+       return NULL;
+#endif
 }
 
 const char *SysLibError() {
+#ifndef _WIN32
        return dlerror();
+#else
+       return "not supported";
+#endif
 }
 
 void SysCloseLibrary(void *lib) {
@@ -1005,6 +1023,8 @@ void SysCloseLibrary(void *lib) {
        if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
                return;
 
+#ifndef _WIN32
        dlclose(lib);
+#endif
 }
 
index a7012e6..0088a63 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) GraÅžvydas "notaz" Ignotas, 2010-2014
+ * (C) GraÅžvydas "notaz" Ignotas, 2010-2015
  *
  * This work is licensed under the terms of any of these licenses
  * (at your option):
@@ -75,6 +75,7 @@ typedef enum
        MA_OPT_SAVECFG,
        MA_OPT_SAVECFG_GAME,
        MA_OPT_CPU_CLOCKS,
+       MA_OPT_SPU_THREAD,
        MA_OPT_DISP_OPTS,
        MA_OPT_VARSCALER,
        MA_OPT_VARSCALER_C,
@@ -444,6 +445,7 @@ static const struct {
        CE_INTVAL(spu_config.iXAPitch),
        CE_INTVAL(spu_config.iUseInterpolation),
        CE_INTVAL(spu_config.iTempo),
+       CE_INTVAL(spu_config.iUseThread),
        CE_INTVAL(config_save_counter),
        CE_INTVAL(in_evdev_allow_abs_only),
        CE_INTVAL(volume_boost),
@@ -1604,6 +1606,11 @@ static menu_entry e_menu_options[] =
        mee_onoff     ("Show FPS",                 0, g_opts, OPT_SHOWFPS),
        mee_enum      ("Region",                   0, region, men_region),
        mee_range     ("CPU clock",                MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
+#ifdef C64X_DSP
+       mee_onoff     ("Use C64x DSP for sound",   MA_OPT_SPU_THREAD, spu_config.iUseThread, 1),
+#else
+       mee_onoff     ("Threaded SPU",             MA_OPT_SPU_THREAD, spu_config.iUseThread, 1),
+#endif
        mee_handler_id("[Display]",                MA_OPT_DISP_OPTS, menu_loop_gfx_options),
        mee_handler   ("[BIOS/Plugins]",           menu_loop_plugin_options),
        mee_handler   ("[Advanced]",               menu_loop_adv_options),
@@ -1616,10 +1623,9 @@ static menu_entry e_menu_options[] =
 static int menu_loop_options(int id, int keys)
 {
        static int sel = 0;
-       int i;
 
-       i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
-       e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
+       me_enable(e_menu_options, MA_OPT_CPU_CLOCKS, cpu_clock_st > 0);
+       me_enable(e_menu_options, MA_OPT_SPU_THREAD, spu_config.iThreadAvail);
        me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
 
        me_loop(e_menu_options, &sel);
@@ -1928,7 +1934,7 @@ static const char credits_text[] =
        "PCSX4ALL plugin by PCSX4ALL team\n"
        "  Chui, Franxis, Unai\n\n"
        "integration, optimization and\n"
-       "  frontend (C) 2010-2014 notaz\n";
+       "  frontend (C) 2010-2015 notaz\n";
 
 static int reset_game(void)
 {
index 7ae3c6c..f748065 100644 (file)
@@ -4,7 +4,7 @@
   <titles>
     <title lang="en_US">PCSX ReARMed</title>
   </titles>
-  <version major="1" minor="9" release="92" build="%PR%"/>
+  <version major="1" minor="9" release="93" build="%PR%"/>
   <author name="PCSX team/notaz" website="http://notaz.gp2x.de/"/>
 </package>
 <application id="pcsx_rearmed.notaz.%PR%" appdata="pcsx_rearmed">
@@ -25,7 +25,7 @@ The emulator features MIPS->ARM recompiler by Ari64 and ARM NEON GPU by Exophase
 
   <author name="PCSX team/notaz" website="http://notaz.gp2x.de/"/>
 
-  <version major="1" minor="9" release="92" build="%PR%"/>
+  <version major="1" minor="9" release="93" build="%PR%"/>
 
   <licenses>
     <license name="GPLv2+" url="http://www.gnu.org/licenses/gpl-2.0.html" sourcecodeurl="http://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git"/>
index a69ca31..710f641 100755 (executable)
@@ -10,6 +10,9 @@ nub1mode=`cat /proc/pandora/nub1/mode`
 # no big deal if this fails, only performance loss
 sudo -n /usr/pandora/scripts/op_hugetlb.sh 24
 
+# C64x DSP for SPU
+sudo -n /usr/pandora/scripts/op_dsp_c64.sh
+
 ./pcsx "$@"
 
 # restore stuff if pcsx crashes
index cf3d575..d9eb04a 100644 (file)
 #include "../libpcsxcore/system.h"
 #include "../plugins/cdrcimg/cdrcimg.h"
 
+#ifndef _WIN32
+#define CALLBACK
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
 static int dummy_func() {
        return 0;
 }
 
 /* SPU */
-extern long SPUopen(void);
-extern long SPUinit(void);
-extern long SPUshutdown(void);
-extern long SPUclose(void);
-extern void SPUplaySample(unsigned char);
-extern void SPUwriteRegister(unsigned long, unsigned short, unsigned int);
-extern unsigned short SPUreadRegister(unsigned long);
-extern void SPUwriteDMA(unsigned short);
-extern unsigned short SPUreadDMA(void);
-extern void SPUwriteDMAMem(unsigned short *, int, unsigned int);
-extern void SPUreadDMAMem(unsigned short *, int, unsigned int);
-extern void SPUplayADPCMchannel(void *);
-extern void SPUregisterCallback(void (*cb)(void));
-extern void SPUregisterScheduleCb(void (*cb)(unsigned int));
-extern long SPUconfigure(void);
-extern long SPUtest(void);
-extern void SPUabout(void);
-extern long SPUfreeze(unsigned int, void *, unsigned int);
-extern void SPUasync(unsigned int, unsigned int);
-extern int  SPUplayCDDAchannel(short *, int);
+extern long CALLBACK SPUopen(void);
+extern long CALLBACK SPUinit(void);
+extern long CALLBACK SPUshutdown(void);
+extern long CALLBACK SPUclose(void);
+extern void CALLBACK SPUplaySample(unsigned char);
+extern void CALLBACK SPUwriteRegister(unsigned long, unsigned short, unsigned int);
+extern unsigned short CALLBACK SPUreadRegister(unsigned long);
+extern void CALLBACK SPUwriteDMA(unsigned short);
+extern unsigned short CALLBACK SPUreadDMA(void);
+extern void CALLBACK SPUwriteDMAMem(unsigned short *, int, unsigned int);
+extern void CALLBACK SPUreadDMAMem(unsigned short *, int, unsigned int);
+extern void CALLBACK SPUplayADPCMchannel(void *);
+extern void CALLBACK SPUregisterCallback(void (*cb)(void));
+extern void CALLBACK SPUregisterScheduleCb(void (*cb)(unsigned int));
+extern long CALLBACK SPUconfigure(void);
+extern long CALLBACK SPUtest(void);
+extern void CALLBACK SPUabout(void);
+extern long CALLBACK SPUfreeze(unsigned int, void *, unsigned int);
+extern void CALLBACK SPUasync(unsigned int, unsigned int);
+extern int  CALLBACK SPUplayCDDAchannel(short *, int);
 
 /* PAD */
 static long PADreadPort1(PadDataS *pad)
index 163d4f1..56da763 100644 (file)
@@ -44,7 +44,7 @@ void *tsdev;
 void *pl_vout_buf;
 int g_layer_x, g_layer_y, g_layer_w, g_layer_h;
 static int pl_vout_w, pl_vout_h, pl_vout_bpp; /* output display/layer */
-static int pl_vout_scale, pl_vout_yoffset;
+static int pl_vout_scale_w, pl_vout_scale_h, pl_vout_yoffset;
 static int psx_w, psx_h, psx_bpp;
 static int vsync_cnt;
 static int is_pal, frame_interval, frame_interval1024;
@@ -230,7 +230,7 @@ static void update_layer_size(int w, int h)
 }
 
 // XXX: this is platform specific really
-static int resolution_ok(int w, int h)
+static inline int resolution_ok(int w, int h)
 {
        return w <= 1024 && h <= 512;
 }
@@ -261,20 +261,25 @@ static void pl_vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp)
                vout_h = 192;
        }
 
-       pl_vout_scale = 1;
+       pl_vout_scale_w = pl_vout_scale_h = 1;
 #ifdef __ARM_NEON__
        if (soft_filter) {
                if (resolution_ok(w * 2, h * 2) && bpp == 16) {
-                       vout_w *= 2;
-                       vout_h *= 2;
-                       pl_vout_scale = 2;
+                       pl_vout_scale_w = 2;
+                       pl_vout_scale_h = 2;
                }
                else {
                        // filter unavailable
                        hud_msg[0] = 0;
                }
        }
+       else if (scanlines != 0 && scanline_level != 100 && bpp == 16) {
+               if (h <= 256)
+                       pl_vout_scale_h = 2;
+       }
 #endif
+       vout_w *= pl_vout_scale_w;
+       vout_h *= pl_vout_scale_h;
 
        update_layer_size(vout_w, vout_h);
 
@@ -316,7 +321,7 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h)
        }
 
        // borders
-       doffs = (dstride - w * pl_vout_scale) / 2 & ~1;
+       doffs = (dstride - w * pl_vout_scale_w) / 2 & ~1;
 
        if (doffs > doffs_old)
                clear_counter = 2;
@@ -361,12 +366,12 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h)
                }
        }
 #ifdef __ARM_NEON__
-       else if (soft_filter == SOFT_FILTER_SCALE2X && pl_vout_scale == 2)
+       else if (soft_filter == SOFT_FILTER_SCALE2X && pl_vout_scale_w == 2)
        {
                neon_scale2x_16_16(src, (void *)dest, w,
                        stride * 2, dstride * 2, h);
        }
-       else if (soft_filter == SOFT_FILTER_EAGLE2X && pl_vout_scale == 2)
+       else if (soft_filter == SOFT_FILTER_EAGLE2X && pl_vout_scale_w == 2)
        {
                neon_eagle2x_16_16(src, (void *)dest, w,
                        stride * 2, dstride * 2, h);
@@ -374,11 +379,13 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h)
        else if (scanlines != 0 && scanline_level != 100)
        {
                int l = scanline_level * 2048 / 100;
+               int stride_0 = pl_vout_scale_h >= 2 ? 0 : stride;
 
+               h1 *= pl_vout_scale_h;
                for (; h1 >= 2; h1 -= 2)
                {
                        bgr555_to_rgb565(dest, src, w * 2);
-                       dest += dstride * 2, src += stride;
+                       dest += dstride * 2, src += stride_0;
 
                        bgr555_to_rgb565_b(dest, src, w * 2, l);
                        dest += dstride * 2, src += stride;
@@ -394,7 +401,7 @@ static void pl_vout_flip(const void *vram, int stride, int bgr24, int w, int h)
        }
 
 out_hud:
-       print_hud(w * pl_vout_scale, h * pl_vout_scale, 0);
+       print_hud(w * pl_vout_scale_w, h * pl_vout_scale_h, 0);
 
 out:
        pcnt_end(PCNT_BLIT);
@@ -457,7 +464,8 @@ static int dispmode_default(void)
        return 1;
 }
 
-int dispmode_doubleres(void)
+#ifdef __ARM_NEON__
+static int dispmode_doubleres(void)
 {
        if (!(pl_rearmed_cbs.gpu_caps & GPU_CAP_SUPPORTS_2X)
            || !resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
@@ -469,7 +477,7 @@ int dispmode_doubleres(void)
        return 1;
 }
 
-int dispmode_scale2x(void)
+static int dispmode_scale2x(void)
 {
        if (!resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
                return 0;
@@ -480,7 +488,7 @@ int dispmode_scale2x(void)
        return 1;
 }
 
-int dispmode_eagle2x(void)
+static int dispmode_eagle2x(void)
 {
        if (!resolution_ok(psx_w * 2, psx_h * 2) || psx_bpp != 16)
                return 0;
@@ -490,6 +498,7 @@ int dispmode_eagle2x(void)
        snprintf(hud_msg, sizeof(hud_msg), "eagle2x");
        return 1;
 }
+#endif
 
 static int (*dispmode_switchers[])(void) = {
        dispmode_default,
index b733f5b..09aed17 100644 (file)
 #include "ppf.h"
 
 #ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
 #include <process.h>
 #include <windows.h>
 #define strcasecmp _stricmp
+#define usleep(x) Sleep((x) / 1000)
 #else
 #include <pthread.h>
 #include <sys/time.h>
index b686855..3a2eb1f 100644 (file)
@@ -126,7 +126,7 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
 #define STATUS_ERROR     (1<<0) // 0x01
 
 /* Errors */
-#define ERROR_NOT_READY  (1<<7) // 0x80
+#define ERROR_NOTREADY   (1<<7) // 0x80
 #define ERROR_INVALIDCMD (1<<6) // 0x40
 #define ERROR_INVALIDARG (1<<5) // 0x20
 
@@ -984,7 +984,7 @@ void cdrInterrupt() {
                case DRIVESTATE_PREPARE_CD:
                        SetResultSize(2);
                        cdr.Result[0] = cdr.StatP | STATUS_ERROR;
-                       cdr.Result[1] = ERROR_NOT_READY;
+                       cdr.Result[1] = ERROR_NOTREADY;
                        cdr.Stat = DiskError;
                        break;
                }
index f4dbdd6..294f058 100644 (file)
@@ -2,7 +2,7 @@
 #include <errno.h>
 #include <io.h>
 
-#include "mman.h"
+#include "memmap.h"
 
 #ifndef FILE_MAP_EXECUTE
 #define FILE_MAP_EXECUTE    0x0020
index b7a2489..092c8ae 100644 (file)
@@ -305,7 +305,7 @@ static int ari64_init()
 {
        extern void (*psxCP2[64])();
        extern void psxNULL();
-       extern u_char *out;
+       extern unsigned char *out;
        size_t i;
 
        new_dynarec_init();
@@ -438,7 +438,7 @@ int new_dynarec_hacks;
 void *psxH_ptr;
 void *zeromem_ptr;
 u8 zero_mem[0x1000];
-u_char *out;
+unsigned char *out;
 void *mem_rtab;
 void *scratch_buf_ptr;
 void new_dynarec_init() { (void)ari64_execute; }
index d5c32be..9376ff4 100644 (file)
@@ -292,7 +292,7 @@ void new_dyna_pcsx_mem_load_state(void)
        map_rcnt_rcount2(rcnts[2].mode);
 }
 
-int pcsxmem_is_handler_dynamic(u_int addr)
+int pcsxmem_is_handler_dynamic(unsigned int addr)
 {
        if ((addr & 0xfffff000) != 0x1f801000)
                return 0;
index 99bb5d4..72892a8 100644 (file)
@@ -6,4 +6,4 @@ void new_dyna_pcsx_mem_reset(void);
 void new_dyna_pcsx_mem_load_state(void);
 void new_dyna_pcsx_mem_shutdown(void);
 
-int pcsxmem_is_handler_dynamic(u_int addr);
+int pcsxmem_is_handler_dynamic(unsigned int addr);
index e6ac694..132df90 100644 (file)
@@ -33,24 +33,19 @@ extern "C" {
 typedef void* HWND;\r
 #define CALLBACK\r
 \r
-typedef long (*GPUopen)(unsigned long *, char *, char *);\r
-typedef long (*SPUopen)(void);\r
-typedef long (*PADopen)(unsigned long *);\r
-typedef long (*NETopen)(unsigned long *);\r
-typedef long (*SIO1open)(unsigned long *);\r
-\r
 #else\r
 \r
+#define WIN32_LEAN_AND_MEAN\r
 #include <windows.h>\r
 \r
-typedef long (CALLBACK* GPUopen)(HWND);\r
-typedef long (CALLBACK* SPUopen)(HWND);\r
-typedef long (CALLBACK* PADopen)(HWND);\r
-typedef long (CALLBACK* NETopen)(HWND);\r
-typedef long (CALLBACK* SIO1open)(HWND);\r
-\r
 #endif\r
 \r
+typedef long (CALLBACK *GPUopen)(unsigned long *, char *, char *);\r
+typedef long (CALLBACK *SPUopen)(void);\r
+typedef long (CALLBACK *PADopen)(unsigned long *);\r
+typedef long (CALLBACK *NETopen)(unsigned long *);\r
+typedef long (CALLBACK *SIO1open)(unsigned long *);\r
+\r
 #include "spu.h"\r
 \r
 #include "psemu_plugin_defs.h"\r
index 0ec14db..76cdfba 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <zlib.h>
+#ifndef _WIN32
+#define CALLBACK
 #include <dlfcn.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
 
 #include "cdrcimg.h"
 
@@ -44,7 +50,7 @@ static struct {
 static int current_block, current_sect_in_blk;
 
 struct CdrStat;
-extern long CDR__getStatus(struct CdrStat *stat);
+extern long CALLBACK CDR__getStatus(struct CdrStat *stat);
 
 struct CdrStat
 {
@@ -279,6 +285,7 @@ static long CDRinit(void)
                        return -1;
                }
        }
+#ifndef _WIN32
        if (pBZ2_bzBuffToBuffDecompress == NULL) {
                void *h = dlopen("/usr/lib/libbz2.so.1", RTLD_LAZY);
                if (h == NULL)
@@ -291,6 +298,7 @@ static long CDRinit(void)
                        }
                }
        }
+#endif
        return 0;
 }
 
index 73b2bda..475ea07 100644 (file)
@@ -8,6 +8,13 @@
  * See the COPYING file in the top-level directory.
  */
 
+#ifndef _WIN32
+#define CALLBACK
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
 #include "main.h"
 
 unsigned char CurPad, CurByte, CurCmd, CmdLen;
@@ -15,10 +22,10 @@ unsigned char CurPad, CurByte, CurCmd, CmdLen;
 /* since this is not a proper plugin, so we'll hook emu internals in a hackish way like this */
 extern void *PAD1_startPoll, *PAD1_poll;
 extern void *PAD2_startPoll, *PAD2_poll;
-extern unsigned char PAD1__startPoll(int pad);
-extern unsigned char PAD2__startPoll(int pad);
-extern unsigned char PAD1__poll(unsigned char value);
-extern unsigned char PAD2__poll(unsigned char value);
+extern unsigned char CALLBACK PAD1__startPoll(int pad);
+extern unsigned char CALLBACK PAD2__startPoll(int pad);
+extern unsigned char CALLBACK PAD1__poll(unsigned char value);
+extern unsigned char CALLBACK PAD2__poll(unsigned char value);
 
 static int old_controller_type1 = -1, old_controller_type2 = -1;
 
diff --git a/plugins/dfsound/Makefile.c64p b/plugins/dfsound/Makefile.c64p
new file mode 100644 (file)
index 0000000..45fe76a
--- /dev/null
@@ -0,0 +1,15 @@
+ifndef C64_TOOLS_DSP_ROOT
+$(error need C64_TOOLS_DSP_ROOT)
+endif
+
+include $(C64_TOOLS_DSP_ROOT)/install.mk
+
+TARGET_BASENAME = pcsxr_spu
+OPTFLAGS += -O2
+CFLAGS += -DNO_OS -DWANT_THREAD_CODE
+
+OBJ = \
+       spu_c64x_dspcode.o64
+
+include $(C64_TOOLS_DSP_ROOT)/build_area3.mk
+include $(C64_TOOLS_DSP_ROOT)/build.mk
index c1e98b3..9e32862 100644 (file)
@@ -57,22 +57,22 @@ void InitADSR(void)                                    // INIT ADSR
 \r
 INLINE void StartADSR(int ch)                          // MIX ADSR\r
 {\r
- s_chan[ch].ADSRX.State=0;                             // and init some adsr vars\r
- s_chan[ch].ADSRX.EnvelopeVol=0;\r
+ spu.s_chan[ch].ADSRX.State = ADSR_ATTACK;             // and init some adsr vars\r
+ spu.s_chan[ch].ADSRX.EnvelopeVol = 0;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR\r
+static int MixADSR(ADSRInfoEx *adsr, int ns_to)\r
 {\r
- int EnvelopeVol = s_chan[ch].ADSRX.EnvelopeVol;\r
- int val, rto, level;\r
+ int EnvelopeVol = adsr->EnvelopeVol;\r
+ int ns = 0, val, rto, level;\r
 \r
- if (s_chan[ch].bStop)                                 // should be stopped:\r
- {                                                     // do release\r
-   val = RateTableSub[s_chan[ch].ADSRX.ReleaseRate * 4];\r
+ if (adsr->State == ADSR_RELEASE)\r
+ {\r
+   val = RateTableSub[adsr->ReleaseRate * 4];\r
 \r
-   if (s_chan[ch].ADSRX.ReleaseModeExp)\r
+   if (adsr->ReleaseModeExp)\r
    {\r
      for (; ns < ns_to; ns++)\r
      {\r
@@ -97,19 +97,16 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
      }\r
    }\r
 \r
-   if (EnvelopeVol <= 0)\r
-     goto stop;\r
-\r
    goto done;\r
  }\r
 \r
- switch (s_chan[ch].ADSRX.State)\r
+ switch (adsr->State)\r
  {\r
-   case 0:                                             // -> attack\r
+   case ADSR_ATTACK:                                   // -> attack\r
      rto = 0;\r
-     if (s_chan[ch].ADSRX.AttackModeExp && EnvelopeVol >= 0x60000000)\r
+     if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000)\r
        rto = 8;\r
-     val = RateTableAdd[s_chan[ch].ADSRX.AttackRate + rto];\r
+     val = RateTableAdd[adsr->AttackRate + rto];\r
 \r
      for (; ns < ns_to; ns++)\r
      {\r
@@ -124,7 +121,7 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
      if (EnvelopeVol < 0) // overflow\r
      {\r
        EnvelopeVol = 0x7fffffff;\r
-       s_chan[ch].ADSRX.State = 1;\r
+       adsr->State = ADSR_DECAY;\r
        ns++; // sample is good already\r
        goto decay;\r
      }\r
@@ -132,9 +129,9 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
 \r
    //--------------------------------------------------//\r
    decay:\r
-   case 1:                                             // -> decay\r
-     val = RateTableSub[s_chan[ch].ADSRX.DecayRate * 4];\r
-     level = s_chan[ch].ADSRX.SustainLevel;\r
+   case ADSR_DECAY:                                    // -> decay\r
+     val = RateTableSub[adsr->DecayRate * 4];\r
+     level = adsr->SustainLevel;\r
 \r
      for (; ns < ns_to; )\r
      {\r
@@ -148,7 +145,7 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
 \r
        if (((EnvelopeVol >> 27) & 0xf) <= level)\r
        {\r
-         s_chan[ch].ADSRX.State = 2;\r
+         adsr->State = ADSR_SUSTAIN;\r
          goto sustain;\r
        }\r
      }\r
@@ -156,16 +153,19 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
 \r
    //--------------------------------------------------//\r
    sustain:\r
-   case 2:                                             // -> sustain\r
-     if (s_chan[ch].ADSRX.SustainIncrease)\r
+   case ADSR_SUSTAIN:                                  // -> sustain\r
+     if (adsr->SustainIncrease)\r
      {\r
        if (EnvelopeVol >= 0x7fff0000)\r
+       {\r
+         ns = ns_to;\r
          break;\r
+       }\r
 \r
        rto = 0;\r
-       if (s_chan[ch].ADSRX.SustainModeExp && EnvelopeVol >= 0x60000000)\r
+       if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000)\r
          rto = 8;\r
-       val = RateTableAdd[s_chan[ch].ADSRX.SustainRate + rto];\r
+       val = RateTableAdd[adsr->SustainRate + rto];\r
 \r
        for (; ns < ns_to; ns++)\r
        {\r
@@ -173,6 +173,7 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
          if ((unsigned int)EnvelopeVol >= 0x7fe00000)\r
          {\r
            EnvelopeVol = 0x7fffffff;\r
+           ns = ns_to;\r
            break;\r
          }\r
 \r
@@ -182,14 +183,14 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
      }\r
      else\r
      {\r
-       val = RateTableSub[s_chan[ch].ADSRX.SustainRate];\r
-       if (s_chan[ch].ADSRX.SustainModeExp)\r
+       val = RateTableSub[adsr->SustainRate];\r
+       if (adsr->SustainModeExp)\r
        {\r
          for (; ns < ns_to; ns++)\r
          {\r
            EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
            if (EnvelopeVol < 0) \r
-             goto stop;\r
+             break;\r
 \r
            ChanBuf[ns] *= EnvelopeVol >> 21;\r
            ChanBuf[ns] >>= 10;\r
@@ -201,7 +202,7 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
          {\r
            EnvelopeVol += val;\r
            if (EnvelopeVol < 0) \r
-             goto stop;\r
+             break;\r
 \r
            ChanBuf[ns] *= EnvelopeVol >> 21;\r
            ChanBuf[ns] >>= 10;\r
@@ -212,13 +213,135 @@ static void MixADSR(int ch, int ns, int ns_to)         // MIX ADSR
  }\r
 \r
 done:\r
- s_chan[ch].ADSRX.EnvelopeVol = EnvelopeVol;\r
- return;\r
+ adsr->EnvelopeVol = EnvelopeVol;\r
+ return ns;\r
+}\r
+\r
+static int SkipADSR(ADSRInfoEx *adsr, int ns_to)\r
+{\r
+ int EnvelopeVol = adsr->EnvelopeVol;\r
+ int ns = 0, val, rto, level;\r
+ int64_t v64;\r
+\r
+ if (adsr->State == ADSR_RELEASE)\r
+ {\r
+   val = RateTableSub[adsr->ReleaseRate * 4];\r
+   if (adsr->ReleaseModeExp)\r
+   {\r
+     for (; ns < ns_to; ns++)\r
+     {\r
+       EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
+       if (EnvelopeVol <= 0)\r
+         break;\r
+     }\r
+   }\r
+   else\r
+   {\r
+     v64 = EnvelopeVol;\r
+     v64 += (int64_t)val * ns_to;\r
+     EnvelopeVol = (int)v64;\r
+     if (v64 > 0)\r
+       ns = ns_to;\r
+   }\r
+   goto done;\r
+ }\r
+\r
+ switch (adsr->State)\r
+ {\r
+   case ADSR_ATTACK:                                   // -> attack\r
+     rto = 0;\r
+     if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000)\r
+       rto = 8;\r
+     val = RateTableAdd[adsr->AttackRate + rto];\r
+\r
+     for (; ns < ns_to; ns++)\r
+     {\r
+       EnvelopeVol += val;\r
+       if (EnvelopeVol < 0)\r
+        break;\r
+     }\r
+     if (EnvelopeVol < 0) // overflow\r
+     {\r
+       EnvelopeVol = 0x7fffffff;\r
+       adsr->State = ADSR_DECAY;\r
+       ns++;\r
+       goto decay;\r
+     }\r
+     break;\r
+\r
+   //--------------------------------------------------//\r
+   decay:\r
+   case ADSR_DECAY:                                    // -> decay\r
+     val = RateTableSub[adsr->DecayRate * 4];\r
+     level = adsr->SustainLevel;\r
+\r
+     for (; ns < ns_to; )\r
+     {\r
+       EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
+       if (EnvelopeVol < 0)\r
+         EnvelopeVol = 0;\r
+\r
+       ns++;\r
+\r
+       if (((EnvelopeVol >> 27) & 0xf) <= level)\r
+       {\r
+         adsr->State = ADSR_SUSTAIN;\r
+         goto sustain;\r
+       }\r
+     }\r
+     break;\r
+\r
+   //--------------------------------------------------//\r
+   sustain:\r
+   case ADSR_SUSTAIN:                                  // -> sustain\r
+     if (adsr->SustainIncrease)\r
+     {\r
+       ns = ns_to;\r
+\r
+       if (EnvelopeVol >= 0x7fff0000)\r
+         break;\r
+\r
+       rto = 0;\r
+       if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000)\r
+         rto = 8;\r
+       val = RateTableAdd[adsr->SustainRate + rto];\r
+\r
+       v64 = EnvelopeVol;\r
+       v64 += (int64_t)val * (ns_to - ns);\r
+       EnvelopeVol = (int)v64;\r
+       if (v64 >= 0x7fe00000ll)\r
+         EnvelopeVol = 0x7fffffff;\r
+     }\r
+     else\r
+     {\r
+       val = RateTableSub[adsr->SustainRate];\r
+       if (adsr->SustainModeExp)\r
+       {\r
+         for (; ns < ns_to; ns++)\r
+         {\r
+           EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
+           if (EnvelopeVol < 0)\r
+             break;\r
+         }\r
+       }\r
+       else\r
+       {\r
+         v64 = EnvelopeVol;\r
+         v64 += (int64_t)val * (ns_to - ns);\r
+         EnvelopeVol = (int)v64;\r
+         if (v64 > 0)\r
+         {\r
+           ns = ns_to;\r
+           break;\r
+         }\r
+       }\r
+     }\r
+     break;\r
+ }\r
 \r
-stop:\r
- memset(&ChanBuf[ns], 0, (ns_to - ns) * sizeof(ChanBuf[0]));\r
- s_chan[ch].ADSRX.EnvelopeVol = 0;\r
- spu.dwChannelOn &= ~(1<<ch);\r
+done:\r
+ adsr->EnvelopeVol = EnvelopeVol;\r
+ return ns;\r
 }\r
 \r
 #endif\r
index b5655a9..6b9f83e 100644 (file)
@@ -195,8 +195,21 @@ static void alsa_feed(void *pSound, int lBytes)
    snd_pcm_prepare(handle);
    snd_pcm_writei(handle, sbuf, sizeof(sbuf) / 4);
    snd_pcm_writei(handle, sbuf, sizeof(sbuf) / 4);
+   snd_pcm_writei(handle, sbuf, sizeof(sbuf) / 4);
+  }
+ else
+  {
+   int l = snd_pcm_avail(handle);
+   if (l < lBytes / 4)
+    {
+     if (l == 0)
+      return;
+
+     lBytes = l * 4;
+    }
   }
- snd_pcm_writei(handle,pSound, lBytes / 4);
+
+ snd_pcm_writei(handle, pSound, lBytes / 4);
 }
 
 void out_register_alsa(struct out_driver *drv)
index 1726389..9652313 100644 (file)
@@ -14,7 +14,6 @@
 .data
 .align 2
 ptr_ChanBuf:   .word ESYM(ChanBuf)
-ptr_SSumLR:    .word ESYM(SSumLR)
 #endif
 
 .text
@@ -36,14 +35,11 @@ ptr_SSumLR:    .word ESYM(SSumLR)
 
 #ifdef __ARM_NEON__
 
-FUNCTION(mix_chan): @ (int start, int count, int lv, int rv)
+FUNCTION(mix_chan): @ (int *SSumLR, int count, int lv, int rv)
     vmov.32     d14[0], r2
     vmov.32     d14[1], r3             @ multipliers
-    mov         r12, r0
+    mov         r2, r0
     load_varadr r0, ChanBuf
-    load_varadr r2, SSumLR
-    add         r0, r12, lsl #2
-    add         r2, r12, lsl #3
 0:
     vldmia      r0!, {d0-d1}
     vldmia      r2, {d2-d5}
@@ -69,16 +65,12 @@ mc_finish:
     bx          lr
 
 
-FUNCTION(mix_chan_rvb): @ (int start, int count, int lv, int rv, int *rvb)
+FUNCTION(mix_chan_rvb): @ (int *SSumLR, int count, int lv, int rv, int *rvb)
     vmov.32     d14[0], r2
     vmov.32     d14[1], r3             @ multipliers
-    mov         r12, r0
+    mov         r2, r0
     load_varadr r0, ChanBuf
     ldr         r3, [sp]               @ rvb
-    load_varadr r2, SSumLR
-    add         r0, r12, lsl #2
-    add         r2, r12, lsl #3
-    add         r3, r12, lsl #3
 0:
     vldmia      r0!, {d0-d1}
     vldmia      r2, {d2-d5}
@@ -112,15 +104,12 @@ mcr_finish:
 
 #elif defined(HAVE_ARMV5)
 
-FUNCTION(mix_chan): @ (int start, int count, int lv, int rv)
+FUNCTION(mix_chan): @ (int *SSumLR, int count, int lv, int rv)
     stmfd       sp!, {r4-r8,lr}
     orr         r3, r2, r3, lsl #16
     lsl         r3, #1                 @ packed multipliers << 1
-    mov         r12, r0
+    mov         r2, r0
     load_varadr r0, ChanBuf
-    load_varadr r2, SSumLR
-    add         r0, r12, lsl #2
-    add         r2, r12, lsl #3
 0:
     ldmia       r0!, {r4,r5}
     ldmia       r2, {r6-r8,lr}
@@ -141,16 +130,13 @@ mc_finish:
     ldmfd       sp!, {r4-r8,pc}
 
 
-FUNCTION(mix_chan_rvb): @ (int start, int count, int lv, int rv, int *rvb)
+FUNCTION(mix_chan_rvb): @ (int *SSumLR, int count, int lv, int rv, int *rvb)
     stmfd       sp!, {r4-r8,lr}
     orr         lr, r2, r3, lsl #16
     lsl         lr, #1
-    ldr         r3, [sp]               @ rvb
-    load_varadr r2, SSumLR
-    load_varadr r4, ChanBuf
-    add         r2, r2, r0, lsl #3
-    add         r3, r3, r0, lsl #3
-    add         r0, r4, r0, lsl #2
+    mov         r2, r0
+    load_varadr r0, ChanBuf
+    ldr         r3, [sp, #6*4]         @ rvb
 0:
     ldr         r4, [r0], #4
     ldmia       r2, {r6,r7}
index d3706b9..4798a19 100644 (file)
@@ -27,9 +27,9 @@
 \r
 unsigned short CALLBACK SPUreadDMA(void)\r
 {\r
- unsigned short s=spu.spuMem[spu.spuAddr>>1];\r
- spu.spuAddr+=2;\r
if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
+ unsigned short s = *(unsigned short *)(spu.spuMemC + spu.spuAddr);\r
+ spu.spuAddr += 2;\r
spu.spuAddr &= 0x7fffe;\r
 \r
  return s;\r
 }\r
@@ -43,13 +43,13 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize,
 {\r
  int i;\r
 \r
- do_samples_if_needed(cycles);\r
+ do_samples_if_needed(cycles, 1);\r
 \r
  for(i=0;i<iSize;i++)\r
   {\r
-   *pusPSXMem++=spu.spuMem[spu.spuAddr>>1];            // spu addr got by writeregister\r
-   spu.spuAddr+=2;                                     // inc spu addr\r
-   if(spu.spuAddr>0x7ffff) spu.spuAddr=0;              // wrap\r
+   *pusPSXMem++ = *(unsigned short *)(spu.spuMemC + spu.spuAddr);\r
+   spu.spuAddr += 2;\r
+   spu.spuAddr &= 0x7fffe;\r
   }\r
 }\r
 \r
@@ -67,10 +67,10 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize,
   \r
 void CALLBACK SPUwriteDMA(unsigned short val)\r
 {\r
- spu.spuMem[spu.spuAddr>>1] = val;                     // spu addr got by writeregister\r
+ *(unsigned short *)(spu.spuMemC + spu.spuAddr) = val;\r
 \r
- spu.spuAddr+=2;                                       // inc spu addr\r
- if(spu.spuAddr>0x7ffff) spu.spuAddr=0;                // wrap\r
+ spu.spuAddr += 2;\r
+ spu.spuAddr &= 0x7fffe;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -82,20 +82,20 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize,
 {\r
  int i;\r
  \r
- do_samples_if_needed(cycles);\r
+ do_samples_if_needed(cycles, 1);\r
 \r
  if(spu.spuAddr + iSize*2 < 0x80000)\r
   {\r
-   memcpy(&spu.spuMem[spu.spuAddr>>1], pusPSXMem, iSize*2);\r
+   memcpy(spu.spuMemC + spu.spuAddr, pusPSXMem, iSize*2);\r
    spu.spuAddr += iSize*2;\r
    return;\r
   }\r
 \r
  for(i=0;i<iSize;i++)\r
   {\r
-   spu.spuMem[spu.spuAddr>>1] = *pusPSXMem++;          // spu addr got by writeregister\r
-   spu.spuAddr+=2;                                     // inc spu addr\r
-   spu.spuAddr&=0x7ffff;                               // wrap\r
+   *(unsigned short *)(spu.spuMemC + spu.spuAddr) = *pusPSXMem++;\r
+   spu.spuAddr += 2;\r
+   spu.spuAddr &= 0x7fffe;\r
   }\r
 }\r
 \r
index 7935cb9..f6fc440 100644 (file)
 #define noinline\r
 #define unlikely(x) x\r
 #endif\r
+#if defined(__GNUC__) && !defined(_TMS320C6X)\r
+#define preload __builtin_prefetch\r
+#else\r
+#define preload(...)\r
+#endif\r
 \r
 #define PSE_LT_SPU                  4\r
 #define PSE_SPU_ERR_SUCCESS         0\r
 // struct defines\r
 ///////////////////////////////////////////////////////////\r
 \r
+enum ADSR_State {\r
+ ADSR_ATTACK = 0,\r
+ ADSR_DECAY = 1,\r
+ ADSR_SUSTAIN = 2,\r
+ ADSR_RELEASE = 3,\r
+};\r
+\r
 // ADSR INFOS PER CHANNEL\r
 typedef struct\r
 {\r
- unsigned char  State:2;\r
+ unsigned char  State:2;                               // ADSR_State\r
  unsigned char  AttackModeExp:1;\r
  unsigned char  SustainModeExp:1;\r
  unsigned char  SustainIncrease:1;\r
@@ -93,7 +105,6 @@ typedef struct
  unsigned char *   pCurr;                              // current pos in sound mem\r
  unsigned char *   pLoop;                              // loop ptr in sound mem\r
 \r
- unsigned int      bStop:1;                            // is channel stopped (sample _can_ still be playing, ADSR Release phase)\r
  unsigned int      bReverb:1;                          // can we do reverb on this channel? must have ctrl register bit, to get active\r
  unsigned int      bRVBActive:1;                       // reverb active flag\r
  unsigned int      bNoise:1;                           // noise active flag\r
@@ -104,8 +115,6 @@ typedef struct
  int               iRightVolume;                       // right volume\r
  ADSRInfoEx        ADSRX;\r
  int               iRawPitch;                          // raw pitch (0...3fff)\r
-\r
- int               SB[32+4];\r
 } SPUCHAN;\r
 \r
 ///////////////////////////////////////////////////////////\r
@@ -117,8 +126,6 @@ typedef struct
 \r
  int VolLeft;\r
  int VolRight;\r
- int iRVBLeft;\r
- int iRVBRight;\r
 \r
  int FB_SRC_A;       // (offset)\r
  int FB_SRC_B;       // (offset)\r
@@ -169,13 +176,18 @@ typedef struct
 \r
 // psx buffers / addresses\r
 \r
+#define SB_SIZE (32 + 4)\r
+\r
 typedef struct\r
 {\r
  unsigned short  spuCtrl;\r
  unsigned short  spuStat;\r
 \r
  unsigned int    spuAddr;\r
- unsigned char * spuMemC;\r
+ union {\r
+  unsigned char  *spuMemC;\r
+  unsigned short *spuMem;\r
+ };\r
  unsigned char * pSpuIrq;\r
 \r
  unsigned int    cycles_played;\r
@@ -197,8 +209,6 @@ typedef struct
  void (CALLBACK *cddavCallback)(unsigned short,unsigned short);\r
  void (CALLBACK *scheduleCallback)(unsigned int);\r
 \r
- int           * sRVBStart;\r
-\r
  xa_decode_t   * xapGlobal;\r
  unsigned int  * XAFeed;\r
  unsigned int  * XAPlay;\r
@@ -216,9 +226,15 @@ typedef struct
  int             iLeftXAVol;\r
  int             iRightXAVol;\r
 \r
- int             pad[32];\r
+ SPUCHAN       * s_chan;\r
+ REVERBInfo    * rvb;\r
+\r
+ // buffers\r
+ int           * SB;\r
+ int           * SSumLR;\r
+\r
+ int             pad[29];\r
  unsigned short  regArea[0x400];\r
- unsigned short  spuMem[256*1024];\r
 } SPUInfo;\r
 \r
 ///////////////////////////////////////////////////////////\r
@@ -228,19 +244,17 @@ typedef struct
 #ifndef _IN_SPU\r
 \r
 extern SPUInfo spu;\r
-extern SPUCHAN s_chan[];\r
-extern REVERBInfo rvb;\r
 \r
-void do_samples(unsigned int cycles_to);\r
+void do_samples(unsigned int cycles_to, int do_sync);\r
 void schedule_next_irq(void);\r
 \r
 #define regAreaGet(ch,offset) \\r
   spu.regArea[((ch<<4)|(offset))>>1]\r
 \r
-#define do_samples_if_needed(c) \\r
+#define do_samples_if_needed(c, sync) \\r
  do { \\r
-  if ((int)((c) - spu.cycles_played) >= 16 * 768) \\r
-   do_samples(c); \\r
+  if (sync || (int)((c) - spu.cycles_played) >= 16 * 768) \\r
+   do_samples(c, sync); \\r
  } while (0)\r
 \r
 #endif\r
index d38faa6..5b4267b 100644 (file)
@@ -143,12 +143,12 @@ static void save_channel(SPUCHAN_orig *d, const SPUCHAN *s, int ch)
  d->iSBPos = s->iSBPos;\r
  d->spos = s->spos;\r
  d->sinc = s->sinc;\r
- memcpy(d->SB, s->SB, sizeof(d->SB));\r
+ memcpy(d->SB, spu.SB + ch * SB_SIZE, sizeof(d->SB[0]) * SB_SIZE);\r
  d->iStart = (regAreaGet(ch,6)&~1)<<3;\r
  d->iCurr = 0; // set by the caller\r
  d->iLoop = 0; // set by the caller\r
  d->bOn = !!(spu.dwChannelOn & (1<<ch));\r
- d->bStop = s->bStop;\r
+ d->bStop = s->ADSRX.State == ADSR_RELEASE;\r
  d->bReverb = s->bReverb;\r
  d->iActFreq = 1;\r
  d->iUsedFreq = 2;\r
@@ -157,8 +157,8 @@ static void save_channel(SPUCHAN_orig *d, const SPUCHAN *s, int ch)
  d->bIgnoreLoop = (s->prevflags ^ 2) << 1;\r
  d->iRightVolume = s->iRightVolume;\r
  d->iRawPitch = s->iRawPitch;\r
- d->s_1 = s->SB[27]; // yes it's reversed\r
- d->s_2 = s->SB[26];\r
+ d->s_1 = spu.SB[ch * SB_SIZE + 27]; // yes it's reversed\r
+ d->s_2 = spu.SB[ch * SB_SIZE + 26];\r
  d->bRVBActive = s->bRVBActive;\r
  d->bNoise = s->bNoise;\r
  d->bFMod = s->bFMod;\r
@@ -185,10 +185,9 @@ static void load_channel(SPUCHAN *d, const SPUCHAN_orig *s, int ch)
  d->spos = s->spos;\r
  d->sinc = s->sinc;\r
  d->sinc_inv = 0;\r
- memcpy(d->SB, s->SB, sizeof(d->SB));\r
+ memcpy(spu.SB + ch * SB_SIZE, s->SB, sizeof(spu.SB[0]) * SB_SIZE);\r
  d->pCurr = (void *)((long)s->iCurr & 0x7fff0);\r
  d->pLoop = (void *)((long)s->iLoop & 0x7fff0);\r
- d->bStop = s->bStop;\r
  d->bReverb = s->bReverb;\r
  d->iLeftVolume = s->iLeftVolume;\r
  d->iRightVolume = s->iRightVolume;\r
@@ -198,6 +197,7 @@ static void load_channel(SPUCHAN *d, const SPUCHAN_orig *s, int ch)
  d->bFMod = s->bFMod;\r
  d->prevflags = (s->bIgnoreLoop >> 1) ^ 2;\r
  d->ADSRX.State = s->ADSRX.State;\r
+ if (s->bStop) d->ADSRX.State = ADSR_RELEASE;\r
  d->ADSRX.AttackModeExp = s->ADSRX.AttackModeExp;\r
  d->ADSRX.AttackRate = s->ADSRX.AttackRate;\r
  d->ADSRX.DecayRate = s->ADSRX.DecayRate;\r
@@ -242,7 +242,7 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
 \r
    if(ulFreezeMode==2) return 1;                       // info mode? ok, bye\r
                                                        // save mode:\r
-   do_samples(cycles);\r
+   do_samples(cycles, 1);\r
 \r
    memcpy(pF->cSPURam,spu.spuMem,0x80000);             // copy common infos\r
    memcpy(pF->cSPUPort,spu.regArea,0x200);\r
@@ -264,11 +264,11 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
 \r
    for(i=0;i<MAXCHAN;i++)\r
     {\r
-     save_channel(&pFO->s_chan[i],&s_chan[i],i);\r
-     if(s_chan[i].pCurr)\r
-      pFO->s_chan[i].iCurr=s_chan[i].pCurr-spu.spuMemC;\r
-     if(s_chan[i].pLoop)\r
-      pFO->s_chan[i].iLoop=s_chan[i].pLoop-spu.spuMemC;\r
+     save_channel(&pFO->s_chan[i],&spu.s_chan[i],i);\r
+     if(spu.s_chan[i].pCurr)\r
+      pFO->s_chan[i].iCurr=spu.s_chan[i].pCurr-spu.spuMemC;\r
+     if(spu.s_chan[i].pLoop)\r
+      pFO->s_chan[i].iLoop=spu.s_chan[i].pLoop-spu.spuMemC;\r
     }\r
 \r
    return 1;\r
@@ -302,7 +302,7 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
  load_register(H_CDRight, cycles);\r
 \r
  // fix to prevent new interpolations from crashing\r
- for(i=0;i<MAXCHAN;i++) s_chan[i].SB[28]=0;\r
+ for(i=0;i<MAXCHAN;i++) spu.SB[i * SB_SIZE + 28]=0;\r
 \r
  ClearWorkingState();\r
  spu.cycles_played = cycles;\r
@@ -325,8 +325,8 @@ void LoadStateV5(SPUFreeze_t * pF)
 \r
  if(pFO->spuAddr)\r
   {\r
-   spu.spuAddr = pFO->spuAddr;\r
-   if (spu.spuAddr == 0xbaadf00d) spu.spuAddr = 0;\r
+   if (pFO->spuAddr == 0xbaadf00d) spu.spuAddr = 0;\r
+   else spu.spuAddr = pFO->spuAddr & 0x7fffe;\r
   }\r
 \r
  spu.dwNewChannel=0;\r
@@ -334,10 +334,10 @@ void LoadStateV5(SPUFreeze_t * pF)
  spu.dwChannelDead=0;\r
  for(i=0;i<MAXCHAN;i++)\r
   {\r
-   load_channel(&s_chan[i],&pFO->s_chan[i],i);\r
+   load_channel(&spu.s_chan[i],&pFO->s_chan[i],i);\r
 \r
-   s_chan[i].pCurr+=(unsigned long)spu.spuMemC;\r
-   s_chan[i].pLoop+=(unsigned long)spu.spuMemC;\r
+   spu.s_chan[i].pCurr+=(unsigned long)spu.spuMemC;\r
+   spu.s_chan[i].pLoop+=(unsigned long)spu.spuMemC;\r
   }\r
 }\r
 \r
@@ -349,8 +349,7 @@ void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles)
 \r
  for(i=0;i<MAXCHAN;i++)\r
   {\r
-   s_chan[i].bStop=0;\r
-   s_chan[i].pLoop=spu.spuMemC;\r
+   spu.s_chan[i].pLoop=spu.spuMemC;\r
   }\r
 \r
  spu.dwNewChannel=0;\r
index 8093ae4..6b1cb4a 100644 (file)
@@ -34,6 +34,9 @@
 
 #define OSS_SPEED_44100     44100
 
+#define FRAGMENT_SHIFT 12
+#define FRAGMENT_SIZE  (1 << FRAGMENT_SHIFT)
+
 static int oss_audio_fd = -1;
 extern int errno;
 
@@ -46,7 +49,6 @@ static int oss_init(void)
  int pspeed=44100;
  int pstereo;
  int format;
- int fragsize = 0;
  int myfrag;
  int oss_speed, oss_stereo;
 
@@ -69,8 +71,7 @@ static int oss_init(void)
  // we use 64 fragments with 1024 bytes each
  // rearmed: now using 10*4096 for better latency
 
- fragsize=12;
- myfrag=(10<<16)|fragsize;
+ myfrag = (10<<16) | FRAGMENT_SHIFT;
 
  if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1)
   {
@@ -160,11 +161,18 @@ static void oss_feed(void *buf, int bytes)
  if(oss_audio_fd == -1) return;
  if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==0)
   {
+   // for fast forward
+   if(bytes > info.fragments * FRAGMENT_SIZE)
+    bytes = info.fragments * FRAGMENT_SIZE;
+   if(bytes == 0)
+    return;
+
    if(info.fragments==info.fragstotal)
     {
      memset(sbuf, 0, sizeof(sbuf));
      write(oss_audio_fd, sbuf, sizeof(sbuf));
      write(oss_audio_fd, sbuf, sizeof(sbuf));
+     write(oss_audio_fd, sbuf, sizeof(sbuf));
     }
   }
 
index 210adb2..4588fa7 100644 (file)
@@ -57,7 +57,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
  if (val == 0 && (r & 0xff8) == 0xd88)\r
   return;\r
 \r
- do_samples_if_needed(cycles);\r
+ do_samples_if_needed(cycles, 0);\r
 \r
  if(r>=0x0c00 && r<0x0d80)                             // some channel info?\r
   {\r
@@ -85,10 +85,10 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
        {\r
         const unsigned long lval=val;\r
         //---------------------------------------------//\r
-        s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; \r
-        s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
-        s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
-        s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
+        spu.s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;\r
+        spu.s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
+        spu.s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
+        spu.s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
         //---------------------------------------------//\r
        }\r
       break;\r
@@ -98,11 +98,11 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
        const unsigned long lval=val;\r
 \r
        //----------------------------------------------//\r
-       s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
-       s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
-       s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
-       s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
-       s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
+       spu.s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
+       spu.s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
+       spu.s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
+       spu.s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
+       spu.s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
        //----------------------------------------------//\r
       }\r
      break;\r
@@ -111,7 +111,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
        break;\r
      //------------------------------------------------//\r
      case 14:                                          // loop?\r
-       s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
+       spu.s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
        goto upd_irq;\r
      //------------------------------------------------//\r
     }\r
@@ -126,9 +126,9 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
       break;\r
     //-------------------------------------------------//\r
     case H_SPUdata:\r
-      spu.spuMem[spu.spuAddr>>1] = val;\r
-      spu.spuAddr+=2;\r
-      if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
+      *(unsigned short *)(spu.spuMemC + spu.spuAddr) = val;\r
+      spu.spuAddr += 2;\r
+      spu.spuAddr &= 0x7fffe;\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUctrl:\r
@@ -146,14 +146,14 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
     //-------------------------------------------------//\r
     case H_SPUReverbAddr:\r
       if(val==0xFFFF || val<=0x200)\r
-       {rvb.StartAddr=rvb.CurrAddr=0;}\r
+       {spu.rvb->StartAddr=spu.rvb->CurrAddr=0;}\r
       else\r
        {\r
         const long iv=(unsigned long)val<<2;\r
-        if(rvb.StartAddr!=iv)\r
+        if(spu.rvb->StartAddr!=iv)\r
          {\r
-          rvb.StartAddr=(unsigned long)val<<2;\r
-          rvb.CurrAddr=rvb.StartAddr;\r
+          spu.rvb->StartAddr=(unsigned long)val<<2;\r
+          spu.rvb->CurrAddr=spu.rvb->StartAddr;\r
          }\r
        }\r
       goto rvbd;\r
@@ -163,11 +163,11 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
       goto upd_irq;\r
     //-------------------------------------------------//\r
     case H_SPUrvolL:\r
-      rvb.VolLeft=val;\r
+      spu.rvb->VolLeft=val;\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUrvolR:\r
-      rvb.VolRight=val;\r
+      spu.rvb->VolRight=val;\r
       break;\r
     //-------------------------------------------------//\r
 \r
@@ -246,38 +246,38 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
       ReverbOn(16,24,val);\r
       break;\r
     //-------------------------------------------------//\r
-    case H_Reverb+0   : rvb.FB_SRC_A=val*4;         goto rvbd;\r
-    case H_Reverb+2   : rvb.FB_SRC_B=val*4;         goto rvbd;\r
-    case H_Reverb+4   : rvb.IIR_ALPHA=(short)val;   goto rvbd;\r
-    case H_Reverb+6   : rvb.ACC_COEF_A=(short)val;  goto rvbd;\r
-    case H_Reverb+8   : rvb.ACC_COEF_B=(short)val;  goto rvbd;\r
-    case H_Reverb+10  : rvb.ACC_COEF_C=(short)val;  goto rvbd;\r
-    case H_Reverb+12  : rvb.ACC_COEF_D=(short)val;  goto rvbd;\r
-    case H_Reverb+14  : rvb.IIR_COEF=(short)val;    goto rvbd;\r
-    case H_Reverb+16  : rvb.FB_ALPHA=(short)val;    goto rvbd;\r
-    case H_Reverb+18  : rvb.FB_X=(short)val;        goto rvbd;\r
-    case H_Reverb+20  : rvb.IIR_DEST_A0=val*4;      goto rvbd;\r
-    case H_Reverb+22  : rvb.IIR_DEST_A1=val*4;      goto rvbd;\r
-    case H_Reverb+24  : rvb.ACC_SRC_A0=val*4;       goto rvbd;\r
-    case H_Reverb+26  : rvb.ACC_SRC_A1=val*4;       goto rvbd;\r
-    case H_Reverb+28  : rvb.ACC_SRC_B0=val*4;       goto rvbd;\r
-    case H_Reverb+30  : rvb.ACC_SRC_B1=val*4;       goto rvbd;\r
-    case H_Reverb+32  : rvb.IIR_SRC_A0=val*4;       goto rvbd;\r
-    case H_Reverb+34  : rvb.IIR_SRC_A1=val*4;       goto rvbd;\r
-    case H_Reverb+36  : rvb.IIR_DEST_B0=val*4;      goto rvbd;\r
-    case H_Reverb+38  : rvb.IIR_DEST_B1=val*4;      goto rvbd;\r
-    case H_Reverb+40  : rvb.ACC_SRC_C0=val*4;       goto rvbd;\r
-    case H_Reverb+42  : rvb.ACC_SRC_C1=val*4;       goto rvbd;\r
-    case H_Reverb+44  : rvb.ACC_SRC_D0=val*4;       goto rvbd;\r
-    case H_Reverb+46  : rvb.ACC_SRC_D1=val*4;       goto rvbd;\r
-    case H_Reverb+48  : rvb.IIR_SRC_B1=val*4;       goto rvbd;\r
-    case H_Reverb+50  : rvb.IIR_SRC_B0=val*4;       goto rvbd;\r
-    case H_Reverb+52  : rvb.MIX_DEST_A0=val*4;      goto rvbd;\r
-    case H_Reverb+54  : rvb.MIX_DEST_A1=val*4;      goto rvbd;\r
-    case H_Reverb+56  : rvb.MIX_DEST_B0=val*4;      goto rvbd;\r
-    case H_Reverb+58  : rvb.MIX_DEST_B1=val*4;      goto rvbd;\r
-    case H_Reverb+60  : rvb.IN_COEF_L=(short)val;   goto rvbd;\r
-    case H_Reverb+62  : rvb.IN_COEF_R=(short)val;   goto rvbd;\r
+    case H_Reverb+0   : spu.rvb->FB_SRC_A=val*4;         goto rvbd;\r
+    case H_Reverb+2   : spu.rvb->FB_SRC_B=val*4;         goto rvbd;\r
+    case H_Reverb+4   : spu.rvb->IIR_ALPHA=(short)val;   goto rvbd;\r
+    case H_Reverb+6   : spu.rvb->ACC_COEF_A=(short)val;  goto rvbd;\r
+    case H_Reverb+8   : spu.rvb->ACC_COEF_B=(short)val;  goto rvbd;\r
+    case H_Reverb+10  : spu.rvb->ACC_COEF_C=(short)val;  goto rvbd;\r
+    case H_Reverb+12  : spu.rvb->ACC_COEF_D=(short)val;  goto rvbd;\r
+    case H_Reverb+14  : spu.rvb->IIR_COEF=(short)val;    goto rvbd;\r
+    case H_Reverb+16  : spu.rvb->FB_ALPHA=(short)val;    goto rvbd;\r
+    case H_Reverb+18  : spu.rvb->FB_X=(short)val;        goto rvbd;\r
+    case H_Reverb+20  : spu.rvb->IIR_DEST_A0=val*4;      goto rvbd;\r
+    case H_Reverb+22  : spu.rvb->IIR_DEST_A1=val*4;      goto rvbd;\r
+    case H_Reverb+24  : spu.rvb->ACC_SRC_A0=val*4;       goto rvbd;\r
+    case H_Reverb+26  : spu.rvb->ACC_SRC_A1=val*4;       goto rvbd;\r
+    case H_Reverb+28  : spu.rvb->ACC_SRC_B0=val*4;       goto rvbd;\r
+    case H_Reverb+30  : spu.rvb->ACC_SRC_B1=val*4;       goto rvbd;\r
+    case H_Reverb+32  : spu.rvb->IIR_SRC_A0=val*4;       goto rvbd;\r
+    case H_Reverb+34  : spu.rvb->IIR_SRC_A1=val*4;       goto rvbd;\r
+    case H_Reverb+36  : spu.rvb->IIR_DEST_B0=val*4;      goto rvbd;\r
+    case H_Reverb+38  : spu.rvb->IIR_DEST_B1=val*4;      goto rvbd;\r
+    case H_Reverb+40  : spu.rvb->ACC_SRC_C0=val*4;       goto rvbd;\r
+    case H_Reverb+42  : spu.rvb->ACC_SRC_C1=val*4;       goto rvbd;\r
+    case H_Reverb+44  : spu.rvb->ACC_SRC_D0=val*4;       goto rvbd;\r
+    case H_Reverb+46  : spu.rvb->ACC_SRC_D1=val*4;       goto rvbd;\r
+    case H_Reverb+48  : spu.rvb->IIR_SRC_B1=val*4;       goto rvbd;\r
+    case H_Reverb+50  : spu.rvb->IIR_SRC_B0=val*4;       goto rvbd;\r
+    case H_Reverb+52  : spu.rvb->MIX_DEST_A0=val*4;      goto rvbd;\r
+    case H_Reverb+54  : spu.rvb->MIX_DEST_A1=val*4;      goto rvbd;\r
+    case H_Reverb+56  : spu.rvb->MIX_DEST_B0=val*4;      goto rvbd;\r
+    case H_Reverb+58  : spu.rvb->MIX_DEST_B1=val*4;      goto rvbd;\r
+    case H_Reverb+60  : spu.rvb->IN_COEF_L=(short)val;   goto rvbd;\r
+    case H_Reverb+62  : spu.rvb->IN_COEF_R=(short)val;   goto rvbd;\r
    }\r
  return;\r
 \r
@@ -287,7 +287,7 @@ upd_irq:
  return;\r
 \r
 rvbd:\r
rvb.dirty = 1; // recalculate on next update\r
spu.rvb->dirty = 1; // recalculate on next update\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -307,15 +307,15 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
        const int ch=(r>>4)-0xc0;\r
        if(spu.dwNewChannel&(1<<ch)) return 1;          // we are started, but not processed? return 1\r
        if((spu.dwChannelOn&(1<<ch)) &&                 // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well\r
-          !s_chan[ch].ADSRX.EnvelopeVol)\r
+          !spu.s_chan[ch].ADSRX.EnvelopeVol)\r
         return 1;\r
-       return (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16);\r
+       return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol>>16);\r
       }\r
 \r
      case 14:                                          // get loop address\r
       {\r
        const int ch=(r>>4)-0xc0;\r
-       return (unsigned short)((s_chan[ch].pLoop-spu.spuMemC)>>3);\r
+       return (unsigned short)((spu.s_chan[ch].pLoop-spu.spuMemC)>>3);\r
       }\r
     }\r
   }\r
@@ -333,9 +333,9 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
 \r
     case H_SPUdata:\r
      {\r
-      unsigned short s=spu.spuMem[spu.spuAddr>>1];\r
-      spu.spuAddr+=2;\r
-      if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
+      unsigned short s = *(unsigned short *)(spu.spuMemC + spu.spuAddr);\r
+      spu.spuAddr += 2;\r
+      spu.spuAddr &= 0x7fffe;\r
       return s;\r
      }\r
 \r
@@ -362,16 +362,9 @@ static void SoundOn(int start,int end,unsigned short val)
   {\r
    if((val&1) && regAreaGet(ch,6))                     // mmm... start has to be set before key on !?!\r
     {\r
-     // do this here, not in StartSound\r
-     // - fixes fussy timing issues\r
-     s_chan[ch].bStop=0;\r
-     s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned\r
-     s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3);\r
-     s_chan[ch].prevflags=2;\r
-\r
+     spu.s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned\r
+     spu.s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3);\r
      spu.dwNewChannel|=(1<<ch);\r
-     spu.dwChannelOn|=1<<ch;\r
-     spu.dwChannelDead&=~(1<<ch);\r
     }\r
   }\r
 }\r
@@ -385,9 +378,9 @@ static void SoundOff(int start,int end,unsigned short val)
  int ch;\r
  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
   {\r
-   if(val&1)                                           // && s_chan[i].bOn)  mmm...\r
+   if(val&1)\r
     {\r
-     s_chan[ch].bStop=1;\r
+     spu.s_chan[ch].ADSRX.State = ADSR_RELEASE;\r
 \r
      // Jungle Book - Rhythm 'n Groove\r
      // - turns off buzzing sound (loop hangs)\r
@@ -410,15 +403,15 @@ static void FModOn(int start,int end,unsigned short val)
     {\r
      if(ch>0) \r
       {\r
-       s_chan[ch].bFMod=1;                             // --> sound channel\r
-       s_chan[ch-1].bFMod=2;                           // --> freq channel\r
+       spu.s_chan[ch].bFMod=1;                         // --> sound channel\r
+       spu.s_chan[ch-1].bFMod=2;                       // --> freq channel\r
       }\r
     }\r
    else\r
     {\r
-     s_chan[ch].bFMod=0;                               // --> turn off fmod\r
-     if(ch>0&&s_chan[ch-1].bFMod==2)\r
-      s_chan[ch-1].bFMod=0;\r
+     spu.s_chan[ch].bFMod=0;                           // --> turn off fmod\r
+     if(ch>0&&spu.s_chan[ch-1].bFMod==2)\r
+      spu.s_chan[ch-1].bFMod=0;\r
     }\r
   }\r
 }\r
@@ -433,7 +426,7 @@ static void NoiseOn(int start,int end,unsigned short val)
 \r
  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
   {\r
-   s_chan[ch].bNoise=val&1;                            // -> noise on/off\r
+   spu.s_chan[ch].bNoise=val&1;                        // -> noise on/off\r
   }\r
 }\r
 \r
@@ -463,7 +456,7 @@ static void SetVolumeL(unsigned char ch,short vol)     // LEFT VOLUME
   }\r
 \r
  vol&=0x3fff;\r
- s_chan[ch].iLeftVolume=vol;                           // store volume\r
+ spu.s_chan[ch].iLeftVolume=vol;                       // store volume\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -489,7 +482,7 @@ static void SetVolumeR(unsigned char ch,short vol)     // RIGHT VOLUME
 \r
  vol&=0x3fff;\r
 \r
- s_chan[ch].iRightVolume=vol;\r
+ spu.s_chan[ch].iRightVolume=vol;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -502,10 +495,11 @@ static void SetPitch(int ch,unsigned short val)               // SET PITCH
  if(val>0x3fff) NP=0x3fff;                             // get pitch val\r
  else           NP=val;\r
 \r
- s_chan[ch].iRawPitch=NP;\r
- s_chan[ch].sinc=(NP<<4)|8;\r
- s_chan[ch].sinc_inv=0;\r
- if(spu_config.iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simple interpolation mode: set flag\r
+ spu.s_chan[ch].iRawPitch=NP;\r
+ spu.s_chan[ch].sinc=(NP<<4)|8;\r
+ spu.s_chan[ch].sinc_inv=0;\r
+ if (spu_config.iUseInterpolation == 1)\r
+  spu.SB[ch * SB_SIZE + 32] = 1; // -> freq change in simple interpolation mode: set flag\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -518,6 +512,6 @@ static void ReverbOn(int start,int end,unsigned short val)
 \r
  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
   {\r
-   s_chan[ch].bReverb=val&1;                           // -> reverb on/off\r
+   spu.s_chan[ch].bReverb=val&1;                       // -> reverb on/off\r
   }\r
 }\r
index bb5ee8e..2ff6edc 100644 (file)
 \r
 INLINE void StartREVERB(int ch)\r
 {\r
- if(s_chan[ch].bReverb && (spu.spuCtrl&0x80))          // reverb possible?\r
+ if(spu.s_chan[ch].bReverb && (spu.spuCtrl&0x80))      // reverb possible?\r
   {\r
-   s_chan[ch].bRVBActive=!!spu_config.iUseReverb;\r
+   spu.s_chan[ch].bRVBActive=!!spu_config.iUseReverb;\r
   }\r
- else s_chan[ch].bRVBActive=0;                         // else -> no reverb\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////\r
-// HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf\r
-////////////////////////////////////////////////////////////////////////\r
-\r
-INLINE void InitREVERB(int ns_to)\r
-{\r
- memset(spu.sRVBStart,0,ns_to*sizeof(spu.sRVBStart[0])*2);\r
+ else spu.s_chan[ch].bRVBActive=0;                     // else -> no reverb\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -59,41 +50,40 @@ INLINE int rvb2ram_offs(int curr, int space, int iOff)
 \r
 // get_buffer content helper: takes care about wraps\r
 #define g_buffer(var) \\r
- ((int)(signed short)spu.spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var)])\r
+ ((int)(signed short)spu.spuMem[rvb2ram_offs(curr_addr, space, rvb->n##var)])\r
 \r
 // saturate iVal and store it as var\r
 #define s_buffer(var, iVal) \\r
  ssat32_to_16(iVal); \\r
- spu.spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var)] = iVal\r
+ spu.spuMem[rvb2ram_offs(curr_addr, space, rvb->n##var)] = iVal\r
 \r
 #define s_buffer1(var, iVal) \\r
  ssat32_to_16(iVal); \\r
- spu.spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var + 1)] = iVal\r
+ spu.spuMem[rvb2ram_offs(curr_addr, space, rvb->n##var + 1)] = iVal\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
 // portions based on spu2-x from PCSX2\r
-static void MixREVERB(int ns_to)\r
+static void MixREVERB(int *SSumLR, int *RVB, int ns_to, int curr_addr)\r
 {\r
int l_old = rvb.iRVBLeft;\r
- int r_old = rvb.iRVBRight;\r
- int curr_addr = rvb.CurrAddr;\r
- int space = 0x40000 - rvb.StartAddr;\r
- int l = 0, r = 0, ns;\r
const REVERBInfo *rvb = spu.rvb;\r
+ int IIR_ALPHA = rvb->IIR_ALPHA;\r
+ int IIR_COEF = rvb->IIR_COEF;\r
+ int space = 0x40000 - rvb->StartAddr;\r
+ int l, r, ns;\r
 \r
  for (ns = 0; ns < ns_to * 2; )\r
   {\r
-   int IIR_ALPHA = rvb.IIR_ALPHA;\r
    int ACC0, ACC1, FB_A0, FB_A1, FB_B0, FB_B1;\r
    int mix_dest_a0, mix_dest_a1, mix_dest_b0, mix_dest_b1;\r
 \r
-   int input_L = spu.sRVBStart[ns]   * rvb.IN_COEF_L;\r
-   int input_R = spu.sRVBStart[ns+1] * rvb.IN_COEF_R;\r
+   int input_L = RVB[ns]   * rvb->IN_COEF_L;\r
+   int input_R = RVB[ns+1] * rvb->IN_COEF_R;\r
 \r
-   int IIR_INPUT_A0 = ((g_buffer(IIR_SRC_A0) * rvb.IIR_COEF) + input_L) >> 15;\r
-   int IIR_INPUT_A1 = ((g_buffer(IIR_SRC_A1) * rvb.IIR_COEF) + input_R) >> 15;\r
-   int IIR_INPUT_B0 = ((g_buffer(IIR_SRC_B0) * rvb.IIR_COEF) + input_L) >> 15;\r
-   int IIR_INPUT_B1 = ((g_buffer(IIR_SRC_B1) * rvb.IIR_COEF) + input_R) >> 15;\r
+   int IIR_INPUT_A0 = ((g_buffer(IIR_SRC_A0) * IIR_COEF) + input_L) >> 15;\r
+   int IIR_INPUT_A1 = ((g_buffer(IIR_SRC_A1) * IIR_COEF) + input_R) >> 15;\r
+   int IIR_INPUT_B0 = ((g_buffer(IIR_SRC_B0) * IIR_COEF) + input_L) >> 15;\r
+   int IIR_INPUT_B1 = ((g_buffer(IIR_SRC_B1) * IIR_COEF) + input_R) >> 15;\r
 \r
    int iir_dest_a0 = g_buffer(IIR_DEST_A0);\r
    int iir_dest_a1 = g_buffer(IIR_DEST_A1);\r
@@ -105,30 +95,34 @@ static void MixREVERB(int ns_to)
    int IIR_B0 = iir_dest_b0 + ((IIR_INPUT_B0 - iir_dest_b0) * IIR_ALPHA >> 15);\r
    int IIR_B1 = iir_dest_b1 + ((IIR_INPUT_B1 - iir_dest_b1) * IIR_ALPHA >> 15);\r
 \r
+   preload(SSumLR + ns + 64*2/4 - 4);\r
+\r
    s_buffer1(IIR_DEST_A0, IIR_A0);\r
    s_buffer1(IIR_DEST_A1, IIR_A1);\r
    s_buffer1(IIR_DEST_B0, IIR_B0);\r
    s_buffer1(IIR_DEST_B1, IIR_B1);\r
 \r
-   ACC0 = (g_buffer(ACC_SRC_A0) * rvb.ACC_COEF_A +\r
-           g_buffer(ACC_SRC_B0) * rvb.ACC_COEF_B +\r
-           g_buffer(ACC_SRC_C0) * rvb.ACC_COEF_C +\r
-           g_buffer(ACC_SRC_D0) * rvb.ACC_COEF_D) >> 15;\r
-   ACC1 = (g_buffer(ACC_SRC_A1) * rvb.ACC_COEF_A +\r
-           g_buffer(ACC_SRC_B1) * rvb.ACC_COEF_B +\r
-           g_buffer(ACC_SRC_C1) * rvb.ACC_COEF_C +\r
-           g_buffer(ACC_SRC_D1) * rvb.ACC_COEF_D) >> 15;\r
+   preload(RVB + ns + 64*2/4 - 4);\r
+\r
+   ACC0 = (g_buffer(ACC_SRC_A0) * rvb->ACC_COEF_A +\r
+           g_buffer(ACC_SRC_B0) * rvb->ACC_COEF_B +\r
+           g_buffer(ACC_SRC_C0) * rvb->ACC_COEF_C +\r
+           g_buffer(ACC_SRC_D0) * rvb->ACC_COEF_D) >> 15;\r
+   ACC1 = (g_buffer(ACC_SRC_A1) * rvb->ACC_COEF_A +\r
+           g_buffer(ACC_SRC_B1) * rvb->ACC_COEF_B +\r
+           g_buffer(ACC_SRC_C1) * rvb->ACC_COEF_C +\r
+           g_buffer(ACC_SRC_D1) * rvb->ACC_COEF_D) >> 15;\r
 \r
    FB_A0 = g_buffer(FB_SRC_A0);\r
    FB_A1 = g_buffer(FB_SRC_A1);\r
    FB_B0 = g_buffer(FB_SRC_B0);\r
    FB_B1 = g_buffer(FB_SRC_B1);\r
 \r
-   mix_dest_a0 = ACC0 - ((FB_A0 * rvb.FB_ALPHA) >> 15);\r
-   mix_dest_a1 = ACC1 - ((FB_A1 * rvb.FB_ALPHA) >> 15);\r
+   mix_dest_a0 = ACC0 - ((FB_A0 * rvb->FB_ALPHA) >> 15);\r
+   mix_dest_a1 = ACC1 - ((FB_A1 * rvb->FB_ALPHA) >> 15);\r
 \r
-   mix_dest_b0 = FB_A0 + (((ACC0 - FB_A0) * rvb.FB_ALPHA - FB_B0 * rvb.FB_X) >> 15);\r
-   mix_dest_b1 = FB_A1 + (((ACC1 - FB_A1) * rvb.FB_ALPHA - FB_B1 * rvb.FB_X) >> 15);\r
+   mix_dest_b0 = FB_A0 + (((ACC0 - FB_A0) * rvb->FB_ALPHA - FB_B0 * rvb->FB_X) >> 15);\r
+   mix_dest_b1 = FB_A1 + (((ACC1 - FB_A1) * rvb->FB_ALPHA - FB_B1 * rvb->FB_X) >> 15);\r
 \r
    s_buffer(MIX_DEST_A0, mix_dest_a0);\r
    s_buffer(MIX_DEST_A1, mix_dest_a1);\r
@@ -138,73 +132,60 @@ static void MixREVERB(int ns_to)
    l = (mix_dest_a0 + mix_dest_b0) / 2;\r
    r = (mix_dest_a1 + mix_dest_b1) / 2;\r
 \r
-   l = (l * rvb.VolLeft)  >> 15; // 15?\r
-   r = (r * rvb.VolRight) >> 15;\r
+   l = (l * rvb->VolLeft)  >> 15; // 15?\r
+   r = (r * rvb->VolRight) >> 15;\r
 \r
-   SSumLR[ns++] += (l + l_old) / 2;\r
-   SSumLR[ns++] += (r + r_old) / 2;\r
    SSumLR[ns++] += l;\r
    SSumLR[ns++] += r;\r
-\r
-   l_old = l;\r
-   r_old = r;\r
+   SSumLR[ns++] += l;\r
+   SSumLR[ns++] += r;\r
 \r
    curr_addr++;\r
-   if (curr_addr >= 0x40000) curr_addr = rvb.StartAddr;\r
+   if (curr_addr >= 0x40000) curr_addr = rvb->StartAddr;\r
   }\r
-\r
- rvb.iRVBLeft = l;\r
- rvb.iRVBRight = r;\r
- rvb.CurrAddr = curr_addr;\r
 }\r
 \r
-static void MixREVERB_off(int ns_to)\r
+static void MixREVERB_off(int *SSumLR, int ns_to, int curr_addr)\r
 {\r
- int l_old = rvb.iRVBLeft;\r
- int r_old = rvb.iRVBRight;\r
- int curr_addr = rvb.CurrAddr;\r
- int space = 0x40000 - rvb.StartAddr;\r
- int l = 0, r = 0, ns;\r
+ const REVERBInfo *rvb = spu.rvb;\r
+ int space = 0x40000 - rvb->StartAddr;\r
+ int l, r, ns;\r
 \r
  for (ns = 0; ns < ns_to * 2; )\r
   {\r
+   preload(SSumLR + ns + 64*2/4 - 4);\r
+\r
    l = (g_buffer(MIX_DEST_A0) + g_buffer(MIX_DEST_B0)) / 2;\r
    r = (g_buffer(MIX_DEST_A1) + g_buffer(MIX_DEST_B1)) / 2;\r
 \r
-   l = (l * rvb.VolLeft)  >> 15;\r
-   r = (r * rvb.VolRight) >> 15;\r
+   l = (l * rvb->VolLeft)  >> 15;\r
+   r = (r * rvb->VolRight) >> 15;\r
 \r
-   SSumLR[ns++] += (l + l_old) / 2;\r
-   SSumLR[ns++] += (r + r_old) / 2;\r
    SSumLR[ns++] += l;\r
    SSumLR[ns++] += r;\r
-\r
-   l_old = l;\r
-   r_old = r;\r
+   SSumLR[ns++] += l;\r
+   SSumLR[ns++] += r;\r
 \r
    curr_addr++;\r
-   if (curr_addr >= 0x40000) curr_addr = rvb.StartAddr;\r
+   if (curr_addr >= 0x40000) curr_addr = rvb->StartAddr;\r
   }\r
-\r
- rvb.iRVBLeft = l;\r
- rvb.iRVBRight = r;\r
- rvb.CurrAddr = curr_addr;\r
 }\r
 \r
-static void prepare_offsets(void)\r
+static void REVERBPrep(void)\r
 {\r
- int space = 0x40000 - rvb.StartAddr;\r
+ REVERBInfo *rvb = spu.rvb;\r
+ int space = 0x40000 - rvb->StartAddr;\r
  int t;\r
  #define prep_offs(v) \\r
-   t = rvb.v; \\r
+   t = rvb->v; \\r
    while (t >= space) \\r
      t -= space; \\r
-   rvb.n##v = t\r
+   rvb->n##v = t\r
  #define prep_offs2(d, v1, v2) \\r
-   t = rvb.v1 - rvb.v2; \\r
+   t = rvb->v1 - rvb->v2; \\r
    while (t >= space) \\r
      t -= space; \\r
-   rvb.n##d = t\r
+   rvb->n##d = t\r
 \r
  prep_offs(IIR_SRC_A0);\r
  prep_offs(IIR_SRC_A1);\r
@@ -233,37 +214,18 @@ static void prepare_offsets(void)
 \r
 #undef prep_offs\r
 #undef prep_offs2\r
- rvb.dirty = 0;\r
+ rvb->dirty = 0;\r
 }\r
 \r
-INLINE void REVERBDo(int ns_to)\r
+INLINE void REVERBDo(int *SSumLR, int *RVB, int ns_to, int curr_addr)\r
 {\r
- if (!rvb.StartAddr)                                   // reverb is off\r
- {\r
-  rvb.iRVBLeft = rvb.iRVBRight = 0;\r
-  return;\r
- }\r
-\r
  if (spu.spuCtrl & 0x80)                               // -> reverb on? oki\r
  {\r
-  if (unlikely(rvb.dirty))\r
-   prepare_offsets();\r
-\r
-  MixREVERB(ns_to);\r
- }\r
- else if (rvb.VolLeft || rvb.VolRight)\r
- {\r
-  if (unlikely(rvb.dirty))\r
-   prepare_offsets();\r
-\r
-  MixREVERB_off(ns_to);\r
+  MixREVERB(SSumLR, RVB, ns_to, curr_addr);\r
  }\r
- else                                                  // -> reverb off\r
+ else if (spu.rvb->VolLeft || spu.rvb->VolRight)\r
  {\r
-  // reverb runs anyway\r
-  rvb.CurrAddr += ns_to / 2;\r
-  while (rvb.CurrAddr >= 0x40000)\r
-   rvb.CurrAddr -= 0x40000 - rvb.StartAddr;\r
+  MixREVERB_off(SSumLR, ns_to, curr_addr);\r
  }\r
 }\r
 \r
index 835555d..8681d35 100644 (file)
@@ -5,7 +5,7 @@
     copyright            : (C) 2002 by Pete Bernert
     email                : BlackDove@addcom.de
 
- Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2012,2014
+ Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2012,2014,2015
 
  ***************************************************************************/
 /***************************************************************************
  *                                                                         *
  ***************************************************************************/
 
+#if !defined(_WIN32) && !defined(NO_OS)
+#include <sys/time.h> // gettimeofday in xa.c
+#define THREAD_ENABLED 1
+#endif
 #include "stdafx.h"
 
 #define _IN_SPU
 #include "externals.h"
 #include "registers.h"
 #include "out.h"
-#include "arm_features.h"
 #include "spu_config.h"
 
-#ifdef ENABLE_NLS
-#include <libintl.h>
-#include <locale.h>
-#define _(x)  gettext(x)
-#define N_(x) (x)
-#else
-#define _(x)  (x)
-#define N_(x) (x)
+#ifdef __arm__
+#include "arm_features.h"
 #endif
 
 #ifdef __ARM_ARCH_7A__
@@ -76,21 +73,9 @@ static char * libraryInfo     = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete B
 SPUInfo         spu;
 SPUConfig       spu_config;
 
-// MAIN infos struct for each channel
-
-SPUCHAN         s_chan[MAXCHAN+1];                     // channel + 1 infos (1 is security for fmod handling)
-REVERBInfo      rvb;
-
-// certain globals (were local before, but with the new timeproc I need em global)
-
-static const int f[8][2] = {   {    0,  0  },
-                        {   60,  0  },
-                        {  115, -52 },
-                        {   98, -55 },
-                        {  122, -60 } };
+static int iFMod[NSSIZE];
+static int RVB[NSSIZE * 2];
 int ChanBuf[NSSIZE];
-int SSumLR[NSSIZE*2];
-int iFMod[NSSIZE];
 
 #define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2
 
@@ -145,71 +130,70 @@ int iFMod[NSSIZE];
 //          /
 //
 
-
-INLINE void InterpolateUp(int ch)
+static void InterpolateUp(int *SB, int sinc)
 {
- if(s_chan[ch].SB[32]==1)                              // flag == 1? calc step and set flag... and don't change the value in this pass
+ if(SB[32]==1)                                         // flag == 1? calc step and set flag... and don't change the value in this pass
   {
-   const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29];  // curr delta to next val
-   const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30];  // and next delta to next-next val :)
+   const int id1=SB[30]-SB[29];                        // curr delta to next val
+   const int id2=SB[31]-SB[30];                        // and next delta to next-next val :)
 
-   s_chan[ch].SB[32]=0;
+   SB[32]=0;
 
    if(id1>0)                                           // curr delta positive
     {
      if(id2<id1)
-      {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
+      {SB[28]=id1;SB[32]=2;}
      else
      if(id2<(id1<<1))
-      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
+      SB[28]=(id1*sinc)>>16;
      else
-      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
+      SB[28]=(id1*sinc)>>17;
     }
    else                                                // curr delta negative
     {
      if(id2>id1)
-      {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
+      {SB[28]=id1;SB[32]=2;}
      else
      if(id2>(id1<<1))
-      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
+      SB[28]=(id1*sinc)>>16;
      else
-      s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
+      SB[28]=(id1*sinc)>>17;
     }
   }
  else
- if(s_chan[ch].SB[32]==2)                              // flag 1: calc step and set flag... and don't change the value in this pass
+ if(SB[32]==2)                                         // flag 1: calc step and set flag... and don't change the value in this pass
   {
-   s_chan[ch].SB[32]=0;
+   SB[32]=0;
 
-   s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
-   //if(s_chan[ch].sinc<=0x8000)
-   //     s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
+   SB[28]=(SB[28]*sinc)>>17;
+   //if(sinc<=0x8000)
+   //     SB[29]=SB[30]-(SB[28]*((0x10000/sinc)-1));
    //else
-   s_chan[ch].SB[29]+=s_chan[ch].SB[28];
+   SB[29]+=SB[28];
   }
  else                                                  // no flags? add bigger val (if possible), calc smaller step, set flag1
-  s_chan[ch].SB[29]+=s_chan[ch].SB[28];
+  SB[29]+=SB[28];
 }
 
 //
 // even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
 //
 
-INLINE void InterpolateDown(int ch)
+static void InterpolateDown(int *SB, int sinc)
 {
- if(s_chan[ch].sinc>=0x20000L)                                 // we would skip at least one val?
+ if(sinc>=0x20000L)                                 // we would skip at least one val?
   {
-   s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
-   if(s_chan[ch].sinc>=0x30000L)                               // we would skip even more vals?
-    s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
+   SB[29]+=(SB[30]-SB[29])/2;                                  // add easy weight
+   if(sinc>=0x30000L)                               // we would skip even more vals?
+    SB[29]+=(SB[31]-SB[30])/2;                                 // add additional next weight
   }
 }
 
 ////////////////////////////////////////////////////////////////////////
 // helpers for gauss interpolation
 
-#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos&3])
-#define gval(x) ((int)((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
+#define gval0 (((short*)(&SB[29]))[gpos&3])
+#define gval(x) ((int)((short*)(&SB[29]))[(gpos+x)&3])
 
 #include "gauss_i.h"
 
@@ -241,46 +225,56 @@ static int check_irq(int ch, unsigned char *pos)
 // START SOUND... called by main thread to setup a new sound on a channel
 ////////////////////////////////////////////////////////////////////////
 
-INLINE void StartSound(int ch)
+static void StartSoundSB(int *SB)
 {
- StartADSR(ch);
- StartREVERB(ch);
+ SB[26]=0;                                             // init mixing vars
+ SB[27]=0;
 
- // fussy timing issues - do in VoiceOn
- //s_chan[ch].pCurr=s_chan[ch].pStart;                   // set sample start
- //s_chan[ch].bStop=0;
- //s_chan[ch].bOn=1;
+ SB[28]=0;
+ SB[29]=0;                                             // init our interpolation helpers
+ SB[30]=0;
+ SB[31]=0;
+}
 
- s_chan[ch].SB[26]=0;                                  // init mixing vars
- s_chan[ch].SB[27]=0;
- s_chan[ch].iSBPos=27;
+static void StartSoundMain(int ch)
+{
+ SPUCHAN *s_chan = &spu.s_chan[ch];
+
+ StartADSR(ch);
+ StartREVERB(ch);
 
- s_chan[ch].SB[28]=0;
- s_chan[ch].SB[29]=0;                                  // init our interpolation helpers
- s_chan[ch].SB[30]=0;
- s_chan[ch].SB[31]=0;
- s_chan[ch].spos=0;
+ s_chan->prevflags=2;
+ s_chan->iSBPos=27;
+ s_chan->spos=0;
 
  spu.dwNewChannel&=~(1<<ch);                           // clear new channel bit
+ spu.dwChannelOn|=1<<ch;
+ spu.dwChannelDead&=~(1<<ch);
+}
+
+static void StartSound(int ch)
+{
+ StartSoundMain(ch);
+ StartSoundSB(spu.SB + ch * SB_SIZE);
 }
 
 ////////////////////////////////////////////////////////////////////////
 // ALL KIND OF HELPERS
 ////////////////////////////////////////////////////////////////////////
 
-INLINE int FModChangeFrequency(int ch,int ns)
+INLINE int FModChangeFrequency(int *SB, int pitch, int ns)
 {
- unsigned int NP=s_chan[ch].iRawPitch;
+ unsigned int NP=pitch;
  int sinc;
 
- NP=((32768L+iFMod[ns])*NP)/32768L;
+ NP=((32768L+iFMod[ns])*NP)>>15;
 
  if(NP>0x3fff) NP=0x3fff;
  if(NP<0x1)    NP=0x1;
 
  sinc=NP<<4;                                           // calc frequency
  if(spu_config.iUseInterpolation==1)                   // freq change in simple interpolation mode
-  s_chan[ch].SB[32]=1;
+  SB[32]=1;
  iFMod[ns]=0;
 
  return sinc;
@@ -288,50 +282,50 @@ INLINE int FModChangeFrequency(int ch,int ns)
 
 ////////////////////////////////////////////////////////////////////////
 
-INLINE void StoreInterpolationVal(int ch,int fa)
+INLINE void StoreInterpolationVal(int *SB, int sinc, int fa, int fmod_freq)
 {
- if(s_chan[ch].bFMod==2)                               // fmod freq channel
-  s_chan[ch].SB[29]=fa;
+ if(fmod_freq)                                         // fmod freq channel
+  SB[29]=fa;
  else
   {
    ssat32_to_16(fa);
 
    if(spu_config.iUseInterpolation>=2)                 // gauss/cubic interpolation
-    {     
-     int gpos = s_chan[ch].SB[28];
-     gval0 = fa;          
+    {
+     int gpos = SB[28];
+     gval0 = fa;
      gpos = (gpos+1) & 3;
-     s_chan[ch].SB[28] = gpos;
+     SB[28] = gpos;
     }
    else
    if(spu_config.iUseInterpolation==1)                 // simple interpolation
     {
-     s_chan[ch].SB[28] = 0;                    
-     s_chan[ch].SB[29] = s_chan[ch].SB[30];            // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour'
-     s_chan[ch].SB[30] = s_chan[ch].SB[31];
-     s_chan[ch].SB[31] = fa;
-     s_chan[ch].SB[32] = 1;                            // -> flag: calc new interolation
+     SB[28] = 0;
+     SB[29] = SB[30];                                  // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour'
+     SB[30] = SB[31];
+     SB[31] = fa;
+     SB[32] = 1;                                       // -> flag: calc new interolation
     }
-   else s_chan[ch].SB[29]=fa;                          // no interpolation
+   else SB[29]=fa;                                     // no interpolation
   }
 }
 
 ////////////////////////////////////////////////////////////////////////
 
-INLINE int iGetInterpolationVal(int ch, int spos)
+INLINE int iGetInterpolationVal(int *SB, int sinc, int spos, int fmod_freq)
 {
  int fa;
 
- if(s_chan[ch].bFMod==2) return s_chan[ch].SB[29];
+ if(fmod_freq) return SB[29];
 
  switch(spu_config.iUseInterpolation)
-  {   
+  {
    //--------------------------------------------------//
    case 3:                                             // cubic interpolation
     {
      long xd;int gpos;
      xd = (spos >> 1)+1;
-     gpos = s_chan[ch].SB[28];
+     gpos = SB[28];
 
      fa  = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
      fa *= (xd - (2<<15)) / 6;
@@ -350,7 +344,7 @@ INLINE int iGetInterpolationVal(int ch, int spos)
     {
      int vl, vr;int gpos;
      vl = (spos >> 6) & ~3;
-     gpos = s_chan[ch].SB[28];
+     gpos = SB[28];
      vr=(gauss[vl]*(int)gval0)&~2047;
      vr+=(gauss[vl+1]*gval(1))&~2047;
      vr+=(gauss[vl+2]*gval(2))&~2047;
@@ -360,15 +354,15 @@ INLINE int iGetInterpolationVal(int ch, int spos)
    //--------------------------------------------------//
    case 1:                                             // simple interpolation
     {
-     if(s_chan[ch].sinc<0x10000L)                      // -> upsampling?
-          InterpolateUp(ch);                           // --> interpolate up
-     else InterpolateDown(ch);                         // --> else down
-     fa=s_chan[ch].SB[29];
+     if(sinc<0x10000L)                                 // -> upsampling?
+          InterpolateUp(SB, sinc);                     // --> interpolate up
+     else InterpolateDown(SB, sinc);                   // --> else down
+     fa=SB[29];
     } break;
    //--------------------------------------------------//
    default:                                            // no interpolation
     {
-     fa=s_chan[ch].SB[29];                  
+     fa=SB[29];
     } break;
    //--------------------------------------------------//
   }
@@ -378,6 +372,13 @@ INLINE int iGetInterpolationVal(int ch, int spos)
 
 static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor)
 {
+ static const int f[16][2] = {
+    {    0,  0  },
+    {   60,  0  },
+    {  115, -52 },
+    {   98, -55 },
+    {  122, -60 }
+ };
  int nSample;
  int fa, s_1, s_2, d, s;
 
@@ -404,56 +405,49 @@ static void decode_block_data(int *dest, const unsigned char *src, int predict_n
  }
 }
 
-static int decode_block(int ch)
+static int decode_block(void *unused, int ch, int *SB)
 {
+ SPUCHAN *s_chan = &spu.s_chan[ch];
  unsigned char *start;
- int predict_nr,shift_factor,flags;
- int stop = 0;
+ int predict_nr, shift_factor, flags;
  int ret = 0;
 
- start = s_chan[ch].pCurr;                 // set up the current pos
- if(start == spu.spuMemC)                  // ?
-  stop = 1;
+ start = s_chan->pCurr;                    // set up the current pos
+ if (start == spu.spuMemC)                 // ?
+  ret = 1;
 
- if(s_chan[ch].prevflags&1)                // 1: stop/loop
+ if (s_chan->prevflags & 1)                // 1: stop/loop
  {
-  if(!(s_chan[ch].prevflags&2))
-   stop = 1;
+  if (!(s_chan->prevflags & 2))
+   ret = 1;
 
-  start = s_chan[ch].pLoop;
+  start = s_chan->pLoop;
  }
  else
-  ret = check_irq(ch, start);              // hack, see check_irq below..
-
- if(stop)
- {
-  spu.dwChannelOn &= ~(1<<ch);             // -> turn everything off
-  s_chan[ch].bStop = 1;
-  s_chan[ch].ADSRX.EnvelopeVol = 0;
- }
+  check_irq(ch, start);                    // hack, see check_irq below..
 
- predict_nr=(int)start[0];
- shift_factor=predict_nr&0xf;
+ predict_nr = start[0];
+ shift_factor = predict_nr & 0xf;
  predict_nr >>= 4;
 
- decode_block_data(s_chan[ch].SB, start + 2, predict_nr, shift_factor);
+ decode_block_data(SB, start + 2, predict_nr, shift_factor);
 
- flags=(int)start[1];
- if(flags&4)
-  s_chan[ch].pLoop=start;                  // loop adress
+ flags = start[1];
+ if (flags & 4)
+  s_chan->pLoop = start;                   // loop adress
 
- start+=16;
+ start += 16;
 
- if(flags&1) {                             // 1: stop/loop
-  start = s_chan[ch].pLoop;
-  ret |= check_irq(ch, start);             // hack.. :(
+ if (flags & 1) {                          // 1: stop/loop
+  start = s_chan->pLoop;
+  check_irq(ch, start);                    // hack.. :(
  }
 
  if (start - spu.spuMemC >= 0x80000)
   start = spu.spuMemC;
 
- s_chan[ch].pCurr = start;                 // store values for next cycle
- s_chan[ch].prevflags = flags;
+ s_chan->pCurr = start;                    // store values for next cycle
+ s_chan->prevflags = flags;
 
  return ret;
 }
@@ -461,23 +455,33 @@ static int decode_block(int ch)
 // do block, but ignore sample data
 static int skip_block(int ch)
 {
- unsigned char *start = s_chan[ch].pCurr;
- int flags = start[1];
- int ret = check_irq(ch, start);
+ SPUCHAN *s_chan = &spu.s_chan[ch];
+ unsigned char *start = s_chan->pCurr;
+ int flags;
+ int ret = 0;
 
- if(s_chan[ch].prevflags & 1)
-  start = s_chan[ch].pLoop;
+ if (s_chan->prevflags & 1) {
+  if (!(s_chan->prevflags & 2))
+   ret = 1;
 
- if(flags & 4)
-  s_chan[ch].pLoop = start;
+  start = s_chan->pLoop;
+ }
+ else
+  check_irq(ch, start);
+
+ flags = start[1];
+ if (flags & 4)
+  s_chan->pLoop = start;
 
  start += 16;
 
- if(flags & 1)
-  start = s_chan[ch].pLoop;
+ if (flags & 1) {
+  start = s_chan->pLoop;
+  check_irq(ch, start);
+ }
 
- s_chan[ch].pCurr = start;
- s_chan[ch].prevflags = flags;
+ s_chan->pCurr = start;
+ s_chan->prevflags = flags;
 
  return ret;
 }
@@ -485,16 +489,17 @@ static int skip_block(int ch)
 // if irq is going to trigger sooner than in upd_samples, set upd_samples
 static void scan_for_irq(int ch, unsigned int *upd_samples)
 {
+ SPUCHAN *s_chan = &spu.s_chan[ch];
  int pos, sinc, sinc_inv, end;
  unsigned char *block;
  int flags;
 
- block = s_chan[ch].pCurr;
- pos = s_chan[ch].spos;
- sinc = s_chan[ch].sinc;
+ block = s_chan->pCurr;
+ pos = s_chan->spos;
+ sinc = s_chan->sinc;
  end = pos + *upd_samples * sinc;
 
- pos += (28 - s_chan[ch].iSBPos) << 16;
+ pos += (28 - s_chan->iSBPos) << 16;
  while (pos < end)
  {
   if (block == spu.pSpuIrq)
@@ -502,7 +507,7 @@ static void scan_for_irq(int ch, unsigned int *upd_samples)
   flags = block[1];
   block += 16;
   if (flags & 1) {                          // 1: stop/loop
-   block = s_chan[ch].pLoop;
+   block = s_chan->pLoop;
    if (block == spu.pSpuIrq)                // hack.. (see decode_block)
     break;
   }
@@ -511,11 +516,11 @@ static void scan_for_irq(int ch, unsigned int *upd_samples)
 
  if (pos < end)
  {
-  sinc_inv = s_chan[ch].sinc_inv;
+  sinc_inv = s_chan->sinc_inv;
   if (sinc_inv == 0)
-   sinc_inv = s_chan[ch].sinc_inv = (0x80000000u / (uint32_t)sinc) << 1;
+   sinc_inv = s_chan->sinc_inv = (0x80000000u / (uint32_t)sinc) << 1;
 
-  pos -= s_chan[ch].spos;
+  pos -= s_chan->spos;
   *upd_samples = (((uint64_t)pos * sinc_inv) >> 32) + 1;
   //xprintf("ch%02d: irq sched: %3d %03d\n",
   // ch, *upd_samples, *upd_samples * 60 * 263 / 44100);
@@ -523,118 +528,144 @@ static void scan_for_irq(int ch, unsigned int *upd_samples)
 }
 
 #define make_do_samples(name, fmod_code, interp_start, interp1_code, interp2_code, interp_end) \
-static noinline int do_samples_##name(int ch, int ns, int ns_to) \
+static noinline int do_samples_##name( \
+ int (*decode_f)(void *context, int ch, int *SB), void *ctx, \
+ int ch, int ns_to, int *SB, int sinc, int *spos, int *sbpos) \
 {                                            \
- int sinc = s_chan[ch].sinc;                 \
- int spos = s_chan[ch].spos;                 \
- int sbpos = s_chan[ch].iSBPos;              \
- int *SB = s_chan[ch].SB;                    \
- int ret = -1;                               \
- int d, fa;                                  \
+ int ns, d, fa;                              \
+ int ret = ns_to;                            \
  interp_start;                               \
                                              \
- for (; ns < ns_to; ns++)                    \
+ for (ns = 0; ns < ns_to; ns++)              \
  {                                           \
   fmod_code;                                 \
                                              \
-  spos += sinc;                              \
-  while (spos >= 0x10000)                    \
+  *spos += sinc;                             \
+  while (*spos >= 0x10000)                   \
   {                                          \
-   fa = SB[sbpos++];                         \
-   if(sbpos >= 28)                           \
+   fa = SB[(*sbpos)++];                      \
+   if (*sbpos >= 28)                         \
    {                                         \
-    sbpos = 0;                               \
-    d = decode_block(ch);                    \
-    if(d)                                    \
-     ret = /*ns_to =*/ ns + 1;               \
+    *sbpos = 0;                              \
+    d = decode_f(ctx, ch, SB);               \
+    if (d && ns < ret)                       \
+     ret = ns;                               \
    }                                         \
                                              \
    interp1_code;                             \
-   spos -= 0x10000;                          \
+   *spos -= 0x10000;                         \
   }                                          \
                                              \
   interp2_code;                              \
  }                                           \
                                              \
- s_chan[ch].sinc = sinc;                     \
- s_chan[ch].spos = spos;                     \
- s_chan[ch].iSBPos = sbpos;                  \
  interp_end;                                 \
                                              \
  return ret;                                 \
 }
 
 #define fmod_recv_check \
-  if(s_chan[ch].bFMod==1 && iFMod[ns]) \
-    sinc = FModChangeFrequency(ch,ns)
+  if(spu.s_chan[ch].bFMod==1 && iFMod[ns]) \
+    sinc = FModChangeFrequency(SB, spu.s_chan[ch].iRawPitch, ns)
 
 make_do_samples(default, fmod_recv_check, ,
-  StoreInterpolationVal(ch, fa),
-  ChanBuf[ns] = iGetInterpolationVal(ch, spos), )
-make_do_samples(noint, , fa = s_chan[ch].SB[29], , ChanBuf[ns] = fa, s_chan[ch].SB[29] = fa)
+  StoreInterpolationVal(SB, sinc, fa, spu.s_chan[ch].bFMod==2),
+  ChanBuf[ns] = iGetInterpolationVal(SB, sinc, *spos, spu.s_chan[ch].bFMod==2), )
+make_do_samples(noint, , fa = SB[29], , ChanBuf[ns] = fa, SB[29] = fa)
 
 #define simple_interp_store \
-  s_chan[ch].SB[28] = 0; \
-  s_chan[ch].SB[29] = s_chan[ch].SB[30]; \
-  s_chan[ch].SB[30] = s_chan[ch].SB[31]; \
-  s_chan[ch].SB[31] = fa; \
-  s_chan[ch].SB[32] = 1
+  SB[28] = 0; \
+  SB[29] = SB[30]; \
+  SB[30] = SB[31]; \
+  SB[31] = fa; \
+  SB[32] = 1
 
 #define simple_interp_get \
-  if(sinc<0x10000)          /* -> upsampling? */ \
-       InterpolateUp(ch);   /* --> interpolate up */ \
-  else InterpolateDown(ch); /* --> else down */ \
-  ChanBuf[ns] = s_chan[ch].SB[29]
+  if(sinc<0x10000)                /* -> upsampling? */ \
+       InterpolateUp(SB, sinc);   /* --> interpolate up */ \
+  else InterpolateDown(SB, sinc); /* --> else down */ \
+  ChanBuf[ns] = SB[29]
 
 make_do_samples(simple, , ,
   simple_interp_store, simple_interp_get, )
 
-static noinline int do_samples_noise(int ch, int ns, int ns_to)
+static int do_samples_skip(int ch, int ns_to)
 {
- int level, shift, bit;
- int ret = -1, d;
+ SPUCHAN *s_chan = &spu.s_chan[ch];
+ int spos = s_chan->spos;
+ int sinc = s_chan->sinc;
+ int ret = ns_to, ns, d;
+
+ spos += s_chan->iSBPos << 16;
 
- s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns);
- while (s_chan[ch].spos >= 28*0x10000)
+ for (ns = 0; ns < ns_to; ns++)
  {
-  d = skip_block(ch);
-  if (d)
-   ret = ns_to;
-  s_chan[ch].spos -= 28*0x10000;
+  spos += sinc;
+  while (spos >= 28*0x10000)
+  {
+   d = skip_block(ch);
+   if (d && ns < ret)
+    ret = ns;
+   spos -= 28*0x10000;
+  }
  }
 
+ s_chan->iSBPos = spos >> 16;
+ s_chan->spos = spos & 0xffff;
+
+ return ret;
+}
+
+static void do_lsfr_samples(int ns_to, int ctrl,
+ unsigned int *dwNoiseCount, unsigned int *dwNoiseVal)
+{
+ unsigned int counter = *dwNoiseCount;
+ unsigned int val = *dwNoiseVal;
+ unsigned int level, shift, bit;
+ int ns;
+
  // modified from DrHell/shalma, no fraction
- level = (spu.spuCtrl >> 10) & 0x0f;
+ level = (ctrl >> 10) & 0x0f;
  level = 0x8000 >> level;
 
- for (; ns < ns_to; ns++)
+ for (ns = 0; ns < ns_to; ns++)
  {
-  spu.dwNoiseCount += 2;
-  if (spu.dwNoiseCount >= level)
+  counter += 2;
+  if (counter >= level)
   {
-   spu.dwNoiseCount -= level;
-   shift = (spu.dwNoiseVal >> 10) & 0x1f;
+   counter -= level;
+   shift = (val >> 10) & 0x1f;
    bit = (0x69696969 >> shift) & 1;
-   if (spu.dwNoiseVal & 0x8000)
-    bit ^= 1;
-   spu.dwNoiseVal = (spu.dwNoiseVal << 1) | bit;
+   bit ^= (val >> 15) & 1;
+   val = (val << 1) | bit;
   }
 
-  ChanBuf[ns] = (signed short)spu.dwNoiseVal;
+  ChanBuf[ns] = (signed short)val;
  }
 
+ *dwNoiseCount = counter;
+ *dwNoiseVal = val;
+}
+
+static int do_samples_noise(int ch, int ns_to)
+{
+ int ret;
+
+ ret = do_samples_skip(ch, ns_to);
+
+ do_lsfr_samples(ns_to, spu.spuCtrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
+
  return ret;
 }
 
 #ifdef HAVE_ARMV5
 // asm code; lv and rv must be 0-3fff
-extern void mix_chan(int start, int count, int lv, int rv);
-extern void mix_chan_rvb(int start, int count, int lv, int rv, int *rvb);
+extern void mix_chan(int *SSumLR, int count, int lv, int rv);
+extern void mix_chan_rvb(int *SSumLR, int count, int lv, int rv, int *rvb);
 #else
-static void mix_chan(int start, int count, int lv, int rv)
+static void mix_chan(int *SSumLR, int count, int lv, int rv)
 {
- int *dst = SSumLR + start * 2;
- const int *src = ChanBuf + start;
+ const int *src = ChanBuf;
  int l, r;
 
  while (count--)
@@ -643,16 +674,16 @@ static void mix_chan(int start, int count, int lv, int rv)
 
    l = (sval * lv) >> 14;
    r = (sval * rv) >> 14;
-   *dst++ += l;
-   *dst++ += r;
+   *SSumLR++ += l;
+   *SSumLR++ += r;
   }
 }
 
-static void mix_chan_rvb(int start, int count, int lv, int rv, int *rvb)
+static void mix_chan_rvb(int *SSumLR, int count, int lv, int rv, int *rvb)
 {
int *dst = SSumLR + start * 2;
- int *drvb = rvb + start * 2;
const int *src = ChanBuf + start;
const int *src = ChanBuf;
+ int *dst = SSumLR;
int *drvb = rvb;
  int l, r;
 
  while (count--)
@@ -671,11 +702,12 @@ static void mix_chan_rvb(int start, int count, int lv, int rv, int *rvb)
 
 // 0x0800-0x0bff  Voice 1
 // 0x0c00-0x0fff  Voice 3
-static noinline void do_decode_bufs(int which, int start, int count)
+static noinline void do_decode_bufs(unsigned short *mem, int which,
+ int count, int decode_pos)
 {
const int *src = ChanBuf + start;
unsigned short *dst = &spu.spuMem[0x800/2 + which*0x400/2];
- int cursor = spu.decode_pos + start;
unsigned short *dst = &mem[0x800/2 + which*0x400/2];
const int *src = ChanBuf;
+ int cursor = decode_pos;
 
  while (count-- > 0)
   {
@@ -687,19 +719,383 @@ static noinline void do_decode_bufs(int which, int start, int count)
  // decode_pos is updated and irqs are checked later, after voice loop
 }
 
+static void do_silent_chans(int ns_to, int silentch)
+{
+ unsigned int mask;
+ SPUCHAN *s_chan;
+ int ch;
+
+ mask = silentch & 0xffffff;
+ for (ch = 0; mask != 0; ch++, mask >>= 1)
+  {
+   if (!(mask & 1)) continue;
+   if (spu.dwChannelDead & (1<<ch)) continue;
+
+   s_chan = &spu.s_chan[ch];
+   if (s_chan->pCurr > spu.pSpuIrq && s_chan->pLoop > spu.pSpuIrq)
+    continue;
+
+   s_chan->spos += s_chan->iSBPos << 16;
+   s_chan->iSBPos = 0;
+
+   s_chan->spos += s_chan->sinc * ns_to;
+   while (s_chan->spos >= 28 * 0x10000)
+    {
+     unsigned char *start = s_chan->pCurr;
+
+     skip_block(ch);
+     if (start == s_chan->pCurr || start - spu.spuMemC < 0x1000)
+      {
+       // looping on self or stopped(?)
+       spu.dwChannelDead |= 1<<ch;
+       s_chan->spos = 0;
+       break;
+      }
+
+     s_chan->spos -= 28 * 0x10000;
+    }
+  }
+}
+
+static void do_channels(int ns_to)
+{
+ unsigned int mask;
+ int do_rvb, ch, d;
+ SPUCHAN *s_chan;
+ int *SB, sinc;
+
+ do_rvb = spu.rvb->StartAddr && spu_config.iUseReverb;
+ if (do_rvb)
+  memset(RVB, 0, ns_to * sizeof(RVB[0]) * 2);
+
+ mask = spu.dwNewChannel & 0xffffff;
+ for (ch = 0; mask != 0; ch++, mask >>= 1) {
+  if (mask & 1)
+   StartSound(ch);
+ }
+
+ mask = spu.dwChannelOn & 0xffffff;
+ for (ch = 0; mask != 0; ch++, mask >>= 1)         // loop em all...
+  {
+   if (!(mask & 1)) continue;                      // channel not playing? next
+
+   s_chan = &spu.s_chan[ch];
+   SB = spu.SB + ch * SB_SIZE;
+   sinc = s_chan->sinc;
+
+   if (s_chan->bNoise)
+    d = do_samples_noise(ch, ns_to);
+   else if (s_chan->bFMod == 2
+         || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0))
+    d = do_samples_noint(decode_block, NULL, ch, ns_to,
+          SB, sinc, &s_chan->spos, &s_chan->iSBPos);
+   else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1)
+    d = do_samples_simple(decode_block, NULL, ch, ns_to,
+          SB, sinc, &s_chan->spos, &s_chan->iSBPos);
+   else
+    d = do_samples_default(decode_block, NULL, ch, ns_to,
+          SB, sinc, &s_chan->spos, &s_chan->iSBPos);
+
+   d = MixADSR(&s_chan->ADSRX, d);
+   if (d < ns_to) {
+    spu.dwChannelOn &= ~(1 << ch);
+    s_chan->ADSRX.EnvelopeVol = 0;
+    memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
+   }
+
+   if (ch == 1 || ch == 3)
+    {
+     do_decode_bufs(spu.spuMem, ch/2, ns_to, spu.decode_pos);
+     spu.decode_dirty_ch |= 1 << ch;
+    }
+
+   if (s_chan->bFMod == 2)                         // fmod freq channel
+    memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0]));
+   if (s_chan->bRVBActive && do_rvb)
+    mix_chan_rvb(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, RVB);
+   else
+    mix_chan(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume);
+  }
+
+  if (spu.rvb->StartAddr) {
+   if (do_rvb) {
+    if (unlikely(spu.rvb->dirty))
+     REVERBPrep();
+
+    REVERBDo(spu.SSumLR, RVB, ns_to, spu.rvb->CurrAddr);
+   }
+
+   spu.rvb->CurrAddr += ns_to / 2;
+   while (spu.rvb->CurrAddr >= 0x40000)
+    spu.rvb->CurrAddr -= 0x40000 - spu.rvb->StartAddr;
+  }
+}
+
+static void do_samples_finish(int *SSumLR, int ns_to,
+ int silentch, int decode_pos);
+
+// optional worker thread handling
+
+#if defined(THREAD_ENABLED) || defined(WANT_THREAD_CODE)
+
+// worker thread state
+static struct spu_worker {
+ union {
+  struct {
+   unsigned int exit_thread;
+   unsigned int i_ready;
+   unsigned int i_reaped;
+   unsigned int last_boot_cnt; // dsp
+  };
+  // aligning for C64X_DSP
+  unsigned int _pad0[128/4];
+ };
+ union {
+  struct {
+   unsigned int i_done;
+   unsigned int active; // dsp
+   unsigned int boot_cnt;
+  };
+  unsigned int _pad1[128/4];
+ };
+ struct work_item {
+  int ns_to;
+  int ctrl;
+  int decode_pos;
+  int rvb_addr;
+  unsigned int channels_new;
+  unsigned int channels_on;
+  unsigned int channels_silent;
+  struct {
+   int spos;
+   int sbpos;
+   int sinc;
+   int start;
+   int loop;
+   int ns_to;
+   short vol_l;
+   short vol_r;
+   ADSRInfoEx adsr;
+   // might also want to add fmod flags..
+  } ch[24];
+  int SSumLR[NSSIZE * 2];
+ } i[4];
+} *worker;
+
+#define WORK_MAXCNT (sizeof(worker->i) / sizeof(worker->i[0]))
+#define WORK_I_MASK (WORK_MAXCNT - 1)
+
+static void thread_work_start(void);
+static void thread_work_wait_sync(struct work_item *work, int force);
+static void thread_sync_caches(void);
+static int  thread_get_i_done(void);
+
+static int decode_block_work(void *context, int ch, int *SB)
+{
+ const unsigned char *ram = spu.spuMemC;
+ int predict_nr, shift_factor, flags;
+ struct work_item *work = context;
+ int start = work->ch[ch].start;
+ int loop = work->ch[ch].loop;
+
+ predict_nr = ram[start];
+ shift_factor = predict_nr & 0xf;
+ predict_nr >>= 4;
+
+ decode_block_data(SB, ram + start + 2, predict_nr, shift_factor);
+
+ flags = ram[start + 1];
+ if (flags & 4)
+  loop = start;                            // loop adress
+
+ start += 16;
+
+ if (flags & 1)                            // 1: stop/loop
+  start = loop;
+
+ work->ch[ch].start = start & 0x7ffff;
+ work->ch[ch].loop = loop;
+
+ return 0;
+}
+
+static void queue_channel_work(int ns_to, unsigned int silentch)
+{
+ struct work_item *work;
+ SPUCHAN *s_chan;
+ unsigned int mask;
+ int ch, d;
+
+ work = &worker->i[worker->i_ready & WORK_I_MASK];
+ work->ns_to = ns_to;
+ work->ctrl = spu.spuCtrl;
+ work->decode_pos = spu.decode_pos;
+ work->channels_silent = silentch;
+
+ mask = work->channels_new = spu.dwNewChannel & 0xffffff;
+ for (ch = 0; mask != 0; ch++, mask >>= 1) {
+  if (mask & 1)
+   StartSoundMain(ch);
+ }
+
+ mask = work->channels_on = spu.dwChannelOn & 0xffffff;
+ spu.decode_dirty_ch |= mask & 0x0a;
+
+ for (ch = 0; mask != 0; ch++, mask >>= 1)
+  {
+   if (!(mask & 1)) continue;
+
+   s_chan = &spu.s_chan[ch];
+   work->ch[ch].spos = s_chan->spos;
+   work->ch[ch].sbpos = s_chan->iSBPos;
+   work->ch[ch].sinc = s_chan->sinc;
+   work->ch[ch].adsr = s_chan->ADSRX;
+   work->ch[ch].vol_l = s_chan->iLeftVolume;
+   work->ch[ch].vol_r = s_chan->iRightVolume;
+   work->ch[ch].start = s_chan->pCurr - spu.spuMemC;
+   work->ch[ch].loop = s_chan->pLoop - spu.spuMemC;
+   if (s_chan->prevflags & 1)
+    work->ch[ch].start = work->ch[ch].loop;
+
+   d = do_samples_skip(ch, ns_to);
+   work->ch[ch].ns_to = d;
+
+   // note: d is not accurate on skip
+   d = SkipADSR(&s_chan->ADSRX, d);
+   if (d < ns_to) {
+    spu.dwChannelOn &= ~(1 << ch);
+    s_chan->ADSRX.EnvelopeVol = 0;
+   }
+  }
+
+ work->rvb_addr = 0;
+ if (spu.rvb->StartAddr) {
+  if (spu_config.iUseReverb) {
+   if (unlikely(spu.rvb->dirty))
+    REVERBPrep();
+   work->rvb_addr = spu.rvb->CurrAddr;
+  }
+
+  spu.rvb->CurrAddr += ns_to / 2;
+  while (spu.rvb->CurrAddr >= 0x40000)
+   spu.rvb->CurrAddr -= 0x40000 - spu.rvb->StartAddr;
+ }
+
+ worker->i_ready++;
+ thread_work_start();
+}
+
+static void do_channel_work(struct work_item *work)
+{
+ unsigned int mask;
+ unsigned int decode_dirty_ch = 0;
+ int *SB, sinc, spos, sbpos;
+ int d, ch, ns_to;
+ SPUCHAN *s_chan;
+
+ ns_to = work->ns_to;
+
+ if (work->rvb_addr)
+  memset(RVB, 0, ns_to * sizeof(RVB[0]) * 2);
+
+ mask = work->channels_new;
+ for (ch = 0; mask != 0; ch++, mask >>= 1) {
+  if (mask & 1)
+   StartSoundSB(spu.SB + ch * SB_SIZE);
+ }
+
+ mask = work->channels_on;
+ for (ch = 0; mask != 0; ch++, mask >>= 1)
+  {
+   if (!(mask & 1)) continue;
+
+   d = work->ch[ch].ns_to;
+   spos = work->ch[ch].spos;
+   sbpos = work->ch[ch].sbpos;
+   sinc = work->ch[ch].sinc;
+
+   s_chan = &spu.s_chan[ch];
+   SB = spu.SB + ch * SB_SIZE;
+
+   if (s_chan->bNoise)
+    do_lsfr_samples(d, work->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
+   else if (s_chan->bFMod == 2
+         || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0))
+    do_samples_noint(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos);
+   else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1)
+    do_samples_simple(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos);
+   else
+    do_samples_default(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos);
+
+   d = MixADSR(&work->ch[ch].adsr, d);
+   if (d < ns_to) {
+    work->ch[ch].adsr.EnvelopeVol = 0;
+    memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
+   }
+
+   if (ch == 1 || ch == 3)
+    {
+     do_decode_bufs(spu.spuMem, ch/2, ns_to, work->decode_pos);
+     decode_dirty_ch |= 1 << ch;
+    }
+
+   if (s_chan->bFMod == 2)                         // fmod freq channel
+    memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0]));
+   if (s_chan->bRVBActive && work->rvb_addr)
+    mix_chan_rvb(work->SSumLR, ns_to,
+      work->ch[ch].vol_l, work->ch[ch].vol_r, RVB);
+   else
+    mix_chan(work->SSumLR, ns_to, work->ch[ch].vol_l, work->ch[ch].vol_r);
+  }
+
+  if (work->rvb_addr)
+   REVERBDo(work->SSumLR, RVB, ns_to, work->rvb_addr);
+}
+
+static void sync_worker_thread(int force)
+{
+ struct work_item *work;
+ int done, used_space;
+
+ done = thread_get_i_done() - worker->i_reaped;
+ used_space = worker->i_ready - worker->i_reaped;
+ //printf("done: %d use: %d dsp: %u/%u\n", done, used_space,
+ //  worker->boot_cnt, worker->i_done);
+
+ while ((force && used_space > 0) || used_space >= WORK_MAXCNT || done > 0) {
+  work = &worker->i[worker->i_reaped & WORK_I_MASK];
+  thread_work_wait_sync(work, force);
+
+  do_samples_finish(work->SSumLR, work->ns_to,
+   work->channels_silent, work->decode_pos);
+
+  worker->i_reaped++;
+  done = thread_get_i_done() - worker->i_reaped;
+  used_space = worker->i_ready - worker->i_reaped;
+ }
+ if (force)
+  thread_sync_caches();
+}
+
+#else
+
+static void queue_channel_work(int ns_to, int silentch) {}
+static void sync_worker_thread(int force) {}
+
+static const void * const worker = NULL;
+
+#endif // THREAD_ENABLED
+
 ////////////////////////////////////////////////////////////////////////
 // MAIN SPU FUNCTION
 // here is the main job handler...
-// basically the whole sound processing is done in this fat func!
 ////////////////////////////////////////////////////////////////////////
 
-void do_samples(unsigned int cycles_to)
+void do_samples(unsigned int cycles_to, int do_direct)
 {
- const int ns_from = 0;
- int ns,ns_to,ns_len;
- int volmult = spu_config.iVolume;
- int ch,d,silentch;
+ unsigned int silentch;
  int cycle_diff;
+ int ns_to;
 
  cycle_diff = cycles_to - spu.cycles_played;
  if (cycle_diff < -2*1048576 || cycle_diff > 2*1048576)
@@ -709,6 +1105,12 @@ void do_samples(unsigned int cycles_to)
    return;
   }
 
+ silentch = ~(spu.dwChannelOn | spu.dwNewChannel) & 0xffffff;
+
+ do_direct |= (silentch == 0xffffff);
+ if (worker != NULL)
+  sync_worker_thread(do_direct);
+
  if (cycle_diff < 2 * 768)
   return;
 
@@ -748,77 +1150,32 @@ void do_samples(unsigned int cycles_to)
      }
    }
 
-  InitREVERB(ns_to);
+  if (do_direct || worker == NULL || !spu_config.iUseThread) {
+   do_channels(ns_to);
+   do_samples_finish(spu.SSumLR, ns_to, silentch, spu.decode_pos);
+  }
+  else {
+   queue_channel_work(ns_to, silentch);
+  }
 
-  {
-   silentch=~(spu.dwChannelOn|spu.dwNewChannel);
+  // advance "stopped" channels that can cause irqs
+  // (all chans are always playing on the real thing..)
+  if (spu.spuCtrl & CTRL_IRQ)
+   do_silent_chans(ns_to, silentch);
 
-   //--------------------------------------------------//
-   //- main channel loop                              -// 
-   //--------------------------------------------------//
-    {
-     for(ch=0;ch<MAXCHAN;ch++)                         // loop em all...
-      {
-       if(spu.dwNewChannel&(1<<ch)) StartSound(ch);    // start new sound
-       if(!(spu.dwChannelOn&(1<<ch))) continue;        // channel not playing? next
-
-       if(s_chan[ch].bNoise)
-        do_samples_noise(ch, ns_from, ns_to);
-       else if(s_chan[ch].bFMod==2 || (s_chan[ch].bFMod==0 && spu_config.iUseInterpolation==0))
-        do_samples_noint(ch, ns_from, ns_to);
-       else if(s_chan[ch].bFMod==0 && spu_config.iUseInterpolation==1)
-        do_samples_simple(ch, ns_from, ns_to);
-       else
-        do_samples_default(ch, ns_from, ns_to);
-
-       ns_len = ns_to - ns_from;
-
-       MixADSR(ch, ns_from, ns_to);
-
-       if(ch==1 || ch==3)
-        {
-         do_decode_bufs(ch/2, ns_from, ns_len);
-         spu.decode_dirty_ch |= 1<<ch;
-        }
-
-       if(s_chan[ch].bFMod==2)                         // fmod freq channel
-        memcpy(&iFMod[ns_from], &ChanBuf[ns_from], ns_len * sizeof(iFMod[0]));
-       if(s_chan[ch].bRVBActive)
-        mix_chan_rvb(ns_from, ns_len, s_chan[ch].iLeftVolume, s_chan[ch].iRightVolume, spu.sRVBStart);
-       else
-        mix_chan(ns_from, ns_len, s_chan[ch].iLeftVolume, s_chan[ch].iRightVolume);
-      }
-    }
+  spu.cycles_played += ns_to * 768;
+  spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff;
+}
 
-    // advance "stopped" channels that can cause irqs
-    // (all chans are always playing on the real thing..)
-    if(spu.spuCtrl&CTRL_IRQ)
-     for(ch=0;ch<MAXCHAN;ch++)
-      {
-       if(!(silentch&(1<<ch))) continue;               // already handled
-       if(spu.dwChannelDead&(1<<ch)) continue;
-       if(s_chan[ch].pCurr > spu.pSpuIrq && s_chan[ch].pLoop > spu.pSpuIrq)
-        continue;
-
-       s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns_from);
-       while(s_chan[ch].spos >= 28 * 0x10000)
-        {
-         unsigned char *start = s_chan[ch].pCurr;
-
-         skip_block(ch);
-         if(start == s_chan[ch].pCurr || start - spu.spuMemC < 0x1000)
-          {
-           // looping on self or stopped(?)
-           spu.dwChannelDead |= 1<<ch;
-           s_chan[ch].spos = 0;
-           break;
-          }
-
-         s_chan[ch].spos -= 28 * 0x10000;
-        }
-      }
+static void do_samples_finish(int *SSumLR, int ns_to,
+ int silentch, int decode_pos)
+{
+  int volmult = spu_config.iVolume;
+  int ns;
+  int d;
 
-  if(unlikely(silentch & spu.decode_dirty_ch & (1<<1))) // must clear silent channel decode buffers
+  // must clear silent channel decode buffers
+  if(unlikely(silentch & spu.decode_dirty_ch & (1<<1)))
    {
     memset(&spu.spuMem[0x800/2], 0, 0x400);
     spu.decode_dirty_ch &= ~(1<<1);
@@ -829,17 +1186,8 @@ void do_samples(unsigned int cycles_to)
     spu.decode_dirty_ch &= ~(1<<3);
    }
 
-  //---------------------------------------------------//
-  // mix XA infos (if any)
-
-  MixXA(ns_to);
+  MixXA(SSumLR, ns_to, decode_pos);
   
-  ///////////////////////////////////////////////////////
-  // mix all channels (including reverb) into one buffer
-
-  if(spu_config.iUseReverb)
-   REVERBDo(ns_to);
-
   if((spu.spuCtrl&0x4000)==0) // muted? (rare, don't optimize for this)
    {
     memset(spu.pS, 0, ns_to * 2 * sizeof(spu.pS[0]));
@@ -860,11 +1208,6 @@ void do_samples(unsigned int cycles_to)
     *spu.pS++ = d;
     ns++;
    }
-
-  spu.cycles_played += ns_to * 768;
-
-  spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff;
- }
 }
 
 void schedule_next_irq(void)
@@ -881,8 +1224,8 @@ void schedule_next_irq(void)
  {
   if (spu.dwChannelDead & (1 << ch))
    continue;
-  if ((unsigned long)(spu.pSpuIrq - s_chan[ch].pCurr) > IRQ_NEAR_BLOCKS * 16
-    && (unsigned long)(spu.pSpuIrq - s_chan[ch].pLoop) > IRQ_NEAR_BLOCKS * 16)
+  if ((unsigned long)(spu.pSpuIrq - spu.s_chan[ch].pCurr) > IRQ_NEAR_BLOCKS * 16
+    && (unsigned long)(spu.pSpuIrq - spu.s_chan[ch].pLoop) > IRQ_NEAR_BLOCKS * 16)
    continue;
 
   scan_for_irq(ch, &upd_samples);
@@ -909,7 +1252,7 @@ void schedule_next_irq(void)
 
 void CALLBACK SPUasync(unsigned int cycle, unsigned int flags)
 {
- do_samples(cycle);
+ do_samples(cycle, 0);
 
  if (spu.spuCtrl & CTRL_IRQ)
   schedule_next_irq();
@@ -962,19 +1305,15 @@ int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
 // to be called after state load
 void ClearWorkingState(void)
 {
- memset(SSumLR,0,sizeof(SSumLR));                      // init some mixing buffers
- memset(iFMod,0,sizeof(iFMod));     
+ memset(iFMod, 0, sizeof(iFMod));
  spu.pS=(short *)spu.pSpuBuffer;                       // setup soundbuffer pointer
 }
 
 // SETUPSTREAMS: init most of the spu buffers
-void SetupStreams(void)
+static void SetupStreams(void)
 { 
- int i;
-
  spu.pSpuBuffer = (unsigned char *)malloc(32768);      // alloc mixing buffer
- spu.sRVBStart = (int *)malloc(NSSIZE*2*4);            // alloc reverb buffer
- memset(spu.sRVBStart,0,NSSIZE*2*4);
+ spu.SSumLR = calloc(NSSIZE * 2, sizeof(spu.SSumLR[0]));
 
  spu.XAStart =                                         // alloc xa buffer
   (uint32_t *)malloc(44100 * sizeof(uint32_t));
@@ -988,44 +1327,152 @@ void SetupStreams(void)
  spu.CDDAPlay  = spu.CDDAStart;
  spu.CDDAFeed  = spu.CDDAStart;
 
- for(i=0;i<MAXCHAN;i++)                                // loop sound channels
-  {
-   s_chan[i].ADSRX.SustainLevel = 0xf;                 // -> init sustain
-   s_chan[i].ADSRX.SustainIncrease = 1;
-   s_chan[i].pLoop=spu.spuMemC;
-   s_chan[i].pCurr=spu.spuMemC;
-  }
-
  ClearWorkingState();
-
- spu.bSpuInit=1;                                       // flag: we are inited
 }
 
 // REMOVESTREAMS: free most buffer
-void RemoveStreams(void)
+static void RemoveStreams(void)
 { 
  free(spu.pSpuBuffer);                                 // free mixing buffer
  spu.pSpuBuffer = NULL;
- free(spu.sRVBStart);                                  // free reverb buffer
- spu.sRVBStart = NULL;
+ free(spu.SSumLR);
+ spu.SSumLR = NULL;
  free(spu.XAStart);                                    // free XA buffer
  spu.XAStart = NULL;
  free(spu.CDDAStart);                                  // free CDDA buffer
  spu.CDDAStart = NULL;
 }
 
-// INIT/EXIT STUFF
+#if defined(C64X_DSP)
+
+/* special code for TI C64x DSP */
+#include "spu_c64x.c"
+
+#elif defined(THREAD_ENABLED)
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>
+
+static struct {
+ pthread_t thread;
+ sem_t sem_avail;
+ sem_t sem_done;
+} t;
+
+/* generic pthread implementation */
+
+static void thread_work_start(void)
+{
+ sem_post(&t.sem_avail);
+}
+
+static void thread_work_wait_sync(struct work_item *work, int force)
+{
+ sem_wait(&t.sem_done);
+}
+
+static int thread_get_i_done(void)
+{
+ return worker->i_done;
+}
+
+static void thread_sync_caches(void)
+{
+}
+
+static void *spu_worker_thread(void *unused)
+{
+ struct work_item *work;
+
+ while (1) {
+  sem_wait(&t.sem_avail);
+  if (worker->exit_thread)
+   break;
+
+  work = &worker->i[worker->i_done & WORK_I_MASK];
+  do_channel_work(work);
+  worker->i_done++;
+
+  sem_post(&t.sem_done);
+ }
+
+ return NULL;
+}
+
+static void init_spu_thread(void)
+{
+ int ret;
+
+ if (sysconf(_SC_NPROCESSORS_ONLN) <= 1)
+  return;
+
+ worker = calloc(1, sizeof(*worker));
+ if (worker == NULL)
+  return;
+ ret = sem_init(&t.sem_avail, 0, 0);
+ if (ret != 0)
+  goto fail_sem_avail;
+ ret = sem_init(&t.sem_done, 0, 0);
+ if (ret != 0)
+  goto fail_sem_done;
+
+ ret = pthread_create(&t.thread, NULL, spu_worker_thread, NULL);
+ if (ret != 0)
+  goto fail_thread;
+
+ spu_config.iThreadAvail = 1;
+ return;
+
+fail_thread:
+ sem_destroy(&t.sem_done);
+fail_sem_done:
+ sem_destroy(&t.sem_avail);
+fail_sem_avail:
+ free(worker);
+ worker = NULL;
+ spu_config.iThreadAvail = 0;
+}
+
+static void exit_spu_thread(void)
+{
+ if (worker == NULL)
+  return;
+ worker->exit_thread = 1;
+ sem_post(&t.sem_avail);
+ pthread_join(t.thread, NULL);
+ sem_destroy(&t.sem_done);
+ sem_destroy(&t.sem_avail);
+ free(worker);
+ worker = NULL;
+}
+
+#else // if !THREAD_ENABLED
+
+static void init_spu_thread(void)
+{
+}
+
+static void exit_spu_thread(void)
+{
+}
+
+#endif
 
 // SPUINIT: this func will be called first by the main emu
 long CALLBACK SPUinit(void)
 {
- spu.spuMemC = (unsigned char *)spu.spuMem;            // just small setup
- memset((void *)&rvb, 0, sizeof(REVERBInfo));
+ int i;
+
+ spu.spuMemC = calloc(1, 512 * 1024);
  InitADSR();
 
- spu.spuAddr = 0xffffffff;
+ spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling)
+ spu.rvb = calloc(1, sizeof(REVERBInfo));
+ spu.SB = calloc(MAXCHAN, sizeof(spu.SB[0]) * SB_SIZE);
+
+ spu.spuAddr = 0;
  spu.decode_pos = 0;
- memset((void *)s_chan, 0, sizeof(s_chan));
  spu.pSpuIrq = spu.spuMemC;
 
  SetupStreams();                                       // prepare streaming
@@ -1033,6 +1480,18 @@ long CALLBACK SPUinit(void)
  if (spu_config.iVolume == 0)
   spu_config.iVolume = 768; // 1024 is 1.0
 
+ init_spu_thread();
+
+ for (i = 0; i < MAXCHAN; i++)                         // loop sound channels
+  {
+   spu.s_chan[i].ADSRX.SustainLevel = 0xf;             // -> init sustain
+   spu.s_chan[i].ADSRX.SustainIncrease = 1;
+   spu.s_chan[i].pLoop = spu.spuMemC;
+   spu.s_chan[i].pCurr = spu.spuMemC;
+  }
+
+ spu.bSpuInit=1;                                       // flag: we are inited
+
  return 0;
 }
 
@@ -1064,6 +1523,18 @@ long CALLBACK SPUclose(void)
 long CALLBACK SPUshutdown(void)
 {
  SPUclose();
+
+ exit_spu_thread();
+
+ free(spu.spuMemC);
+ spu.spuMemC = NULL;
+ free(spu.SB);
+ spu.SB = NULL;
+ free(spu.s_chan);
+ spu.s_chan = NULL;
+ free(spu.rvb);
+ spu.rvb = NULL;
+
  RemoveStreams();                                      // no more streaming
  spu.bSpuInit=0;
 
@@ -1143,15 +1614,18 @@ void spu_get_debug_info(int *chans_out, int *run_chans, int *fmod_chans_out, int
 {
  int ch = 0, fmod_chans = 0, noise_chans = 0, irq_chans = 0;
 
+ if (spu.s_chan == NULL)
+  return;
+
  for(;ch<MAXCHAN;ch++)
  {
   if (!(spu.dwChannelOn & (1<<ch)))
    continue;
-  if (s_chan[ch].bFMod == 2)
+  if (spu.s_chan[ch].bFMod == 2)
    fmod_chans |= 1 << ch;
-  if (s_chan[ch].bNoise)
+  if (spu.s_chan[ch].bNoise)
    noise_chans |= 1 << ch;
-  if((spu.spuCtrl&CTRL_IRQ) && s_chan[ch].pCurr <= spu.pSpuIrq && s_chan[ch].pLoop <= spu.pSpuIrq)
+  if((spu.spuCtrl&CTRL_IRQ) && spu.s_chan[ch].pCurr <= spu.pSpuIrq && spu.s_chan[ch].pLoop <= spu.pSpuIrq)
    irq_chans |= 1 << ch;
  }
 
diff --git a/plugins/dfsound/spu_c64x.c b/plugins/dfsound/spu_c64x.c
new file mode 100644 (file)
index 0000000..be10a6b
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * SPU processing offload to TI C64x DSP using bsp's c64_tools
+ * (C) GraÅžvydas "notaz" Ignotas, 2015
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy of
+ *  this software and associated documentation files (the "Software"), to deal in
+ *  the Software without restriction, including without limitation the rights to
+ *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ *  of the Software, and to permit persons to whom the Software is furnished to do
+ *  so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <inc_libc64_mini.h>
+#include "spu_c64x.h"
+
+static struct {
+ void *handle;
+ int  (*dsp_open)(void);
+ dsp_mem_region_t (*dsp_shm_alloc)(dsp_cache_t _type, sU32 _numBytes);
+ int  (*dsp_shm_free)(dsp_mem_region_t _mem);
+ void (*dsp_close)(void);
+ int  (*dsp_component_load)(const char *_path, const char *_name, dsp_component_id_t *_id);
+ int  (*dsp_cache_inv_virt)(void *_virtAddr, sU32 _size);
+ int  (*dsp_rpc_send)(const dsp_msg_t *_msgTo);
+ int  (*dsp_rpc_recv)(dsp_msg_t *_msgFrom);
+ int  (*dsp_rpc)(const dsp_msg_t *_msgTo, dsp_msg_t *_msgFrom);
+ void (*dsp_logbuf_print)(void);
+
+ dsp_mem_region_t region;
+ dsp_component_id_t compid;
+ unsigned int stale_caches:1;
+ unsigned int req_sent:1;
+} f;
+
+static void thread_work_start(void)
+{
+ struct region_mem *mem;
+ dsp_msg_t msg;
+ int ret;
+
+ // make sure new work is written out
+ __sync_synchronize();
+
+ // this should be safe, as dsp checks for new work even
+ // after it decrements ->active
+ // cacheline: i_done, active
+ f.dsp_cache_inv_virt(&worker->i_done, 64);
+ if (worker->active == ACTIVE_CNT)
+  return;
+
+ // to start the DSP, dsp_rpc_send() must be used,
+ // but before that, previous request must be finished
+ if (f.req_sent) {
+  if (worker->boot_cnt == worker->last_boot_cnt) {
+   // hopefully still booting
+   //printf("booting?\n");
+   return;
+  }
+
+  ret = f.dsp_rpc_recv(&msg);
+  if (ret != 0) {
+   fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret);
+   f.dsp_logbuf_print();
+   f.req_sent = 0;
+   spu_config.iUseThread = 0;
+   return;
+  }
+ }
+
+ f.dsp_cache_inv_virt(&worker->i_done, 64);
+ worker->last_boot_cnt = worker->boot_cnt;
+
+ mem = (void *)f.region.virt_addr;
+ memcpy(&mem->spu_config, &spu_config, sizeof(mem->spu_config));
+
+ DSP_MSG_INIT(&msg, f.compid, CCMD_DOIT, f.region.phys_addr, 0);
+ ret = f.dsp_rpc_send(&msg);
+ if (ret != 0) {
+  fprintf(stderr, "dsp_rpc_send failed: %d\n", ret);
+  f.dsp_logbuf_print();
+  spu_config.iUseThread = 0;
+  return;
+ }
+ f.req_sent = 1;
+}
+
+static int thread_get_i_done(void)
+{
+ f.dsp_cache_inv_virt(&worker->i_done, sizeof(worker->i_done));
+ return worker->i_done;
+}
+
+static void thread_work_wait_sync(struct work_item *work, int force)
+{
+ int limit = 1000;
+ int ns_to;
+
+ while (worker->i_done == worker->i_reaped && limit-- > 0) {
+  if (!f.req_sent) {
+   printf("dsp: req not sent?\n");
+   break;
+  }
+
+  if (worker->boot_cnt != worker->last_boot_cnt && !worker->active) {
+   printf("dsp: broken sync\n");
+   worker->last_boot_cnt = ~0;
+   break;
+  }
+
+  usleep(500);
+  f.dsp_cache_inv_virt(&worker->i_done, 64);
+ }
+
+ ns_to = work->ns_to;
+ f.dsp_cache_inv_virt(work->SSumLR, sizeof(work->SSumLR[0]) * 2 * ns_to);
+ preload(work->SSumLR);
+ preload(work->SSumLR + 64/4);
+
+ f.stale_caches = 1; // SB, spuMem
+
+ if (limit == 0)
+  printf("dsp: wait timeout\n");
+
+ // still in results loop?
+ if (worker->i_reaped != worker->i_done - 1)
+  return;
+
+ if (f.req_sent && (force || worker->i_done == worker->i_ready)) {
+  dsp_msg_t msg;
+  int ret;
+
+  ret = f.dsp_rpc_recv(&msg);
+  if (ret != 0) {
+   fprintf(stderr, "dsp_rpc_recv failed: %d\n", ret);
+   f.dsp_logbuf_print();
+   spu_config.iUseThread = 0;
+  }
+  f.req_sent = 0;
+ }
+}
+
+static void thread_sync_caches(void)
+{
+ if (f.stale_caches) {
+  f.dsp_cache_inv_virt(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24);
+  f.dsp_cache_inv_virt(spu.spuMemC + 0x800, 0x800);
+  if (spu.rvb->StartAddr) {
+   int left = 0x40000 - spu.rvb->StartAddr;
+   f.dsp_cache_inv_virt(spu.spuMem + spu.rvb->StartAddr, left * 2);
+  }
+  f.stale_caches = 0;
+ }
+}
+
+static void init_spu_thread(void)
+{
+ dsp_msg_t init_msg, msg_in;
+ struct region_mem *mem;
+ int ret;
+
+ if (f.handle == NULL) {
+  const char lib[] = "libc64.so.1";
+  int failed = 0;
+
+  f.handle = dlopen(lib, RTLD_NOW);
+  if (f.handle == NULL) {
+   fprintf(stderr, "can't load %s: %s\n", lib, dlerror());
+   goto fail_open;
+  }
+  #define LDS(name) \
+    failed |= (f.name = dlsym(f.handle, #name)) == NULL
+  LDS(dsp_open);
+  LDS(dsp_close);
+  LDS(dsp_shm_alloc);
+  LDS(dsp_shm_free);
+  LDS(dsp_cache_inv_virt);
+  LDS(dsp_component_load);
+  LDS(dsp_rpc_send);
+  LDS(dsp_rpc_recv);
+  LDS(dsp_rpc);
+  LDS(dsp_logbuf_print);
+  #undef LDS
+  if (failed) {
+   fprintf(stderr, "missing symbol(s) in %s\n", lib);
+   dlclose(f.handle);
+   f.handle = NULL;
+   goto fail_open;
+  }
+ }
+
+ ret = f.dsp_open();
+ if (ret != 0) {
+  fprintf(stderr, "dsp_open failed: %d\n", ret);
+  goto fail_open;
+ }
+
+ ret = f.dsp_component_load(NULL, COMPONENT_NAME, &f.compid);
+ if (ret != 0) {
+  fprintf(stderr, "dsp_component_load failed: %d\n", ret);
+  goto fail_cload;
+ }
+
+ f.region = f.dsp_shm_alloc(DSP_CACHE_R, sizeof(*mem)); // writethrough
+ if (f.region.size < sizeof(*mem) || f.region.virt_addr == 0) {
+  fprintf(stderr, "dsp_shm_alloc failed\n");
+  goto fail_mem;
+ }
+ mem = (void *)f.region.virt_addr;
+
+ memcpy(&mem->spu_config, &spu_config, sizeof(mem->spu_config));
+
+ DSP_MSG_INIT(&init_msg, f.compid, CCMD_INIT, f.region.phys_addr, 0);
+ ret = f.dsp_rpc(&init_msg, &msg_in);
+ if (ret != 0) {
+  fprintf(stderr, "dsp_rpc failed: %d\n", ret);
+  goto fail_init;
+ }
+
+ if (mem->sizeof_region_mem != sizeof(*mem)) {
+  fprintf(stderr, "error: size mismatch 1: %d vs %zd\n",
+    mem->sizeof_region_mem, sizeof(*mem));
+  goto fail_init;
+ }
+ if (mem->offsetof_s_chan1 != offsetof(typeof(*mem), in.s_chan[1])) {
+  fprintf(stderr, "error: size mismatch 2: %d vs %zd\n",
+    mem->offsetof_s_chan1, offsetof(typeof(*mem), in.s_chan[1]));
+  goto fail_init;
+ }
+ if (mem->offsetof_spos_3_20 != offsetof(typeof(*mem), worker.i[3].ch[20])) {
+  fprintf(stderr, "error: size mismatch 3: %d vs %zd\n",
+    mem->offsetof_spos_3_20, offsetof(typeof(*mem), worker.i[3].ch[20]));
+  goto fail_init;
+ }
+
+ // override default allocations
+ free(spu.spuMemC);
+ spu.spuMemC = mem->spu_ram;
+ free(spu.SB);
+ spu.SB = mem->SB;
+ free(spu.s_chan);
+ spu.s_chan = mem->in.s_chan;
+ free(spu.rvb);
+ spu.rvb = &mem->in.rvb;
+ worker = &mem->worker;
+
+ printf("spu: C64x DSP ready (id=%d).\n", (int)f.compid);
+ f.dsp_logbuf_print();
+
+ spu_config.iThreadAvail = 1;
+ (void)do_channel_work; // used by DSP instead
+ return;
+
+fail_init:
+ f.dsp_shm_free(f.region);
+fail_mem:
+ // no component unload func?
+fail_cload:
+ f.dsp_logbuf_print();
+ f.dsp_close();
+fail_open:
+ printf("spu: C64x DSP init failed.\n");
+ spu_config.iUseThread = spu_config.iThreadAvail = 0;
+ worker = NULL;
+}
+
+static void exit_spu_thread(void)
+{
+ dsp_msg_t msg;
+
+ if (worker == NULL)
+  return;
+
+ if (f.req_sent) {
+  f.dsp_rpc_recv(&msg);
+  f.req_sent = 0;
+ }
+
+ f.dsp_logbuf_print();
+ f.dsp_shm_free(f.region);
+ f.dsp_close();
+
+ spu.spuMemC = NULL;
+ spu.SB = NULL;
+ spu.s_chan = NULL;
+ spu.rvb = NULL;
+ worker = NULL;
+}
+
+// vim:shiftwidth=1:expandtab
diff --git a/plugins/dfsound/spu_c64x.h b/plugins/dfsound/spu_c64x.h
new file mode 100644 (file)
index 0000000..8210e63
--- /dev/null
@@ -0,0 +1,28 @@
+#define COMPONENT_NAME "pcsxr_spu"
+
+enum {
+ CCMD_INIT = 0x101,
+ CCMD_DOIT = 0x102,
+};
+
+struct region_mem {
+ unsigned char spu_ram[512 * 1024];
+ int SB[SB_SIZE * 24];
+ // careful not to lose ARM writes by DSP overwriting
+ // with old data when it's writing out neighbor cachelines
+ int _pad1[128/4 - ((SB_SIZE * 24) & (128/4 - 1))];
+ struct spu_in {
+  // these are not to be modified by DSP
+  SPUCHAN s_chan[24 + 1];
+  REVERBInfo rvb;
+ } in;
+ int _pad2[128/4 - ((sizeof(struct spu_in) / 4) & (128/4 - 1))];
+ struct spu_worker worker;
+ SPUConfig spu_config;
+ // init/debug
+ int sizeof_region_mem;
+ int offsetof_s_chan1;
+ int offsetof_spos_3_20;
+};
+
+#define ACTIVE_CNT 3
diff --git a/plugins/dfsound/spu_c64x_dspcode.c b/plugins/dfsound/spu_c64x_dspcode.c
new file mode 100644 (file)
index 0000000..b0352a9
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * SPU processing offload to TI C64x DSP using bsp's c64_tools
+ * (C) GraÅžvydas "notaz" Ignotas, 2015
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy of
+ *  this software and associated documentation files (the "Software"), to deal in
+ *  the Software without restriction, including without limitation the rights to
+ *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ *  of the Software, and to permit persons to whom the Software is furnished to do
+ *  so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ */
+
+#define SYSCALLS_C
+#include <libc64_dsp/include/inc_overlay.h>
+#include <stddef.h>
+
+#include "spu.c"
+#include "spu_c64x.h"
+
+/* dummy deps, some bloat but avoids ifdef hell in SPU code.. */
+static void thread_work_start(void) {}
+static void thread_work_wait_sync(struct work_item *work, int force) {}
+static void thread_sync_caches(void) {}
+static int  thread_get_i_done(void) { return 0; }
+struct out_driver *out_current;
+void SetupSound(void) {}
+
+
+static void invalidate_cache(struct work_item *work)
+{
+ // see comment in writeout_cache()
+ //syscalls.cache_inv(work, offsetof(typeof(*work), SSumLR), 1);
+ syscalls.cache_inv(spu.s_chan, sizeof(spu.s_chan[0]) * 24, 0);
+ syscalls.cache_inv(work->SSumLR,
+   sizeof(work->SSumLR[0]) * 2 * work->ns_to, 0);
+}
+
+static void writeout_cache(struct work_item *work)
+{
+ int ns_to = work->ns_to;
+
+ syscalls.cache_wb(work->SSumLR, sizeof(work->SSumLR[0]) * 2 * ns_to, 1);
+ // have to invalidate now, otherwise there is a race between
+ // DSP evicting dirty lines and ARM writing new data to this area
+ syscalls.cache_inv(work, offsetof(typeof(*work), SSumLR), 0);
+}
+
+static void do_processing(void)
+{
+ int left, dirty = 0, had_rvb = 0;
+ struct work_item *work;
+
+ while (worker->active)
+ {
+  // i_ready is in first cacheline
+  syscalls.cache_inv(worker, 64, 1);
+
+  left = worker->i_ready - worker->i_done;
+  if (left > 0) {
+   dirty = 1;
+   worker->active = ACTIVE_CNT;
+   syscalls.cache_wb(&worker->active, 4, 1);
+
+   work = &worker->i[worker->i_done & WORK_I_MASK];
+   invalidate_cache(work);
+   had_rvb |= work->rvb_addr;
+   spu.spuCtrl = work->ctrl;
+   do_channel_work(work);
+   writeout_cache(work);
+
+   worker->i_done++;
+   syscalls.cache_wb(&worker->i_done, 4, 1);
+   continue;
+  }
+
+  // nothing to do? Write out non-critical caches
+  if (dirty) {
+   syscalls.cache_wb(spu.spuMemC + 0x800, 0x800, 1);
+   syscalls.cache_wb(spu.SB, sizeof(spu.SB[0]) * SB_SIZE * 24, 1);
+   if (had_rvb) {
+    left = 0x40000 - spu.rvb->StartAddr;
+    syscalls.cache_wb(spu.spuMem + spu.rvb->StartAddr, left * 2, 1);
+    had_rvb = 0;
+   }
+   dirty = 0;
+   continue;
+  }
+
+  // this ->active loop thing is to avoid a race where we miss
+  // new work and clear ->active just after ARM checks it
+  worker->active--;
+  syscalls.cache_wb(&worker->active, 4, 1);
+ }
+}
+
+static unsigned int exec(dsp_component_cmd_t cmd,
+  unsigned int arg1, unsigned int arg2,
+  unsigned int *ret1, unsigned int *ret2)
+{
+ struct region_mem *mem = (void *)arg1;
+
+ switch (cmd) {
+  case CCMD_INIT:
+   InitADSR();
+
+   spu.spuMemC = mem->spu_ram;
+   spu.SB = mem->SB;
+   spu.s_chan = mem->in.s_chan;
+   spu.rvb = &mem->in.rvb;
+   worker = &mem->worker;
+   memcpy(&spu_config, &mem->spu_config, sizeof(spu_config));
+
+   mem->sizeof_region_mem = sizeof(*mem);
+   mem->offsetof_s_chan1 = offsetof(typeof(*mem), in.s_chan[1]);
+   mem->offsetof_spos_3_20 = offsetof(typeof(*mem), worker.i[3].ch[20]);
+   // seems to be unneeded, no write-alloc? but just in case..
+   syscalls.cache_wb(&mem->sizeof_region_mem, 3 * 4, 1);
+   break;
+
+  case CCMD_DOIT:
+   worker->active = ACTIVE_CNT;
+   worker->boot_cnt++;
+   syscalls.cache_wb(&worker->i_done, 64, 1);
+   memcpy(&spu_config, &mem->spu_config, sizeof(spu_config));
+
+   do_processing();
+
+   // c64_tools lib does BCACHE_wbInvAll() when it receives mailbox irq,
+   // but invalidate anyway in case c64_tools is ever fixed..
+   // XXX edit: don't bother as reverb is not handled, will fix if needed
+   //syscalls.cache_inv(mem, sizeof(mem->spu_ram) + sizeof(mem->SB), 0);
+   //syscalls.cache_inv(&mem->in, sizeof(mem->in), 0);
+   break;
+
+  default:
+   syscalls.printf("bad cmd: %x\n", cmd);
+   break;
+ }
+
+ return 0;
+}
+
+#pragma DATA_SECTION(component_test_dsp, ".sec_com");
+dsp_component_t component_test_dsp = {
+ {
+  NULL,       /* init */
+  exec,
+  NULL,       /* exec fastcall RPC */
+  NULL,       /* exit */
+ },
+
+ COMPONENT_NAME,
+};
+
+DSP_COMPONENT_MAIN
+
+// vim:shiftwidth=1:expandtab
index c6641be..fce1cda 100644 (file)
@@ -7,6 +7,10 @@ typedef struct
  int        iUseReverb;
  int        iUseInterpolation;
  int        iTempo;
+ int        iUseThread;
+
+ // status
+ int        iThreadAvail;
 } SPUConfig;
 
 extern SPUConfig spu_config;
index 8993bb3..7e22029 100644 (file)
  *                                                                         *
  ***************************************************************************/
 
-#ifndef _MACOSX
-#include "config.h"
-#endif
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <pthread.h>
-#define RRand(range) (random()%range)  
 #include <string.h> 
-#include <sys/time.h>  
-#include <math.h>  
 
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
 #undef CALLBACK
 #define CALLBACK
 #define DWORD unsigned int
-#define LOWORD(l)           ((unsigned short)(l)) 
-#define HIWORD(l)           ((unsigned short)(((unsigned int)(l) >> 16) & 0xFFFF)) 
+#define LOWORD(l)           ((unsigned short)(l))
+#define HIWORD(l)           ((unsigned short)(((unsigned int)(l) >> 16) & 0xFFFF))
+#endif
 
 #ifndef INLINE
 #define INLINE static inline
index 704847b..ad7e824 100644 (file)
@@ -38,12 +38,12 @@ static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0};
 // MIX XA & CDDA
 ////////////////////////////////////////////////////////////////////////
 
-INLINE void MixXA(int ns_to)
+INLINE void MixXA(int *SSumLR, int ns_to, int decode_pos)
 {
+ int cursor = decode_pos;
  int ns;
  short l, r;
  uint32_t v;
- int cursor = spu.decode_pos;
 
  if(spu.XAPlay != spu.XAFeed || spu.XARepeat > 0)
  {
@@ -90,9 +90,15 @@ INLINE void MixXA(int ns_to)
 
 static unsigned long timeGetTime_spu()
 {
+#if defined(NO_OS)
+ return 0;
+#elif defined(_WIN32)
+ return GetTickCount();
+#else
  struct timeval tv;
  gettimeofday(&tv, 0);                                 // well, maybe there are better ways
  return tv.tv_sec * 1000 + tv.tv_usec/1000;            // to do that, but at least it works
+#endif
 }
 
 ////////////////////////////////////////////////////////////////////////
index 337e27a..0e6fe63 100644 (file)
 #include "gpu.h"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#ifdef __GNUC__
 #define unlikely(x) __builtin_expect((x), 0)
+#define preload __builtin_prefetch
 #define noinline __attribute__((noinline))
+#else
+#define unlikely(x)
+#define preload(...)
+#define noinline
+#error huh
+#endif
 
 #define gpu_log(fmt, ...) \
   printf("%d:%03d: " fmt, *gpu.state.frame_count, *gpu.state.hcnt, ##__VA_ARGS__)
@@ -513,11 +521,13 @@ void GPUwriteData(uint32_t data)
 
 long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
 {
-  uint32_t addr, *list;
+  uint32_t addr, *list, ld_addr = 0;
   uint32_t *llist_entry = NULL;
   int len, left, count;
   long cpu_cycles = 0;
 
+  preload(rambase + (start_addr & 0x1fffff) / 4);
+
   if (unlikely(gpu.cmd_len > 0))
     flush_cmd_buffer();
 
@@ -532,39 +542,50 @@ long GPUdmaChain(uint32_t *rambase, uint32_t start_addr)
 
   log_io("gpu_dma_chain\n");
   addr = start_addr & 0xffffff;
-  for (count = 0; addr != 0xffffff; count++)
+  for (count = 0; (addr & 0x800000) == 0; count++)
   {
     list = rambase + (addr & 0x1fffff) / 4;
     len = list[0] >> 24;
     addr = list[0] & 0xffffff;
+    preload(rambase + (addr & 0x1fffff) / 4);
+
     cpu_cycles += 10;
     if (len > 0)
       cpu_cycles += 5 + len;
 
     log_io(".chain %08x #%d\n", (list - rambase) * 4, len);
 
-    // loop detection marker
-    // (bit23 set causes DMA error on real machine, so
-    //  unlikely to be ever set by the game)
-    list[0] |= 0x800000;
-
     if (len) {
       left = do_cmd_buffer(list + 1, len);
       if (left)
         log_anomaly("GPUdmaChain: discarded %d/%d words\n", left, len);
     }
 
-    if (addr & 0x800000)
-      break;
+    #define LD_THRESHOLD (8*1024)
+    if (count >= LD_THRESHOLD) {
+      if (count == LD_THRESHOLD) {
+        ld_addr = addr;
+        continue;
+      }
+
+      // loop detection marker
+      // (bit23 set causes DMA error on real machine, so
+      //  unlikely to be ever set by the game)
+      list[0] |= 0x800000;
+    }
   }
 
-  // remove loop detection markers
-  addr = start_addr & 0x1fffff;
-  while (count-- > 0) {
-    list = rambase + addr / 4;
-    addr = list[0] & 0x1fffff;
-    list[0] &= ~0x800000;
+  if (ld_addr != 0) {
+    // remove loop detection markers
+    count -= LD_THRESHOLD + 2;
+    addr = ld_addr & 0x1fffff;
+    while (count-- > 0) {
+      list = rambase + addr / 4;
+      addr = list[0] & 0x1fffff;
+      list[0] &= ~0x800000;
+    }
   }
+
   if (llist_entry)
     *llist_entry &= ~0x800000;
 
index c523f60..435a682 100644 (file)
@@ -113,6 +113,15 @@ the main menu where it is possible to enable/disable individual cheats.
 Changelog
 ---------
 
+r21 (2015-01-12)
++ general: added ability to run SPU emulation on a separate thread, enabled it
+  by default when multicore CPU is detected. Significant effort was made to
+  avoid any compatibility problems which the old P.E.Op.S. implementation had.
++ pandora: added ability to run SPU emulation on TI C64x DSP by using bsp's
+  c64_tools.
+* libretro: fixed win32 build (mingw only)
+* some tweaks for the scanline effect and other things
+
 r20 (2014-12-25)
 * fixed various sound accuracy issues, like effects in ff7-ff9
   for standalone build, audio will no longer slow down when emu is not fast