Home | History | Annotate | Download | only in audio_utils
      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 #include <stdio.h>
     20 #include <string.h>
     21 #include <errno.h>
     22 
     23 #define WAVE_FORMAT_PCM         1
     24 #define WAVE_FORMAT_IEEE_FLOAT  3
     25 #define WAVE_FORMAT_EXTENSIBLE  0xFFFE
     26 
     27 struct SNDFILE_ {
     28     int mode;
     29     uint8_t *temp;  // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping
     30     FILE *stream;
     31     size_t bytesPerFrame;
     32     size_t remaining;   // frames unread for SFM_READ, frames written for SFM_WRITE
     33     SF_INFO info;
     34 };
     35 
     36 static unsigned little2u(unsigned char *ptr)
     37 {
     38     return (ptr[1] << 8) + ptr[0];
     39 }
     40 
     41 static unsigned little4u(unsigned char *ptr)
     42 {
     43     return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0];
     44 }
     45 
     46 static int isLittleEndian(void)
     47 {
     48     static const short one = 1;
     49     return *((const char *) &one) == 1;
     50 }
     51 
     52 // "swab" conflicts with OS X <string.h>
     53 static void my_swab(short *ptr, size_t numToSwap)
     54 {
     55     while (numToSwap > 0) {
     56         *ptr = little2u((unsigned char *) ptr);
     57         --numToSwap;
     58         ++ptr;
     59     }
     60 }
     61 
     62 static SNDFILE *sf_open_read(const char *path, SF_INFO *info)
     63 {
     64     FILE *stream = fopen(path, "rb");
     65     if (stream == NULL) {
     66         fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
     67         return NULL;
     68     }
     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];
     78     size_t actual;
     79     actual = fread(wav, sizeof(char), sizeof(wav), stream);
     80     if (actual < 12) {
     81         fprintf(stderr, "actual %zu < 44\n", actual);
     82         goto close;
     83     }
     84     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)) {
    104             fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk));
    105             goto close;
    106         }
    107         remaining -= 8;
    108         unsigned chunkSize = little4u(&chunk[4]);
    109         if (chunkSize > remaining) {
    110             fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining);
    111             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) {
    125                 fprintf(stderr, "actual %zu != 2\n", actual);
    126                 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) {
    143                 fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize);
    144                 goto close;
    145             }
    146             actual = fread(&fmt[2], sizeof(char), minSize - 2, stream);
    147             if (actual != minSize - 2) {
    148                 fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16);
    149                 goto close;
    150             }
    151             if (chunkSize > minSize) {
    152                 fseek(stream, (long) (chunkSize - minSize), SEEK_CUR);
    153             }
    154             unsigned channels = little2u(&fmt[2]);
    155             if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) {
    156                 fprintf(stderr, "unsupported channels %u\n", channels);
    157                 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) {
    218         fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining);
    219         goto close;
    220     }
    221     if (!hadData) {
    222         fprintf(stderr, "missing data\n");
    223         goto close;
    224     }
    225     *info = handle->info;
    226     return handle;
    227 
    228 close:
    229     free(handle);
    230     fclose(stream);
    231     return NULL;
    232 }
    233 
    234 static 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 
    242 static SNDFILE *sf_open_write(const char *path, SF_INFO *info)
    243 {
    244     int sub = info->format & SF_FORMAT_SUBMASK;
    245     if (!(
    246             (info->samplerate > 0) &&
    247             (info->channels > 0 && info->channels <= 8) &&
    248             ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) &&
    249             (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT)
    250           )) {
    251         return NULL;
    252     }
    253     FILE *stream = fopen(path, "w+b");
    254     if (stream == NULL) {
    255         fprintf(stderr, "fopen %s failed errno %d\n", path, errno);
    256         return NULL;
    257     }
    258     unsigned char wav[58];
    259     memset(wav, 0, sizeof(wav));
    260     memcpy(wav, "RIFF", 4);
    261     memcpy(&wav[8], "WAVEfmt ", 8);
    262     if (sub == SF_FORMAT_FLOAT) {
    263         wav[4] = 50;    // riffSize
    264         wav[16] = 18;   // fmtSize
    265         wav[20] = WAVE_FORMAT_IEEE_FLOAT;
    266     } else {
    267         wav[4] = 36;    // riffSize
    268         wav[16] = 16;   // fmtSize
    269         wav[20] = WAVE_FORMAT_PCM;
    270     }
    271     wav[22] = info->channels;
    272     write4u(&wav[24], info->samplerate);
    273     unsigned bitsPerSample;
    274     switch (sub) {
    275     case SF_FORMAT_PCM_16:
    276         bitsPerSample = 16;
    277         break;
    278     case SF_FORMAT_PCM_U8:
    279         bitsPerSample = 8;
    280         break;
    281     case SF_FORMAT_FLOAT:
    282         bitsPerSample = 32;
    283         break;
    284     default:    // not reachable
    285         bitsPerSample = 0;
    286         break;
    287     }
    288     unsigned blockAlignment = (bitsPerSample >> 3) * info->channels;
    289     unsigned byteRate = info->samplerate * blockAlignment;
    290     write4u(&wav[28], byteRate);
    291     wav[32] = blockAlignment;
    292     wav[34] = bitsPerSample;
    293     size_t extra = 0;
    294     if (sub == SF_FORMAT_FLOAT) {
    295         memcpy(&wav[38], "fact", 4);
    296         wav[42] = 4;
    297         memcpy(&wav[50], "data", 4);
    298         extra = 14;
    299     } else
    300         memcpy(&wav[36], "data", 4);
    301     // dataSize is initially zero
    302     (void) fwrite(wav, 44 + extra, 1, stream);
    303     SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE));
    304     handle->mode = SFM_WRITE;
    305     handle->temp = NULL;
    306     handle->stream = stream;
    307     handle->bytesPerFrame = blockAlignment;
    308     handle->remaining = 0;
    309     handle->info = *info;
    310     return handle;
    311 }
    312 
    313 SNDFILE *sf_open(const char *path, int mode, SF_INFO *info)
    314 {
    315     if (path == NULL || info == NULL) {
    316         fprintf(stderr, "path=%p info=%p\n", path, info);
    317         return NULL;
    318     }
    319     switch (mode) {
    320     case SFM_READ:
    321         return sf_open_read(path, info);
    322     case SFM_WRITE:
    323         return sf_open_write(path, info);
    324     default:
    325         fprintf(stderr, "mode=%d\n", mode);
    326         return NULL;
    327     }
    328 }
    329 
    330 void sf_close(SNDFILE *handle)
    331 {
    332     if (handle == NULL)
    333         return;
    334     free(handle->temp);
    335     if (handle->mode == SFM_WRITE) {
    336         (void) fflush(handle->stream);
    337         rewind(handle->stream);
    338         unsigned char wav[58];
    339         size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0;
    340         (void) fread(wav, 44 + extra, 1, handle->stream);
    341         unsigned dataSize = handle->remaining * handle->bytesPerFrame;
    342         write4u(&wav[4], dataSize + 36 + extra);    // riffSize
    343         write4u(&wav[40 + extra], dataSize);        // dataSize
    344         rewind(handle->stream);
    345         (void) fwrite(wav, 44 + extra, 1, handle->stream);
    346     }
    347     (void) fclose(handle->stream);
    348     free(handle);
    349 }
    350 
    351 sf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames)
    352 {
    353     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
    354             desiredFrames <= 0) {
    355         return 0;
    356     }
    357     if (handle->remaining < (size_t) desiredFrames) {
    358         desiredFrames = handle->remaining;
    359     }
    360     // does not check for numeric overflow
    361     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
    362     size_t actualBytes;
    363     void *temp = NULL;
    364     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
    365     if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) {
    366         temp = malloc(desiredBytes);
    367         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
    368     } else {
    369         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
    370     }
    371     size_t actualFrames = actualBytes / handle->bytesPerFrame;
    372     handle->remaining -= actualFrames;
    373     switch (format) {
    374     case SF_FORMAT_PCM_U8:
    375         memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels);
    376         break;
    377     case SF_FORMAT_PCM_16:
    378         if (!isLittleEndian())
    379             my_swab(ptr, actualFrames * handle->info.channels);
    380         break;
    381     case SF_FORMAT_PCM_32:
    382         memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels);
    383         free(temp);
    384         break;
    385     case SF_FORMAT_FLOAT:
    386         memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels);
    387         free(temp);
    388         break;
    389     default:
    390         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short));
    391         break;
    392     }
    393     return actualFrames;
    394 }
    395 
    396 sf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames)
    397 {
    398     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
    399             desiredFrames <= 0) {
    400         return 0;
    401     }
    402     if (handle->remaining < (size_t) desiredFrames) {
    403         desiredFrames = handle->remaining;
    404     }
    405     // does not check for numeric overflow
    406     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
    407     size_t actualBytes;
    408     void *temp = NULL;
    409     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
    410     if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
    411         temp = malloc(desiredBytes);
    412         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
    413     } else {
    414         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
    415     }
    416     size_t actualFrames = actualBytes / handle->bytesPerFrame;
    417     handle->remaining -= actualFrames;
    418     switch (format) {
    419     case SF_FORMAT_PCM_U8:
    420 #if 0
    421         // TODO - implement
    422         memcpy_to_float_from_u8(ptr, (const unsigned char *) temp,
    423                 actualFrames * handle->info.channels);
    424 #endif
    425         free(temp);
    426         break;
    427     case SF_FORMAT_PCM_16:
    428         memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
    429         free(temp);
    430         break;
    431     case SF_FORMAT_PCM_32:
    432         memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels);
    433         break;
    434     case SF_FORMAT_FLOAT:
    435         break;
    436     default:
    437         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float));
    438         break;
    439     }
    440     return actualFrames;
    441 }
    442 
    443 sf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames)
    444 {
    445     if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining ||
    446             desiredFrames <= 0) {
    447         return 0;
    448     }
    449     if (handle->remaining < (size_t) desiredFrames) {
    450         desiredFrames = handle->remaining;
    451     }
    452     // does not check for numeric overflow
    453     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
    454     void *temp = NULL;
    455     unsigned format = handle->info.format & SF_FORMAT_SUBMASK;
    456     size_t actualBytes;
    457     if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) {
    458         temp = malloc(desiredBytes);
    459         actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream);
    460     } else {
    461         actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream);
    462     }
    463     size_t actualFrames = actualBytes / handle->bytesPerFrame;
    464     handle->remaining -= actualFrames;
    465     switch (format) {
    466     case SF_FORMAT_PCM_U8:
    467 #if 0
    468         // TODO - implement
    469         memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp,
    470                 actualFrames * handle->info.channels);
    471 #endif
    472         free(temp);
    473         break;
    474     case SF_FORMAT_PCM_16:
    475         memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels);
    476         free(temp);
    477         break;
    478     case SF_FORMAT_PCM_32:
    479         break;
    480     case SF_FORMAT_FLOAT:
    481         memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels);
    482         break;
    483     default:
    484         memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int));
    485         break;
    486     }
    487     return actualFrames;
    488 }
    489 
    490 sf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames)
    491 {
    492     if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
    493         return 0;
    494     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
    495     size_t actualBytes = 0;
    496     switch (handle->info.format & SF_FORMAT_SUBMASK) {
    497     case SF_FORMAT_PCM_U8:
    498         handle->temp = realloc(handle->temp, desiredBytes);
    499         memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes);
    500         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
    501         break;
    502     case SF_FORMAT_PCM_16:
    503         // does not check for numeric overflow
    504         if (isLittleEndian()) {
    505             actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
    506         } else {
    507             handle->temp = realloc(handle->temp, desiredBytes);
    508             memcpy(handle->temp, ptr, desiredBytes);
    509             my_swab((short *) handle->temp, desiredFrames * handle->info.channels);
    510             actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
    511         }
    512         break;
    513     case SF_FORMAT_FLOAT:
    514         handle->temp = realloc(handle->temp, desiredBytes);
    515         memcpy_to_float_from_i16((float *) handle->temp, ptr,
    516                 desiredFrames * handle->info.channels);
    517         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
    518         break;
    519     default:
    520         break;
    521     }
    522     size_t actualFrames = actualBytes / handle->bytesPerFrame;
    523     handle->remaining += actualFrames;
    524     return actualFrames;
    525 }
    526 
    527 sf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames)
    528 {
    529     if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0)
    530         return 0;
    531     size_t desiredBytes = desiredFrames * handle->bytesPerFrame;
    532     size_t actualBytes = 0;
    533     switch (handle->info.format & SF_FORMAT_SUBMASK) {
    534     case SF_FORMAT_FLOAT:
    535         actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream);
    536         break;
    537     case SF_FORMAT_PCM_16:
    538         handle->temp = realloc(handle->temp, desiredBytes);
    539         memcpy_to_i16_from_float((short *) handle->temp, ptr,
    540                 desiredFrames * handle->info.channels);
    541         actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream);
    542         break;
    543     case SF_FORMAT_PCM_U8:  // transcoding from float to byte not yet implemented
    544     default:
    545         break;
    546     }
    547     size_t actualFrames = actualBytes / handle->bytesPerFrame;
    548     handle->remaining += actualFrames;
    549     return actualFrames;
    550 }
    551