source: src/io/sink_wavwrite.c @ a9fd272

feature/autosinkfeature/constantqfeature/pitchshiftfeature/pydocstringsfeature/timestretchpitchshiftsamplertimestretchyinfft+
Last change on this file since a9fd272 was a9fd272, checked in by Paul Brossier <piem@piem.org>, 7 years ago

src/io/sink*: add _close function, improve error messages

  • Property mode set to 100644
File size: 5.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
22#include "config.h"
23
24#ifdef HAVE_WAVWRITE
25
26#include "aubio_priv.h"
27#include "sink_wavwrite.h"
28#include "fvec.h"
29
30#include <errno.h>
31
32#define MAX_CHANNELS 6
33#define MAX_SIZE 4096
34
35#define FLOAT_TO_SHORT(x) (short)(x * 32768)
36
37// swap endian of a short
38#define SWAPS(x) ((x & 0xff) << 8) | ((x & 0xff00) >> 8)
39
40// swap host to little endian
41#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
42#define HTOLES(x) SWAPS(x)
43#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
44#define HTOLES(x) x
45#else
46#define HTOLES(x) SWAPS(htons(x))
47#endif
48
49struct _aubio_sink_wavwrite_t {
50  char_t *path;
51  uint_t samplerate;
52  uint_t channels;
53  uint_t bitspersample;
54  uint_t total_frames_written;
55
56  FILE *fid;
57
58  uint_t max_size;
59
60  uint_t scratch_size;
61  unsigned short *scratch_data;
62};
63
64unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned int length);
65unsigned char *write_little_endian (unsigned int s, unsigned char *str, unsigned int length) {
66  uint_t i;
67  for (i = 0; i < length; i++) {
68    str[i] = s >> (i * 8);
69  }
70  return str;
71}
72
73aubio_sink_wavwrite_t * new_aubio_sink_wavwrite(char_t * path, uint_t samplerate) {
74  aubio_sink_wavwrite_t * s = AUBIO_NEW(aubio_sink_wavwrite_t);
75  unsigned char buf[5];
76  uint_t byterate, blockalign;
77
78  if (path == NULL) {
79    AUBIO_ERR("sink_wavwrite: Aborted opening null path\n");
80    goto beach;
81  }
82  if ((sint_t)samplerate < 0) {
83    AUBIO_ERR("sink_wavwrite: Can not create %s with samplerate %d\n", path, samplerate);
84    goto beach;
85  }
86
87  s->path = path;
88  s->samplerate = samplerate;
89  s->max_size = MAX_SIZE;
90  s->channels = 1;
91  s->bitspersample = 16;
92  s->total_frames_written = 0;
93
94  /* set output format */
95  s->fid = fopen((const char *)path, "wb");
96  if (!s->fid) {
97    AUBIO_ERR("sink_wavwrite: could not open %s (%s)\n", s->path, strerror(errno));
98    goto beach;
99  }
100
101  // ChunkID
102  fwrite("RIFF", 4, 1, s->fid);
103
104  // ChunkSize (0 for now, actual size will be written in _close)
105  fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
106
107  // Format
108  fwrite("WAVE", 4, 1, s->fid);
109
110  // Subchunk1ID
111  fwrite("fmt ", 4, 1, s->fid);
112
113  // Subchunk1Size
114  fwrite(write_little_endian(16, buf, 4), 4, 1, s->fid);
115
116  // AudioFormat
117  fwrite(write_little_endian(1, buf, 2), 2, 1, s->fid);
118
119  // NumChannels
120  fwrite(write_little_endian(s->channels, buf, 2), 2, 1, s->fid);
121
122  // SampleRate
123  fwrite(write_little_endian(s->samplerate, buf, 4), 4, 1, s->fid);
124
125  // ByteRate
126  byterate = s->samplerate * s->channels * s->bitspersample / 8;
127  fwrite(write_little_endian(byterate, buf, 4), 4, 1, s->fid);
128
129  // BlockAlign
130  blockalign = s->channels * s->bitspersample / 8;
131  fwrite(write_little_endian(blockalign, buf, 2), 2, 1, s->fid);
132
133  // BitsPerSample
134  fwrite(write_little_endian(s->bitspersample, buf, 2), 2, 1, s->fid);
135
136  // Subchunk2ID
137  fwrite("data", 4, 1, s->fid);
138
139  // Subchunk1Size (0 for now, actual size will be written in _close)
140  fwrite(write_little_endian(0, buf, 4), 4, 1, s->fid);
141
142  s->scratch_size = s->max_size * s->channels;
143  /* allocate data for de/interleaving reallocated when needed. */
144  if (s->scratch_size >= MAX_SIZE * MAX_CHANNELS) {
145    AUBIO_ERR("sink_wavwrite: %d x %d exceeds maximum buffer size %d\n",
146        s->max_size, s->channels, MAX_CHANNELS * MAX_CHANNELS);
147    AUBIO_FREE(s);
148    return NULL;
149  }
150  s->scratch_data = AUBIO_ARRAY(unsigned short,s->scratch_size);
151
152  return s;
153
154beach:
155  //AUBIO_ERR("sink_wavwrite: failed creating %s with samplerate %dHz\n",
156  //    s->path, s->samplerate);
157  del_aubio_sink_wavwrite(s);
158  return NULL;
159}
160
161
162void aubio_sink_wavwrite_do(aubio_sink_wavwrite_t *s, fvec_t * write_data, uint_t write){
163  uint_t i = 0, written_frames = 0;
164
165  if (write > s->max_size) {
166    AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
167        "but only %d can be written at a time\n", write, s->path, s->max_size);
168    write = s->max_size;
169  }
170
171  for (i = 0; i < write; i++) {
172    s->scratch_data[i] = HTOLES(FLOAT_TO_SHORT(write_data->data[i]));
173  }
174  written_frames = fwrite(s->scratch_data, 2, write, s->fid);
175
176  if (written_frames != write) {
177    AUBIO_WRN("sink_wavwrite: trying to write %d frames to %s, "
178        "but only %d could be written\n", write, s->path, written_frames);
179  }
180  s->total_frames_written += written_frames;
181  return;
182}
183
184uint_t aubio_sink_wavwrite_close(aubio_sink_wavwrite_t * s) {
185  uint_t data_size = s->total_frames_written * s->bitspersample * s->channels / 8;
186  unsigned char buf[5];
187  if (!s->fid) return AUBIO_FAIL;
188  // ChunkSize
189  fseek(s->fid, 4, SEEK_SET);
190  fwrite(write_little_endian(data_size + 36, buf, 4), 4, 1, s->fid);
191  // Subchunk2Size
192  fseek(s->fid, 40, SEEK_SET);
193  fwrite(write_little_endian(data_size, buf, 4), 4, 1, s->fid);
194  // close file
195  if (fclose(s->fid)) {
196    AUBIO_ERR("sink_wavwrite: Error closing file %s (%s)\n", s->path, strerror(errno));
197  }
198  s->fid = NULL;
199  return AUBIO_OK;
200}
201
202void del_aubio_sink_wavwrite(aubio_sink_wavwrite_t * s){
203  if (!s) return;
204  aubio_sink_wavwrite_close(s);
205  AUBIO_FREE(s->scratch_data);
206  AUBIO_FREE(s);
207}
208
209#endif /* HAVE_WAVWRITE */
Note: See TracBrowser for help on using the repository browser.