1 /*
2 * audio-sgi.cc --
3 *
4 * FIXME: This file needs a description here.
5 *
6 * Copyright (c) 1991-2002 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 static const char rcsid[] =
35 "@(#) $Header: /usr/mash/src/repository/mash/mash-1/audio/audio-sgi.cc,v 1.9 2002/02/03 03:10:46 lim Exp $";
36
37 #include "config.h"
38 #define _BSD_COMPAT 1
39 #include "tclcl.h"
40
41 /*
42 * We have AF/audio.h, ./audio.h and /usr/include/audio.h. Crimony.
43 */
44 #include </usr/include/audio.h>
45 #include "audio.h"
46
47 class SGIAudio : public Audio {
48 public:
49 SGIAudio();
50 virtual int FrameReady();
51 virtual u_char* Read();
52 virtual void Write(u_char *);
53 virtual void SetRGain(int);
54 virtual void SetPGain(int);
55 virtual void InputPort(int);
56 virtual void Obtain();
57 virtual void Release();
58 protected:
59 int GainClip(int);
60
61 u_int lastsamp_;
62 u_int lastout_;
63 u_char* buf_;
64 ALport in;
65 ALport out;
66 ALconfig conf;
67 };
68
69
70 extern const u_char lintomulawX[];
71 extern const short mulawtolin[];
72
73
74 #define AUDIO_MIN_GAIN 0
75 #define AUDIO_MAX_GAIN 255
76
77 static class SGIAudioClass : public TclClass {
78 public:
79 SGIAudioClass() : TclClass("Audio/SGI") {}
80 TclObject* create(int argc, const char*const* argv) {
81 return (new SGIAudio);
82 }
83 } sgiaudio_class;
84
85 SGIAudio::SGIAudio()
86 {
87 /* open (or create) the lock file */
88 openlock();
89 conf = ALnewconfig();
90 ALsetwidth(conf, AL_SAMPLE_16);
91 ALsetqueuesize(conf, 8000);
92 ALsetchannels(conf, AL_MONO);
93 fd_ = -1;
94 lastout_ = 0;
95 lastsamp_ = 0;
96 buf_ = new u_char[blksize_];
97
98 input_names_ = "mike linein";
99 output_names_ = "speaker";
100 }
101
102 void SGIAudio::Release()
103 {
104 if (haveaudio()) {
105 unlock();
106 unlink();
107 fd_ = -1;
108 ALcloseport(in);
109 ALcloseport(out);
110 notify();
111 }
112 }
113
114 void SGIAudio::Obtain()
115 {
116 if (haveaudio())
117 abort();
118
119 if (lock() == 0) {
120 out = ALopenport("vatOut", "w", conf);
121 if (out == NULL) {
122 fprintf(stderr,
123 "vat: couldn't open AL output port.\n");
124 return;
125 }
126 in = ALopenport("vatIn", "r", conf);
127 if (in == NULL) {
128 fprintf(stderr,
129 "vat: couldn't open AL input port.\n");
130 return;
131 }
132 ALsetfillpoint(in, 160);
133 long pvbuf[6];
134 pvbuf[0] = AL_INPUT_RATE;
135 pvbuf[1] = 8000;
136 pvbuf[2] = AL_OUTPUT_RATE;
137 pvbuf[3] = 8000;
138 pvbuf[4] = AL_INPUT_SOURCE;
139 pvbuf[5] = iport_? AL_INPUT_LINE : AL_INPUT_MIC;
140 ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 6);
141 fd_ = ALgetfd(in);
142 SetRGain(rgain_);
143 SetPGain(pgain_);
144 Audio::Obtain();
145 }
146 }
147
148 void SGIAudio::Write(u_char *cp)
149 {
150 register int len = blksize_;
151 u_int samps[MAXAUDIOSIZE/2];
152 register u_int* sp = samps;
153 register u_int* ep = sp + len / 2;
154 register const u_short* u2l = (u_short*)mulawtolin;
155 register u_int* ip = (u_int*)cp;
156 for ( ; sp < ep; sp += 4) {
157 register u_int s = *ip++;
158 sp[0] = (u2l[(s >> 24) & 0xff] << 16) | u2l[(s >> 16) & 0xff];
159 sp[1] = (u2l[(s >> 8) & 0xff] << 16) | u2l[s & 0xff];
160 s = *ip++;
161 sp[2] = (u2l[(s >> 24) & 0xff] << 16) | u2l[(s >> 16) & 0xff];
162 sp[3] = (u2l[(s >> 8) & 0xff] << 16) | u2l[s & 0xff];
163 }
164 ALwritesamps(out, samps, len);
165 }
166
167 int SGIAudio::FrameReady()
168 {
169 return (ALgetfilled(in) >= blksize_);
170 }
171
172 u_char* SGIAudio::Read()
173 {
174 register long len = blksize_;
175 u_char* cp = buf_;
176
177 /*
178 * for some reason, SGI didn't bother to filter out the
179 * mike 'phantom power' DC signal (god forbid they should
180 * use the Indigo DSP for anything or invest a dime in
181 * transformer coupling the mike) so we end up with a
182 * large DC offset that screws up the lin-to-mu conversion
183 * and the speakerphone power calculations. So all the
184 * extra junk in the following loop is a low pass filter
185 * to estimate the DC bias & remove it.
186 *
187 * The multiply by 2 on the samples is because SGI maps
188 * stereo to mono by doing (L+R)/2 rather than clip(L+R).
189 * Since the mikes they ship are mono, this effectively
190 * cuts the mike gain by a factor of two. We can't
191 * restore the 1 bit of dynamic range they throw away
192 * but we jack the gain back up where is should be.
193 */
194 short samps[MAXAUDIOSIZE];
195 register short* sp = samps;
196 ALreadsamps(in, sp, len);
197 register short* ep = sp + len;
198 register const u_char* l2u = lintomulawX;
199 register u_int* ip = (u_int*)cp;
200 register int smean = lastsamp_;
201 for ( ; sp < ep; sp += 4) {
202 register int mean, dif;
203 register u_int res;
204 register int s0 = sp[0] << 1;
205 register int s1 = sp[1] << 1;
206 register int s2 = sp[2] << 1;
207 register int s3 = sp[3] << 1;
208
209 mean = smean >> 13;
210 dif = s0 - mean;
211 smean += dif;
212 res = l2u[dif & 0x1ffff] << 24;
213
214 mean = smean >> 13;
215 dif = s1 - mean;
216 smean += dif;
217 res |= l2u[dif & 0x1ffff] << 16;
218
219 mean = smean >> 13;
220 dif = s2 - mean;
221 smean += dif;
222 res |= l2u[dif & 0x1ffff] << 8;
223
224 mean = smean >> 13;
225 dif = s3 - mean;
226 smean += dif;
227 res |= l2u[dif & 0x1ffff];
228
229 *ip++ = res;
230 }
231 lastsamp_ = smean;
232 return (cp);
233 }
234
235 int SGIAudio::GainClip(int level)
236 {
237 if (level < AUDIO_MIN_GAIN)
238 return AUDIO_MIN_GAIN;
239 else if (level > AUDIO_MAX_GAIN)
240 return AUDIO_MAX_GAIN;
241 else
242 return level;
243 }
244
245 void SGIAudio::SetRGain(int level)
246 {
247 rgain_ = GainClip(level);
248 if (fd_ >= 0) {
249 static long atten[] = { 34, 37, 40, 45, 50, 55, 63 };
250 long pvbuf[4];
251 int index = ((255 - rgain_) * 39) / 255;
252 pvbuf[3] = pvbuf[1] = (index > 32) ?
253 (atten[index-33] << 2) : (index << 2);
254 pvbuf[0] = AL_LEFT_INPUT_ATTEN;
255 pvbuf[2] = AL_RIGHT_INPUT_ATTEN;
256 ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 4);
257 }
258 }
259
260 void SGIAudio::SetPGain(int level)
261 {
262 pgain_ = GainClip(level);
263 if (fd_ >= 0) {
264 long pvbuf[4];
265 #ifdef SGI_COMPAT
266 float gain = pgain_ <= 0?
267 0.
268 : pow(10.0, float(pgain_)*(2.406540183/255.)) + 0.5;
269 pvbuf[3] = pvbuf[1] = long(gain);
270 #else
271 pvbuf[3] = pvbuf[1] = long(pgain_);
272 #endif
273 pvbuf[0] = AL_LEFT_SPEAKER_GAIN;
274 pvbuf[2] = AL_RIGHT_SPEAKER_GAIN;
275 ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 4);
276 }
277 }
278
279 void SGIAudio::InputPort(int p)
280 {
281 iport_ = p;
282 if (fd_ >= 0) {
283 long pvbuf[2];
284 pvbuf[0] = AL_INPUT_SOURCE;
285 pvbuf[1] = iport_? AL_INPUT_LINE : AL_INPUT_MIC;
286 ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2);
287 }
288 }
289
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.