Advertisement
Guest User

7shi

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