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::
AudioTypeChannel()42 AudioTypeChannel()
43 {
44 }
45
46 // Destructor
47 AudioTypeChannel::
~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::
CanConvert(AudioHdr) const55 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::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)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::
Flush(AudioBuffer * &)206 Flush(
207 AudioBuffer*& /* buf */)
208 {
209 return (AUDIO_SUCCESS);
210 }
211