简体   繁体   English

使用Java混音(不使用混音器API)

[英]Audio Mixing with Java (without Mixer API)

I am attempting to mix several different audio streams and trying to get them to play at the same time instead of one-at-a-time. 我试图混合几个不同的音频流,并尝试让它们同时播放, 而不是一次一个。

The code below plays them one-at-a-time and I cannot figure out a solution that does not use the Java Mixer API. 下面的代码一次一个地播放它们,我无法找到不使用Java Mixer API的解决方案。 Unfortunately, my audio card does not support synchronization using the Mixer API and I am forced to figure out a way to do it through code. 不幸的是,我的声卡不支持使用Mixer API进行同步,我不得不想办法通过代码来实现。

Please advise. 请指教。

/////CODE IS BELOW//// /////代码如下////

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

The problem is that you are not adding the samples together. 问题是您没有将样本添加到一起。 If we are looking at 4 tracks, 16-bit PCM data, you need to add all the different values together to "mix" them into one final output. 如果我们查看4个轨道,16位PCM数据,您需要将所有不同的值一起添加到一个最终输出中“混合”它们。 So, from a purely-numbers point-of-view, it would look like this: 因此,从纯数字的角度来看,它看起来像这样:

[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

In your above code, you should only be writing a single byte array. 在上面的代码中,您应该只编写单个字节数组。 That byte array is the final mix of all tracks added together. 该字节数组是加在一起的所有轨道的最终组合。 The problem is that you are writing a byte array for each different track (so there is no mixdown happening, as you observed). 问题是你正在为每个不同的轨道写一个字节数组(所以没有发生混音,正如你所观察到的那样)。

If you want to guarantee you don't have any "clipping", you should take the average of all tracks (so add all four tracks above and divide by 4). 如果你想保证你没有任何“剪辑”,你应该取所有曲目的平均值(所以添加上面的所有四个曲目并除以4)。 However, there are artifacts from choosing that approach (like if you have silence on three tracks and one loud track, the final output will be much quiter than the volume of the one track that is not silent). 但是,选择这种方法会有一些瑕疵(例如,如果你在三个音轨和一个响亮的音轨上保持沉默,最终的输出将比一个非静音音轨的音量更安静)。 There are more complicated algorithms you can use to do the mixing, but by then you are writing your own mixer :P. 您可以使用更复杂的算法进行混音,但到那时您正在编写自己的混音器:P。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM