<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.neogeodev.org//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lord+Nightmare</id>
	<title>NeoGeo Development Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.neogeodev.org//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lord+Nightmare"/>
	<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php/Special:Contributions/Lord_Nightmare"/>
	<updated>2026-07-27T21:54:21Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki.neogeodev.org//index.php?title=ADPCM_codecs&amp;diff=6478</id>
		<title>ADPCM codecs</title>
		<link rel="alternate" type="text/html" href="https://wiki.neogeodev.org//index.php?title=ADPCM_codecs&amp;diff=6478"/>
		<updated>2019-04-22T17:11:37Z</updated>

		<summary type="html">&lt;p&gt;Lord Nightmare: fix accumulator wrapping for ADPCM_A decoding to match YM2610 hardware. Thanks MrMadbrain for info, and darrylrev for hardware tests.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;ADPCM codecs are used to encode samples to be used by the [[YM2610]].&lt;br /&gt;
&lt;br /&gt;
All the code in this page process 16bit monoral, little endian raw sound data data (&amp;quot;.snd&amp;quot; files, Goldwave can output this), make sure to have your samples at the proper frequency. C# implementation.&lt;br /&gt;
&lt;br /&gt;
Remember to size/pad your sample so it&#039;s a 256 bytes multiple, this is not done in the following code.&lt;br /&gt;
&lt;br /&gt;
== ADPCM-A ==&lt;br /&gt;
This codec accepts 18.5kHz samples, playback rate is fixed.&lt;br /&gt;
&lt;br /&gt;
Inspired by Mame and MVStracker. This codec implementation was done with some trial &amp;amp; error, might not be 100% correct. It however fixes the issue with long samples degenerating.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
static short[] step_size = { &lt;br /&gt;
			   16, 17, 19, 21, 23, 25, 28, 31, 34, 37,&lt;br /&gt;
			   41, 45, 50, 55, 60, 66, 73, 80, 88, 97,&lt;br /&gt;
			   107, 118, 130, 143, 157, 173, 190, 209, 230, 253,&lt;br /&gt;
			   279, 307, 337, 371, 408, 449, 494, 544, 598, 658,&lt;br /&gt;
			   724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552&lt;br /&gt;
			   }; //49 items&lt;br /&gt;
static int[] step_adj = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 };&lt;br /&gt;
&lt;br /&gt;
//buffers&lt;br /&gt;
private byte[] buffer;	//input buffer, load your sound file into this&lt;br /&gt;
private short[] inBuffer;	//temp work buffer, used correct byte order and downsample&lt;br /&gt;
private byte[] outBuffer;	//output buffer, this is your PCM file, save it&lt;br /&gt;
&lt;br /&gt;
//decode stuff&lt;br /&gt;
private int[] jedi_table;&lt;br /&gt;
int acc = 0; //ADPCM accumulator, initial condition must be 0&lt;br /&gt;
int decstep = 0; //ADPCM decoding step, initial condition must be 0&lt;br /&gt;
&lt;br /&gt;
//encode stuff&lt;br /&gt;
int diff;&lt;br /&gt;
int step;&lt;br /&gt;
int predsample;&lt;br /&gt;
int index;&lt;br /&gt;
int prevsample = 0; // previous sample, initial condition must be 0&lt;br /&gt;
int previndex = 0; //previous index, initial condition must be 0&lt;br /&gt;
&lt;br /&gt;
//jedi table is used speed up decoding, run this to init the table before encoding. Mame copy-pasta.&lt;br /&gt;
private void jedi_table_init()&lt;br /&gt;
{&lt;br /&gt;
	int step, nib;&lt;br /&gt;
&lt;br /&gt;
	jedi_table = new int[16 * 49];&lt;br /&gt;
	for (step = 0; step &amp;lt; 49; step++)&lt;br /&gt;
	{&lt;br /&gt;
		for (nib = 0; nib &amp;lt; 16; nib++)&lt;br /&gt;
		{&lt;br /&gt;
			int value = (2 * (nib &amp;amp; 0x07) + 1) * step_size[step] / 8;&lt;br /&gt;
			jedi_table[step * 16 + nib] = ((nib &amp;amp; 0x08) != 0) ? -value : value;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//decode sub, returns decoded 12bit data&lt;br /&gt;
private short YM2610_ADPCM_A_Decode(byte code)&lt;br /&gt;
{&lt;br /&gt;
	acc += jedi_table[decstep + code];&lt;br /&gt;
	acc &amp;amp;= 0xfff; // accumulator wraps&lt;br /&gt;
	if (acc &amp;amp; 0x800) acc |= ~0xfff; // sign extend if negative&lt;br /&gt;
	decstep += step_adj[code &amp;amp; 7] * 16;&lt;br /&gt;
	if (decstep &amp;lt; 0) decstep = 0;&lt;br /&gt;
	if (decstep &amp;gt; 48 * 16) decstep = 48 * 16;&lt;br /&gt;
	return (short)acc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// our encoding sub, returns ADPCM nibble&lt;br /&gt;
private byte YM2610_ADPCM_A_Encode(short sample)&lt;br /&gt;
{&lt;br /&gt;
	int tempstep;&lt;br /&gt;
	byte code;&lt;br /&gt;
&lt;br /&gt;
	predsample = prevsample;&lt;br /&gt;
	index = previndex;&lt;br /&gt;
	step = step_size[index];&lt;br /&gt;
&lt;br /&gt;
	diff = sample - predsample;&lt;br /&gt;
	if (diff &amp;gt;= 0)&lt;br /&gt;
		code = 0;&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		code = 8;&lt;br /&gt;
		diff = -diff;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	tempstep = step;&lt;br /&gt;
	if (diff &amp;gt;= tempstep)&lt;br /&gt;
	{&lt;br /&gt;
		code |= 4;&lt;br /&gt;
		diff -= tempstep;&lt;br /&gt;
	}&lt;br /&gt;
	tempstep &amp;gt;&amp;gt;= 1;&lt;br /&gt;
	if (diff &amp;gt;= tempstep)&lt;br /&gt;
	{&lt;br /&gt;
		code |= 2;&lt;br /&gt;
		diff -= tempstep;&lt;br /&gt;
	}&lt;br /&gt;
	tempstep &amp;gt;&amp;gt;= 1;&lt;br /&gt;
	if (diff &amp;gt;= tempstep) code |= 1;&lt;br /&gt;
&lt;br /&gt;
	predsample = YM2610_ADPCM_A_Decode(code);&lt;br /&gt;
&lt;br /&gt;
	index += step_adj[code];&lt;br /&gt;
	if (index &amp;lt; 0) index = 0;&lt;br /&gt;
	if (index &amp;gt; 48) index = 48;&lt;br /&gt;
&lt;br /&gt;
	prevsample = predsample;&lt;br /&gt;
	previndex = index;&lt;br /&gt;
&lt;br /&gt;
	return code;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//our main sub, init buffers and runs the encode process&lt;br /&gt;
//enter this with your sound file loaded into buffer&lt;br /&gt;
private void YM_encode()&lt;br /&gt;
{&lt;br /&gt;
	int i;&lt;br /&gt;
&lt;br /&gt;
	//reset to initial conditions&lt;br /&gt;
	acc = 0;&lt;br /&gt;
	decstep = 0;&lt;br /&gt;
	prevsample = 0;&lt;br /&gt;
	previndex = 0;&lt;br /&gt;
&lt;br /&gt;
	//watch out for odd data count &amp;amp; allocate buffers&lt;br /&gt;
	if ((buffer.Length / 2) % 2 != 0)&lt;br /&gt;
	{&lt;br /&gt;
		inBuffer = new short[(buffer.Length / 2) + 1];&lt;br /&gt;
		inBuffer[inBuffer.Length - 1] = 0x00;&lt;br /&gt;
	}&lt;br /&gt;
	else inBuffer = new short[buffer.Length / 2];&lt;br /&gt;
	outBuffer = new byte[inBuffer.Length / 2];&lt;br /&gt;
&lt;br /&gt;
	//fix byte order and downscale data to 12 bits&lt;br /&gt;
	for (i = 0; i &amp;lt; buffer.Length; i += 2)&lt;br /&gt;
	{&lt;br /&gt;
		inBuffer[i / 2] = (short)((buffer[i]) | (buffer[i + 1] &amp;lt;&amp;lt; 8));&lt;br /&gt;
		inBuffer[i / 2] &amp;gt;&amp;gt;= 4;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	//actual encoding&lt;br /&gt;
	for (i = 0; i &amp;lt; inBuffer.Length; i += 2)&lt;br /&gt;
	{&lt;br /&gt;
		outBuffer[i / 2] = (byte)((YM2610_ADPCM_A_Encode(inBuffer[i]) &amp;lt;&amp;lt; 4) | YM2610_ADPCM_A_Encode(inBuffer[i + 1]));&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Encoding example: [[File:Gold_Rush_16b.snd.zip]]&lt;br /&gt;
&lt;br /&gt;
== ADPCM-B ==&lt;br /&gt;
This codec accepts 1.8kHz ~ 55.5kHz samples, playback rate has to be specified at runtime.&lt;br /&gt;
&lt;br /&gt;
Official codec from the [[YM2610]] datasheeet, works fine.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
static long[] stepsizeTable = { 57, 57, 57, 57, 77, 102, 128, 153, 57, 57, 57, 57, 77, 102, 128, 153 };&lt;br /&gt;
private byte[] buffer;	//our input buffer, load your sample file into this before encoding&lt;br /&gt;
private byte[] outBuffer; //our output buffer, this is your PCM file, save it after encoding. Its size has to be allocated to buffer.length / 4 (16 bits per sample to 4 bits per sample)&lt;br /&gt;
private int outBufferIndex = 0; //reset to 0 before each encoding&lt;br /&gt;
&lt;br /&gt;
private void YM2610_ADPCM_B_Encode()&lt;br /&gt;
{&lt;br /&gt;
	int lpc, flag;&lt;br /&gt;
	long i, dn, xn, stepSize;&lt;br /&gt;
	byte adpcm;&lt;br /&gt;
	byte adpcmPack = 0;&lt;br /&gt;
	short src;&lt;br /&gt;
&lt;br /&gt;
	xn = 0;&lt;br /&gt;
	stepSize = 127;&lt;br /&gt;
	flag = 0;&lt;br /&gt;
&lt;br /&gt;
	for (lpc = 0; lpc &amp;lt; (buffer.Length / 2); lpc++)&lt;br /&gt;
	{&lt;br /&gt;
		src = (short)((buffer[lpc * 2]) | (buffer[lpc * 2 + 1] &amp;lt;&amp;lt; 8)); //16 bit samples, + fixing byte order&lt;br /&gt;
		dn = src - xn;&lt;br /&gt;
		i = (Math.Abs(dn) &amp;lt;&amp;lt; 16) / (stepSize &amp;lt;&amp;lt; 14);&lt;br /&gt;
		if (i &amp;gt; 7) i = 7;&lt;br /&gt;
		adpcm = (byte)i;&lt;br /&gt;
		i = (adpcm * 2 + 1) * stepSize / 8;&lt;br /&gt;
		if (dn &amp;lt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			adpcm |= 0x8;&lt;br /&gt;
			xn -= i;&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			xn += i;&lt;br /&gt;
		}&lt;br /&gt;
		stepSize = (stepsizeTable[adpcm] * stepSize) / 64;&lt;br /&gt;
		if (stepSize &amp;lt; 127)&lt;br /&gt;
			stepSize = 127;&lt;br /&gt;
		else if (stepSize &amp;gt; 24576)&lt;br /&gt;
			stepSize = 24576;&lt;br /&gt;
		if (flag == 0)&lt;br /&gt;
		{&lt;br /&gt;
			adpcmPack = (byte)(adpcm &amp;lt;&amp;lt; 4);&lt;br /&gt;
			flag = 1;&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			adpcmPack |= adpcm;&lt;br /&gt;
			outBuffer[outBufferIndex++] = adpcmPack;&lt;br /&gt;
			flag = 0;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Decoding tool==&lt;br /&gt;
[[File:decoder_shot.png|right|thumb|DAT interface]]&lt;br /&gt;
&lt;br /&gt;
Decoding ROM files / samples can be done using the YM2610 ADPCM decoder tool.&lt;br /&gt;
It decodes A and B type samples to a WAV file.&lt;br /&gt;
&lt;br /&gt;
Works under modern windows OS, unlike previous tools that are deprecated.&lt;br /&gt;
&lt;br /&gt;
[[File:YM2610_Decoder.zip]]&lt;br /&gt;
&lt;br /&gt;
==ABOUT NEO GEO CD==&lt;br /&gt;
[[File:Pcmvader.png|right|thumb|Actual events leading to this discovery.]]&lt;br /&gt;
&lt;br /&gt;
Fun fact: Neo Geo CD does not support ADPCM-B.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Audio system]]&lt;/div&gt;</summary>
		<author><name>Lord Nightmare</name></author>
	</entry>
</feed>