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