+static void do_irq(void)
+{
+ if(!(spuStat & STAT_IRQ))
+ {
+ spuStat |= STAT_IRQ;
+ if(irqCallback) irqCallback();
+ }
+}
+
+static int decode_block(int ch)
+{
+ unsigned char *start;
+ unsigned int nSample;
+ int predict_nr,shift_factor,flags,d,s;
+ int fa,s_1,s_2;
+ int ret = 0;
+
+ s_chan[ch].iSBPos=0;
+
+ start=s_chan[ch].pCurr; // set up the current pos
+ if(start == (unsigned char*)-1 || // special "stop" sign
+ (dwPendingChanOff&(1<<ch)))
+ {
+ dwChannelOn&=~(1<<ch); // -> turn everything off
+ dwPendingChanOff&=~(1<<ch);
+ s_chan[ch].bStop=1;
+ s_chan[ch].ADSRX.EnvelopeVol=0;
+ return 0; // -> and done for this channel
+ }
+
+ //////////////////////////////////////////// irq check
+
+ if(spuCtrl&CTRL_IRQ)
+ {
+ if(pSpuIrq == start) // irq address reached?
+ {
+ do_irq(); // -> call main emu
+ ret = 1;
+ }
+ }
+
+ s_1=s_chan[ch].s_1;
+ s_2=s_chan[ch].s_2;
+
+ predict_nr=(int)*start;start++;
+ shift_factor=predict_nr&0xf;
+ predict_nr >>= 4;
+ flags=(int)*start;start++;
+
+ // -------------------------------------- //
+
+ for (nSample=0;nSample<28;start++)
+ {
+ d=(int)*start;
+ s=((d&0xf)<<12);
+ if(s&0x8000) s|=0xffff0000;
+
+ fa=(s >> shift_factor);
+ fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
+ s_2=s_1;s_1=fa;
+ s=((d & 0xf0) << 8);
+
+ s_chan[ch].SB[nSample++]=fa;
+
+ if(s&0x8000) s|=0xffff0000;
+ fa=(s>>shift_factor);
+ fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
+ s_2=s_1;s_1=fa;
+
+ s_chan[ch].SB[nSample++]=fa;
+ }
+
+ //////////////////////////////////////////// flag handler
+
+ if((flags&4) && (!s_chan[ch].bIgnoreLoop))
+ s_chan[ch].pLoop=start-16; // loop adress
+
+ if(flags&1) // 1: stop/loop
+ {
+ if(!(flags&2))
+ dwPendingChanOff|=1<<ch;
+
+ start = s_chan[ch].pLoop;
+ }
+
+ if (start - spuMemC >= 0x80000)
+ start = (unsigned char*)-1;
+
+ s_chan[ch].pCurr=start; // store values for next cycle
+ s_chan[ch].s_1=s_1;
+ s_chan[ch].s_2=s_2;
+
+ return ret;
+}
+