lua: added EVT_MENU_LONG on Taranis (#3991)
[opentx.git] / sound / recorder / clsWaveProcessor.cs
blob858cc4c8214ce4fa2b1c1eed1622acf7c8d1ae83
1 using System;
2 using System.Text;
3 using System.IO;
4 using System.Runtime.InteropServices;
5 using WaveLib;
8 public class wavProcessor
10 public int Length;
11 public short Channels;
12 public int SampleRate;
13 public int DataLength;
14 public short BitsPerSample;
16 /// <summary>
17 /// Filter out silence or noise from start and end of wave file.
18 /// </summary>
19 /// <param name="strPath">Source wave file</param>
20 /// <param name="noiceLevel">Absolute value for noice threshold</param>
21 /// <returns>True/False</returns>
22 public bool StripSilence(string strPath, int noiceLevel)
24 if ((strPath == null) || (strPath == ""))
25 return false;
27 // Read from file
28 wavProcessor wain = new wavProcessor();
29 if (!wain.WaveHeaderIN(@strPath)) return false;
30 byte[] arrfile = GetWAVEData(strPath);
32 int startpos = 0;
33 int endpos = arrfile.Length - 1;
35 // Check for silence at start
36 for (int j = 0; isSilence(arrfile, j, noiceLevel); j += 20)
37 startpos = j;
39 // Allow room for tone-in buffer
40 int buffer = wain.SampleRate * (wain.BitsPerSample / 8) / 32; // 1/32 seconds lead time
41 startpos = startpos - buffer;
42 if (startpos < 0)
43 startpos = 0;
45 // Check for silence at end. No need to check tone out buffer
46 for (int k = arrfile.Length - buffer; (k >= 0) && (isSilence(arrfile, k, noiceLevel)); k -= 20)
47 endpos = k;
49 // Allow room for tone-out buffer
50 endpos = endpos + buffer;
51 if (endpos > arrfile.Length)
52 endpos = arrfile.Length - 2;
54 if (startpos >= endpos)
55 return false;
57 byte[] newarr = new byte[endpos - startpos];
58 for (int ni = 0, m = startpos; ni < newarr.Length; m++, ni++)
59 newarr[ni] = arrfile[m];
61 // write file back
62 WavFileWriter writer = new WavFileWriter(@strPath, wain.SampleRate, wain.BitsPerSample, wain.Channels);
63 writer.Write(newarr, newarr.Length);
64 writer.Close();
66 return true;
69 // Helper function that checks if the next 10 samples is silence
70 private bool isSilence(byte[] buff, int index, int noiceLevel)
72 if (buff.Length <= (index + 20))
73 return false;
75 int totalSnd = 0;
76 for (int i = 0; i < 20; i += 2)
78 short snd = ComplementToSigned(ref buff, i + index);
79 if (snd < 0)
80 snd = (short)(snd * -1);
81 totalSnd += snd;
83 return (totalSnd < (10 * noiceLevel));
86 /// <summary>
87 /// Tone in wav file
88 /// </summary>
89 /// <param name="strPath">Source wave</param>
90 /// <returns>True/False</returns>
91 public bool ToneIn(string strPath)
93 if ((strPath == null) || (strPath == ""))
94 return false;
96 // Read from file
97 wavProcessor wain = new wavProcessor();
98 if (!wain.WaveHeaderIN(@strPath)) return false;
99 byte[] arrfile = GetWAVEData(strPath);
101 // Calculate constants
102 int start = 0;
103 int end = wain.SampleRate * (wain.BitsPerSample / 8) / 16; // 1/16 seconds
104 int span = end - start;
106 //change volume
107 for (int j = start; j < end; j += 2)
109 short snd = ComplementToSigned(ref arrfile, j);
110 snd = Convert.ToInt16(snd * (j / span));
111 byte[] newval = SignedToComplement(snd);
112 arrfile[j] = newval[0];
113 arrfile[j + 1] = newval[1];
115 // write file back
116 WavFileWriter writer = new WavFileWriter(@strPath, wain.SampleRate, wain.BitsPerSample, wain.Channels);
117 writer.Write(arrfile, arrfile.Length);
118 writer.Close();
120 return true;
122 /// <summary>
123 /// Tone out wav file
124 /// </summary>
125 /// <param name="strPath">Source wave</param>
126 /// <returns>True/False</returns>
127 public bool ToneOut(string strPath)
129 if ((strPath == null) || (strPath == ""))
130 return false;
132 // Read from file
133 wavProcessor wain = new wavProcessor();
134 if (!wain.WaveHeaderIN(@strPath)) return false;
135 byte[] arrfile = GetWAVEData(strPath);
137 // Calculate constants
138 int end = wain.Length;
139 int start = end - (wain.SampleRate * (wain.BitsPerSample / 8) / 16); // 1/16 seconds from end
140 int span = end - start;
142 //change volume
143 for (int j = start; j < arrfile.Length; j += 2)
145 short snd = ComplementToSigned(ref arrfile, j);
146 snd = Convert.ToInt16(snd * (end - j) / span);
148 byte[] newval = SignedToComplement(snd);
149 arrfile[j] = newval[0];
150 arrfile[j + 1] = newval[1];
152 // write file back
153 WavFileWriter writer = new WavFileWriter(@strPath, wain.SampleRate, wain.BitsPerSample, wain.Channels);
154 writer.Write(arrfile, arrfile.Length);
155 writer.Close();
157 return true;
159 /// <summary>
160 /// Speed up wav file to mimic Donald Duck
161 /// </summary>
162 /// <param name="strPath">Source wave</param>
163 /// <param name="speed">Speed between 0 and 19 </param>
164 /// <returns>True/False</returns>
165 public bool SpeedUp(string strPath, int speed)
167 if ((strPath == null) || (strPath == ""))
168 return false;
170 if ((speed < 0) || (speed > 19))
171 return false;
173 // Read from file
174 wavProcessor wain = new wavProcessor();
175 if (!wain.WaveHeaderIN(@strPath)) return false;
176 byte[] arrfile = GetWAVEData(strPath);
177 byte[] newfile = new byte[arrfile.Length];
179 int skip = 21-speed;
180 int j = 0;
181 for (int i = 0; i < arrfile.Length; i += 2)
183 if (skip > 20 || (((i/2) % skip) != 0))
185 newfile[j] = arrfile[i];
186 newfile[j + 1] = arrfile[i + 1];
187 j += 2;
190 // write file back
191 WavFileWriter writer = new WavFileWriter(@strPath, wain.SampleRate, wain.BitsPerSample, wain.Channels);
192 writer.Write(newfile, j);
193 writer.Close();
194 return true;
197 /// <summary>
198 /// Read the wave file header and store the key values in public variable.
199 /// </summary>
200 /// <param name="strPath">The physical path of wave file incl. file name for reading</param>
201 /// <returns>True/False</returns>
202 private bool WaveHeaderIN(string strPath)
204 if (strPath == null) strPath = "";
205 if (strPath == "") return false;
207 FileStream fs = new FileStream(strPath, FileMode.Open, FileAccess.Read);
209 BinaryReader br = new BinaryReader(fs);
212 Length = (int)fs.Length - 8;
213 fs.Position = 22;
214 Channels = br.ReadInt16(); //1
215 fs.Position = 24;
216 SampleRate = br.ReadInt32(); //16000
217 fs.Position = 34;
218 BitsPerSample = br.ReadInt16(); //16
219 DataLength = (int)fs.Length - 44;
220 byte[] arrfile = new byte[fs.Length - 44];
221 fs.Position = 44;
222 fs.Read(arrfile, 0, arrfile.Length);
224 catch
226 return false;
228 finally
230 br.Close();
231 fs.Close();
233 return true;
236 /// <summary>
237 /// In stereo wave format, samples are stored in 2's complement. For Mono, it's necessary to
238 /// convert those samples to their equivalent signed value. This method is used
239 /// by other public methods to equilibrate wave formats of different files.
240 /// </summary>
241 /// <param name="bytArr">Sample data in array</param>
242 /// <param name="intPos">Array offset</param>
243 /// <returns>Mono value as signed short</returns>
244 private short ComplementToSigned(ref byte[] bytArr, int intPos) // 2's complement to normal signed value
246 short snd = BitConverter.ToInt16(bytArr, intPos);
247 if (intPos >= bytArr.Length) return 0;
248 if (snd != 0)
249 snd = Convert.ToInt16((~snd | 1));
250 return snd;
252 /// <summary>
253 /// Convert signed sample value back to 2's complement value equivalent to Stereo. This method is used
254 /// by other public methods to equilibrate wave formats of different files.
255 /// </summary>
256 /// <param name="shtVal">The mono signed value as short</param>
257 /// <returns>Stereo 2's complement value as byte array</returns>
258 private byte[] SignedToComplement(short shtVal) //Convert to 2's complement and return as byte array of 2 bytes
260 byte[] bt = new byte[2];
261 shtVal = Convert.ToInt16((~shtVal | 1));
262 bt = BitConverter.GetBytes(shtVal);
263 return bt;
265 /// <summary>
266 /// Read the WAVE file then position to DADA segment and return the chunk as byte array
267 /// </summary>
268 /// <param name="strWAVEPath">Path of WAVE file</param>
269 /// <returns>byte array</returns>
270 private byte[] GetWAVEData(string strWAVEPath)
274 FileStream fs = new FileStream(@strWAVEPath, FileMode.Open, FileAccess.Read);
275 byte[] arrfile = new byte[fs.Length - 44];
276 fs.Position = 44;
277 fs.Read(arrfile, 0, arrfile.Length);
278 fs.Close();
279 return arrfile;
281 catch (IOException ioex)
283 throw ioex;
286 } // End of clsWaveProcessor class