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