-
Notifications
You must be signed in to change notification settings - Fork 25
/
snd.c
415 lines (335 loc) · 10 KB
/
snd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
/* some wrapper for libsndfile
* Copyright (C) 2007-2013 Kengo Ichiki <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h> // memset()
#include <sndfile.h>
#include "memory-check.h" // CHECK_MALLOC() macro
long sndfile_read (SNDFILE *sf, SF_INFO sfinfo,
double * left, double * right,
int len)
{
static double *buf = NULL;
static int nbuf = 0;
if (buf == NULL)
{
buf = (double *)malloc (sizeof (double) * len * sfinfo.channels);
CHECK_MALLOC (buf, "sndfile_read");
nbuf = len * sfinfo.channels;
}
if (len * sfinfo.channels > nbuf)
{
buf = (double *)realloc (buf, sizeof (double) * len * sfinfo.channels);
CHECK_MALLOC (buf, "sndfile_read");
nbuf = len * sfinfo.channels;
}
sf_count_t status;
if (sfinfo.channels == 1)
{
status = sf_readf_double (sf, left, (sf_count_t)len);
}
else
{
status = sf_readf_double (sf, buf, (sf_count_t)len);
int i;
for (i = 0; i < len; i ++)
{
left [i] = buf [i * sfinfo.channels];
right [i] = buf [i * sfinfo.channels + 1];
}
}
return ((long) status);
}
long sndfile_read_at (SNDFILE *sf, SF_INFO sfinfo,
long start,
double * left, double * right,
int len)
{
sf_count_t status;
// check the range
if (start < 0) return 0;
else if (start >= sfinfo.frames) return 0;
// seek the point start
status = sf_seek (sf, (sf_count_t)start, SEEK_SET);
if (status == -1)
{
fprintf (stderr, "seek error\n");
exit (1);
}
return (sndfile_read (sf, sfinfo, left, right, len));
}
/* print sfinfo
*/
void sndfile_print_info (SF_INFO *sfinfo)
{
// Major
switch (sfinfo->format & SF_FORMAT_TYPEMASK)
{
case SF_FORMAT_WAV:
fprintf (stderr, "Format: Microsoft WAV format (little endian default).\n");
break;
case SF_FORMAT_AIFF:
fprintf (stderr, "Format: Apple/SGI AIFF format (big endian).\n");
break;
case SF_FORMAT_AU:
fprintf (stderr, "Format: Sun/NeXT AU format (big endian).\n");
break;
case SF_FORMAT_RAW:
fprintf (stderr, "Format: RAW PCM data.\n");
break;
case SF_FORMAT_PAF:
fprintf (stderr, "Format: Ensoniq PARIS file format.\n");
break;
case SF_FORMAT_SVX:
fprintf (stderr, "Format: Amiga IFF / SVX8 / SV16 format.\n");
break;
case SF_FORMAT_NIST:
fprintf (stderr, "Format: Sphere NIST format.\n");
break;
case SF_FORMAT_VOC:
fprintf (stderr, "Format: VOC files.\n");
break;
case SF_FORMAT_IRCAM:
fprintf (stderr, "Format: Berkeley/IRCAM/CARL\n");
break;
case SF_FORMAT_W64:
fprintf (stderr, "Format: Sonic Foundry's 64 bit RIFF/WAV\n");
break;
case SF_FORMAT_MAT4:
fprintf (stderr, "Format: Matlab (tm) V4.2 / GNU Octave 2.0\n");
break;
case SF_FORMAT_MAT5:
fprintf (stderr, "Format: Matlab (tm) V5.0 / GNU Octave 2.1\n");
break;
case SF_FORMAT_PVF:
fprintf (stderr, "Format: Portable Voice Format\n");
break;
case SF_FORMAT_XI:
fprintf (stderr, "Format: Fasttracker 2 Extended Instrument\n");
break;
case SF_FORMAT_HTK:
fprintf (stderr, "Format: HMM Tool Kit format\n");
break;
case SF_FORMAT_SDS:
fprintf (stderr, "Format: Midi Sample Dump Standard\n");
break;
case SF_FORMAT_AVR:
fprintf (stderr, "Format: Audio Visual Research\n");
break;
case SF_FORMAT_WAVEX:
fprintf (stderr, "Format: MS WAVE with WAVEFORMATEX\n");
break;
case SF_FORMAT_SD2:
fprintf (stderr, "Format: Sound Designer 2\n");
break;
case SF_FORMAT_FLAC:
fprintf (stderr, "Format: FLAC lossless file format\n");
break;
case SF_FORMAT_CAF:
fprintf (stderr, "Format: Core Audio File format\n");
break;
default :
fprintf (stderr, "unknown Subtype\n");
exit (1);
}
// Subtypes
switch (sfinfo->format & SF_FORMAT_SUBMASK)
{
case SF_FORMAT_PCM_S8:
fprintf (stderr, "Subtype: Signed 8 bit data\n");
break;
case SF_FORMAT_PCM_16:
fprintf (stderr, "Subtype: Signed 16 bit data\n");
break;
case SF_FORMAT_PCM_24:
fprintf (stderr, "Subtype: Signed 24 bit data\n");
break;
case SF_FORMAT_PCM_32:
fprintf (stderr, "Subtype: Signed 32 bit data\n");
break;
case SF_FORMAT_PCM_U8:
fprintf (stderr, "Subtype: Unsigned 8 bit data (WAV and RAW only)\n");
break;
case SF_FORMAT_FLOAT:
fprintf (stderr, "Subtype: 32 bit float data\n");
break;
case SF_FORMAT_DOUBLE:
fprintf (stderr, "Subtype: 64 bit float data\n");
break;
case SF_FORMAT_ULAW:
fprintf (stderr, "Subtype: U-Law encoded.\n");
break;
case SF_FORMAT_ALAW:
fprintf (stderr, "Subtype: A-Law encoded.\n");
break;
case SF_FORMAT_IMA_ADPCM:
fprintf (stderr, "Subtype: IMA ADPCM.\n");
break;
case SF_FORMAT_MS_ADPCM:
fprintf (stderr, "Subtype: Microsoft ADPCM.\n");
break;
case SF_FORMAT_GSM610:
fprintf (stderr, "Subtype: GSM 6.10 encoding.\n");
break;
case SF_FORMAT_VOX_ADPCM:
fprintf (stderr, "Subtype: Oki Dialogic ADPCM encoding.\n");
break;
case SF_FORMAT_G721_32:
fprintf (stderr, "Subtype: 32kbs G721 ADPCM encoding.\n");
break;
case SF_FORMAT_G723_24:
fprintf (stderr, "Subtype: 24kbs G723 ADPCM encoding.\n");
break;
case SF_FORMAT_G723_40:
fprintf (stderr, "Subtype: 40kbs G723 ADPCM encoding.\n");
break;
case SF_FORMAT_DWVW_12:
fprintf (stderr, "Subtype: 12 bit Delta Width Variable Word encoding.\n");
break;
case SF_FORMAT_DWVW_16:
fprintf (stderr, "Subtype: 16 bit Delta Width Variable Word encoding.\n");
break;
case SF_FORMAT_DWVW_24:
fprintf (stderr, "Subtype: 24 bit Delta Width Variable Word encoding.\n");
break;
case SF_FORMAT_DWVW_N:
fprintf (stderr, "Subtype: N bit Delta Width Variable Word encoding.\n");
break;
case SF_FORMAT_DPCM_8:
fprintf (stderr, "Subtype: 8 bit differential PCM (XI only)\n");
break;
case SF_FORMAT_DPCM_16:
fprintf (stderr, "Subtype: 16 bit differential PCM (XI only)\n");
break;
default :
fprintf (stderr, "unknown Subtype\n");
exit (1);
}
// Endian
switch (sfinfo->format & SF_FORMAT_ENDMASK)
{
case SF_ENDIAN_FILE:
fprintf (stderr, "Endian type: Default file endian-ness.\n");
break;
case SF_ENDIAN_LITTLE:
fprintf (stderr, "Endian type: Force little endian-ness.\n");
break;
case SF_ENDIAN_BIG:
fprintf (stderr, "Endian type: Force big endian-ness.\n");
break;
case SF_ENDIAN_CPU:
fprintf (stderr, "Endian type: Force CPU endian-ness.\n");
break;
default :
fprintf (stderr, "unknown Endian type\n");
exit (1);
}
fprintf (stderr, "frames : %d\n", (int)sfinfo->frames);
fprintf (stderr, "samplerate : %d\n", sfinfo->samplerate);
fprintf (stderr, "channels : %d\n", sfinfo->channels);
fprintf (stderr, "sections : %d\n", sfinfo->sections);
fprintf (stderr, "seekable : %d\n", sfinfo->seekable);
}
/*
* OUTPUT (returned value)
* -1 : no extension or unsupported format
* 0 : wav
* 1 : flac
*/
int check_filetype_by_extension (const char *file)
{
int len;
len = strlen (file);
int i;
for (i = len-1; i >= 0; i--)
{
if (file [i] == '.') break;
}
if (file [i] != '.') return -1; // no extension
else if (strcmp (file + i + 1, "wav") == 0) return 0; // wav
else if (strcmp (file + i + 1, "flac") == 0) return 1; // flac
else return -1; // unsupported format
}
/* output functions
*/
SNDFILE * sndfile_open_for_write (SF_INFO *sfinfo,
const char *file,
int samplerate,
int channels)
{
int mode;
mode = check_filetype_by_extension (file);
if (mode < 0)
{
fprintf (stderr, "unknown or unsupported format %s."
" we force to write in wav format.\n", file);
mode = 0; // wav
}
memset (sfinfo, 0, sizeof (*sfinfo));
// format
switch (mode)
{
case 0: // wav
sfinfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_FILE;
break;
case 1: // flac
sfinfo->format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16 | SF_ENDIAN_FILE;
break;
default:
fprintf (stderr, "invalid mode %d\n", mode);
exit (1);
}
//sfinfo->frames = 0;
sfinfo->samplerate = samplerate;
sfinfo->channels = channels;
sfinfo->sections = 1;
sfinfo->seekable = 1;
// open
SNDFILE *sf = NULL;
sf = sf_open (file, SFM_WRITE, sfinfo);
if (sf == NULL)
{
fprintf (stderr, "fail to open %s\n", file);
exit (1);
}
return (sf);
}
long sndfile_write (SNDFILE *sf, SF_INFO sfinfo,
double * left, double * right,
int len)
{
sf_count_t status;
if (sfinfo.channels == 1)
{
status = sf_writef_double (sf, left, (sf_count_t)len);
}
else
{
double *buf = NULL;
buf = (double *) malloc (sizeof (double) * len * sfinfo.channels);
CHECK_MALLOC (buf, "sndfile_write");
int i;
for (i = 0; i < len; i ++)
{
buf [i * sfinfo.channels] = left [i];
buf [i * sfinfo.channels + 1] = right [i];
}
status = sf_writef_double (sf, buf, (sf_count_t)len);
free (buf);
}
return ((long) status);
}