MyCaffe  1.12.2.41
Deep learning software for Windows C# programmers.
WAVWriter.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Runtime.InteropServices;
6using System.Text;
7using System.Threading.Tasks;
8
13namespace MyCaffe.db.stream
14{
18 public class WAVWriter : BinaryWriter
19 {
20 Stream m_stream;
21 WaveFormat m_format = new WaveFormat();
22 Dictionary<string, List<string>> m_rgInfo = new Dictionary<string, List<string>>();
23 long m_lSizePos = 0;
24 List<double[]> m_rgrgSamples;
25 int m_nSampleStep = 1;
26
31 public WAVWriter(Stream stream) : base(stream)
32 {
33 m_stream = stream;
34 }
35
40 {
41 get { return m_format; }
42 set { m_format = value; }
43 }
44
48 public List<double[]> Samples
49 {
50 get { return m_rgrgSamples; }
51 set { m_rgrgSamples = value; }
52 }
53
59 public bool WriteAll(int nNewSampleRate = 0)
60 {
61 if (m_rgrgSamples == null)
62 throw new Exception("You must set the audio data first!");
63
64 if (m_format.nChannels == 0)
65 throw new Exception("You must set the format first!");
66
67 if (nNewSampleRate > 0)
68 {
69 m_nSampleStep = (int)m_format.nSamplesPerSec / nNewSampleRate;
70 m_format.nSamplesPerSec = (uint)nNewSampleRate;
71 m_format.nAvgBytesPerSec = (uint)(nNewSampleRate * m_format.wBitsPerSample / 8);
72 }
73
74 if (!writeContent())
75 return false;
76
77 if (!writeAudioContent())
78 return false;
79
80 int nSize = (int)(m_stream.Position - m_lSizePos) - 4;
81 m_stream.Seek(m_lSizePos, SeekOrigin.Begin);
82 Write(nSize);
83
84 return true;
85 }
86
87 private bool writeAudioContent()
88 {
89 int nSamples = m_rgrgSamples[0].Length;
90 int nChannels = m_rgrgSamples.Count;
91
92 for (int s = 0; s < nSamples; s++)
93 {
94 for (int ch = 0; ch < nChannels; ch++)
95 {
96 if (s % m_nSampleStep == 0)
97 {
98 double dfSample = m_rgrgSamples[ch][s];
99
100 switch (m_format.wBitsPerSample)
101 {
102 case 32:
103 {
104 int v = (int)(dfSample * (double)0x80000000);
105 byte b1 = (byte)(0x000000FF & v);
106 byte b2 = (byte)((0x0000FF00 & v) >> 8);
107 byte b3 = (byte)((0x00FF0000 & v) >> 16);
108 byte b4 = (byte)((0xFF000000 & v) >> 24);
109 Write(b1);
110 Write(b2);
111 Write(b3);
112 Write(b4);
113 }
114 break;
115
116 default:
117 throw new NotImplementedException("The bits per sample of " + m_format.wBitsPerSample.ToString() + " is not supported.");
118 }
119 }
120 }
121 }
122
123 return true;
124 }
125
126 private bool writeContent()
127 {
128 return writeRiff();
129 }
130
131 private bool writeRiff()
132 {
133 if (!writeID("RIFF"))
134 return false;
135
136 m_lSizePos = m_stream.Position;
137 int nSize = 0;
138 Write(nSize);
139
140 if (!writeID("WAVE"))
141 return false;
142
143 if (!writeChunk("fmt "))
144 return false;
145
146 if (!writeChunk("data"))
147 return false;
148
149 return true;
150 }
151
152 private bool writeID(string strID)
153 {
154 if (strID.Length != 4)
155 throw new Exception("The ID must have a length of 4.");
156
157 byte b1 = (byte)strID[0];
158 byte b2 = (byte)strID[1];
159 byte b3 = (byte)strID[2];
160 byte b4 = (byte)strID[3];
161
162 Write(b1);
163 Write(b2);
164 Write(b3);
165 Write(b4);
166
167 return true;
168 }
169
170 private bool writeChunk(string strType)
171 {
172 if (!writeID(strType))
173 return false;
174
175 switch (strType)
176 {
177 case "fmt ":
178 return writeFmt();
179
180 case "data":
181 return writeData();
182
183 default:
184 throw new NotImplementedException("The format '" + strType + "' is not supported.");
185 }
186 }
187
188 private bool writeFmt()
189 {
190 int nStructSize = Marshal.SizeOf(m_format);
191 byte[] rgData = StructureToByteArray<WaveFormat>(m_format);
192
193 if (nStructSize != rgData.Length)
194 throw new Exception("Invalid byte sizing.");
195
196 Write(nStructSize);
197 Write(rgData);
198 return true;
199 }
200
201 private bool writeData()
202 {
203 int nSize = 0;
204 int nByteCount = m_format.wBitsPerSample / 8;
205
206 for (int i = 0; i < m_rgrgSamples.Count; i++)
207 {
208 nSize += nByteCount * m_rgrgSamples[i].Length;
209 }
210
211 Write(nSize);
212
213 return true;
214 }
215
222 public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
223 {
224 GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
225 T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
226 typeof(T));
227 handle.Free();
228 return stuff;
229 }
230
237 public static byte[] StructureToByteArray<T>(T val)
238 {
239 int size = Marshal.SizeOf(val);
240 byte[] arr = new byte[size];
241
242 IntPtr ptr = Marshal.AllocHGlobal(size);
243 Marshal.StructureToPtr(val, ptr, true);
244 Marshal.Copy(ptr, arr, 0, size);
245 Marshal.FreeHGlobal(ptr);
246 return arr;
247 }
248 }
249}
The WAVWriter is a special BinaryWriter used to write WAV files.
Definition: WAVWriter.cs:19
bool WriteAll(int nNewSampleRate=0)
The WriteAll method writes all WAV file data to the file.
Definition: WAVWriter.cs:59
static T ByteArrayToStructure< T >(byte[] bytes)
Converts a byte array into a structure.
Definition: WAVWriter.cs:222
WaveFormat Format
Get/set the WaveFormat.
Definition: WAVWriter.cs:40
static byte[] StructureToByteArray< T >(T val)
Converts a structure into a byte array.
Definition: WAVWriter.cs:237
WAVWriter(Stream stream)
The constructor.
Definition: WAVWriter.cs:31
List< double[]> Samples
Get/set the frequency samples.
Definition: WAVWriter.cs:49
The MyCaffe.db.stream namespace contains all data streaming related classes.
The WaveFormat structure describes the header information of a WAV file.
Definition: WAVReader.cs:74
uint nAvgBytesPerSec
Specifies the average byte rate per second (nSamplesPerSec * Channels * BitsPerSample / 8)
Definition: WAVReader.cs:90
uint nSamplesPerSec
Specifies the sample rate (e.g. 8000, 44100, etc.)
Definition: WAVReader.cs:86
ushort nChannels
Specifies the number of channels in the data where Mono = 1 and Stero = 2.
Definition: WAVReader.cs:82
ushort wBitsPerSample
Specifies the number of bits per sample (8, 16, 32, etc.)
Definition: WAVReader.cs:98