Advertisement
Moolah60

Untitled

Aug 5th, 2021
1,005
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.06 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7. namespace AC_Audiobank_Dumper
  8. {
  9.     public static class ADPCMConverter
  10.     {
  11.         private static readonly short[] itable =
  12.         {
  13.             0,1,2,3,4,5,6,7,
  14.             -8,-7,-6,-5,-4,-3,-2,-1,
  15.         };
  16.  
  17.         private static readonly short[] itable_half =
  18.         {
  19.             0, 1,
  20.             -2, -1,
  21.         };
  22.  
  23.         private static short SignExtend16(int b, short x)
  24.         {
  25.             int m = 1 << (b - 1);
  26.             x = (short)(x & ((1 << b) - 1));
  27.             return (short)((x ^ m) - m);
  28.         }
  29.  
  30.         private static void Decode_8(in byte[] adpcm, ref int readIdx, in short[] outData, ref int writeIdx, int index, in short[] pred1, in short[] lastsmp)
  31.         {
  32.             short[] tmp = new short[8];
  33.             short[] pred2 = pred1.Skip(8).ToArray();
  34.  
  35.             //printf("pred2[] = %x\n" , pred2[0]);
  36.             for (int i = 0; i < 8; i++)
  37.             {
  38.                 tmp[i] = (short)(itable[(i & 1) == 1 ? (adpcm[readIdx++] & 0xf) : ((adpcm[readIdx] >> 4) & 0xf)] << index);
  39.                 tmp[i] = SignExtend16(index + 4, tmp[i]);
  40.             }
  41.  
  42.             for(int i=0; i<8; i++)
  43.             {
  44.                 int total = (pred1[i] * lastsmp[6]);
  45.                 total += (pred2[i] * lastsmp[7]);
  46.  
  47.                 if (i>0)
  48.                 {
  49.                     for(int x=i-1; x>-1; x--)
  50.                     {
  51.                         total += (tmp[((i - 1) - x)] * pred2[x] );
  52.                         //printf("sample: %x - pred: %x - _smp: %x\n" , ((i-1)-x) , pred2[x] , tmp[((i-1)-x)]);
  53.                     }
  54.                 }
  55.  
  56.                 //printf("pred = %x | total = %x\n" , pred2[0] , total);
  57.                 float result = ((tmp[i] << 0xb) + total) >> 0xb;
  58.                 short sample;
  59.                 if (result > 32767)
  60.                     sample = 32767;
  61.                 else if (result < -32768)
  62.                     sample = -32768;
  63.                 else
  64.                     sample = (short)result;
  65.  
  66.                 outData[writeIdx++] = sample;
  67.             }
  68.  
  69.             // update the last sample set for subsequent iterations
  70.             Buffer.BlockCopy(outData, writeIdx - 8, lastsmp, 0, sizeof(short) * 8);
  71.         }
  72.  
  73.         private static void decode_8_half(in byte[] adpcm, ref int readIdx, in short[] outData, ref int writeIdx, int index, in short[] pred1, in short[] lastsmp)
  74.         {
  75.             int i;
  76.             short[] tmp = new short[8];
  77.             short[] pred2 = pred1.Skip(8).ToArray();
  78.  
  79.             //printf("pred2[] = %x\n" , pred2[0]);
  80.  
  81.             tmp[0] = (short)(((((adpcm[readIdx]) & 0xC0) >> 6) & 0x3) << index);
  82.             tmp[0] = SignExtend16(index + 2, tmp[0]);
  83.             tmp[1] = (short)(((((adpcm[readIdx]) & 0x30) >> 4) & 0x3) << index);
  84.             tmp[1] = SignExtend16(index + 2, tmp[1]);
  85.             tmp[2] = (short)(((((adpcm[readIdx]) & 0x0C) >> 2) & 0x3) << index);
  86.             tmp[2] = SignExtend16(index + 2, tmp[2]);
  87.             tmp[3] = (short)(((adpcm[readIdx++]) & 0x03 & 0x3) << index);
  88.             tmp[3] = SignExtend16(index + 2, tmp[3]);
  89.             tmp[4] = (short)(((((adpcm[readIdx]) & 0xC0) >> 6) & 0x3) << index);
  90.             tmp[4] = SignExtend16(index + 2, tmp[4]);
  91.             tmp[5] = (short)(((((adpcm[readIdx]) & 0x30) >> 4) & 0x3) << index);
  92.             tmp[5] = SignExtend16(index + 2, tmp[5]);
  93.             tmp[6] = (short)(((((adpcm[readIdx]) & 0x0C) >> 2) & 0x3) << index);
  94.             tmp[6] = SignExtend16(index + 2, tmp[6]);
  95.             tmp[7] = (short)(((adpcm[readIdx++]) & 0x03 & 0x3) << index);
  96.             tmp[7] = SignExtend16(index + 2, tmp[7]);
  97.  
  98.             for (i = 0; i < 8; i++)
  99.             {
  100.                 int total = (pred1[i] * lastsmp[6]);
  101.                 total += (pred2[i] * lastsmp[7]);
  102.  
  103.                 if (i > 0)
  104.                 {
  105.                     for (int x = i - 1; x > -1; x--)
  106.                     {
  107.                         total += (tmp[((i - 1) - x)] * pred2[x]);
  108.                         //printf("sample: %x - pred: %x - _smp: %x\n" , ((i-1)-x) , pred2[x] , tmp[((i-1)-x)]);
  109.                     }
  110.                 }
  111.  
  112.                 //printf("pred = %x | total = %x\n" , pred2[0] , total);
  113.                 float result = ((tmp[i] << 0xb) + total) >> 0xb;
  114.                 short sample;
  115.                 if (result > 32767)
  116.                     sample = 32767;
  117.                 else if (result < -32768)
  118.                     sample = -32768;
  119.                 else
  120.                     sample = (short)result;
  121.  
  122.                 outData[writeIdx++] = sample;
  123.             }
  124.             // update the last sample set for subsequent iterations
  125.             Buffer.BlockCopy(outData, writeIdx - 8, lastsmp, 0, sizeof(short) * 8);
  126.         }
  127.  
  128.     private static (short[], int) DecodeADPCMData(in byte[] adpcm, ADPCMBook book, bool decode8Only)
  129.         {
  130.             short[] convertedData = new short[adpcm.Length * 4];
  131.             short[] lastSmp = new short[8];
  132.             int readIdx = 0;
  133.             int writeIdx = 0;
  134.             int samples = 0;
  135.  
  136.             if (!decode8Only)
  137.             {
  138.                 int len = (adpcm.Length / 9) * 9;
  139.  
  140.                 while (len > 0)
  141.                 {
  142.                     int idx = (adpcm[readIdx] >> 4) & 0xF;
  143.                     int pred = adpcm[readIdx] & 0xF;
  144.  
  145.                     // Uncomment if crash
  146.                     pred %= (int)book.nPredictors;
  147.                     len--;
  148.                     short[] pred1 = new short[16];
  149.                     Buffer.BlockCopy(book.predictors, pred * 16, pred1, 0, sizeof(short) * 16);
  150.  
  151.                     readIdx++;
  152.                     Decode_8(adpcm, ref readIdx, convertedData, ref writeIdx, idx, pred1, lastSmp);
  153.                     //readIdx += 4;
  154.                     len -= 4;
  155.                     //writeIdx += 8;
  156.  
  157.                     Decode_8(adpcm, ref readIdx, convertedData, ref writeIdx, idx, pred1, lastSmp);
  158.                     //readIdx += 4;
  159.                     len -= 4;
  160.                     //writeIdx += 8;
  161.  
  162.                     samples += 16;
  163.                 }
  164.             }
  165.             else
  166.             {
  167.                 int len = (adpcm.Length / 5) * 5;   //make sure length was actually a multiple of 5
  168.  
  169.                 while (len > 0)
  170.                 {
  171.                     int index = (adpcm[readIdx] >> 4) & 0xf;
  172.                     int pred = (adpcm[readIdx] & 0xf);
  173.  
  174.                     // to not make zelda crash but doesn't fix it
  175.                     pred %= (int)book.nPredictors;
  176.  
  177.                     len--;
  178.  
  179.                     short[] pred1 = new short[16];
  180.                     Buffer.BlockCopy(book.predictors, pred * 16, pred1, 0, sizeof(short) * 16);
  181.  
  182.                     readIdx++;
  183.                     decode_8_half(adpcm, ref readIdx, convertedData, ref writeIdx, index, pred1, lastSmp);
  184.                     //readIdx += 2;
  185.                     len -= 2;
  186.                     //writeIdx += 8;
  187.  
  188.                     decode_8_half(adpcm, ref readIdx, convertedData, ref writeIdx, index, pred1, lastSmp);
  189.                     //readIdx += 2;
  190.                     len -= 2;
  191.                     //writeIdx += 8;
  192.  
  193.                     samples += 16;
  194.                 }
  195.             }
  196.  
  197.             return (convertedData, samples);
  198.         }
  199.  
  200.         public static void ConvertToWAV(Instrument inst, in string filePath)
  201.         {
  202.             (short[] rawData, int samples) = DecodeADPCMData(inst.Sound.Wave.RawWaveData, inst.Sound.Wave.ADPCMWaveInfo.book, (inst.Sound.Wave.WaveInfo.GetFlags() & 0x30) != 0);
  203.             using var writer = new BinaryWriter(File.Create(filePath));
  204.  
  205.             // Write WAV header.
  206.             writer.Write(Encoding.ASCII.GetBytes("RIFF"));
  207.             int chunkSize = 0x28 + (samples * 2) + 0x2C - 0x8;
  208.             if (inst.Sound.Wave.ADPCMWaveInfo.loop.count > 0)
  209.                 chunkSize += 0x18;
  210.             writer.Write(chunkSize);
  211.             writer.Write(Encoding.ASCII.GetBytes("WAVE"));
  212.             writer.Write(Encoding.ASCII.GetBytes("fmt "));
  213.             writer.Write(16u); // 16 byte chunk size
  214.             writer.Write((ushort)1); // wFormatTag -- 1 = PCM
  215.             writer.Write((ushort)1); // nChannels
  216.             writer.Write(32000); // sampling rate
  217.             writer.Write(32000 * 2); // data rate -- bytes per second... not sure about this one.
  218.             writer.Write((ushort)2); // Block alignment
  219.             writer.Write((ushort)16); // Bits per sample
  220.             // TODO: Aren't we missing some stuff? http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
  221.  
  222.             // Write data tag
  223.             writer.Write(Encoding.ASCII.GetBytes("data"));
  224.             writer.Write(samples * 2); // Total samples
  225.  
  226.             // Write data
  227.             for (int i = 0; i < rawData.Length; i++)
  228.                 writer.Write(rawData[i]);
  229.  
  230.             // Write loop if present
  231.             if (inst.Sound.Wave.ADPCMWaveInfo.loop.count > 0)
  232.             {
  233.                 writer.Write(Encoding.ASCII.GetBytes("smpl")); // Chunk type
  234.                 writer.Write(0x3C); // Chunk header size
  235.                 writer.Write(0); // Manufacturer
  236.                 writer.Write(0); // Product
  237.                 writer.Write(0); // Sample Period
  238.                 writer.Write(0x3C); // MIDI Unity Node
  239.                 writer.Write(0); // MIDI Pitch Fraction
  240.                 writer.Write(0); // SMPTE Format
  241.                 writer.Write(0); // SMPTE Offset
  242.                 writer.Write(1); // Num Sample Loops
  243.                 writer.Write(0); // Sampler Data
  244.                 // Sample List
  245.                 writer.Write(inst.Sound.Wave.ADPCMWaveInfo.loop.start);
  246.                 writer.Write(inst.Sound.Wave.ADPCMWaveInfo.loop.end);
  247.                 writer.Write(0); // Pad? idk
  248.                 if (inst.Sound.Wave.ADPCMWaveInfo.loop.count == uint.MaxValue)
  249.                     writer.Write(0);
  250.                 else
  251.                     writer.Write(inst.Sound.Wave.ADPCMWaveInfo.loop.count);
  252.             }
  253.  
  254.             // Done writing WAV file.
  255.             writer.Close();
  256.         }
  257.     }
  258. }
  259.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement