Changeset 1155 for OniSplit/Sound/SoundData.cs
- Timestamp:
- May 3, 2021, 5:26:34 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
OniSplit/Sound/SoundData.cs
r1131 r1155 2 2 using System.Collections.Generic; 3 3 using System.Text; 4 using System.IO; 4 5 5 6 namespace Oni.Sound … … 7 8 internal class SoundData 8 9 { 10 public bool IsPCM; 9 11 public bool IsIMA4; 10 12 public int SampleRate; 11 13 public int ChannelCount; 12 14 public byte[] Data; 15 16 public UInt16 nGameTicks; 17 18 public int SampleCount; // calculated 19 20 //MS WAV variables 21 public int AverageDataRate; 22 public int BlockAlignment; 23 public int BitsPerSample; 24 public int HeaderSizeADPCM; 25 26 // optional MSADPCM values 27 public UInt16 SamplesPerBlock; 28 public UInt16 nCoefPairs; 29 public Int16[] CoefADPCMa; 30 public Int16[] CoefADPCMb; 13 31 14 32 public static SoundData Read(InstanceDescriptor sndd, bool do_pc_demo_test) … … 24 42 using (var reader = sndd.OpenRead()) 25 43 { 44 // sample rate 45 // duration in frames 46 47 // IMA4 or 48 // MS ADPCM: block size (default 512 for mono, 1024 for stereo, interruptible) 49 50 // sample count (automatic for IMA4 and PC demo) 51 52 53 // size in raw / offset in raw 26 54 if (sndd.IsMacFile) 27 55 { 28 sound.ChannelCount = (reader.ReadInt32() >> 1) + 1; 56 sound.ChannelCount = (reader.ReadInt32() >> 1) + 1; // TODO: interpret the low bit? (uncompressed/compressed?) 29 57 sound.SampleRate = 22050; 30 reader.Skip(4); 58 sound.nGameTicks = (UInt16)reader.ReadInt32(); 59 31 60 sound.IsIMA4 = true; 61 sound.IsPCM = false; 32 62 } 33 63 else 34 64 { 35 reader.Skip(6); // ADPCM format identifiers (change to support PCM?) 65 sound.IsPCM = false; 66 reader.Skip(4); // flags (1=?, 2=?, 4=?, 8=compressed) TODO: Try uncompressed (even for demo?) 67 reader.Skip(2); // Int16; format ID (2= ADPCM, 1=PCM?) TODO: Try uncompressed (even for demo?) 36 68 sound.ChannelCount = reader.ReadInt16(); 37 69 sound.SampleRate = reader.ReadInt32(); 38 reader.Skip(44); 70 sound.AverageDataRate = reader.ReadInt32(); // in B/s (2 or 4 for PCM; 11155, 22311 or 22179 for Vanilla ADPCM) 71 sound.BlockAlignment = reader.ReadInt16(); // 2 or 4 bytes per block for PCM; 512 or 1024 for Vanilla ADPCM 72 sound.BitsPerSample = reader.ReadInt16(); // bits per sample per channel (4 bits per sample for ADPCM, 16 bits for PCM) 73 sound.HeaderSizeADPCM = reader.ReadInt16(); // size of additional (ADPCM) header (zero for PCM); typically 32 bytes 74 75 sound.SamplesPerBlock = reader.ReadUInt16(); // UInt16; samples per block (can be inferred from block alignment etc) 76 77 sound.nCoefPairs = reader.ReadUInt16(); // usually 7 78 sound.CoefADPCMa = new Int16[sound.nCoefPairs]; // usually 256 512 0 192 240 460 392 79 sound.CoefADPCMb = new Int16[sound.nCoefPairs]; // usually 0 -256 0 64 0 -208 -232 80 for (int coefPair = 0; coefPair < sound.nCoefPairs; ++coefPair) 81 { 82 sound.CoefADPCMa[coefPair] = reader.ReadInt16(); 83 sound.CoefADPCMb[coefPair] = reader.ReadInt16(); 84 } 85 86 sound.nGameTicks = reader.ReadUInt16(); // UInt16; number of game ticks (truncated to lower value) 39 87 sound.IsIMA4 = false; 40 88 } … … 65 113 else 66 114 sound.IsIMA4 = false; 67 if (!(sound.IsIMA4)) 68 Console.WriteLine("PC-demo MS ADPCM detected; use -nodemo flag to treat as IMA4."); 115 if (!(sound.IsIMA4)) // fill in default values of WAV (MS ADCPM) header 116 { 117 sound.IsPCM = false; 118 Console.WriteLine("PC-demo MS ADPCM detected; use -nodemo flag to treat as Mac IMA4."); 119 sound.AverageDataRate = (sound.ChannelCount == 1) ? 11155 : 22311; 120 sound.BlockAlignment = (sound.ChannelCount == 1) ? 512 : 1024; 121 sound.BitsPerSample = 4; 122 sound.SamplesPerBlock = 1012; 123 sound.HeaderSizeADPCM = 32; 124 sound.nCoefPairs = 7; 125 sound.CoefADPCMa = new Int16[7]; // usually 256 512 0 192 240 460 392 126 sound.CoefADPCMb = new Int16[7]; // usually 0 -256 0 64 0 -208 -232 127 sound.CoefADPCMa[0] = 256; sound.CoefADPCMb[0] = 0; 128 sound.CoefADPCMa[1] = 512; sound.CoefADPCMb[1] = -256; 129 sound.CoefADPCMa[2] = 0; sound.CoefADPCMb[2] = 0; 130 sound.CoefADPCMa[3] = 192; sound.CoefADPCMb[3] = 64; 131 sound.CoefADPCMa[4] = 240; sound.CoefADPCMb[4] = 0; 132 sound.CoefADPCMa[5] = 460; sound.CoefADPCMb[5] = -208; 133 sound.CoefADPCMa[6] = 392; sound.CoefADPCMb[6] = -232; 134 } 69 135 } 136 // validate data and calculate sample count 137 if(sound.IsIMA4) // get the sample count 138 { 139 int nIMABlocks = sound.Data.Length / 34 / sound.ChannelCount; 140 if(sound.Data.Length - nIMABlocks * 34 * sound.ChannelCount > 0) 141 throw new InvalidDataException("IMA4 data shouldn't have incomplete blocks."); 142 sound.SampleCount = nIMABlocks * 64; 143 } 144 else 145 { 146 // TODO: validate all the parameters: resolve conflicts if any, or bail out 147 // TODO: handle PCM (the following assumes MS ADPCM) 148 if (sound.IsPCM) 149 { 150 } 151 else 152 { 153 int wholeBlocks = sound.Data.Length / sound.BlockAlignment; 154 int leftoverBytes = sound.Data.Length - (wholeBlocks * sound.BlockAlignment); 155 int leftoverSamples = 8 * (leftoverBytes - 7 * sound.ChannelCount) 156 / sound.BitsPerSample / sound.ChannelCount + 2; // assuming 4 bits per sample 157 sound.SampleCount = wholeBlocks * sound.SamplesPerBlock + leftoverSamples; 158 } 159 } 160 // Console.WriteLine("Sample count:"); 161 // Console.WriteLine(sound.SampleCount); 70 162 71 163 return sound;
Note:
See TracChangeset
for help on using the changeset viewer.