Exoplayer(MediaX)实现音频变调和变速播放

在K歌或录音类应用中变调是个常见需求,比如需要播出萝莉音/大叔音等。变速播放在影视播放类应用中普遍存在,在传统播放器Mediaplayer中这两个功能都比较难以实现,特别在低版本SDK中,而Exoplayer作为google官方推出的Mediaplayer替代者就可以轻松实现。在前两篇文章中向大家介绍了Exoplayer拓展FFmpeg实现音频软解码和切换原伴唱功能,我们继续在此基础上实现变调和变速播放。

最新版本Exoplayer扩展FFmpeg音频软解码保姆级教程

最新版本Exoplayer(MediaX)实现K歌原伴唱包括单音轨和双音轨

一·变调

首先我们回忆一下初中物理学习的声音三大特性:音调-音色-响度

1. 音调

  • 定义:音调是指声音的高低,它是由发声体振动的频率决定的。

  • 原理:振动频率越高,音调越高;振动频率越低,音调越低。例如,女高音的音调通常比男低音高,因为女高音的声带振动频率更高。

  • 单位:频率的单位是赫兹(Hz),表示每秒振动的次数。

2. 响度

  • 定义:响度是指声音的强弱或大小,它是由发声体振动的振幅决定的。

  • 原理:振幅越大,声音越响亮;振幅越小,声音越微弱。同时,响度还与距离发声体的远近有关,距离越远,响度越小。

  • 单位:响度的单位是分贝(dB)。例如,安静的图书馆声音约为30分贝,而摇滚音乐会的声音可能达到100分贝以上。

3. 音色

  • 定义:音色是指不同物体发声时,声音的特色和品质。即使音调和响度相同,不同发声体发出的声音仍然可以通过音色进行区分。

  • 原理:音色由发声体的材料、结构和发声方式决定。例如,小提琴和钢琴演奏同一首曲子,音调和响度可能相似,但音色不同,因为它们的发声结构和材料不同。

  • 应用:音色是人们辨别不同乐器和人声的重要依据。例如,我们可以通过音色区分不同人的说话声,或者区分小提琴、大提琴和吉他等乐器的声音。

变调就是要调节音调,加减音量就是要调节响度。Exoplayer本身并不支持调节音调,而是集成了第三方开源音效库Sonic来实现的,源码地址为:https://github.com/waywardgeek/sonic,Exoplayer在此基础上封装了SonicAudioProcessor供开发调用,源码分析参考Android 分场景集成不同音频倍速算法的实现。而 ijkplayer使用的是soundtouch音效库。下面看具体实现:

1.自定义DefaultRenderersFactory,得到AudioSink

复制代码
    @SuppressLint("UnsafeOptInUsageError")
    public class PluginRenderFactory extends DefaultRenderersFactory {
        /**
         * @param context A {@link Context}.
         */
        public PluginRenderFactory(Context context) {
            super(context);
        }

        @Nullable
        @Override
        protected AudioSink buildAudioSink(Context context, boolean enableFloatOutput, boolean enableAudioTrackPlaybackParams) {
            audioSink = new DefaultAudioSink.Builder().setAudioProcessors(new AudioProcessor[]{new SonicAudioProcessor()}).setEnableAudioTrackPlaybackParams(true).build();
            return audioSink;
            // return super.buildAudioSink(context, enableFloatOutput, enableAudioTrackPlaybackParams);
        }

        @Override
        protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList<Renderer> out) {
            //  audioSink.setPlaybackParameters(new PlaybackParameters(1.0f,0.1f));

            Log.i(TAG, "=audio pitch=" + audioSink.getPlaybackParameters().pitch);
            ffmpegAudioRenderer = new FfmpegAudioRenderer(eventHandler, eventListener, audioSink);
            out.add(ffmpegAudioRenderer);
            super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out);
        }
    }

2.初始化Exoplayer并设置上述自定义的Renderer

复制代码
 renderersFactory = new PluginRenderFactory(context)
                .setEnableAudioTrackPlaybackParams(true)
                // .setEnableDecoderFallback(true)
                .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON);

        mExoPlayer = new ExoPlayer.Builder(context, renderersFactory)
                .setTrackSelector(trackSelector)
                // .setHandleAudioBecomingNoisy(true)
                .build();
  1. 通过audioSink.setPlaybackParameters(new PlaybackParameters(1.0f, pitch));实现变调不变速,pitch取值【0.1~1.0】越大,音调越高,第一个参数是speed,可设置音频播放速度

    复制代码
     public void setPitch(int tone) {
         if (!mExoPlayer.isPlaying() || lastTone == tone)
             return;
         try {
             lastTone = tone;
             // Log.i(TAG,"=setPitch="+tone);
             //   ffmpegAudioRenderer.setPitchMode(tone + 10);
             float pitch = 1.0f;
             if (tone >= -5 && tone <= 5) {
                 pitch = 1.0f + 0.1f * tone;
             }
             Log.i(TAG, "=setPitch=" + tone + "=pitch=" + pitch);
             audioSink.pause();
             audioSink.setPlaybackParameters(new PlaybackParameters(1.0f, pitch));
             audioSink.play();
         } catch (Exception e) {
             Log.i(TAG, "=setPitch error=" + e.toString());
         }
    
     }

二 设置音量

方式一通过AudioSink设置:

复制代码
audioSink.setVolume(defaultVol);

方式二·通过Exoplayer实例直接设置

复制代码
mExoPlayer.setVolume(defaultVol);

三 变速播放

复制代码
   public void setSpeed(float speed) {
        PlaybackParameters parameters = new PlaybackParameters(speed);
        mExoPlayer.setPlaybackParameters(parameters);
    }
相关推荐
每次的天空1 小时前
Kotlin 内联函数深度解析:从源码到实践优化
android·开发语言·kotlin
练习本1 小时前
Android MVC架构的现代化改造:构建清晰单向数据流
android·架构·mvc
早上好啊! 树哥2 小时前
android studio开发:设置屏幕朝向为竖屏,强制应用的包体始终以竖屏(纵向)展示
android·ide·android studio
YY_pdd2 小时前
使用go开发安卓程序
android·golang
Android 小码峰啊4 小时前
Android Compose 框架物理动画之捕捉动画深入剖析(29)
android·spring
bubiyoushang8884 小时前
深入探索Laravel框架中的Blade模板引擎
android·android studio·laravel
cyy2984 小时前
android 记录应用内存
android·linux·运维
CYRUS STUDIO5 小时前
adb 实用命令汇总
android·adb·命令模式·工具
这儿有一堆花5 小时前
安卓应用卡顿、性能低下的背后原因
android·安卓
byte轻骑兵5 小时前
【Bluedroid】蓝牙HID DEVICE断开连接流程源码分析
android·c++·蓝牙·hid·bluedroid