1 /* $NetBSD: wav.c,v 1.4 2002/12/08 10:49:03 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 36 #include <sys/types.h> 37 #include <sys/audioio.h> 38 #include <sys/ioctl.h> 39 #include <sys/time.h> 40 41 #include <ctype.h> 42 #include <err.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 #include "libaudio.h" 48 49 struct { 50 int wenc; 51 const char *wname; 52 } wavencs[] = { 53 { WAVE_FORMAT_UNKNOWN, "Microsoft Official Unknown" }, 54 { WAVE_FORMAT_PCM, "Microsoft PCM" }, 55 { WAVE_FORMAT_ADPCM, "Microsoft ADPCM" }, 56 { WAVE_FORMAT_ALAW, "Microsoft A-law" }, 57 { WAVE_FORMAT_MULAW, "Microsoft U-law" }, 58 { WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" }, 59 { WAVE_FORMAT_DIGISTD, "Digistd format" }, 60 { WAVE_FORMAT_DIGIFIX, "Digifix format" }, 61 { -1, "?Unknown?" }, 62 }; 63 64 const char * 65 wav_enc_from_val(int encoding) 66 { 67 int i; 68 69 for (i = 0; wavencs[i].wenc != -1; i++) 70 if (wavencs[i].wenc == encoding) 71 break; 72 return (wavencs[i].wname); 73 } 74 75 /* 76 * sample header is: 77 * 78 * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@ 79 * 80 */ 81 /* 82 * WAV format helpers 83 */ 84 /* 85 * find a .wav header, etc. returns header length on success 86 */ 87 ssize_t 88 audio_wav_parse_hdr(hdr, sz, enc, prec, sample, channels, datasize) 89 void *hdr; 90 size_t sz; 91 int *enc; 92 int *prec; 93 int *sample; 94 int *channels; 95 size_t *datasize; 96 { 97 char *where = hdr, *owhere; 98 wav_audioheaderpart part; 99 wav_audioheaderfmt fmt; 100 char *end = (((char *)hdr) + sz); 101 int newenc, newprec; 102 static const char 103 strfmt[4] = "fmt ", 104 strRIFF[4] = "RIFF", 105 strWAVE[4] = "WAVE", 106 strdata[4] = "data"; 107 108 if (sz < 32) 109 return (AUDIO_ENOENT); 110 111 if (strncmp(where, strRIFF, sizeof strRIFF)) 112 return (AUDIO_ENOENT); 113 where += 8; 114 if (strncmp(where, strWAVE, sizeof strWAVE)) 115 return (AUDIO_ENOENT); 116 where += 4; 117 118 do { 119 memcpy(&part, where, sizeof part); 120 owhere = where; 121 where += getle32(part.len) + 8; 122 } while (where < end && strncmp(part.name, strfmt, sizeof strfmt)); 123 124 /* too short ? */ 125 if (where + sizeof fmt > end) 126 return (AUDIO_ESHORTHDR); 127 128 memcpy(&fmt, (owhere + 8), sizeof fmt); 129 130 switch (getle16(fmt.tag)) { 131 case WAVE_FORMAT_UNKNOWN: 132 case WAVE_FORMAT_ADPCM: 133 case WAVE_FORMAT_OKI_ADPCM: 134 case WAVE_FORMAT_DIGISTD: 135 case WAVE_FORMAT_DIGIFIX: 136 case IBM_FORMAT_MULAW: 137 case IBM_FORMAT_ALAW: 138 case IBM_FORMAT_ADPCM: 139 default: 140 return (AUDIO_EWAVUNSUPP); 141 142 case WAVE_FORMAT_PCM: 143 switch (getle16(fmt.bits_per_sample)) { 144 case 8: 145 newprec = 8; 146 break; 147 case 16: 148 newprec = 16; 149 break; 150 case 24: 151 newprec = 24; 152 break; 153 case 32: 154 newprec = 32; 155 break; 156 default: 157 return (AUDIO_EWAVBADPCM); 158 } 159 if (newprec == 8) 160 newenc = AUDIO_ENCODING_ULINEAR_LE; 161 else 162 newenc = AUDIO_ENCODING_SLINEAR_LE; 163 break; 164 case WAVE_FORMAT_ALAW: 165 newenc = AUDIO_ENCODING_ALAW; 166 newprec = 8; 167 break; 168 case WAVE_FORMAT_MULAW: 169 newenc = AUDIO_ENCODING_ULAW; 170 newprec = 8; 171 break; 172 } 173 174 do { 175 memcpy(&part, where, sizeof part); 176 owhere = where; 177 where += (getle32(part.len) + 8); 178 } while (where < end && strncmp(part.name, strdata, sizeof strdata)); 179 180 if ((where - getle32(part.len)) <= end) { 181 if (channels) 182 *channels = getle16(fmt.channels); 183 if (sample) 184 *sample = getle32(fmt.sample_rate); 185 if (enc) 186 *enc = newenc; 187 if (prec) 188 *prec = newprec; 189 if (datasize) 190 *datasize = (size_t)getle32(part.len); 191 return (owhere - (char *)hdr + 8); 192 } 193 return (AUDIO_EWAVNODATA); 194 } 195