1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <audio_utils/sndfile.h>
18 #include <audio_utils/primitives.h>
19 #ifdef HAVE_STDERR
20 #include <stdio.h>
21 #endif
22 #include <string.h>
23 #include <errno.h>
24
25 #define WAVE_FORMAT_PCM 1
26 #define WAVE_FORMAT_IEEE_FLOAT 3
27 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
28
29 struct SNDFILE_ {
30 int mode;
31 uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
32 FILE *stream;
33 size_t bytesPerFrame;
34 size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE
35 SF_INFO info;
36 };
37
little2u(unsigned char * ptr)38 static unsigned little2u(unsigned char *ptr)
39 {
40 return (ptr[1] << 8) + ptr[0];
41 }
42
little4u(unsigned char * ptr)43 static unsigned little4u(unsigned char *ptr)
44 {
45 return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
46 }
47
isLittleEndian(void)48 static int isLittleEndian(void)
49 {
50 static const short one = 1;
51 return *((const char *) &one) == 1;
52 }
53
54 // "swab" conflicts with OS X <string.h>
my_swab(short * ptr,size_t numToSwap)55 static void my_swab(short *ptr, size_t numToSwap)
56 {
57 while (numToSwap > 0) {
58 *ptr = little2u((unsigned char *) ptr);
59 --numToSwap;
60 ++ptr;
61 }
62 }
63
sf_open_read(const char * path,SF_INFO * info)64 static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
65 {
66 FILE *stream = fopen(path, "rb");
67 if (stream == NULL) {
68 #ifdef HAVE_STDERR
69 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
70 #endif
71 return NULL;
72 }
73
74 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
75 handle->mode = SFM_READ;
76 handle->temp = NULL;
77 handle->stream = stream;
78 handle->info.format = SF_FORMAT_WAV;
79
80 // don't attempt to parse all valid forms, just the most common ones
81 unsigned char wav[12];
82 size_t actual;
83 actual = fread(wav, sizeof(char), sizeof(wav), stream);
84 if (actual < 12) {
85 #ifdef HAVE_STDERR
86 fprintf(stderr, "actual %zu < 44\n", actual);
87 #endif
88 goto close;
89 }
90 if (memcmp(wav, "RIFF", 4)) {
91 #ifdef HAVE_STDERR
92 fprintf(stderr, "wav != RIFF\n");
93 #endif
94 goto close;
95 }
96 unsigned riffSize = little4u(&wav[4]);
97 if (riffSize < 4) {
98 #ifdef HAVE_STDERR
99 fprintf(stderr, "riffSize %u < 4\n", riffSize);
100 #endif
101 goto close;
102 }
103 if (memcmp(&wav[8], "WAVE", 4)) {
104 #ifdef HAVE_STDERR
105 fprintf(stderr, "missing WAVE\n");
106 #endif
107 goto close;
108 }
109 size_t remaining = riffSize - 4;
110 int hadFmt = 0;
111 int hadData = 0;
112 long dataTell = 0L;
113 while (remaining >= 8) {
114 unsigned char chunk[8];
115 actual = fread(chunk, sizeof(char), sizeof(chunk), stream);
116 if (actual != sizeof(chunk)) {
117 #ifdef HAVE_STDERR
118 fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
119 #endif
120 goto close;
121 }
122 remaining -= 8;
123 unsigned chunkSize = little4u(&chunk[4]);
124 if (chunkSize > remaining) {
125 #ifdef HAVE_STDERR
126 fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
127 #endif
128 goto close;
129 }
130 if (!memcmp(&chunk[0], "fmt ", 4)) {
131 if (hadFmt) {
132 #ifdef HAVE_STDERR
133 fprintf(stderr, "multiple fmt\n");
134 #endif
135 goto close;
136 }
137 if (chunkSize < 2) {
138 #ifdef HAVE_STDERR
139 fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
140 #endif
141 goto close;
142 }
143 unsigned char fmt[40];
144 actual = fread(fmt, sizeof(char), 2, stream);
145 if (actual != 2) {
146 #ifdef HAVE_STDERR
147 fprintf(stderr, "actual %zu != 2\n", actual);
148 #endif
149 goto close;
150 }
151 unsigned format = little2u(&fmt[0]);
152 size_t minSize = 0;
153 switch (format) {
154 case WAVE_FORMAT_PCM:
155 case WAVE_FORMAT_IEEE_FLOAT:
156 minSize = 16;
157 break;
158 case WAVE_FORMAT_EXTENSIBLE:
159 minSize = 40;
160 break;
161 default:
162 #ifdef HAVE_STDERR
163 fprintf(stderr, "unsupported format %u\n", format);
164 #endif
165 goto close;
166 }
167 if (chunkSize < minSize) {
168 #ifdef HAVE_STDERR
169 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
170 #endif
171 goto close;
172 }
173 actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
174 if (actual != minSize - 2) {
175 #ifdef HAVE_STDERR
176 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
177 #endif
178 goto close;
179 }
180 if (chunkSize > minSize) {
181 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
182 }
183 unsigned channels = little2u(&fmt[2]);
184 // FIXME FCC_8
185 if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
186 #ifdef HAVE_STDERR
187 fprintf(stderr, "unsupported channels %u\n", channels);
188 #endif
189 goto close;
190 }
191 unsigned samplerate = little4u(&fmt[4]);
192 if (samplerate == 0) {
193 #ifdef HAVE_STDERR
194 fprintf(stderr, "samplerate %u == 0\n", samplerate);
195 #endif
196 goto close;
197 }
198 // ignore byte rate
199 // ignore block alignment
200 unsigned bitsPerSample = little2u(&fmt[14]);
201 if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 &&
202 bitsPerSample != 32) {
203 #ifdef HAVE_STDERR
204 fprintf(stderr, "bitsPerSample %u != 8 or 16 or 24 or 32\n", bitsPerSample);
205 #endif
206 goto close;
207 }
208 unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
209 handle->bytesPerFrame = bytesPerFrame;
210 handle->info.samplerate = samplerate;
211 handle->info.channels = channels;
212 switch (bitsPerSample) {
213 case 8:
214 handle->info.format |= SF_FORMAT_PCM_U8;
215 break;
216 case 16:
217 handle->info.format |= SF_FORMAT_PCM_16;
218 break;
219 case 24:
220 handle->info.format |= SF_FORMAT_PCM_24;
221 break;
222 case 32:
223 if (format == WAVE_FORMAT_IEEE_FLOAT)
224 handle->info.format |= SF_FORMAT_FLOAT;
225 else
226 handle->info.format |= SF_FORMAT_PCM_32;
227 break;
228 }
229 hadFmt = 1;
230 } else if (!memcmp(&chunk[0], "data", 4)) {
231 if (!hadFmt) {
232 #ifdef HAVE_STDERR
233 fprintf(stderr, "data not preceded by fmt\n");
234 #endif
235 goto close;
236 }
237 if (hadData) {
238 #ifdef HAVE_STDERR
239 fprintf(stderr, "multiple data\n");
240 #endif
241 goto close;
242 }
243 handle->remaining = chunkSize / handle->bytesPerFrame;
244 handle->info.frames = handle->remaining;
245 dataTell = ftell(stream);
246 if (chunkSize > 0) {
247 fseek(stream, (long) chunkSize, SEEK_CUR);
248 }
249 hadData = 1;
250 } else if (!memcmp(&chunk[0], "fact", 4)) {
251 // ignore fact
252 if (chunkSize > 0) {
253 fseek(stream, (long) chunkSize, SEEK_CUR);
254 }
255 } else {
256 // ignore unknown chunk
257 #ifdef HAVE_STDERR
258 fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
259 chunk[0], chunk[1], chunk[2], chunk[3]);
260 #endif
261 if (chunkSize > 0) {
262 fseek(stream, (long) chunkSize, SEEK_CUR);
263 }
264 }
265 remaining -= chunkSize;
266 }
267 if (remaining > 0) {
268 #ifdef HAVE_STDERR
269 fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
270 #endif
271 goto close;
272 }
273 if (!hadData) {
274 #ifdef HAVE_STDERR
275 fprintf(stderr, "missing data\n");
276 #endif
277 goto close;
278 }
279 (void) fseek(stream, dataTell, SEEK_SET);
280 *info = handle->info;
281 return handle;
282
283 close:
284 free(handle);
285 fclose(stream);
286 return NULL;
287 }
288
write4u(unsigned char * ptr,unsigned u)289 static void write4u(unsigned char *ptr, unsigned u)
290 {
291 ptr[0] = u;
292 ptr[1] = u >> 8;
293 ptr[2] = u >> 16;
294 ptr[3] = u >> 24;
295 }
296
sf_open_write(const char * path,SF_INFO * info)297 static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
298 {
299 int sub = info->format & SF_FORMAT_SUBMASK;
300 if (!(
301 (info->samplerate > 0) &&
302 // FIXME FCC_8
303 (info->channels > 0 && info->channels <= 8) &&
304 ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
305 (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT ||
306 sub == SF_FORMAT_PCM_24 || sub == SF_FORMAT_PCM_32)
307 )) {
308 return NULL;
309 }
310 FILE *stream = fopen(path, "w+b");
311 if (stream == NULL) {
312 #ifdef HAVE_STDERR
313 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
314 #endif
315 return NULL;
316 }
317 unsigned char wav[58];
318 memset(wav, 0, sizeof(wav));
319 memcpy(wav, "RIFF", 4);
320 memcpy(&wav[8], "WAVEfmt ", 8);
321 if (sub == SF_FORMAT_FLOAT) {
322 wav[4] = 50; // riffSize
323 wav[16] = 18; // fmtSize
324 wav[20] = WAVE_FORMAT_IEEE_FLOAT;
325 } else {
326 wav[4] = 36; // riffSize
327 wav[16] = 16; // fmtSize
328 wav[20] = WAVE_FORMAT_PCM;
329 }
330 wav[22] = info->channels;
331 write4u(&wav[24], info->samplerate);
332 unsigned bitsPerSample;
333 switch (sub) {
334 case SF_FORMAT_PCM_16:
335 bitsPerSample = 16;
336 break;
337 case SF_FORMAT_PCM_U8:
338 bitsPerSample = 8;
339 break;
340 case SF_FORMAT_FLOAT:
341 bitsPerSample = 32;
342 break;
343 case SF_FORMAT_PCM_24:
344 bitsPerSample = 24;
345 break;
346 case SF_FORMAT_PCM_32:
347 bitsPerSample = 32;
348 break;
349 default: // not reachable
350 bitsPerSample = 0;
351 break;
352 }
353 unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
354 unsigned byteRate = info->samplerate * blockAlignment;
355 write4u(&wav[28], byteRate);
356 wav[32] = blockAlignment;
357 wav[34] = bitsPerSample;
358 size_t extra = 0;
359 if (sub == SF_FORMAT_FLOAT) {
360 memcpy(&wav[38], "fact", 4);
361 wav[42] = 4;
362 memcpy(&wav[50], "data", 4);
363 extra = 14;
364 } else
365 memcpy(&wav[36], "data", 4);
366 // dataSize is initially zero
367 (void) fwrite(wav, 44 + extra, 1, stream);
368 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
369 handle->mode = SFM_WRITE;
370 handle->temp = NULL;
371 handle->stream = stream;
372 handle->bytesPerFrame = blockAlignment;
373 handle->remaining = 0;
374 handle->info = *info;
375 return handle;
376 }
377
sf_open(const char * path,int mode,SF_INFO * info)378 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
379 {
380 if (path == NULL || info == NULL) {
381 #ifdef HAVE_STDERR
382 fprintf(stderr, "path=%p info=%p\n", path, info);
383 #endif
384 return NULL;
385 }
386 switch (mode) {
387 case SFM_READ:
388 return sf_open_read(path, info);
389 case SFM_WRITE:
390 return sf_open_write(path, info);
391 default:
392 #ifdef HAVE_STDERR
393 fprintf(stderr, "mode=%d\n", mode);
394 #endif
395 return NULL;
396 }
397 }
398
sf_close(SNDFILE * handle)399 void sf_close(SNDFILE *handle)
400 {
401 if (handle == NULL)
402 return;
403 free(handle->temp);
404 if (handle->mode == SFM_WRITE) {
405 (void) fflush(handle->stream);
406 rewind(handle->stream);
407 unsigned char wav[58];
408 size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0;
409 (void) fread(wav, 44 + extra, 1, handle->stream);
410 unsigned dataSize = handle->remaining * handle->bytesPerFrame;
411 write4u(&wav[4], dataSize + 36 + extra); // riffSize
412 write4u(&wav[40 + extra], dataSize); // dataSize
413 rewind(handle->stream);
414 (void) fwrite(wav, 44 + extra, 1, handle->stream);
415 }
416 (void) fclose(handle->stream);
417 free(handle);
418 }
419
sf_readf_short(SNDFILE * handle,short * ptr,sf_count_t desiredFrames)420 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
421 {
422 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
423 desiredFrames <= 0) {
424 return 0;
425 }
426 if (handle->remaining < (size_t) desiredFrames) {
427 desiredFrames = handle->remaining;
428 }
429 // does not check for numeric overflow
430 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
431 size_t actualBytes;
432 void *temp = NULL;
433 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
434 if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT || format == SF_FORMAT_PCM_24) {
435 temp = malloc(desiredBytes);
436 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
437 } else {
438 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
439 }
440 size_t actualFrames = actualBytes / handle->bytesPerFrame;
441 handle->remaining -= actualFrames;
442 switch (format) {
443 case SF_FORMAT_PCM_U8:
444 memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
445 break;
446 case SF_FORMAT_PCM_16:
447 if (!isLittleEndian())
448 my_swab(ptr, actualFrames * handle->info.channels);
449 break;
450 case SF_FORMAT_PCM_32:
451 memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
452 free(temp);
453 break;
454 case SF_FORMAT_FLOAT:
455 memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
456 free(temp);
457 break;
458 case SF_FORMAT_PCM_24:
459 memcpy_to_i16_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
460 free(temp);
461 break;
462 default:
463 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
464 break;
465 }
466 return actualFrames;
467 }
468
sf_readf_float(SNDFILE * handle,float * ptr,sf_count_t desiredFrames)469 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
470 {
471 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
472 desiredFrames <= 0) {
473 return 0;
474 }
475 if (handle->remaining < (size_t) desiredFrames) {
476 desiredFrames = handle->remaining;
477 }
478 // does not check for numeric overflow
479 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
480 size_t actualBytes;
481 void *temp = NULL;
482 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
483 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) {
484 temp = malloc(desiredBytes);
485 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
486 } else {
487 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
488 }
489 size_t actualFrames = actualBytes / handle->bytesPerFrame;
490 handle->remaining -= actualFrames;
491 switch (format) {
492 case SF_FORMAT_PCM_U8:
493 #if 0
494 // TODO - implement
495 memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
496 actualFrames * handle->info.channels);
497 #endif
498 free(temp);
499 break;
500 case SF_FORMAT_PCM_16:
501 memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
502 free(temp);
503 break;
504 case SF_FORMAT_PCM_32:
505 memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
506 break;
507 case SF_FORMAT_FLOAT:
508 break;
509 case SF_FORMAT_PCM_24:
510 memcpy_to_float_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
511 free(temp);
512 break;
513 default:
514 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
515 break;
516 }
517 return actualFrames;
518 }
519
sf_readf_int(SNDFILE * handle,int * ptr,sf_count_t desiredFrames)520 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
521 {
522 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
523 desiredFrames <= 0) {
524 return 0;
525 }
526 if (handle->remaining < (size_t) desiredFrames) {
527 desiredFrames = handle->remaining;
528 }
529 // does not check for numeric overflow
530 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
531 void *temp = NULL;
532 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
533 size_t actualBytes;
534 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8 || format == SF_FORMAT_PCM_24) {
535 temp = malloc(desiredBytes);
536 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
537 } else {
538 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
539 }
540 size_t actualFrames = actualBytes / handle->bytesPerFrame;
541 handle->remaining -= actualFrames;
542 switch (format) {
543 case SF_FORMAT_PCM_U8:
544 #if 0
545 // TODO - implement
546 memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
547 actualFrames * handle->info.channels);
548 #endif
549 free(temp);
550 break;
551 case SF_FORMAT_PCM_16:
552 memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
553 free(temp);
554 break;
555 case SF_FORMAT_PCM_32:
556 break;
557 case SF_FORMAT_FLOAT:
558 memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
559 break;
560 case SF_FORMAT_PCM_24:
561 memcpy_to_i32_from_p24(ptr, (const uint8_t *) temp, actualFrames * handle->info.channels);
562 free(temp);
563 break;
564 default:
565 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
566 break;
567 }
568 return actualFrames;
569 }
570
sf_writef_short(SNDFILE * handle,const short * ptr,sf_count_t desiredFrames)571 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
572 {
573 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
574 return 0;
575 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
576 size_t actualBytes = 0;
577 switch (handle->info.format & SF_FORMAT_SUBMASK) {
578 case SF_FORMAT_PCM_U8:
579 handle->temp = realloc(handle->temp, desiredBytes);
580 memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
581 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
582 break;
583 case SF_FORMAT_PCM_16:
584 // does not check for numeric overflow
585 if (isLittleEndian()) {
586 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
587 } else {
588 handle->temp = realloc(handle->temp, desiredBytes);
589 memcpy(handle->temp, ptr, desiredBytes);
590 my_swab((short *) handle->temp, desiredFrames * handle->info.channels);
591 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
592 }
593 break;
594 case SF_FORMAT_FLOAT:
595 handle->temp = realloc(handle->temp, desiredBytes);
596 memcpy_to_float_from_i16((float *) handle->temp, ptr,
597 desiredFrames * handle->info.channels);
598 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
599 break;
600 default:
601 break;
602 }
603 size_t actualFrames = actualBytes / handle->bytesPerFrame;
604 handle->remaining += actualFrames;
605 return actualFrames;
606 }
607
sf_writef_float(SNDFILE * handle,const float * ptr,sf_count_t desiredFrames)608 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
609 {
610 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
611 return 0;
612 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
613 size_t actualBytes = 0;
614 switch (handle->info.format & SF_FORMAT_SUBMASK) {
615 case SF_FORMAT_FLOAT:
616 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
617 break;
618 case SF_FORMAT_PCM_16:
619 handle->temp = realloc(handle->temp, desiredBytes);
620 memcpy_to_i16_from_float((short *) handle->temp, ptr,
621 desiredFrames * handle->info.channels);
622 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
623 break;
624 case SF_FORMAT_PCM_U8: // transcoding from float to byte not yet implemented
625 default:
626 break;
627 }
628 size_t actualFrames = actualBytes / handle->bytesPerFrame;
629 handle->remaining += actualFrames;
630 return actualFrames;
631 }
632
sf_writef_int(SNDFILE * handle,const int * ptr,sf_count_t desiredFrames)633 sf_count_t sf_writef_int(SNDFILE *handle, const int *ptr, sf_count_t desiredFrames)
634 {
635 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
636 return 0;
637 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
638 size_t actualBytes = 0;
639 switch (handle->info.format & SF_FORMAT_SUBMASK) {
640 case SF_FORMAT_PCM_32:
641 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
642 break;
643 default: // transcoding from other formats not yet implemented
644 break;
645 }
646 size_t actualFrames = actualBytes / handle->bytesPerFrame;
647 handle->remaining += actualFrames;
648 return actualFrames;
649 }
650