/src/libsndfile/src/command.c
Line | Count | Source |
1 | | /* |
2 | | ** Copyright (C) 2001-2016 Erik de Castro Lopo <erikd@mega-nerd.com> |
3 | | ** |
4 | | ** This program is free software; you can redistribute it and/or modify |
5 | | ** it under the terms of the GNU Lesser General Public License as published by |
6 | | ** the Free Software Foundation; either version 2.1 of the License, or |
7 | | ** (at your option) any later version. |
8 | | ** |
9 | | ** This program is distributed in the hope that it will be useful, |
10 | | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | ** GNU Lesser General Public License for more details. |
13 | | ** |
14 | | ** You should have received a copy of the GNU Lesser General Public License |
15 | | ** along with this program; if not, write to the Free Software |
16 | | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 | | */ |
18 | | |
19 | | #include "sfconfig.h" |
20 | | |
21 | | #include <stdio.h> |
22 | | #include <string.h> |
23 | | #include <math.h> |
24 | | |
25 | | #include "sndfile.h" |
26 | | #include "common.h" |
27 | | |
28 | | static SF_FORMAT_INFO const simple_formats [] = |
29 | | { |
30 | | { SF_FORMAT_AIFF | SF_FORMAT_PCM_16, |
31 | | "AIFF (Apple/SGI 16 bit PCM)", "aiff" |
32 | | }, |
33 | | |
34 | | { SF_FORMAT_AIFF | SF_FORMAT_FLOAT, |
35 | | "AIFF (Apple/SGI 32 bit float)", "aifc" |
36 | | }, |
37 | | |
38 | | { SF_FORMAT_AIFF | SF_FORMAT_PCM_S8, |
39 | | "AIFF (Apple/SGI 8 bit PCM)", "aiff" |
40 | | }, |
41 | | |
42 | | { SF_FORMAT_AU | SF_FORMAT_PCM_16, |
43 | | "AU (Sun/Next 16 bit PCM)", "au" |
44 | | }, |
45 | | |
46 | | { SF_FORMAT_AU | SF_FORMAT_ULAW, |
47 | | "AU (Sun/Next 8-bit u-law)", "au" |
48 | | }, |
49 | | |
50 | | { SF_FORMAT_CAF | SF_FORMAT_ALAC_16, |
51 | | "CAF (Apple 16 bit ALAC)", "caf" |
52 | | }, |
53 | | |
54 | | { SF_FORMAT_CAF | SF_FORMAT_PCM_16, |
55 | | "CAF (Apple 16 bit PCM)", "caf" |
56 | | }, |
57 | | |
58 | | #if HAVE_EXTERNAL_XIPH_LIBS |
59 | | { SF_FORMAT_FLAC | SF_FORMAT_PCM_16, |
60 | | "FLAC 16 bit", "flac" |
61 | | }, |
62 | | #endif |
63 | | |
64 | | #if HAVE_MPEG |
65 | | { SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III, |
66 | | "MPEG Layer 3", "mp3" |
67 | | }, |
68 | | #endif |
69 | | |
70 | | { SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, |
71 | | "OKI Dialogic VOX ADPCM", "vox" |
72 | | }, |
73 | | |
74 | | #if HAVE_EXTERNAL_XIPH_LIBS |
75 | | { SF_FORMAT_OGG | SF_FORMAT_OPUS, |
76 | | "Ogg Opus (Xiph Foundation)", "opus" |
77 | | }, |
78 | | |
79 | | { SF_FORMAT_OGG | SF_FORMAT_VORBIS, |
80 | | "Ogg Vorbis (Xiph Foundation)", "ogg" |
81 | | }, |
82 | | #endif |
83 | | |
84 | | { SF_FORMAT_WAV | SF_FORMAT_PCM_16, |
85 | | "WAV (Microsoft 16 bit PCM)", "wav" |
86 | | }, |
87 | | |
88 | | { SF_FORMAT_WAV | SF_FORMAT_FLOAT, |
89 | | "WAV (Microsoft 32 bit float)", "wav" |
90 | | }, |
91 | | |
92 | | { SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, |
93 | | "WAV (Microsoft 4 bit IMA ADPCM)", "wav" |
94 | | }, |
95 | | |
96 | | { SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, |
97 | | "WAV (Microsoft 4 bit MS ADPCM)", "wav" |
98 | | }, |
99 | | |
100 | | { SF_FORMAT_WAV | SF_FORMAT_PCM_U8, |
101 | | "WAV (Microsoft 8 bit PCM)", "wav" |
102 | | }, |
103 | | |
104 | | } ; /* simple_formats */ |
105 | | |
106 | | int |
107 | | psf_get_format_simple_count (void) |
108 | 0 | { return (sizeof (simple_formats) / sizeof (SF_FORMAT_INFO)) ; |
109 | 0 | } /* psf_get_format_simple_count */ |
110 | | |
111 | | int |
112 | | psf_get_format_simple (SF_FORMAT_INFO *data) |
113 | 0 | { int indx ; |
114 | |
|
115 | 0 | if (data->format < 0 || data->format >= (SIGNED_SIZEOF (simple_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) |
116 | 0 | return SFE_BAD_COMMAND_PARAM ; |
117 | | |
118 | 0 | indx = data->format ; |
119 | 0 | memcpy (data, &(simple_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; |
120 | |
|
121 | 0 | return 0 ; |
122 | 0 | } /* psf_get_format_simple */ |
123 | | |
124 | | /*============================================================================ |
125 | | ** Major format info. |
126 | | */ |
127 | | |
128 | | static SF_FORMAT_INFO const major_formats [] = |
129 | | { |
130 | | { SF_FORMAT_AIFF, "AIFF (Apple/SGI)", "aiff" }, |
131 | | { SF_FORMAT_AU, "AU (Sun/NeXT)", "au" }, |
132 | | { SF_FORMAT_AVR, "AVR (Audio Visual Research)", "avr" }, |
133 | | { SF_FORMAT_CAF, "CAF (Apple Core Audio File)", "caf" }, |
134 | | #if HAVE_EXTERNAL_XIPH_LIBS |
135 | | { SF_FORMAT_FLAC, "FLAC (Free Lossless Audio Codec)", "flac" }, |
136 | | #endif |
137 | | { SF_FORMAT_HTK, "HTK (HMM Tool Kit)", "htk" }, |
138 | | { SF_FORMAT_SVX, "IFF (Amiga IFF/SVX8/SV16)", "iff" }, |
139 | | { SF_FORMAT_MAT4, "MAT4 (GNU Octave 2.0 / Matlab 4.2)", "mat" }, |
140 | | { SF_FORMAT_MAT5, "MAT5 (GNU Octave 2.1 / Matlab 5.0)", "mat" }, |
141 | | { SF_FORMAT_MPC2K, "MPC (Akai MPC 2k)", "mpc" }, |
142 | | #if HAVE_MPEG |
143 | | { SF_FORMAT_MPEG, "MPEG-1/2 Audio", "m1a" }, |
144 | | #endif |
145 | | #if HAVE_EXTERNAL_XIPH_LIBS |
146 | | { SF_FORMAT_OGG, "OGG (OGG Container format)", "oga" }, |
147 | | #endif |
148 | | { SF_FORMAT_PAF, "PAF (Ensoniq PARIS)", "paf" }, |
149 | | { SF_FORMAT_PVF, "PVF (Portable Voice Format)", "pvf" }, |
150 | | { SF_FORMAT_RAW, "RAW (header-less)", "raw" }, |
151 | | { SF_FORMAT_RF64, "RF64 (RIFF 64)", "rf64" }, |
152 | | { SF_FORMAT_SD2, "SD2 (Sound Designer II)", "sd2" }, |
153 | | { SF_FORMAT_SDS, "SDS (Midi Sample Dump Standard)", "sds" }, |
154 | | { SF_FORMAT_IRCAM, "SF (Berkeley/IRCAM/CARL)", "sf" }, |
155 | | { SF_FORMAT_VOC, "VOC (Creative Labs)", "voc" }, |
156 | | { SF_FORMAT_W64, "W64 (SoundFoundry WAVE 64)", "w64" }, |
157 | | { SF_FORMAT_WAV, "WAV (Microsoft)", "wav" }, |
158 | | { SF_FORMAT_NIST, "WAV (NIST Sphere)", "wav" }, |
159 | | { SF_FORMAT_WAVEX, "WAVEX (Microsoft)", "wav" }, |
160 | | { SF_FORMAT_WVE, "WVE (Psion Series 3)", "wve" }, |
161 | | { SF_FORMAT_XI, "XI (FastTracker 2)", "xi" }, |
162 | | |
163 | | } ; /* major_formats */ |
164 | | |
165 | | int |
166 | | psf_get_format_major_count (void) |
167 | 0 | { return (sizeof (major_formats) / sizeof (SF_FORMAT_INFO)) ; |
168 | 0 | } /* psf_get_format_major_count */ |
169 | | |
170 | | int |
171 | | psf_get_format_major (SF_FORMAT_INFO *data) |
172 | 0 | { int indx ; |
173 | |
|
174 | 0 | if (data->format < 0 || data->format >= (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) |
175 | 0 | return SFE_BAD_COMMAND_PARAM ; |
176 | | |
177 | 0 | indx = data->format ; |
178 | 0 | memcpy (data, &(major_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; |
179 | |
|
180 | 0 | return 0 ; |
181 | 0 | } /* psf_get_format_major */ |
182 | | |
183 | | /*============================================================================ |
184 | | ** Subtype format info. |
185 | | */ |
186 | | |
187 | | static SF_FORMAT_INFO subtype_formats [] = |
188 | | { |
189 | | { SF_FORMAT_PCM_S8, "Signed 8 bit PCM", NULL }, |
190 | | { SF_FORMAT_PCM_16, "Signed 16 bit PCM", NULL }, |
191 | | { SF_FORMAT_PCM_24, "Signed 24 bit PCM", NULL }, |
192 | | { SF_FORMAT_PCM_32, "Signed 32 bit PCM", NULL }, |
193 | | |
194 | | { SF_FORMAT_PCM_U8, "Unsigned 8 bit PCM", NULL }, |
195 | | |
196 | | { SF_FORMAT_FLOAT, "32 bit float", NULL }, |
197 | | { SF_FORMAT_DOUBLE, "64 bit float", NULL }, |
198 | | |
199 | | { SF_FORMAT_ULAW, "U-Law", NULL }, |
200 | | { SF_FORMAT_ALAW, "A-Law", NULL }, |
201 | | { SF_FORMAT_IMA_ADPCM, "IMA ADPCM", NULL }, |
202 | | { SF_FORMAT_MS_ADPCM, "Microsoft ADPCM", NULL }, |
203 | | |
204 | | { SF_FORMAT_GSM610, "GSM 6.10", NULL }, |
205 | | |
206 | | { SF_FORMAT_G721_32, "32kbs G721 ADPCM", NULL }, |
207 | | { SF_FORMAT_G723_24, "24kbs G723 ADPCM", NULL }, |
208 | | { SF_FORMAT_G723_40, "40kbs G723 ADPCM", NULL }, |
209 | | |
210 | | { SF_FORMAT_DWVW_12, "12 bit DWVW", NULL }, |
211 | | { SF_FORMAT_DWVW_16, "16 bit DWVW", NULL }, |
212 | | { SF_FORMAT_DWVW_24, "24 bit DWVW", NULL }, |
213 | | { SF_FORMAT_VOX_ADPCM, "VOX ADPCM", "vox" }, |
214 | | |
215 | | { SF_FORMAT_NMS_ADPCM_16, "16kbs NMS ADPCM", NULL }, |
216 | | { SF_FORMAT_NMS_ADPCM_24, "24kbs NMS ADPCM", NULL }, |
217 | | { SF_FORMAT_NMS_ADPCM_32, "32kbs NMS ADPCM", NULL }, |
218 | | |
219 | | { SF_FORMAT_DPCM_16, "16 bit DPCM", NULL }, |
220 | | { SF_FORMAT_DPCM_8, "8 bit DPCM", NULL }, |
221 | | |
222 | | #if HAVE_EXTERNAL_XIPH_LIBS |
223 | | { SF_FORMAT_VORBIS, "Vorbis", NULL }, |
224 | | { SF_FORMAT_OPUS, "Opus", NULL }, |
225 | | #endif |
226 | | |
227 | | #if HAVE_MPEG |
228 | | { SF_FORMAT_MPEG_LAYER_I, "MPEG Layer I", "mp1" }, |
229 | | { SF_FORMAT_MPEG_LAYER_II, "MPEG Layer II", "mp2" }, |
230 | | { SF_FORMAT_MPEG_LAYER_III, "MPEG Layer III", "mp3" }, |
231 | | #endif |
232 | | |
233 | | { SF_FORMAT_ALAC_16, "16 bit ALAC", NULL }, |
234 | | { SF_FORMAT_ALAC_20, "20 bit ALAC", NULL }, |
235 | | { SF_FORMAT_ALAC_24, "24 bit ALAC", NULL }, |
236 | | { SF_FORMAT_ALAC_32, "32 bit ALAC", NULL }, |
237 | | } ; /* subtype_formats */ |
238 | | |
239 | | int |
240 | | psf_get_format_subtype_count (void) |
241 | 0 | { return (sizeof (subtype_formats) / sizeof (SF_FORMAT_INFO)) ; |
242 | 0 | } /* psf_get_format_subtype_count */ |
243 | | |
244 | | int |
245 | | psf_get_format_subtype (SF_FORMAT_INFO *data) |
246 | 0 | { int indx ; |
247 | |
|
248 | 0 | if (data->format < 0 || data->format >= (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) |
249 | 0 | { data->format = 0 ; |
250 | 0 | return SFE_BAD_COMMAND_PARAM ; |
251 | 0 | } ; |
252 | |
|
253 | 0 | indx = data->format ; |
254 | 0 | memcpy (data, &(subtype_formats [indx]), sizeof (SF_FORMAT_INFO)) ; |
255 | |
|
256 | 0 | return 0 ; |
257 | 0 | } /* psf_get_format_subtype */ |
258 | | |
259 | | /*============================================================================== |
260 | | */ |
261 | | |
262 | | int |
263 | | psf_get_format_info (SF_FORMAT_INFO *data) |
264 | 0 | { int k, format ; |
265 | |
|
266 | 0 | if (SF_CONTAINER (data->format)) |
267 | 0 | { format = SF_CONTAINER (data->format) ; |
268 | |
|
269 | 0 | for (k = 0 ; k < (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) |
270 | 0 | { if (format == major_formats [k].format) |
271 | 0 | { memcpy (data, &(major_formats [k]), sizeof (SF_FORMAT_INFO)) ; |
272 | 0 | return 0 ; |
273 | 0 | } ; |
274 | 0 | } ; |
275 | 0 | } |
276 | 0 | else if (SF_CODEC (data->format)) |
277 | 0 | { format = SF_CODEC (data->format) ; |
278 | |
|
279 | 0 | for (k = 0 ; k < (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) |
280 | 0 | { if (format == subtype_formats [k].format) |
281 | 0 | { memcpy (data, &(subtype_formats [k]), sizeof (SF_FORMAT_INFO)) ; |
282 | 0 | return 0 ; |
283 | 0 | } ; |
284 | 0 | } ; |
285 | 0 | } ; |
286 | |
|
287 | 0 | memset (data, 0, sizeof (SF_FORMAT_INFO)) ; |
288 | |
|
289 | 0 | return SFE_BAD_COMMAND_PARAM ; |
290 | 0 | } /* psf_get_format_info */ |
291 | | |
292 | | /*============================================================================== |
293 | | */ |
294 | | |
295 | | double |
296 | | psf_calc_signal_max (SF_PRIVATE *psf, int normalize) |
297 | 0 | { BUF_UNION ubuf ; |
298 | 0 | sf_count_t position ; |
299 | 0 | double max_val, temp, *data ; |
300 | 0 | int k, len, readcount, save_state ; |
301 | | |
302 | | /* If the file is not seekable, there is nothing we can do. */ |
303 | 0 | if (! psf->sf.seekable) |
304 | 0 | { psf->error = SFE_NOT_SEEKABLE ; |
305 | 0 | return 0.0 ; |
306 | 0 | } ; |
307 | |
|
308 | 0 | if (! psf->read_double) |
309 | 0 | { psf->error = SFE_UNIMPLEMENTED ; |
310 | 0 | return 0.0 ; |
311 | 0 | } ; |
312 | |
|
313 | 0 | save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ; |
314 | 0 | sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ; |
315 | | |
316 | | /* Brute force. Read the whole file and find the biggest sample. */ |
317 | | /* Get current position in file */ |
318 | 0 | position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; |
319 | | /* Go to start of file. */ |
320 | 0 | sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; |
321 | |
|
322 | 0 | data = ubuf.dbuf ; |
323 | | /* Make sure len is an integer multiple of the channel count. */ |
324 | 0 | len = ARRAY_LEN (ubuf.dbuf) - (ARRAY_LEN (ubuf.dbuf) % psf->sf.channels) ; |
325 | |
|
326 | 0 | for (readcount = 1, max_val = 0.0 ; readcount > 0 ; /* nothing */) |
327 | 0 | { readcount = (int) sf_read_double ((SNDFILE*) psf, data, len) ; |
328 | 0 | for (k = 0 ; k < readcount ; k++) |
329 | 0 | { temp = fabs (data [k]) ; |
330 | 0 | max_val = temp > max_val ? temp : max_val ; |
331 | 0 | } ; |
332 | 0 | } ; |
333 | | |
334 | | /* Return to SNDFILE to original state. */ |
335 | 0 | sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; |
336 | 0 | sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ; |
337 | |
|
338 | 0 | return max_val ; |
339 | 0 | } /* psf_calc_signal_max */ |
340 | | |
341 | | int |
342 | | psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize) |
343 | 0 | { BUF_UNION ubuf ; |
344 | 0 | sf_count_t position ; |
345 | 0 | double temp, *data ; |
346 | 0 | int k, len, readcount, save_state ; |
347 | 0 | int chan ; |
348 | | |
349 | | /* If the file is not seekable, there is nothing we can do. */ |
350 | 0 | if (! psf->sf.seekable) |
351 | 0 | return (psf->error = SFE_NOT_SEEKABLE) ; |
352 | | |
353 | 0 | if (! psf->read_double) |
354 | 0 | return (psf->error = SFE_UNIMPLEMENTED) ; |
355 | | |
356 | 0 | save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ; |
357 | 0 | sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ; |
358 | |
|
359 | 0 | memset (peaks, 0, sizeof (double) * psf->sf.channels) ; |
360 | | |
361 | | /* Brute force. Read the whole file and find the biggest sample for each channel. */ |
362 | 0 | position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; /* Get current position in file */ |
363 | 0 | sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; /* Go to start of file. */ |
364 | |
|
365 | 0 | len = ARRAY_LEN (ubuf.dbuf) - (ARRAY_LEN (ubuf.dbuf) % psf->sf.channels) ; |
366 | |
|
367 | 0 | data = ubuf.dbuf ; |
368 | |
|
369 | 0 | chan = 0 ; |
370 | 0 | readcount = len ; |
371 | 0 | while (readcount > 0) |
372 | 0 | { readcount = (int) sf_read_double ((SNDFILE*) psf, data, len) ; |
373 | 0 | for (k = 0 ; k < readcount ; k++) |
374 | 0 | { temp = fabs (data [k]) ; |
375 | 0 | peaks [chan] = temp > peaks [chan] ? temp : peaks [chan] ; |
376 | 0 | chan = (chan + 1) % psf->sf.channels ; |
377 | 0 | } ; |
378 | 0 | } ; |
379 | |
|
380 | 0 | sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; /* Return to original position. */ |
381 | |
|
382 | 0 | sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ; |
383 | |
|
384 | 0 | return 0 ; |
385 | 0 | } /* psf_calc_max_all_channels */ |
386 | | |
387 | | int |
388 | | psf_get_signal_max (SF_PRIVATE *psf, double *peak) |
389 | 0 | { int k ; |
390 | |
|
391 | 0 | if (psf->peak_info == NULL) |
392 | 0 | return SF_FALSE ; |
393 | | |
394 | 0 | peak [0] = psf->peak_info->peaks [0].value ; |
395 | |
|
396 | 0 | for (k = 1 ; k < psf->sf.channels ; k++) |
397 | 0 | peak [0] = SF_MAX (peak [0], psf->peak_info->peaks [k].value) ; |
398 | |
|
399 | 0 | return SF_TRUE ; |
400 | 0 | } /* psf_get_signal_max */ |
401 | | |
402 | | int |
403 | | psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks) |
404 | 0 | { int k ; |
405 | |
|
406 | 0 | if (psf->peak_info == NULL) |
407 | 0 | return SF_FALSE ; |
408 | | |
409 | 0 | for (k = 0 ; k < psf->sf.channels ; k++) |
410 | 0 | peaks [k] = psf->peak_info->peaks [k].value ; |
411 | |
|
412 | 0 | return SF_TRUE ; |
413 | 0 | } /* psf_get_max_all_channels */ |
414 | | |
415 | | |