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