1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
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.  Sun designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22  * CA 95054 USA or visit www.sun.com if you need additional information or
23  * have any questions.
24  */
25 package com.sun.media.sound;
26 
27 import java.io.IOException;
28 import java.util.Arrays;
29 import java.util.HashMap;
30 import java.util.Map;
31 
32 import javax.sound.midi.VoiceStatus;
33 
34 /**
35  * Software synthesizer voice class.
36  *
37  * @author Karl Helgason
38  */
39 public class SoftVoice extends VoiceStatus {
40 
41     public int exclusiveClass = 0;
42     public boolean releaseTriggered = false;
43     private int noteOn_noteNumber = 0;
44     private int noteOn_velocity = 0;
45     private int noteOff_velocity = 0;
46     protected ModelChannelMixer channelmixer = null;
47     protected double tunedKey = 0;
48     protected SoftTuning tuning = null;
49     protected SoftChannel stealer_channel = null;
50     protected ModelConnectionBlock[] stealer_extendedConnectionBlocks = null;
51     protected SoftPerformer stealer_performer = null;
52     protected ModelChannelMixer stealer_channelmixer = null;
53     protected int stealer_voiceID = -1;
54     protected int stealer_noteNumber = 0;
55     protected int stealer_velocity = 0;
56     protected boolean stealer_releaseTriggered = false;
57     protected int voiceID = -1;
58     protected boolean sustain = false;
59     protected boolean sostenuto = false;
60     protected boolean portamento = false;
61     private SoftFilter filter_left;
62     private SoftFilter filter_right;
63     private SoftProcess eg = new SoftEnvelopeGenerator();
64     private SoftProcess lfo = new SoftLowFrequencyOscillator();
65     protected Map<String, SoftControl> objects =
66             new HashMap<String, SoftControl>();
67     protected SoftSynthesizer synthesizer;
68     protected SoftInstrument instrument;
69     protected SoftPerformer performer;
70     protected SoftChannel softchannel = null;
71     protected boolean on = false;
72     private boolean audiostarted = false;
73     private boolean started = false;
74     private boolean stopping = false;
75     private float osc_attenuation = 0.0f;
76     private ModelOscillatorStream osc_stream;
77     private int osc_stream_nrofchannels;
78     private float[][] osc_buff = new float[2][];
79     private boolean osc_stream_off_transmitted = false;
80     private boolean out_mixer_end = false;
81     private float out_mixer_left = 0;
82     private float out_mixer_right = 0;
83     private float out_mixer_effect1 = 0;
84     private float out_mixer_effect2 = 0;
85     private float last_out_mixer_left = 0;
86     private float last_out_mixer_right = 0;
87     private float last_out_mixer_effect1 = 0;
88     private float last_out_mixer_effect2 = 0;
89     protected ModelConnectionBlock[] extendedConnectionBlocks = null;
90     private ModelConnectionBlock[] connections;
91     // Last value added to destination
92     private double[] connections_last = new double[50];
93     // Pointer to source value
94     private double[][][] connections_src = new double[50][3][];
95     // Key-based override (if any)
96     private int[][] connections_src_kc = new int[50][3];
97     // Pointer to destination value
98     private double[][] connections_dst = new double[50][];
99     private boolean soundoff = false;
100     private float lastMuteValue = 0;
101     private float lastSoloMuteValue = 0;
102     protected double[] co_noteon_keynumber = new double[1];
103     protected double[] co_noteon_velocity = new double[1];
104     protected double[] co_noteon_on = new double[1];
105     private SoftControl co_noteon = new SoftControl() {
106         double[] keynumber = co_noteon_keynumber;
107         double[] velocity = co_noteon_velocity;
108         double[] on = co_noteon_on;
109         public double[] get(int instance, String name) {
110             if (name == null)
111                 return null;
112             if (name.equals("keynumber"))
113                 return keynumber;
114             if (name.equals("velocity"))
115                 return velocity;
116             if (name.equals("on"))
117                 return on;
118             return null;
119         }
120     };
121     private double[] co_mixer_active = new double[1];
122     private double[] co_mixer_gain = new double[1];
123     private double[] co_mixer_pan = new double[1];
124     private double[] co_mixer_balance = new double[1];
125     private double[] co_mixer_reverb = new double[1];
126     private double[] co_mixer_chorus = new double[1];
127     private SoftControl co_mixer = new SoftControl() {
128         double[] active = co_mixer_active;
129         double[] gain = co_mixer_gain;
130         double[] pan = co_mixer_pan;
131         double[] balance = co_mixer_balance;
132         double[] reverb = co_mixer_reverb;
133         double[] chorus = co_mixer_chorus;
134         public double[] get(int instance, String name) {
135             if (name == null)
136                 return null;
137             if (name.equals("active"))
138                 return active;
139             if (name.equals("gain"))
140                 return gain;
141             if (name.equals("pan"))
142                 return pan;
143             if (name.equals("balance"))
144                 return balance;
145             if (name.equals("reverb"))
146                 return reverb;
147             if (name.equals("chorus"))
148                 return chorus;
149             return null;
150         }
151     };
152     private double[] co_osc_pitch = new double[1];
153     private SoftControl co_osc = new SoftControl() {
154         double[] pitch = co_osc_pitch;
155         public double[] get(int instance, String name) {
156             if (name == null)
157                 return null;
158             if (name.equals("pitch"))
159                 return pitch;
160             return null;
161         }
162     };
163     private double[] co_filter_freq = new double[1];
164     private double[] co_filter_type = new double[1];
165     private double[] co_filter_q = new double[1];
166     private SoftControl co_filter = new SoftControl() {
167         double[] freq = co_filter_freq;
168         double[] ftype = co_filter_type;
169         double[] q = co_filter_q;
170         public double[] get(int instance, String name) {
171             if (name == null)
172                 return null;
173             if (name.equals("freq"))
174                 return freq;
175             if (name.equals("type"))
176                 return ftype;
177             if (name.equals("q"))
178                 return q;
179             return null;
180         }
181     };
182     protected SoftResamplerStreamer resampler;
183     private int nrofchannels;
184 
SoftVoice(SoftSynthesizer synth)185     public SoftVoice(SoftSynthesizer synth) {
186         synthesizer = synth;
187         filter_left = new SoftFilter(synth.getFormat().getSampleRate());
188         filter_right = new SoftFilter(synth.getFormat().getSampleRate());
189         nrofchannels = synth.getFormat().getChannels();
190     }
191 
getValueKC(ModelIdentifier id)192     private int getValueKC(ModelIdentifier id) {
193         if (id.getObject().equals("midi_cc")) {
194             int ic = Integer.parseInt(id.getVariable());
195             if (ic != 0 && ic != 32) {
196                 if (ic < 120)
197                     return ic;
198             }
199         } else if (id.getObject().equals("midi_rpn")) {
200             if (id.getVariable().equals("1"))
201                 return 120; // Fine tuning
202             if (id.getVariable().equals("2"))
203                 return 121; // Coarse tuning
204         }
205         return -1;
206     }
207 
getValue(ModelIdentifier id)208     private double[] getValue(ModelIdentifier id) {
209         SoftControl o = objects.get(id.getObject());
210         if (o == null)
211             return null;
212         return o.get(id.getInstance(), id.getVariable());
213     }
214 
transformValue(double value, ModelSource src)215     private double transformValue(double value, ModelSource src) {
216         if (src.getTransform() != null)
217             return src.getTransform().transform(value);
218         else
219             return value;
220     }
221 
transformValue(double value, ModelDestination dst)222     private double transformValue(double value, ModelDestination dst) {
223         if (dst.getTransform() != null)
224             return dst.getTransform().transform(value);
225         else
226             return value;
227     }
228 
processKeyBasedController(double value, int keycontrol)229     private double processKeyBasedController(double value, int keycontrol) {
230         if (keycontrol == -1)
231             return value;
232         if (softchannel.keybasedcontroller_active != null)
233             if (softchannel.keybasedcontroller_active[note] != null)
234                 if (softchannel.keybasedcontroller_active[note][keycontrol]) {
235                     double key_controlvalue =
236                             softchannel.keybasedcontroller_value[note][keycontrol];
237                     if (keycontrol == 10 || keycontrol == 91 || keycontrol == 93)
238                         return key_controlvalue;
239                     value += key_controlvalue * 2.0 - 1.0;
240                     if (value > 1)
241                         value = 1;
242                     else if (value < 0)
243                         value = 0;
244                 }
245         return value;
246     }
247 
processConnection(int ix)248     private void processConnection(int ix) {
249         ModelConnectionBlock conn = connections[ix];
250         double[][] src = connections_src[ix];
251         double[] dst = connections_dst[ix];
252         if (dst == null || Double.isInfinite(dst[0]))
253             return;
254 
255         double value = conn.getScale();
256         if (softchannel.keybasedcontroller_active == null) {
257             ModelSource[] srcs = conn.getSources();
258             for (int i = 0; i < srcs.length; i++) {
259                 value *= transformValue(src[i][0], srcs[i]);
260                 if (value == 0)
261                     break;
262             }
263         } else {
264             ModelSource[] srcs = conn.getSources();
265             int[] src_kc = connections_src_kc[ix];
266             for (int i = 0; i < srcs.length; i++) {
267                 value *= transformValue(processKeyBasedController(src[i][0],
268                         src_kc[i]), srcs[i]);
269                 if (value == 0)
270                     break;
271             }
272         }
273 
274         value = transformValue(value, conn.getDestination());
275         dst[0] = dst[0] - connections_last[ix] + value;
276         connections_last[ix] = value;
277         // co_mixer_gain[0] = 0;
278     }
279 
updateTuning(SoftTuning newtuning)280     protected void updateTuning(SoftTuning newtuning) {
281         tunedKey = tuning.getTuning(note) / 100.0;
282         if (!portamento) {
283             co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0);
284             int[] c = performer.midi_connections[4];
285             if (c == null)
286                 return;
287             for (int i = 0; i < c.length; i++)
288                 processConnection(c[i]);
289         }
290     }
291 
setNote(int noteNumber)292     protected void setNote(int noteNumber) {
293         note = noteNumber;
294         tunedKey = tuning.getTuning(noteNumber) / 100.0;
295     }
296 
noteOn(int noteNumber, int velocity)297     protected void noteOn(int noteNumber, int velocity) {
298 
299         sustain = false;
300         sostenuto = false;
301         portamento = false;
302 
303         soundoff = false;
304         on = true;
305         active = true;
306         started = true;
307         // volume = velocity;
308 
309         noteOn_noteNumber = noteNumber;
310         noteOn_velocity = velocity;
311 
312         lastMuteValue = 0;
313         lastSoloMuteValue = 0;
314 
315         setNote(noteNumber);
316 
317         if (performer.forcedKeynumber)
318             co_noteon_keynumber[0] = 0;
319         else
320             co_noteon_keynumber[0] = tunedKey * (1f / 128f);
321         if (performer.forcedVelocity)
322             co_noteon_velocity[0] = 0;
323         else
324             co_noteon_velocity[0] = velocity * (1f / 128f);
325         co_mixer_active[0] = 0;
326         co_mixer_gain[0] = 0;
327         co_mixer_pan[0] = 0;
328         co_mixer_balance[0] = 0;
329         co_mixer_reverb[0] = 0;
330         co_mixer_chorus[0] = 0;
331         co_osc_pitch[0] = 0;
332         co_filter_freq[0] = 0;
333         co_filter_q[0] = 0;
334         co_filter_type[0] = 0;
335         co_noteon_on[0] = 1;
336 
337         eg.reset();
338         lfo.reset();
339         filter_left.reset();
340         filter_right.reset();
341 
342         objects.put("master", synthesizer.getMainMixer().co_master);
343         objects.put("eg", eg);
344         objects.put("lfo", lfo);
345         objects.put("noteon", co_noteon);
346         objects.put("osc", co_osc);
347         objects.put("mixer", co_mixer);
348         objects.put("filter", co_filter);
349 
350         connections = performer.connections;
351 
352         if (connections_last == null
353                 || connections_last.length < connections.length) {
354             connections_last = new double[connections.length];
355         }
356         if (connections_src == null
357                 || connections_src.length < connections.length) {
358             connections_src = new double[connections.length][][];
359             connections_src_kc = new int[connections.length][];
360         }
361         if (connections_dst == null
362                 || connections_dst.length < connections.length) {
363             connections_dst = new double[connections.length][];
364         }
365         for (int i = 0; i < connections.length; i++) {
366             ModelConnectionBlock conn = connections[i];
367             connections_last[i] = 0;
368             if (conn.getSources() != null) {
369                 ModelSource[] srcs = conn.getSources();
370                 if (connections_src[i] == null
371                         || connections_src[i].length < srcs.length) {
372                     connections_src[i] = new double[srcs.length][];
373                     connections_src_kc[i] = new int[srcs.length];
374                 }
375                 double[][] src = connections_src[i];
376                 int[] src_kc = connections_src_kc[i];
377                 connections_src[i] = src;
378                 for (int j = 0; j < srcs.length; j++) {
379                     src_kc[j] = getValueKC(srcs[j].getIdentifier());
380                     src[j] = getValue(srcs[j].getIdentifier());
381                 }
382             }
383 
384             if (conn.getDestination() != null)
385                 connections_dst[i] = getValue(conn.getDestination()
386                         .getIdentifier());
387             else
388                 connections_dst[i] = null;
389         }
390 
391         for (int i = 0; i < connections.length; i++)
392             processConnection(i);
393 
394         if (extendedConnectionBlocks != null) {
395             for (ModelConnectionBlock connection: extendedConnectionBlocks) {
396                 double value = 0;
397 
398                 if (softchannel.keybasedcontroller_active == null) {
399                     for (ModelSource src: connection.getSources()) {
400                         double x = getValue(src.getIdentifier())[0];
401                         ModelTransform t = src.getTransform();
402                         if (t == null)
403                             value += x;
404                         else
405                             value += t.transform(x);
406                     }
407                 } else {
408                     for (ModelSource src: connection.getSources()) {
409                         double x = getValue(src.getIdentifier())[0];
410                         x = processKeyBasedController(x,
411                                 getValueKC(src.getIdentifier()));
412                         ModelTransform t = src.getTransform();
413                         if (t == null)
414                             value += x;
415                         else
416                             value += t.transform(x);
417                     }
418                 }
419 
420                 ModelDestination dest = connection.getDestination();
421                 ModelTransform t = dest.getTransform();
422                 if (t != null)
423                     value = t.transform(value);
424                 getValue(dest.getIdentifier())[0] += value;
425             }
426         }
427 
428         eg.init(synthesizer);
429         lfo.init(synthesizer);
430 
431     }
432 
setPolyPressure(int pressure)433     protected void setPolyPressure(int pressure) {
434         int[] c = performer.midi_connections[2];
435         if (c == null)
436             return;
437         for (int i = 0; i < c.length; i++)
438             processConnection(c[i]);
439     }
440 
setChannelPressure(int pressure)441     protected void setChannelPressure(int pressure) {
442         int[] c = performer.midi_connections[1];
443         if (c == null)
444             return;
445         for (int i = 0; i < c.length; i++)
446             processConnection(c[i]);
447     }
448 
controlChange(int controller, int value)449     protected void controlChange(int controller, int value) {
450         int[] c = performer.midi_ctrl_connections[controller];
451         if (c == null)
452             return;
453         for (int i = 0; i < c.length; i++)
454             processConnection(c[i]);
455     }
456 
nrpnChange(int controller, int value)457     protected void nrpnChange(int controller, int value) {
458         int[] c = performer.midi_nrpn_connections.get(controller);
459         if (c == null)
460             return;
461         for (int i = 0; i < c.length; i++)
462             processConnection(c[i]);
463     }
464 
rpnChange(int controller, int value)465     protected void rpnChange(int controller, int value) {
466         int[] c = performer.midi_rpn_connections.get(controller);
467         if (c == null)
468             return;
469         for (int i = 0; i < c.length; i++)
470             processConnection(c[i]);
471     }
472 
setPitchBend(int bend)473     protected void setPitchBend(int bend) {
474         int[] c = performer.midi_connections[0];
475         if (c == null)
476             return;
477         for (int i = 0; i < c.length; i++)
478             processConnection(c[i]);
479     }
480 
setMute(boolean mute)481     protected void setMute(boolean mute) {
482         co_mixer_gain[0] -= lastMuteValue;
483         lastMuteValue = mute ? -960 : 0;
484         co_mixer_gain[0] += lastMuteValue;
485     }
486 
setSoloMute(boolean mute)487     protected void setSoloMute(boolean mute) {
488         co_mixer_gain[0] -= lastSoloMuteValue;
489         lastSoloMuteValue = mute ? -960 : 0;
490         co_mixer_gain[0] += lastSoloMuteValue;
491     }
492 
shutdown()493     protected void shutdown() {
494         if (co_noteon_on[0] < -0.5)
495             return;
496         on = false;
497 
498         co_noteon_on[0] = -1;
499 
500         int[] c = performer.midi_connections[3];
501         if (c == null)
502             return;
503         for (int i = 0; i < c.length; i++)
504             processConnection(c[i]);
505     }
506 
soundOff()507     protected void soundOff() {
508         on = false;
509         soundoff = true;
510     }
511 
noteOff(int velocity)512     protected void noteOff(int velocity) {
513         if (!on)
514             return;
515         on = false;
516 
517         noteOff_velocity = velocity;
518 
519         if (softchannel.sustain) {
520             sustain = true;
521             return;
522         }
523         if (sostenuto)
524             return;
525 
526         co_noteon_on[0] = 0;
527 
528         int[] c = performer.midi_connections[3];
529         if (c == null)
530             return;
531         for (int i = 0; i < c.length; i++)
532             processConnection(c[i]);
533     }
534 
redamp()535     protected void redamp() {
536         if (co_noteon_on[0] > 0.5)
537             return;
538         if (co_noteon_on[0] < -0.5)
539             return; // don't redamp notes in shutdown stage
540 
541         sustain = true;
542         co_noteon_on[0] = 1;
543 
544         int[] c = performer.midi_connections[3];
545         if (c == null)
546             return;
547         for (int i = 0; i < c.length; i++)
548             processConnection(c[i]);
549     }
550 
processControlLogic()551     protected void processControlLogic() {
552         if (stopping) {
553             active = false;
554             stopping = false;
555             audiostarted = false;
556             if (osc_stream != null)
557                 try {
558                     osc_stream.close();
559                 } catch (IOException e) {
560                     //e.printStackTrace();
561                 }
562 
563             if (stealer_channel != null) {
564                 stealer_channel.initVoice(this, stealer_performer,
565                         stealer_voiceID, stealer_noteNumber, stealer_velocity,
566                         stealer_extendedConnectionBlocks, stealer_channelmixer,
567                         stealer_releaseTriggered);
568                 stealer_releaseTriggered = false;
569                 stealer_channel = null;
570                 stealer_performer = null;
571                 stealer_voiceID = -1;
572                 stealer_noteNumber = 0;
573                 stealer_velocity = 0;
574                 stealer_extendedConnectionBlocks = null;
575                 stealer_channelmixer = null;
576             }
577         }
578         if (started) {
579             audiostarted = true;
580 
581             ModelOscillator osc = performer.oscillators[0];
582 
583             osc_stream_off_transmitted = false;
584             if (osc instanceof ModelWavetable) {
585                 try {
586                     resampler.open((ModelWavetable)osc,
587                             synthesizer.getFormat().getSampleRate());
588                     osc_stream = resampler;
589                 } catch (IOException e) {
590                     //e.printStackTrace();
591                 }
592             } else {
593                 osc_stream = osc.open(synthesizer.getFormat().getSampleRate());
594             }
595             osc_attenuation = osc.getAttenuation();
596             osc_stream_nrofchannels = osc.getChannels();
597             if (osc_buff == null || osc_buff.length < osc_stream_nrofchannels)
598                 osc_buff = new float[osc_stream_nrofchannels][];
599 
600             if (osc_stream != null)
601                 osc_stream.noteOn(softchannel, this, noteOn_noteNumber,
602                         noteOn_velocity);
603 
604 
605         }
606         if (audiostarted) {
607             if (portamento) {
608                 double note_delta = tunedKey - (co_noteon_keynumber[0] * 128);
609                 double note_delta_a = Math.abs(note_delta);
610                 if (note_delta_a < 0.0000000001) {
611                     co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0);
612                     portamento = false;
613                 } else {
614                     if (note_delta_a > softchannel.portamento_time)
615                         note_delta = Math.signum(note_delta)
616                                 * softchannel.portamento_time;
617                     co_noteon_keynumber[0] += note_delta * (1.0 / 128.0);
618                 }
619 
620                 int[] c = performer.midi_connections[4];
621                 if (c == null)
622                     return;
623                 for (int i = 0; i < c.length; i++)
624                     processConnection(c[i]);
625             }
626 
627             eg.processControlLogic();
628             lfo.processControlLogic();
629 
630             for (int i = 0; i < performer.ctrl_connections.length; i++)
631                 processConnection(performer.ctrl_connections[i]);
632 
633             osc_stream.setPitch((float)co_osc_pitch[0]);
634 
635             int filter_type = (int)co_filter_type[0];
636             double filter_freq;
637 
638             if (co_filter_freq[0] == 13500.0)
639                 filter_freq = 19912.126958213175;
640             else
641                 filter_freq = 440.0 * Math.exp(
642                         ((co_filter_freq[0]) - 6900.0) *
643                         (Math.log(2.0) / 1200.0));
644             /*
645             filter_freq = 440.0 * Math.pow(2.0,
646             ((co_filter_freq[0]) - 6900.0) / 1200.0);*/
647             /*
648              * double velocity = co_noteon_velocity[0]; if(velocity < 0.5)
649              * filter_freq *= ((velocity * 2)*0.75 + 0.25);
650              */
651 
652             double q = co_filter_q[0] / 10.0;
653             filter_left.setFilterType(filter_type);
654             filter_left.setFrequency(filter_freq);
655             filter_left.setResonance(q);
656             filter_right.setFilterType(filter_type);
657             filter_right.setFrequency(filter_freq);
658             filter_right.setResonance(q);
659             /*
660             float gain = (float) Math.pow(10,
661             (-osc_attenuation + co_mixer_gain[0]) / 200.0);
662              */
663             float gain = (float)Math.exp(
664                     (-osc_attenuation + co_mixer_gain[0])*(Math.log(10) / 200.0));
665 
666             if (co_mixer_gain[0] <= -960)
667                 gain = 0;
668 
669             if (soundoff) {
670                 stopping = true;
671                 gain = 0;
672                 /*
673                  * if(co_mixer_gain[0] > -960)
674                  *   co_mixer_gain[0] -= 960;
675                  */
676             }
677 
678             volume = (int)(Math.sqrt(gain) * 128);
679 
680             // gain *= 0.2;
681 
682             double pan = co_mixer_pan[0] * (1.0 / 1000.0);
683             // System.out.println("pan = " + pan);
684             if (pan < 0)
685                 pan = 0;
686             else if (pan > 1)
687                 pan = 1;
688 
689             if (pan == 0.5) {
690                 out_mixer_left = gain * 0.7071067811865476f;
691                 out_mixer_right = out_mixer_left;
692             } else {
693                 out_mixer_left = gain * (float)Math.cos(pan * Math.PI * 0.5);
694                 out_mixer_right = gain * (float)Math.sin(pan * Math.PI * 0.5);
695             }
696 
697             double balance = co_mixer_balance[0] * (1.0 / 1000.0);
698             if (balance != 0.5) {
699                 if (balance > 0.5)
700                     out_mixer_left *= (1 - balance) * 2;
701                 else
702                     out_mixer_right *= balance * 2;
703             }
704 
705             if (synthesizer.reverb_on) {
706                 out_mixer_effect1 = (float)(co_mixer_reverb[0] * (1.0 / 1000.0));
707                 out_mixer_effect1 *= gain;
708             } else
709                 out_mixer_effect1 = 0;
710             if (synthesizer.chorus_on) {
711                 out_mixer_effect2 = (float)(co_mixer_chorus[0] * (1.0 / 1000.0));
712                 out_mixer_effect2 *= gain;
713             } else
714                 out_mixer_effect2 = 0;
715             out_mixer_end = co_mixer_active[0] < 0.5;
716 
717             if (!on)
718                 if (!osc_stream_off_transmitted) {
719                     osc_stream_off_transmitted = true;
720                     if (osc_stream != null)
721                         osc_stream.noteOff(noteOff_velocity);
722                 }
723 
724         }
725         if (started) {
726             last_out_mixer_left = out_mixer_left;
727             last_out_mixer_right = out_mixer_right;
728             last_out_mixer_effect1 = out_mixer_effect1;
729             last_out_mixer_effect2 = out_mixer_effect2;
730             started = false;
731         }
732 
733     }
734 
735     protected void mixAudioStream(SoftAudioBuffer in, SoftAudioBuffer out,
736             float amp_from, float amp_to) {
737         int bufferlen = in.getSize();
738         if (amp_from < 0.000000001 && amp_to < 0.000000001)
739             return;
740         if (amp_from == amp_to) {
741             float[] fout = out.array();
742             float[] fin = in.array();
743             for (int i = 0; i < bufferlen; i++)
744                 fout[i] += fin[i] * amp_to;
745         } else {
746             float amp = amp_from;
747             float amp_delta = (amp_to - amp_from) / bufferlen;
748             float[] fout = out.array();
749             float[] fin = in.array();
750             for (int i = 0; i < bufferlen; i++) {
751                 amp += amp_delta;
752                 fout[i] += fin[i] * amp;
753             }
754         }
755 
756     }
757 
758     protected void processAudioLogic(SoftAudioBuffer[] buffer) {
759         if (!audiostarted)
760             return;
761 
762         int bufferlen = buffer[0].getSize();
763 
764         try {
765             osc_buff[0] = buffer[SoftMainMixer.CHANNEL_LEFT_DRY].array();
766             if (nrofchannels != 1)
767                 osc_buff[1] = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY].array();
768             int ret = osc_stream.read(osc_buff, 0, bufferlen);
769             if (ret == -1) {
770                 stopping = true;
771                 return;
772             }
773             if (ret != bufferlen) {
774                 Arrays.fill(osc_buff[0], ret, bufferlen, 0f);
775                 if (nrofchannels != 1)
776                     Arrays.fill(osc_buff[1], ret, bufferlen, 0f);
777             }
778 
779         } catch (IOException e) {
780             //e.printStackTrace();
781         }
782 
783         SoftAudioBuffer left = buffer[SoftMainMixer.CHANNEL_LEFT];
784         SoftAudioBuffer right = buffer[SoftMainMixer.CHANNEL_RIGHT];
785         SoftAudioBuffer eff1 = buffer[SoftMainMixer.CHANNEL_EFFECT1];
786         SoftAudioBuffer eff2 = buffer[SoftMainMixer.CHANNEL_EFFECT2];
787         SoftAudioBuffer leftdry = buffer[SoftMainMixer.CHANNEL_LEFT_DRY];
788         SoftAudioBuffer rightdry = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY];
789 
790         if (osc_stream_nrofchannels == 1)
791             rightdry = null;
792 
793         if (!Double.isInfinite(co_filter_freq[0])) {
794             filter_left.processAudio(leftdry);
795             if (rightdry != null)
796                 filter_right.processAudio(rightdry);
797         }
798 
799         if (nrofchannels == 1) {
800             out_mixer_left = (out_mixer_left + out_mixer_right) / 2;
801             mixAudioStream(leftdry, left, last_out_mixer_left, out_mixer_left);
802             if (rightdry != null)
803                 mixAudioStream(rightdry, left, last_out_mixer_left,
804                         out_mixer_left);
805         } else {
806             mixAudioStream(leftdry, left, last_out_mixer_left, out_mixer_left);
807             if (rightdry != null)
808                 mixAudioStream(rightdry, right, last_out_mixer_right,
809                         out_mixer_right);
810             else
811                 mixAudioStream(leftdry, right, last_out_mixer_right,
812                         out_mixer_right);
813         }
814 
815         if (rightdry == null) {
816             mixAudioStream(leftdry, eff1, last_out_mixer_effect1,
817                     out_mixer_effect1);
818             mixAudioStream(leftdry, eff2, last_out_mixer_effect2,
819                     out_mixer_effect2);
820         } else {
821             mixAudioStream(leftdry, eff1, last_out_mixer_effect1 * 0.5f,
822                     out_mixer_effect1 * 0.5f);
823             mixAudioStream(leftdry, eff2, last_out_mixer_effect2 * 0.5f,
824                     out_mixer_effect2 * 0.5f);
825             mixAudioStream(rightdry, eff1, last_out_mixer_effect1 * 0.5f,
826                     out_mixer_effect1 * 0.5f);
827             mixAudioStream(rightdry, eff2, last_out_mixer_effect2 * 0.5f,
828                     out_mixer_effect2 * 0.5f);
829         }
830 
831         last_out_mixer_left = out_mixer_left;
832         last_out_mixer_right = out_mixer_right;
833         last_out_mixer_effect1 = out_mixer_effect1;
834         last_out_mixer_effect2 = out_mixer_effect2;
835 
836         if (out_mixer_end) {
837             stopping = true;
838         }
839 
840     }
841 }
842