Guest User

7shi

a guest
Mar 29th, 2009
804
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // C# IMA ADPCM decoder
  2. // This source code is in the public domain.
  3. // usage: new SoundPlayer(new IMA_ADPCM("imaadpcm.wav")).Play();
  4.  
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Text;
  9.  
  10. namespace Decoder
  11. {
  12.     public enum WAVE_FORMAT
  13.     {
  14.         UNKNOWN,
  15.         PCM,
  16.         ADPCM,
  17.         IMA_ADPCM = 0x11
  18.     }
  19.  
  20.     public class IMA_ADPCM : Stream
  21.     {
  22.         private Stream fs;
  23.         private int length, position, blocklen;
  24.         public ushort Channels;
  25.         public int SamplesPerSec;
  26.         public ushort BlockAlign;
  27.         private int DataPosition, DataSize;
  28.         private byte[] Header;
  29.  
  30.         public IMA_ADPCM(string path)
  31.             : this(new FileStream(path, FileMode.Open))
  32.         {
  33.         }
  34.  
  35.         public IMA_ADPCM(Stream stream)
  36.         {
  37.             fs = stream;
  38.             if (ReadID() != "RIFF")
  39.                 throw Abort("Invalid RIFF header");
  40.             ReadInt32();
  41.             if (ReadID() != "WAVE")
  42.                 throw Abort("Wave type is expected");
  43.             int fmtsize = 0;
  44.             DataSize = 0;
  45.             while (fs.Position < fs.Length)
  46.             {
  47.                 switch (ReadID())
  48.                 {
  49.                     case "fmt ":
  50.                         fmtsize = ReadInt32();
  51.                         if (ReadUInt16() != (ushort)WAVE_FORMAT.IMA_ADPCM)
  52.                             throw Abort("Not IMA ADPCM");
  53.                         Channels = ReadUInt16();
  54.                         SamplesPerSec = ReadInt32();
  55.                         ReadInt32();
  56.                         BlockAlign = ReadUInt16();
  57.                         if (ReadUInt16() != 4)
  58.                             throw Abort("Not 4-bit format");
  59.                         ReadBytes(fmtsize - 16);
  60.                         break;
  61.                     case "data":
  62.                         DataSize = ReadInt32();
  63.                         DataPosition = (int)fs.Position;
  64.                         fs.Position += DataSize;
  65.                         break;
  66.                     default:
  67.                         var size = ReadInt32();
  68.                         fs.Position += size;
  69.                         break;
  70.                 }
  71.             }
  72.             if (fmtsize == 0)
  73.                 throw Abort("No format information");
  74.             else if (DataSize == 0)
  75.                 throw Abort("No data");
  76.  
  77.             int blocks = (int)(DataSize / BlockAlign);
  78.             blocklen = (BlockAlign - Channels * 4) * 4 + Channels * 2;
  79.             int datalen = blocks * blocklen;
  80.             length = datalen + 44;
  81.  
  82.             var ms = new MemoryStream();
  83.             var bw = new BinaryWriter(ms);
  84.             bw.Write(Encoding.UTF8.GetBytes("RIFF"));
  85.             bw.Write(length - 8);
  86.             bw.Write(Encoding.UTF8.GetBytes("WAVE"));
  87.             bw.Write(Encoding.UTF8.GetBytes("fmt "));
  88.             bw.Write(16);
  89.             bw.Write((ushort)WAVE_FORMAT.PCM); // FormatTag
  90.             bw.Write(Channels);
  91.             bw.Write(SamplesPerSec);
  92.             bw.Write(SamplesPerSec * Channels * 2); // AvgBytesPerSec
  93.             bw.Write((ushort)(Channels * 2)); // BlockAlign
  94.             bw.Write((ushort)16); // BitsPerSample
  95.             bw.Write(Encoding.UTF8.GetBytes("data"));
  96.             bw.Write(datalen);
  97.             Header = ms.ToArray();
  98.             bw.Close();
  99.             ms.Close();
  100.         }
  101.  
  102.         private int CacheNo = -1;
  103.         private byte[] Cache;
  104.  
  105.         public void Decode(string path)
  106.         {
  107.             using (var fs = new FileStream(path, FileMode.Create))
  108.             {
  109.                 position = 0;
  110.                 fs.Write(Header, 0, Header.Length);
  111.                 int blocks = DataSize / BlockAlign;
  112.                 for (int i = 0; i < blocks; i++)
  113.                 {
  114.                     var block = DecodeBlock(i);
  115.                     fs.Write(block, 0, block.Length);
  116.                 }
  117.             }
  118.         }
  119.  
  120.         public IEnumerable<byte[]> DecodeSamples()
  121.         {
  122.             position = 0;
  123.             int blocks = DataSize / BlockAlign;
  124.             for (int i = 0; i < blocks; i++)
  125.             {
  126.                 var block = DecodeBlock(i);
  127.                 yield return block;
  128.             }
  129.         }
  130.  
  131.         private byte[] DecodeBlock(int n)
  132.         {
  133.             if (n >= DataSize / BlockAlign) return null;
  134.             if (CacheNo == n) return Cache;
  135.  
  136.             int pos = DataPosition + n * BlockAlign;
  137.             if (pos >= fs.Length) return null;
  138.  
  139.             fs.Position = pos;
  140.             var data = ReadBytes(BlockAlign);
  141.             var ms = new MemoryStream();
  142.             var bw = new BinaryWriter(ms);
  143.             var v = new SampleValue[Channels];
  144.             for (int ch = 0; ch < Channels; ch++)
  145.             {
  146.                 v[ch] = new SampleValue(data, ch * 4);
  147.                 bw.Write(v[ch].Value);
  148.             }
  149.             int ch4 = Channels * 4;
  150.             for (int i = ch4; i < BlockAlign; i += ch4)
  151.             {
  152.                 for (int j = 0; j < 4; j++)
  153.                 {
  154.                     for (int ch = 0; ch < Channels; ch++)
  155.                         bw.Write(v[ch].Next(data[i + j + ch * 4] & 0xf));
  156.                     for (int ch = 0; ch < Channels; ch++)
  157.                         bw.Write(v[ch].Next(data[i + j + ch * 4] >> 4));
  158.                 }
  159.             }
  160.             CacheNo = n;
  161.             Cache = ms.ToArray();
  162.             bw.Close();
  163.             ms.Close();
  164.             return Cache;
  165.         }
  166.  
  167.         private struct SampleValue
  168.         {
  169.             public short Value;
  170.             public int Index;
  171.  
  172.             public SampleValue(byte[] value, int startIndex)
  173.             {
  174.                 Value = BitConverter.ToInt16(value, startIndex);
  175.                 Index = value[startIndex + 2];
  176.             }
  177.  
  178.             private static int[] StepTable = new[]
  179.             {
  180.                 7, 8, 9, 10, 11, 12, 13, 14,
  181.                 16, 17, 19, 21, 23, 25, 28, 31,
  182.                 34, 37, 41, 45, 50, 55, 60, 66,
  183.                 73, 80, 88, 97, 107, 118, 130, 143,
  184.                 157, 173, 190, 209, 230, 253, 279, 307,
  185.                 337, 371, 408, 449, 494, 544, 598, 658,
  186.                 724, 796, 876, 963, 1060, 1166, 1282, 1411,
  187.                 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
  188.                 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
  189.                 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
  190.                 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
  191.                 32767
  192.             };
  193.  
  194.             private static int[] IndexTable = new[]
  195.             {
  196.                 -1, -1, -1, -1, 2, 4, 6, 8,
  197.                 -1, -1, -1, -1, 2, 4, 6, 8
  198.             };
  199.  
  200.             public short Next(int v)
  201.             {
  202.                 int d = 0;
  203.                 int s = StepTable[Index];
  204.                 if ((v & 4) != 0) d += s;
  205.                 if ((v & 2) != 0) d += s >> 1;
  206.                 if ((v & 1) != 0) d += s >> 2;
  207.                 d += s >> 3;
  208.                 if ((v & 8) != 0) d = -d;
  209.                 int val = ((int)Value) + d;
  210.                 if (val > short.MaxValue) val = short.MaxValue;
  211.                 if (val < short.MinValue) val = short.MinValue;
  212.  
  213.                 int idx = Index + IndexTable[v];
  214.                 if (idx >= StepTable.Length) idx = StepTable.Length - 1;
  215.                 if (idx < 0) idx = 0;
  216.  
  217.                 Value = (short)val;
  218.                 Index = idx;
  219.                 return Value;
  220.             }
  221.         }
  222.  
  223.         private byte[] ReadBytes(int length)
  224.         {
  225.             var ret = new byte[length];
  226.             if (length > 0) fs.Read(ret, 0, length);
  227.             return ret;
  228.         }
  229.  
  230.         private string ReadID() { return Encoding.UTF8.GetString(ReadBytes(4), 0, 4); }
  231.         private int ReadInt32() { return BitConverter.ToInt32(ReadBytes(4), 0); }
  232.         private uint ReadUInt32() { return BitConverter.ToUInt32(ReadBytes(4), 0); }
  233.         private ushort ReadUInt16() { return BitConverter.ToUInt16(ReadBytes(2), 0); }
  234.  
  235.         protected override void Dispose(bool disposing)
  236.         {
  237.             if (fs != null)
  238.             {
  239.                 fs.Close();
  240.                 fs = null;
  241.             }
  242.             base.Dispose(disposing);
  243.         }
  244.  
  245.         public override bool CanRead { get { return true; } }
  246.         public override bool CanSeek { get { return true; } }
  247.         public override bool CanWrite { get { return false; } }
  248.         public override void Flush() { }
  249.         public override long Length { get { return length; } }
  250.  
  251.         public override long Position
  252.         {
  253.             get { return position; }
  254.             set
  255.             {
  256.                 position = (int)value;
  257.                 if (position < 0) position = 0;
  258.                 if (position > length) position = length;
  259.             }
  260.         }
  261.  
  262.         public override int Read(byte[] buffer, int offset, int count)
  263.         {
  264.             int len = Math.Min(count, length - position);
  265.             int hlen = Header.Length;
  266.             for (int i = 0; i < len; )
  267.             {
  268.                 int p = position + i;
  269.                 if (p < hlen)
  270.                 {
  271.                     int len2 = Math.Min(len - i, hlen - p);
  272.                     Array.Copy(Header, p, buffer, offset + i, len2);
  273.                     i += len2;
  274.                 }
  275.                 else
  276.                 {
  277.                     int bn = (p - hlen) / blocklen;
  278.                     int bs = bn * blocklen + hlen;
  279.                     int be = bs + blocklen;
  280.                     int len2 = Math.Min(len - i, be - p);
  281.                     var data = DecodeBlock(bn);
  282.                     Array.Copy(data, p - bs, buffer, offset + i, len2);
  283.                     i += len2;
  284.                 }
  285.             }
  286.             position += len;
  287.             return len;
  288.         }
  289.  
  290.         public override long Seek(long offset, SeekOrigin origin)
  291.         {
  292.             switch (origin)
  293.             {
  294.                 case SeekOrigin.Begin:
  295.                     Position = offset;
  296.                     break;
  297.                 case SeekOrigin.Current:
  298.                     Position += offset;
  299.                     break;
  300.                 case SeekOrigin.End:
  301.                     Position = length + (int)origin;
  302.                     break;
  303.             }
  304.             return Position;
  305.         }
  306.  
  307.         public override void SetLength(long value)
  308.         {
  309.             throw new NotImplementedException();
  310.         }
  311.  
  312.         public override void Write(byte[] buffer, int offset, int count)
  313.         {
  314.             throw new NotImplementedException();
  315.         }
  316.  
  317.         public Exception Abort(string message)
  318.         {
  319.             Dispose();
  320.             return new Exception(message);
  321.         }
  322.     }
  323. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×