5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.media.sound;
26
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31
32 import javax.sound.sampled.AudioFormat;
33 import javax.sound.sampled.AudioSystem;
34 import javax.sound.sampled.BooleanControl;
35 import javax.sound.sampled.Control;
36 import javax.sound.sampled.DataLine;
37 import javax.sound.sampled.FloatControl;
38 import javax.sound.sampled.LineEvent;
39 import javax.sound.sampled.LineListener;
40 import javax.sound.sampled.Control.Type;
41
42 /**
43 * General software mixing line.
44 *
45 * @author Karl Helgason
46 */
47 public abstract class SoftMixingDataLine implements DataLine {
48
49 public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
50 "Chorus Send") {
51 };
52
53 protected static final class AudioFloatInputStreamResampler extends
54 AudioFloatInputStream {
55
56 private final AudioFloatInputStream ais;
57
58 private final AudioFormat targetFormat;
59
60 private float[] skipbuffer;
113 this.resampler = new SoftLinearResampler2();
114 if (resamplerType.equalsIgnoreCase("cubic"))
115 this.resampler = new SoftCubicResampler();
116 if (resamplerType.equalsIgnoreCase("lanczos"))
117 this.resampler = new SoftLanczosResampler();
118 if (resamplerType.equalsIgnoreCase("sinc"))
119 this.resampler = new SoftSincResampler();
120 }
121 if (resampler == null)
122 resampler = new SoftLinearResampler2(); // new
123 // SoftLinearResampler2();
124 pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
125 pad = resampler.getPadding();
126 pad2 = pad * 2;
127 ibuffer = new float[nrofchannels][buffer_len + pad2];
128 ibuffer2 = new float[nrofchannels * buffer_len];
129 ibuffer_index = buffer_len + pad;
130 ibuffer_len = buffer_len;
131 }
132
133 public int available() throws IOException {
134 return 0;
135 }
136
137 public void close() throws IOException {
138 ais.close();
139 }
140
141 public AudioFormat getFormat() {
142 return targetFormat;
143 }
144
145 public long getFrameLength() {
146 return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength();
147 }
148
149 public void mark(int readlimit) {
150 ais.mark((int) (readlimit * pitch[0]));
151 mark_ibuffer_index = ibuffer_index;
152 mark_ibuffer_len = ibuffer_len;
153 if (mark_ibuffer == null) {
154 mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
155 }
156 for (int c = 0; c < ibuffer.length; c++) {
157 float[] from = ibuffer[c];
158 float[] to = mark_ibuffer[c];
159 for (int i = 0; i < to.length; i++) {
160 to[i] = from[i];
161 }
162 }
163 }
164
165 public boolean markSupported() {
166 return ais.markSupported();
167 }
168
169 private void readNextBuffer() throws IOException {
170
171 if (ibuffer_len == -1)
172 return;
173
174 for (int c = 0; c < nrofchannels; c++) {
175 float[] buff = ibuffer[c];
176 int buffer_len_pad = ibuffer_len + pad2;
177 for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
178 buff[ix] = buff[i];
179 }
180 }
181
182 ibuffer_index -= (ibuffer_len);
183
184 ibuffer_len = ais.read(ibuffer2);
189 if (ret == -1)
190 break;
191 ibuffer_len += ret;
192 }
193 Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
194 ibuffer_len /= nrofchannels;
195 } else {
196 Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
197 }
198
199 int ibuffer2_len = ibuffer2.length;
200 for (int c = 0; c < nrofchannels; c++) {
201 float[] buff = ibuffer[c];
202 for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
203 buff[ix] = ibuffer2[i];
204 }
205 }
206
207 }
208
209 public int read(float[] b, int off, int len) throws IOException {
210
211 if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
212 cbuffer = new float[nrofchannels][len / nrofchannels];
213 }
214 if (ibuffer_len == -1)
215 return -1;
216 if (len < 0)
217 return 0;
218 int remain = len / nrofchannels;
219 int destPos = 0;
220 int in_end = ibuffer_len;
221 while (remain > 0) {
222 if (ibuffer_len >= 0) {
223 if (ibuffer_index >= (ibuffer_len + pad))
224 readNextBuffer();
225 in_end = ibuffer_len + pad;
226 }
227
228 if (ibuffer_len < 0) {
238 ix[0] = ibuffer_index;
239 ox[0] = destPos;
240 float[] buff = ibuffer[c];
241 resampler.interpolate(buff, ix, in_end, pitch, 0,
242 cbuffer[c], ox, len / nrofchannels);
243 }
244 ibuffer_index = ix[0];
245 destPos = ox[0];
246 remain -= destPos - preDestPos;
247 }
248 for (int c = 0; c < nrofchannels; c++) {
249 int ix = 0;
250 float[] buff = cbuffer[c];
251 for (int i = c; i < b.length; i += nrofchannels) {
252 b[i] = buff[ix++];
253 }
254 }
255 return len - remain * nrofchannels;
256 }
257
258 public void reset() throws IOException {
259 ais.reset();
260 if (mark_ibuffer == null)
261 return;
262 ibuffer_index = mark_ibuffer_index;
263 ibuffer_len = mark_ibuffer_len;
264 for (int c = 0; c < ibuffer.length; c++) {
265 float[] from = mark_ibuffer[c];
266 float[] to = ibuffer[c];
267 for (int i = 0; i < to.length; i++) {
268 to[i] = from[i];
269 }
270 }
271
272 }
273
274 public long skip(long len) throws IOException {
275 if (len > 0)
276 return 0;
277 if (skipbuffer == null)
278 skipbuffer = new float[1024 * targetFormat.getFrameSize()];
279 float[] l_skipbuffer = skipbuffer;
280 long remain = len;
281 while (remain > 0) {
282 int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
283 skipbuffer.length));
284 if (ret < 0) {
285 if (remain == len)
286 return ret;
287 break;
288 }
289 remain -= ret;
290 }
291 return len - remain;
292
293 }
294
295 }
296
297 private final class Gain extends FloatControl {
298
299 private Gain() {
300
301 super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
302 -1, 0.0f, "dB", "Minimum", "", "Maximum");
303 }
304
305 public void setValue(float newValue) {
306 super.setValue(newValue);
307 calcVolume();
308 }
309 }
310
311 private final class Mute extends BooleanControl {
312
313 private Mute() {
314 super(BooleanControl.Type.MUTE, false, "True", "False");
315 }
316
317 public void setValue(boolean newValue) {
318 super.setValue(newValue);
319 calcVolume();
320 }
321 }
322
323 private final class ApplyReverb extends BooleanControl {
324
325 private ApplyReverb() {
326 super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
327 }
328
329 public void setValue(boolean newValue) {
330 super.setValue(newValue);
331 calcVolume();
332 }
333
334 }
335
336 private final class Balance extends FloatControl {
337
338 private Balance() {
339 super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
340 0.0f, "", "Left", "Center", "Right");
341 }
342
343 public void setValue(float newValue) {
344 super.setValue(newValue);
345 calcVolume();
346 }
347
348 }
349
350 private final class Pan extends FloatControl {
351
352 private Pan() {
353 super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
354 0.0f, "", "Left", "Center", "Right");
355 }
356
357 public void setValue(float newValue) {
358 super.setValue(newValue);
359 balance_control.setValue(newValue);
360 }
361
362 public float getValue() {
363 return balance_control.getValue();
364 }
365
366 }
367
368 private final class ReverbSend extends FloatControl {
369
370 private ReverbSend() {
371 super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
372 -1, -80f, "dB", "Minimum", "", "Maximum");
373 }
374
375 public void setValue(float newValue) {
376 super.setValue(newValue);
377 balance_control.setValue(newValue);
378 }
379
380 }
381
382 private final class ChorusSend extends FloatControl {
383
384 private ChorusSend() {
385 super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
386 "Minimum", "", "Maximum");
387 }
388
389 public void setValue(float newValue) {
390 super.setValue(newValue);
391 balance_control.setValue(newValue);
392 }
393
394 }
395
396 private final Gain gain_control = new Gain();
397
398 private final Mute mute_control = new Mute();
399
400 private final Balance balance_control = new Balance();
401
402 private final Pan pan_control = new Pan();
403
404 private final ReverbSend reverbsend_control = new ReverbSend();
405
406 private final ChorusSend chorussend_control = new ChorusSend();
407
408 private final ApplyReverb apply_reverb = new ApplyReverb();
409
410 private final Control[] controls;
411
412 float leftgain = 1;
413
414 float rightgain = 1;
415
416 float eff1gain = 0;
417
418 float eff2gain = 0;
419
420 List<LineListener> listeners = new ArrayList<LineListener>();
421
422 final Object control_mutex;
423
424 SoftMixingMixer mixer;
425
426 DataLine.Info info;
427
428 protected abstract void processControlLogic();
429
430 protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
431
432 SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
433 this.mixer = mixer;
434 this.info = info;
435 this.control_mutex = mixer.control_mutex;
436
437 controls = new Control[] { gain_control, mute_control, balance_control,
438 pan_control, reverbsend_control, chorussend_control,
439 apply_reverb };
440 calcVolume();
459 }
460
461 eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
462 eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);
463
464 if (!apply_reverb.getValue()) {
465 eff1gain = 0;
466 }
467 }
468
469 final void sendEvent(LineEvent event) {
470 if (listeners.size() == 0)
471 return;
472 LineListener[] listener_array = listeners
473 .toArray(new LineListener[listeners.size()]);
474 for (LineListener listener : listener_array) {
475 listener.update(event);
476 }
477 }
478
479 public final void addLineListener(LineListener listener) {
480 synchronized (control_mutex) {
481 listeners.add(listener);
482 }
483 }
484
485 public final void removeLineListener(LineListener listener) {
486 synchronized (control_mutex) {
487 listeners.add(listener);
488 }
489 }
490
491 public final javax.sound.sampled.Line.Info getLineInfo() {
492 return info;
493 }
494
495 public final Control getControl(Type control) {
496 if (control != null) {
497 for (int i = 0; i < controls.length; i++) {
498 if (controls[i].getType() == control) {
499 return controls[i];
500 }
501 }
502 }
503 throw new IllegalArgumentException("Unsupported control type : "
504 + control);
505 }
506
507 public final Control[] getControls() {
508 return Arrays.copyOf(controls, controls.length);
509 }
510
511 public final boolean isControlSupported(Type control) {
512 if (control != null) {
513 for (int i = 0; i < controls.length; i++) {
514 if (controls[i].getType() == control) {
515 return true;
516 }
517 }
518 }
519 return false;
520 }
521
522 }
|
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.media.sound;
27
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.List;
32
33 import javax.sound.sampled.AudioFormat;
34 import javax.sound.sampled.AudioSystem;
35 import javax.sound.sampled.BooleanControl;
36 import javax.sound.sampled.Control;
37 import javax.sound.sampled.Control.Type;
38 import javax.sound.sampled.DataLine;
39 import javax.sound.sampled.FloatControl;
40 import javax.sound.sampled.LineEvent;
41 import javax.sound.sampled.LineListener;
42
43 /**
44 * General software mixing line.
45 *
46 * @author Karl Helgason
47 */
48 public abstract class SoftMixingDataLine implements DataLine {
49
50 public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
51 "Chorus Send") {
52 };
53
54 protected static final class AudioFloatInputStreamResampler extends
55 AudioFloatInputStream {
56
57 private final AudioFloatInputStream ais;
58
59 private final AudioFormat targetFormat;
60
61 private float[] skipbuffer;
114 this.resampler = new SoftLinearResampler2();
115 if (resamplerType.equalsIgnoreCase("cubic"))
116 this.resampler = new SoftCubicResampler();
117 if (resamplerType.equalsIgnoreCase("lanczos"))
118 this.resampler = new SoftLanczosResampler();
119 if (resamplerType.equalsIgnoreCase("sinc"))
120 this.resampler = new SoftSincResampler();
121 }
122 if (resampler == null)
123 resampler = new SoftLinearResampler2(); // new
124 // SoftLinearResampler2();
125 pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
126 pad = resampler.getPadding();
127 pad2 = pad * 2;
128 ibuffer = new float[nrofchannels][buffer_len + pad2];
129 ibuffer2 = new float[nrofchannels * buffer_len];
130 ibuffer_index = buffer_len + pad;
131 ibuffer_len = buffer_len;
132 }
133
134 @Override
135 public int available() throws IOException {
136 return 0;
137 }
138
139 @Override
140 public void close() throws IOException {
141 ais.close();
142 }
143
144 @Override
145 public AudioFormat getFormat() {
146 return targetFormat;
147 }
148
149 @Override
150 public long getFrameLength() {
151 return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength();
152 }
153
154 @Override
155 public void mark(int readlimit) {
156 ais.mark((int) (readlimit * pitch[0]));
157 mark_ibuffer_index = ibuffer_index;
158 mark_ibuffer_len = ibuffer_len;
159 if (mark_ibuffer == null) {
160 mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
161 }
162 for (int c = 0; c < ibuffer.length; c++) {
163 float[] from = ibuffer[c];
164 float[] to = mark_ibuffer[c];
165 for (int i = 0; i < to.length; i++) {
166 to[i] = from[i];
167 }
168 }
169 }
170
171 @Override
172 public boolean markSupported() {
173 return ais.markSupported();
174 }
175
176 private void readNextBuffer() throws IOException {
177
178 if (ibuffer_len == -1)
179 return;
180
181 for (int c = 0; c < nrofchannels; c++) {
182 float[] buff = ibuffer[c];
183 int buffer_len_pad = ibuffer_len + pad2;
184 for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
185 buff[ix] = buff[i];
186 }
187 }
188
189 ibuffer_index -= (ibuffer_len);
190
191 ibuffer_len = ais.read(ibuffer2);
196 if (ret == -1)
197 break;
198 ibuffer_len += ret;
199 }
200 Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
201 ibuffer_len /= nrofchannels;
202 } else {
203 Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
204 }
205
206 int ibuffer2_len = ibuffer2.length;
207 for (int c = 0; c < nrofchannels; c++) {
208 float[] buff = ibuffer[c];
209 for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
210 buff[ix] = ibuffer2[i];
211 }
212 }
213
214 }
215
216 @Override
217 public int read(float[] b, int off, int len) throws IOException {
218
219 if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
220 cbuffer = new float[nrofchannels][len / nrofchannels];
221 }
222 if (ibuffer_len == -1)
223 return -1;
224 if (len < 0)
225 return 0;
226 int remain = len / nrofchannels;
227 int destPos = 0;
228 int in_end = ibuffer_len;
229 while (remain > 0) {
230 if (ibuffer_len >= 0) {
231 if (ibuffer_index >= (ibuffer_len + pad))
232 readNextBuffer();
233 in_end = ibuffer_len + pad;
234 }
235
236 if (ibuffer_len < 0) {
246 ix[0] = ibuffer_index;
247 ox[0] = destPos;
248 float[] buff = ibuffer[c];
249 resampler.interpolate(buff, ix, in_end, pitch, 0,
250 cbuffer[c], ox, len / nrofchannels);
251 }
252 ibuffer_index = ix[0];
253 destPos = ox[0];
254 remain -= destPos - preDestPos;
255 }
256 for (int c = 0; c < nrofchannels; c++) {
257 int ix = 0;
258 float[] buff = cbuffer[c];
259 for (int i = c; i < b.length; i += nrofchannels) {
260 b[i] = buff[ix++];
261 }
262 }
263 return len - remain * nrofchannels;
264 }
265
266 @Override
267 public void reset() throws IOException {
268 ais.reset();
269 if (mark_ibuffer == null)
270 return;
271 ibuffer_index = mark_ibuffer_index;
272 ibuffer_len = mark_ibuffer_len;
273 for (int c = 0; c < ibuffer.length; c++) {
274 float[] from = mark_ibuffer[c];
275 float[] to = ibuffer[c];
276 for (int i = 0; i < to.length; i++) {
277 to[i] = from[i];
278 }
279 }
280
281 }
282
283 @Override
284 public long skip(long len) throws IOException {
285 if (len > 0)
286 return 0;
287 if (skipbuffer == null)
288 skipbuffer = new float[1024 * targetFormat.getFrameSize()];
289 float[] l_skipbuffer = skipbuffer;
290 long remain = len;
291 while (remain > 0) {
292 int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
293 skipbuffer.length));
294 if (ret < 0) {
295 if (remain == len)
296 return ret;
297 break;
298 }
299 remain -= ret;
300 }
301 return len - remain;
302
303 }
304
305 }
306
307 private final class Gain extends FloatControl {
308
309 private Gain() {
310
311 super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
312 -1, 0.0f, "dB", "Minimum", "", "Maximum");
313 }
314
315 @Override
316 public void setValue(float newValue) {
317 super.setValue(newValue);
318 calcVolume();
319 }
320 }
321
322 private final class Mute extends BooleanControl {
323
324 private Mute() {
325 super(BooleanControl.Type.MUTE, false, "True", "False");
326 }
327
328 @Override
329 public void setValue(boolean newValue) {
330 super.setValue(newValue);
331 calcVolume();
332 }
333 }
334
335 private final class ApplyReverb extends BooleanControl {
336
337 private ApplyReverb() {
338 super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
339 }
340
341 @Override
342 public void setValue(boolean newValue) {
343 super.setValue(newValue);
344 calcVolume();
345 }
346
347 }
348
349 private final class Balance extends FloatControl {
350
351 private Balance() {
352 super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
353 0.0f, "", "Left", "Center", "Right");
354 }
355
356 @Override
357 public void setValue(float newValue) {
358 super.setValue(newValue);
359 calcVolume();
360 }
361
362 }
363
364 private final class Pan extends FloatControl {
365
366 private Pan() {
367 super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
368 0.0f, "", "Left", "Center", "Right");
369 }
370
371 @Override
372 public void setValue(float newValue) {
373 super.setValue(newValue);
374 balance_control.setValue(newValue);
375 }
376
377 @Override
378 public float getValue() {
379 return balance_control.getValue();
380 }
381
382 }
383
384 private final class ReverbSend extends FloatControl {
385
386 private ReverbSend() {
387 super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
388 -1, -80f, "dB", "Minimum", "", "Maximum");
389 }
390
391 @Override
392 public void setValue(float newValue) {
393 super.setValue(newValue);
394 balance_control.setValue(newValue);
395 }
396
397 }
398
399 private final class ChorusSend extends FloatControl {
400
401 private ChorusSend() {
402 super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
403 "Minimum", "", "Maximum");
404 }
405
406 @Override
407 public void setValue(float newValue) {
408 super.setValue(newValue);
409 balance_control.setValue(newValue);
410 }
411
412 }
413
414 private final Gain gain_control = new Gain();
415
416 private final Mute mute_control = new Mute();
417
418 private final Balance balance_control = new Balance();
419
420 private final Pan pan_control = new Pan();
421
422 private final ReverbSend reverbsend_control = new ReverbSend();
423
424 private final ChorusSend chorussend_control = new ChorusSend();
425
426 private final ApplyReverb apply_reverb = new ApplyReverb();
427
428 private final Control[] controls;
429
430 float leftgain = 1;
431
432 float rightgain = 1;
433
434 float eff1gain = 0;
435
436 float eff2gain = 0;
437
438 List<LineListener> listeners = new ArrayList<>();
439
440 final Object control_mutex;
441
442 SoftMixingMixer mixer;
443
444 DataLine.Info info;
445
446 protected abstract void processControlLogic();
447
448 protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
449
450 SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
451 this.mixer = mixer;
452 this.info = info;
453 this.control_mutex = mixer.control_mutex;
454
455 controls = new Control[] { gain_control, mute_control, balance_control,
456 pan_control, reverbsend_control, chorussend_control,
457 apply_reverb };
458 calcVolume();
477 }
478
479 eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
480 eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);
481
482 if (!apply_reverb.getValue()) {
483 eff1gain = 0;
484 }
485 }
486
487 final void sendEvent(LineEvent event) {
488 if (listeners.size() == 0)
489 return;
490 LineListener[] listener_array = listeners
491 .toArray(new LineListener[listeners.size()]);
492 for (LineListener listener : listener_array) {
493 listener.update(event);
494 }
495 }
496
497 @Override
498 public final void addLineListener(LineListener listener) {
499 synchronized (control_mutex) {
500 listeners.add(listener);
501 }
502 }
503
504 @Override
505 public final void removeLineListener(LineListener listener) {
506 synchronized (control_mutex) {
507 listeners.add(listener);
508 }
509 }
510
511 @Override
512 public final javax.sound.sampled.Line.Info getLineInfo() {
513 return info;
514 }
515
516 @Override
517 public final Control getControl(Type control) {
518 if (control != null) {
519 for (int i = 0; i < controls.length; i++) {
520 if (controls[i].getType() == control) {
521 return controls[i];
522 }
523 }
524 }
525 throw new IllegalArgumentException("Unsupported control type : "
526 + control);
527 }
528
529 @Override
530 public final Control[] getControls() {
531 return Arrays.copyOf(controls, controls.length);
532 }
533
534 @Override
535 public final boolean isControlSupported(Type control) {
536 if (control != null) {
537 for (int i = 0; i < controls.length; i++) {
538 if (controls[i].getType() == control) {
539 return true;
540 }
541 }
542 }
543 return false;
544 }
545 }
|