2011-05-07 82 views
3

我試圖混合幾個不同的音頻流,並試圖讓他們同時播放而不是一次。與Java混合音頻(不帶混音器API)

下面的代碼一次一個播放它們,我找不到一個不使用Java Mixer API的解決方案。不幸的是,我的聲卡不支持使用Mixer API進行同步,我不得不想出一種通過代碼實現的方法。

請指教。

/////代碼如下////

class MixerProgram { 
public static AudioFormat monoFormat; 
private JFileChooser fileChooser = new JFileChooser(); 
private static File[] files; 
private int trackCount; 
private FileInputStream[] fileStreams = new FileInputStream[trackCount]; 
public static AudioInputStream[] audioInputStream; 
private Thread trackThread[] = new Thread[trackCount]; 
private static DataLine.Info sourceDataLineInfo = null; 
private static SourceDataLine[] sourceLine; 

public MixerProgram(String[] s) 
{ 
    trackCount = s.length; 
    sourceLine = new SourceDataLine[trackCount]; 
    audioInputStream = new AudioInputStream[trackCount]; 
    files = new File[s.length]; 
} 

public static void getFiles(String[] s) 
{ 
    files = new File[s.length]; 
    for(int i=0; i<s.length;i++) 
    { 
    File f = new File(s[i]); 
    if (!f.exists()) 
    System.err.println("Wave file not found: " + filename); 
    files[i] = f; 
    } 
} 


public static void loadAudioFiles(String[] s) 
{ 
    AudioInputStream in = null; 
    audioInputStream = new AudioInputStream[s.length]; 
    sourceLine = new SourceDataLine[s.length]; 
    for(int i=0;i<s.length;i++){ 
    try 
    { 
     in = AudioSystem.getAudioInputStream(files[i]); 
    } 
    catch(Exception e) 
    { 
     System.err.println("Failed to assign audioInputStream"); 
    } 
    monoFormat = in.getFormat(); 
    AudioFormat decodedFormat = new AudioFormat(
               AudioFormat.Encoding.PCM_SIGNED, 
               monoFormat.getSampleRate(), 16, monoFormat.getChannels(), 
               monoFormat.getChannels() * 2, monoFormat.getSampleRate(), 
               false); 
    monoFormat = decodedFormat; //give back name 
    audioInputStream[i] = AudioSystem.getAudioInputStream(decodedFormat, in); 
    sourceDataLineInfo = new DataLine.Info(SourceDataLine.class, monoFormat); 
    try 
    { 
    sourceLine[i] = (SourceDataLine) AudioSystem.getLine(sourceDataLineInfo); 
    sourceLine[i].open(monoFormat); 
    } 
    catch(LineUnavailableException e) 
    { 
    System.err.println("Failed to get SourceDataLine" + e); 
    } 
}    
} 

public static void playAudioMix(String[] s) 
{ 
    final int tracks = s.length; 
    System.out.println(tracks); 
    Runnable playAudioMixRunner = new Runnable() 
    { 
    int bufferSize = (int) monoFormat.getSampleRate() * monoFormat.getFrameSize(); 
    byte[] buffer = new byte[bufferSize]; 
    public void run() 
    { 
     if(tracks==0) 
     return; 
     for(int i = 0; i < tracks; i++) 
     { 
     sourceLine[i].start(); 
     }   
     int bytesRead = 0; 
     while(bytesRead != -1) 
     { 
     for(int i = 0; i < tracks; i++) 
     { 
      try 
      { 
      bytesRead = audioInputStream[i].read(buffer, 0, buffer.length); 
      } 
      catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
      }    
      if(bytesRead >= 0) 
      { 
      int bytesWritten = sourceLine[i].write(buffer, 0, bytesRead); 
      System.out.println(bytesWritten); 
      } 
     } 
     } 
    } 
    }; 
    Thread playThread = new Thread(playAudioMixRunner); 
    playThread.start(); 
} 
} 

回答

5

的問題是,你不加入的樣品一起。如果我們正在查看4條軌道,即16位PCM數據,則需要將所有不同的值加在一起,以將它們「混合」爲一個最終輸出。所以,從純粹的號碼點的視圖,它應該是這樣的:

[Track1] 320 -16 2000 200 400 
[Track2] 16 8 123 -87 91 
[Track3] -16 -34 -356 1200 805 
[Track4] 1011 1230 -1230 -100 19 
[Final!] 1331 1188 537 1213 1315 

在你上面的代碼中,你應該只寫一個字節數組。該字節數組是所有軌道加在一起的最終組合。問題在於你正在爲每個不同的軌道寫一個字節數組(所以沒有發生混頻,就像你觀察到的那樣)。

如果你想保證你沒有任何「剪輯」,你應該取所有曲目的平均值(因此將上面的所有四個曲目添加併除以4)。然而,選擇這種方法會產生人爲因素(例如,如果您在三首曲目和一首響亮的曲目中保持沉默,最終輸出將比不靜音的一首曲目的音量大得多)。您可以使用更復雜的算法來進行混音,但是到那時您正在編寫自己的混音器:P。