1 /* $NetBSD: sun.c,v 1.10 2019/11/09 12:46:44 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 2002, 2013, 2015 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 * XXX this is slightly icky in places... 31 */ 32 #include <sys/cdefs.h> 33 34 #ifndef lint 35 __RCSID("$NetBSD: sun.c,v 1.10 2019/11/09 12:46:44 mrg Exp $"); 36 #endif 37 38 39 #include <sys/types.h> 40 #include <sys/audioio.h> 41 #include <sys/ioctl.h> 42 #include <sys/time.h> 43 44 #include <ctype.h> 45 #include <err.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "libaudio.h" 52 #include "auconv.h" 53 54 /* 55 * SunOS/NeXT .au format helpers 56 */ 57 static const struct { 58 int file_encoding; 59 int encoding; 60 int precision; 61 } file2sw_encodings[] = { 62 { AUDIO_FILE_ENCODING_MULAW_8, AUDIO_ENCODING_ULAW, 8 }, 63 { AUDIO_FILE_ENCODING_LINEAR_8, AUDIO_ENCODING_SLINEAR_BE, 8 }, 64 { AUDIO_FILE_ENCODING_LINEAR_16, AUDIO_ENCODING_SLINEAR_BE, 16 }, 65 { AUDIO_FILE_ENCODING_LINEAR_24, AUDIO_ENCODING_SLINEAR_BE, 24 }, 66 { AUDIO_FILE_ENCODING_LINEAR_32, AUDIO_ENCODING_SLINEAR_BE, 32 }, 67 #if 0 68 /* 69 * we should make some of these available. the, eg ultrasparc, port 70 * can use the VIS instructions (if available) do do some of these 71 * mpeg ones. 72 */ 73 { AUDIO_FILE_ENCODING_FLOAT, AUDIO_ENCODING_ULAW, 32 }, 74 { AUDIO_FILE_ENCODING_DOUBLE, AUDIO_ENCODING_ULAW, 64 }, 75 { AUDIO_FILE_ENCODING_ADPCM_G721, AUDIO_ENCODING_ULAW, 4 }, 76 { AUDIO_FILE_ENCODING_ADPCM_G722, AUDIO_ENCODING_ULAW, 0 }, 77 { AUDIO_FILE_ENCODING_ADPCM_G723_3, AUDIO_ENCODING_ULAW, 3 }, 78 { AUDIO_FILE_ENCODING_ADPCM_G723_5, AUDIO_ENCODING_ULAW, 5 }, 79 #endif 80 { AUDIO_FILE_ENCODING_ALAW_8, AUDIO_ENCODING_ALAW, 8 }, 81 { -1, -1, -1 } 82 }; 83 84 int 85 audio_sun_to_encoding(int sun_encoding, u_int *encp, u_int *precp) 86 { 87 int i; 88 89 for (i = 0; file2sw_encodings[i].file_encoding != -1; i++) 90 if (file2sw_encodings[i].file_encoding == sun_encoding) { 91 *precp = file2sw_encodings[i].precision; 92 *encp = file2sw_encodings[i].encoding; 93 return (0); 94 } 95 return (1); 96 } 97 98 int 99 audio_encoding_to_sun(int encoding, int precision, int *sunep) 100 { 101 int i; 102 103 for (i = 0; file2sw_encodings[i].file_encoding != -1; i++) 104 if (file2sw_encodings[i].encoding == encoding && 105 file2sw_encodings[i].precision == precision) { 106 *sunep = file2sw_encodings[i].file_encoding; 107 return (0); 108 } 109 return (1); 110 } 111 112 int 113 sun_prepare_header(struct track_info *ti, void **hdrp, size_t *lenp, int *leftp) 114 { 115 static int warned = 0; 116 static sun_audioheader auh; 117 int sunenc, oencoding = ti->encoding; 118 119 /* only perform conversions if we don't specify the encoding */ 120 switch (ti->encoding) { 121 122 case AUDIO_ENCODING_ULINEAR_LE: 123 #if BYTE_ORDER == LITTLE_ENDIAN 124 case AUDIO_ENCODING_ULINEAR: 125 #endif 126 if (ti->precision == 16 || ti->precision == 32) 127 ti->encoding = AUDIO_ENCODING_SLINEAR_BE; 128 break; 129 130 case AUDIO_ENCODING_ULINEAR_BE: 131 #if BYTE_ORDER == BIG_ENDIAN 132 case AUDIO_ENCODING_ULINEAR: 133 #endif 134 if (ti->precision == 16 || ti->precision == 32) 135 ti->encoding = AUDIO_ENCODING_SLINEAR_BE; 136 break; 137 138 case AUDIO_ENCODING_SLINEAR_LE: 139 #if BYTE_ORDER == LITTLE_ENDIAN 140 case AUDIO_ENCODING_SLINEAR: 141 #endif 142 if (ti->precision == 16 || ti->precision == 32) 143 ti->encoding = AUDIO_ENCODING_SLINEAR_BE; 144 break; 145 146 #if BYTE_ORDER == BIG_ENDIAN 147 case AUDIO_ENCODING_SLINEAR: 148 ti->encoding = AUDIO_ENCODING_SLINEAR_BE; 149 break; 150 #endif 151 } 152 153 /* if we can't express this as a Sun header, don't write any */ 154 if (audio_encoding_to_sun(ti->encoding, ti->precision, &sunenc) != 0) { 155 if (!ti->qflag && !warned) { 156 const char *s = audio_enc_from_val(oencoding); 157 158 if (s == NULL) 159 s = "(unknown)"; 160 warnx("failed to convert to sun encoding from %s " 161 "(precision %d);\nSun audio header not written", 162 s, ti->precision); 163 } 164 ti->format = AUDIO_FORMAT_NONE; 165 warned = 1; 166 return -1; 167 } 168 169 auh.magic = htonl(AUDIO_FILE_MAGIC); 170 if (ti->outfd == STDOUT_FILENO) 171 auh.data_size = htonl(AUDIO_UNKNOWN_SIZE); 172 else if (ti->total_size != -1) 173 auh.data_size = htonl(ti->total_size); 174 else 175 auh.data_size = 0; 176 auh.encoding = htonl(sunenc); 177 auh.sample_rate = htonl(ti->sample_rate); 178 auh.channels = htonl(ti->channels); 179 if (ti->header_info) { 180 int len, infolen; 181 182 infolen = ((len = strlen(ti->header_info)) + 7) & 0xfffffff8; 183 *leftp = infolen - len; 184 auh.hdr_size = htonl(sizeof(auh) + infolen); 185 } else { 186 *leftp = sizeof(audio_default_info); 187 auh.hdr_size = htonl(sizeof(auh) + *leftp); 188 } 189 *(sun_audioheader **)hdrp = &auh; 190 *lenp = sizeof auh; 191 return 0; 192 } 193 194 write_conv_func 195 sun_write_get_conv_func(struct track_info *ti) 196 { 197 write_conv_func conv_func = NULL; 198 199 /* only perform conversions if we don't specify the encoding */ 200 switch (ti->encoding) { 201 202 case AUDIO_ENCODING_ULINEAR_LE: 203 #if BYTE_ORDER == LITTLE_ENDIAN 204 case AUDIO_ENCODING_ULINEAR: 205 #endif 206 if (ti->precision == 16) 207 conv_func = change_sign16_swap_bytes_le; 208 else if (ti->precision == 32) 209 conv_func = change_sign32_swap_bytes_le; 210 break; 211 212 case AUDIO_ENCODING_ULINEAR_BE: 213 #if BYTE_ORDER == BIG_ENDIAN 214 case AUDIO_ENCODING_ULINEAR: 215 #endif 216 if (ti->precision == 16) 217 conv_func = change_sign16_be; 218 else if (ti->precision == 32) 219 conv_func = change_sign32_be; 220 break; 221 222 case AUDIO_ENCODING_SLINEAR_LE: 223 #if BYTE_ORDER == LITTLE_ENDIAN 224 case AUDIO_ENCODING_SLINEAR: 225 #endif 226 if (ti->precision == 16) 227 conv_func = swap_bytes; 228 else if (ti->precision == 32) 229 conv_func = swap_bytes32; 230 break; 231 } 232 233 return conv_func; 234 } 235