1207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten/* 2207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * Copyright (C) 2012 The Android Open Source Project 3207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * 4207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * you may not use this file except in compliance with the License. 6207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * You may obtain a copy of the License at 7207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * 8207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * 10207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * Unless required by applicable law or agreed to in writing, software 11207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * See the License for the specific language governing permissions and 14207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten * limitations under the License. 15207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten */ 16207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 17207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten#include <audio_utils/sndfile.h> 1836c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten#include <audio_utils/primitives.h> 19207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten#include <stdio.h> 20207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten#include <string.h> 21c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten#include <errno.h> 22c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 23c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten#define WAVE_FORMAT_PCM 1 24c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten#define WAVE_FORMAT_IEEE_FLOAT 3 25c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten#define WAVE_FORMAT_EXTENSIBLE 0xFFFE 26207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 27207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kastenstruct SNDFILE_ { 28eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten int mode; 29eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten uint8_t *temp; // realloc buffer used for shrinking 16 bits to 8 bits and byte-swapping 30207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten FILE *stream; 31207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten size_t bytesPerFrame; 32eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t remaining; // frames unread for SFM_READ, frames written for SFM_WRITE 33207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten SF_INFO info; 34207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten}; 35207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 36207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kastenstatic unsigned little2u(unsigned char *ptr) 37207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 38207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return (ptr[1] << 8) + ptr[0]; 39207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 40207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 41207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kastenstatic unsigned little4u(unsigned char *ptr) 42207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 43207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return (ptr[3] << 24) + (ptr[2] << 16) + (ptr[1] << 8) + ptr[0]; 44207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 45207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 46207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kastenstatic int isLittleEndian(void) 47207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 48207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten static const short one = 1; 49207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return *((const char *) &one) == 1; 50207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 51207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 528fdafc906bc3abd9ce897c6c0e87598417bd4d58Glenn Kasten// "swab" conflicts with OS X <string.h> 538fdafc906bc3abd9ce897c6c0e87598417bd4d58Glenn Kastenstatic void my_swab(short *ptr, size_t numToSwap) 54207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 55207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten while (numToSwap > 0) { 56207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten *ptr = little2u((unsigned char *) ptr); 57207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten --numToSwap; 58207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten ++ptr; 59207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten } 60207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 61207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 62eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kastenstatic SNDFILE *sf_open_read(const char *path, SF_INFO *info) 63207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 64207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten FILE *stream = fopen(path, "rb"); 65c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (stream == NULL) { 66c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "fopen %s failed errno %d\n", path, errno); 67207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return NULL; 68c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 69c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 70c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE)); 71c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->mode = SFM_READ; 72c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->temp = NULL; 73c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->stream = stream; 74c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.format = SF_FORMAT_WAV; 75c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 76c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten // don't attempt to parse all valid forms, just the most common ones 77c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char wav[12]; 78207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten size_t actual; 79207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten actual = fread(wav, sizeof(char), sizeof(wav), stream); 80c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (actual < 12) { 8196d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "actual %zu < 44\n", actual); 82c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 83c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 84c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (memcmp(wav, "RIFF", 4)) { 85c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "wav != RIFF\n"); 86c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 87c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 88c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned riffSize = little4u(&wav[4]); 89c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (riffSize < 4) { 90c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "riffSize %u < 4\n", riffSize); 91c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 92c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 93c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (memcmp(&wav[8], "WAVE", 4)) { 94c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "missing WAVE\n"); 95c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 96c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 97c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t remaining = riffSize - 4; 98c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten int hadFmt = 0; 99c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten int hadData = 0; 100c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten while (remaining >= 8) { 101c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char chunk[8]; 102c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actual = fread(chunk, sizeof(char), sizeof(chunk), stream); 103c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (actual != sizeof(chunk)) { 10496d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "actual %zu != %zu\n", actual, sizeof(chunk)); 105c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 106c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 107c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten remaining -= 8; 108c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned chunkSize = little4u(&chunk[4]); 109c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (chunkSize > remaining) { 11096d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "chunkSize %u > remaining %zu\n", chunkSize, remaining); 111c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 112c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 113c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (!memcmp(&chunk[0], "fmt ", 4)) { 114c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (hadFmt) { 115c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "multiple fmt\n"); 116c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 117c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 118c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (chunkSize < 2) { 119c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "chunkSize %u < 2\n", chunkSize); 120c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 121c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 122c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char fmt[40]; 123c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actual = fread(fmt, sizeof(char), 2, stream); 124c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (actual != 2) { 12596d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "actual %zu != 2\n", actual); 126c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 127c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 128c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned format = little2u(&fmt[0]); 129c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t minSize = 0; 130c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (format) { 131c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case WAVE_FORMAT_PCM: 132c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case WAVE_FORMAT_IEEE_FLOAT: 133c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten minSize = 16; 134c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 135c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case WAVE_FORMAT_EXTENSIBLE: 136c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten minSize = 40; 137c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 138c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 139c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "unsupported format %u\n", format); 140c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 141c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 142c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (chunkSize < minSize) { 14396d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "chunkSize %u < minSize %zu\n", chunkSize, minSize); 144c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 145c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 146c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actual = fread(&fmt[2], sizeof(char), minSize - 2, stream); 147c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (actual != minSize - 2) { 14896d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "actual %zu != %zu\n", actual, minSize - 16); 149c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 150c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 151c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (chunkSize > minSize) { 152c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fseek(stream, (long) (chunkSize - minSize), SEEK_CUR); 153c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 154c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned channels = little2u(&fmt[2]); 1557c1930a39b04ce8c018df5f49e3be4ccdccbd3fdGlenn Kasten if (channels != 1 && channels != 2 && channels != 4 && channels != 6 && channels != 8) { 1567c1930a39b04ce8c018df5f49e3be4ccdccbd3fdGlenn Kasten fprintf(stderr, "unsupported channels %u\n", channels); 157c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 158c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 159c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned samplerate = little4u(&fmt[4]); 160c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (samplerate == 0) { 161c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "samplerate %u == 0\n", samplerate); 162c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 163c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 164c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten // ignore byte rate 165c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten // ignore block alignment 166c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned bitsPerSample = little2u(&fmt[14]); 167c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32) { 168c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "bitsPerSample %u != 8 or 16 or 32\n", bitsPerSample); 169c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 170c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 171c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned bytesPerFrame = (bitsPerSample >> 3) * channels; 172c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->bytesPerFrame = bytesPerFrame; 173c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.samplerate = samplerate; 174c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.channels = channels; 175c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (bitsPerSample) { 176c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case 8: 177c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.format |= SF_FORMAT_PCM_U8; 178c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 179c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case 16: 180c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.format |= SF_FORMAT_PCM_16; 181c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 182c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case 32: 183c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (format == WAVE_FORMAT_IEEE_FLOAT) 184c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.format |= SF_FORMAT_FLOAT; 185c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten else 186c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.format |= SF_FORMAT_PCM_32; 187c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 188c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 189c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten hadFmt = 1; 190c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else if (!memcmp(&chunk[0], "data", 4)) { 191c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (!hadFmt) { 192c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "data not preceded by fmt\n"); 193c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 194c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 195c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (hadData) { 196c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "multiple data\n"); 197c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 198c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 199c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->remaining = chunkSize / handle->bytesPerFrame; 200c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->info.frames = handle->remaining; 201c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten hadData = 1; 202c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else if (!memcmp(&chunk[0], "fact", 4)) { 203c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten // ignore fact 204c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (chunkSize > 0) { 205c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fseek(stream, (long) chunkSize, SEEK_CUR); 206c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 207c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else { 208c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten // ignore unknown chunk 209c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "ignoring unknown chunk %c%c%c%c\n", 210c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten chunk[0], chunk[1], chunk[2], chunk[3]); 211c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (chunkSize > 0) { 212c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fseek(stream, (long) chunkSize, SEEK_CUR); 213c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 214c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 215c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten remaining -= chunkSize; 216c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 217c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (remaining > 0) { 21896d859ca87493056f13b1b653f49ffe7bf9bcd2fKévin PETIT fprintf(stderr, "partial chunk at end of RIFF, remaining %zu\n", remaining); 219c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 220207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten } 221c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (!hadData) { 222c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "missing data\n"); 223c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten goto close; 224c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 225c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten *info = handle->info; 226c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten return handle; 227c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 228c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kastenclose: 229c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten free(handle); 230c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fclose(stream); 231207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return NULL; 232207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 233207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 234eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kastenstatic void write4u(unsigned char *ptr, unsigned u) 235eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten{ 236eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten ptr[0] = u; 237eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten ptr[1] = u >> 8; 238eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten ptr[2] = u >> 16; 239eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten ptr[3] = u >> 24; 240eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 241eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 242eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kastenstatic SNDFILE *sf_open_write(const char *path, SF_INFO *info) 243eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten{ 244c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten int sub = info->format & SF_FORMAT_SUBMASK; 245eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (!( 246eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten (info->samplerate > 0) && 2477095bc708771377cd195d426ae23bc961bf9ac30Andy Hung (info->channels > 0 && info->channels <= 8) && 248eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten ((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) && 249c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten (sub == SF_FORMAT_PCM_16 || sub == SF_FORMAT_PCM_U8 || sub == SF_FORMAT_FLOAT) 250eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten )) { 251eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return NULL; 252eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 253eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten FILE *stream = fopen(path, "w+b"); 2541fa816b623b8d912d78742b4a447693c8eb383edAndy Hung if (stream == NULL) { 2551fa816b623b8d912d78742b4a447693c8eb383edAndy Hung fprintf(stderr, "fopen %s failed errno %d\n", path, errno); 2561fa816b623b8d912d78742b4a447693c8eb383edAndy Hung return NULL; 2571fa816b623b8d912d78742b4a447693c8eb383edAndy Hung } 258c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char wav[58]; 259eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memset(wav, 0, sizeof(wav)); 260eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy(wav, "RIFF", 4); 261eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy(&wav[8], "WAVEfmt ", 8); 262c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (sub == SF_FORMAT_FLOAT) { 263c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[4] = 50; // riffSize 264c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[16] = 18; // fmtSize 265c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[20] = WAVE_FORMAT_IEEE_FLOAT; 266c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else { 267c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[4] = 36; // riffSize 268c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[16] = 16; // fmtSize 269c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[20] = WAVE_FORMAT_PCM; 270c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 271eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten wav[22] = info->channels; 272eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten write4u(&wav[24], info->samplerate); 273c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned bitsPerSample; 274c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (sub) { 275c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_16: 276c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 16; 277c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 278c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_U8: 279c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 8; 280c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 281c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: 282c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 32; 283c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 284c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: // not reachable 285c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 0; 286c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 287c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 288eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten unsigned blockAlignment = (bitsPerSample >> 3) * info->channels; 289eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten unsigned byteRate = info->samplerate * blockAlignment; 290eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten write4u(&wav[28], byteRate); 291eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten wav[32] = blockAlignment; 292eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten wav[34] = bitsPerSample; 293c74f4b7ace224c3435fd4a2f5127aa09f448d2a5Andy Hung size_t extra = 0; 294c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (sub == SF_FORMAT_FLOAT) { 295c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy(&wav[38], "fact", 4); 296c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[42] = 4; 297c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy(&wav[50], "data", 4); 298c74f4b7ace224c3435fd4a2f5127aa09f448d2a5Andy Hung extra = 14; 299c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else 300c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy(&wav[36], "data", 4); 301eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten // dataSize is initially zero 302c74f4b7ace224c3435fd4a2f5127aa09f448d2a5Andy Hung (void) fwrite(wav, 44 + extra, 1, stream); 303eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE)); 304eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->mode = SFM_WRITE; 305eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->temp = NULL; 306eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->stream = stream; 307eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->bytesPerFrame = blockAlignment; 308eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->remaining = 0; 309eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->info = *info; 310eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return handle; 311eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 312eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 313eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn KastenSNDFILE *sf_open(const char *path, int mode, SF_INFO *info) 314eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten{ 315c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (path == NULL || info == NULL) { 316c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "path=%p info=%p\n", path, info); 317eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return NULL; 318c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 319eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten switch (mode) { 320eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SFM_READ: 321eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return sf_open_read(path, info); 322eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SFM_WRITE: 323eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return sf_open_write(path, info); 324eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten default: 325c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "mode=%d\n", mode); 326eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return NULL; 327eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 328eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 329eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 330207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kastenvoid sf_close(SNDFILE *handle) 331207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 332207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten if (handle == NULL) 333207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return; 334eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten free(handle->temp); 335eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (handle->mode == SFM_WRITE) { 336eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten (void) fflush(handle->stream); 337eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten rewind(handle->stream); 338c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char wav[58]; 339c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0; 340c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten (void) fread(wav, 44 + extra, 1, handle->stream); 341eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten unsigned dataSize = handle->remaining * handle->bytesPerFrame; 342c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten write4u(&wav[4], dataSize + 36 + extra); // riffSize 343c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten write4u(&wav[40 + extra], dataSize); // dataSize 344eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten rewind(handle->stream); 345c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten (void) fwrite(wav, 44 + extra, 1, handle->stream); 346eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 347207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten (void) fclose(handle->stream); 348eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten free(handle); 349207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 350207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 35136c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kastensf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames) 352207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 353eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 354eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten desiredFrames <= 0) { 355207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return 0; 356eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 357c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten if (handle->remaining < (size_t) desiredFrames) { 358207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten desiredFrames = handle->remaining; 359c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten } 360207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten // does not check for numeric overflow 361c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 362c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t actualBytes; 363c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten void *temp = NULL; 364c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 365c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) { 366c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten temp = malloc(desiredBytes); 367c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 368c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else { 369c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 370c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 371207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 372207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten handle->remaining -= actualFrames; 373c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (format) { 37436c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten case SF_FORMAT_PCM_U8: 37536c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels); 37636c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten break; 37736c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten case SF_FORMAT_PCM_16: 37836c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten if (!isLittleEndian()) 3798fdafc906bc3abd9ce897c6c0e87598417bd4d58Glenn Kasten my_swab(ptr, actualFrames * handle->info.channels); 38036c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten break; 381c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_32: 382c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels); 383c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten free(temp); 384c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 385c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: 386c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels); 387c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten free(temp); 388c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 389c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 390c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short)); 391c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 39236c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten } 393207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return actualFrames; 394207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 395eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 396c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kastensf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames) 397c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten{ 398c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 399c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten desiredFrames <= 0) { 400c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten return 0; 401c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten } 402c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten if (handle->remaining < (size_t) desiredFrames) { 403c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten desiredFrames = handle->remaining; 404c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten } 405c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten // does not check for numeric overflow 406c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 407c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten size_t actualBytes; 40852370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung void *temp = NULL; 409c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 41052370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) { 41152370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung temp = malloc(desiredBytes); 41252370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 41352370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung } else { 41452370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 41552370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung } 416c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 417c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten handle->remaining -= actualFrames; 418c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten switch (format) { 419c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten case SF_FORMAT_PCM_U8: 42052370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung#if 0 42152370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung // TODO - implement 42252370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung memcpy_to_float_from_u8(ptr, (const unsigned char *) temp, 423c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten actualFrames * handle->info.channels); 424c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten#endif 42552370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung free(temp); 42652370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung break; 427c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten case SF_FORMAT_PCM_16: 42852370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung memcpy_to_float_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels); 42952370169f1de6905db69ef5a16fcf1ab9ae4b1abAndy Hung free(temp); 430c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten break; 431c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten case SF_FORMAT_PCM_32: 432c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten memcpy_to_float_from_i32(ptr, (const int *) ptr, actualFrames * handle->info.channels); 433c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten break; 434c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten case SF_FORMAT_FLOAT: 435c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten break; 436c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten default: 437c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten memset(ptr, 0, actualFrames * handle->info.channels * sizeof(float)); 438c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten break; 439c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten } 440c89cb607706c98d64d5d1b1cae645353d0c8e8feGlenn Kasten return actualFrames; 441c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten} 442c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 4437b9378104f3709d6c07ed00fe11066860a4e9999Andy Hungsf_count_t sf_readf_int(SNDFILE *handle, int *ptr, sf_count_t desiredFrames) 4447b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung{ 4457b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 4467b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung desiredFrames <= 0) { 4477b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung return 0; 4487b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung } 4497b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung if (handle->remaining < (size_t) desiredFrames) { 4507b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung desiredFrames = handle->remaining; 4517b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung } 4527b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung // does not check for numeric overflow 4537b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 4547b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung void *temp = NULL; 4557b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 4567b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung size_t actualBytes; 4577b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung if (format == SF_FORMAT_PCM_16 || format == SF_FORMAT_PCM_U8) { 4587b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung temp = malloc(desiredBytes); 4597b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 4607b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung } else { 4617b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 4627b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung } 4637b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung size_t actualFrames = actualBytes / handle->bytesPerFrame; 4647b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung handle->remaining -= actualFrames; 4657b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung switch (format) { 4667b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung case SF_FORMAT_PCM_U8: 4677b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung#if 0 4687b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung // TODO - implement 4697b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung memcpy_to_i32_from_u8(ptr, (const unsigned char *) temp, 4707b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung actualFrames * handle->info.channels); 4717b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung#endif 4727b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung free(temp); 4737b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung break; 4747b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung case SF_FORMAT_PCM_16: 4757b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung memcpy_to_i32_from_i16(ptr, (const short *) temp, actualFrames * handle->info.channels); 4767b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung free(temp); 4777b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung break; 4787b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung case SF_FORMAT_PCM_32: 4797b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung break; 4807b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung case SF_FORMAT_FLOAT: 4817b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung memcpy_to_i32_from_float(ptr, (const float *) ptr, actualFrames * handle->info.channels); 4827b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung break; 4837b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung default: 4847b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung memset(ptr, 0, actualFrames * handle->info.channels * sizeof(int)); 4857b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung break; 4867b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung } 4877b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung return actualFrames; 4887b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung} 4897b9378104f3709d6c07ed00fe11066860a4e9999Andy Hung 490eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kastensf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames) 491eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten{ 492eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0) 493eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return 0; 494eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 495eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t actualBytes = 0; 496eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten switch (handle->info.format & SF_FORMAT_SUBMASK) { 497eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SF_FORMAT_PCM_U8: 498eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->temp = realloc(handle->temp, desiredBytes); 499eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes); 500eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 501eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten break; 502eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SF_FORMAT_PCM_16: 503eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten // does not check for numeric overflow 504eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (isLittleEndian()) { 505eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream); 506eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } else { 507eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->temp = realloc(handle->temp, desiredBytes); 508eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy(handle->temp, ptr, desiredBytes); 5098fdafc906bc3abd9ce897c6c0e87598417bd4d58Glenn Kasten my_swab((short *) handle->temp, desiredFrames * handle->info.channels); 510eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 511eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 512eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten break; 513e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung case SF_FORMAT_FLOAT: 514e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung handle->temp = realloc(handle->temp, desiredBytes); 5151fa816b623b8d912d78742b4a447693c8eb383edAndy Hung memcpy_to_float_from_i16((float *) handle->temp, ptr, 5161fa816b623b8d912d78742b4a447693c8eb383edAndy Hung desiredFrames * handle->info.channels); 517e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 518e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung break; 519c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 520c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 521c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 522c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 523c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->remaining += actualFrames; 524c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten return actualFrames; 525c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten} 526c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 527c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kastensf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames) 528c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten{ 529c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0) 530c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten return 0; 531c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 532c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t actualBytes = 0; 533c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (handle->info.format & SF_FORMAT_SUBMASK) { 534c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: 535c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream); 536c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 537c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_16: 538e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung handle->temp = realloc(handle->temp, desiredBytes); 5391fa816b623b8d912d78742b4a447693c8eb383edAndy Hung memcpy_to_i16_from_float((short *) handle->temp, ptr, 5401fa816b623b8d912d78742b4a447693c8eb383edAndy Hung desiredFrames * handle->info.channels); 541e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 542e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung break; 543e9b333c8b17dea46125ac26f0a388f62b43a8931Andy Hung case SF_FORMAT_PCM_U8: // transcoding from float to byte not yet implemented 544c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 545c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 546eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 547eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 548eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->remaining += actualFrames; 549eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return actualFrames; 550eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 551