4 using System
.Runtime
.InteropServices
;
8 public class wavProcessor
11 public short Channels
;
12 public int SampleRate
;
13 public int DataLength
;
14 public short BitsPerSample
;
17 /// Filter out silence or noise from start and end of wave file.
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
== ""))
28 wavProcessor wain
= new wavProcessor();
29 if (!wain
.WaveHeaderIN(@strPath
)) return false;
30 byte[] arrfile
= GetWAVEData(strPath
);
33 int endpos
= arrfile
.Length
- 1;
35 // Check for silence at start
36 for (int j
= 0; isSilence(arrfile
, j
, noiceLevel
); j
+= 20)
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
;
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)
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
)
57 byte[] newarr
= new byte[endpos
- startpos
];
58 for (int ni
= 0, m
= startpos
; ni
< newarr
.Length
; m
++, ni
++)
59 newarr
[ni
] = arrfile
[m
];
62 WavFileWriter writer
= new WavFileWriter(@strPath
, wain
.SampleRate
, wain
.BitsPerSample
, wain
.Channels
);
63 writer
.Write(newarr
, newarr
.Length
);
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))
76 for (int i
= 0; i
< 20; i
+= 2)
78 short snd
= ComplementToSigned(ref buff
, i
+ index
);
80 snd
= (short)(snd
* -1);
83 return (totalSnd
< (10 * noiceLevel
));
89 /// <param name="strPath">Source wave</param>
90 /// <returns>True/False</returns>
91 public bool ToneIn(string strPath
)
93 if ((strPath
== null) || (strPath
== ""))
97 wavProcessor wain
= new wavProcessor();
98 if (!wain
.WaveHeaderIN(@strPath
)) return false;
99 byte[] arrfile
= GetWAVEData(strPath
);
101 // Calculate constants
103 int end
= wain
.SampleRate
* (wain
.BitsPerSample
/ 8) / 16; // 1/16 seconds
104 int span
= end
- start
;
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];
116 WavFileWriter writer
= new WavFileWriter(@strPath
, wain
.SampleRate
, wain
.BitsPerSample
, wain
.Channels
);
117 writer
.Write(arrfile
, arrfile
.Length
);
123 /// Tone out wav file
125 /// <param name="strPath">Source wave</param>
126 /// <returns>True/False</returns>
127 public bool ToneOut(string strPath
)
129 if ((strPath
== null) || (strPath
== ""))
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
;
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];
153 WavFileWriter writer
= new WavFileWriter(@strPath
, wain
.SampleRate
, wain
.BitsPerSample
, wain
.Channels
);
154 writer
.Write(arrfile
, arrfile
.Length
);
160 /// Speed up wav file to mimic Donald Duck
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
== ""))
170 if ((speed
< 0) || (speed
> 19))
174 wavProcessor wain
= new wavProcessor();
175 if (!wain
.WaveHeaderIN(@strPath
)) return false;
176 byte[] arrfile
= GetWAVEData(strPath
);
177 byte[] newfile
= new byte[arrfile
.Length
];
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];
191 WavFileWriter writer
= new WavFileWriter(@strPath
, wain
.SampleRate
, wain
.BitsPerSample
, wain
.Channels
);
192 writer
.Write(newfile
, j
);
198 /// Read the wave file header and store the key values in public variable.
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;
214 Channels
= br
.ReadInt16(); //1
216 SampleRate
= br
.ReadInt32(); //16000
218 BitsPerSample
= br
.ReadInt16(); //16
219 DataLength
= (int)fs
.Length
- 44;
220 byte[] arrfile
= new byte[fs
.Length
- 44];
222 fs
.Read(arrfile
, 0, arrfile
.Length
);
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.
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;
249 snd
= Convert
.ToInt16((~snd
| 1));
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.
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
);
266 /// Read the WAVE file then position to DADA segment and return the chunk as byte array
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];
277 fs
.Read(arrfile
, 0, arrfile
.Length
);
281 catch (IOException ioex
)
286 } // End of clsWaveProcessor class