SLIP  1.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
WavReader.hpp
Go to the documentation of this file.
1 
9 #ifndef WAVREADER_HPP_
10 #define WAVREADER_HPP_
11 
12 #include <fstream>
13 #include <iostream>
14 #include <sstream>
15 
16 #include "ContainerReader.hpp"
17 #include "WavDef.hpp"
18 
19 namespace slip {
20 
21 
22 
36 template<class Container1d, typename T, std::size_t Nb_block>
37 class WavReader: public ContainerReader<Container1d,T,Nb_block> {
38 public:
39  typedef Container1d container_type;
40  typedef T value_type;
42 
47 
52  :base(),
53  wave(),header_size(0),output_size(0),infile(),indblock(1),block_size(0),last_block_size(0),
54  last_it(0),finished(0),initialized(0)
55  {infile.exceptions(std::ifstream::failbit | std::ifstream::badbit);}
56 
62  WavReader(std::string data_filename)
63  :base(data_filename),
64  wave(),header_size(0),output_size(0),infile(),indblock(1),block_size(0),last_block_size(0),
65  last_it(0),finished(0),initialized(0)
66  {infile.exceptions(std::ifstream::failbit | std::ifstream::badbit);initialize();}
67 
72  virtual ~WavReader(){
73  if(initialized){
74  release();
75  }
76  }
83  void initialize();
84 
89  void release();
90 
102  int read(container_type & in);
103 
104 
105 
110  std::size_t get_output_size() const {
111  return output_size;
112  }
117  const WAVE_HEADER& get_header() const {
118  return wave;
119  }
120 
121 
122 private:
123 
128  WAVE_HEADER wave;//wave header parameters
129  std::size_t header_size;//number of bytes of the header (in most cases it is 44)
130  std::size_t output_size;//Output signal size;
133  std::ifstream infile;//input file stream
134  std::size_t indblock;//current read block indice
135  std::size_t block_size;//block size
136  std::size_t last_block_size;//last block size
137  bool last_it;//indicates that the current read is the last.
138  bool finished;//indicates that the last read has been done and no more data are available.
139  bool initialized;//indicates that the reader has been initialized
140 
141 };
142 
143 }
145 namespace slip {
146 
147 
148 
149 template<class Container1d, typename T, std::size_t Nb_block>
150 inline
152  if (!initialized){
153  try {
154  infile.open(this->data_filename_.c_str(), std::ifstream::binary);
155  }
156  catch(...){
157  std::ostringstream err;
158  err << FILE_OPEN_ERROR << this->data_filename_;
159  slip::slip_exception exc(std::string("slip"), std::string("WavReader::initialize()"), err.str());
160  throw (exc);
161  }
162  // Read the RIFF chunk header
163  infile.read(wave.riff_header.chunk_id,4);
164  wave.riff_header.chunk_id[4] = '\0';
165  header_size += 4;
166  if (wave.riff_header.chunk_id[0] != 'R' || wave.riff_header.chunk_id[1] != 'I'
167  || wave.riff_header.chunk_id[2] != 'F' || wave.riff_header.chunk_id[3] != 'F'){
168  std::ostringstream err;
169  err << FILE_READ_ERROR << this->data_filename_ << " | unable to find the RIFF chunk.";
170  slip::slip_exception exc(std::string("slip"), std::string("WavReader::initialize()"), err.str());
171  if (infile.is_open())
172  infile.close();
173  throw (exc);
174  }
175  infile.read(reinterpret_cast<char8*>(&wave.riff_header.chunk_size),4);
176  header_size += 4;
177 #ifdef REVERSE_ENDIANISM
178  // reverse the endianism of the chunk size.
179  wave.riff_header.chunk_size = SWAP_32(wave.riff_header.chunk_size);
180 #endif
181  infile.read(wave.riff_header.format,4);
182  wave.riff_header.format[4] = '\0';
183  header_size += 4;
184  if (wave.riff_header.format[0] != 'W' || wave.riff_header.format[1] != 'A'
185  || wave.riff_header.format[2] != 'V' || wave.riff_header.format[3] != 'E'){
186  std::ostringstream err;
187  err << FILE_READ_ERROR << this->data_filename_ << " | not a WAVE file.";
188  slip::slip_exception exc(std::string("slip"), std::string("WavReader::initialize()"), err.str());
189  if (infile.is_open())
190  infile.close();
191  throw (exc);
192  }
193 
194  // Read the FORMAT chunk header
195  infile.read(wave.format_header.chunk_id,4);
196  wave.format_header.chunk_id[4] = '\0';
197  header_size += 4;
198  if (wave.format_header.chunk_id[0] != 'f' || wave.format_header.chunk_id[1] != 'm'
199  || wave.format_header.chunk_id[2] != 't' || wave.format_header.chunk_id[3] != ' '){
200  std::ostringstream err;
201  err << FILE_READ_ERROR << this->data_filename_ << " | unable to find the fmt chunk.";
202  slip::slip_exception exc(std::string("slip"), std::string("WavReader::initialize()"), err.str());
203  if (infile.is_open())
204  infile.close();
205  throw (exc);
206  }
207  infile.read(reinterpret_cast<char8*>(&wave.format_header.chunk_size),4);
208  infile.read(reinterpret_cast<char8*>(&wave.format_header.format),2);
209  infile.read(reinterpret_cast<char8*>(&wave.format_header.num_channels),2);
210  infile.read(reinterpret_cast<char8*>(&wave.format_header.sample_rate),4);
211  infile.read(reinterpret_cast<char8*>(&wave.format_header.byte_rate),4);
212  infile.read(reinterpret_cast<char8*>(&wave.format_header.align),2);
213  infile.read(reinterpret_cast<char8*>(&wave.format_header.bits_per_sample),2);
214  header_size += 20;
215 #ifdef REVERSE_ENDIANISM
216  wave.format_header.chunk_size = SWAP_32(wave.format_header.chunk_size);
217  wave.format_header.format = SWAP_16(wave.format_header.format);
218  wave.format_header.num_channels = SWAP_16(wave.format_header.num_channels);
219  wave.format_header.sample_rate = SWAP_32(wave.format_header.sample_rate);
220  wave.format_header.byte_rate = SWAP_32(wave.format_header.byte_rate);
221  wave.format_header.align = SWAP_16(wave.format_header.align);
222  wave.format_header.bits_per_sample = SWAP_16(wave.format_header.bits_per_sample);
223 #endif
224 
225  //assume we have 8,16 or 32 bits samples
226  if (wave.format_header.bits_per_sample > 32){
227  std::ostringstream err;
228  err << FILE_READ_ERROR << this->data_filename_ << " | Too much bit per sample.";
229  slip::slip_exception exc(std::string("slip"), std::string("WavReader::read()"), err.str());
230  if (infile.is_open())
231  infile.close();
232  throw (exc);
233  }
234 
235  // As it is possible to have are other chunks, like "fact" chunks, in the file,
236  // we will skip over these extra chunks until we find a "data" chunk
237  std::size_t pos = infile.tellg();
238  std::size_t length = wave.riff_header.chunk_size + 4;
239  infile.read(wave.data_header.chunk_id,4);
240  wave.data_header.chunk_id[4] = '\0';
241  header_size += 4;
242  while ((wave.data_header.chunk_id[0] != 'd' || wave.data_header.chunk_id[1] != 'a' ||
243  wave.data_header.chunk_id[2] != 't' || wave.data_header.chunk_id[3] != 'a')
244  && (pos < length))
245  {
246  pos++;
247  infile.seekg(pos);
248  infile.read(wave.data_header.chunk_id,4);
249  wave.data_header.chunk_id[4] = '\0';
250  header_size += 1;
251  }
252 
253  if (pos >= length){
254  std::ostringstream err;
255  err << FILE_READ_ERROR << this->data_filename_ << " | unable to find the data chunk.";
256  slip::slip_exception exc(std::string("slip"), std::string("WavReader::initialize()"), err.str());
257  if (infile.is_open())
258  infile.close();
259  throw (exc);
260  }
261 
262  infile.read(reinterpret_cast<char8*>(&wave.data_header.chunk_size),4);
263  header_size += 4;
264 #ifdef REVERSE_ENDIANISM
265  wave.data_header.chunk_size = SWAP_32(wave.data_header.chunk_size);
266 #endif
267  output_size = (wave.data_header.chunk_size) / static_cast<std::size_t>(wave.format_header.align);
268  block_size = output_size / Nb_block;
269  last_block_size = output_size % Nb_block;
270  last_block_size = (last_block_size == 0 ? block_size : block_size+last_block_size);
271  last_it = (Nb_block == 1);
272  finished = (last_it && last_block_size == 0);
273  initialized = true;
274  }
275 }
276 
277 template<class Container1d, typename T, std::size_t Nb_block>
279  if(!initialized){
280  std::ostringstream err;
281  err << FILE_READ_ERROR << this->data_filename_ << " | The reader needs to be initialized before reading.";
282  slip::slip_exception exc(std::string("slip"), std::string("WavReader::read()"), err.str());
283  throw (exc);
284  }
285  if (finished)
286  return 0;
287 
288  if (last_it)
289  in.resize(last_block_size,T());
290  else{
291  in.resize(block_size,T());
292  }
293  // std::size_t step_size = static_cast<std::size_t>(wave.format_header.bits_per_sample) / 8;
294  std::size_t pos = (static_cast<std::size_t>(infile.tellg()) - header_size) / static_cast<std::size_t>(wave.format_header.align);
295  if(output_size - pos < in.size()){
296  std::ostringstream err;
297  err << FILE_READ_ERROR << this->data_filename_ << " | Bad audio dimensions.";
298  slip::slip_exception exc(std::string("slip"), std::string("WavReader::read()"), err.str());
299  release();
300  throw (exc);
301  }
302 
303 
304 
305  std::size_t bps = static_cast<std::size_t>(wave.format_header.bits_per_sample);
306 
307  //assume we have at most 32 bits per samples
308  switch(bps){
309  case 8:
310  {
311  for(std::size_t i=0; i<in.size(); i++){
312  char8 d = 0;
313  infile.read(reinterpret_cast<char8*>(&d),1);
314  in[i] = static_cast<T>(d);
315  if (wave.format_header.num_channels > 1){
316  std::size_t newpos = static_cast<std::size_t>(infile.tellg()) +
317  static_cast<std::size_t>(wave.format_header.num_channels - 1);
318  infile.seekg(newpos);
319  }
320  }
321  break;
322  }
323  case 16:
324  {
325  for(std::size_t i=0; i<in.size(); ++i){
326  int16 d = 0;
327  infile.read(reinterpret_cast<char8*>(&d),2);
328 #ifdef REVERSE_ENDIANISM
329  d = SWAP_16(d);
330 #endif
331  in[i] = static_cast<T>(d);
332  if (wave.format_header.num_channels > 1){
333  std::size_t newpos = static_cast<std::size_t>(infile.tellg()) +
334  2* static_cast<std::size_t>(wave.format_header.num_channels - 1);
335  infile.seekg(newpos);
336  }
337  }
338  break;
339  }
340  case 32:
341  {
342  for(std::size_t i=0; i<in.size(); ++i){
343  int32 d = 0;
344  infile.read(reinterpret_cast<char8*>(&d),4);
345 #ifdef REVERSE_ENDIANISM
346  d = SWAP_32(d);
347 #endif
348  in[i] = static_cast<T>(d);
349  if (wave.format_header.num_channels > 1){
350  std::size_t newpos = static_cast<std::size_t>(infile.tellg()) +
351  4* static_cast<std::size_t>(wave.format_header.num_channels - 1);
352  infile.seekg(newpos);
353  }
354  }
355  break;
356  }
357  default:
358  {
359  std::ostringstream err;
360  err << FILE_WRITE_ERROR << this->data_filename_ << " | The specified bit per sample is not valid.";
361  slip::slip_exception exc(std::string("slip"), std::string("WavReader::write()"), err.str());
362  release();
363  throw (exc);
364  }
365  }
366  //int32_t d = 0;
367  //infile.read(reinterpret_cast<char8*>(&d),step_size);
368  //#ifdef REVERSE_ENDIANISM
369  //d = SWAP_32(d);
370  //#endif
371  //d = d << ((4 - step_size) * 8);
372  //in[i] = static_cast<T>(d);
373  //if (wave.format_header.num_channels > 1){
374  // std::size_t newpos = static_cast<std::size_t>(infile.tellg()) +
375  // step_size * static_cast<std::size_t>(wave.format_header.num_channels - 1);
376  // infile.seekg(newpos);
377  //}
378  //}
379  indblock++;
380  if (last_it)
381  finished = true;
382  else
383  last_it = (indblock == Nb_block);
384  return (!finished);
385 }
386 
387 template<class Container1d, typename T, std::size_t Nb_block>
389  if(initialized){
390 
391  if (infile.is_open())
392  infile.close();
393  wave = WAVE_HEADER();
394  header_size = 0;
395  output_size = 0;
396  indblock = 1;
397  block_size = 0;
398  last_block_size = 0;
399  last_it = false;
400  finished = false;
401  initialized = false;
402  }
403 }
404 
405 }
407 #endif /* WAVREADER_HPP_ */
Contains the container reader base class.
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
Container1d container_type
Definition: WavReader.hpp:39
std::size_t get_output_size() const
Get the output signal size.
Definition: WavReader.hpp:110
WavReader, inherited from ContainerReader, is a reader for wav audio files.
Definition: WavReader.hpp:37
const WAVE_HEADER & get_header() const
Get the wav file header.
Definition: WavReader.hpp:117
const std::string FILE_OPEN_ERROR
Definition: error.hpp:82
Some definitions specific to wav files manipulations.
ContainerReader is the base class of the readers classes. All readers are working the same way: ...
void initialize()
initialized the reading process.
Definition: WavReader.hpp:151
virtual ~WavReader()
Definition: WavReader.hpp:72
void release()
release the reading process.
Definition: WavReader.hpp:388
int read(container_type &in)
virtual read function. If Nb_block is more than one, it reads only one container, and returns 0...
Definition: WavReader.hpp:278
ContainerReader< Container1d, T, Nb_block > base
Definition: WavReader.hpp:41
WavReader(std::string data_filename)
Definition: WavReader.hpp:62
const std::string FILE_READ_ERROR
Definition: error.hpp:90