1 /* $NetBSD: wav.c,v 1.3 2002/01/25 15:33:51 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 #if 0 131 printf("fmt header is:\n\t%d\ttag\n\t%d\tchannels\n\t%d\tsample rate\n\t%d\tavg_bps\n\t%d\talignment\n\t%d\tbits per sample\n", getle16(fmt.tag), getle16(fmt.channels), getle32(fmt.sample_rate), getle32(fmt.avg_bps), getle16(fmt.alignment), getle16(fmt.bits_per_sample)); 132 #endif 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 #if 0 181 printf("part `%c%c%c%c' len = %d\n", part.name[0], part.name[1], part.name[2], part.name[3], getle32(part.len)); 182 #endif 183 owhere = where; 184 where += (getle32(part.len) + 8); 185 } while (where < end && strncmp(part.name, strdata, sizeof strdata)); 186 187 if ((where - getle32(part.len)) <= end) { 188 if (channels) 189 *channels = getle16(fmt.channels); 190 if (sample) 191 *sample = getle32(fmt.sample_rate); 192 if (enc) 193 *enc = newenc; 194 if (prec) 195 *prec = newprec; 196 if (datasize) 197 *datasize = (size_t)getle32(part.len); 198 return (owhere - (char *)hdr + 8); 199 } 200 return (AUDIO_EWAVNODATA); 201 } 202