X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=fbd555b179877bccbe49b8dce4995a43693ffd61;hp=f5edd3a7f33b8d1052cf7718b3dd605e94ada2b6;hb=5fdcf5cd320abef2c685630e3edf3598645d141e;hpb=3bd31caf9e9f5ddab2bf4fbdb5a129f4972c45f3 diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index f5edd3a7..fbd555b1 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -35,7 +35,7 @@ #include "arm_features.h" #endif -#ifdef __ARM_ARCH_7A__ +#ifdef HAVE_ARMV7 #define ssat32_to_16(v) \ asm("ssat %0,#16,%1" : "=r" (v) : "r" (v)) #else @@ -73,11 +73,8 @@ 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 - -REVERBInfo rvb; - static int iFMod[NSSIZE]; +static int RVB[NSSIZE * 2]; int ChanBuf[NSSIZE]; #define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2 @@ -250,9 +247,12 @@ static void StartSoundMain(int ch) s_chan->iSBPos=27; s_chan->spos=0; + s_chan->pCurr = spu.spuMemC + ((regAreaGetCh(ch, 6) & ~1) << 3); + spu.dwNewChannel&=~(1<iRawPitch) + spu.dwChannelsAudible|=1<bIgnoreLoop)) s_chan->pLoop = start; // loop adress start += 16; @@ -595,24 +595,26 @@ make_do_samples(simple, , , static int do_samples_skip(int ch, int ns_to) { SPUCHAN *s_chan = &spu.s_chan[ch]; + int spos = s_chan->spos; + int sinc = s_chan->sinc; int ret = ns_to, ns, d; - s_chan->spos += s_chan->iSBPos << 16; + spos += s_chan->iSBPos << 16; for (ns = 0; ns < ns_to; ns++) { - s_chan->spos += s_chan->sinc; - while (s_chan->spos >= 28*0x10000) + spos += sinc; + while (spos >= 28*0x10000) { d = skip_block(ch); if (d && ns < ret) ret = ns; - s_chan->spos -= 28*0x10000; + spos -= 28*0x10000; } } - s_chan->iSBPos = s_chan->spos >> 16; - s_chan->spos &= 0xffff; + s_chan->iSBPos = spos >> 16; + s_chan->spos = spos & 0xffff; return ret; } @@ -761,11 +763,13 @@ static void do_silent_chans(int ns_to, int silentch) static void do_channels(int ns_to) { unsigned int mask; + int do_rvb, ch, d; SPUCHAN *s_chan; int *SB, sinc; - int ch, d; - memset(spu.RVB, 0, ns_to * sizeof(spu.RVB[0]) * 2); + 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) { @@ -773,7 +777,7 @@ static void do_channels(int ns_to) StartSound(ch); } - mask = spu.dwChannelOn & 0xffffff; + mask = spu.dwChannelsAudible & 0xffffff; for (ch = 0; mask != 0; ch++, mask >>= 1) // loop em all... { if (!(mask & 1)) continue; // channel not playing? next @@ -797,7 +801,8 @@ static void do_channels(int ns_to) d = MixADSR(&s_chan->ADSRX, d); if (d < ns_to) { - spu.dwChannelOn &= ~(1 << ch); + spu.dwChannelsAudible &= ~(1 << ch); + s_chan->ADSRX.State = ADSR_RELEASE; s_chan->ADSRX.EnvelopeVol = 0; memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0])); } @@ -810,14 +815,23 @@ static void do_channels(int ns_to) if (s_chan->bFMod == 2) // fmod freq channel memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0])); - if (s_chan->bRVBActive) - mix_chan_rvb(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, spu.RVB); + 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) + 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 *RVB, int ns_to, +static void do_samples_finish(int *SSumLR, int ns_to, int silentch, int decode_pos); // optional worker thread handling @@ -831,8 +845,8 @@ static struct spu_worker { unsigned int exit_thread; unsigned int i_ready; unsigned int i_reaped; - unsigned int req_sent; // dsp - unsigned int last_boot_cnt; + unsigned int last_boot_cnt; // dsp + unsigned int ram_dirty; }; // aligning for C64X_DSP unsigned int _pad0[128/4]; @@ -849,6 +863,7 @@ static struct spu_worker { int ns_to; int ctrl; int decode_pos; + int rvb_addr; unsigned int channels_new; unsigned int channels_on; unsigned int channels_silent; @@ -859,10 +874,11 @@ static struct spu_worker { int start; int loop; int ns_to; + short vol_l; + short vol_r; ADSRInfoEx adsr; - // might want to add vol and fmod flags.. + // might also want to add fmod flags.. } ch[24]; - int RVB[NSSIZE * 2]; int SSumLR[NSSIZE * 2]; } i[4]; } *worker; @@ -872,6 +888,7 @@ static struct spu_worker { 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) @@ -922,7 +939,7 @@ static void queue_channel_work(int ns_to, unsigned int silentch) StartSoundMain(ch); } - mask = work->channels_on = spu.dwChannelOn & 0xffffff; + mask = work->channels_on = spu.dwChannelsAudible & 0xffffff; spu.decode_dirty_ch |= mask & 0x0a; for (ch = 0; mask != 0; ch++, mask >>= 1) @@ -934,6 +951,8 @@ static void queue_channel_work(int ns_to, unsigned int silentch) 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) @@ -945,11 +964,21 @@ static void queue_channel_work(int ns_to, unsigned int silentch) // note: d is not accurate on skip d = SkipADSR(&s_chan->ADSRX, d); if (d < ns_to) { - spu.dwChannelOn &= ~(1 << ch); + spu.dwChannelsAudible &= ~(1 << ch); s_chan->ADSRX.EnvelopeVol = 0; } } + work->rvb_addr = 0; + if (spu.rvb->StartAddr) { + if (spu_config.iUseReverb) + 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(); } @@ -958,12 +987,14 @@ static void do_channel_work(struct work_item *work) { unsigned int mask; unsigned int decode_dirty_ch = 0; + const SPUCHAN *s_chan; int *SB, sinc, spos, sbpos; int d, ch, ns_to; - SPUCHAN *s_chan; ns_to = work->ns_to; - memset(work->RVB, 0, ns_to * sizeof(work->RVB[0]) * 2); + + 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) { @@ -1008,12 +1039,15 @@ static void do_channel_work(struct work_item *work) if (s_chan->bFMod == 2) // fmod freq channel memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0])); - if (s_chan->bRVBActive) + if (s_chan->bRVBActive && work->rvb_addr) mix_chan_rvb(work->SSumLR, ns_to, - s_chan->iLeftVolume, s_chan->iRightVolume, work->RVB); + work->ch[ch].vol_l, work->ch[ch].vol_r, RVB); else - mix_chan(work->SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume); + 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) @@ -1021,8 +1055,12 @@ static void sync_worker_thread(int force) struct work_item *work; int done, used_space; + // rvb offsets will change, thread may be using them + force |= spu.rvb->dirty && spu.rvb->StartAddr; + 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); @@ -1030,13 +1068,15 @@ static void sync_worker_thread(int force) work = &worker->i[worker->i_reaped & WORK_I_MASK]; thread_work_wait_sync(work, force); - do_samples_finish(work->SSumLR, work->RVB, work->ns_to, + 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 @@ -1067,7 +1107,7 @@ void do_samples(unsigned int cycles_to, int do_direct) return; } - silentch = ~(spu.dwChannelOn | spu.dwNewChannel) & 0xffffff; + silentch = ~(spu.dwChannelsAudible | spu.dwNewChannel) & 0xffffff; do_direct |= (silentch == 0xffffff); if (worker != NULL) @@ -1112,9 +1152,12 @@ void do_samples(unsigned int cycles_to, int do_direct) } } + if (unlikely(spu.rvb->dirty)) + REVERBPrep(); + if (do_direct || worker == NULL || !spu_config.iUseThread) { do_channels(ns_to); - do_samples_finish(spu.SSumLR, spu.RVB, ns_to, silentch, spu.decode_pos); + do_samples_finish(spu.SSumLR, ns_to, silentch, spu.decode_pos); } else { queue_channel_work(ns_to, silentch); @@ -1129,10 +1172,11 @@ void do_samples(unsigned int cycles_to, int do_direct) spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff; } -static void do_samples_finish(int *SSumLR, int *RVB, int ns_to, +static void do_samples_finish(int *SSumLR, int ns_to, int silentch, int decode_pos) { - int volmult = spu_config.iVolume; + int vol_l = ((int)regAreaGet(H_SPUmvolL) << 17) >> 17; + int vol_r = ((int)regAreaGet(H_SPUmvolR) << 17) >> 17; int ns; int d; @@ -1148,33 +1192,29 @@ static void do_samples_finish(int *SSumLR, int *RVB, int ns_to, spu.decode_dirty_ch &= ~(1<<3); } - //---------------------------------------------------// - // mix XA infos (if any) - MixXA(SSumLR, ns_to, decode_pos); - - /////////////////////////////////////////////////////// - // mix all channels (including reverb) into one buffer - if(spu_config.iUseReverb) - REVERBDo(SSumLR, RVB, ns_to); + vol_l = vol_l * spu_config.iVolume >> 10; + vol_r = vol_r * spu_config.iVolume >> 10; - if((spu.spuCtrl&0x4000)==0) // muted? (rare, don't optimize for this) + if (!(spu.spuCtrl & 0x4000) || !(vol_l | vol_r)) { + // muted? (rare) memset(spu.pS, 0, ns_to * 2 * sizeof(spu.pS[0])); + memset(SSumLR, 0, ns_to * 2 * sizeof(SSumLR[0])); spu.pS += ns_to * 2; } else for (ns = 0; ns < ns_to * 2; ) { d = SSumLR[ns]; SSumLR[ns] = 0; - d = d * volmult >> 10; + d = d * vol_l >> 15; ssat32_to_16(d); *spu.pS++ = d; ns++; d = SSumLR[ns]; SSumLR[ns] = 0; - d = d * volmult >> 10; + d = d * vol_r >> 15; ssat32_to_16(d); *spu.pS++ = d; ns++; @@ -1198,6 +1238,8 @@ void schedule_next_irq(void) 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; + if (spu.s_chan[ch].sinc == 0) + continue; scan_for_irq(ch, &upd_samples); } @@ -1223,7 +1265,7 @@ void schedule_next_irq(void) void CALLBACK SPUasync(unsigned int cycle, unsigned int flags) { - do_samples(cycle, 0); + do_samples(cycle, spu_config.iUseFixedUpdates); if (spu.spuCtrl & CTRL_IRQ) schedule_next_irq(); @@ -1281,46 +1323,29 @@ void ClearWorkingState(void) } // 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.RVB = calloc(NSSIZE * 2, sizeof(spu.RVB[0])); spu.SSumLR = calloc(NSSIZE * 2, sizeof(spu.SSumLR[0])); - spu.XAStart = // alloc xa buffer - (uint32_t *)malloc(44100 * sizeof(uint32_t)); + spu.XAStart = malloc(44100 * sizeof(uint32_t)); // alloc xa buffer spu.XAEnd = spu.XAStart + 44100; spu.XAPlay = spu.XAStart; spu.XAFeed = spu.XAStart; - spu.CDDAStart = // alloc cdda buffer - (uint32_t *)malloc(CDDA_BUFFER_SIZE); + spu.CDDAStart = malloc(CDDA_BUFFER_SIZE); // alloc cdda buffer spu.CDDAEnd = spu.CDDAStart + 16384; spu.CDDAPlay = spu.CDDAStart; spu.CDDAFeed = spu.CDDAStart; - for(i=0;i init sustain - spu.s_chan[i].ADSRX.SustainIncrease = 1; - spu.s_chan[i].pLoop=spu.spuMemC; - spu.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.RVB); // free reverb buffer - spu.RVB = NULL; free(spu.SSumLR); spu.SSumLR = NULL; free(spu.XAStart); // free XA buffer @@ -1363,6 +1388,10 @@ 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; @@ -1444,11 +1473,13 @@ static void exit_spu_thread(void) // SPUINIT: this func will be called first by the main emu long CALLBACK SPUinit(void) { + int i; + spu.spuMemC = calloc(1, 512 * 1024); - memset((void *)&rvb, 0, sizeof(REVERBInfo)); InitADSR(); 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; @@ -1462,6 +1493,17 @@ long CALLBACK SPUinit(void) 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.s_chan[i].bIgnoreLoop = 0; + } + + spu.bSpuInit=1; // flag: we are inited + return 0; } @@ -1502,6 +1544,8 @@ long CALLBACK SPUshutdown(void) spu.SB = NULL; free(spu.s_chan); spu.s_chan = NULL; + free(spu.rvb); + spu.rvb = NULL; RemoveStreams(); // no more streaming spu.bSpuInit=0; @@ -1544,7 +1588,7 @@ void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void)) spu.irqCallback = callback; } -void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short)) +void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(short, short)) { spu.cddavCallback = CDDAVcallback; } @@ -1587,7 +1631,7 @@ void spu_get_debug_info(int *chans_out, int *run_chans, int *fmod_chans_out, int for(;ch