xref: /illumos-gate/usr/src/cmd/audio/utilities/AudioTypeMux.cc (revision 7d98732934f32a5f80fe624c9689e8f54dd17ffe)
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) 1992-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 <AudioTypeMux.h>
32 
33 // This is a conversion class for channel multiplex/demultiplex
34 
35 // class AudioTypeMux methods
36 
37 // Constructor
38 AudioTypeMux::
AudioTypeMux()39 AudioTypeMux()
40 {
41 }
42 
43 // Destructor
44 AudioTypeMux::
~AudioTypeMux()45 ~AudioTypeMux()
46 {
47 }
48 
49 // Test conversion possibilities.
50 // Return TRUE if conversion to/from the specified type is possible.
51 Boolean AudioTypeMux::
CanConvert(AudioHdr) const52 CanConvert(
53 	AudioHdr	/* h */) const		// target header
54 {
55 	// XXX - The test is whether we're converting 1->many or many->1
56 	//	This routine needs a to/from argument.
57 	// XXX - What if the format doesn't have fixed-size sample units?
58 	return (TRUE);
59 }
60 
61 // Multiplex or demultiplex.
62 // The buffer pointer should be a NULL-terminated array of buffers if 1-channel
63 AudioError AudioTypeMux::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)64 Convert(
65 	AudioBuffer*&	inbuf,			// data buffer to process
66 	AudioHdr	outhdr)			// target header
67 {
68 	AudioBuffer*	outbuf;
69 	AudioBuffer**	multibuf;
70 	AudioHdr	inhdr;
71 	Double		length;
72 	unsigned int	channels;
73 	size_t		nsamps;
74 	size_t		nbytes;
75 	size_t		unitsz;
76 	unsigned char	**inptrs;
77 	unsigned char	*in;
78 	unsigned char	*out;
79 	int		i;
80 	int		j;
81 	int		k;
82 	AudioError	err;
83 
84 	channels = outhdr.channels;
85 	if (channels == 1) {
86 		inhdr = inbuf->GetHeader();	// Demux multi-channel data
87 		length = inbuf->GetLength();
88 	} else {
89 		multibuf = (AudioBuffer**) inbuf;	// Mux multiple buffers
90 		inhdr = multibuf[0]->GetHeader();
91 		length = multibuf[0]->GetLength();
92 	}
93 
94 	// Make sure we're not being asked to do the impossible or trivial
95 	if ((err = inhdr.Validate()))
96 		return (err);
97 	if ((inhdr.sample_rate != outhdr.sample_rate) ||
98 	    (inhdr.encoding != outhdr.encoding) ||
99 	    (inhdr.samples_per_unit != outhdr.samples_per_unit) ||
100 	    (inhdr.bytes_per_unit != outhdr.bytes_per_unit))
101 		return (AUDIO_ERR_HDRINVAL);
102 	if (inhdr.channels == outhdr.channels)
103 		return (AUDIO_SUCCESS);
104 	if ((inhdr.channels != 1) && (outhdr.channels != 1))
105 		return (AUDIO_ERR_HDRINVAL);
106 	if (Undefined(length))
107 		return (AUDIO_ERR_BADARG);
108 
109 	// Get the number of sample frames and the size of each
110 	nsamps = (size_t)inhdr.Time_to_Samples(length);
111 	nbytes = (size_t)inhdr.FrameLength();
112 	unitsz = (size_t)inhdr.bytes_per_unit;
113 
114 	// Figure out if we're multiplexing or demultiplexing
115 	if (channels == 1) {
116 		// Demultiplex multi-channel data into several mono channels
117 
118 		// Allocate buffer pointer array and each buffer
119 		channels = inhdr.channels;
120 		multibuf = (AudioBuffer**)
121 		    calloc((channels + 1), sizeof (AudioBuffer*));
122 		for (i = 0; i < channels; i++) {
123 			multibuf[i] = new AudioBuffer(length,
124 			    "(Demultiplex conversion buffer)");
125 			if (multibuf[i] == 0) {
126 				err = AUDIO_UNIXERROR;
127 				goto cleanup;
128 			}
129 			err = multibuf[i]->SetHeader(outhdr);
130 			if (err != AUDIO_SUCCESS) {
131 				delete multibuf[i];
132 cleanup:			while (--i >= 0) {
133 					delete multibuf[i];
134 				}
135 				delete multibuf;
136 				return (err);
137 			}
138 		}
139 		multibuf[i] = NULL;
140 
141 		for (i = 0; i < channels; i++) {
142 			// Get output pointer and input channel pointer
143 			out = (unsigned char *)multibuf[i]->GetAddress();
144 			in = (unsigned char *)inbuf->GetAddress();
145 			in += (i * unitsz);
146 
147 			// Copy a sample unit and bump the input pointer
148 			for (j = 0; j < nsamps; j++) {
149 				for (k = 0; k < unitsz; k++) {
150 					*out++ = *in++;
151 				}
152 				in += ((channels - 1) * unitsz);
153 			}
154 
155 			// Set the valid data length
156 			multibuf[i]->SetLength(length);
157 		}
158 		// Release the input buffer
159 		inbuf->Reference();
160 		inbuf->Dereference();
161 
162 		// Return the array pointer (callers beware!)
163 		inbuf = (AudioBuffer*) multibuf;
164 
165 	} else {
166 		// Multiplex several mono channels into multi-channel data
167 
168 		// Allocate an output buffer
169 		outbuf = new AudioBuffer(length,
170 		    "(Multiplex conversion buffer)");
171 		if (outbuf == 0)
172 			return (AUDIO_UNIXERROR);
173 		err = outbuf->SetHeader(outhdr);
174 		if (err != AUDIO_SUCCESS) {
175 			delete outbuf;
176 			return (err);
177 		}
178 
179 		// Verify the input pointer is an array of buffer pointers
180 		multibuf = (AudioBuffer**) inbuf;
181 		for (channels = 0; ; channels++) {
182 			// Look for NULL termination
183 			if (multibuf[channels] == NULL)
184 				break;
185 			if (!multibuf[channels]->isBuffer())
186 				return (AUDIO_ERR_BADARG);
187 		}
188 		if (channels != outhdr.channels)
189 			return (AUDIO_ERR_BADARG);
190 
191 		// Allocate a bunch of input pointers
192 		inptrs = (unsigned char **)
193 		    calloc(channels, sizeof (unsigned char *));
194 		for (i = 0; i < channels; i++) {
195 			inptrs[i] = (unsigned char *) multibuf[i]->GetAddress();
196 		}
197 
198 		// Get output pointer
199 		out = (unsigned char *)outbuf->GetAddress();
200 
201 		for (i = 0; i < nsamps; i++) {
202 			// Copy a sample frame from each input buffer
203 			for (j = 0; j < channels; j++) {
204 				in = inptrs[j];
205 				for (k = 0; k < nbytes; k++) {
206 					*out++ = *in++;
207 				}
208 				inptrs[j] = in;
209 			}
210 		}
211 		// Set the valid data length
212 		outbuf->SetLength(length);
213 
214 		// Release the input buffers and pointer arrays
215 		for (i = 0; i < channels; i++) {
216 			multibuf[i]->Reference();
217 			multibuf[i]->Dereference();
218 			multibuf[i] = NULL;
219 		}
220 		delete multibuf;
221 		delete inptrs;
222 
223 		// Set the valid data length and return the new pointer
224 		outbuf->SetLength(length);
225 		inbuf = outbuf;
226 	}
227 	return (AUDIO_SUCCESS);
228 }
229 
230 AudioError AudioTypeMux::
Flush(AudioBuffer * &)231 Flush(
232 	AudioBuffer*&	/* buf */)
233 {
234 	return (AUDIO_SUCCESS);
235 }
236