ViewVC Help
View File | Revision Log | View Changeset | Root Listing
root/Oni2/OniSplit/Sound/WavFile.cs
(Generate patch)

Comparing OniSplit/Sound/WavFile.cs (file contents):
Revision 1114 by iritscen, Wed Jan 22 14:08:57 2020 UTC vs.
Revision 1156 by geyser, Sat May 8 01:44:24 2021 UTC

# Line 1 | Line 1
1   using System;
2   using System.Collections.Generic;
3   using System.IO;
4 + //using System.Runtime.Remoting.Metadata.W3cXsd2001;
5  
6   namespace Oni.Sound
7   {
# Line 9 | Line 10 | namespace Oni.Sound
10          #region Private data
11          private const int fcc_RIFF = 0x46464952;
12          private const int fcc_WAVE = 0x45564157;
13 <        private const int fcc_fmt = 0x20746d66;
13 >        private const int fcc_fmt  = 0x20746d66;
14 >        private const int fcc_fact = 0x74636166;
15          private const int fcc_data = 0x61746164;
16  
17          private WavFormat format;
# Line 18 | Line 20 | namespace Oni.Sound
20          private int averageBytesPerSecond;
21          private int blockAlign;
22          private int bitsPerSample;
23 +        private int sampleCount;
24          private byte[] extraData;
25          private byte[] soundData;
26          #endregion
# Line 34 | Line 37 | namespace Oni.Sound
37                  if (reader.ReadInt32() != fcc_WAVE)
38                      throw new InvalidDataException("Not a WAV file");
39  
40 <                var header = new WavFile();
40 >                var header = new WavFile()
41 >                {
42 >                    sampleCount = -1
43 >                };
44  
45                  for (int chunkType, chunkSize, chunkStart; reader.Position < size; reader.Position = chunkStart + chunkSize)
46                  {
# Line 44 | Line 50 | namespace Oni.Sound
50  
51                      if (chunkType == fcc_fmt)
52                          header.ReadFormatChunk(reader, chunkSize);
53 <                    else if (chunkType == fcc_data)
53 >                    if (chunkType == fcc_fact)
54 >                        header.ReadFactChunk(reader, chunkSize);
55 >                    if (chunkType == fcc_data)
56                          header.ReadDataChunk(reader, chunkSize);
57                  }
58 <
58 >                header.TruncatePerFact();
59                  return header;
60              }
61          }
# Line 67 | Line 75 | namespace Oni.Sound
75                  extraData = new byte[0];
76          }
77  
78 +        private void ReadFactChunk(BinaryReader reader, int chunkSize)
79 +        {
80 +            sampleCount = reader.ReadInt32();
81 +        }
82 +
83          private void ReadDataChunk(BinaryReader reader, int chunkSize)
84          {
85              soundData = reader.ReadBytes(chunkSize);
86          }
87 +        private void TruncatePerFact() // TODO: MORE THOROUGH VALIDATION?
88 +        {
89 +            if(sampleCount == -1) // not explicitly set (no fact chunk present)
90 +            {
91 +                Console.WriteLine("The imported WAV file has no FACT chunk.");
92 +            }
93 +            else if (format == WavFormat.Adpcm) // calculate truncated data size
94 +            {
95 +                var blockSizeADPCM = blockAlign;
96 +                var samplesPerBlock = 2 + (blockSizeADPCM - channelCount * 7) * 8 / channelCount / bitsPerSample;
97 +                int wholeBlocks = sampleCount / samplesPerBlock;
98 +                if (wholeBlocks * blockAlign > soundData.Length)
99 +                    Console.Error.WriteLine("Sample count exceeds the range of sound data.");
100 +                int leftoverSamples = sampleCount - wholeBlocks * samplesPerBlock;
101 +                if (leftoverSamples < 2) // a block always starts with at least two samples?
102 +                    Console.Error.WriteLine("Improper trailing bytes/samples!");
103 +                if (bitsPerSample != 4) // are MS ADPCM nibbles always 4-bit-sized?
104 +                    Console.Error.WriteLine("Nibble size is expected to be 4 bits!");
105 +                int leftoverNibbles = (leftoverSamples - 2) * channelCount;
106 +                int leftoverBytes = 7 * channelCount
107 +                    + (int)Math.Ceiling((leftoverNibbles * bitsPerSample) * 0.125);
108 +                Array.Resize(ref soundData, wholeBlocks * blockAlign + leftoverBytes);
109 +            }
110 +        }
111  
112          public WavFormat Format => format;
113          public int ChannelCount => channelCount;
# Line 78 | Line 115 | namespace Oni.Sound
115          public int AverageBytesPerSecond => averageBytesPerSecond;
116          public int BlockAlign => blockAlign;
117          public int BitsPerSample => bitsPerSample;
118 +        public int SampleCount => sampleCount;
119          public byte[] ExtraData => extraData;
120          public byte[] SoundData => soundData;
121      }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)