alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (SoftMainMixer.java)

This example Java source code file (SoftMainMixer.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

audio, change, control, dls, dump, general, master, midi, object, patch, softaudiobuffer, softchannel, softchannelmixercontainer, softtuning, softvoice, sound, tuning, util

The SoftMainMixer.java Java example source code

/*
 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.sun.media.sound;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;

import javax.sound.midi.MidiMessage;
import javax.sound.midi.Patch;
import javax.sound.midi.ShortMessage;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

/**
 * Software synthesizer main audio mixer.
 *
 * @author Karl Helgason
 */
public final class SoftMainMixer {

    // A private class thats contains a ModelChannelMixer and it's private buffers.
    // This becomes necessary when we want to have separate delay buffers for each channel mixer.
    private class SoftChannelMixerContainer
    {
        ModelChannelMixer mixer;
        SoftAudioBuffer[] buffers;
    }

    public final static int CHANNEL_LEFT = 0;
    public final static int CHANNEL_RIGHT = 1;
    public final static int CHANNEL_MONO = 2;
    public final static int CHANNEL_DELAY_LEFT = 3;
    public final static int CHANNEL_DELAY_RIGHT = 4;
    public final static int CHANNEL_DELAY_MONO = 5;
    public final static int CHANNEL_EFFECT1 = 6;
    public final static int CHANNEL_EFFECT2 = 7;
    public final static int CHANNEL_DELAY_EFFECT1 = 8;
    public final static int CHANNEL_DELAY_EFFECT2 = 9;
    public final static int CHANNEL_LEFT_DRY = 10;
    public final static int CHANNEL_RIGHT_DRY = 11;
    public final static int CHANNEL_SCRATCH1 = 12;
    public final static int CHANNEL_SCRATCH2 = 13;
    boolean active_sensing_on = false;
    private long msec_last_activity = -1;
    private boolean pusher_silent = false;
    private int pusher_silent_count = 0;
    private long sample_pos = 0;
    boolean readfully = true;
    private final Object control_mutex;
    private SoftSynthesizer synth;
    private float samplerate = 44100;
    private int nrofchannels = 2;
    private SoftVoice[] voicestatus = null;
    private SoftAudioBuffer[] buffers;
    private SoftReverb reverb;
    private SoftAudioProcessor chorus;
    private SoftAudioProcessor agc;
    private long msec_buffer_len = 0;
    private int buffer_len = 0;
    TreeMap<Long, Object> midimessages = new TreeMap();
    private int delay_midievent = 0;
    private int max_delay_midievent = 0;
    double last_volume_left = 1.0;
    double last_volume_right = 1.0;
    private double[] co_master_balance = new double[1];
    private double[] co_master_volume = new double[1];
    private double[] co_master_coarse_tuning = new double[1];
    private double[] co_master_fine_tuning = new double[1];
    private AudioInputStream ais;
    private Set<SoftChannelMixerContainer> registeredMixers = null;
    private Set<ModelChannelMixer> stoppedMixers = null;
    private SoftChannelMixerContainer[] cur_registeredMixers = null;
    SoftControl co_master = new SoftControl() {

        double[] balance = co_master_balance;
        double[] volume = co_master_volume;
        double[] coarse_tuning = co_master_coarse_tuning;
        double[] fine_tuning = co_master_fine_tuning;

        public double[] get(int instance, String name) {
            if (name == null)
                return null;
            if (name.equals("balance"))
                return balance;
            if (name.equals("volume"))
                return volume;
            if (name.equals("coarse_tuning"))
                return coarse_tuning;
            if (name.equals("fine_tuning"))
                return fine_tuning;
            return null;
        }
    };

    private void processSystemExclusiveMessage(byte[] data) {
        synchronized (synth.control_mutex) {
            activity();

            // Universal Non-Real-Time SysEx
            if ((data[1] & 0xFF) == 0x7E) {
                int deviceID = data[2] & 0xFF;
                if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {
                    int subid1 = data[3] & 0xFF;
                    int subid2;
                    switch (subid1) {
                    case 0x08:  // MIDI Tuning Standard
                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x01:  // BULK TUNING DUMP
                        {
                            // http://www.midi.org/about-midi/tuning.shtml
                            SoftTuning tuning = synth.getTuning(new Patch(0,
                                    data[5] & 0xFF));
                            tuning.load(data);
                            break;
                        }
                        case 0x04:  // KEY-BASED TUNING DUMP
                        case 0x05:  // SCALE/OCTAVE TUNING DUMP, 1 byte format
                        case 0x06:  // SCALE/OCTAVE TUNING DUMP, 2 byte format
                        case 0x07:  // SINGLE NOTE TUNING CHANGE (NON REAL-TIME)
                                    // (BANK)
                        {
                            // http://www.midi.org/about-midi/tuning_extens.shtml
                            SoftTuning tuning = synth.getTuning(new Patch(
                                    data[5] & 0xFF, data[6] & 0xFF));
                            tuning.load(data);
                            break;
                        }
                        case 0x08:  // scale/octave tuning 1-byte form (Non
                                    // Real-Time)
                        case 0x09:  // scale/octave tuning 2-byte form (Non
                                    // Real-Time)
                        {
                            // http://www.midi.org/about-midi/tuning-scale.shtml
                            SoftTuning tuning = new SoftTuning(data);
                            int channelmask = (data[5] & 0xFF) * 16384
                                    + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);
                            SoftChannel[] channels = synth.channels;
                            for (int i = 0; i < channels.length; i++)
                                if ((channelmask & (1 << i)) != 0)
                                    channels[i].tuning = tuning;
                            break;
                        }
                        default:
                            break;
                        }
                        break;
                    case 0x09:  // General Midi Message
                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x01:  // General Midi 1 On
                            synth.setGeneralMidiMode(1);
                            reset();
                            break;
                        case 0x02:  // General Midi Off
                            synth.setGeneralMidiMode(0);
                            reset();
                            break;
                        case 0x03:  // General MidI Level 2 On
                            synth.setGeneralMidiMode(2);
                            reset();
                            break;
                        default:
                            break;
                        }
                        break;
                    case 0x0A: // DLS Message
                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x01:  // DLS On
                            if (synth.getGeneralMidiMode() == 0)
                                synth.setGeneralMidiMode(1);
                            synth.voice_allocation_mode = 1;
                            reset();
                            break;
                        case 0x02:  // DLS Off
                            synth.setGeneralMidiMode(0);
                            synth.voice_allocation_mode = 0;
                            reset();
                            break;
                        case 0x03:  // DLS Static Voice Allocation Off
                            synth.voice_allocation_mode = 0;
                            break;
                        case 0x04:  // DLS Static Voice Allocation On
                            synth.voice_allocation_mode = 1;
                            break;
                        default:
                            break;
                        }
                        break;

                    default:
                        break;
                    }
                }
            }

            // Universal Real-Time SysEx
            if ((data[1] & 0xFF) == 0x7F) {
                int deviceID = data[2] & 0xFF;
                if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {
                    int subid1 = data[3] & 0xFF;
                    int subid2;
                    switch (subid1) {
                    case 0x04: // Device Control

                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x01: // Master Volume
                        case 0x02: // Master Balane
                        case 0x03: // Master fine tuning
                        case 0x04: // Master coarse tuning
                            int val = (data[5] & 0x7F)
                                    + ((data[6] & 0x7F) * 128);
                            if (subid2 == 0x01)
                                setVolume(val);
                            else if (subid2 == 0x02)
                                setBalance(val);
                            else if (subid2 == 0x03)
                                setFineTuning(val);
                            else if (subid2 == 0x04)
                                setCoarseTuning(val);
                            break;
                        case 0x05: // Global Parameter Control
                            int ix = 5;
                            int slotPathLen = (data[ix++] & 0xFF);
                            int paramWidth = (data[ix++] & 0xFF);
                            int valueWidth = (data[ix++] & 0xFF);
                            int[] slotPath = new int[slotPathLen];
                            for (int i = 0; i < slotPathLen; i++) {
                                int msb = (data[ix++] & 0xFF);
                                int lsb = (data[ix++] & 0xFF);
                                slotPath[i] = msb * 128 + lsb;
                            }
                            int paramCount = (data.length - 1 - ix)
                                    / (paramWidth + valueWidth);
                            long[] params = new long[paramCount];
                            long[] values = new long[paramCount];
                            for (int i = 0; i < paramCount; i++) {
                                values[i] = 0;
                                for (int j = 0; j < paramWidth; j++)
                                    params[i] = params[i] * 128
                                            + (data[ix++] & 0xFF);
                                for (int j = 0; j < valueWidth; j++)
                                    values[i] = values[i] * 128
                                            + (data[ix++] & 0xFF);

                            }
                            globalParameterControlChange(slotPath, params, values);
                            break;
                        default:
                            break;
                        }
                        break;

                    case 0x08:  // MIDI Tuning Standard
                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x02:  // SINGLE NOTE TUNING CHANGE (REAL-TIME)
                        {
                            // http://www.midi.org/about-midi/tuning.shtml
                            SoftTuning tuning = synth.getTuning(new Patch(0,
                                    data[5] & 0xFF));
                            tuning.load(data);
                            SoftVoice[] voices = synth.getVoices();
                            for (int i = 0; i < voices.length; i++)
                                if (voices[i].active)
                                    if (voices[i].tuning == tuning)
                                        voices[i].updateTuning(tuning);
                            break;
                        }
                        case 0x07:  // SINGLE NOTE TUNING CHANGE (REAL-TIME)
                                    // (BANK)
                        {
                            // http://www.midi.org/about-midi/tuning_extens.shtml
                            SoftTuning tuning = synth.getTuning(new Patch(
                                    data[5] & 0xFF, data[6] & 0xFF));
                            tuning.load(data);
                            SoftVoice[] voices = synth.getVoices();
                            for (int i = 0; i < voices.length; i++)
                                if (voices[i].active)
                                    if (voices[i].tuning == tuning)
                                        voices[i].updateTuning(tuning);
                            break;
                        }
                        case 0x08:  // scale/octave tuning 1-byte form
                                    //(Real-Time)
                        case 0x09:  // scale/octave tuning 2-byte form
                                    // (Real-Time)
                        {
                            // http://www.midi.org/about-midi/tuning-scale.shtml
                            SoftTuning tuning = new SoftTuning(data);
                            int channelmask = (data[5] & 0xFF) * 16384
                                    + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);
                            SoftChannel[] channels = synth.channels;
                            for (int i = 0; i < channels.length; i++)
                                if ((channelmask & (1 << i)) != 0)
                                    channels[i].tuning = tuning;
                            SoftVoice[] voices = synth.getVoices();
                            for (int i = 0; i < voices.length; i++)
                                if (voices[i].active)
                                    if ((channelmask & (1 << (voices[i].channel))) != 0)
                                        voices[i].updateTuning(tuning);
                            break;
                        }
                        default:
                            break;
                        }
                        break;
                    case 0x09:  // Control Destination Settings
                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x01: // Channel Pressure
                        {
                            int[] destinations = new int[(data.length - 7) / 2];
                            int[] ranges = new int[(data.length - 7) / 2];
                            int ix = 0;
                            for (int j = 6; j < data.length - 1; j += 2) {
                                destinations[ix] = data[j] & 0xFF;
                                ranges[ix] = data[j + 1] & 0xFF;
                                ix++;
                            }
                            int channel = data[5] & 0xFF;
                            SoftChannel softchannel = synth.channels[channel];
                            softchannel.mapChannelPressureToDestination(
                                    destinations, ranges);
                            break;
                        }
                        case 0x02: // Poly Pressure
                        {
                            int[] destinations = new int[(data.length - 7) / 2];
                            int[] ranges = new int[(data.length - 7) / 2];
                            int ix = 0;
                            for (int j = 6; j < data.length - 1; j += 2) {
                                destinations[ix] = data[j] & 0xFF;
                                ranges[ix] = data[j + 1] & 0xFF;
                                ix++;
                            }
                            int channel = data[5] & 0xFF;
                            SoftChannel softchannel = synth.channels[channel];
                            softchannel.mapPolyPressureToDestination(
                                    destinations, ranges);
                            break;
                        }
                        case 0x03: // Control Change
                        {
                            int[] destinations = new int[(data.length - 7) / 2];
                            int[] ranges = new int[(data.length - 7) / 2];
                            int ix = 0;
                            for (int j = 7; j < data.length - 1; j += 2) {
                                destinations[ix] = data[j] & 0xFF;
                                ranges[ix] = data[j + 1] & 0xFF;
                                ix++;
                            }
                            int channel = data[5] & 0xFF;
                            SoftChannel softchannel = synth.channels[channel];
                            int control = data[6] & 0xFF;
                            softchannel.mapControlToDestination(control,
                                    destinations, ranges);
                            break;
                        }
                        default:
                            break;
                        }
                        break;

                    case 0x0A:  // Key Based Instrument Control
                    {
                        subid2 = data[4] & 0xFF;
                        switch (subid2) {
                        case 0x01: // Basic Message
                            int channel = data[5] & 0xFF;
                            int keynumber = data[6] & 0xFF;
                            SoftChannel softchannel = synth.channels[channel];
                            for (int j = 7; j < data.length - 1; j += 2) {
                                int controlnumber = data[j] & 0xFF;
                                int controlvalue = data[j + 1] & 0xFF;
                                softchannel.controlChangePerNote(keynumber,
                                        controlnumber, controlvalue);
                            }
                            break;
                        default:
                            break;
                        }
                        break;
                    }
                    default:
                        break;
                    }
                }
            }

        }
    }

    private void processMessages(long timeStamp) {
        Iterator<Entry iter = midimessages.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<Long, Object> entry = iter.next();
            if (entry.getKey() >= (timeStamp + msec_buffer_len))
                return;
            long msec_delay = entry.getKey() - timeStamp;
            delay_midievent = (int)(msec_delay * (samplerate / 1000000.0) + 0.5);
            if(delay_midievent > max_delay_midievent)
                delay_midievent = max_delay_midievent;
            if(delay_midievent < 0)
                delay_midievent = 0;
            processMessage(entry.getValue());
            iter.remove();
        }
        delay_midievent = 0;
    }

    void processAudioBuffers() {

        if(synth.weakstream != null && synth.weakstream.silent_samples != 0)
        {
            sample_pos += synth.weakstream.silent_samples;
            synth.weakstream.silent_samples = 0;
        }

        for (int i = 0; i < buffers.length; i++) {
            if(i != CHANNEL_DELAY_LEFT &&
                    i != CHANNEL_DELAY_RIGHT &&
                    i != CHANNEL_DELAY_MONO &&
                    i != CHANNEL_DELAY_EFFECT1 &&
                    i != CHANNEL_DELAY_EFFECT2)
                buffers[i].clear();
        }

        if(!buffers[CHANNEL_DELAY_LEFT].isSilent())
        {
            buffers[CHANNEL_LEFT].swap(buffers[CHANNEL_DELAY_LEFT]);
        }
        if(!buffers[CHANNEL_DELAY_RIGHT].isSilent())
        {
            buffers[CHANNEL_RIGHT].swap(buffers[CHANNEL_DELAY_RIGHT]);
        }
        if(!buffers[CHANNEL_DELAY_MONO].isSilent())
        {
            buffers[CHANNEL_MONO].swap(buffers[CHANNEL_DELAY_MONO]);
        }
        if(!buffers[CHANNEL_DELAY_EFFECT1].isSilent())
        {
            buffers[CHANNEL_EFFECT1].swap(buffers[CHANNEL_DELAY_EFFECT1]);
        }
        if(!buffers[CHANNEL_DELAY_EFFECT2].isSilent())
        {
            buffers[CHANNEL_EFFECT2].swap(buffers[CHANNEL_DELAY_EFFECT2]);
        }

        double volume_left;
        double volume_right;

        SoftChannelMixerContainer[] act_registeredMixers;

        // perform control logic
        synchronized (control_mutex) {

            long msec_pos = (long)(sample_pos * (1000000.0 / samplerate));

            processMessages(msec_pos);

            if (active_sensing_on) {
                // Active Sensing
                // if no message occurs for max 1000 ms
                // then do AllSoundOff on all channels
                if ((msec_pos - msec_last_activity) > 1000000) {
                    active_sensing_on = false;
                    for (SoftChannel c : synth.channels)
                        c.allSoundOff();
                }

            }

            for (int i = 0; i < voicestatus.length; i++)
                if (voicestatus[i].active)
                    voicestatus[i].processControlLogic();
            sample_pos += buffer_len;

            double volume = co_master_volume[0];
            volume_left = volume;
            volume_right = volume;

            double balance = co_master_balance[0];
            if (balance > 0.5)
                volume_left *= (1 - balance) * 2;
            else
                volume_right *= balance * 2;

            chorus.processControlLogic();
            reverb.processControlLogic();
            agc.processControlLogic();

            if (cur_registeredMixers == null) {
                if (registeredMixers != null) {
                    cur_registeredMixers =
                            new SoftChannelMixerContainer[registeredMixers.size()];
                    registeredMixers.toArray(cur_registeredMixers);
                }
            }

            act_registeredMixers = cur_registeredMixers;
            if (act_registeredMixers != null)
                if (act_registeredMixers.length == 0)
                    act_registeredMixers = null;

        }

        if (act_registeredMixers != null) {

            // Make backup of left,right,mono channels
            SoftAudioBuffer leftbak = buffers[CHANNEL_LEFT];
            SoftAudioBuffer rightbak = buffers[CHANNEL_RIGHT];
            SoftAudioBuffer monobak = buffers[CHANNEL_MONO];
            SoftAudioBuffer delayleftbak = buffers[CHANNEL_DELAY_LEFT];
            SoftAudioBuffer delayrightbak = buffers[CHANNEL_DELAY_RIGHT];
            SoftAudioBuffer delaymonobak = buffers[CHANNEL_DELAY_MONO];

            int bufferlen = buffers[CHANNEL_LEFT].getSize();

            float[][] cbuffer = new float[nrofchannels][];
            float[][] obuffer = new float[nrofchannels][];
            obuffer[0] = leftbak.array();
            if (nrofchannels != 1)
                obuffer[1] = rightbak.array();

            for (SoftChannelMixerContainer cmixer : act_registeredMixers) {

                // Reroute default left,right output
                // to channelmixer left,right input/output
                buffers[CHANNEL_LEFT] =  cmixer.buffers[CHANNEL_LEFT];
                buffers[CHANNEL_RIGHT] = cmixer.buffers[CHANNEL_RIGHT];
                buffers[CHANNEL_MONO] = cmixer.buffers[CHANNEL_MONO];
                buffers[CHANNEL_DELAY_LEFT] = cmixer.buffers[CHANNEL_DELAY_LEFT];
                buffers[CHANNEL_DELAY_RIGHT] = cmixer.buffers[CHANNEL_DELAY_RIGHT];
                buffers[CHANNEL_DELAY_MONO] = cmixer.buffers[CHANNEL_DELAY_MONO];

                buffers[CHANNEL_LEFT].clear();
                buffers[CHANNEL_RIGHT].clear();
                buffers[CHANNEL_MONO].clear();

                if(!buffers[CHANNEL_DELAY_LEFT].isSilent())
                {
                    buffers[CHANNEL_LEFT].swap(buffers[CHANNEL_DELAY_LEFT]);
                }
                if(!buffers[CHANNEL_DELAY_RIGHT].isSilent())
                {
                    buffers[CHANNEL_RIGHT].swap(buffers[CHANNEL_DELAY_RIGHT]);
                }
                if(!buffers[CHANNEL_DELAY_MONO].isSilent())
                {
                    buffers[CHANNEL_MONO].swap(buffers[CHANNEL_DELAY_MONO]);
                }

                cbuffer[0] = buffers[CHANNEL_LEFT].array();
                if (nrofchannels != 1)
                    cbuffer[1] = buffers[CHANNEL_RIGHT].array();

                boolean hasactivevoices = false;
                for (int i = 0; i < voicestatus.length; i++)
                    if (voicestatus[i].active)
                        if (voicestatus[i].channelmixer == cmixer.mixer) {
                            voicestatus[i].processAudioLogic(buffers);
                            hasactivevoices = true;
                        }

                if(!buffers[CHANNEL_MONO].isSilent())
                {
                    float[] mono = buffers[CHANNEL_MONO].array();
                    float[] left = buffers[CHANNEL_LEFT].array();
                    if (nrofchannels != 1) {
                        float[] right = buffers[CHANNEL_RIGHT].array();
                        for (int i = 0; i < bufferlen; i++) {
                            float v = mono[i];
                            left[i] += v;
                            right[i] += v;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < bufferlen; i++) {
                            left[i] += mono[i];
                        }
                    }
                }

                if (!cmixer.mixer.process(cbuffer, 0, bufferlen)) {
                    synchronized (control_mutex) {
                        registeredMixers.remove(cmixer);
                        cur_registeredMixers = null;
                    }
                }

                for (int i = 0; i < cbuffer.length; i++) {
                    float[] cbuff = cbuffer[i];
                    float[] obuff = obuffer[i];
                    for (int j = 0; j < bufferlen; j++)
                        obuff[j] += cbuff[j];
                }

                if (!hasactivevoices) {
                    synchronized (control_mutex) {
                        if (stoppedMixers != null) {
                            if (stoppedMixers.contains(cmixer)) {
                                stoppedMixers.remove(cmixer);
                                cmixer.mixer.stop();
                            }
                        }
                    }
                }

            }

            buffers[CHANNEL_LEFT] = leftbak;
            buffers[CHANNEL_RIGHT] = rightbak;
            buffers[CHANNEL_MONO] = monobak;
            buffers[CHANNEL_DELAY_LEFT] = delayleftbak;
            buffers[CHANNEL_DELAY_RIGHT] = delayrightbak;
            buffers[CHANNEL_DELAY_MONO] = delaymonobak;

        }

        for (int i = 0; i < voicestatus.length; i++)
            if (voicestatus[i].active)
                if (voicestatus[i].channelmixer == null)
                    voicestatus[i].processAudioLogic(buffers);

        if(!buffers[CHANNEL_MONO].isSilent())
        {
            float[] mono = buffers[CHANNEL_MONO].array();
            float[] left = buffers[CHANNEL_LEFT].array();
            int bufferlen = buffers[CHANNEL_LEFT].getSize();
            if (nrofchannels != 1) {
                float[] right = buffers[CHANNEL_RIGHT].array();
                for (int i = 0; i < bufferlen; i++) {
                    float v = mono[i];
                    left[i] += v;
                    right[i] += v;
                }
            }
            else
            {
                for (int i = 0; i < bufferlen; i++) {
                    left[i] += mono[i];
                }
            }
        }

        // Run effects
        if (synth.chorus_on)
            chorus.processAudio();

        if (synth.reverb_on)
            reverb.processAudio();

        if (nrofchannels == 1)
            volume_left = (volume_left + volume_right) / 2;

        // Set Volume / Balance
        if (last_volume_left != volume_left || last_volume_right != volume_right) {
            float[] left = buffers[CHANNEL_LEFT].array();
            float[] right = buffers[CHANNEL_RIGHT].array();
            int bufferlen = buffers[CHANNEL_LEFT].getSize();

            float amp;
            float amp_delta;
            amp = (float)(last_volume_left * last_volume_left);
            amp_delta = (float)((volume_left * volume_left - amp) / bufferlen);
            for (int i = 0; i < bufferlen; i++) {
                amp += amp_delta;
                left[i] *= amp;
            }
            if (nrofchannels != 1) {
                amp = (float)(last_volume_right * last_volume_right);
                amp_delta = (float)((volume_right*volume_right - amp) / bufferlen);
                for (int i = 0; i < bufferlen; i++) {
                    amp += amp_delta;
                    right[i] *= volume_right;
                }
            }
            last_volume_left = volume_left;
            last_volume_right = volume_right;

        } else {
            if (volume_left != 1.0 || volume_right != 1.0) {
                float[] left = buffers[CHANNEL_LEFT].array();
                float[] right = buffers[CHANNEL_RIGHT].array();
                int bufferlen = buffers[CHANNEL_LEFT].getSize();
                float amp;
                amp = (float) (volume_left * volume_left);
                for (int i = 0; i < bufferlen; i++)
                    left[i] *= amp;
                if (nrofchannels != 1) {
                    amp = (float)(volume_right * volume_right);
                    for (int i = 0; i < bufferlen; i++)
                        right[i] *= amp;
                }

            }
        }

        if(buffers[CHANNEL_LEFT].isSilent()
            && buffers[CHANNEL_RIGHT].isSilent())
        {

            int midimessages_size;
            synchronized (control_mutex) {
                midimessages_size = midimessages.size();
            }

            if(midimessages_size == 0)
            {
                pusher_silent_count++;
                if(pusher_silent_count > 5)
                {
                    pusher_silent_count = 0;
                    synchronized (control_mutex) {
                        pusher_silent = true;
                        if(synth.weakstream != null)
                            synth.weakstream.setInputStream(null);
                    }
                }
            }
        }
        else
            pusher_silent_count = 0;

        if (synth.agc_on)
            agc.processAudio();

    }

    // Must only we called within control_mutex synchronization
    public void activity()
    {
        long silent_samples = 0;
        if(pusher_silent)
        {
            pusher_silent = false;
            if(synth.weakstream != null)
            {
                synth.weakstream.setInputStream(ais);
                silent_samples = synth.weakstream.silent_samples;
            }
        }
        msec_last_activity = (long)((sample_pos + silent_samples)
                * (1000000.0 / samplerate));
    }

    public void stopMixer(ModelChannelMixer mixer) {
        if (stoppedMixers == null)
            stoppedMixers = new HashSet<ModelChannelMixer>();
        stoppedMixers.add(mixer);
    }

    public void registerMixer(ModelChannelMixer mixer) {
        if (registeredMixers == null)
            registeredMixers = new HashSet<SoftChannelMixerContainer>();
        SoftChannelMixerContainer mixercontainer = new SoftChannelMixerContainer();
        mixercontainer.buffers = new SoftAudioBuffer[6];
        for (int i = 0; i < mixercontainer.buffers.length; i++) {
            mixercontainer.buffers[i] =
                new SoftAudioBuffer(buffer_len, synth.getFormat());
        }
        mixercontainer.mixer = mixer;
        registeredMixers.add(mixercontainer);
        cur_registeredMixers = null;
    }

    public SoftMainMixer(SoftSynthesizer synth) {
        this.synth = synth;

        sample_pos = 0;

        co_master_balance[0] = 0.5;
        co_master_volume[0] = 1;
        co_master_coarse_tuning[0] = 0.5;
        co_master_fine_tuning[0] = 0.5;

        msec_buffer_len = (long) (1000000.0 / synth.getControlRate());
        samplerate = synth.getFormat().getSampleRate();
        nrofchannels = synth.getFormat().getChannels();

        int buffersize = (int) (synth.getFormat().getSampleRate()
                                / synth.getControlRate());

        buffer_len = buffersize;

        max_delay_midievent = buffersize;

        control_mutex = synth.control_mutex;
        buffers = new SoftAudioBuffer[14];
        for (int i = 0; i < buffers.length; i++) {
            buffers[i] = new SoftAudioBuffer(buffersize, synth.getFormat());
        }
        voicestatus = synth.getVoices();

        reverb = new SoftReverb();
        chorus = new SoftChorus();
        agc = new SoftLimiter();

        float samplerate = synth.getFormat().getSampleRate();
        float controlrate = synth.getControlRate();
        reverb.init(samplerate, controlrate);
        chorus.init(samplerate, controlrate);
        agc.init(samplerate, controlrate);

        reverb.setLightMode(synth.reverb_light);

        reverb.setMixMode(true);
        chorus.setMixMode(true);
        agc.setMixMode(false);

        chorus.setInput(0, buffers[CHANNEL_EFFECT2]);
        chorus.setOutput(0, buffers[CHANNEL_LEFT]);
        if (nrofchannels != 1)
            chorus.setOutput(1, buffers[CHANNEL_RIGHT]);
        chorus.setOutput(2, buffers[CHANNEL_EFFECT1]);

        reverb.setInput(0, buffers[CHANNEL_EFFECT1]);
        reverb.setOutput(0, buffers[CHANNEL_LEFT]);
        if (nrofchannels != 1)
            reverb.setOutput(1, buffers[CHANNEL_RIGHT]);

        agc.setInput(0, buffers[CHANNEL_LEFT]);
        if (nrofchannels != 1)
            agc.setInput(1, buffers[CHANNEL_RIGHT]);
        agc.setOutput(0, buffers[CHANNEL_LEFT]);
        if (nrofchannels != 1)
            agc.setOutput(1, buffers[CHANNEL_RIGHT]);

        InputStream in = new InputStream() {

            private final SoftAudioBuffer[] buffers = SoftMainMixer.this.buffers;
            private final int nrofchannels
                    = SoftMainMixer.this.synth.getFormat().getChannels();
            private final int buffersize = buffers[0].getSize();
            private final byte[] bbuffer = new byte[buffersize
                    * (SoftMainMixer.this.synth.getFormat()
                        .getSampleSizeInBits() / 8)
                    * nrofchannels];
            private int bbuffer_pos = 0;
            private final byte[] single = new byte[1];

            public void fillBuffer() {
                /*
                boolean pusher_silent2;
                synchronized (control_mutex) {
                    pusher_silent2 = pusher_silent;
                }
                if(!pusher_silent2)*/
                processAudioBuffers();
                for (int i = 0; i < nrofchannels; i++)
                    buffers[i].get(bbuffer, i);
                bbuffer_pos = 0;
            }

            public int read(byte[] b, int off, int len) {
                int bbuffer_len = bbuffer.length;
                int offlen = off + len;
                int orgoff = off;
                byte[] bbuffer = this.bbuffer;
                while (off < offlen) {
                    if (available() == 0)
                        fillBuffer();
                    else {
                        int bbuffer_pos = this.bbuffer_pos;
                        while (off < offlen && bbuffer_pos < bbuffer_len)
                            b[off++] = bbuffer[bbuffer_pos++];
                        this.bbuffer_pos = bbuffer_pos;
                        if (!readfully)
                            return off - orgoff;
                    }
                }
                return len;
            }

            public int read() throws IOException {
                int ret = read(single);
                if (ret == -1)
                    return -1;
                return single[0] & 0xFF;
            }

            public int available() {
                return bbuffer.length - bbuffer_pos;
            }

            public void close() {
                SoftMainMixer.this.synth.close();
            }
        };

        ais = new AudioInputStream(in, synth.getFormat(), AudioSystem.NOT_SPECIFIED);

    }

    public AudioInputStream getInputStream() {
        return ais;
    }

    public void reset() {

        SoftChannel[] channels = synth.channels;
        for (int i = 0; i < channels.length; i++) {
            channels[i].allSoundOff();
            channels[i].resetAllControllers(true);

            if (synth.getGeneralMidiMode() == 2) {
                if (i == 9)
                    channels[i].programChange(0, 0x78 * 128);
                else
                    channels[i].programChange(0, 0x79 * 128);
            } else
                channels[i].programChange(0, 0);
        }
        setVolume(0x7F * 128 + 0x7F);
        setBalance(0x40 * 128 + 0x00);
        setCoarseTuning(0x40 * 128 + 0x00);
        setFineTuning(0x40 * 128 + 0x00);
        // Reset Reverb
        globalParameterControlChange(
                new int[]{0x01 * 128 + 0x01}, new long[]{0}, new long[]{4});
        // Reset Chorus
        globalParameterControlChange(
                new int[]{0x01 * 128 + 0x02}, new long[]{0}, new long[]{2});
    }

    public void setVolume(int value) {
        synchronized (control_mutex) {
            co_master_volume[0] = value / 16384.0;
        }
    }

    public void setBalance(int value) {
        synchronized (control_mutex) {
            co_master_balance[0] = value / 16384.0;
        }
    }

    public void setFineTuning(int value) {
        synchronized (control_mutex) {
            co_master_fine_tuning[0] = value / 16384.0;
        }
    }

    public void setCoarseTuning(int value) {
        synchronized (control_mutex) {
            co_master_coarse_tuning[0] = value / 16384.0;
        }
    }

    public int getVolume() {
        synchronized (control_mutex) {
            return (int) (co_master_volume[0] * 16384.0);
        }
    }

    public int getBalance() {
        synchronized (control_mutex) {
            return (int) (co_master_balance[0] * 16384.0);
        }
    }

    public int getFineTuning() {
        synchronized (control_mutex) {
            return (int) (co_master_fine_tuning[0] * 16384.0);
        }
    }

    public int getCoarseTuning() {
        synchronized (control_mutex) {
            return (int) (co_master_coarse_tuning[0] * 16384.0);
        }
    }

    public void globalParameterControlChange(int[] slothpath, long[] params,
            long[] paramsvalue) {
        if (slothpath.length == 0)
            return;

        synchronized (control_mutex) {

            // slothpath: 01xx are reserved only for GM2

            if (slothpath[0] == 0x01 * 128 + 0x01) {
                for (int i = 0; i < paramsvalue.length; i++) {
                    reverb.globalParameterControlChange(slothpath, params[i],
                            paramsvalue[i]);
                }
            }
            if (slothpath[0] == 0x01 * 128 + 0x02) {
                for (int i = 0; i < paramsvalue.length; i++) {
                    chorus.globalParameterControlChange(slothpath, params[i],
                            paramsvalue[i]);
                }

            }

        }
    }

    public void processMessage(Object object) {
        if (object instanceof byte[])
            processMessage((byte[]) object);
        if (object instanceof MidiMessage)
            processMessage((MidiMessage)object);
    }

    public void processMessage(MidiMessage message) {
        if (message instanceof ShortMessage) {
            ShortMessage sms = (ShortMessage)message;
            processMessage(sms.getChannel(), sms.getCommand(),
                    sms.getData1(), sms.getData2());
            return;
        }
        processMessage(message.getMessage());
    }

    public void processMessage(byte[] data) {
        int status = 0;
        if (data.length > 0)
            status = data[0] & 0xFF;

        if (status == 0xF0) {
            processSystemExclusiveMessage(data);
            return;
        }

        int cmd = (status & 0xF0);
        int ch = (status & 0x0F);

        int data1;
        int data2;
        if (data.length > 1)
            data1 = data[1] & 0xFF;
        else
            data1 = 0;
        if (data.length > 2)
            data2 = data[2] & 0xFF;
        else
            data2 = 0;

        processMessage(ch, cmd, data1, data2);

    }

    public void processMessage(int ch, int cmd, int data1, int data2) {
        synchronized (synth.control_mutex) {
            activity();
        }

        if (cmd == 0xF0) {
            int status = cmd | ch;
            switch (status) {
            case ShortMessage.ACTIVE_SENSING:
                synchronized (synth.control_mutex) {
                    active_sensing_on = true;
                }
                break;
            default:
                break;
            }
            return;
        }

        SoftChannel[] channels = synth.channels;
        if (ch >= channels.length)
            return;
        SoftChannel softchannel = channels[ch];

        switch (cmd) {
        case ShortMessage.NOTE_ON:
            if(delay_midievent != 0)
                softchannel.noteOn(data1, data2, delay_midievent);
            else
                softchannel.noteOn(data1, data2);
            break;
        case ShortMessage.NOTE_OFF:
            softchannel.noteOff(data1, data2);
            break;
        case ShortMessage.POLY_PRESSURE:
            softchannel.setPolyPressure(data1, data2);
            break;
        case ShortMessage.CONTROL_CHANGE:
            softchannel.controlChange(data1, data2);
            break;
        case ShortMessage.PROGRAM_CHANGE:
            softchannel.programChange(data1);
            break;
        case ShortMessage.CHANNEL_PRESSURE:
            softchannel.setChannelPressure(data1);
            break;
        case ShortMessage.PITCH_BEND:
            softchannel.setPitchBend(data1 + data2 * 128);
            break;
        default:
            break;
        }

    }

    public long getMicrosecondPosition() {
        if(pusher_silent)
        {
            if(synth.weakstream != null)
            {
                return (long)((sample_pos  + synth.weakstream.silent_samples)
                        * (1000000.0 / samplerate));
            }
        }
        return (long)(sample_pos * (1000000.0 / samplerate));
    }

    public void close() {
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java SoftMainMixer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.