jmri.jmrit.vsdecoder.SteamSound.java Source code

Java tutorial

Introduction

Here is the source code for jmri.jmrit.vsdecoder.SteamSound.java

Source

package jmri.jmrit.vsdecoder;

/*
 * <hr>
 * This file is part of JMRI.
 * <P>
 * JMRI is free software; you can redistribute it and/or modify it under 
 * the terms of version 2 of the GNU General Public License as published 
 * by the Free Software Foundation. See the "COPYING" file for a copy
 * of this license.
 * <P>
 * JMRI 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 
 * for more details.
 * <P>
 *
 * @author         Mark Underwood Copyright (C) 2011
 * @version         $Revision: 18481 $
 */
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import jmri.util.PhysicalLocation;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// Usage:
// SteamSound() : constructor
// play() : plays short horn pop
// loop() : starts extended sustain horn
// stop() : ends extended sustain horn (plays end sound)
class SteamSound extends EngineSound {

    // Inner class for handling steam RPM sounds
    class RPMSound {

        public SoundBite sound;
        public int min_rpm;
        public int max_rpm;
        public boolean use_chuff;
        private javax.swing.Timer t;

        public RPMSound(SoundBite sb, int min_r, int max_r, boolean chuff) {
            sound = sb;
            min_rpm = min_r;
            max_rpm = max_r;
            use_chuff = chuff;
            if (use_chuff) {
                sound.setLooped(false);
                t = newTimer(1000, true, new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        doChuff();
                    }
                });
            }
        }

        private void doChuff() {
            sound.play();
        }

        public void setRPM(int rpm) {
            if (use_chuff) {
                t.setDelay(calcChuffInterval(rpm));
            }
        }

        public void startChuff() {
            if (!t.isRunning()) {
                t.start();
            }
        }

        public void stopChuff() {
            t.stop();
        }
    }

    // Engine Sounds
    ArrayList<RPMSound> rpm_sounds;
    SoundBite idle_sound;
    int top_speed;
    int driver_diameter;
    int num_cylinders;
    RPMSound current_rpm_sound;
    int current_chuff_time;

    public SteamSound(String name) {
        super(name);
    }

    // Note:  Play and Loop do the same thing, since all of the notch sounds are set to loop.
    @Override
    public void play() {
        log.debug("EngineSound Play");
        if (engine_started || auto_start_engine) {
            current_rpm_sound.sound.play();
            is_playing = true;
        }
    }

    // Note:  Play and Loop do the same thing, since all of the notch sounds are set to loop.
    @Override
    public void loop() {
        if ((engine_started || auto_start_engine)) {
            current_rpm_sound.sound.play();
            is_playing = true;
        }
    }

    @Override
    public void stop() {
        current_rpm_sound.sound.stop();
        is_playing = false;
    }

    public void startEngine() {
        log.debug("Starting Engine");
        current_rpm_sound = getRPMSound(0);
        current_rpm_sound.sound.loop();
        engine_started = true;
    }

    public void stopEngine() {
        current_rpm_sound.sound.fadeOut();
        engine_started = false;
    }

    private RPMSound getRPMSound(int rpm) {
        for (RPMSound rps : rpm_sounds) {
            if ((rps.min_rpm <= rpm) && (rps.max_rpm >= rpm)) {
                return (rps);
            }
        }
        // Didn't find anything
        return (null);
    }

    private int calcRPM(float t) {
        // Speed = % of top_speed (mph)
        // RPM = speed * ((inches/mile) / (minutes/hour)) / (pi * driver_diameter)
        double rpm_f = speedCurve(t) * top_speed * 1056 / (Math.PI * driver_diameter);
        log.debug("RPM Calculated: " + rpm_f + " (int) " + (int) Math.round(rpm_f));
        return ((int) Math.round(rpm_f));
    }

    private double speedCurve(float t) {
        return (Math.pow(t, 2.0) / 1.0);
    }

    private int calcChuffInterval(int rpm) {
        return (1000 * num_cylinders / rpm);
    }

    @Override
    public void changeThrottle(float t) {
        RPMSound rps;
        // Yes, I'm checking to see if rps and current_rpm_sound are the *same object*
        if (((rps = getRPMSound(calcRPM(t))) != null) && (rps != current_rpm_sound)) {
            // Stop the current sound
            if ((current_rpm_sound != null) && (current_rpm_sound.sound != null)) {
                current_rpm_sound.sound.fadeOut();
                if (current_rpm_sound.use_chuff) {
                    current_rpm_sound.stopChuff();
                }
            }
            // Start the new sound.
            current_rpm_sound = rps;
            if (rps.use_chuff) {
                rps.setRPM(calcRPM(t));
                rps.startChuff();
            }
            rps.sound.fadeIn();
        }
        log.debug("RPS = " + rps + " RPM = " + calcRPM(t) + " current_RPM = " + current_rpm_sound);
    }

    @Override
    public void shutdown() {
        for (RPMSound rps : rpm_sounds) {
            rps.sound.stop();
        }
    }

    @Override
    public void mute(boolean m) {
        for (RPMSound rps : rpm_sounds) {
            rps.sound.mute(m);
        }
    }

    @Override
    public void setVolume(float v) {
        for (RPMSound rps : rpm_sounds) {
            rps.sound.setVolume(v);
        }
    }

    @Override
    public void setPosition(PhysicalLocation p) {
        for (RPMSound rps : rpm_sounds) {
            rps.sound.setPosition(p);
        }
    }

    public Element getXml() {
        // OUT OF DATE
        return (super.getXml());
    }

    @Override
    public void setXml(Element e, VSDFile vf) {
        Element el;
        //int num_rpms;
        String fn;
        SoundBite sb;

        super.setXml(e, vf);

        log.debug("Steam EngineSound: " + e.getAttribute("name").getValue());
        String n = e.getChild("top-speed").getValue();
        if (n != null) {
            top_speed = Integer.parseInt(n);
            //log.debug("Top speed: " + top_speed + " MPH");
        }
        n = e.getChildText("driver-diameter");
        if (n != null) {
            driver_diameter = Integer.parseInt(n);
            //log.debug("Driver diameter: " + driver_diameter + " inches");
        }
        n = e.getChildText("cylinders");
        if (n != null) {
            num_cylinders = Integer.parseInt(n);
            //log.debug("Num Cylinders: " + num_cylinders);
        }
        // For now, num_rpms is not used.  
        /*
              n = e.getChild("rpm-steps").getValue();
              if (n != null) {
              num_rpms = Integer.parseInt(n);
              //log.debug("Number of rpm steps: " + num_rpms);
              }
              */

        rpm_sounds = new ArrayList<RPMSound>();

        // Get the RPM steps
        Iterator<Element> itr = (e.getChildren("rpm-step")).iterator();
        int i = 0;
        while (itr.hasNext()) {
            el = itr.next();
            fn = el.getChildText("file");
            int min_r = Integer.parseInt(el.getChildText("min-rpm"));
            int max_r = Integer.parseInt(el.getChildText("max-rpm"));
            //log.debug("Notch: " + nn + " File: " + fn);
            sb = new SoundBite(vf, fn, "Steam_n" + i, "Steam_" + i);
            sb.setLooped(true);
            sb.setFadeTimes(100, 100);
            sb.setGain(setXMLGain(el));
            // Store in the list.
            boolean chuff = false;
            Element c;
            if ((c = el.getChild("use-chuff-gen")) != null) {
                log.debug("Use Chuff Generator " + c.toString());
                chuff = true;
            }

            rpm_sounds.add(new RPMSound(sb, min_r, max_r, chuff));
            i++;
        }

        /*
         // Get the start and stop sounds
         el = e.getChild("start-sound");
         if (el != null) {
         fn = el.getChild("file").getValue();
         log.debug("Start sound: " + fn);
         start_sound = new SoundBite(vf, fn, "Engine_start", 
         "Engine_Start");
         // Handle gain
         start_sound.setGain(setXMLGain(el));
         start_sound.setLooped(false);
         }
         */
    }

    private static final Logger log = LoggerFactory.getLogger(SteamSound.class.getName());

}