diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index 4833dea33..6e5266b43 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -9,7 +9,7 @@ #define SB_SUBTYPE_ESS_ES1688 4 /* ESS Technology ES1688 */ /* ESS-related */ -#define IS_ESS(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_ESS_ES688) +#define IS_ESS(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_ESS_ES688 || (dsp)->sb_subtype == SB_SUBTYPE_ESS_ES1688) /* check for future ESS cards here */ /* aztech-related */ #define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) /* check for future AZT cards here */ @@ -148,6 +148,13 @@ typedef struct sb_dsp_t { uint8_t ess_reload_len; uint32_t ess_dma_counter; + // ESPCM + uint8_t espcm_sample_idx; + uint8_t espcm_range; + uint8_t espcm_byte_buffer[4]; + uint8_t espcm_code_buffer[10]; /* used for ESPCM_3 */ + uint8_t espcm_last_nibble; /* used for ESPCM_3 */ + mpu_t *mpu; } sb_dsp_t; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index f179ce284..54c8bcc5e 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -32,6 +32,9 @@ #define ADPCM_4 1 #define ADPCM_26 2 #define ADPCM_2 3 +#define ESPCM_4 4 +#define ESPCM_3 5 +#define ESPCM_1 6 // not ESPCM_2, unlike what the manuals say /*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/ #define SB_DSP_REC_SAFEFTY_MARGIN 4096 @@ -116,6 +119,25 @@ uint8_t adjustMap2[24] = { 252, 0, 252, 0 }; +uint8_t espcm_range_map[256] = { + -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, + -10, -8, -7, -5, -4, -3, -2, -1, 0, 2, 3, 4, 5, 6, 8, 9, + -12, -11, -9, -8, -6, -5, -3, -2, 0, 2, 3, 5, 6, 8, 10, 11, + -14, -12, -11, -9, -7, -5, -4, -2, 0, 2, 4, 5, 7, 9, 11, 13, + -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, + -21, -18, -16, -13, -11, -8, -6, -3, 0, 2, 5, 7, 10, 12, 15, 18, + -27, -24, -21, -17, -14, -11, -8, -4, 0, 3, 7, 10, 13, 17, 20, 24, + -35, -28, -24, -20, -16, -12, -8, -4, 0, 4, 8, 12, 16, 20, 24, 28, + -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, + -48, -42, -36, -30, -24, -18, -12, -6, 0, 6, 12, 18, 24, 30, 36, 43, + -56, -49, -42, -35, -28, -21, -14, -7, 0, 7, 14, 21, 28, 35, 42, 49, + -72, -63, -54, -45, -36, -27, -18, -9, 0, 9, 18, 27, 36, 45, 54, 63, + -85, -74, -64, -53, -43, -32, -22, -11, 0, 11, 22, 33, 43, 54, 64, 75, + -102, -98, -85, -71, -58, -45, -31, -14, 0, 13, 26, 39, 52, 65, 78, 90, + -127,-112, -96, -80, -64, -48, -32, -16, 0, 16, 32, 48, 64, 80, 96, 112, + -128,-127,-109, -91, -73, -54, -36, -18, 0, 18, 36, 54, 73, 91, 109, 127 +}; + double low_fir_sb16_coef[4][SB16_NCoef]; #ifdef ENABLE_SB_DSP_LOG @@ -1216,6 +1238,78 @@ sb_exec_command(sb_dsp_t *dsp) case 0x48: /* Set DSP block transfer size */ dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); break; + case 0x65: /* 4-bit ESPCM output with reference */ + if (!IS_ESS(dsp)) + { + break; + } + dsp->sbref = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + dsp->ess_dma_counter++; + fallthrough; + case 0x64: /* 4-bit ESPCM output */ + if (IS_ESS(dsp)) + { + sb_start_dma(dsp, 1, 0, ESPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + dsp->ess_dma_counter++; + } + break; + case 0x67: /* 3-bit ESPCM output with reference */ + if (!IS_ESS(dsp)) + { + break; + } + dsp->sbref = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + dsp->ess_dma_counter++; + fallthrough; + case 0x66: /* 3-bit ESPCM output */ + if (IS_ESS(dsp)) + { + sb_start_dma(dsp, 1, 0, ESPCM_3, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + dsp->ess_dma_counter++; + } + break; + case 0x6B: /* 1-bit ESPCM output with reference */ + if (!IS_ESS(dsp)) + { + break; + } + dsp->sbref = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + dsp->ess_dma_counter++; + fallthrough; + case 0x6A: /* 1-bit ESPCM output */ + if (IS_ESS(dsp)) + { + sb_start_dma(dsp, 1, 0, ESPCM_1, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv); + dsp->sb_8_length--; + dsp->ess_dma_counter++; + } + break; + case 0x6F: /* 4-bit ESPCM input with reference */ + if (!IS_ESS(dsp)) + { + break; + } + dsp->sbref = (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + fallthrough; + case 0x6E: /* 4-bit ESPCM input */ + if (IS_ESS(dsp)) + { + sb_start_dma_i(dsp, 1, 0, ESPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80; + dsp->record_pos_read += 2; + dsp->record_pos_read &= 0xFFFF; + } + break; case 0x75: /* 4-bit ADPCM output with reference */ dsp->sbref = dsp->dma_readb(dsp->dma_priv); dsp->sbstep = 0; @@ -2060,6 +2154,112 @@ pollsb(void *priv) dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; + case ESPCM_4: + if (dsp->espcm_sample_idx >= 19) + { + dsp->espcm_sample_idx = 0; + } + if (dsp->espcm_sample_idx == 0) + { + dsp->espcm_byte_buffer[0] = dsp->dma_readb(dsp->dma_priv); + dsp->espcm_sample_idx++; + dsp->sb_8_length--; + dsp->ess_dma_counter++; + + dsp->espcm_range = dsp->espcm_byte_buffer[0] & 0x0F; + tempi = dsp->espcm_byte_buffer[0] >> 4; + } + else if (dsp->espcm_sample_idx & 1) + { + dsp->espcm_byte_buffer[0] = dsp->dma_readb(dsp->dma_priv); + dsp->espcm_sample_idx++; + dsp->sb_8_length--; + dsp->ess_dma_counter++; + + tempi = dsp->espcm_byte_buffer[0] & 0x0F; + } + else + { + dsp->espcm_sample_idx++; + tempi = dsp->espcm_byte_buffer[0] >> 4; + } + + tempi |= (dsp->espcm_range << 4); + data[0] = espcm_range_map[tempi]; + dsp->sbdat = data[0] << 8; + if (dsp->stereo) + { + sb_dsp_log("pollsb: ESPCM 4, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + { + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + } + break; + + case ESPCM_3: + // TODO + break; + + case ESPCM_1: + if (dsp->espcm_sample_idx >= 19) + { + dsp->espcm_sample_idx = 0; + } + if (dsp->espcm_sample_idx == 0) + { + dsp->espcm_byte_buffer[0] = dsp->dma_readb(dsp->dma_priv); + dsp->espcm_sample_idx++; + dsp->sb_8_length--; + dsp->ess_dma_counter++; + + dsp->espcm_range = dsp->espcm_byte_buffer[0] & 0x0F; + dsp->espcm_byte_buffer[0] >>= 5; + tempi = dsp->espcm_byte_buffer[0] & 1 ? 0xF : 0x0; + dsp->espcm_byte_buffer[0] >>= 1; + } + else if (dsp->espcm_sample_idx == 3 | dsp->espcm_sample_idx == 11) + { + dsp->espcm_byte_buffer[0] = dsp->dma_readb(dsp->dma_priv); + dsp->espcm_sample_idx++; + dsp->sb_8_length--; + dsp->ess_dma_counter++; + + tempi = dsp->espcm_byte_buffer[0] & 1 ? 0xF : 0x0; + dsp->espcm_byte_buffer[0] >>= 1; + } + else + { + dsp->espcm_sample_idx++; + tempi = dsp->espcm_byte_buffer[0] & 1 ? 0xF : 0x0; + dsp->espcm_byte_buffer[0] >>= 1; + } + + tempi |= (dsp->espcm_range << 4); + data[0] = espcm_range_map[tempi]; + dsp->sbdat = data[0] << 8; + if (dsp->stereo) + { + sb_dsp_log("pollsb: ESPCM 1, dsp->stereo, %s channel, %04X\n", + dsp->sbleftright ? "left" : "right", dsp->sbdat); + if (dsp->sbleftright) + dsp->sbdatl = dsp->sbdat; + else + dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + { + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + } + break; + default: break; }