Slick Forums

Discuss the Slick 2D Library
It is currently Fri May 24, 2013 7:54 am

All times are UTC




Post new topic Reply to topic  [ 11 posts ] 
Author Message
PostPosted: Tue Sep 08, 2009 3:31 pm 
Offline

Joined: Wed Jan 07, 2009 9:20 pm
Posts: 41
I have modified the following files to correct volume issues for music, and allow calls to Music.play(), loop() and setPosition() to be threaded. These changes include NateS's fixes for setPosition listed previously.

Music.java
Code:
package org.newdawn.slick;

import java.net.URL;
import java.util.ArrayList;

import org.newdawn.slick.openal.Audio;
import org.newdawn.slick.openal.AudioImpl;
import org.newdawn.slick.openal.SoundStore;
import org.newdawn.slick.util.Log;

/**
* A piece of music loaded and playable within the game. Only one piece of music can
* play at any given time and a channel is reserved so music will always play.
*
* @author kevin
* @author Nathan Sweet <misc@n4te.com>
* @author Rockstar Enabled threaded play/loop and setPosition
*/
public class Music {
   /** The music currently being played or null if none */
   private static Music currentMusic;
   
   /**
    * Poll the state of the current music. This causes streaming music
    * to stream and checks listeners. Note that if you're using a game container
    * this will be auto-magically called for you.
    *
    * @param delta The amount of time since last poll
    */
   public static void poll(int delta) {
      if (currentMusic != null && currentMusic.playing) {
         SoundStore.get().poll(delta);
         if (!SoundStore.get().isMusicPlaying()) {
            if (!currentMusic.positioning) {
               Music oldMusic = currentMusic;
               currentMusic = null;
               oldMusic.fireMusicEnded();
            }
         } else {
            currentMusic.update(delta);
         }
      }
   }
   
   /** The sound from FECK representing this music */
   private Audio sound;
   /** True if the music is playing */
   private boolean playing;
   /** The list of listeners waiting for notification that the music ended */
   private ArrayList listeners = new ArrayList();
   /** The volume of this music */
   private float volume = 1.0f;
   /** Start gain for fading in/out */
   private float fadeStartGain;
   /** End gain for fading in/out */
   private float fadeEndGain;
   /** Countdown for fading in/out */
   private int fadeTime;
   /** Duration for fading in/out */
   private int fadeDuration;
   /** True if music should be stopped after fading in/out */
   private boolean stopAfterFade;
   /** True if the music is being repositioned and it is therefore normal that it's not playing */
   private boolean positioning;
   
   /**
    * Create and load a piece of music (either OGG or MOD/XM)
    *
    * @param ref The location of the music
    * @throws SlickException
    */
   public Music(String ref) throws SlickException {
      this(ref, false);
   }

   /**
    * Create and load a piece of music (either OGG or MOD/XM)
    *
    * @param ref The location of the music
    * @throws SlickException
    */
   public Music(URL ref) throws SlickException {
      this(ref, false);
   }
   
   /**
    * Create and load a piece of music (either OGG or MOD/XM)
    *
    * @param url The location of the music
    * @param streamingHint A hint to indicate whether streaming should be used if possible
    * @throws SlickException
    */
   public Music(URL url, boolean streamingHint) throws SlickException {
      SoundStore.get().init();
      String ref = url.getFile();
      
      try {
         if (ref.toLowerCase().endsWith(".ogg")) {
            if (streamingHint) {
               sound = SoundStore.get().getOggStream(url);
            } else {
               sound = SoundStore.get().getOgg(url.openStream());
            }
         } else if (ref.toLowerCase().endsWith(".wav")) {
            sound = SoundStore.get().getWAV(url.openStream());
         } else if (ref.toLowerCase().endsWith(".xm") || ref.toLowerCase().endsWith(".mod")) {
            sound = SoundStore.get().getMOD(url.openStream());
         } else if (ref.toLowerCase().endsWith(".aif") || ref.toLowerCase().endsWith(".aiff")) {
            sound = SoundStore.get().getAIF(url.openStream());
         } else {
            throw new SlickException("Only .xm, .mod, .ogg, and .aif/f are currently supported.");
         }
      } catch (Exception e) {
         Log.error(e);
         throw new SlickException("Failed to load sound: "+url);
      }
   }
   
   /**
    * Create and load a piece of music (either OGG or MOD/XM)
    *
    * @param ref The location of the music
    * @param streamingHint A hint to indicate whether streaming should be used if possible
    * @throws SlickException
    */
   public Music(String ref, boolean streamingHint) throws SlickException {
      SoundStore.get().init();
      
      try {
         if (ref.toLowerCase().endsWith(".ogg")) {
            if (streamingHint) {
               sound = SoundStore.get().getOggStream(ref);
            } else {
               sound = SoundStore.get().getOgg(ref);
            }
         } else if (ref.toLowerCase().endsWith(".wav")) {
            sound = SoundStore.get().getWAV(ref);
         } else if (ref.toLowerCase().endsWith(".xm") || ref.toLowerCase().endsWith(".mod")) {
            sound = SoundStore.get().getMOD(ref);
         } else if (ref.toLowerCase().endsWith(".aif") || ref.toLowerCase().endsWith(".aiff")) {
            sound = SoundStore.get().getAIF(ref);
         } else {
            throw new SlickException("Only .xm, .mod, .ogg, and .aif/f are currently supported.");
         }
      } catch (Exception e) {
         Log.error(e);
         throw new SlickException("Failed to load sound: "+ref);
      }
   }

   /**
    * Add a listener to this music
    *
    * @param listener The listener to add
    */
   public void addListener(MusicListener listener) {
      listeners.add(listener);
   }

   /**
    * Remove a listener from this music
    *
    * @param listener The listener to remove
    */
   public void removeListener(MusicListener listener) {
      listeners.remove(listener);
   }
   
   /**
    * Fire notifications that this music ended
    */
   private void fireMusicEnded() {
      playing = false;
      for (int i=0;i<listeners.size();i++) {
         ((MusicListener) listeners.get(i)).musicEnded(this);
      }
   }

   /**
    * Fire notifications that this music was swapped out
    *
    * @param newMusic The new music that will be played
    */
   private void fireMusicSwapped(Music newMusic) {
      playing = false;
      for (int i=0;i<listeners.size();i++) {
         ((MusicListener) listeners.get(i)).musicSwapped(this, newMusic);
      }
   }
   /**
    * Loop the music
    */
   public void loop() {
      loop(1.0f, 1.0f);
   }
   
   /**
    * Play the music
    */
   public void play() {
      play(1.0f, 1.0f);
   }

   /**
    * Play the music at a given pitch and volume
    *
    * @param pitch The pitch to play the music at (1.0 = default)
    * @param volume The volume to play the music at (1.0 = default)
    */
   public void play(float pitch, float volume) {
      startMusic(pitch, volume, false);
   }

   /**
    * Loop the music at a given pitch and volume
    *
    * @param pitch The pitch to play the music at (1.0 = default)
    * @param volume The volume to play the music at (1.0 = default)
    */
   public void loop(float pitch, float volume) {
      startMusic(pitch, volume, true);
   }
   
   /**
    * play or loop the music at a given pitch and volume
    * @param pitch The pitch to play the music at (1.0 = default)
    * @param volume The volume to play the music at (1.0 = default)
    * @param loop if false the music is played once, the music is looped otherwise
    */
   private void startMusic(float pitch, float volume, boolean loop) {
      if (currentMusic != null) {
         currentMusic.stop();
         currentMusic.fireMusicSwapped(this);
      }
      
      currentMusic = this;
      if (volume < 0.0f)
         volume = 0.0f;
      if (volume > 1.0f)
         volume = 1.0f;

      setVolume(volume);
      sound.playAsMusic(pitch, volume, loop);
      playing = true;
   }
   
   /**
    * Pause the music playback
    */
   public void pause() {
      playing = false;
      AudioImpl.pauseMusic();
   }
   
   /**
    * Stop the music playing
    */
   public void stop() {
      sound.stop();
   }
   
   /**
    * Resume the music playback
    */
   public void resume() {
      playing = true;
      AudioImpl.restartMusic();
   }
   
   /**
    * Check if the music is being played
    *
    * @return True if the music is being played
    */
   public boolean playing() {
      return (currentMusic == this) && (playing);
   }
   
   /**
    * Set the volume of the music as a factor of the global volume setting
    *
    * @param volume The volume to play music at. 0 - 1, 1 is Max
    */
   public void setVolume(float volume) {
      // Bounds check
      if(volume > 1) {
         volume = 1;
      } else if(volume < 0) {
         volume = 0;
      }
      
      this.volume = volume;
      // This sound is being played as music
      if (currentMusic == this) {
         SoundStore.get().setCurrentMusicVolume(volume);
      }
   }

   /**
    * Get the individual volume of the music
    * @return The volume of this music, still effected by global SoundStore volume. 0 - 1, 1 is Max
    */
   public float getVolume() {
      return volume;
   }

   /**
    * Fade this music to the volume specified
    *
    * @param duration Fade time in milliseconds.
    * @param endVolume The target volume
    * @param stopAfterFade True if music should be stopped after fading in/out
    */
   public void fade (int duration, float endVolume, boolean stopAfterFade) {
      this.stopAfterFade = stopAfterFade;
      fadeStartGain = volume;
      fadeEndGain = endVolume;
      fadeDuration = duration;
      fadeTime = duration;
   }

   /**
    * Update the current music applying any effects that need to updated per
    * tick.
    *
    * @param delta The amount of time in milliseconds thats passed since last update
    */
   void update(int delta) {
      if (!playing) {
         return;
      }
       
      if (fadeTime > 0) {
         fadeTime -= delta;
         if (fadeTime < 0) {
            fadeTime = 0;
            if (stopAfterFade) {
               stop();
               return;
            }
         }
         
         float offset = (fadeEndGain - fadeStartGain) * (1 - (fadeTime / (float)fadeDuration));
         setVolume(fadeStartGain + offset);
      }
   }

   /**
    * Seeks to a position in the music. For streaming music, seeking before the current position causes
    * the stream to be reloaded.
    *
    * @param position Position in seconds.
    * @return True if the seek was successful
    */
   public boolean setPosition (float position) {
      if (playing) {
         positioning = true;
         playing = false;
         boolean result = sound.setPosition(position);
         playing = true;
         positioning = false;
         
         return result;
      } else {
         return false;
      }
   }

   /**
    * The position into the sound thats being played
    *
    * @return The current position in seconds.
    */
   public float getPosition () {
      return sound.getPosition();
   }
}


SoundStore.java
Code:
package org.newdawn.slick.openal;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;

import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.OpenALException;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;

/**
* Responsible for holding and playing the sounds used in the game.
*
* @author Kevin Glass
* @author Rockstar setVolume cleanup
*/
public class SoundStore {
   
   /** The single instance of this class */
   private static SoundStore store = new SoundStore();
   
   /** True if sound effects are turned on */
   private boolean sounds;
   /** True if music is turned on */
   private boolean music;
   /** True if sound initialisation succeeded */
   private boolean soundWorks;
   /** The number of sound sources enabled - default 8 */
   private int sourceCount;
   /** The map of references to IDs of previously loaded sounds */
   private HashMap loaded = new HashMap();
   /** The ID of the buffer containing the music currently being played */
   private int currentMusic = -1;
   /** The OpenGL AL sound sources in use */
   private IntBuffer sources;
   /** The next source to be used for sound effects */
   private int nextSource;
   /** True if the sound system has been initialise */
   private boolean inited = false;
   /** The MODSound to be updated */
   private MODSound mod;
   /** The stream to be updated */
   private OpenALStreamPlayer stream;
   
   /** The global music volume setting */
   private float musicVolume = 1.0f;
   /** The global sound fx volume setting */
   private float soundVolume = 1.0f;
   /** The volume given for the last current music */
   private float lastCurrentMusicVolume = 1.0f;
   
   /** True if the music is paused */
   private boolean paused;
   /** True if we're returning deferred versions of resources */
   private boolean deferred;
   
   /** The buffer used to set the velocity of a source */
    private FloatBuffer sourceVel = BufferUtils.createFloatBuffer(3).put(new float[] { 0.0f, 0.0f, 0.0f });
    /** The buffer used to set the position of a source */
    private FloatBuffer sourcePos = BufferUtils.createFloatBuffer(3);
   
    /** The maximum number of sources */
    private int maxSources = 64;
   
   /**
    * Create a new sound store
    */
   private SoundStore() {
   }
   
   /**
    * Clear out the sound store contents
    */
   public void clear() {
      store = new SoundStore();
   }

   /**
    * Disable use of the Sound Store
    */
   public void disable() {
      inited = true;
   }
   
    /**
     * True if we should only record the request to load in the intention
     * of loading the sound later
     *
     * @param deferred True if the we should load a token
     */
    public void setDeferredLoading(boolean deferred) {
       this.deferred = deferred;
    }
   
    /**
     * Check if we're using deferred loading
     *
     * @return True if we're loading deferred sounds
     */
    public boolean isDeferredLoading() {
       return deferred;
    }
   
   /**
    * Inidicate whether music should be playing
    *
    * @param music True if music should be played
    */
   public void setMusicOn(boolean music) {
      if (soundWorks) {
         this.music = music;
         if (music) {
            restartLoop();
            setMusicVolume(musicVolume);
         } else {
            pauseLoop();
         }
      }
   }
   
   /**
    * Check if music should currently be playing
    *
    * @return True if music is currently playing
    */
   public boolean isMusicOn() {
      return music;
   }

   /**
    * Set the music volume
    *
    * @param volume The volume for music
    */
   public void setMusicVolume(float volume) {
      if (volume < 0) {
         volume = 0;
      }
      if (volume > 1) {
         volume = 1;
      }
      
      musicVolume = volume;
      if (soundWorks) {
         AL10.alSourcef(sources.get(0), AL10.AL_GAIN, lastCurrentMusicVolume * musicVolume);
      }
   }

   /**
    * Get the volume scalar of the music that is currently playing.
    *
    * @return The volume of the music currently playing
    */
   public float getCurrentMusicVolume() {
      return lastCurrentMusicVolume;
   }
   
   /**
    * Set the music volume of the current playing music. Does NOT affect the global volume
    *
    * @param volume The volume for the current playing music
    */
   public void setCurrentMusicVolume(float volume) {
      if (volume < 0) {
         volume = 0;
      }
      if (volume > 1) {
         volume = 1;
      }
      
      if (soundWorks) {
         lastCurrentMusicVolume = volume;
         AL10.alSourcef(sources.get(0), AL10.AL_GAIN, lastCurrentMusicVolume * musicVolume);
      }
   }
   
   /**
    * Set the sound volume
    *
    * @param volume The volume for sound fx
    */
   public void setSoundVolume(float volume) {
      if (volume < 0) {
         volume = 0;
      }
      soundVolume = volume;
   }
   
   /**
    * Check if sound works at all
    *
    * @return True if sound works at all
    */
   public boolean soundWorks() {
      return soundWorks;
   }
   
   /**
    * Check if music is currently enabled
    *
    * @return True if music is currently enabled
    */
   public boolean musicOn() {
      return music;
   }

   /**
    * Get the volume for sounds
    *
    * @return The volume for sounds
    */
   public float getSoundVolume() {
      return soundVolume;
   }
   
   /**
    * Get the volume for music
    *
    * @return The volume for music
    */
   public float getMusicVolume() {
      return musicVolume;
   }
   
   /**
    * Get the ID of a given source
    *
    * @param index The ID of a given source
    * @return The ID of the given source
    */
   public int getSource(int index) {
      if (!soundWorks) {
         return -1;
      }
      if (index < 0) {
         return -1;
      }
      return sources.get(index);
   }
   
   /**
    * Indicate whether sound effects should be played
    *
    * @param sounds True if sound effects should be played
    */
   public void setSoundsOn(boolean sounds) {
      if (soundWorks) {
         this.sounds = sounds;
      }
   }
   
   /**
    * Check if sound effects are currently enabled
    *
    * @return True if sound effects are currently enabled
    */
   public boolean soundsOn() {
      return sounds;
   }
   
   /**
    * Set the maximum number of concurrent sound effects that will be
    * attempted
    *
    * @param max The maximum number of sound effects/music to mix
    */
   public void setMaxSources(int max) {
      this.maxSources = max;
   }
   
   /**
    * Initialise the sound effects stored. This must be called
    * before anything else will work
    */
   public void init() {
      if (inited) {
         return;
      }
      Log.info("Initialising sounds..");
      inited = true;
      
      AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
            try {
               AL.create();
               soundWorks = true;
               sounds = true;
               music = true;
               Log.info("- Sound works");
            } catch (Exception e) {
               Log.error("Sound initialisation failure.");
               Log.error(e);
               soundWorks = false;
               sounds = false;
               music = false;
            }
            
            return null;
            }});
      
      if (soundWorks) {
         sourceCount = 0;
         sources = BufferUtils.createIntBuffer(maxSources);
         while (AL10.alGetError() == AL10.AL_NO_ERROR) {
            IntBuffer temp = BufferUtils.createIntBuffer(1);
            
            try {
               AL10.alGenSources(temp);
            
               if (AL10.alGetError() == AL10.AL_NO_ERROR) {
                  sourceCount++;
                  sources.put(temp.get(0));
                  if (sourceCount > maxSources-1) {
                     break;
                  }
               }
            } catch (OpenALException e) {
               // expected at the end
               break;
            }
         }
         Log.info("- "+sourceCount+" OpenAL source available");
      
         if (AL10.alGetError() != AL10.AL_NO_ERROR) {
            sounds = false;
            music = false;
            soundWorks = false;
            Log.error("- AL init failed");
         } else {
            FloatBuffer listenerOri = BufferUtils.createFloatBuffer(6).put(
                  new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f });
            FloatBuffer listenerVel = BufferUtils.createFloatBuffer(3).put(
                  new float[] { 0.0f, 0.0f, 0.0f });
            FloatBuffer listenerPos = BufferUtils.createFloatBuffer(3).put(
                  new float[] { 0.0f, 0.0f, 0.0f });
            listenerPos.flip();
            listenerVel.flip();
            listenerOri.flip();
            AL10.alListener(AL10.AL_POSITION, listenerPos);
            AL10.alListener(AL10.AL_VELOCITY, listenerVel);
            AL10.alListener(AL10.AL_ORIENTATION, listenerOri);
            
            Log.info("- Sounds source generated");
         }
      }
   }

   /**
    * Stop a particular sound source
    *
    * @param index The index of the source to stop
    */
   void stopSource(int index) {
      AL10.alSourceStop(sources.get(index));
   }
   
   /**
    * Play the specified buffer as a sound effect with the specified
    * pitch and gain.
    *
    * @param buffer The ID of the buffer to play
    * @param pitch The pitch to play at
    * @param gain The gain to play at
    * @param loop True if the sound should loop
    * @return source The source that will be used
    */
   int playAsSound(int buffer,float pitch,float gain,boolean loop) {
      return playAsSoundAt(buffer, pitch, gain, loop, 0, 0, 0);
   }
   
   /**
    * Play the specified buffer as a sound effect with the specified
    * pitch and gain.
    *
    * @param buffer The ID of the buffer to play
    * @param pitch The pitch to play at
    * @param gain The gain to play at
    * @param loop True if the sound should loop
    * @param x The x position to play the sound from
    * @param y The y position to play the sound from
    * @param z The z position to play the sound from
    * @return source The source that will be used
    */
   int playAsSoundAt(int buffer,float pitch,float gain,boolean loop,float x, float y, float z) {
      gain *= soundVolume;
      if (gain == 0) {
         gain = 0.001f;
      }
      if (soundWorks) {
         if (sounds) {
            int nextSource = findFreeSource();
            if (nextSource == -1) {
               return -1;
            }
            
            AL10.alSourceStop(sources.get(nextSource));
            
            AL10.alSourcei(sources.get(nextSource), AL10.AL_BUFFER, buffer);
            AL10.alSourcef(sources.get(nextSource), AL10.AL_PITCH, pitch);
            AL10.alSourcef(sources.get(nextSource), AL10.AL_GAIN, gain);
             AL10.alSourcei(sources.get(nextSource), AL10.AL_LOOPING, loop ? AL10.AL_TRUE : AL10.AL_FALSE);
            
             sourcePos.clear();
             sourceVel.clear();
            sourceVel.put(new float[] { 0, 0, 0 });
            sourcePos.put(new float[] { x, y, z });
             sourcePos.flip();
             sourceVel.flip();
             AL10.alSource(sources.get(nextSource), AL10.AL_POSITION, sourcePos);
             AL10.alSource(sources.get(nextSource), AL10.AL_VELOCITY, sourceVel);
            
            AL10.alSourcePlay(sources.get(nextSource));
            
            return nextSource;
         }
      }
      
      return -1;
   }
   /**
    * Check if a particular source is playing
    *
    * @param index The index of the source to check
    * @return True if the source is playing
    */
   boolean isPlaying(int index) {
      int state = AL10.alGetSourcei(sources.get(index), AL10.AL_SOURCE_STATE);
      
      return (state == AL10.AL_PLAYING);
   }
   
   /**
    * Find a free sound source
    *
    * @return The index of the free sound source
    */
   private int findFreeSource() {
      for (int i=1;i<sourceCount-1;i++) {
         int state = AL10.alGetSourcei(sources.get(i), AL10.AL_SOURCE_STATE);
         
         if ((state != AL10.AL_PLAYING) && (state != AL10.AL_PAUSED)) {
            return i;
         }
      }
      
      return -1;
   }
   
   /**
    * Play the specified buffer as music (i.e. use the music channel)
    *
    * @param buffer The buffer to be played
    * @param pitch The pitch to play the music at
    * @param gain The gaing to play the music at
    * @param loop True if we should loop the music
    */
   void playAsMusic(int buffer,float pitch,float gain, boolean loop) {
      paused = false;
      
      setMOD(null);
      
      if (soundWorks) {
         if (currentMusic != -1) {
            AL10.alSourceStop(sources.get(0));
         }
         
         getMusicSource();
         
         AL10.alSourcei(sources.get(0), AL10.AL_BUFFER, buffer);
         AL10.alSourcef(sources.get(0), AL10.AL_PITCH, pitch);
          AL10.alSourcei(sources.get(0), AL10.AL_LOOPING, loop ? AL10.AL_TRUE : AL10.AL_FALSE);
         
         currentMusic = sources.get(0);
         
         if (!music) {
            pauseLoop();
         } else {
            AL10.alSourcePlay(sources.get(0));
         }
      }
   }
   
   /**
    * Get the OpenAL source used for music
    *
    * @return The open al source used for music
    */
   private int getMusicSource() {
      return sources.get(0);
   }
   
   /**
    * Set the pitch at which the current music is being played
    *
    * @param pitch The pitch at which the current music is being played
    */
   public void setMusicPitch(float pitch) {
      if (soundWorks) {
         AL10.alSourcef(sources.get(0), AL10.AL_PITCH, pitch);
      }
   }
   
   /**
    * Pause the music loop that is currently playing
    */
   public void pauseLoop() {
      if ((soundWorks) && (currentMusic != -1)){
         paused = true;
         AL10.alSourcePause(currentMusic);
      }
   }

   /**
    * Restart the music loop that is currently paused
    */
   public void restartLoop() {
      if ((music) && (soundWorks) && (currentMusic != -1)){
         paused = false;
         AL10.alSourcePlay(currentMusic);
      }
   }
   
   /**
    * Check if the supplied player is currently being polled by this
    * sound store.
    *
    * @param player The player to check
    * @return True if this player is currently in use by this sound store
    */
   boolean isPlaying(OpenALStreamPlayer player) {
      return stream == player;
   }
   
   /**
    * Get a MOD sound (mod/xm etc)
    *
    * @param ref The refernece to the mod to load
    * @return The sound for play back
    * @throws IOException Indicates a failure to read the data
    */
   public Audio getMOD(String ref) throws IOException {
      return getMOD(ref, ResourceLoader.getResourceAsStream(ref));
   }

   /**
    * Get a MOD sound (mod/xm etc)
    *
    * @param in The stream to the MOD to load
    * @return The sound for play back
    * @throws IOException Indicates a failure to read the data
    */
   public Audio getMOD(InputStream in) throws IOException {
      return getMOD(in.toString(), in);
   }
   
   /**
    * Get a MOD sound (mod/xm etc)
    *
    * @param ref The stream to the MOD to load
    * @param in The stream to the MOD to load
    * @return The sound for play back
    * @throws IOException Indicates a failure to read the data
    */
   public Audio getMOD(String ref, InputStream in) throws IOException {
      if (!soundWorks) {
         return new NullAudio();
      }
      if (!inited) {
         throw new RuntimeException("Can't load sounds until SoundStore is init(). Use the container init() method.");
      }
      if (deferred) {
         return new DeferredSound(ref, in, DeferredSound.MOD);
      }
      
      return new MODSound(this, in);
   }

   /**
    * Get the Sound based on a specified AIF file
    *
    * @param ref The reference to the AIF file in the classpath
    * @return The Sound read from the AIF file
    * @throws IOException Indicates a failure to load the AIF
    */
   public Audio getAIF(String ref) throws IOException {
      return getAIF(ref, ResourceLoader.getResourceAsStream(ref));
   }
   

   /**
    * Get the Sound based on a specified AIF file
    *
    * @param in The stream to the MOD to load
    * @return The Sound read from the AIF file
    * @throws IOException Indicates a failure to load the AIF
    */
   public Audio getAIF(InputStream in) throws IOException {
      return getAIF(in.toString(), in);
   }
   
   /**
    * Get the Sound based on a specified AIF file
    *
    * @param ref The reference to the AIF file in the classpath
    * @param in The stream to the AIF to load
    * @return The Sound read from the AIF file
    * @throws IOException Indicates a failure to load the AIF
    */
   public Audio getAIF(String ref, InputStream in) throws IOException {
      in = new BufferedInputStream(in);

      if (!soundWorks) {
         return new NullAudio();
      }
      if (!inited) {
         throw new RuntimeException("Can't load sounds until SoundStore is init(). Use the container init() method.");
      }
      if (deferred) {
         return new DeferredSound(ref, in, DeferredSound.AIF);
      }
      
      int buffer = -1;
      
      if (loaded.get(ref) != null) {
         buffer = ((Integer) loaded.get(ref)).intValue();
      } else {
         try {
            IntBuffer buf = BufferUtils.createIntBuffer(1);
            
            AiffData data = AiffData.create(in);
            AL10.alGenBuffers(buf);
            AL10.alBufferData(buf.get(0), data.format, data.data, data.samplerate);
            
            loaded.put(ref,new Integer(buf.get(0)));
            buffer = buf.get(0);
         } catch (Exception e) {
            Log.error(e);
            IOException x = new IOException("Failed to load: "+ref);
            x.initCause(e);
            
            throw x;
         }
      }
      
      if (buffer == -1) {
         throw new IOException("Unable to load: "+ref);
      }
      
      return new AudioImpl(this, buffer);
   }
   

   
   /**
    * Get the Sound based on a specified WAV file
    *
    * @param ref The reference to the WAV file in the classpath
    * @return The Sound read from the WAV file
    * @throws IOException Indicates a failure to load the WAV
    */
   public Audio getWAV(String ref) throws IOException {
      return getWAV(ref, ResourceLoader.getResourceAsStream(ref));
   }
   
   /**
    * Get the Sound based on a specified WAV file
    *
    * @param in The stream to the WAV to load
    * @return The Sound read from the WAV file
    * @throws IOException Indicates a failure to load the WAV
    */
   public Audio getWAV(InputStream in) throws IOException {
      return getWAV(in.toString(), in);
   }
   
   /**
    * Get the Sound based on a specified WAV file
    *
    * @param ref The reference to the WAV file in the classpath
    * @param in The stream to the WAV to load
    * @return The Sound read from the WAV file
    * @throws IOException Indicates a failure to load the WAV
    */
   public Audio getWAV(String ref, InputStream in) throws IOException {
      if (!soundWorks) {
         return new NullAudio();
      }
      if (!inited) {
         throw new RuntimeException("Can't load sounds until SoundStore is init(). Use the container init() method.");
      }
      if (deferred) {
         return new DeferredSound(ref, in, DeferredSound.WAV);
      }
      
      int buffer = -1;
      
      if (loaded.get(ref) != null) {
         buffer = ((Integer) loaded.get(ref)).intValue();
      } else {
         try {
            IntBuffer buf = BufferUtils.createIntBuffer(1);
            
            WaveData data = WaveData.create(in);
            AL10.alGenBuffers(buf);
            AL10.alBufferData(buf.get(0), data.format, data.data, data.samplerate);
            
            loaded.put(ref,new Integer(buf.get(0)));
            buffer = buf.get(0);
         } catch (Exception e) {
            Log.error(e);
            IOException x = new IOException("Failed to load: "+ref);
            x.initCause(e);
            
            throw x;
         }
      }
      
      if (buffer == -1) {
         throw new IOException("Unable to load: "+ref);
      }
      
      return new AudioImpl(this, buffer);
   }

   /**
    * Get the Sound based on a specified OGG file
    *
    * @param ref The reference to the OGG file in the classpath
    * @return The Sound read from the OGG file
    * @throws IOException Indicates a failure to load the OGG
    */
   public Audio getOggStream(String ref) throws IOException {
      if (!soundWorks) {
         return new NullAudio();
      }
      
      setMOD(null);
      setStream(null);
      
      if (currentMusic != -1) {
         AL10.alSourceStop(sources.get(0));
      }
      
      getMusicSource();
      currentMusic = sources.get(0);
      
      return new StreamSound(new OpenALStreamPlayer(currentMusic, ref));
   }

   /**
    * Get the Sound based on a specified OGG file
    *
    * @param ref The reference to the OGG file in the classpath
    * @return The Sound read from the OGG file
    * @throws IOException Indicates a failure to load the OGG
    */
   public Audio getOggStream(URL ref) throws IOException {
      if (!soundWorks) {
         return new NullAudio();
      }
      
      setMOD(null);
      setStream(null);
      
      if (currentMusic != -1) {
         AL10.alSourceStop(sources.get(0));
      }
      
      getMusicSource();
      currentMusic = sources.get(0);
      
      return new StreamSound(new OpenALStreamPlayer(currentMusic, ref));
   }
   
   /**
    * Get the Sound based on a specified OGG file
    *
    * @param ref The reference to the OGG file in the classpath
    * @return The Sound read from the OGG file
    * @throws IOException Indicates a failure to load the OGG
    */
   public Audio getOgg(String ref) throws IOException {
      return getOgg(ref, ResourceLoader.getResourceAsStream(ref));
   }
   
   /**
    * Get the Sound based on a specified OGG file
    *
    * @param in The stream to the OGG to load
    * @return The Sound read from the OGG file
    * @throws IOException Indicates a failure to load the OGG
    */
   public Audio getOgg(InputStream in) throws IOException {
      return getOgg(in.toString(), in);
   }
   
   /**
    * Get the Sound based on a specified OGG file
    *
    * @param ref The reference to the OGG file in the classpath
    * @param in The stream to the OGG to load
    * @return The Sound read from the OGG file
    * @throws IOException Indicates a failure to load the OGG
    */
   public Audio getOgg(String ref, InputStream in) throws IOException {
      if (!soundWorks) {
         return new NullAudio();
      }
      if (!inited) {
         throw new RuntimeException("Can't load sounds until SoundStore is init(). Use the container init() method.");
      }
      if (deferred) {
         return new DeferredSound(ref, in, DeferredSound.OGG);
      }
      
      int buffer = -1;
      
      if (loaded.get(ref) != null) {
         buffer = ((Integer) loaded.get(ref)).intValue();
      } else {
         try {
            IntBuffer buf = BufferUtils.createIntBuffer(1);
            
            OggDecoder decoder = new OggDecoder();
            OggData ogg = decoder.getData(in);
            
            AL10.alGenBuffers(buf);
            AL10.alBufferData(buf.get(0), ogg.channels > 1 ? AL10.AL_FORMAT_STEREO16 : AL10.AL_FORMAT_MONO16, ogg.data, ogg.rate);
            
            loaded.put(ref,new Integer(buf.get(0)));
                                 
            buffer = buf.get(0);
         } catch (Exception e) {
            Log.error(e);
            Sys.alert("Error","Failed to load: "+ref+" - "+e.getMessage());
            throw new IOException("Unable to load: "+ref);
         }
      }
      
      if (buffer == -1) {
         throw new IOException("Unable to load: "+ref);
      }
      
      return new AudioImpl(this, buffer);
   }
   
   /**
    * Set the mod thats being streamed if any
    *
    * @param sound The mod being streamed
    */
   void setMOD(MODSound sound) {
      if (!soundWorks) {
         return;
      }

      currentMusic = sources.get(0);
      stopSource(0);
      
      this.mod = sound;
      if (sound != null) {
         this.stream = null;
      }
      paused = false;
   }

   /**
    * Set the stream being played
    *
    * @param stream The stream being streamed
    */
   void setStream(OpenALStreamPlayer stream) {
      if (!soundWorks) {
         return;
      }

      currentMusic = sources.get(0);
      this.stream = stream;
      if (stream != null) {
         this.mod = null;
      }
      paused = false;
   }
   
   /**
    * Poll the streaming system
    *
    * @param delta The amount of time passed since last poll (in milliseconds)
    */
   public void poll(int delta) {
      if (!soundWorks) {
         return;
      }
      if (paused) {
         return;
      }

      if (music) {
         if (mod != null) {
            try {
               mod.poll();
            } catch (OpenALException e) {
               Log.error("Error with OpenGL MOD Player on this this platform");
               Log.error(e);
               mod = null;
            }
         }
         if (stream != null) {
            try {
               stream.update();
            } catch (OpenALException e) {
               Log.error("Error with OpenGL Streaming Player on this this platform");
               Log.error(e);
               mod = null;
            }
         }
      }
   }
   
   /**
    * Check if the music is currently playing
    *
    * @return True if the music is playing
    */
   public boolean isMusicPlaying()
   {
      if (!soundWorks) {
         return false;
      }
      
      int state = AL10.alGetSourcei(sources.get(0), AL10.AL_SOURCE_STATE);
      return ((state == AL10.AL_PLAYING) || (state == AL10.AL_PAUSED));
   }
   
   /**
    * Get the single instance of this class
    *
    * @return The single instnace of this class
    */
   public static SoundStore get() {
      return store;
   }
   
   /**
    * Stop a playing sound identified by the ID returned from playing. This utility method
    * should only be used when needing to stop sound effects that may have been played
    * more than once and need to be explicitly stopped.
    *
    * @param id The ID of the underlying OpenAL source as returned from playAsSoundEffect
    */
   public void stopSoundEffect(int id) {
      AL10.alSourceStop(id);
   }
   
   /**
    * Retrieve the number of OpenAL sound sources that have been
    * determined at initialisation.
    *
    * @return The number of sources available
    */
   public int getSourceCount() {
      return sourceCount;
   }
}


StreamSound.java:
Code:
package org.newdawn.slick.openal;

import java.io.IOException;
import java.nio.IntBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL10;
import org.newdawn.slick.util.Log;

/**
* A sound implementation wrapped round a player which reads (and potentially) rereads
* a stream. This supplies streaming audio
*
* @author kevin
* @author Nathan Sweet <misc@n4te.com>
* @author Rockstar playAsMusic cleanup
*/
public class StreamSound extends AudioImpl {
   /** The player we're going to ask to stream data */
   private OpenALStreamPlayer player;
   
   /**
    * Create a new sound wrapped round a stream
    *
    * @param player The stream player we'll use to access the stream
    */
   public StreamSound(OpenALStreamPlayer player) {
      this.player = player;
   }
   
   /**
    * @see org.newdawn.slick.openal.AudioImpl#isPlaying()
    */
   public boolean isPlaying() {
      return SoundStore.get().isPlaying(player);
   }

   /**
    * @see org.newdawn.slick.openal.AudioImpl#playAsMusic(float, float, boolean)
    */
   public int playAsMusic(float pitch, float gain, boolean loop) {
      try {
         cleanUpSource();
         
         player.setup(pitch);
         player.play(loop);
         SoundStore.get().setStream(player);
      } catch (IOException e) {
         Log.error("Failed to read OGG source: "+player.getSource());
      }
      
      return SoundStore.get().getSource(0);
   }

   /**
    * Clean up the buffers applied to the sound source
    */
   private void cleanUpSource() {
      SoundStore store = SoundStore.get();
      
      AL10.alSourceStop(store.getSource(0));
      IntBuffer buffer = BufferUtils.createIntBuffer(1);
      int queued = AL10.alGetSourcei(store.getSource(0), AL10.AL_BUFFERS_QUEUED);
      
      while (queued > 0)
      {
         AL10.alSourceUnqueueBuffers(store.getSource(0), buffer);
         queued--;
      }
      
      AL10.alSourcei(store.getSource(0), AL10.AL_BUFFER, 0);
   }
   
   /**
    * @see org.newdawn.slick.openal.AudioImpl#playAsSoundEffect(float, float, boolean, float, float, float)
    */
   public int playAsSoundEffect(float pitch, float gain, boolean loop, float x, float y, float z) {
      return playAsMusic(pitch, gain, loop);
   }

   /**
    * @see org.newdawn.slick.openal.AudioImpl#playAsSoundEffect(float, float, boolean)
    */
   public int playAsSoundEffect(float pitch, float gain, boolean loop) {
      return playAsMusic(pitch, gain, loop);
   }

   /**
    * @see org.newdawn.slick.openal.AudioImpl#stop()
    */
   public void stop() {
      SoundStore.get().setStream(null);
   }

   /**
    * @see org.newdawn.slick.openal.AudioImpl#setPosition(float)
    */
   public boolean setPosition(float position) {
      return player.setPosition(position);
   }

   /**
    * @see org.newdawn.slick.openal.AudioImpl#getPosition()
    */
   public float getPosition() {
      return player.getPosition();
   }
}


OpenALStreamPlayer.java:
Code:
package org.newdawn.slick.openal;

import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.AL11;
import org.lwjgl.openal.OpenALException;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;

/**
* A generic tool to work on a supplied stream, pulling out PCM data and buffered it to OpenAL
* as required.
*
* @author Kevin Glass
* @author Nathan Sweet <misc@n4te.com>
* @author Rockstar play and setPosition cleanup
*/
public class OpenALStreamPlayer {
   /** The number of buffers to maintain */
   public static final int BUFFER_COUNT = 3;
   /** The size of the sections to stream from the stream */
   private static final int sectionSize = 4096 * 20;
   
   /** The buffer read from the data stream */
   private byte[] buffer = new byte[sectionSize];
   /** Holds the OpenAL buffer names */
   private IntBuffer bufferNames;
   /** The byte buffer passed to OpenAL containing the section */
   private ByteBuffer bufferData = BufferUtils.createByteBuffer(sectionSize);
   /** The buffer holding the names of the OpenAL buffer thats been fully played back */
   private IntBuffer unqueued = BufferUtils.createIntBuffer(1);
   /** The source we're playing back on */
    private int source;
   /** The number of buffers remaining */
    private int remainingBufferCount;
   /** True if we should loop the track */
   private boolean loop;
   /** True if we've completed play back */
   private boolean done = true;
   /** The stream we're currently reading from */
   private AudioInputStream audio;
   /** The source of the data */
   private String ref;
   /** The source of the data */
   private URL url;
   /** The pitch of the music */
   private float pitch;
   /** Position in seconds of the previously played buffers */
   private float positionOffset;
   
   /**
    * Create a new player to work on an audio stream
    *
    * @param source The source on which we'll play the audio
    * @param ref A reference to the audio file to stream
    */
   public OpenALStreamPlayer(int source, String ref) {
      this.source = source;
      this.ref = ref;
      
      bufferNames = BufferUtils.createIntBuffer(BUFFER_COUNT);
      AL10.alGenBuffers(bufferNames);
   }

   /**
    * Create a new player to work on an audio stream
    *
    * @param source The source on which we'll play the audio
    * @param url A reference to the audio file to stream
    */
   public OpenALStreamPlayer(int source, URL url) {
      this.source = source;
      this.url = url;

      bufferNames = BufferUtils.createIntBuffer(BUFFER_COUNT);
      AL10.alGenBuffers(bufferNames);
   }
   
   /**
    * Initialise our connection to the underlying resource
    *
    * @throws IOException Indicates a failure to open the underling resource
    */
   private void initStreams() throws IOException {
      if (audio != null) {
         audio.close();
      }
      
      OggInputStream audio;
      
      if (url != null) {
         audio = new OggInputStream(url.openStream());
      } else {
         audio = new OggInputStream(ResourceLoader.getResourceAsStream(ref));
      }
      
      this.audio = audio;
      positionOffset = 0;
   }
   
   /**
    * Get the source of this stream
    *
    * @return The name of the source of string
    */
   public String getSource() {
      return (url == null) ? ref : url.toString();
   }
   
   /**
    * Clean up the buffers applied to the sound source
    */
   private void removeBuffers() {
      IntBuffer buffer = BufferUtils.createIntBuffer(1);
      int queued = AL10.alGetSourcei(source, AL10.AL_BUFFERS_QUEUED);
      
      while (queued > 0)
      {
         AL10.alSourceUnqueueBuffers(source, buffer);
         queued--;
      }
   }
   
   /**
    * Start this stream playing
    *
    * @param loop True if the stream should loop
    * @throws IOException Indicates a failure to read from the stream
    */
   public void play(boolean loop) throws IOException {
      this.loop = loop;
      initStreams();
      
      done = false;

      AL10.alSourceStop(source);
      removeBuffers();
      startPlayback();
   }
   
   /**
    * Setup the playback properties
    *
    * @param pitch The pitch to play back at
    * @param gain The volume to play back at
    */
   public void setup(float pitch) {
      this.pitch = pitch;
   }
   
   /**
    * Check if the playback is complete. Note this will never
    * return true if we're looping
    *
    * @return True if we're looping
    */
   public boolean done() {
      return done;
   }
   
   /**
    * Poll the bufferNames - check if we need to fill the bufferNames with another
    * section.
    *
    * Most of the time this should be reasonably quick
    */
   public void update() {
      if (done) {
         return;
      }

      float sampleRate = audio.getRate();
      float sampleSize;
      if (audio.getChannels() > 1) {
         sampleSize = 4; // AL10.AL_FORMAT_STEREO16
      } else {
         sampleSize = 2; // AL10.AL_FORMAT_MONO16
      }
      
      int processed = AL10.alGetSourcei(source, AL10.AL_BUFFERS_PROCESSED);
      while (processed > 0) {
         unqueued.clear();
         AL10.alSourceUnqueueBuffers(source, unqueued);
         
         int bufferIndex = unqueued.get(0);

         float bufferLength = (AL10.alGetBufferi(bufferIndex, AL10.AL_SIZE) / sampleSize) / sampleRate;
         positionOffset += bufferLength;
         
           if (stream(bufferIndex)) {         
              AL10.alSourceQueueBuffers(source, unqueued);
           } else {
              remainingBufferCount--;
              if (remainingBufferCount == 0) {
                 done = true;
              }
           }
           processed--;
      }
      
      int state = AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE);
      
       if (state != AL10.AL_PLAYING) {
          AL10.alSourcePlay(source);
       }
   }
   
   /**
    * Stream some data from the audio stream to the buffer indicates by the ID
    *
    * @param bufferId The ID of the buffer to fill
    * @return True if another section was available
    */
   public boolean stream(int bufferId) {
      try {
         int count = audio.read(buffer);
         
         if (count != -1) {
            bufferData.clear();
            bufferData.put(buffer,0,count);
            bufferData.flip();

            int format = audio.getChannels() > 1 ? AL10.AL_FORMAT_STEREO16 : AL10.AL_FORMAT_MONO16;
            try {
               AL10.alBufferData(bufferId, format, bufferData, audio.getRate());
            } catch (OpenALException e) {
               Log.error("Failed to loop buffer: "+bufferId+" "+format+" "+count+" "+audio.getRate(), e);
               return false;
            }
         } else {
            if (loop) {
               initStreams();
               stream(bufferId);
            } else {
               done = true;
               return false;
            }
         }
         
         return true;
      } catch (IOException e) {
         Log.error(e);
         return false;
      }
   }

   /**
    * Seeks to a position in the music.
    *
    * @param position Position in seconds.
    * @return True if the setting of the position was successful
    */
   public boolean setPosition(float position) {
      try {
         AL10.alSourceStop(source);
         removeBuffers();

         if (getPosition() > position) {
            initStreams();
         }

         float sampleRate = audio.getRate();
         float sampleSize;
         if (audio.getChannels() > 1) {
            sampleSize = 4; // AL10.AL_FORMAT_STEREO16
         } else {
            sampleSize = 2; // AL10.AL_FORMAT_MONO16
         }

         while (positionOffset < position) {
            int count = audio.read(buffer);
            if (count != -1) {
               float bufferLength = (count / sampleSize) / sampleRate;
               positionOffset += bufferLength;
            } else {
               if (loop) {
                  initStreams();
               } else {
                  done = true;
               }
               return false;
            }
         }
         
         startPlayback();
         
         return true;
      } catch (IOException e) {
         Log.error(e);
         return false;
      }
   }

   private void startPlayback() {
       AL10.alSourcei(source, AL10.AL_LOOPING, AL10.AL_FALSE);
      AL10.alSourcef(source, AL10.AL_PITCH, pitch);
      
      remainingBufferCount = BUFFER_COUNT;
   
      for (int i = 0; i < BUFFER_COUNT; i++) {
           stream(bufferNames.get(i));
      }
      
        AL10.alSourceQueueBuffers(source, bufferNames);
      AL10.alSourcePlay(source);
   }
   
   /**
    * Return the current playing position in the sound
    *
    * @return The current position in seconds.
    */
   public float getPosition() {
      return positionOffset + AL10.alGetSourcef(source, AL11.AL_SEC_OFFSET);
   }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 15, 2009 7:58 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Tried to diff the change manually, it's not working out.

Could you provide a patch please.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 16, 2009 6:03 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
FWIW, I use Subversion to generate a patch. I use TortoiseSVN, but that is Windows only.

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 16, 2009 12:34 pm 
Offline

Joined: Wed Jan 07, 2009 9:20 pm
Posts: 41
I usually copy the new contents into the file in Eclipse, then use Compare with Local History to see the differences.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 16, 2009 2:13 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Thats what I meant by:

Quote:
Tried to diff the change manually, it's not working out.


Unfortunately when I copy in the version supplied here the whole file turns up as changed, so I can't validate the changes.

Kev


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 16, 2009 6:30 pm 
Offline

Joined: Wed Jan 07, 2009 9:20 pm
Posts: 41
Well, I don't know how I could build a "patch", but from Eclipse's compare between my current version and the ones from the Slick 0.3 source pack, the differences are as follows:

In Music.java:
-Changed the poll method (30 to 40 in old file, 30 to 43 in new file) to support repositing and threading properly.
-Added repositioning variable (after line 59 in old file, lines 63-64 in new file)
-Changed the no-params loop() and play() methods to use 1.0f as a value (lines 189, 196 in old file, 194, 201 in new file)
-Modified the setPosition() method to handle threading properly (line 351 in old file, lines 356 to 366 in new file)

In StreamSound.java:
-In the playAsMusic method, changed player.setup() to only include pitch, not volume, and removed the call to SoundStore.get().setCurrentMusicVolume() as this was a redundant call in the stack (line 44, 45 in old file, line 45 in new file)

In SoundStore.java:
-Changed setCurrentMusicVolume to use the proper multiplication of global volume and specific volume (line 182 in old file, 183 in new file)
-Changed getOggStream(String) to remove redundant check on soundWorks (lines 749 to 760 in old file, 750 to 757 in new file)
-Same change in getOffStream(URL), lines 778 to 789 in old file, 775 to 782 in new file.

In OpenALStreamPlayer.java:
-Removed gain attribute since it is useless in here (lines 52, 53 in old file)
-Refactored common code between play(boolean) and setPosition(float) into a new private startPlayback() method. Lines 144 to 155 in old file are removed and replaced with line 143 in new file. New startPlayback() method is lines 299 to 312 in new file.
-In setPosition(), moved the stop and removeBuffers commands to the beginning, so it is done before repositioning (new lines 260, 261 in new file)
-Removed gain parameter in the setup(float) method; lines 164 to 166 in old file, 152 to 153 in new file.

I don't know how else to generate a patch; is this something that could be done in Eclipse??


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 16, 2009 8:03 pm 
Offline
User avatar

Joined: Fri Dec 28, 2007 3:37 pm
Posts: 87
Location: bremen, germany
Can't you create a patch by right clicking the changed file/project > Team > Create Patch ? On my Eclipse Ganymede (3.4.2) with Subclipse it's possible.

bye, kulpae


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 17, 2009 9:19 am 
Offline
Game Developer
User avatar

Joined: Sun May 25, 2008 9:45 am
Posts: 578
Rockstar, hopefully Eclipse can do it. If not, the Unix command "diff" can create patches.

Kev, you could overwrite your local copy, use Eclipse to format the new source, then do a diff against what is in SVN. But it could be time consuming for Kev to go through this when a patch is much easier for him.

_________________
SingSong Karaoke - http://singthegame.com


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 17, 2009 12:32 pm 
Offline

Joined: Wed Jan 07, 2009 9:20 pm
Posts: 41
I'll try connecting to the SVN later today from my Windows computer and see if I have the option to create a patch from Eclipse.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 17, 2009 5:44 pm 
Offline

Joined: Wed Jan 07, 2009 9:20 pm
Posts: 41
Is this the way to do it?

Code:
### Eclipse Workspace Patch 1.0
#P Slick
Index: src/org/newdawn/slick/openal/SoundStore.java
===================================================================
--- src/org/newdawn/slick/openal/SoundStore.java   (revision 1260)
+++ src/org/newdawn/slick/openal/SoundStore.java   (working copy)
@@ -22,6 +22,7 @@
  * Responsible for holding and playing the sounds used in the game.
  *
  * @author Kevin Glass
+ * @author Rockstar setVolume cleanup
  */
public class SoundStore {
   
@@ -179,7 +180,7 @@
      
      if (soundWorks) {
         lastCurrentMusicVolume = volume;
-         AL10.alSourcef(sources.get(0), AL10.AL_GAIN, volume);
+         AL10.alSourcef(sources.get(0), AL10.AL_GAIN, lastCurrentMusicVolume * musicVolume);
      }
   }
   
@@ -746,18 +747,14 @@
      setMOD(null);
      setStream(null);
      
-      if (soundWorks) {
-         if (currentMusic != -1) {
-            AL10.alSourceStop(sources.get(0));
-         }
-         
-         getMusicSource();
-         currentMusic = sources.get(0);
-         
-         return new StreamSound(new OpenALStreamPlayer(currentMusic, ref));
+      if (currentMusic != -1) {
+         AL10.alSourceStop(sources.get(0));
      }
      
-      return new StreamSound(new OpenALStreamPlayer(0, ref));
+      getMusicSource();
+      currentMusic = sources.get(0);
+      
+      return new StreamSound(new OpenALStreamPlayer(currentMusic, ref));
   }

   /**
@@ -775,18 +772,14 @@
      setMOD(null);
      setStream(null);
      
-      if (soundWorks) {
-         if (currentMusic != -1) {
-            AL10.alSourceStop(sources.get(0));
-         }
-         
-         getMusicSource();
-         currentMusic = sources.get(0);
-         
-         return new StreamSound(new OpenALStreamPlayer(currentMusic, ref));
+      if (currentMusic != -1) {
+         AL10.alSourceStop(sources.get(0));
      }
      
-      return new StreamSound(new OpenALStreamPlayer(0, ref));
+      getMusicSource();
+      currentMusic = sources.get(0);
+      
+      return new StreamSound(new OpenALStreamPlayer(currentMusic, ref));
   }
   
   /**
Index: src/org/newdawn/slick/Music.java
===================================================================
--- src/org/newdawn/slick/Music.java   (revision 1260)
+++ src/org/newdawn/slick/Music.java   (working copy)
@@ -14,6 +14,7 @@
  *
  * @author kevin
  * @author Nathan Sweet <misc@n4te.com>
+ * @author Rockstar Enabled threaded play/loop and setPosition
  */
public class Music {
   /** The music currently being played or null if none */
@@ -27,12 +28,14 @@
    * @param delta The amount of time since last poll
    */
   public static void poll(int delta) {
-      if (currentMusic != null) {
+      if (currentMusic != null && currentMusic.playing) {
         SoundStore.get().poll(delta);
         if (!SoundStore.get().isMusicPlaying()) {
-            Music oldMusic = currentMusic;
-            currentMusic = null;
-            oldMusic.fireMusicEnded();
+            if (!currentMusic.positioning) {
+               Music oldMusic = currentMusic;
+               currentMusic = null;
+               oldMusic.fireMusicEnded();
+            }
         } else {
            currentMusic.update(delta);
         }
@@ -57,6 +60,8 @@
   private int fadeDuration;
   /** True if music should be stopped after fading in/out */
   private boolean stopAfterFade;
+   /** True if the music is being repositioned and it is therefore normal that it's not playing */
+   private boolean positioning;
   
   /**
    * Create and load a piece of music (either OGG or MOD/XM)
@@ -186,14 +191,14 @@
    * Loop the music
    */
   public void loop() {
-      loop(1.0f, volume * SoundStore.get().getMusicVolume());
+      loop(1.0f, 1.0f);
   }
   
   /**
    * Play the music
    */
   public void play() {
-      play(1.0f, volume * SoundStore.get().getMusicVolume());
+      play(1.0f, 1.0f);
   }

   /**
@@ -348,7 +353,17 @@
    * @return True if the seek was successful
    */
   public boolean setPosition (float position) {
-      return sound.setPosition(position);
+      if (playing) {
+         positioning = true;
+         playing = false;
+         boolean result = sound.setPosition(position);
+         playing = true;
+         positioning = false;
+         
+         return result;
+      } else {
+         return false;
+      }
   }

   /**
Index: src/org/newdawn/slick/openal/StreamSound.java
===================================================================
--- src/org/newdawn/slick/openal/StreamSound.java   (revision 1260)
+++ src/org/newdawn/slick/openal/StreamSound.java   (working copy)
@@ -13,6 +13,7 @@
  *
  * @author kevin
  * @author Nathan Sweet <misc@n4te.com>
+ * @author Rockstar playAsMusic cleanup
  */
public class StreamSound extends AudioImpl {
   /** The player we're going to ask to stream data */
@@ -41,8 +42,7 @@
      try {
         cleanUpSource();
         
-         player.setup(pitch, 1.0f);
-         SoundStore.get().setCurrentMusicVolume(gain);
+         player.setup(pitch);
         player.play(loop);
         SoundStore.get().setStream(player);
      } catch (IOException e) {
Index: src/org/newdawn/slick/openal/OpenALStreamPlayer.java
===================================================================
--- src/org/newdawn/slick/openal/OpenALStreamPlayer.java   (revision 1260)
+++ src/org/newdawn/slick/openal/OpenALStreamPlayer.java   (working copy)
@@ -18,6 +18,7 @@
  *
  * @author Kevin Glass
  * @author Nathan Sweet <misc@n4te.com>
+ * @author Rockstar play and setPosition cleanup
  */
public class OpenALStreamPlayer {
   /** The number of buffers to maintain */
@@ -49,8 +50,6 @@
   private URL url;
   /** The pitch of the music */
   private float pitch;
-   /** The gain of the music */
-   private float gain;
   /** Position in seconds of the previously played buffers */
   private float positionOffset;
   
@@ -141,29 +140,16 @@

      AL10.alSourceStop(source);
      removeBuffers();
-       AL10.alSourcei(source, AL10.AL_LOOPING, AL10.AL_FALSE);
-      AL10.alSourcef(source, AL10.AL_PITCH, pitch);
-      AL10.alSourcef(source, AL10.AL_GAIN, gain);
-      
-      remainingBufferCount = BUFFER_COUNT;
-   
-      for (int i=0;i<BUFFER_COUNT;i++) {
-           stream(bufferNames.get(i));
-      }
-      
-        AL10.alSourceQueueBuffers(source, bufferNames);
-      AL10.alSourcePlay(source);
+      startPlayback();
   }
   
   /**
    * Setup the playback properties
    *
    * @param pitch The pitch to play back at
-    * @param gain The volume to play back at
    */
-   public void setup(float pitch, float gain) {
+   public void setup(float pitch) {
      this.pitch = pitch;
-      this.gain = gain;
   }
   
   /**
@@ -268,57 +254,64 @@
    * @param position Position in seconds.
    * @return True if the setting of the position was successful
    */
-   public boolean setPosition(float position) {
-      try {
+   public boolean setPosition(float position) {
+      try {
+         AL10.alSourceStop(source);
+         removeBuffers();
+
         if (getPosition() > position) {
-            initStreams();
-         }
+            initStreams();
+         }

-         float sampleRate = audio.getRate();
-         float sampleSize;
-         if (audio.getChannels() > 1) {
-            sampleSize = 4; // AL10.AL_FORMAT_STEREO16
-         } else {
-            sampleSize = 2; // AL10.AL_FORMAT_MONO16
-         }
+         float sampleRate = audio.getRate();
+         float sampleSize;
+         if (audio.getChannels() > 1) {
+            sampleSize = 4; // AL10.AL_FORMAT_STEREO16
+         } else {
+            sampleSize = 2; // AL10.AL_FORMAT_MONO16
+         }

-         while (positionOffset < position) {
-            int count = audio.read(buffer);
-            if (count != -1) {
-               float bufferLength = (count / sampleSize) / sampleRate;
-               positionOffset += bufferLength;
-            } else {
-               if (loop) {
-                  initStreams();
-               } else {
-                  done = true;
-               }
-               return false;
-            }
-         }
+         while (positionOffset < position) {
+            int count = audio.read(buffer);
+            if (count != -1) {
+               float bufferLength = (count / sampleSize) / sampleRate;
+               positionOffset += bufferLength;
+            } else {
+               if (loop) {
+                  initStreams();
+               } else {
+                  done = true;
+               }
+               return false;
+            }
+         }
+         
+         startPlayback();
+         
+         return true;
+      } catch (IOException e) {
+         Log.error(e);
+         return false;
+      }
+   }

-         AL10.alSourceStop(source);
-         removeBuffers();
-         AL10.alSourcei(source, AL10.AL_LOOPING, AL10.AL_FALSE);
-         AL10.alSourcef(source, AL10.AL_PITCH, pitch);
-         AL10.alSourcef(source, AL10.AL_GAIN, gain);
-
-         remainingBufferCount = BUFFER_COUNT;
-
-         for (int i = 0; i < BUFFER_COUNT; i++) {
-            stream(bufferNames.get(i));
-         }
-
-         AL10.alSourceQueueBuffers(source, bufferNames);
-         AL10.alSourcePlay(source);
-
-         return true;
-      } catch (IOException e) {
-         Log.error(e);
-         return false;
+   /**
+    * Starts the streaming.
+    */
+   private void startPlayback() {
+       AL10.alSourcei(source, AL10.AL_LOOPING, AL10.AL_FALSE);
+      AL10.alSourcef(source, AL10.AL_PITCH, pitch);
+      
+      remainingBufferCount = BUFFER_COUNT;
+   
+      for (int i = 0; i < BUFFER_COUNT; i++) {
+           stream(bufferNames.get(i));
      }
+      
+        AL10.alSourceQueueBuffers(source, bufferNames);
+      AL10.alSourcePlay(source);
   }
-
+   
   /**
    * Return the current playing position in the sound
    *


Let me know if that works out.

Edit: reapplied patch since the original one had the java imports removed (because of a version mismatch). This should be better now.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 23, 2009 7:44 pm 
Offline
Site Admin
User avatar

Joined: Thu Jan 01, 1970 12:00 am
Posts: 3143
Awesome stuff, applied in SVN. Thanks!

Kev


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group