Воспроизведение java mp3 одновременно с разной громкостью

Я использую JLayer для воспроизведения своих звуков в игре. Я пытаюсь установить независимые уровни громкости для моей музыки (постоянно играющей) и звуковых эффектов (спорадически). Прямо сейчас мой код изменяет уровень основной громкости, поэтому, как и ожидалось, он меняет громкость обоих. Вот пример кода, чтобы продемонстрировать, что я хочу сделать (я вырезал много вещей, чтобы попытаться быть похожим на SSCCE и понять, что есть некоторые «ошибки»).

Любая помощь будет очень признательна.

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();
        }
    }
}

person KisnardOnline    schedule 19.03.2016    source источник
comment
@gpasch куда делся твой ответ? Я только что закончил его реализацию, и он отлично работает. Невозможно назначить награду :(   -  person KisnardOnline    schedule 30.03.2016


Ответы (1)


У вас есть буферизованный входной поток: вы читаете его, манипулируете данными (уменьшаете значение на 0,5 (50%)), затем вставляете в новый поток и играете во втором проигрывателе.

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);

--

Вот класс, который будет обрабатывать и воспроизводить файл; метод processPlay() можно настроить для уменьшения на определенную долю (0,5), как указано выше, — вы можете создать свой собственный метод с этой долей в качестве параметра.

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");
  }

}
person gpasch    schedule 19.03.2016
comment
Я изменил audioInputStream на bis? Я добавил int k = 0; Я изменил outData на audioData? Не получилось - музыка вся перевирается... звучит как лай собаки. Есть предположения? - person KisnardOnline; 20.03.2016
comment
скорее всего это связано с плеером - person gpasch; 20.03.2016
comment
если мы строго придерживаемся, он говорит, что проигрыватель может воспроизводить поток Mpeg - поэтому не будет воспроизводить поток байтов - возможно, вы можете подождать какого-то другого решения - в противном случае вы можете создать свой собственный проигрыватель с Line - person gpasch; 20.03.2016
comment
да, думаю, я подожду другого решения :( если вы не можете связать меня где-нибудь с линейным плеером :p - person KisnardOnline; 21.03.2016
comment
Спасибо, это сработало. В конце игры есть исключение ArrayIndexException (но я его пока только ловлю). Мне нужно было добавить еще два файла jar (spi и triton). Очень ценю помощь! - person KisnardOnline; 30.03.2016