Reply 2180 of 2421, by hail-to-the-ryzen
Given the overflow does not occur, would this work:
if (sizeof(Type) == 1) {const Bit8u xr = signeddata ? 0x00 : 0x80;+ Bit8s d;len--;- current[0] = ((Bit8s)((*data++) ^ xr)) << 8;+ d = (Bit8s)((*data++) ^ xr);+ current[0] = d > xr ? (d << 8) | (2 * d + 1) : d << 8;- if (stereo)+ if (stereo) {- current[1] = ((Bit8s)((*data++) ^ xr)) << 8;+ d = (Bit8s)((*data++) ^ xr);+ current[1] = d > xr ? (d << 8) | (2 * d + 1) : d << 8;+ }elsecurrent[1] = current[0];
This is based on kcgen's work at https://github.com/dosbox-staging/dosbox-staging/pull/1005.
Tested with modified test code from kcgen:
// gcc convert-8bit-16bit.c -o convert-8bit-16bit.exeshort scale_uto16(unsigned char val) {if (val > 128)return (((char)(val ^0x80)) << 8) | (2 * ((char)(val ^0x80)) + 1);elsereturn (char)(val ^0x80) << 8;}short scale_sto16(char val) {if (val > 0)return (val << 8) | (2 * val + 1);elsereturn (val << 8);}void main(){int x;printf("%8s %12s\n", "value", "int-shift");unsigned char unsigned_val[] = { 0, 15, 16, 31, 32, 33, 96, 127, 128, 129, 168, 254, 255 };for (x = 0; x < 13; x++)printf("%8u %12d\n", unsigned_val[x], scale_uto16(unsigned_val[x]));printf("\n%8s %12s\n", "value", "int-shift");char signed_val[] = { -128, -96, -63, -64, -65, -33, -32, -1, 0, 1, 32, 33, 63, 64, 65, 96, 126, 127 };for (x = 0; x < 18; x++)printf("%8d %12d\n", signed_val[x], scale_sto16(signed_val[x]));}