
http://nemesis.hacking-cult.org/MegaDrive/Documentation/YM2608.ZIP  
http://web.archive.org/web/20050215154112/http://www.memb.jp/~dearna/ma/ym2608/ym2608adpcm.c

/*
	YM2608 ADPCM Codec

	code : Masashi Wada ( DEARNA )
	http://www.memb.jp/~dearna/
*/

#include <math.h>

static long stepsizeTable[ 16 ] =
{
	57, 57, 57, 57, 77,102,128,153,
	57, 57, 57, 57, 77,102,128,153
};

int YM2608ADPCM_Encode( short *src , unsigned char *dest , int len )
{
	int lpc , flag;
	long i , dn , xn , stepSize;
	unsigned char adpcm;
	unsigned char adpcmPack;

	/* l̐ݒ */
	xn			= 0;
	stepSize	= 127;
	flag		= 0;
	
	for( lpc = 0 ; lpc < len ; lpc++ )
	{
		/* GR[h2 */
		dn = *src - xn;
		src++;

		/*
			GR[h3A4
			I = | dn | / Sn An߂B
			搔gpĐʂŉZB
		*/
		i = ( abs( dn ) << 16 ) / ( stepSize << 14 );
		if( i > 7 ) i = 7;
		adpcm = ( unsigned char )i;

		/*
			GR[h5
			L3+L2/2+L1/4+1/8 * stepSize 8{ĐZ
		*/
		i = ( adpcm * 2 + 1 ) * stepSize / 8;

		/* 1-2*L4 -> L41̏ꍇ-1̂Ɠ */
		if( dn < 0 )
		{
			/*
				-̏ꍇrbgtB
				GR[h5ADPCMזɂȂ̂ŁA\lXV܂ŕۗB
			*/
			adpcm |= 0x8;
			xn -= i;
		}
		else
		{
			xn += i;
		}

		/*
			GR[h6
			XebvTCY̍XV
		*/
		stepSize = ( stepsizeTable[ adpcm ] * stepSize ) / 64;

		/* GR[h7	*/
		if( stepSize < 127 )
			stepSize = 127;
		else if( stepSize > 24576 )
			stepSize = 24576;

		/* ADPCMŕۑ */
		if( flag == 0 )
		{
			adpcmPack = ( adpcm << 4 ) ;
			flag = 1;
		}
		else
		{
			adpcmPack |= adpcm;
			*dest = adpcmPack;
			dest++;
			flag = 0;
		}
	}

	return 0;
}

int YM2608ADPCM_Decode( unsigned char *src , short *dest , int len )
{
	int lpc , flag , shift , step;
	long i , xn , stepSize;
	long adpcm;

	/* l̐ݒ */
	xn			= 0;
	stepSize	= 127;
	flag		= 0;
	shift		= 4;
	step		= 0;

	for( lpc = 0 ; lpc < len ; lpc++ )
	{
		adpcm = ( *src >> shift ) & 0xf;

		/*
			fR[h2A3
			L3+L2/2+L1/4+1/8 * stepSize 8{ĐZ
		*/
		i = ( ( adpcm & 7 ) * 2 + 1 ) * stepSize / 8;
		if( adpcm & 8 )
			xn -= i;
		else
			xn += i;

		/* fR[h4 */
		if( xn > 32767 )
			xn = 32767;
		else if( xn < -32768 )
			xn = -32768;

		/* fR[h5 */
		stepSize = stepSize * stepsizeTable[ adpcm ] / 64;

		/* fR[h6 */
		if( stepSize < 127 )
			stepSize = 127;
		else if ( stepSize > 24576 )
			stepSize = 24576;

		/* PCMŕۑ */
		*dest = ( short )xn;
		dest++;

		src += step;
		step = step ^ 1;
		shift = shift ^ 4;
	}

	return 0;
}

