SLIP  1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
WavWriter.hpp
Go to the documentation of this file.
1 
9 #ifndef WAVWRITER_HPP_
10 #define WAVWRITER_HPP_
11 
12 #include <fstream>
13 #include <iostream>
14 #include <sstream>
15 
16 #include "ContainerWriter.hpp"
17 #include "WavDef.hpp"
18 
19 namespace slip {
20 
34 template<class Container1d, typename T>
35 class WavWriter: public ContainerWriter<Container1d,T> {
36 public:
37  typedef Container1d container_type;
38  typedef T value_type;
40 
45 
50  :base(),wave_(),outfile(),finished(0),total_nb_elem(0),initialized(false),output_audio_size_(0)
51  {outfile.exceptions(std::ofstream::failbit | std::ofstream::badbit);}
52 
60  WavWriter(std::string output_filename, const WAVE_HEADER & wave,
61  std::size_t output_audio_size);
62 
63 
72  WavWriter(std::string output_filename, short sample_rate,
73  short byte_per_sample, std::size_t output_audio_size);
74 
78  virtual ~WavWriter(){}
79 
87  void initialize(const WAVE_HEADER & wave, std::size_t output_audio_size);
88 
95  void initialize(short sample_rate, short byte_per_sample, std::size_t output_audio_size);
96 
97 
101  void release();
102 
111  int write(const container_type & data);
112 
119  void set_header(const WAVE_HEADER& wave) {
120  this->wave_ = wave;
121  }
122 
129  const WAVE_HEADER& get_header() const {
130  return wave_;
131  }
132 
133 private:
134 
136  WAVE_HEADER wave_;
138  std::ofstream outfile;
140  bool finished;
142  std::size_t total_nb_elem;
144  bool initialized;
146  std::size_t output_audio_size_;
147 
148  void initialize();
149 
150  void init_wave(short sample_rate, short byte_per_sample);
151 };
152 
153 }
156 namespace slip {
157 
158 template<class Container1d, typename T>
159 inline
160 WavWriter<Container1d,T>::WavWriter(std::string output_filename, const WAVE_HEADER & wave,
161  std::size_t output_audio_size)
162  :base(output_filename),wave_(wave),outfile(),finished(0),total_nb_elem(0),initialized(false),
163  output_audio_size_(output_audio_size)
164  {
165  outfile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
166  initialize();
167  }
168 
169 template<class Container1d, typename T>
170 inline
171 WavWriter<Container1d,T>::WavWriter(std::string output_filename, short sample_rate,
172  short byte_per_sample, std::size_t output_audio_size)
173  :base(output_filename),wave_(),outfile(),finished(0),total_nb_elem(0),initialized(false),
174  output_audio_size_(output_audio_size)
175  {
176  outfile.exceptions(std::ofstream::failbit | std::ofstream::badbit);
177  init_wave(sample_rate,byte_per_sample);
178  initialize();
179  }
180 
181 template<class Container1d, typename T>
182 inline
183 void WavWriter<Container1d,T>::init_wave(short sample_rate, short byte_per_sample){
184  wave_.format_header.sample_rate = static_cast<int32>(sample_rate);
185  wave_.format_header.bits_per_sample = static_cast<int16>(byte_per_sample);
186  wave_.format_header.format = 1;
187  wave_.format_header.num_channels = 1;
188  wave_.format_header.align = wave_.format_header.bits_per_sample / 8;
189  wave_.format_header.byte_rate = wave_.format_header.sample_rate
190  * static_cast<int32>(wave_.format_header.align);
191 
192  wave_.riff_header.chunk_id[0] = 'R';
193  wave_.riff_header.chunk_id[1] = 'I';
194  wave_.riff_header.chunk_id[2] = 'F';
195  wave_.riff_header.chunk_id[3] = 'F';
196  wave_.riff_header.chunk_id[4] = '\0';
197  wave_.riff_header.chunk_size = 36 + static_cast<int32>(output_audio_size_)
198  * static_cast<int32>(wave_.format_header.align);
199  wave_.riff_header.format[0] = 'W';
200  wave_.riff_header.format[1] = 'A';
201  wave_.riff_header.format[2] = 'V';
202  wave_.riff_header.format[3] = 'E';
203  wave_.riff_header.format[4] = '\0';
204 
205  wave_.format_header.chunk_id[0] = 'f';
206  wave_.format_header.chunk_id[1] = 'm';
207  wave_.format_header.chunk_id[2] = 't';
208  wave_.format_header.chunk_id[3] = ' ';
209  wave_.format_header.chunk_id[4] = '\0';
210  wave_.format_header.chunk_size = 16;
211 
212  wave_.data_header.chunk_id[0] = 'd';
213  wave_.data_header.chunk_id[1] = 'a';
214  wave_.data_header.chunk_id[2] = 't';
215  wave_.data_header.chunk_id[3] = 'a';
216  wave_.data_header.chunk_id[4] = '\0';
217  wave_.data_header.chunk_size = static_cast<int32>(output_audio_size_) *
218  static_cast<int32>(wave_.format_header.align);
219 }
220 
221 template<class Container1d, typename T>
222 inline
224  short byte_per_sample, std::size_t output_audio_size){
225  init_wave(sample_rate,byte_per_sample);
226  output_audio_size_ = output_audio_size;
227  initialize();
228 }
229 
230 template<class Container1d, typename T>
231 inline
232 void WavWriter<Container1d,T>::initialize(const WAVE_HEADER & wave, std::size_t output_audio_size){
233  wave_ = wave;
234  output_audio_size_ = output_audio_size;
235  initialize();
236 }
237 
238 
239 template<class Container1d, typename T>
240 inline
242  if(!initialized){
243  try {
244  outfile.open(this->output_filename_.c_str(), std::ofstream::binary);
245  }
246  catch(...){
247  std::ostringstream err;
248  err << FILE_OPEN_ERROR << this->output_filename_;
249  slip::slip_exception exc(std::string("slip"), std::string("WavWriter::initialize()"), err.str());
250  throw (exc);
251  }
252 
253  // Write the RIFF chunk header
254  outfile.write("RIFF",4);
255  //Calculating the total number of bytes in the output file
256  int32 chunk_size = 36 + static_cast<int32>(output_audio_size_)
257  * static_cast<int32>(wave_.format_header.align);
258 #ifdef REVERSE_ENDIANISM
259  // reversing the endianism of the chunk size.
260  chunk_size = SWAP_32(chunk_size);
261 #endif
262  outfile.write(reinterpret_cast<char8*>(&chunk_size),4);
263  outfile.write("WAVE",4);
264 
265  // Write the Fmt chunk header
266  outfile.write("fmt ",4);
267  chunk_size = 16;
268  int16 audiofmt = wave_.format_header.format;
269  int16 numchannel = wave_.format_header.num_channels;
270  int32 freq = wave_.format_header.sample_rate;
271  int16 bytpersample = wave_.format_header.bits_per_sample;
272  int16 bytperbl = numchannel * bytpersample / 8;
273  int32 bytrate = freq * static_cast<int32>(bytperbl);
274 
275 #ifdef REVERSE_ENDIANISM
276  chunk_size = SWAP_32(chunk_size);
277  audiofmt = SWAP_16(audiofmt);
278  numchannel = SWAP_16(numchannel);
279  freq = SWAP_32(freq);
280  bytrate = SWAP_32(bytrate);
281  bytperbl = SWAP_16(bytperbl);
282  bytpersample = SWAP_16(bytpersample);
283 #endif
284  outfile.write(reinterpret_cast<char8*>(&chunk_size),4);
285  outfile.write(reinterpret_cast<char8*>(&audiofmt),2);
286  outfile.write(reinterpret_cast<char8*>(&numchannel),2);
287  outfile.write(reinterpret_cast<char8*>(&freq),4);
288  outfile.write(reinterpret_cast<char8*>(&bytrate),4);
289  outfile.write(reinterpret_cast<char8*>(&bytperbl),2);
290  outfile.write(reinterpret_cast<char8*>(&bytpersample),2);
291 
292  // Write the data chunk header
293  outfile.write("data",4);
294  chunk_size = output_audio_size_ * static_cast<std::size_t>(bytperbl);
295 #ifdef REVERSE_ENDIANISM
296  chunk_size = SWAP_32(chunk_size);
297 #endif
298  outfile.write(reinterpret_cast<char8*>(&chunk_size),4);
299 
300  initialized = true;
301  }
302 }
303 
304 
305 
306 template<class Container1d, typename T>
307 inline
309  if(!initialized){
310  std::ostringstream err;
311  err << FILE_WRITE_ERROR << this->output_filename_ << " | The writer to be initialized before writing.";
312  slip_exception exc(std::string("slip"), std::string("WavWriter::write()"), err.str());
313  throw (exc);
314  }
315  if (finished){
316  return 0;
317  }
318 
319  total_nb_elem += data.size();
320 
321  if(output_audio_size_ < total_nb_elem){
322  std::ostringstream err;
323  err << FILE_WRITE_ERROR << this->output_filename_ << " | Allocation problem during wav writing.";
324  slip_exception exc(std::string("slip"), std::string("WavWriter::write()"), err.str());
325  release();
326  throw (exc);
327  }
328 
329  std::size_t bps = static_cast<std::size_t>(wave_.format_header.bits_per_sample);
330  std::size_t nbch = static_cast<std::size_t>(wave_.format_header.num_channels);
331  std::size_t size_d = data.size();
332  double max = static_cast<double>(*std::max_element(data.begin(),data.end()));
333  double min = static_cast<double>(*std::min_element(data.begin(),data.end()));
334  double delta = max - min;
335  double max32 = static_cast<double>(std::numeric_limits<int32>::max());
336  double min32 = static_cast<double>(std::numeric_limits<int32>::min());
337  double delta32 = max32 - min32;
338  double max16 = static_cast<double>(std::numeric_limits<int16>::max());
339  double min16 = static_cast<double>(std::numeric_limits<int16>::min());
340  double delta16 = max16 - min16;
341  double max8 = static_cast<double>(255);
342  switch(bps){
343  case 8:
344  {
345  if ((max <= max8) && (min >= 0)){
346  for(std::size_t j=0; j<size_d; j++){
347  for(std::size_t i=0;i<nbch;i++){
348  char d = static_cast<char>(data[j]);
349  outfile.write(reinterpret_cast<char8*>(&d),1);
350  }
351  }
352  }else{
353  double alpha = max8/delta;
354  for(std::size_t j=0; j<size_d; j++){
355  char d = static_cast<char>(max8 - alpha*(max - static_cast<double>(data[j])));
356  for(std::size_t i=0;i<nbch;i++){
357  outfile.write(reinterpret_cast<char8*>(&d),1);
358  }
359  }
360  }
361  break;
362  }
363  case 16:
364  {
365  if ((max <= max16) && (min >= min16)){
366  for(std::size_t j=0; j<size_d; j++){
367  for(std::size_t i=0;i<nbch;i++){
368  int16 d = static_cast<int16>(data[j]);
369 #ifdef REVERSE_ENDIANISM
370  d = SWAP_16(d);
371 #endif
372  outfile.write(reinterpret_cast<char8*>(&d),2);
373  }
374  }
375  }else{
376  double alpha = delta16/delta;
377  for(std::size_t j=0; j<size_d; ++j){
378  int16 d = static_cast<int16>(max16 - alpha*(max - static_cast<double>(data[j])));
379 #ifdef REVERSE_ENDIANISM
380  d = SWAP_16(d);
381 #endif
382  for(std::size_t i=0;i<nbch;i++){
383  outfile.write(reinterpret_cast<char8*>(&d),2);
384  }
385  }
386  }
387  break;
388  }
389  case 32:
390  {
391  if ((max <= max32) && (min >= min32)){
392  for(std::size_t j=0; j<size_d; j++){
393  for(std::size_t i=0;i<nbch;i++){
394  int32 d = static_cast<int32>(d);
395 #ifdef REVERSE_ENDIANISM
396  d = SWAP_32(d);
397 #endif
398  outfile.write(reinterpret_cast<char8*>(&d),4);
399  }
400  }
401  }else{
402  double alpha = delta32/delta;
403  for(std::size_t j=0; j<size_d; ++j){
404  int32 d = static_cast<int32>(max32 - alpha*(max - static_cast<double>(data[j])));
405 #ifdef REVERSE_ENDIANISM
406  d = SWAP_32(d);
407 #endif
408  for(std::size_t i=0;i<nbch;i++){
409  outfile.write(reinterpret_cast<char8*>(&d),4);
410  }
411  }
412  }
413  break;
414  }
415  default:
416  std::ostringstream err;
417  err << FILE_WRITE_ERROR << this->output_filename_ << " | The specified bit per sample is not valid.";
418  slip_exception exc(std::string("slip"), std::string("WavWriter::write()"), err.str());
419  release();
420  throw (exc);
421  }
422 
423  if (total_nb_elem == output_audio_size_)
424  finished = true;
425 
426  return (!finished);
427 }
428 
429 template<class Container1d, typename T>
430 inline
432  if(initialized){
433  if (outfile.is_open())
434  outfile.close();
435  wave_ = WAVE_HEADER();
436  finished = false;
437  total_nb_elem = 0;
438  output_audio_size_ = 0;
439  initialized = false;
440  }
441 }
442 
443 }
444 #endif /* WAVWRITER_HPP_ */
void release()
release the writing process. Has to be called when an audio file has been fully written.
Definition: WavWriter.hpp:431
virtual ~WavWriter()
Definition: WavWriter.hpp:78
T & min(const GrayscaleImage< T > &M1)
Returns the min element of a GrayscaleImage.
const std::string FILE_WRITE_ERROR
Definition: error.hpp:91
standard exception extension name have been changed to eliminate conflicts with QT ...
Definition: error.hpp:106
Contains the container writer base class.
const std::string FILE_OPEN_ERROR
Definition: error.hpp:82
Some definitions specific to wav files manipulations.
int write(const container_type &data)
write function. This function write the data within the output file after the previous one...
Definition: WavWriter.hpp:308
Container1d container_type
Definition: WavWriter.hpp:37
const WAVE_HEADER & get_header() const
Get the wav file header.
Definition: WavWriter.hpp:129
void set_header(const WAVE_HEADER &wave)
Set the wav header file.
Definition: WavWriter.hpp:119
ContainerWriter is the base class of the writer classes. All the writers are working the same way: ...
void initialize(const WAVE_HEADER &wave, std::size_t output_audio_size)
initialized the writing process. Has to be called before the first write() call of a given array...
Definition: WavWriter.hpp:232
ContainerWriter< Container1d, T > base
Definition: WavWriter.hpp:39
T & max(const GrayscaleImage< T > &M1)
Returns the max element of a GrayscaleImage.
WavWriter is the wave array writer.
Definition: WavWriter.hpp:35