source: OniSplit/Sound/WavFile.cs @ 1154

Last change on this file since 1154 was 1154, checked in by geyser, 14 months ago

Implemented import/export of "fact" chunk for .wav files. Added a -demo tag for storing sounds in the PC demo format (if compatible).

File size: 3.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.IO;
4//using System.Runtime.Remoting.Metadata.W3cXsd2001;
5
6namespace Oni.Sound
7{
8    internal class WavFile
9    {
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;
14        private const int fcc_fact = 0x74636166;
15        private const int fcc_data = 0x61746164;
16
17        private WavFormat format;
18        private int channelCount;
19        private int sampleRate;
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
27
28        public static WavFile FromFile(string filePath)
29        {
30            using (var reader = new BinaryReader(filePath))
31            {
32                if (reader.ReadInt32() != fcc_RIFF)
33                    throw new InvalidDataException("Not a WAV file");
34
35                int size = reader.ReadInt32();
36
37                if (reader.ReadInt32() != fcc_WAVE)
38                    throw new InvalidDataException("Not a WAV file");
39
40                var header = new WavFile()
41                {
42                    sampleCount = 0
43                };
44
45                for (int chunkType, chunkSize, chunkStart; reader.Position < size; reader.Position = chunkStart + chunkSize)
46                {
47                    chunkType = reader.ReadInt32();
48                    chunkSize = reader.ReadInt32();
49                    chunkStart = reader.Position;
50
51                    if (chunkType == fcc_fmt)
52                        header.ReadFormatChunk(reader, chunkSize);
53                    if (chunkType == fcc_fact)
54                        header.ReadFactChunk(reader, chunkSize);
55                    if (chunkType == fcc_data)
56                        header.ReadDataChunk(reader, chunkSize);
57                }
58
59                header.ValidateSampleCount();
60                return header;
61            }
62        }
63
64        private void ReadFormatChunk(BinaryReader reader, int chunkSize)
65        {
66            format = (WavFormat)reader.ReadInt16();
67            channelCount = reader.ReadInt16();
68            sampleRate = reader.ReadInt32();
69            averageBytesPerSecond = reader.ReadInt32();
70            blockAlign = reader.ReadInt16();
71            bitsPerSample = reader.ReadInt16();
72
73            if (chunkSize > 16)
74                extraData = reader.ReadBytes(reader.ReadInt16());
75            else
76                extraData = new byte[0];
77        }
78
79        private void ReadFactChunk(BinaryReader reader, int chunkSize)
80        {
81            sampleCount = reader.ReadInt32();
82        }
83
84        private void ReadDataChunk(BinaryReader reader, int chunkSize)
85        {
86            soundData = reader.ReadBytes(chunkSize);
87        }
88        private void ValidateSampleCount() // TODO: ACTUAL VALIDATION/CORRECTION
89        {
90            int sampleCountFromData = 0;
91            int wholeBlocks = soundData.Length / blockAlign;
92            if(sampleCount == 0) // not explicitly set (no fact chunk present)
93            {
94                Console.WriteLine("The imported WAV file has no FACT chunk.");
95            }
96            else // TODO: calculate sampleCountFromData, compare with sampleCount
97            {
98
99            }
100        }
101
102        public WavFormat Format => format;
103        public int ChannelCount => channelCount;
104        public int SampleRate => sampleRate;
105        public int AverageBytesPerSecond => averageBytesPerSecond;
106        public int BlockAlign => blockAlign;
107        public int BitsPerSample => bitsPerSample;
108        public byte[] ExtraData => extraData;
109        public byte[] SoundData => soundData;
110    }
111}
Note: See TracBrowser for help on using the repository browser.