changeset 2471:2f4c17b4fe10

Switch to YMZ280B ADPCM algorithm. Still sounds a little rough, but definitely much better than with the YM2610 ADPCM-A setup
author Michael Pavone <pavone@retrodev.com>
date Sun, 25 Feb 2024 11:08:35 -0800
parents 6bec9e66d0db
children f171a12fc98c
files ymz263b.c ymz263b.h
diffstat 2 files changed, 41 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/ymz263b.c	Sat Feb 24 23:16:37 2024 -0800
+++ b/ymz263b.c	Sun Feb 25 11:08:35 2024 -0800
@@ -234,49 +234,45 @@
 					break;
 				}
 				pcm->output = sample;
+				if (pcm->output & 0x800) {
+					pcm->output |= 0xF000;
+				} else {
+					pcm->output &= 0x0FFF;
+				}
 			} else {
-				//Values taken from YMFM 2610 ADPCM-A implementation
-				//They are almost certainly wrong for YMZ263B
-				static const int16_t mults[49] = {
-					16,  17,  19,   21,   23,   25,   28,
-					31,  34,  37,   41,   45,   50,   55,
-					60,  66,  73,   80,   88,   97,   107,
-					118, 130, 143,  157,  173,  190,  209,
-					230, 253, 279,  307,  337,  371,  408,
-					449, 494, 544,  598,  658,  724,  796,
-					876, 963, 1060, 1166, 1282, 1411, 1552
-				};
-				static const int8_t index_deltas[8] = {
-					-1, -1, -1, -1, 2, 5, 7, 9
-				};
+				//This uses superctr's YMZ280B decoder as a reference
+				//That chip has 16-bit output, but supposedly is compatible
+				//with ADPCM data from the YM263B
+				//Currently I'm 'calculating as 16-bit internally and
+				//truncating to 12-bit on output
 				uint16_t mag = sample & 7;
-				int16_t delta = (((mag << 1) + 1) * mults[pcm->adpcm_mul_index]) >> 3;
+				int32_t delta = (((mag << 1) + 1) * pcm->adpcm_step) >> 3;
+				if (delta > 0x7FFF) {
+					delta = 0x7FFF;
+				}
 				if (sample & 8) {
 					delta = -delta;
 				}
-				uint8_t old_index = pcm->adpcm_mul_index;
-				pcm->output += delta;
-				if (pcm->adpcm_mul_index || mag > 3) {
-					pcm->adpcm_mul_index += index_deltas[mag];
-					if (pcm->adpcm_mul_index >= sizeof(mults)) {
-						pcm->adpcm_mul_index = sizeof(mults) - 1;
-					}
+				int32_t value = ((int16_t)pcm->output);
+				value = (value * 254) >> 8;
+				value += delta;
+				if (value > 0x7FFF) {
+					value = 0x7FFF;
+				} else if (value < -0x8000) {
+					value = -0x8000;
 				}
-				int16_t output = pcm->output;
-				//Supposedly the YM2610 and YM2608 wrap around rather than clamp
-				//but since my tables have the wrong values I need to clamp
-				//in order to get something resembling the correct output
-				if (output > 0x7FF) {
-					pcm->output = 0x7FF;
-				} else if (output < -0x800) {
-					pcm->output = -0x800;
+				pcm->output = value;
+				
+				static const uint16_t step_adjust[8] = {
+					230, 230, 230, 230, 307, 409, 512, 614
+				};
+				int32_t step = pcm->adpcm_step * step_adjust[mag];
+				if (step > 24576) {
+					step = 24576;
+				} else if (step < 127) {
+					step = 127;
 				}
-				//printf("Sample %X, mag %X, delta %d, old index %d, new index %d, out %d\n", sample, mag, delta, old_index, pcm->adpcm_mul_index, (int16_t)pcm->output);
-			}
-			if (pcm->output & 0x800) {
-				pcm->output |= 0xF000;
-			} else {
-				pcm->output &= 0x0FFF;
+				pcm->adpcm_step = step;
 			}
 			if (pcm_fifo_free(pcm) > fifo_threshold) {
 				ymz->status |= pcm == &ymz->pcm[0] ? STATUS_FIF1 : STATUS_FIF2;
@@ -296,11 +292,15 @@
 	
 	if (pcm->regs[0] & BIT_PLY_REC) {
 		//TODO: Volume
+		int16_t value = pcm->output;
+		if (!(pcm->regs[0] & BIT_PCM)) {
+			value >>= 4;
+		}
 		if (pcm->regs[0] & BIT_PAN_L) {
-			output[0] += pcm->output;
+			output[0] += value;
 		}
 		if (pcm->regs[0] & BIT_PAN_R) {
-			output[1] += pcm->output;
+			output[1] += value;
 		}
 	}
 }
@@ -505,7 +505,7 @@
 					ymz->pcm[1].fifo_read = FIFO_EMPTY;
 					ymz->pcm[1].nibble = ymz->pcm[1].nibble_write = 0;
 					ymz->pcm[1].output = 0;
-					ymz->pcm[1].adpcm_mul_index = 0;
+					ymz->pcm[1].adpcm_step = 127;
 				}
 			}
 			ymz->pcm[1].regs[ymz->address - YMZ_PCM_PLAY_CTRL] = value;
@@ -539,7 +539,7 @@
 				ymz->pcm[0].fifo_read = FIFO_EMPTY;
 				ymz->pcm[0].nibble = ymz->pcm[1].nibble_write = 0;
 				ymz->pcm[0].output = 0;
-				ymz->pcm[0].adpcm_mul_index = 0;
+				ymz->pcm[0].adpcm_step = 127;
 			}
 			ymz->pcm[0].regs[ymz->address - YMZ_PCM_PLAY_CTRL] = value;
 			if (ymz->address == YMZ_PCM_DATA) {
--- a/ymz263b.h	Sat Feb 24 23:16:37 2024 -0800
+++ b/ymz263b.h	Sun Feb 25 11:08:35 2024 -0800
@@ -7,6 +7,7 @@
 
 typedef struct {
 	uint16_t output;
+	uint16_t adpcm_step;
 	uint8_t  fifo[128];
 	uint8_t  fifo_read;
 	uint8_t  fifo_write;
@@ -15,7 +16,6 @@
 	uint8_t  counter;
 	uint8_t  nibble;
 	uint8_t  nibble_write;
-	uint8_t  adpcm_mul_index;
 } ymz263b_pcm;
 
 typedef struct {