+// 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 = 0;
+
+ // Tron Bonne hack, probably wrong (could be wrong memory contents..)
+ if(flags & ~7) flags = 0;
+
+ if(start == pSpuIrq)
+ {
+ do_irq();
+ ret = 1;
+ }
+
+ if(flags & 4)
+ s_chan[ch].pLoop=start;
+
+ s_chan[ch].pCurr += 16;
+
+ if(flags & 1)
+ s_chan[ch].pCurr = s_chan[ch].pLoop;
+
+ return ret;
+}
+
+#define make_do_samples(name, fmod_code, interp_start, interp1_code, interp2_code, interp_end) \
+static int do_samples_##name(int ch, int ns, int ns_to) \
+{ \
+ 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; \
+ interp_start; \
+ \
+ for (; ns < ns_to; ns++) \
+ { \
+ fmod_code; \
+ \
+ while (spos >= 0x10000) \
+ { \
+ if(sbpos == 28) \
+ { \
+ sbpos = 0; \
+ d = decode_block(ch); \
+ if(d && iSPUIRQWait) \
+ { \
+ ret = ns; \
+ goto out; \
+ } \
+ } \
+ \
+ fa = SB[sbpos++]; \
+ interp1_code; \
+ spos -= 0x10000; \
+ } \
+ \
+ interp2_code; \
+ spos += sinc; \
+ } \
+ \
+out: \
+ 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)
+
+make_do_samples(default, fmod_recv_check, ,
+ StoreInterpolationVal(ch, fa),
+ ChanBuf[ns] = iGetInterpolationVal(ch), )
+make_do_samples(noint, , fa = s_chan[ch].SB[29], , ChanBuf[ns] = fa, s_chan[ch].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
+
+#define simple_interp_get \
+ if(sinc<0x10000) /* -> upsampling? */ \
+ InterpolateUp(ch); /* --> interpolate up */ \
+ else InterpolateDown(ch); /* --> else down */ \
+ ChanBuf[ns] = s_chan[ch].SB[29]
+
+make_do_samples(simple, , ,
+ simple_interp_store, simple_interp_get, )
+
+static int do_samples_noise(int ch, int ns, int ns_to)
+{
+ int level, shift, bit;
+
+ s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns);
+ while (s_chan[ch].spos >= 28*0x10000)
+ {
+ skip_block(ch);
+ s_chan[ch].spos -= 28*0x10000;
+ }
+
+ // modified from DrHell/shalma, no fraction
+ level = (spuCtrl >> 10) & 0x0f;
+ level = 0x8000 >> level;
+
+ for (; ns < ns_to; ns++)
+ {
+ dwNoiseCount += 2;
+ if (dwNoiseCount >= level)
+ {
+ dwNoiseCount -= level;
+ shift = (dwNoiseVal >> 10) & 0x1f;
+ bit = (0x69696969 >> shift) & 1;
+ if (dwNoiseVal & 0x8000)
+ bit ^= 1;
+ dwNoiseVal = (dwNoiseVal << 1) | bit;
+ }
+
+ ChanBuf[ns] = (signed short)dwNoiseVal;
+ }
+
+ return -1;
+}
+
+#ifdef __arm__
+// asm code
+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);
+#else
+static void mix_chan(int start, int count, int lv, int rv)
+{
+ int *dst = SSumLR + start * 2;
+ const int *src = ChanBuf + start;
+ int l, r;
+
+ while (count--)
+ {
+ int sval = *src++;
+
+ l = (sval * lv) >> 14;
+ r = (sval * rv) >> 14;
+ *dst++ += l;
+ *dst++ += r;
+ }
+}
+
+static void mix_chan_rvb(int start, int count, int lv, int rv)
+{
+ int *dst = SSumLR + start * 2;
+ int *drvb = sRVBStart + start * 2;
+ const int *src = ChanBuf + start;
+ int l, r;
+
+ while (count--)
+ {
+ int sval = *src++;
+
+ l = (sval * lv) >> 14;
+ r = (sval * rv) >> 14;
+ *dst++ += l;
+ *dst++ += r;
+ *drvb++ += l;
+ *drvb++ += r;
+ }
+}
+#endif
+