Guest User

Untitled

a guest
Nov 23rd, 2017
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 17.38 KB | None | 0 0
  1. /*
  2.  * To change this template, choose Tools | Templates
  3.  * and open the template in the editor.
  4.  */
  5. package soundly.impl;
  6.  
  7. import java.util.ArrayList;
  8. import java.util.HashMap;
  9. import java.util.List;
  10. import java.util.Map;
  11. import java.util.Set;
  12. import javax.sound.sampled.AudioFormat;
  13. import paulscode.sound.Channel;
  14. import paulscode.sound.FilenameURL;
  15. import paulscode.sound.ListenerData;
  16. import paulscode.sound.MidiChannel;
  17. import paulscode.sound.SoundBuffer;
  18. import paulscode.sound.SoundSystemConfig;
  19. import paulscode.sound.SoundSystemException;
  20. import paulscode.sound.SoundSystemLogger;
  21. import paulscode.sound.Source;
  22. import paulscode.sound.StreamThread;
  23. import soundly.Sound;
  24.  
  25. /**
  26.  * A simple rework of Library which is more geared toward fast access and
  27.  * modification of sources. Most of the code here was taken from Library.
  28.  *
  29.  * @author Paul, davedes
  30.  */
  31. public class SimpleLibrary {
  32.  
  33.     private StreamThread streamThread;
  34.    
  35.     protected Sound[] sounds;
  36.     /** A list of sounds representing those that are about to be played. */
  37.     protected Sound[] queue;
  38.     /** The actual list of channels. */
  39.     protected Channel[] channels;
  40.     /**
  41.      * Processes status messages, warnings, and error messages.
  42.      */
  43.     protected SoundSystemLogger logger;
  44.     /**
  45.      * Position and orientation of the listener.
  46.      */
  47.     protected ListenerData listener;
  48.     /**
  49.      * Map containing sound file data for easy lookup by filename / identifier.
  50.      */
  51.     protected HashMap<String, SoundBuffer> bufferMap = null;
  52.     /**
  53.      * Interface through which MIDI files can be played.
  54.      */
  55.     private MidiChannel midiChannel;
  56.     private int streamingCount;
  57.     private int normalCount;
  58.     private int channelCount;
  59.     private List<Source> tempSources;
  60.  
  61.     public SimpleLibrary() {
  62.         bufferMap = new HashMap<String, SoundBuffer>();
  63.         tempSources = new ArrayList<Source>();
  64.  
  65.         listener = new ListenerData(0.0f, 0.0f, 0.0f, // position
  66.                 0.0f, 0.0f, -1.0f, // look-at direction
  67.                 0.0f, 1.0f, 0.0f, // up direction
  68.                 0.0f);            // angle
  69.  
  70.         streamThread = new StreamThread();
  71.         streamThread.start();
  72.     }
  73.  
  74.     /* ########################################################################## */
  75.     /*                        BEGIN OVERRIDE METHODS                              */
  76.     /*                                                                            */
  77.     /*         The following methods should be overrided as required              */
  78.     /* ########################################################################## */
  79.    
  80.    
  81.     /**
  82.      * Initializes the sound library.
  83.      */
  84.     public void init() throws SoundSystemException {
  85.         Channel channel = null;
  86.         streamingCount = SoundSystemConfig.getNumberStreamingChannels();
  87.         normalCount = SoundSystemConfig.getNumberNormalChannels();
  88.         channelCount = streamingCount + normalCount;
  89.  
  90.         channels = new Channel[channelCount];
  91.         sounds = new Sound[channelCount];
  92.         queue = new Sound[channelCount];
  93.         for (int i = 0; i < channelCount; i++) {
  94.             channels[i] = createChannel(i < streamingCount
  95.                     ? SoundSystemConfig.TYPE_STREAMING
  96.                     : SoundSystemConfig.TYPE_NORMAL);
  97.         }
  98.  
  99.     }
  100.    
  101.     /**
  102.      * Stops all sources, shuts down sound library, and removes references to all
  103.      * instantiated objects. This will not cleanup() individual sources; that
  104.      * must be done through the Soundly engine.
  105.      */
  106.     public void cleanup() {
  107.         streamThread.kill();
  108.         streamThread.interrupt();
  109.  
  110.         // wait up to 5 seconds for stream thread to end:
  111.         for (int i = 0; i < 50; i++) {
  112.             if (!streamThread.alive()) {
  113.                 break;
  114.             }
  115.             try {
  116.                 Thread.sleep(100);
  117.             } catch (Exception e) {
  118.             }
  119.         }
  120.  
  121.         if (streamThread.alive()) {
  122.             message("Stream did not die... continuing cleanup");
  123.         }
  124.  
  125.         if (midiChannel != null) {
  126.             midiChannel.cleanup();
  127.             midiChannel = null;
  128.         }
  129.  
  130.         Channel channel = null;
  131.         for (int i = 0; i < channels.length; i++) {
  132.             if (channels[i] != null) {
  133.                 channels[i].close();
  134.                 channels[i].cleanup();
  135.                 channels[i] = null;
  136.             }
  137.         }
  138.         listener = null;
  139.         streamThread = null;
  140.        
  141.         //source.cleanup is handled elsewhere
  142.     }
  143.  
  144.     /**
  145.      * Creates a new channel of the specified type (normal or streaming).  Possible
  146.      * values for channel type can be found in the
  147.      * {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} class.
  148.      * @param type Type of channel.
  149.      * @return The new channel.
  150.      */
  151.     public Channel createChannel(int type) {
  152.         return new Channel(type);
  153.     }
  154.  
  155.     /**
  156.      * Checks if the no-sound library type is compatible.
  157.      * @return True or false.
  158.      */
  159.     public static boolean libraryCompatible() {
  160.         return true;  // the no-sound library is always compatible.
  161.     }
  162.  
  163.     /**
  164.      * Pre-loads a sound into memory.  
  165.      * @param filenameURL Filename/URL of the sound file to load.
  166.      * @return True if the sound loaded properly.
  167.      */
  168.     public boolean loadSound(FilenameURL filenameURL) {
  169.         return true;
  170.     }
  171.  
  172.     /**
  173.      * Saves the specified sample data, under the specified identifier.  This
  174.      * identifier can be later used in place of 'filename' parameters to reference
  175.      * the sample data.
  176.      * @param buffer the sample data and audio format to save.
  177.      * @param identifier What to call the sample.
  178.      * @return True if there weren't any problems.
  179.      */
  180.     public boolean loadSound(SoundBuffer buffer, String identifier) {
  181.         return true;
  182.     }
  183.  
  184.     /**
  185.      * Returns the filenames of all previously loaded sounds.
  186.      * @return LinkedList of String filenames.
  187.      */
  188.     public String[] loadedFilenames() {
  189.         Set<String> keys = bufferMap.keySet();
  190.         return keys.toArray(new String[keys.size()]);
  191.     }
  192.  
  193.     /**
  194.      * Removes a pre-loaded sound from memory.  This is a good method to use for
  195.      * freeing up memory after a large sound file is no longer needed.  NOTE: the
  196.      * source will remain in memory after this method has been called, for as long
  197.      * as the sound is attached to an existing source.
  198.      * @param filename Filename/identifier of the sound file to unload.
  199.      */
  200.     public void unloadSound(String filename) {
  201.         bufferMap.remove(filename);
  202.     }
  203.    
  204.     public Source createSource(String name, FilenameURL url, boolean streaming, boolean temporary) {
  205.         float r = SoundSystemConfig.getDefaultRolloff();
  206.         int att = SoundSystemConfig.ATTENUATION_NONE;
  207.         return new Source(false, streaming, false, name, url, null, 0, 0, 0, att, r, temporary);
  208.     }
  209.    
  210.     public Source rawDataStream(AudioFormat audioFormat, String name, boolean streaming, boolean temporary) {
  211.         float r = SoundSystemConfig.getDefaultRolloff();
  212.         int att = SoundSystemConfig.ATTENUATION_NONE;
  213.         Source s = new Source(audioFormat, false, name, 0, 0, 0, att, r);
  214.         s.setTemporary(temporary);
  215.         return s;
  216.     }
  217.  
  218.     public MidiChannel getMidi() {
  219.         return midiChannel;
  220.     }
  221.  
  222.     protected int findBestChannel(Sound sound) {
  223.         return 0;
  224.     }
  225.  
  226.     /**
  227.      * Feeds raw data through the specified source.  The source must be a
  228.      * streaming source and it can not be already associated with a file or URL to
  229.      * stream from.
  230.      * @param source Streaming source to play from.
  231.      * @param buffer Byte buffer containing raw audio data to stream.
  232.      * @return Number of prior buffers that have been processed, or -1 if unable to queue the buffer (if the source was culled, for example).
  233.      */
  234.     public int feedRawAudioData(Sound sound, byte[] buffer, int index) {
  235.         Source source = sound.getSource();
  236.         if (source == null) {
  237.             throw new IllegalArgumentException("Source parameter null in method "
  238.                     + "'feedRawAudioData'");
  239.         }
  240.         if (!source.toStream) {
  241.             throw new IllegalArgumentException("Only a streaming source may be specified in "
  242.                     + "method 'feedRawAudioData'");
  243.         }
  244.         if (!source.rawDataStream) {
  245.             throw new IllegalArgumentException("Streaming source already associated with a "
  246.                     + "file or URL in method'feedRawAudioData'");
  247.         }
  248.         if (index > streamingCount) {
  249.             throw new IllegalArgumentException("Given index for feedRawAudioData cannot be > streamingCount");
  250.         }
  251.  
  252.         if (!source.playing() || source.channel == null) {
  253.             Channel channel;
  254.             if (source.channel != null && (source.channel.attachedSource
  255.                     == source)) {
  256.                 channel = source.channel;
  257.             } else {
  258.                 int cInd = index >= 0 ? index : findBestChannel(sound);
  259.                 channel = channels[cInd];
  260.             }
  261.  
  262.             int processed = source.feedRawAudioData(channel, buffer);
  263.             channel.attachedSource = source;
  264.             streamThread.watch(source);
  265.             streamThread.interrupt();
  266.             return processed;
  267.         }
  268.  
  269.         return (source.feedRawAudioData(source.channel, buffer));
  270.     }
  271.  
  272.     /**
  273.      * Plays the specified source.
  274.      * @param source The source to play.
  275.      */
  276.     public void play(Sound sound, int index) {
  277.         Source source = sound.getSource();
  278.         if (source == null) {
  279.             return;
  280.         }
  281.        
  282.         if (source.toStream && index > streamingCount) {
  283.             throw new IllegalArgumentException("Given play() index for streaming sound must be <= streamCount");
  284.         } else if (!source.toStream && index <= streamingCount) {
  285.             throw new IllegalArgumentException("Given play() index for normal sound must be > streamCount");
  286.         }
  287.        
  288.         // raw data streams will automatically play when data is sent to them,
  289.         // so no need to do anything here.
  290.         if (source.rawDataStream) {
  291.             return;
  292.         }
  293.  
  294.         if (!source.active()) {
  295.             return;
  296.         }
  297.  
  298.         if (!source.playing()) {
  299.             int cInd = index >= 0 ? index : findBestChannel(sound);
  300.             Channel channel = channels[cInd];
  301.  
  302.             if (channel != null) {
  303.                 if (source.channel != null
  304.                         && source.channel.attachedSource != source) {
  305.                     source.channel = null;
  306.                 }
  307.                 channel.attachedSource = source;
  308.                 source.play(channel);
  309.                 if (source.toStream) {
  310.                     streamThread.watch(source);
  311.                     streamThread.interrupt();
  312.                 }
  313.             }
  314.         }
  315.     }
  316.  
  317.     /**
  318.      * Sets the overall volume to the specified value, affecting all sources.
  319.      * @param value New volume, float value ( 0.0f - 1.0f ).
  320.      */
  321.     public void setMasterVolume(float value) {
  322.         SoundSystemConfig.setMasterGain(value);
  323.         if (midiChannel != null) {
  324.             midiChannel.resetGain();
  325.         }
  326.     }
  327.  
  328.     private void listenerChanged() {
  329.         for (int i = 0; i < channelCount; i++) {
  330.             if (queue[i] != null) {
  331.                 queue[i].listenerChanged();
  332.             } else if (sounds[i] != null) {
  333.                 sounds[i].listenerChanged();
  334.             }
  335.         }
  336.     }
  337.  
  338.     public void setListenerPosition(float x, float y, float z) {
  339.         listener.setPosition(x, y, z);
  340.         listenerChanged();
  341.     }
  342.  
  343.     /**
  344.      * Changes the listeners orientation to the specified 'angle' radians
  345.      * counterclockwise around the y-Axis.
  346.      * @param angle Angle in radians.
  347.      */
  348.     public void setListenerAngle(float angle) {
  349.         listener.setAngle(angle);
  350.         listenerChanged();
  351.     }
  352.  
  353.     /**
  354.      * Changes the listeners orientation using the specified coordinates.
  355.      * @param lookX X element of the look-at direction.
  356.      * @param lookY Y element of the look-at direction.
  357.      * @param lookZ Z element of the look-at direction.
  358.      * @param upX X element of the up direction.
  359.      * @param upY Y element of the up direction.
  360.      * @param upZ Z element of the up direction.
  361.      */
  362.     public void setListenerOrientation(float lookX, float lookY, float lookZ,
  363.             float upX, float upY, float upZ) {
  364.         listener.setOrientation(lookX, lookY, lookZ, upX, upY, upZ);
  365.         listenerChanged();
  366.     }
  367.  
  368.     /**
  369.      * Changes the listeners position and orientation using the specified listener
  370.      * data.
  371.      * @param l Listener data to use.
  372.      */
  373.     public void setListenerData(ListenerData l) {
  374.         listener.setData(l);
  375.     }
  376.  
  377.     /**
  378.      * Searches for and removes all temporary sources that have finished playing.
  379.      */
  380.     public void removeTemporarySources() {
  381.         for (Source s : tempSources) {
  382.             if (!s.playing()) {
  383.                 s.cleanup();
  384.             }
  385.         }
  386.         tempSources.clear();
  387.  
  388.     }
  389.  
  390.     /**
  391.      * Makes sure the current volume levels of streaming sources and MIDI are
  392.      * correct.  This method is designed to help reduce the "jerky" fading behavior
  393.      * that happens when using some library and codec pluggins (such as
  394.      * LibraryJavaSound and CodecJOrbis).  This method has no effect on normal
  395.      * "non-streaming" sources.  It would normally be called somewhere in the main
  396.      * "game loop".  IMPORTANT: To optimize frame-rates, do not call this method
  397.      * for every frame.  It is better to just call this method at some acceptable
  398.      * "granularity" (play around with different granularities to find what sounds
  399.      * acceptable for a particular situation).
  400.      */
  401.     public void checkFadeVolumes() {
  402.         if (midiChannel != null) {
  403.             midiChannel.resetGain();
  404.         }
  405.         Channel c;
  406.         Source s;
  407.         for (int x = 0; x < streamingCount; x++) {
  408.             c = channels[x];
  409.             if (c != null) {
  410.                 s = c.attachedSource;
  411.                 if (s != null) {
  412.                     s.checkFadeOut();
  413.                 }
  414.             }
  415.         }
  416.         c = null;
  417.         s = null;
  418.     }
  419.  
  420.     /**
  421.      *
  422.      * Specifies the MIDI channel to use.
  423.      * @param c New MIDI channel.
  424.      */
  425.     public void setMidiChannel(MidiChannel c) {
  426.         if (midiChannel != null && midiChannel != c) {
  427.             midiChannel.cleanup();
  428.         }
  429.  
  430.         midiChannel = c;
  431.     }
  432.  
  433.     /**
  434.      * Loads the specified MIDI file, and saves the source information about it.
  435.      * @param toLoop Midi file should loop or play once.
  436.      * @param sourcename Source identifier.
  437.      * @param filenameURL Filename/URL of the MIDI file to load.
  438.      * @return the newly created MidiChannel
  439.      */
  440.     public MidiChannel loadMidi(boolean toLoop, String sourcename,
  441.             FilenameURL filenameURL) throws SoundSystemException {
  442.         if (filenameURL == null) {
  443.             throw new SoundSystemException("Filename/URL not specified in method 'loadMidi'.");
  444.         }
  445.  
  446.         if (!filenameURL.getFilename().matches(
  447.                 SoundSystemConfig.EXTENSION_MIDI)) {
  448.             throw new SoundSystemException("Filename/identifier doesn't end in '.mid' or"
  449.                     + "'.midi' in method loadMidi.");
  450.         }
  451.  
  452.         if (midiChannel == null) {
  453.             midiChannel = new MidiChannel(toLoop, sourcename, filenameURL);
  454.         } else {
  455.             midiChannel.switchSource(toLoop, sourcename, filenameURL);
  456.         }
  457.         return midiChannel;
  458.     }
  459.  
  460.     /**
  461.      * Notifies the underlying library that the Doppler parameters have changed.
  462.      */
  463.     public void dopplerChanged()
  464.     {}
  465.    
  466.     /**
  467.      * Unloads the current Midi file.
  468.      */
  469.     public void unloadMidi() {
  470.         if (midiChannel != null) {
  471.             midiChannel.cleanup();
  472.         }
  473.         midiChannel = null;
  474.     }
  475.  
  476.     /**
  477.      * Returns information about the listener.
  478.      * @return A ListenerData object.
  479.      */
  480.     public ListenerData getListenerData() {
  481.         return listener;
  482.     }
  483.  
  484.     /**
  485.      * Indicates whether or not this library requires some codecs to reverse-order
  486.      * the audio data they generate.
  487.      * @return True if audio data should be reverse-ordered.
  488.      */
  489.     public boolean reverseByteOrder() {
  490.         return false;
  491.     }
  492.  
  493.     /**
  494.      * Returns the short title of this library type.
  495.      * @return A short title.
  496.      */
  497.     public static String getTitle() {
  498.         return "No Sound";
  499.     }
  500.  
  501.     /**
  502.      * Returns a longer description of this library type.
  503.      * @return A longer description.
  504.      */
  505.     public static String getDescription() {
  506.         return "Silent Mode";
  507.     }
  508.  
  509.     /**
  510.      * Prints a message.
  511.      * @param message Message to print.
  512.      */
  513.     protected void message(String message) {
  514.         logger.message(message, 0);
  515.     }
  516.  
  517.     /**
  518.      * Prints an important message.
  519.      * @param message Message to print.
  520.      */
  521.     protected void importantMessage(String message) {
  522.         logger.importantMessage(message, 0);
  523.     }
  524.  
  525.  
  526.     public String getClassName() {
  527.         return getClass().getName();
  528.     }
  529. }
Add Comment
Please, Sign In to add comment