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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 300     void setNote(int noteNumber) {
 301         note = noteNumber;
 302         tunedKey = tuning.getTuning(noteNumber) / 100.0;
 303     }
 304 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 502     void setMute(boolean mute) {
 503         co_mixer_gain[0] -= lastMuteValue;
 504         lastMuteValue = mute ? -960 : 0;
 505         co_mixer_gain[0] += lastMuteValue;
 506     }
 507 
 508     void setSoloMute(boolean mute) {
 509         co_mixer_gain[0] -= lastSoloMuteValue;
 510         lastSoloMuteValue = mute ? -960 : 0;
 511         co_mixer_gain[0] += lastSoloMuteValue;
 512     }
 513 
 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 
 530     void soundOff() {
 531         on = false;
 532         soundoff = true;
 533     }
 534 
 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 
 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 
 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 }