【问题标题】:Create mixed audio file from two or more mp3 files从两个或多个 mp3 文件创建混合音频文件
【发布时间】:2014-03-25 23:13:39
【问题描述】:

我试图从两个或两个以上相同长度的音频文件创建一个同步音频输出文件。 我做了一些研究,发现这可以通过以下步骤来实现:

  1. 只有未压缩的音频文件可以用于此目的。即将 mp3 音频文件转换为 WAV 格式。
  2. 混合 2 个新的 wav 文件;我遵循了这种方法: Mix audio in android

但同样的问题出现了,混合的音频文件无法播放。

我一直在尝试按照这个答案 Writing PCM recorded data into a .wav file (java android) 向输出文件添加一个有效的标题。

这是我的混音器类:

public class SongMixer2
{

private Context mContext;

public SongMixer2(Context context)
{
    mContext = context;
}

public void onCreate()
{
    try
    {
        mixSound();
    } catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void mixSound() throws IOException
{
    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            44100, AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT, 44100, AudioTrack.MODE_STREAM);

    InputStream in1 = mContext.getResources().openRawResource(R.raw.brokaw);
    InputStream in2 = mContext.getResources().openRawResource(R.raw.brokaw);

    byte[] arrayMusic1 = null;
    arrayMusic1 = new byte[in1.available()];
    arrayMusic1 = createMusicArray(in1);
    in1.close();

    byte[] arrayMusic2 = null;
    arrayMusic2 = new byte[in2.available()];
    arrayMusic2 = createMusicArray(in2);
    in2.close();

    byte[] output = new byte[arrayMusic1.length];

    audioTrack.play();

    for (int i = 0; i < output.length - 1; i++)
    {
        float samplef1 = arrayMusic1[i] / 128.0f;
        float samplef2 = arrayMusic2[i] / 128.0f;
        float mixed = samplef1 + samplef2;

        // reduce the volume a bit:
        mixed *= 0.8;
        // hard clipping
        if (mixed > 1.0f)
            mixed = 1.0f;
        if (mixed < -1.0f)
            mixed = -1.0f;

        byte outputSample = (byte) (mixed * 128.0f);
        output[i] = outputSample;
    }

    audioTrack.write(output, 0, output.length);
    convertByteToFile(output);
}

public static byte[] createMusicArray(InputStream is) throws IOException
{

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buff = new byte[10240];
    int i = Integer.MAX_VALUE;
    while ((i = is.read(buff, 0, buff.length)) > 0)
    {
        baos.write(buff, 0, i);
    }

    return baos.toByteArray(); // be sure to close InputStream in calling
                                // function

}

public static void convertByteToFile(byte[] fileBytes)
        throws FileNotFoundException
{

    String path = Environment.getExternalStorageDirectory().getPath() + "/mixed.wav";
    File f=new File(path);
    BufferedOutputStream bos = new BufferedOutputStream(
            new FileOutputStream(f));
    try
    {
        bos.write(writeHeader(fileBytes.length), 0, 44);
        bos.write(fileBytes);
        bos.flush();
        bos.close();
    } catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static byte[] writeHeader(int totalDataLen)
{
    byte[] header = new byte[44];

    header[0] = 'R';  // RIFF/WAVE header
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    header[4] = (byte) (totalDataLen & 0xff);
    header[5] = (byte) ((totalDataLen >> 8) & 0xff);
    header[6] = (byte) ((totalDataLen >> 16) & 0xff);
    header[7] = (byte) ((totalDataLen >> 24) & 0xff);
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    header[12] = 'f';  // 'fmt ' chunk
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
    header[17] = 0;
   /* header[18] = 0;
    header[19] = 0;
    header[20] = 1;  // format = 1
    header[21] = 0;
    header[22] = (byte) channels;
    header[23] = 0;
    header[24] = (byte) (longSampleRate & 0xff);
    header[25] = (byte) ((longSampleRate >> 8) & 0xff);
    header[26] = (byte) ((longSampleRate >> 16) & 0xff);
    header[27] = (byte) ((longSampleRate >> 24) & 0xff);
    header[28] = (byte) (byteRate & 0xff);
    header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff);
    header[31] = (byte) ((byteRate >> 24) & 0xff);
    header[32] = (byte) (2 * 16 / 8);  // block align
    header[33] = 0;
    header[34] = RECORDER_BPP;  // bits per sample
    header[35] = 0;*/
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
   /* header[40] = (byte) (totalAudioLen & 0xff);
    header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
    header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
*/

 return header;
}

}

还有活动:

public class SoundMixerActivity extends Activity 
{
protected void onCreate(Bundle savedInstanceState) 
    {
    super.onCreate(savedInstanceState);
    new SongMixer2(this).onCreate();
}
}

在 SD 卡中创建了一个文件 'mixed.wav',但无法播放...请大家帮忙!!

【问题讨论】:

  • @Vnay:你找到解决办法了吗?
  • @Vinay 到目前为止你找到解决方案了吗?请帮帮我...我也在做同样的事情

标签: android audio mixing


【解决方案1】:

在您的标题中,您说该文件的音频对齐为 4 个字节。这适用于 16 位立体声音频。

但是,在您的 createMix 中,您假设音频是 8 位(一个字节)而不是 16 位。您需要使用短裤进行混音。

从每个文件中获取样本的平均值也很常见。即 (sample1 + sample2) / 2.

【讨论】:

  • 感谢 Goz,您的快速回复。我将标题更新为标题 [16] = 32;但没有运气,文件已创建但无法播放:(你能告诉我是否有不同的方法来实现目标吗?
  • @Vinay:反应慢,抱歉。为什么你将你的标题更新为 32 字节? 36 - 16 = 20,而不是 32。此外,将数据块中的样本混合在一起确实是错误的(假设您确实想要 16 位音频)。
  • 正确的解决方案是正确解析您的波头。随意使用您迄今为止编写的代码开始另一个问题,并在此处的 cmets 中链接到它。如果可以的话,我会尽力帮助你...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-19
  • 1970-01-01
  • 2016-05-22
  • 2012-03-02
  • 2013-03-17
  • 1970-01-01
  • 2011-12-06
相关资源
最近更新 更多