1
0
Fork 0
forked from len0rd/rockbox

FS#11052 -- SID Playback in Stereo

Original patch by Stefan Waigand
Updated by Igor Poretsky

Change-Id: Icaf7beb8349ab90e21b94baee627c9412cb2b55d
This commit is contained in:
Solomon Peachy 2019-07-24 13:56:58 -04:00
parent a89bf68e88
commit f2fd8fe79b
2 changed files with 121 additions and 109 deletions

View file

@ -680,6 +680,7 @@ Juan Gonzalez
Yangyong Wu Yangyong Wu
Andy Potter Andy Potter
Moshe Piekarski Moshe Piekarski
Stefan Waigand
The libmad team The libmad team
The wavpack team The wavpack team

View file

@ -55,6 +55,10 @@
* Implemented Marco Alanens suggestion for subsong selection: * Implemented Marco Alanens suggestion for subsong selection:
* Select the subsong by seeking: Each second represents a subsong * Select the subsong by seeking: Each second represents a subsong
* *
* v1.3
* Added 25-07-2019: Stefan Waigand, Igor Poretsky, Solomon Peachy
* SID playback in stereo (See FS#11052)
*
**************************/ **************************/
#define USE_FILTER #define USE_FILTER
@ -73,7 +77,9 @@ CODEC_HEADER
* *
*/ */
static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */ /* The sample buffers */
static int32_t samples_r[CHUNK_SIZE] IBSS_ATTR;
static int32_t samples_l[CHUNK_SIZE] IBSS_ATTR;
void sidPoke(int reg, unsigned char val) ICODE_ATTR; void sidPoke(int reg, unsigned char val) ICODE_ATTR;
@ -371,8 +377,8 @@ void synth_init(unsigned long mixfrq)
} }
/* render a buffer of n samples with the actual register contents */ /* render a buffer of n samples with the actual register contents */
void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR; void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR;
void synth_render (int32_t *buffer, unsigned long len) void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len)
{ {
unsigned long bp; unsigned long bp;
/* step 1: convert the not easily processable sid registers into some /* step 1: convert the not easily processable sid registers into some
@ -415,9 +421,9 @@ void synth_render (int32_t *buffer, unsigned long len)
/* now render the buffer */ /* now render the buffer */
for (bp=0;bp<len;bp++) { for (bp=0;bp<len;bp++) {
#ifdef USE_FILTER #ifdef USE_FILTER
int outo=0; int outo[2]={0,0};
#endif #endif
int outf=0; int outf[2]={0,0};
/* step 2 : generate the two output signals (for filtered and non- /* step 2 : generate the two output signals (for filtered and non-
filtered) from the osc/eg sections */ filtered) from the osc/eg sections */
for (v=0;v<3;v++) { for (v=0;v<3;v++) {
@ -524,16 +530,15 @@ void synth_render (int32_t *buffer, unsigned long len)
if (v<2 || filter.v3ena) if (v<2 || filter.v3ena)
{ {
if (osc[v].filter) if (osc[v].filter)
outf+=(((int)(outv-0x80))*osc[v].envval)>>22; outf[v&1]+=(((int)(outv-0x80))*osc[v].envval)>>22;
else else
outo+=(((int)(outv-0x80))*osc[v].envval)>>22; outo[v&1]+=(((int)(outv-0x80))*osc[v].envval)>>22;
} }
#else /* !USE_FILTER */
/* Don't use filters, just mix voices together */
outf[v&1]+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
#endif #endif
#ifndef USE_FILTER } /* for (v=0;v<3;v++) */
/* Don't use filters, just mix all voices together */
outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
#endif
}
#ifdef USE_FILTER #ifdef USE_FILTER
@ -549,23 +554,29 @@ void synth_render (int32_t *buffer, unsigned long len)
* This filter sounds a lot like the 8580, as the low-quality, dirty * This filter sounds a lot like the 8580, as the low-quality, dirty
* sound of the 6581 is uuh too hard to achieve :) */ * sound of the 6581 is uuh too hard to achieve :) */
filter.h = quickfloat_ConvertFromInt(outf) - (filter.b>>8)*filter.rez - filter.l; outf[0]+=outf[2]; /* mix voice 1 and 3 to right channel */
for (v=0;v<2;v++) { /* do step 3 for both channels */
filter.h = quickfloat_ConvertFromInt(outf[v]) - (filter.b>>8)*filter.rez - filter.l;
filter.b += quickfloat_Multiply(filter.freq, filter.h); filter.b += quickfloat_Multiply(filter.freq, filter.h);
filter.l += quickfloat_Multiply(filter.freq, filter.b); filter.l += quickfloat_Multiply(filter.freq, filter.b);
outf = 0; outf[v] = 0;
if (filter.l_ena) outf+=quickfloat_ConvertToInt(filter.l); if (filter.l_ena) outf[v]+=quickfloat_ConvertToInt(filter.l);
if (filter.b_ena) outf+=quickfloat_ConvertToInt(filter.b); if (filter.b_ena) outf[v]+=quickfloat_ConvertToInt(filter.b);
if (filter.h_ena) outf+=quickfloat_ConvertToInt(filter.h); if (filter.h_ena) outf[v]+=quickfloat_ConvertToInt(filter.h);
int final_sample = (filter.vol*(outo+outf));
*(buffer+bp)= GenerateDigi(final_sample)<<13;
#endif
#ifndef USE_FILTER
*(buffer+bp) = GenerateDigi(outf)<<3;
#endif
} }
/* mix in other channel to reduce stereo panning for better sound on headphones */
int final_sample_r = filter.vol*((outo[0]+outf[0]) + ((outo[1]+outf[1])>>4));
int final_sample_l = filter.vol*((outo[1]+outf[1]) + ((outo[0]+outf[0])>>4));
*(buffer_r+bp)= GenerateDigi(final_sample_r)<<13;
*(buffer_l+bp)= GenerateDigi(final_sample_l)<<13;
#else /* !USE_FILTER */
*(buffer_r+bp) = GenerateDigi(outf[0])<<3;
*(buffer_l+bp) = GenerateDigi(outf[1])<<3;
#endif
} /*for (bp=0;bp<len;bp++) */
} }
@ -1238,8 +1249,8 @@ enum codec_status codec_main(enum codec_entry_call_reason reason)
ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE); ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE);
/* Sample depth is 28 bit host endian */ /* Sample depth is 28 bit host endian */
ci->configure(DSP_SET_SAMPLE_DEPTH, 28); ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
/* Mono output */ /* Stereo output */
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
} }
return CODEC_OK; return CODEC_OK;
@ -1323,19 +1334,19 @@ enum codec_status codec_run(void)
} }
if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE) if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
{ {
synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered); synth_render(samples_r+nSamplesRendered, samples_l+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
nSamplesToRender -= CHUNK_SIZE-nSamplesRendered; nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
nSamplesRendered = CHUNK_SIZE; nSamplesRendered = CHUNK_SIZE;
} }
else else
{ {
synth_render(samples+nSamplesRendered, nSamplesToRender); synth_render(samples_r+nSamplesRendered, samples_l+nSamplesRendered, nSamplesToRender);
nSamplesRendered += nSamplesToRender; nSamplesRendered += nSamplesToRender;
nSamplesToRender = 0; nSamplesToRender = 0;
} }
} }
ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE); ci->pcmbuf_insert(samples_r, samples_l, CHUNK_SIZE);
} }
return CODEC_OK; return CODEC_OK;