2011-05-07 169 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。