Android:混合音频

标签 android android-ndk

我正在开发一款使用 mediarecorder 录制语音并使用 mediaplayer 播放音乐的 Android 应用。

我的目标是将两个音频混合到一个文件中,因为 Android 没有为此提供任何 API,所以我正在寻找一个合理的解决方案。

目前,在播放时,我正在使用带有 MIC 源的新媒体记录器来捕获音频并保存它,但这非常糟糕!!!

要混合音频吗?包括任何原生解决方案 lix SOX 或 FFMPEG?

或者,无论如何要使用媒体播放器输出作为源而不是使用 MIC 来记录到文件中?

如有任何建议,我们将不胜感激。

谢谢。

最佳答案

当我遇到同样的问题时,我找到了混合文件的解决方案。 由于无法混合两个 mp3 文件,您必须先将其转换为 wave 格式,然后设置标题值。之后添加数据字段。我按照以下方式做到了这一点。希望我的代码能帮到你。

类 MixFile 扩展了 AsyncTask{

    ProgressDialog dialog;
    protected void onPreExecute() {
        dialog= new ProgressDialog(MainActivity.this);
        dialog.setCancelable(false);
        dialog.setMessage("Mixing two wav files");
        dialog.show();
    }
    @Override
    protected Void doInBackground(Void... arg0) {
        short[] audioData1 = null;
        short[] audioData2 = null;

        int n = 0;

        try {
            DataInputStream in1;

//in1 = new DataInputStream(new FileInputStream(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/one.wav")); in1 = new DataInputStream(new FileInputStream(path1)); ByteArrayOutputStream bos = new ByteArrayOutputStream();

            try {

                while ((n = in1.read()) != -1) {
                    bos.write(n);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
            bb.order(ByteOrder.LITTLE_ENDIAN);
            ShortBuffer sb = bb.asShortBuffer();
            audioData1 = new short[sb.capacity()];

            for (int i = 0; i < sb.capacity(); i++) {
                audioData1[i] = sb.get(i);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            DataInputStream in1;
            in1 = new DataInputStream(new FileInputStream(path2));
            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            try {

                while ((n = in1.read()) != -1) {
                    bos.write(n);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }


            ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
            bb.order(ByteOrder.LITTLE_ENDIAN);
            ShortBuffer sb = bb.asShortBuffer();
            audioData2=  new short[sb.capacity()];

            sb.get(audioData2);


            System.out.println();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // find the max:



        float max = 0;

        Log.d("File audio lenght 1 ", ""+audioData1.length);
        Log.d("File audio lenght 2 ", ""+audioData2.length);

        System.out.println("MainActivity.MixFile.doInBackground() 1"+audioData1.length);
        System.out.println("MainActivity.MixFile.doInBackground() 2"+audioData2.length);

        if(audioData1.length > audioData2.length){

        for (int i = 22; i < audioData2.length; i++) {
            if (Math.abs(audioData1[i] + audioData2[i]) > max)
                max = Math.abs(audioData1[i] + audioData2[i]);
        }

        System.out.println("" + (Short.MAX_VALUE - max));
        int a, b, c;
        // now find the result, with scaling:
        for (int i = 22; i < audioData2.length; i++) {
            a = audioData1[i];
            b = audioData2[i];

            c = Math.round(Short.MAX_VALUE * (audioData1[i] + audioData2[i])
                    / max);

            if (c > Short.MAX_VALUE)
                c = Short.MAX_VALUE;
            if (c < Short.MIN_VALUE)
                c = Short.MIN_VALUE;


            audioData1[i] = (short) c; 

        }

        // to turn shorts back to bytes.
        byte[] end = new byte[audioData1.length * 2];
        ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData1);

        try {
            OutputStream out  = new FileOutputStream(Environment.getExternalStorageDirectory() + "/assets/mixer12.wav");
            for (int i = 0; i < end.length; i++) {
                out.write(end[i]);
                out.flush();
            }
            out.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        }else{

            System.out.println("MainActivity.MixFile.doInBackground() smaller one");
            for (int i = 22; i < audioData1.length; i++) {
                if (Math.abs(audioData2[i] + audioData1[i]) > max)
                    max = Math.abs(audioData2[i] + audioData1[i]);
            }

            System.out.println("" + (Short.MAX_VALUE - max));
            int a, b, c;
            // now find the result, with scaling:
            for (int i = 22; i < audioData1.length; i++) {
                a = audioData2[i];
                b = audioData1[i];

                c = Math.round(Short.MAX_VALUE * (audioData2[i] + audioData1[i])
                        / max);

                if (c > Short.MAX_VALUE)
                    c = Short.MAX_VALUE;
                if (c < Short.MIN_VALUE)
                    c = Short.MIN_VALUE;


                audioData2[i] = (short) c; 

            }

            // to turn shorts back to bytes.
            byte[] end = new byte[audioData2.length * 2];
            ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData2);

            try {
                OutputStream out  = new FileOutputStream(Environment.getExternalStorageDirectory() + "/Assets/mixer1.wav");
                for (int i = 0; i < end.length; i++) {
                    out.write(end[i]);
                    out.flush();
                }
                out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }



        }
        return null;
    }

在 Activity 中我这样调用它

 public class MainActivity extends Activity implements OnClickListener {

  new MixFile().execute();

  }

这里path1和path2是你要混音的wav文件的路径

关于Android:混合音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8803889/

相关文章:

java - 如何使卡片 View 的移动更加流畅?

android - Superpowered API - SuperpoweredDecoder::decode 不为文件末尾返回 0

android - NDK 的回调未在 java 中找到方法

android - 使用 Flutter 访问大量 JSON Assets

java - 如何在 Android < 5.0 上使用 Mailgun 发送 HTML 电子邮件

android - AutoCompleteTextView - 当我们在过滤后有一个完全匹配项时如何禁用下拉列表?

android - glext.h 函数未解析

Android Studio - App + NDK 模块库

android - 在 Android NDK 中使用 -fsigned-char 构建是否安全?

android - 为什么在没有 setDisplayHomeAsUpEnabled() 的情况下出现向上按钮?