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) { 81c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "actual %u < 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)) { 104c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "actual %u != %u\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) { 110c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "chunkSize %u > remaining %u\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) { 125c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "actual %u != 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) { 143c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "chunkSize %u < minSize %u\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) { 148c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "actual %u != %u\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]); 155c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (channels != 1 && channels != 2) { 156c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "channels %u != 1 or 2\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) { 218c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "partial chunk at end of RIFF, remaining %u\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) && 247eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten (info->channels == 1 || info->channels == 2) && 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"); 254c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char wav[58]; 255eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memset(wav, 0, sizeof(wav)); 256eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy(wav, "RIFF", 4); 257eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy(&wav[8], "WAVEfmt ", 8); 258c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (sub == SF_FORMAT_FLOAT) { 259c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[4] = 50; // riffSize 260c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[16] = 18; // fmtSize 261c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[20] = WAVE_FORMAT_IEEE_FLOAT; 262c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else { 263c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[4] = 36; // riffSize 264c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[16] = 16; // fmtSize 265c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[20] = WAVE_FORMAT_PCM; 266c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 267eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten wav[22] = info->channels; 268eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten write4u(&wav[24], info->samplerate); 269c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned bitsPerSample; 270c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (sub) { 271c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_16: 272c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 16; 273c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 274c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_U8: 275c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 8; 276c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 277c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: 278c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 32; 279c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 280c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: // not reachable 281c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten bitsPerSample = 0; 282c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 283c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 284eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten unsigned blockAlignment = (bitsPerSample >> 3) * info->channels; 285eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten unsigned byteRate = info->samplerate * blockAlignment; 286eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten write4u(&wav[28], byteRate); 287eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten wav[32] = blockAlignment; 288eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten wav[34] = bitsPerSample; 289c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (sub == SF_FORMAT_FLOAT) { 290c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy(&wav[38], "fact", 4); 291c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten wav[42] = 4; 292c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy(&wav[50], "data", 4); 293c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else 294c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy(&wav[36], "data", 4); 295eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten // dataSize is initially zero 296eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten (void) fwrite(wav, sizeof(wav), 1, stream); 297eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten SNDFILE *handle = (SNDFILE *) malloc(sizeof(SNDFILE)); 298eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->mode = SFM_WRITE; 299eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->temp = NULL; 300eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->stream = stream; 301eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->bytesPerFrame = blockAlignment; 302eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->remaining = 0; 303eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->info = *info; 304eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return handle; 305eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 306eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 307eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn KastenSNDFILE *sf_open(const char *path, int mode, SF_INFO *info) 308eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten{ 309c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (path == NULL || info == NULL) { 310c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "path=%p info=%p\n", path, info); 311eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return NULL; 312c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 313eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten switch (mode) { 314eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SFM_READ: 315eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return sf_open_read(path, info); 316eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SFM_WRITE: 317eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return sf_open_write(path, info); 318eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten default: 319c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten fprintf(stderr, "mode=%d\n", mode); 320eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return NULL; 321eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 322eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 323eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 324207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kastenvoid sf_close(SNDFILE *handle) 325207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 326207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten if (handle == NULL) 327207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return; 328eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten free(handle->temp); 329eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (handle->mode == SFM_WRITE) { 330eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten (void) fflush(handle->stream); 331eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten rewind(handle->stream); 332c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned char wav[58]; 333c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t extra = (handle->info.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT ? 14 : 0; 334c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten (void) fread(wav, 44 + extra, 1, handle->stream); 335eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten unsigned dataSize = handle->remaining * handle->bytesPerFrame; 336c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten write4u(&wav[4], dataSize + 36 + extra); // riffSize 337c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten write4u(&wav[40 + extra], dataSize); // dataSize 338eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten rewind(handle->stream); 339c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten (void) fwrite(wav, 44 + extra, 1, handle->stream); 340eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 341207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten (void) fclose(handle->stream); 342eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten free(handle); 343207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 344207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten 34536c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kastensf_count_t sf_readf_short(SNDFILE *handle, short *ptr, sf_count_t desiredFrames) 346207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten{ 347eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (handle == NULL || handle->mode != SFM_READ || ptr == NULL || !handle->remaining || 348eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten desiredFrames <= 0) { 349207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return 0; 350eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 35136c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten if (handle->remaining < (size_t) desiredFrames) 352207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten desiredFrames = handle->remaining; 353207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten // does not check for numeric overflow 354c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 355c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t actualBytes; 356c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten void *temp = NULL; 357c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten unsigned format = handle->info.format & SF_FORMAT_SUBMASK; 358c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (format == SF_FORMAT_PCM_32 || format == SF_FORMAT_FLOAT) { 359c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten temp = malloc(desiredBytes); 360c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actualBytes = fread(temp, sizeof(char), desiredBytes, handle->stream); 361c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } else { 362c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actualBytes = fread(ptr, sizeof(char), desiredBytes, handle->stream); 363c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 364207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 365207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten handle->remaining -= actualFrames; 366c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (format) { 36736c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten case SF_FORMAT_PCM_U8: 36836c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten memcpy_to_i16_from_u8(ptr, (unsigned char *) ptr, actualFrames * handle->info.channels); 36936c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten break; 37036c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten case SF_FORMAT_PCM_16: 37136c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten if (!isLittleEndian()) 3728fdafc906bc3abd9ce897c6c0e87598417bd4d58Glenn Kasten my_swab(ptr, actualFrames * handle->info.channels); 37336c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten break; 374c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_32: 375c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy_to_i16_from_i32(ptr, (const int *) temp, actualFrames * handle->info.channels); 376c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten free(temp); 377c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 378c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: 379c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memcpy_to_i16_from_float(ptr, (const float *) temp, actualFrames * handle->info.channels); 380c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten free(temp); 381c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 382c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 383c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten memset(ptr, 0, actualFrames * handle->info.channels * sizeof(short)); 384c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 38536c248b94fd41c0f0bb54106ce8e2b0ad67c40eeGlenn Kasten } 386207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten return actualFrames; 387207ec2930dd429e5d4aa58e2b9899e09aa76e22cGlenn Kasten} 388eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten 389c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kastensf_count_t sf_readf_float(SNDFILE *handle, float *ptr, sf_count_t desiredFrames) 390c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten{ 391c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten return 0; 392c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten} 393c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 394eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kastensf_count_t sf_writef_short(SNDFILE *handle, const short *ptr, sf_count_t desiredFrames) 395eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten{ 396eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0) 397eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return 0; 398eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 399eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t actualBytes = 0; 400eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten switch (handle->info.format & SF_FORMAT_SUBMASK) { 401eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SF_FORMAT_PCM_U8: 402eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->temp = realloc(handle->temp, desiredBytes); 403eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy_to_u8_from_i16(handle->temp, ptr, desiredBytes); 404eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 405eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten break; 406eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten case SF_FORMAT_PCM_16: 407eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten // does not check for numeric overflow 408eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten if (isLittleEndian()) { 409eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream); 410eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } else { 411eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->temp = realloc(handle->temp, desiredBytes); 412eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten memcpy(handle->temp, ptr, desiredBytes); 4138fdafc906bc3abd9ce897c6c0e87598417bd4d58Glenn Kasten my_swab((short *) handle->temp, desiredFrames * handle->info.channels); 414eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten actualBytes = fwrite(handle->temp, sizeof(char), desiredBytes, handle->stream); 415eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 416eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten break; 417c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: // transcoding from short to float not yet implemented 418c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 419c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 420c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten } 421c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 422c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten handle->remaining += actualFrames; 423c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten return actualFrames; 424c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten} 425c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten 426c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kastensf_count_t sf_writef_float(SNDFILE *handle, const float *ptr, sf_count_t desiredFrames) 427c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten{ 428c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten if (handle == NULL || handle->mode != SFM_WRITE || ptr == NULL || desiredFrames <= 0) 429c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten return 0; 430c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t desiredBytes = desiredFrames * handle->bytesPerFrame; 431c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten size_t actualBytes = 0; 432c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten switch (handle->info.format & SF_FORMAT_SUBMASK) { 433c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_FLOAT: 434c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten actualBytes = fwrite(ptr, sizeof(char), desiredBytes, handle->stream); 435c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 436c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_U8: // transcoding from float to byte/short not yet implemented 437c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten case SF_FORMAT_PCM_16: 438c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten default: 439c0bd7157d2d5967a6b222a5d69b7703612f78a49Glenn Kasten break; 440eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten } 441eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten size_t actualFrames = actualBytes / handle->bytesPerFrame; 442eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten handle->remaining += actualFrames; 443eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten return actualFrames; 444eae13ddb9a4fdedf3895a10cdf5c0a4aefe0ff60Glenn Kasten} 445