X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=637e8521629f69968c20055a5fee89b3377e41fa;hp=f2023881bfbb4073af6bd1196fd8eee34c8f1361;hb=HEAD;hpb=25f460eca64d55f980ab57851ffbd9fe58a5793c diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index f2023881..ed5b4b5c 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -27,6 +27,7 @@ #include "registers.h" #include "out.h" #include "spu_config.h" +#include "spu.h" #ifdef __arm__ #include "arm_features.h" @@ -835,7 +836,7 @@ static void do_channels(int ns_to) mix_chan(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume); } - MixXA(spu.SSumLR, RVB, ns_to, spu.decode_pos); + MixCD(spu.SSumLR, RVB, ns_to, spu.decode_pos); if (spu.rvb->StartAddr) { if (do_rvb) @@ -858,11 +859,14 @@ static void do_samples_finish(int *SSumLR, int ns_to, static struct spu_worker { union { struct { - unsigned int exit_thread; + unsigned char exit_thread; + unsigned char prev_work_in_thread; + unsigned char pad[2]; unsigned int i_ready; unsigned int i_reaped; unsigned int last_boot_cnt; // dsp unsigned int ram_dirty; + unsigned int channels_last; }; // aligning for C64X_DSP unsigned int _pad0[128/4]; @@ -953,6 +957,16 @@ static void queue_channel_work(int ns_to, unsigned int silentch) work->decode_pos = spu.decode_pos; work->channels_silent = silentch; + if (!worker->prev_work_in_thread) { + // copy adpcm and interpolation state to sb_thread + worker->prev_work_in_thread = 1; + mask = spu.dwChannelsAudible & ~spu.dwNewChannel & 0xffffff; + for (ch = 0; mask != 0; ch++, mask >>= 1) { + if (mask & 1) + memcpy(spu.sb_thread[ch].SB, spu.sb[ch].SB, sizeof(spu.sb_thread[ch].SB)); + } + } + mask = work->channels_new = spu.dwNewChannel & 0xffffff; for (ch = 0; mask != 0; ch++, mask >>= 1) { if (mask & 1) @@ -960,6 +974,7 @@ static void queue_channel_work(int ns_to, unsigned int silentch) } mask = work->channels_on = spu.dwChannelsAudible & 0xffffff; + worker->channels_last = mask; spu.decode_dirty_ch |= mask & 0x0a; for (ch = 0; mask != 0; ch++, mask >>= 1) @@ -985,8 +1000,10 @@ static void queue_channel_work(int ns_to, unsigned int silentch) if (unlikely(s_chan->bFMod == 2)) { // sucks, have to do double work - assert(!s_chan->bNoise); - d = do_samples_gauss(tmpFMod, decode_block, NULL, ch, ns_to, + if (s_chan->bNoise) + d = do_samples_noise(tmpFMod, ch, ns_to); + else + d = do_samples_gauss(tmpFMod, decode_block, NULL, ch, ns_to, &spu.sb[ch], s_chan->sinc, &s_chan->spos, &s_chan->iSBPos); if (!s_chan->bStarting) { d = MixADSR(tmpFMod, &s_chan->ADSRX, d); @@ -1094,8 +1111,9 @@ static void do_channel_work(struct work_item *work) REVERBDo(work->SSumLR, RVB, ns_to, work->rvb_addr); } -static void sync_worker_thread(int force) +static void sync_worker_thread(int force_no_thread) { + int force = force_no_thread; struct work_item *work; int done, used_space; @@ -1112,7 +1130,7 @@ static void sync_worker_thread(int force) work = &worker->i[worker->i_reaped & WORK_I_MASK]; thread_work_wait_sync(work, force); - MixXA(work->SSumLR, RVB, work->ns_to, work->decode_pos); + MixCD(work->SSumLR, RVB, work->ns_to, work->decode_pos); do_samples_finish(work->SSumLR, work->ns_to, work->channels_silent, work->decode_pos); @@ -1120,14 +1138,21 @@ static void sync_worker_thread(int force) done = thread_get_i_done() - worker->i_reaped; used_space = worker->i_ready - worker->i_reaped; } - if (force) + if (force_no_thread && worker->prev_work_in_thread) { + unsigned int ch, mask = worker->channels_last; + worker->prev_work_in_thread = 0; thread_sync_caches(); + for (ch = 0; mask != 0; ch++, mask >>= 1) { + if (mask & 1) + memcpy(spu.sb[ch].SB, spu.sb_thread[ch].SB, sizeof(spu.sb_thread[ch].SB)); + } + } } #else static void queue_channel_work(int ns_to, int silentch) {} -static void sync_worker_thread(int force) {} +static void sync_worker_thread(int force_no_thread) {} static const void * const worker = NULL; @@ -1138,7 +1163,7 @@ static const void * const worker = NULL; // here is the main job handler... //////////////////////////////////////////////////////////////////////// -void do_samples(unsigned int cycles_to, int do_direct) +void do_samples(unsigned int cycles_to, int force_no_thread) { unsigned int silentch; int cycle_diff; @@ -1147,16 +1172,16 @@ void do_samples(unsigned int cycles_to, int do_direct) cycle_diff = cycles_to - spu.cycles_played; if (cycle_diff < -2*1048576 || cycle_diff > 2*1048576) { - //xprintf("desync %u %d\n", cycles_to, cycle_diff); + log_unhandled("desync %u %d\n", cycles_to, cycle_diff); spu.cycles_played = cycles_to; return; } silentch = ~(spu.dwChannelsAudible | spu.dwNewChannel) & 0xffffff; - do_direct |= (silentch == 0xffffff); + force_no_thread |= (silentch == 0xffffff); if (worker != NULL) - sync_worker_thread(do_direct); + sync_worker_thread(force_no_thread); if (cycle_diff < 2 * 768) return; @@ -1164,7 +1189,7 @@ void do_samples(unsigned int cycles_to, int do_direct) ns_to = (cycle_diff / 768 + 1) & ~1; if (ns_to > NSSIZE) { // should never happen - //xprintf("ns_to oflow %d %d\n", ns_to, NSSIZE); + log_unhandled("ns_to oflow %d %d\n", ns_to, NSSIZE); ns_to = NSSIZE; } @@ -1204,7 +1229,7 @@ void do_samples(unsigned int cycles_to, int do_direct) if (unlikely(spu.rvb->dirty)) REVERBPrep(); - if (do_direct || worker == NULL || !spu_config.iUseThread) { + if (force_no_thread || worker == NULL || !spu_config.iUseThread) { do_channels(ns_to); do_samples_finish(spu.SSumLR, ns_to, silentch, spu.decode_pos); } @@ -1220,6 +1245,7 @@ void do_samples(unsigned int cycles_to, int do_direct) spu.cycles_played += ns_to * 768; spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff; + spu.spuStat = (spu.spuStat & ~0x800) | ((spu.decode_pos << 3) & 0x800); #if 0 static int ccount; static time_t ctime; ccount++; if (time(NULL) != ctime) @@ -1351,16 +1377,19 @@ void CALLBACK SPUupdate(void) // XA AUDIO -void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int unused) +void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start) { if(!xap) return; if(!xap->freq) return; // no xa freq ? bye + if (is_start) + spu.XAPlay = spu.XAFeed = spu.XAStart; if (spu.XAPlay == spu.XAFeed) do_samples(cycle, 1); // catch up to prevent source underflows later FeedXA(xap); // call main XA feeder spu.xapGlobal = xap; // store info for save states + spu.cdClearSamples = 512; } // CDDA AUDIO @@ -1373,9 +1402,21 @@ int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes, unsigned int cycle, int do_samples(cycle, 1); // catch up to prevent source underflows later FeedCDDA((unsigned char *)pcm, nbytes); + spu.cdClearSamples = 512; return 0; } +void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr, + unsigned char rl, unsigned char rr, unsigned int cycle) +{ + if (spu.XAPlay != spu.XAFeed || spu.CDDAPlay != spu.CDDAFeed) + do_samples(cycle, 1); + spu.cdv.ll = ll; + spu.cdv.lr = lr; + spu.cdv.rl = rl; + spu.cdv.rr = rr; +} + // to be called after state load void ClearWorkingState(void) { @@ -1476,6 +1517,8 @@ static void init_spu_thread(void) { int ret; + spu.sb_thread = spu.sb_thread_; + if (sysconf(_SC_NPROCESSORS_ONLN) <= 1) return; @@ -1537,7 +1580,10 @@ long CALLBACK SPUinit(void) int i; memset(&spu, 0, sizeof(spu)); - spu.spuMemC = calloc(1, 512 * 1024); + spu.spuMemC = calloc(1, 512 * 1024 + 16); + // a guard for runaway channels - End+Mute + spu.spuMemC[512 * 1024 + 1] = 1; + InitADSR(); spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling)