1 /* $NetBSD: wav.c,v 1.8 2008/05/29 14:51:27 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * WAV support for the audio tools; thanks go to the sox utility for 31 * clearing up issues with WAV files. 32 */ 33 #include <sys/cdefs.h> 34 35 #ifndef lint 36 __RCSID("$NetBSD: wav.c,v 1.8 2008/05/29 14:51:27 mrg Exp $"); 37 #endif 38 39 40 #include <sys/types.h> 41 #include <sys/audioio.h> 42 #include <sys/ioctl.h> 43 #include <sys/time.h> 44 45 #include <ctype.h> 46 #include <err.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 51 #include "libaudio.h" 52 53 struct { 54 int wenc; 55 const char *wname; 56 } wavencs[] = { 57 { WAVE_FORMAT_UNKNOWN, "Microsoft Official Unknown" }, 58 { WAVE_FORMAT_PCM, "Microsoft PCM" }, 59 { WAVE_FORMAT_ADPCM, "Microsoft ADPCM" }, 60 { WAVE_FORMAT_ALAW, "Microsoft A-law" }, 61 { WAVE_FORMAT_MULAW, "Microsoft mu-law" }, 62 { WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" }, 63 { WAVE_FORMAT_DIGISTD, "Digistd format" }, 64 { WAVE_FORMAT_DIGIFIX, "Digifix format" }, 65 { -1, "?Unknown?" }, 66 }; 67 68 const char * 69 wav_enc_from_val(int encoding) 70 { 71 int i; 72 73 for (i = 0; wavencs[i].wenc != -1; i++) 74 if (wavencs[i].wenc == encoding) 75 break; 76 return (wavencs[i].wname); 77 } 78 79 /* 80 * sample header is: 81 * 82 * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@ 83 * 84 */ 85 /* 86 * WAV format helpers 87 */ 88 /* 89 * find a .wav header, etc. returns header length on success 90 */ 91 ssize_t 92 audio_wav_parse_hdr(hdr, sz, enc, prec, sample, channels, datasize) 93 void *hdr; 94 size_t sz; 95 u_int *enc; 96 u_int *prec; 97 u_int *sample; 98 u_int *channels; 99 size_t *datasize; 100 { 101 char *where = hdr, *owhere; 102 wav_audioheaderpart part; 103 wav_audioheaderfmt fmt; 104 char *end = (((char *)hdr) + sz); 105 u_int newenc, newprec; 106 static const char 107 strfmt[4] = "fmt ", 108 strRIFF[4] = "RIFF", 109 strWAVE[4] = "WAVE", 110 strdata[4] = "data"; 111 112 if (sz < 32) 113 return (AUDIO_ENOENT); 114 115 if (strncmp(where, strRIFF, sizeof strRIFF)) 116 return (AUDIO_ENOENT); 117 where += 8; 118 if (strncmp(where, strWAVE, sizeof strWAVE)) 119 return (AUDIO_ENOENT); 120 where += 4; 121 122 do { 123 memcpy(&part, where, sizeof part); 124 owhere = where; 125 where += getle32(part.len) + 8; 126 } while (where < end && strncmp(part.name, strfmt, sizeof strfmt)); 127 128 /* too short ? */ 129 if (where + sizeof fmt > end) 130 return (AUDIO_ESHORTHDR); 131 132 memcpy(&fmt, (owhere + 8), sizeof fmt); 133 134 switch (getle16(fmt.tag)) { 135 case WAVE_FORMAT_UNKNOWN: 136 case WAVE_FORMAT_ADPCM: 137 case WAVE_FORMAT_OKI_ADPCM: 138 case WAVE_FORMAT_DIGISTD: 139 case WAVE_FORMAT_DIGIFIX: 140 case IBM_FORMAT_MULAW: 141 case IBM_FORMAT_ALAW: 142 case IBM_FORMAT_ADPCM: 143 default: 144 return (AUDIO_EWAVUNSUPP); 145 146 case WAVE_FORMAT_PCM: 147 switch (getle16(fmt.bits_per_sample)) { 148 case 8: 149 newprec = 8; 150 break; 151 case 16: 152 newprec = 16; 153 break; 154 case 24: 155 newprec = 24; 156 break; 157 case 32: 158 newprec = 32; 159 break; 160 default: 161 return (AUDIO_EWAVBADPCM); 162 } 163 if (newprec == 8) 164 newenc = AUDIO_ENCODING_ULINEAR_LE; 165 else 166 newenc = AUDIO_ENCODING_SLINEAR_LE; 167 break; 168 case WAVE_FORMAT_ALAW: 169 newenc = AUDIO_ENCODING_ALAW; 170 newprec = 8; 171 break; 172 case WAVE_FORMAT_MULAW: 173 newenc = AUDIO_ENCODING_ULAW; 174 newprec = 8; 175 break; 176 } 177 178 do { 179 memcpy(&part, where, sizeof part); 180 owhere = where; 181 where += (getle32(part.len) + 8); 182 } while (where < end && strncmp(part.name, strdata, sizeof strdata)); 183 184 if ((where - getle32(part.len)) <= end) { 185 if (channels) 186 *channels = (u_int)getle16(fmt.channels); 187 if (sample) 188 *sample = getle32(fmt.sample_rate); 189 if (enc) 190 *enc = newenc; 191 if (prec) 192 *prec = newprec; 193 if (datasize) 194 *datasize = (size_t)getle32(part.len); 195 return (owhere - (char *)hdr + 8); 196 } 197 return (AUDIO_EWAVNODATA); 198 } 199