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::
AudioTypeChannel()40 AudioTypeChannel()
41 {
42 }
43
44 // Destructor
45 AudioTypeChannel::
~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::
CanConvert(AudioHdr) const53 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::
Convert(AudioBuffer * & inbuf,AudioHdr outhdr)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 err = outbuf->SetHeader(newhdr);
121 if (err != AUDIO_SUCCESS) {
122 delete outbuf;
123 return (err);
124 }
125
126 // Get the number of sample frames and the size of each
127 nsamps = (size_t)inhdr.Time_to_Samples(length);
128 nbytes = (size_t)inhdr.FrameLength();
129 chans = inhdr.channels;
130
131 // multi-channel -> mono conversion
132 if ((chans > 1) && (newhdr.channels == 1)) {
133 switch (inhdr.bytes_per_unit) {
134 case 1:
135 cin = (char *)inbuf->GetAddress();
136 cout = (char *)outbuf->GetAddress();
137
138 for (i = 0; i < nsamps; i++) {
139 smix = 0;
140 for (j = 0; j < chans; j++) {
141 smix += *cin++;
142 }
143 if (smix < -0x7f) {
144 smix = -0x7f;
145 } else if (smix > 0x7f) {
146 smix = 0x7f;
147 }
148 *cout++ = (char)smix;
149 }
150 break;
151 case 2:
152 sin = (short *)inbuf->GetAddress();
153 sout = (short *)outbuf->GetAddress();
154
155 for (i = 0; i < nsamps; i++) {
156 smix = 0;
157 for (j = 0; j < chans; j++) {
158 smix += *sin++;
159 }
160 if (smix < -0x7fff) {
161 smix = -0x7fff;
162 } else if (smix > 0x7fff) {
163 smix = 0x7fff;
164 }
165 *sout++ = (short)smix;
166 }
167 break;
168 default:
169 err = AUDIO_ERR_HDRINVAL;
170 }
171
172 } else if ((chans == 1) && (newhdr.channels > 1)) {
173 // mono -> multi-channel
174 chans = newhdr.channels;
175 cin = (char *)inbuf->GetAddress();
176 cout = (char *)outbuf->GetAddress();
177
178 // XXX - this could be optimized by special-casing stuff
179 for (i = 0; i < nsamps; i++) {
180 for (j = 0; j < chans; j++) {
181 for (k = 0; k < nbytes; k++)
182 *cout++ = cin[k];
183 }
184 cin += nbytes;
185 }
186 }
187
188 if (err) {
189 if (outbuf != inbuf)
190 delete outbuf;
191 return (err);
192 }
193
194 // This will delete the buffer
195 inbuf->Reference();
196 inbuf->Dereference();
197
198 // Set the valid data length
199 outbuf->SetLength(length);
200 inbuf = outbuf;
201 return (AUDIO_SUCCESS);
202 }
203
204 AudioError AudioTypeChannel::
Flush(AudioBuffer * &)205 Flush(
206 AudioBuffer*& /* buf */)
207 {
208 return (AUDIO_SUCCESS);
209 }
210