2

I am using JLayer to play my sounds in my game. I am trying to set independent volume levels for my music (constantly playing) and sound effects (sporadic). Right now my code changes the master volume level so, as expected, it changes the volume of both. Here is some sample code to demonstrate what I want to do(I cut a lot of stuff out to try and be SSCCE-like and realize there are some "bugs").

Any help would be hugely appreciated.

public static void playSoundOrMusic(String filename, String type) {
    String soundFilename = "";

    if (type.equals("SFX")){
        soundFilename = "res/sounds/sfx/" + filename;
    } else if (type.equals("MUSIC")){
        soundFilename = "res/sounds/music/" + filename;
    }

    FileInputStream fis = null;
    try {
        fis = new FileInputStream(soundFilename);
    } catch (FileNotFoundException e) {
        LOGGER.error("Sound file missing", e);
    }  
    BufferedInputStream bis = new BufferedInputStream(fis);  

    try {
        if (type.equals("SFX")){
            sfxPlayer = new Player(bis);
        } else if (type.equals("MUSIC")){
            musicPlayer = new Player(bis);
        }
    } catch (JavaLayerException e) {
        LOGGER.error("Sound file issue", e);
    } catch (ArrayIndexOutOfBoundsException e) {
        LOGGER.error("Sound file issue", e);
    }

    if (type.equals("SFX")){
        Info source = Port.Info.SPEAKER;
        if (AudioSystem.isLineSupported(source)){   
            try {
                Port outline = (Port) AudioSystem.getLine(source);
                outline.open();                
                FloatControl volumeControl = (FloatControl) outline.getControl(FloatControl.Type.VOLUME);                
                volumeControl.setValue(OptionsJPanel.sfxVolume);
            } catch (LineUnavailableException ex) {
                LOGGER.error("Sound line issue", ex);
            }

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        sfxPlayer.play();
                    } catch (Exception ex) {
                        LOGGER.error("Sound(sfx) playing issue", ex);
                    }
                }
            }).start();
        }
    }

    if (type.equals("MUSIC")){
        Info source = Port.Info.SPEAKER;
        if (AudioSystem.isLineSupported(source)){   
            try {
                Port outline = (Port) AudioSystem.getLine(source);
                outline.open();                
                FloatControl volumeControl = (FloatControl) outline.getControl(FloatControl.Type.VOLUME);                
                volumeControl.setValue(OptionsJPanel.musicVolume);
            } catch (LineUnavailableException ex) {
                LOGGER.error("Sound line issue", ex);
            }

            new Thread(new Runnable() {
                String threadFilename = filename;
                @Override
                public void run() {
                    try {
                        musicPlayer.play();
                        while(!musicPlayer.isComplete()){
                            Thread.currentThread();
                            Thread.sleep(1000);
                        }
                        playSoundOrMusic(threadFilename, type);
                    } catch (Exception ex) {
                        LOGGER.error("Sound(music) playing issue", ex);
                    }
                }
            }).start();
        }
    }
}
KisnardOnline
  • 653
  • 4
  • 16
  • 42

1 Answers1

2

You have the buffered input stream: you read it, you manipulate the data (reduce value by 0.5(50%)), then you put into a new stream and play in the second player.

BufferedInputStream bis = new BufferedInputStream(fis);
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
byte[] data=new byte[1024];
while((k=audioInputStream.read(data, 0, data.length))>-1) {
  for(int i=0; i<k; i++) data[i]=(byte)(0.5*data[i]);
  outputStream.write(data, 0, k);
}   
byte[] audioData=outputStream.toByteArray();
InputStream bis2=new ByteArrayInputStream(outData);    
player2.play(bis2);

--

Here is a class that will process and play a file; method processPlay() can be adjusted to reduce by a certain fraction (0.5) as noted above - you could create your own method with that fraction as parameter.

import javax.sound.sampled.*;
import java.io.*;
import java.net.*;
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;

public class QHPlayer {

public void play(String f) {
  int k=0;
  AudioFormat targetFormat=null;
  try {
    AudioInputStream audioInputStream=openFile(f);
    targetFormat=audioInputStream.getFormat();
    byte[] data=new byte[1024];
    DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, targetFormat);
    SourceDataLine line=null;
      line=(SourceDataLine)AudioSystem.getLine(dinfo);
      if(line!=null) {
        line.open(targetFormat);
        line.start();
        while((k=audioInputStream.read(data, 0, data.length))>-1) {
          line.write(data, 0, k);
        }
        line.stop();
        line.close();
    }
  }
  catch(Exception ex) { ex.printStackTrace(); }
}

public void processPlay(String f) {
  int k=0;
  AudioFormat targetFormat=null;
  ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
  try {
    AudioInputStream audioInputStream=openFile(f);
    targetFormat=audioInputStream.getFormat();
    byte[] data=new byte[1024];

    while((k=audioInputStream.read(data, 0, data.length))>-1)
      outputStream.write(data, 0, k);
    byte[] b=outputStream.toByteArray();
    for(k=0; k<b.length; k++) b[k]=(byte)(0.5*b[k]);


    DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, targetFormat);
    SourceDataLine line=null;
      line=(SourceDataLine)AudioSystem.getLine(dinfo);
      if(line!=null) {
        line.open(targetFormat);
        line.start();
        System.out.println(line.available());
        k=0;
        while(k<b.length) {
        System.out.println(line.available());
          int i=line.write(b, k, 8*1024);
          k+=i;
        }
        }
        line.stop();
        line.close();
  }
  catch(Exception ex) { ex.printStackTrace(); }
}

public void play(byte[] b) {
  int k=0;
  AudioFormat targetFormat=getAudioFormat();
  try {
    DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, targetFormat);
    SourceDataLine line=null;
      line=(SourceDataLine)AudioSystem.getLine(dinfo);
      if(line!=null) {
        line.open(targetFormat);
        line.start();
        while(k<b.length) {
          int i=line.write(b, k, 8*1024);
          k+=i;
        }
        line.stop();
        line.close();
    }
  }
  catch(Exception ex) { ex.printStackTrace(); }
}



  public AudioInputStream openFile(String file) {
    AudioInputStream audioInputStream=null;
    try {
      File fileIn = new File(file);
      if(file.endsWith(".mp3"))
        audioInputStream=createMp3(fileIn);
      else
        audioInputStream=AudioSystem.getAudioInputStream(fileIn);
    }
    catch(Exception ex) { ex.printStackTrace(); }
    return audioInputStream;
  }


  AudioInputStream createMp3(File fileIn) throws IOException, Exception {
    AudioInputStream audioInputStream=null;
    AudioFormat targetFormat=null;
    try {
      AudioInputStream in=null;
      MpegAudioFileReader mp=new MpegAudioFileReader();
      in=mp.getAudioInputStream(fileIn);
      AudioFormat baseFormat=in.getFormat();
      targetFormat=new AudioFormat(
              AudioFormat.Encoding.PCM_SIGNED,
              baseFormat.getSampleRate(),
              16,
              baseFormat.getChannels(),
              baseFormat.getChannels() * 2,
              baseFormat.getSampleRate(),
              false);
      audioInputStream=AudioSystem.getAudioInputStream(targetFormat, in);
    }
    catch(UnsupportedAudioFileException ue) { System.out.println("\nUnsupported Audio"); }
    return audioInputStream;
  }


  AudioFormat getAudioFormat() {
    float sampleRate = 44100F;
    int sampleSizeInBits = 16;
    int channels = 2;
    boolean signed = true;
    boolean bigEndian = true;
    return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
  }


  public static void main(String args[]) {
    QHPlayer q=new QHPlayer();
    q.processPlay("c:/.....mp3");
  }

}
gpasch
  • 2,672
  • 3
  • 10
  • 12
  • I changed audioInputStream to be bis? I added in int k = 0; I changed outData to be audioData? Did not work - music is all garbled... sounds like a barking dog. Any thoughts? – KisnardOnline Mar 20 '16 at 06:16
  • it probably has to do with Player – gpasch Mar 20 '16 at 16:22
  • if we adhere strictly it says Player can play "Mpeg stream" - so wont play the byte stream - maybe you can wait for some other solution - otherwise you can create your own player with Line – gpasch Mar 20 '16 at 17:06
  • yeah guess I will wait for another solution :( unless you can link me somewhere on the Line player :p – KisnardOnline Mar 21 '16 at 00:12
  • Thanks this has worked. At the end of playing there is an ArrayIndexException (but I'm just catching it for now). I needed to add two more jar files (spi and triton). Appreciate the help sooo much! – KisnardOnline Mar 30 '16 at 14:40