/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1993-2001 by Sun Microsystems, Inc. * All rights reserved. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include // This is a conversion class for channel conversions // It handles mono->multi-channel and multi-channel->mono (mixing) // class AudioTypeChannel methods // Constructor AudioTypeChannel:: AudioTypeChannel() { } // Destructor AudioTypeChannel:: ~AudioTypeChannel() { } // Test conversion possibilities. // Return TRUE if conversion to/from the specified type is possible. Boolean AudioTypeChannel:: CanConvert( AudioHdr /* h */) const // target header { // XXX - This is misleading. Multi-channel->mono conversions // must be linear format, but mono->multi-channel is // ok in any format. return (TRUE); } // Convert buffer to the specified type // May replace the buffer with a new one, if necessary AudioError AudioTypeChannel:: Convert( AudioBuffer*& inbuf, // data buffer to process AudioHdr outhdr) // target header { AudioBuffer* outbuf; AudioHdr inhdr; AudioHdr newhdr; Double length; size_t nsamps; size_t nbytes; int i; int j; int k; int chans; char *cin; char *cout; short *sin; short *sout; AudioError err; long smix; inhdr = inbuf->GetHeader(); length = inbuf->GetLength(); // Make sure we're not being asked to do the impossible or trivial if ((err = inhdr.Validate())) return (err); if ((inhdr.sample_rate != outhdr.sample_rate) || (inhdr.encoding != outhdr.encoding) || (inhdr.samples_per_unit != outhdr.samples_per_unit) || (inhdr.bytes_per_unit != outhdr.bytes_per_unit)) return (AUDIO_ERR_HDRINVAL); if (inhdr.channels == outhdr.channels) return (AUDIO_SUCCESS); if ((inhdr.channels != 1) && (outhdr.channels != 1)) return (AUDIO_ERR_HDRINVAL); if (Undefined(length)) return (AUDIO_ERR_BADARG); // setup header for output buffer newhdr = inhdr; newhdr.channels = outhdr.channels; // XXX - If multi-channel -> mono, must be linear to mix // We need to test for this before trying the conversion! if ((inhdr.channels > 1) && (newhdr.channels == 1)) { if ((inhdr.encoding != LINEAR) || (inhdr.bytes_per_unit > 2)) return (AUDIO_ERR_HDRINVAL); } // Allocate a new buffer outbuf = new AudioBuffer(length, "(Channel conversion buffer)"); if (outbuf == 0) return (AUDIO_UNIXERROR); if (err = outbuf->SetHeader(newhdr)) { delete outbuf; return (err); } // Get the number of sample frames and the size of each nsamps = (size_t)inhdr.Time_to_Samples(length); nbytes = (size_t)inhdr.FrameLength(); chans = inhdr.channels; // multi-channel -> mono conversion if ((chans > 1) && (newhdr.channels == 1)) { switch (inhdr.bytes_per_unit) { case 1: cin = (char *)inbuf->GetAddress(); cout = (char *)outbuf->GetAddress(); for (i = 0; i < nsamps; i++) { smix = 0; for (j = 0; j < chans; j++) { smix += *cin++; } if (smix < -0x7f) { smix = -0x7f; } else if (smix > 0x7f) { smix = 0x7f; } *cout++ = (char)smix; } break; case 2: sin = (short *)inbuf->GetAddress(); sout = (short *)outbuf->GetAddress(); for (i = 0; i < nsamps; i++) { smix = 0; for (j = 0; j < chans; j++) { smix += *sin++; } if (smix < -0x7fff) { smix = -0x7fff; } else if (smix > 0x7fff) { smix = 0x7fff; } *sout++ = (short)smix; } break; default: err = AUDIO_ERR_HDRINVAL; } } else if ((chans == 1) && (newhdr.channels > 1)) { // mono -> multi-channel chans = newhdr.channels; cin = (char *)inbuf->GetAddress(); cout = (char *)outbuf->GetAddress(); // XXX - this could be optimized by special-casing stuff for (i = 0; i < nsamps; i++) { for (j = 0; j < chans; j++) { for (k = 0; k < nbytes; k++) *cout++ = cin[k]; } cin += nbytes; } } if (err) { if (outbuf != inbuf) delete outbuf; return (err); } // This will delete the buffer inbuf->Reference(); inbuf->Dereference(); // Set the valid data length outbuf->SetLength(length); inbuf = outbuf; return (AUDIO_SUCCESS); } AudioError AudioTypeChannel:: Flush( AudioBuffer*& /* buf */) { return (AUDIO_SUCCESS); }