Advertisement
Guest User

7shi

a guest
Mar 29th, 2009
872
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.72 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement