1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1993-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdlib.h> 30 #include <memory.h> 31 #include <math.h> 32 33 #include <AudioTypeChannel.h> 34 35 // This is a conversion class for channel conversions 36 // It handles mono->multi-channel and multi-channel->mono (mixing) 37 38 // class AudioTypeChannel methods 39 40 // Constructor 41 AudioTypeChannel:: 42 AudioTypeChannel() 43 { 44 } 45 46 // Destructor 47 AudioTypeChannel:: 48 ~AudioTypeChannel() 49 { 50 } 51 52 // Test conversion possibilities. 53 // Return TRUE if conversion to/from the specified type is possible. 54 Boolean AudioTypeChannel:: 55 CanConvert( 56 AudioHdr /* h */) const // target header 57 { 58 // XXX - This is misleading. Multi-channel->mono conversions 59 // must be linear format, but mono->multi-channel is 60 // ok in any format. 61 return (TRUE); 62 } 63 64 // Convert buffer to the specified type 65 // May replace the buffer with a new one, if necessary 66 AudioError AudioTypeChannel:: 67 Convert( 68 AudioBuffer*& inbuf, // data buffer to process 69 AudioHdr outhdr) // target header 70 { 71 AudioBuffer* outbuf; 72 AudioHdr inhdr; 73 AudioHdr newhdr; 74 Double length; 75 size_t nsamps; 76 size_t nbytes; 77 int i; 78 int j; 79 int k; 80 int chans; 81 char *cin; 82 char *cout; 83 short *sin; 84 short *sout; 85 AudioError err; 86 long smix; 87 88 inhdr = inbuf->GetHeader(); 89 length = inbuf->GetLength(); 90 91 // Make sure we're not being asked to do the impossible or trivial 92 if ((err = inhdr.Validate())) 93 return (err); 94 if ((inhdr.sample_rate != outhdr.sample_rate) || 95 (inhdr.encoding != outhdr.encoding) || 96 (inhdr.samples_per_unit != outhdr.samples_per_unit) || 97 (inhdr.bytes_per_unit != outhdr.bytes_per_unit)) 98 return (AUDIO_ERR_HDRINVAL); 99 if (inhdr.channels == outhdr.channels) 100 return (AUDIO_SUCCESS); 101 if ((inhdr.channels != 1) && (outhdr.channels != 1)) 102 return (AUDIO_ERR_HDRINVAL); 103 if (Undefined(length)) 104 return (AUDIO_ERR_BADARG); 105 106 // setup header for output buffer 107 newhdr = inhdr; 108 newhdr.channels = outhdr.channels; 109 110 // XXX - If multi-channel -> mono, must be linear to mix 111 // We need to test for this before trying the conversion! 112 if ((inhdr.channels > 1) && (newhdr.channels == 1)) { 113 if ((inhdr.encoding != LINEAR) || 114 (inhdr.bytes_per_unit > 2)) 115 return (AUDIO_ERR_HDRINVAL); 116 } 117 118 // Allocate a new buffer 119 outbuf = new AudioBuffer(length, "(Channel conversion buffer)"); 120 if (outbuf == 0) 121 return (AUDIO_UNIXERROR); 122 if (err = outbuf->SetHeader(newhdr)) { 123 delete outbuf; 124 return (err); 125 } 126 127 // Get the number of sample frames and the size of each 128 nsamps = (size_t)inhdr.Time_to_Samples(length); 129 nbytes = (size_t)inhdr.FrameLength(); 130 chans = inhdr.channels; 131 132 // multi-channel -> mono conversion 133 if ((chans > 1) && (newhdr.channels == 1)) { 134 switch (inhdr.bytes_per_unit) { 135 case 1: 136 cin = (char *)inbuf->GetAddress(); 137 cout = (char *)outbuf->GetAddress(); 138 139 for (i = 0; i < nsamps; i++) { 140 smix = 0; 141 for (j = 0; j < chans; j++) { 142 smix += *cin++; 143 } 144 if (smix < -0x7f) { 145 smix = -0x7f; 146 } else if (smix > 0x7f) { 147 smix = 0x7f; 148 } 149 *cout++ = (char)smix; 150 } 151 break; 152 case 2: 153 sin = (short *)inbuf->GetAddress(); 154 sout = (short *)outbuf->GetAddress(); 155 156 for (i = 0; i < nsamps; i++) { 157 smix = 0; 158 for (j = 0; j < chans; j++) { 159 smix += *sin++; 160 } 161 if (smix < -0x7fff) { 162 smix = -0x7fff; 163 } else if (smix > 0x7fff) { 164 smix = 0x7fff; 165 } 166 *sout++ = (short)smix; 167 } 168 break; 169 default: 170 err = AUDIO_ERR_HDRINVAL; 171 } 172 173 } else if ((chans == 1) && (newhdr.channels > 1)) { 174 // mono -> multi-channel 175 chans = newhdr.channels; 176 cin = (char *)inbuf->GetAddress(); 177 cout = (char *)outbuf->GetAddress(); 178 179 // XXX - this could be optimized by special-casing stuff 180 for (i = 0; i < nsamps; i++) { 181 for (j = 0; j < chans; j++) { 182 for (k = 0; k < nbytes; k++) 183 *cout++ = cin[k]; 184 } 185 cin += nbytes; 186 } 187 } 188 189 if (err) { 190 if (outbuf != inbuf) 191 delete outbuf; 192 return (err); 193 } 194 195 // This will delete the buffer 196 inbuf->Reference(); 197 inbuf->Dereference(); 198 199 // Set the valid data length 200 outbuf->SetLength(length); 201 inbuf = outbuf; 202 return (AUDIO_SUCCESS); 203 } 204 205 AudioError AudioTypeChannel:: 206 Flush( 207 AudioBuffer*& /* buf */) 208 { 209 return (AUDIO_SUCCESS); 210 } 211