source: src/io/source_wavread.c @ 082c88b

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since 082c88b was 5ab8e59, checked in by Paul Brossier <piem@piem.org>, 11 years ago

src/io/source{,_wavread}.c: improve error message

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/*
2  Copyright (C) 2014 Paul Brossier <piem@aubio.org>
3
4  This file is part of aubio.
5
6  aubio is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10
11  aubio is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21#include "config.h"
22
23#ifdef HAVE_WAVREAD
24
25#include "aubio_priv.h"
26#include "fvec.h"
27#include "fmat.h"
28#include "source_wavread.h"
29
30#include <errno.h>
31
32#define AUBIO_WAVREAD_BUFSIZE 1024
33
34#define SHORT_TO_FLOAT(x) (smpl_t)(x * 3.0517578125e-05)
35
36struct _aubio_source_wavread_t {
37  uint_t hop_size;
38  uint_t samplerate;
39  uint_t channels;
40
41  // some data about the file
42  char_t *path;
43  uint_t input_samplerate;
44  uint_t input_channels;
45
46  // internal stuff
47  FILE *fid;
48
49  uint_t read_samples;
50  uint_t blockalign;
51  uint_t bitspersample;
52  uint_t read_index;
53  uint_t eof;
54
55  unsigned char *short_output;
56  fmat_t *output;
57};
58
59unsigned int read_little_endian (unsigned char *buf, unsigned int length);
60unsigned int read_little_endian (unsigned char *buf, unsigned int length) {
61  uint_t i, ret = 0;
62  for (i = 0; i < length; i++) {
63    ret += buf[i] << (i * 8);
64  }
65  return ret;
66}
67
68aubio_source_wavread_t * new_aubio_source_wavread(char_t * path, uint_t samplerate, uint_t hop_size) {
69  aubio_source_wavread_t * s = AUBIO_NEW(aubio_source_wavread_t);
70  unsigned char buf[5];
71  unsigned int format, channels, sr, byterate, blockalign, bitspersample;//, data_size;
72
73  if (path == NULL) {
74    AUBIO_ERR("source_wavread: Aborted opening null path\n");
75    goto beach;
76  }
77  if ((sint_t)samplerate < 0) {
78    AUBIO_ERR("source_wavread: Can not open %s with samplerate %d\n", path, samplerate);
79    goto beach;
80  }
81  if ((sint_t)hop_size <= 0) {
82    AUBIO_ERR("source_wavread: Can not open %s with hop_size %d\n", path, hop_size);
83    goto beach;
84  }
85
86  s->path = path;
87  s->samplerate = samplerate;
88  s->hop_size = hop_size;
89
90  s->fid = fopen((const char *)path, "rb");
91  if (!s->fid) {
92    AUBIO_ERR("source_wavread: could not open %s (%s)\n", s->path, strerror(errno));
93    goto beach;
94  }
95
96  // ChunkID
97  fread(buf, 4, 1, s->fid);
98  buf[4] = '\0';
99  if ( strcmp((const char *)buf, "RIFF") != 0 ) {
100    AUBIO_ERR("source_wavread: could not find RIFF header in %s\n", s->path);
101    goto beach;
102  }
103
104  // ChunkSize
105  fread(buf, 4, 1, s->fid);
106
107  // Format
108  fread(buf, 4, 1, s->fid);
109  buf[4] = '\0';
110  if ( strcmp((const char *)buf, "WAVE") != 0 ) {
111    AUBIO_ERR("source_wavread: wrong format in RIFF header in %s\n", s->path);
112    goto beach;
113  }
114
115  // Subchunk1ID
116  fread(buf, 4, 1, s->fid);
117  buf[4] = '\0';
118  if ( strcmp((const char *)buf, "fmt ") != 0 ) {
119    AUBIO_ERR("source_wavread: fmt RIFF header in %s\n", s->path);
120    goto beach;
121  }
122
123  // Subchunk1Size
124  fread(buf, 4, 1, s->fid);
125  format = read_little_endian(buf, 4);
126  if ( format != 16 ) {
127    // TODO accept format 18
128    AUBIO_ERR("source_wavread: file %s is not encoded with PCM\n", s->path);
129    goto beach;
130  }
131  if ( buf[1] || buf[2] | buf[3] ) {
132    AUBIO_ERR("source_wavread: Subchunk1Size should be 0, in %s\n", s->path);
133    goto beach;
134  }
135
136  // AudioFormat
137  fread(buf, 2, 1, s->fid);
138  if ( buf[0] != 1 || buf[1] != 0) {
139    AUBIO_ERR("source_wavread: AudioFormat should be PCM, in %s\n", s->path);
140    goto beach;
141  }
142
143  // NumChannels
144  fread(buf, 2, 1, s->fid);
145  channels = read_little_endian(buf, 2);
146
147  // SampleRate
148  fread(buf, 4, 1, s->fid);
149  sr = read_little_endian(buf, 4);
150
151  // ByteRate
152  fread(buf, 4, 1, s->fid);
153  byterate = read_little_endian(buf, 4);
154
155  // BlockAlign
156  fread(buf, 2, 1, s->fid);
157  blockalign = read_little_endian(buf, 2);
158
159  // BitsPerSample
160  fread(buf, 2, 1, s->fid);
161  bitspersample = read_little_endian(buf, 2);
162#if 0
163  if ( bitspersample != 16 ) {
164    AUBIO_ERR("source_wavread: can not process %dbit file %s\n",
165        bitspersample, s->path);
166    goto beach;
167  }
168#endif
169
170  if ( byterate * 8 != sr * channels * bitspersample ) {
171    AUBIO_ERR("source_wavread: wrong byterate in %s\n", s->path);
172    goto beach;
173  }
174
175  if ( blockalign * 8 != channels * bitspersample ) {
176    AUBIO_ERR("source_wavread: wrong blockalign in %s\n", s->path);
177    goto beach;
178  }
179
180  s->input_samplerate = sr;
181  s->input_channels = channels;
182
183#if 0
184  AUBIO_DBG("channels %d\n", channels);
185  AUBIO_DBG("sr %d\n", sr);
186  AUBIO_DBG("byterate %d\n", byterate);
187  AUBIO_DBG("blockalign %d\n", blockalign);
188  AUBIO_DBG("bitspersample %d\n", bitspersample);
189
190  AUBIO_DBG("found %d channels in %s\n", s->input_channels, s->path);
191  AUBIO_DBG("found %d samplerate in %s\n", s->input_samplerate, s->path);
192#endif
193
194  if (samplerate == 0) {
195    s->samplerate = s->input_samplerate;
196  } else if (samplerate != s->input_samplerate) {
197    AUBIO_ERR("source_wavread: can not resample %s from %d to %dHz\n",
198        s->path, s->input_samplerate, samplerate);
199    goto beach;
200  }
201
202  // Subchunk2ID
203  fread(buf, 4, 1, s->fid);
204  buf[4] = '\0';
205  if ( strcmp((const char *)buf, "data") != 0 ) {
206    AUBIO_ERR("source_wavread: data RIFF header not found in %s\n", s->path);
207    goto beach;
208  }
209
210  // Subchunk2Size
211  fread(buf, 4, 1, s->fid);
212  //data_size = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
213  //AUBIO_MSG("found %d frames in %s\n", 8 * data_size / bitspersample / channels, s->path);
214
215  s->output = new_fmat(s->input_channels, AUBIO_WAVREAD_BUFSIZE);
216  s->blockalign= blockalign;
217  s->bitspersample = bitspersample;
218
219  s->short_output = (unsigned char *)calloc(s->blockalign, AUBIO_WAVREAD_BUFSIZE);
220  s->read_index = 0;
221  s->read_samples = 0;
222  s->eof = 0;
223
224  return s;
225
226beach:
227  //AUBIO_ERR("source_wavread: can not read %s at samplerate %dHz with a hop_size of %d\n",
228  //    s->path, s->samplerate, s->hop_size);
229  del_aubio_source_wavread(s);
230  return NULL;
231}
232
233void aubio_source_wavread_readframe(aubio_source_wavread_t *s, uint_t *wavread_read);
234
235void aubio_source_wavread_readframe(aubio_source_wavread_t *s, uint_t *wavread_read) {
236  unsigned char *short_ptr = s->short_output;
237  size_t read = fread(short_ptr, s->blockalign, AUBIO_WAVREAD_BUFSIZE, s->fid);
238  uint_t i, j, b, bitspersample = s->bitspersample;
239  uint_t wrap_at = (1 << ( bitspersample - 1 ) );
240  uint_t wrap_with = (1 << bitspersample);
241  smpl_t scaler = 1. / wrap_at;
242  int signed_val = 0;
243  unsigned int unsigned_val = 0;
244
245  for (j = 0; j < read; j++) {
246    for (i = 0; i < s->input_channels; i++) {
247      unsigned_val = 0;
248      for (b = 0; b < bitspersample; b+=8 ) {
249        unsigned_val += *(short_ptr) << b;
250        short_ptr++;
251      }
252      signed_val = unsigned_val;
253      // FIXME why does 8 bit conversion maps [0;255] to [-128;127]
254      // instead of [0;127] to [0;127] and [128;255] to [-128;-1]
255      if (bitspersample == 8) signed_val -= wrap_at;
256      else if (unsigned_val >= wrap_at) signed_val = unsigned_val - wrap_with;
257      s->output->data[i][j] = signed_val * scaler;
258    }
259  }
260
261  *wavread_read = read;
262
263  if (read == 0) s->eof = 1;
264}
265
266void aubio_source_wavread_do(aubio_source_wavread_t * s, fvec_t * read_data, uint_t * read){
267  uint_t i, j;
268  uint_t end = 0;
269  uint_t total_wrote = 0;
270  while (total_wrote < s->hop_size) {
271    end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
272    for (i = 0; i < end; i++) {
273      read_data->data[i + total_wrote] = 0;
274      for (j = 0; j < s->input_channels; j++ ) {
275        read_data->data[i + total_wrote] += s->output->data[j][i + s->read_index];
276      }
277      read_data->data[i + total_wrote] /= (smpl_t)(s->input_channels);
278    }
279    total_wrote += end;
280    if (total_wrote < s->hop_size) {
281      uint_t wavread_read = 0;
282      aubio_source_wavread_readframe(s, &wavread_read);
283      s->read_samples = wavread_read;
284      s->read_index = 0;
285      if (s->eof) {
286        break;
287      }
288    } else {
289      s->read_index += end;
290    }
291  }
292  if (total_wrote < s->hop_size) {
293    for (i = end; i < s->hop_size; i++) {
294      read_data->data[i] = 0.;
295    }
296  }
297  *read = total_wrote;
298}
299
300void aubio_source_wavread_do_multi(aubio_source_wavread_t * s, fmat_t * read_data, uint_t * read){
301  uint_t i,j;
302  uint_t end = 0;
303  uint_t total_wrote = 0;
304  while (total_wrote < s->hop_size) {
305    end = MIN(s->read_samples - s->read_index, s->hop_size - total_wrote);
306    for (j = 0; j < read_data->height; j++) {
307      for (i = 0; i < end; i++) {
308        read_data->data[j][i + total_wrote] = s->output->data[j][i];
309      }
310    }
311    total_wrote += end;
312    if (total_wrote < s->hop_size) {
313      uint_t wavread_read = 0;
314      aubio_source_wavread_readframe(s, &wavread_read);
315      s->read_samples = wavread_read;
316      s->read_index = 0;
317      if (s->eof) {
318        break;
319      }
320    } else {
321      s->read_index += end;
322    }
323  }
324  if (total_wrote < s->hop_size) {
325    for (j = 0; j < read_data->height; j++) {
326      for (i = end; i < s->hop_size; i++) {
327        read_data->data[j][i] = 0.;
328      }
329    }
330  }
331  *read = total_wrote;
332}
333
334uint_t aubio_source_wavread_get_samplerate(aubio_source_wavread_t * s) {
335  return s->samplerate;
336}
337
338uint_t aubio_source_wavread_get_channels(aubio_source_wavread_t * s) {
339  return s->input_channels;
340}
341
342uint_t aubio_source_wavread_seek (aubio_source_wavread_t * s, uint_t pos) {
343  uint_t ret = fseek(s->fid, 44 + pos * s->blockalign, SEEK_SET);
344  s->eof = 0;
345  s->read_index = 0;
346  return ret;
347}
348
349void del_aubio_source_wavread(aubio_source_wavread_t * s) {
350  if (!s) return;
351  if (s->fid) fclose(s->fid);
352  if (s->short_output) AUBIO_FREE(s->short_output);
353  if (s->output) del_fmat(s->output);
354  AUBIO_FREE(s);
355}
356
357#endif /* HAVE_WAVREAD */
Note: See TracBrowser for help on using the repository browser.