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);
    }
相关推荐
u01090535911 分钟前
神卓 S500 异地组网设备实现监控视频异地组网的详细步骤
网络·音视频
运维_攻城狮1 小时前
遇到liunx服务器IO负载,读IO流量峰值347MB/s,排查并解决。
android·运维·服务器·mysql
m0_748232392 小时前
qwenvl 以及qwenvl 2 模型架构理解
android·前端·后端
山河君2 小时前
音频进阶学习十六——LTI系统的差分方程与频域分析一(频率响应)
学习·音视频·信号处理
web136885658712 小时前
PHP For 循环
android·java·php
Cherry Xie2 小时前
阿里开源正式开园文生视频、图生视频模型-通义万相 WanX2.1
人工智能·音视频
肥or胖2 小时前
【入门音视频】音视频基础知识
笔记·音视频
gma9992 小时前
【音视频】编解码相关概念总结
音视频
avi91112 小时前
[AI相关]问问DeepSeek如何基于Python,moviePy实现视频字幕功能
python·音视频·moviepy·deepseek
Neo Evolution3 小时前
每天一个Flutter开发小项目 (6) : 表单与验证的专业实践 - 构建预约应用
android·开发语言·前端·javascript·flutter