blob: 4843986a5ae39034e3570a6ea12e274d15e81022 [file] [log] [blame]
Glenn Kasten207ec292012-10-30 16:09:18 -07001/*
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>
Glenn Kasten36c248b2012-11-12 14:42:31 -080018#include <audio_utils/primitives.h>
Glenn Kasten207ec292012-10-30 16:09:18 -070019#include <stdio.h>
20#include <string.h>
Glenn Kastenc0bd7152013-02-05 13:14:08 -080021#include <errno.h>
22
23#define WAVE_FORMAT_PCM 1
24#define WAVE_FORMAT_IEEE_FLOAT 3
25#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
Glenn Kasten207ec292012-10-30 16:09:18 -070026
27struct SNDFILE_ {
Glenn Kasteneae13dd2013-01-04 11:24:55 -080028 int mode;
29 uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
Glenn Kasten207ec292012-10-30 16:09:18 -070030 FILE *stream;
31 size_t bytesPerFrame;
Glenn Kasteneae13dd2013-01-04 11:24:55 -080032 size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE
Glenn Kasten207ec292012-10-30 16:09:18 -070033 SF_INFO info;
34};
35
36static unsigned little2u(unsigned char *ptr)
37{
38 return (ptr[1] << 8) + ptr[0];
39}
40
41static unsigned little4u(unsigned char *ptr)
42{
43 return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
44}
45
46static int isLittleEndian(void)
47{
48 static const short one = 1;
49 return *((const char *) &one) == 1;
50}
51
Glenn Kasten8fdafc92013-02-12 16:23:42 -080052// "swab" conflicts with OS X <string.h>
53static void my_swab(short *ptr, size_t numToSwap)
Glenn Kasten207ec292012-10-30 16:09:18 -070054{
55 while (numToSwap > 0) {
56 *ptr = little2u((unsigned char *) ptr);
57 --numToSwap;
58 ++ptr;
59 }
60}
61
Glenn Kasteneae13dd2013-01-04 11:24:55 -080062static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
Glenn Kasten207ec292012-10-30 16:09:18 -070063{
Glenn Kasten207ec292012-10-30 16:09:18 -070064 FILE *stream = fopen(path, "rb");
Glenn Kastenc0bd7152013-02-05 13:14:08 -080065 if (stream == NULL) {
66 fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
Glenn Kasten207ec292012-10-30 16:09:18 -070067 return NULL;
Glenn Kastenc0bd7152013-02-05 13:14:08 -080068 }
69
70 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
71 handle->mode = SFM_READ;
72 handle->temp = NULL;
73 handle->stream = stream;
74 handle->info.format = SF_FORMAT_WAV;
75
76 // don't attempt to parse all valid forms, just the most common ones
77 unsigned char wav[12];
Glenn Kasten207ec292012-10-30 16:09:18 -070078 size_t actual;
79 actual = fread(wav, sizeof(char), sizeof(wav), stream);
Glenn Kastenc0bd7152013-02-05 13:14:08 -080080 if (actual < 12) {
Kévin PETIT96d859c2014-03-26 11:56:32 +000081 fprintf(stderr, "actual %zu < 44\n", actual);
Glenn Kastenc0bd7152013-02-05 13:14:08 -080082 goto close;
Glenn Kasten207ec292012-10-30 16:09:18 -070083 }
Glenn Kastenc0bd7152013-02-05 13:14:08 -080084 if (memcmp(wav, "RIFF", 4)) {
85 fprintf(stderr, "wav != RIFF\n");
86 goto close;
87 }
88 unsigned riffSize = little4u(&wav[4]);
89 if (riffSize < 4) {
90 fprintf(stderr, "riffSize %u < 4\n", riffSize);
91 goto close;
92 }
93 if (memcmp(&wav[8], "WAVE", 4)) {
94 fprintf(stderr, "missing WAVE\n");
95 goto close;
96 }
97 size_t remaining = riffSize - 4;
98 int hadFmt = 0;
99 int hadData = 0;
100 while (remaining >= 8) {
101 unsigned char chunk[8];
102 actual = fread(chunk, sizeof(char), sizeof(chunk), stream);
103 if (actual != sizeof(chunk)) {
Kévin PETIT96d859c2014-03-26 11:56:32 +0000104 fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800105 goto close;
106 }
107 remaining -= 8;
108 unsigned chunkSize = little4u(&chunk[4]);
109 if (chunkSize > remaining) {
Kévin PETIT96d859c2014-03-26 11:56:32 +0000110 fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800111 goto close;
112 }
113 if (!memcmp(&chunk[0], "fmt ", 4)) {
114 if (hadFmt) {
115 fprintf(stderr, "multiple fmt\n");
116 goto close;
117 }
118 if (chunkSize < 2) {
119 fprintf(stderr, "chunkSize %u < 2\n", chunkSize);
120 goto close;
121 }
122 unsigned char fmt[40];
123 actual = fread(fmt, sizeof(char), 2, stream);
124 if (actual != 2) {
Kévin PETIT96d859c2014-03-26 11:56:32 +0000125 fprintf(stderr, "actual %zu != 2\n", actual);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800126 goto close;
127 }
128 unsigned format = little2u(&fmt[0]);
129 size_t minSize = 0;
130 switch (format) {
131 case WAVE_FORMAT_PCM:
132 case WAVE_FORMAT_IEEE_FLOAT:
133 minSize = 16;
134 break;
135 case WAVE_FORMAT_EXTENSIBLE:
136 minSize = 40;
137 break;
138 default:
139 fprintf(stderr, "unsupported format %u\n", format);
140 goto close;
141 }
142 if (chunkSize < minSize) {
Kévin PETIT96d859c2014-03-26 11:56:32 +0000143 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800144 goto close;
145 }
146 actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
147 if (actual != minSize - 2) {
Kévin PETIT96d859c2014-03-26 11:56:32 +0000148 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800149 goto close;
150 }
151 if (chunkSize > minSize) {
152 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
153 }
154 unsigned channels = little2u(&fmt[2]);
Glenn Kasten7c1930a2014-05-07 11:20:55 -0700155 if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
156 fprintf(stderr, "unsupported channels %u\n", channels);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800157 goto close;
158 }
159 unsigned samplerate = little4u(&fmt[4]);
160 if (samplerate == 0) {
161 fprintf(stderr, "samplerate %u == 0\n", samplerate);
162 goto close;
163 }
164 // ignore byte rate
165 // ignore block alignment
166 unsigned bitsPerSample = little2u(&fmt[14]);
167 if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) {
168 fprintf(stderr, "bitsPerSample %u != 8 or 16 or 32\n", bitsPerSample);
169 goto close;
170 }
171 unsigned bytesPerFrame = (bitsPerSample >> 3) * channels;
172 handle->bytesPerFrame = bytesPerFrame;
173 handle->info.samplerate = samplerate;
174 handle->info.channels = channels;
175 switch (bitsPerSample) {
176 case 8:
177 handle->info.format |= SF_FORMAT_PCM_U8;
178 break;
179 case 16:
180 handle->info.format |= SF_FORMAT_PCM_16;
181 break;
182 case 32:
183 if (format == WAVE_FORMAT_IEEE_FLOAT)
184 handle->info.format |= SF_FORMAT_FLOAT;
185 else
186 handle->info.format |= SF_FORMAT_PCM_32;
187 break;
188 }
189 hadFmt = 1;
190 } else if (!memcmp(&chunk[0], "data", 4)) {
191 if (!hadFmt) {
192 fprintf(stderr, "data not preceded by fmt\n");
193 goto close;
194 }
195 if (hadData) {
196 fprintf(stderr, "multiple data\n");
197 goto close;
198 }
199 handle->remaining = chunkSize / handle->bytesPerFrame;
200 handle->info.frames = handle->remaining;
201 hadData = 1;
202 } else if (!memcmp(&chunk[0], "fact", 4)) {
203 // ignore fact
204 if (chunkSize > 0) {
205 fseek(stream, (long) chunkSize, SEEK_CUR);
206 }
207 } else {
208 // ignore unknown chunk
209 fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n",
210 chunk[0], chunk[1], chunk[2], chunk[3]);
211 if (chunkSize > 0) {
212 fseek(stream, (long) chunkSize, SEEK_CUR);
213 }
214 }
215 remaining -= chunkSize;
216 }
217 if (remaining > 0) {
Kévin PETIT96d859c2014-03-26 11:56:32 +0000218 fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800219 goto close;
220 }
221 if (!hadData) {
222 fprintf(stderr, "missing data\n");
223 goto close;
224 }
225 *info = handle->info;
226 return handle;
227
228close:
229 free(handle);
230 fclose(stream);
Glenn Kasten207ec292012-10-30 16:09:18 -0700231 return NULL;
232}
233
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800234static void write4u(unsigned char *ptr, unsigned u)
235{
236 ptr[0] = u;
237 ptr[1] = u >> 8;
238 ptr[2] = u >> 16;
239 ptr[3] = u >> 24;
240}
241
242static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
243{
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800244 int sub = info->format & SF_FORMAT_SUBMASK;
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800245 if (!(
246 (info->samplerate > 0) &&
Andy Hung7095bc72014-04-09 18:52:06 -0700247 (info->channels > 0 && info->channels <= 8) &&
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800248 ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800249 (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT)
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800250 )) {
251 return NULL;
252 }
253 FILE *stream = fopen(path, "w+b");
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800254 unsigned char wav[58];
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800255 memset(wav, 0, sizeof(wav));
256 memcpy(wav, "RIFF", 4);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800257 memcpy(&wav[8], "WAVEfmt ", 8);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800258 if (sub == SF_FORMAT_FLOAT) {
259 wav[4] = 50; // riffSize
260 wav[16] = 18; // fmtSize
261 wav[20] = WAVE_FORMAT_IEEE_FLOAT;
262 } else {
263 wav[4] = 36; // riffSize
264 wav[16] = 16; // fmtSize
265 wav[20] = WAVE_FORMAT_PCM;
266 }
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800267 wav[22] = info->channels;
268 write4u(&wav[24], info->samplerate);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800269 unsigned bitsPerSample;
270 switch (sub) {
271 case SF_FORMAT_PCM_16:
272 bitsPerSample = 16;
273 break;
274 case SF_FORMAT_PCM_U8:
275 bitsPerSample = 8;
276 break;
277 case SF_FORMAT_FLOAT:
278 bitsPerSample = 32;
279 break;
280 default: // not reachable
281 bitsPerSample = 0;
282 break;
283 }
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800284 unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
285 unsigned byteRate = info->samplerate * blockAlignment;
286 write4u(&wav[28], byteRate);
287 wav[32] = blockAlignment;
288 wav[34] = bitsPerSample;
Andy Hungc74f4b72014-06-03 19:15:18 -0700289 size_t extra = 0;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800290 if (sub == SF_FORMAT_FLOAT) {
291 memcpy(&wav[38], "fact", 4);
292 wav[42] = 4;
293 memcpy(&wav[50], "data", 4);
Andy Hungc74f4b72014-06-03 19:15:18 -0700294 extra = 14;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800295 } else
296 memcpy(&wav[36], "data", 4);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800297 // dataSize is initially zero
Andy Hungc74f4b72014-06-03 19:15:18 -0700298 (void) fwrite(wav, 44 + extra, 1, stream);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800299 SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
300 handle->mode = SFM_WRITE;
301 handle->temp = NULL;
302 handle->stream = stream;
303 handle->bytesPerFrame = blockAlignment;
304 handle->remaining = 0;
305 handle->info = *info;
306 return handle;
307}
308
309SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
310{
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800311 if (path == NULL || info == NULL) {
312 fprintf(stderr, "path=%p info=%p\n", path, info);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800313 return NULL;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800314 }
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800315 switch (mode) {
316 case SFM_READ:
317 return sf_open_read(path, info);
318 case SFM_WRITE:
319 return sf_open_write(path, info);
320 default:
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800321 fprintf(stderr, "mode=%d\n", mode);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800322 return NULL;
323 }
324}
325
Glenn Kasten207ec292012-10-30 16:09:18 -0700326void sf_close(SNDFILE *handle)
327{
328 if (handle == NULL)
329 return;
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800330 free(handle->temp);
331 if (handle->mode == SFM_WRITE) {
332 (void) fflush(handle->stream);
333 rewind(handle->stream);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800334 unsigned char wav[58];
335 size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0;
336 (void) fread(wav, 44 + extra, 1, handle->stream);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800337 unsigned dataSize = handle->remaining * handle->bytesPerFrame;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800338 write4u(&wav[4], dataSize + 36 + extra); // riffSize
339 write4u(&wav[40 + extra], dataSize); // dataSize
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800340 rewind(handle->stream);
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800341 (void) fwrite(wav, 44 + extra, 1, handle->stream);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800342 }
Glenn Kasten207ec292012-10-30 16:09:18 -0700343 (void) fclose(handle->stream);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800344 free(handle);
Glenn Kasten207ec292012-10-30 16:09:18 -0700345}
346
Glenn Kasten36c248b2012-11-12 14:42:31 -0800347sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
Glenn Kasten207ec292012-10-30 16:09:18 -0700348{
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800349 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
350 desiredFrames <= 0) {
Glenn Kasten207ec292012-10-30 16:09:18 -0700351 return 0;
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800352 }
Glenn Kastenc89cb602014-03-11 09:03:35 -0700353 if (handle->remaining < (size_t) desiredFrames) {
Glenn Kasten207ec292012-10-30 16:09:18 -0700354 desiredFrames = handle->remaining;
Glenn Kastenc89cb602014-03-11 09:03:35 -0700355 }
Glenn Kasten207ec292012-10-30 16:09:18 -0700356 // does not check for numeric overflow
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800357 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
358 size_t actualBytes;
359 void *temp = NULL;
360 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
361 if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) {
362 temp = malloc(desiredBytes);
363 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
364 } else {
365 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
366 }
Glenn Kasten207ec292012-10-30 16:09:18 -0700367 size_t actualFrames = actualBytes / handle->bytesPerFrame;
368 handle->remaining -= actualFrames;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800369 switch (format) {
Glenn Kasten36c248b2012-11-12 14:42:31 -0800370 case SF_FORMAT_PCM_U8:
371 memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
372 break;
373 case SF_FORMAT_PCM_16:
374 if (!isLittleEndian())
Glenn Kasten8fdafc92013-02-12 16:23:42 -0800375 my_swab(ptr, actualFrames * handle->info.channels);
Glenn Kasten36c248b2012-11-12 14:42:31 -0800376 break;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800377 case SF_FORMAT_PCM_32:
378 memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
379 free(temp);
380 break;
381 case SF_FORMAT_FLOAT:
382 memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
383 free(temp);
384 break;
385 default:
386 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
387 break;
Glenn Kasten36c248b2012-11-12 14:42:31 -0800388 }
Glenn Kasten207ec292012-10-30 16:09:18 -0700389 return actualFrames;
390}
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800391
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800392sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
393{
Glenn Kastenc89cb602014-03-11 09:03:35 -0700394 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
395 desiredFrames <= 0) {
396 return 0;
397 }
398 if (handle->remaining < (size_t) desiredFrames) {
399 desiredFrames = handle->remaining;
400 }
401 // does not check for numeric overflow
402 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
403 size_t actualBytes;
Andy Hung52370162014-05-22 18:17:53 -0700404 void *temp = NULL;
Glenn Kastenc89cb602014-03-11 09:03:35 -0700405 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
Andy Hung52370162014-05-22 18:17:53 -0700406 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
407 temp = malloc(desiredBytes);
408 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
409 } else {
410 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
411 }
Glenn Kastenc89cb602014-03-11 09:03:35 -0700412 size_t actualFrames = actualBytes / handle->bytesPerFrame;
413 handle->remaining -= actualFrames;
414 switch (format) {
Glenn Kastenc89cb602014-03-11 09:03:35 -0700415 case SF_FORMAT_PCM_U8:
Glenn Kastenc89cb602014-03-11 09:03:35 -0700416#if 0
Andy Hung52370162014-05-22 18:17:53 -0700417 // TODO - implement
418 memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
419 actualFrames * handle->info.channels);
420#endif
421 free(temp);
422 break;
423 case SF_FORMAT_PCM_16:
424 memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
425 free(temp);
426 break;
Glenn Kastenc89cb602014-03-11 09:03:35 -0700427 case SF_FORMAT_PCM_32:
428 memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
429 break;
Glenn Kastenc89cb602014-03-11 09:03:35 -0700430 case SF_FORMAT_FLOAT:
431 break;
432 default:
433 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
434 break;
435 }
436 return actualFrames;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800437}
438
Andy Hung7b937812014-05-22 18:26:07 -0700439sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
440{
441 if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
442 desiredFrames <= 0) {
443 return 0;
444 }
445 if (handle->remaining < (size_t) desiredFrames) {
446 desiredFrames = handle->remaining;
447 }
448 // does not check for numeric overflow
449 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
450 void *temp = NULL;
451 unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
452 size_t actualBytes;
453 if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
454 temp = malloc(desiredBytes);
455 actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
456 } else {
457 actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
458 }
459 size_t actualFrames = actualBytes / handle->bytesPerFrame;
460 handle->remaining -= actualFrames;
461 switch (format) {
462 case SF_FORMAT_PCM_U8:
463#if 0
464 // TODO - implement
465 memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
466 actualFrames * handle->info.channels);
467#endif
468 free(temp);
469 break;
470 case SF_FORMAT_PCM_16:
471 memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
472 free(temp);
473 break;
474 case SF_FORMAT_PCM_32:
475 break;
476 case SF_FORMAT_FLOAT:
477 memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
478 break;
479 default:
480 memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
481 break;
482 }
483 return actualFrames;
484}
485
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800486sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
487{
488 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
489 return 0;
490 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
491 size_t actualBytes = 0;
492 switch (handle->info.format & SF_FORMAT_SUBMASK) {
493 case SF_FORMAT_PCM_U8:
494 handle->temp = realloc(handle->temp, desiredBytes);
495 memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
496 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
497 break;
498 case SF_FORMAT_PCM_16:
499 // does not check for numeric overflow
500 if (isLittleEndian()) {
501 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
502 } else {
503 handle->temp = realloc(handle->temp, desiredBytes);
504 memcpy(handle->temp, ptr, desiredBytes);
Glenn Kasten8fdafc92013-02-12 16:23:42 -0800505 my_swab((short *) handle->temp, desiredFrames * handle->info.channels);
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800506 actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
507 }
508 break;
Glenn Kastenc0bd7152013-02-05 13:14:08 -0800509 case SF_FORMAT_FLOAT: // transcoding from short to float not yet implemented
510 default:
511 break;
512 }
513 size_t actualFrames = actualBytes / handle->bytesPerFrame;
514 handle->remaining += actualFrames;
515 return actualFrames;
516}
517
518sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
519{
520 if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
521 return 0;
522 size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
523 size_t actualBytes = 0;
524 switch (handle->info.format & SF_FORMAT_SUBMASK) {
525 case SF_FORMAT_FLOAT:
526 actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
527 break;
528 case SF_FORMAT_PCM_U8: // transcoding from float to byte/short not yet implemented
529 case SF_FORMAT_PCM_16:
530 default:
531 break;
Glenn Kasteneae13dd2013-01-04 11:24:55 -0800532 }
533 size_t actualFrames = actualBytes / handle->bytesPerFrame;
534 handle->remaining += actualFrames;
535 return actualFrames;
536}