All pastes #17856 Raw Edit

rick

public java v1 · immutable
#17856 ·published 2005-07-16 20:21 UTC
rendered paste body
package org.hamnett.adm.audio.impl;import java.util.ArrayList;import java.util.List;import javax.sound.sampled.AudioSystem;import javax.sound.sampled.CompoundControl;import javax.sound.sampled.Control;import javax.sound.sampled.FloatControl;import javax.sound.sampled.Line;import javax.sound.sampled.LineUnavailableException;import javax.sound.sampled.Mixer;import javax.sound.sampled.Port;import org.hamnett.adm.audio.Audio;/** * Default implementation of the SynchronousAudio interface using javax.sound. *  * @author srt * @version $Id: SynchronousAudioImpl.java,v 1.4 2005/07/16 11:48:33 srt Exp $ */class SynchronousAudioImpl implements SynchronousAudio{    public static final long MILLISECONDS_PER_STEP = 100;    boolean cancel;    double fadeToVolume = -1;    //package restricted constructor    SynchronousAudioImpl()    {            }        public void cancelFade()    {        this.cancel = true;    }        public double getVolume()    {        VolumeControl volumeControl;        double currentVolume = 0;        if (fadeToVolume != -1)        {            return fadeToVolume;        }                volumeControl = openVolumeControl();        if (volumeControl == null)        {            return 0;        }        currentVolume = volumeControl.getVolume();        volumeControl.close();        return currentVolume;    }    public void fadeVolume(double percent, long velocity)    {        doFade(percent, true, velocity);    }    public void fadeVolumeTo(double newVolume, long velocity)    {        doFade(newVolume, false, velocity);    }        private void doFade(double value, boolean isRelative, long velocity)    {        VolumeControl volumeControl;        double oldVolume; // volume before fading starts        double currentVolume;        double newVolume; // new volume after fading has finished        long milliseconds; // duration of this fading        double volumeDiff;        double volumeDiffPerStep;        int steps;        cancel = false;        volumeControl = openVolumeControl();        if (volumeControl == null)        {            return;        }        oldVolume = volumeControl.getVolume();        currentVolume = oldVolume;                if (isRelative)        {            volumeDiff = oldVolume * (1 - value);            newVolume = oldVolume - volumeDiff;        }        else        {            newVolume = value;            volumeDiff = oldVolume - newVolume;        }        fadeToVolume = newVolume;        milliseconds = (long) (Math.abs(volumeDiff) * velocity);        steps = (int) (milliseconds / MILLISECONDS_PER_STEP);        volumeDiffPerStep = volumeDiff / steps;        System.out.println("Fading from " + oldVolume + " to " + newVolume + " in " + milliseconds + "ms");                for (int i = 0; i < steps && !cancel; i++)        {            currentVolume -= volumeDiffPerStep;            // System.out.println(currentVolume);            volumeControl.setVolume(currentVolume);            try            {                Thread.sleep(MILLISECONDS_PER_STEP);            }            catch (InterruptedException e)            {                // swallow            }        }        // System.out.println(newVolume);        if (cancel)        {            System.out.println("Fading was canceled.");        }        else        {            volumeControl.setVolume(newVolume);        }        fadeToVolume = -1;        volumeControl.close();    }    // TODO let the user choose which Port to use for volume adjustment    Port getMasterPort(Mixer mixer)    {        Line.Info[] lineInfos = mixer.getTargetLineInfo();        for (int i = 0; i < lineInfos.length; i++)        {            Line.Info lineInfo = lineInfos[i];            Line line;            try            {                line = mixer.getLine(lineInfo);            }            catch (LineUnavailableException e)            {                continue;            }            if (line instanceof Port                    && lineInfo.toString().startsWith("Master"))            {                return (Port) line;            }        }        return null;    }    VolumeControl openVolumeControl()    {        Mixer mixer;        Port port;        FloatControl volumeFloatControl;        mixer = getMixer();        if (mixer == null)        {            return null;        }        try        {            port = getMasterPort(mixer);            port.open();            volumeFloatControl = getVolumeFloatControl(port);        }        catch (LineUnavailableException e)        {            // hmm...            System.out.println("Port not available");            return null;        }        return new PortBasedVolumeControl(volumeFloatControl, port);    }    /**     * Returns the FloatControl to adjust volume for the given Port.     *      * @param port the Port that contains the Volume Control     * @return the Volume Control for the given Port or <code>null</code> if     *         the Port doesn't support Volume adjustment.     */    FloatControl getVolumeFloatControl(Port port)    {        FloatControl volumeControl = null;        boolean bClosePort = false;        if (!port.isOpen())        {            try            {                port.open();            }            catch (LineUnavailableException e)            {                throw new IllegalArgumentException("Unable to open port "                        + port.getLineInfo());            }        }        Control[] controls = port.getControls();        for (int j = 0; j < controls.length && volumeControl == null; j++)        {            Control control = controls[j];            if (isVolumeFloatControl(control))            {                volumeControl = (FloatControl) control;            }            // nested controls?            if (control instanceof CompoundControl)            {                Control[] memberControls;                memberControls = ((CompoundControl) control)                        .getMemberControls();                for (int k = 0; k < memberControls.length; k++)                {                    Control memberControl = memberControls[k];                    if (isVolumeFloatControl(memberControl))                    {                        volumeControl = (FloatControl) memberControl;                        break;                    }                }            }        }        if (bClosePort)        {            port.close();        }        return volumeControl;    }    /**     * Checks if a Control is a Volume Control.     *      * @param control the Control to test     * @return <code>true</code> if the control is a volume control,     *         <code>false</code> otherwise.     */    private boolean isVolumeFloatControl(Control control)    {        return control instanceof FloatControl                && control.getType().equals(FloatControl.Type.VOLUME);    }    Mixer getMixer()    {        // TODO add config        List mixers;                mixers = getPortMixers();        if (mixers.size() < 1)        {            System.out.println("No mixer available.");            return null;        }                    return (Mixer) mixers.get(0);    }    /**     * Returns the Mixers that support Port lines.     *      * @return a List of the availble Mixers that support Port lines.     */    private List getPortMixers()    {        List supportingMixers = new ArrayList();        Mixer.Info[] mixerInfos;        mixerInfos = AudioSystem.getMixerInfo();        for (int i = 0; i < mixerInfos.length; i++)        {            Mixer mixer = AudioSystem.getMixer(mixerInfos[i]);            boolean bSupportsPorts = arePortsSupported(mixer);            if (bSupportsPorts)            {                supportingMixers.add(mixer);            }        }        return supportingMixers;    }    /**     * Checks if a Mixer supports Port lines.     *      * @param mixer the Mixer to test     * @return <code>true</code> if the given Mixer supports Port lines,     *         <code>false</code> otherwise.     */    private boolean arePortsSupported(Mixer mixer)    {        Line.Info[] infos;        infos = mixer.getSourceLineInfo();        for (int i = 0; i < infos.length; i++)        {            if (infos[i] instanceof Port.Info)            {                return true;            }        }        infos = mixer.getTargetLineInfo();        for (int i = 0; i < infos.length; i++)        {            if (infos[i] instanceof Port.Info)            {                return true;            }        }        return false;    }    public static void main(String[] args)    {        Audio audio;        audio = new SynchronousAudioImpl();        audio.fadeVolume(0.2, 3000);        audio.fadeVolumeTo(1.0, 2000);    }}