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 #include <stdlib.h> 28 #include <memory.h> 29 #include <math.h> 30 31 #include <AudioTypeChannel.h> 32 33 // This is a conversion class for channel conversions 34 // It handles mono->multi-channel and multi-channel->mono (mixing) 35 36 // class AudioTypeChannel methods 37 38 // Constructor 39 AudioTypeChannel:: 40 AudioTypeChannel() 41 { 42 } 43 44 // Destructor 45 AudioTypeChannel:: 46 ~AudioTypeChannel() 47 { 48 } 49 50 // Test conversion possibilities. 51 // Return TRUE if conversion to/from the specified type is possible. 52 Boolean AudioTypeChannel:: 53 CanConvert( 54 AudioHdr /* h */) const // target header 55 { 56 // XXX - This is misleading. Multi-channel->mono conversions 57 // must be linear format, but mono->multi-channel is 58 // ok in any format. 59 return (TRUE); 60 } 61 62 // Convert buffer to the specified type 63 // May replace the buffer with a new one, if necessary 64 AudioError AudioTypeChannel:: 65 Convert( 66 AudioBuffer*& inbuf, // data buffer to process 67 AudioHdr outhdr) // target header 68 { 69 AudioBuffer* outbuf; 70 AudioHdr inhdr; 71 AudioHdr newhdr; 72 Double length; 73 size_t nsamps; 74 size_t nbytes; 75 int i; 76 int j; 77 int k; 78 int chans; 79 char *cin; 80 char *cout; 81 short *sin; 82 short *sout; 83 AudioError err; 84 long smix; 85 86 inhdr = inbuf->GetHeader(); 87 length = inbuf->GetLength(); 88 89 // Make sure we're not being asked to do the impossible or trivial 90 if ((err = inhdr.Validate())) 91 return (err); 92 if ((inhdr.sample_rate != outhdr.sample_rate) || 93 (inhdr.encoding != outhdr.encoding) || 94 (inhdr.samples_per_unit != outhdr.samples_per_unit) || 95 (inhdr.bytes_per_unit != outhdr.bytes_per_unit)) 96 return (AUDIO_ERR_HDRINVAL); 97 if (inhdr.channels == outhdr.channels) 98 return (AUDIO_SUCCESS); 99 if ((inhdr.channels != 1) && (outhdr.channels != 1)) 100 return (AUDIO_ERR_HDRINVAL); 101 if (Undefined(length)) 102 return (AUDIO_ERR_BADARG); 103 104 // setup header for output buffer 105 newhdr = inhdr; 106 newhdr.channels = outhdr.channels; 107 108 // XXX - If multi-channel -> mono, must be linear to mix 109 // We need to test for this before trying the conversion! 110 if ((inhdr.channels > 1) && (newhdr.channels == 1)) { 111 if ((inhdr.encoding != LINEAR) || 112 (inhdr.bytes_per_unit > 2)) 113 return (AUDIO_ERR_HDRINVAL); 114 } 115 116 // Allocate a new buffer 117 outbuf = new AudioBuffer(length, "(Channel conversion buffer)"); 118 if (outbuf == 0) 119 return (AUDIO_UNIXERROR); 120 if (err = outbuf->SetHeader(newhdr)) { 121 delete outbuf; 122 return (err); 123 } 124 125 // Get the number of sample frames and the size of each 126 nsamps = (size_t)inhdr.Time_to_Samples(length); 127 nbytes = (size_t)inhdr.FrameLength(); 128 chans = inhdr.channels; 129 130 // multi-channel -> mono conversion 131 if ((chans > 1) && (newhdr.channels == 1)) { 132 switch (inhdr.bytes_per_unit) { 133 case 1: 134 cin = (char *)inbuf->GetAddress(); 135 cout = (char *)outbuf->GetAddress(); 136 137 for (i = 0; i < nsamps; i++) { 138 smix = 0; 139 for (j = 0; j < chans; j++) { 140 smix += *cin++; 141 } 142 if (smix < -0x7f) { 143 smix = -0x7f; 144 } else if (smix > 0x7f) { 145 smix = 0x7f; 146 } 147 *cout++ = (char)smix; 148 } 149 break; 150 case 2: 151 sin = (short *)inbuf->GetAddress(); 152 sout = (short *)outbuf->GetAddress(); 153 154 for (i = 0; i < nsamps; i++) { 155 smix = 0; 156 for (j = 0; j < chans; j++) { 157 smix += *sin++; 158 } 159 if (smix < -0x7fff) { 160 smix = -0x7fff; 161 } else if (smix > 0x7fff) { 162 smix = 0x7fff; 163 } 164 *sout++ = (short)smix; 165 } 166 break; 167 default: 168 err = AUDIO_ERR_HDRINVAL; 169 } 170 171 } else if ((chans == 1) && (newhdr.channels > 1)) { 172 // mono -> multi-channel 173 chans = newhdr.channels; 174 cin = (char *)inbuf->GetAddress(); 175 cout = (char *)outbuf->GetAddress(); 176 177 // XXX - this could be optimized by special-casing stuff 178 for (i = 0; i < nsamps; i++) { 179 for (j = 0; j < chans; j++) { 180 for (k = 0; k < nbytes; k++) 181 *cout++ = cin[k]; 182 } 183 cin += nbytes; 184 } 185 } 186 187 if (err) { 188 if (outbuf != inbuf) 189 delete outbuf; 190 return (err); 191 } 192 193 // This will delete the buffer 194 inbuf->Reference(); 195 inbuf->Dereference(); 196 197 // Set the valid data length 198 outbuf->SetLength(length); 199 inbuf = outbuf; 200 return (AUDIO_SUCCESS); 201 } 202 203 AudioError AudioTypeChannel:: 204 Flush( 205 AudioBuffer*& /* buf */) 206 { 207 return (AUDIO_SUCCESS); 208 } 209