close
当前位置: 物联网在线 > 技术文库 > android >

详解如何使用代码进行音频合成,以Java为示例语言,以Android为示例平台

音频合成在现实生活中应用广泛,在网上可以搜索到不少相关的讲解和代码实现,但个人感觉在网上搜索到的音频合成相关文章的讲解都并非十分透彻,故而写下本篇博文,计划通过讲解如何使用代码实现音频合成功能从而将本人对音频合成的理解阐述给各位,力图读完的各位可以对音频合成整体过程有一个清晰的了解。
        本篇博文以Java为示例语言,以Android为示例平台。
        本篇博文着力于讲解音频合成实现原理与过程中的细节和潜在问题,目的是让各位不被编码语言所限制,在本质上理解如何实现音频合成的功能。

2.音频合成 2.1.功能简介

本次实现的音频合成功能参考"唱吧"的音频合成,功能流程是:录音生成PCM文件,接着根据录音时长对背景音乐文件进行解码加裁剪,同时将解码后的音频调制到与录音文件相同的采样率,采样点字节数,声道数,接着根据指定系数对两个音频文件进行音量调节并合成为PCM文件,最后进行压缩编码生成MP3文件。

2.2.功能实现

2.2.1.录音

录音功能生成的目标音频格式是PCM格式,对于PCM的定义,维基百科上是这么写到的:"Pulse-code modulation (PCM) is a method used to digitally represent sampled analog signals. It is the standard form of digital audio in computers, Compact Discs, digital telephony and other digital audio applications. In a PCM stream, the amplitude of the analog signal is sampled regularly at uniform intervals, and each sample is quantized to the nearest value within a range of digital steps.",大致意思是PCM是用来采样模拟信号的一种方法,是现在数字音频应用中数字音频的标准格式,而PCM采样的原理,是均匀间隔的将模拟信号的振幅量化成指定数据范围内最贴近的数值。
        PCM文件存储的数据是不经压缩的纯音频数据,当然只是这么说可能有些抽象,我们拉上大家熟知的MP3文件进行对比,MP3文件存储的是压缩后的音频,PCM与MP3两者之间的关系简单说就是:PCM文件经过MP3压缩算法处理后生成的文件就是MP3文件。我们简单比较一下双方存储所消耗的空间,1分钟的每采样点16位的双声道的44.1kHz采样率PCM文件大小为:16016/8244.1*1000/1024=10335.9375KB,约为10MB,而对应的128kps的MP3文件大小仅为1MB左右,既然PCM文件占用存储空间这么大,我们是不是应该放弃使用PCM格式存储录音,恰恰相反,注意第一句话:"PCM文件存储的数据是不经压缩的纯音频数据",这意味只有PCM格式的音频数据是可以用来直接进行声音处理,例如进行音量调节,声音滤镜等操作,相对的其他的音频编码格式都是必须解码后才能进行处理(PCM编码的WAV文件也得先读取文件头),当然这不代表PCM文件就好用,因为没有文件头,所以进行处理或者播放之前我们必须事先知道PCM文件的声道数,采样点字节数,采样率,编码大小端,这在大多数情况下都是不可能的,事实上就我所知没有播放器是直接支持PCM文件的播放。不过现在录音的各项系数都是我们定义的,所以我们就不用担心这个问题。
        背景知识了解这些就足够了,下面我给出实现代码,综合代码讲解实现过程。

if (recordVoice) { audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, Constant.RecordSampleRate, AudioFormat.CHANNEL_IN_MONO, pcmFormat.getAudioFormat(), audioRecordBufferSize); try { audioRecord.startRecording(); } catch (Exception e) { NoRecordPermission(); continue; } BufferedOutputStream bufferedOutputStream = FileFunction .GetBufferedOutputStreamFromFile(recordFileUrl); while (recordVoice) { int audioRecordReadDataSize = audioRecord.read(audioRecordBuffer, 0, audioRecordBufferSize); if (audioRecordReadDataSize > 0) { calculateRealVolume(audioRecordBuffer, audioRecordReadDataSize); if (bufferedOutputStream != null) { try { byte[] outputByteArray = CommonFunction .GetByteBuffer(audioRecordBuffer, audioRecordReadDataSize, Variable.isBigEnding); bufferedOutputStream.write(outputByteArray); } catch (IOException e) { e.printStackTrace(); } } } else { NoRecordPermission(); continue; } } if (bufferedOutputStream != null) { try { bufferedOutputStream.close(); } catch (Exception e) { LogFunction.error("关闭录音输出数据流异常", e); } } audioRecord.stop(); audioRecord.release(); audioRecord = null; }

录音的实际实现和控制代码较多,在此仅抽出核心的录音代码进行讲解。在此为获取录音的原始数据,我使用了Android原生的AudioRecord,其他的平台基本也会提供类似的工具类。这段代码实现的功能是当录音开始后,应用会根据设定的采样率和声道数以及采样字节数来不断从MIC中获取原始的音频数据,然后将获取的音频数据写入到指定文件中,直至录音结束。这段代码逻辑比较清晰的,我就不过多讲解了。
        潜在问题的话,手机平台上是需要申请录音权限的,如果没有录音权限就无法生成正确的录音文件。

2.2.2.解码与裁剪背景音乐


(责任编辑:ioter)

用户喜欢...

使用Android Studio开发可独立运行(runnable)混淆过的Jar程序

之前开发Java程序一直都是使用Eclipse 开发Jar程序,现在开发基本上都已经弃用Eclipse了,但是有时偶尔开发个小的Jar程序,还要切换回去好麻烦,刚好前几天有人问几个相关的问题,就顺便整...


如何解决 Android Studio 上远程依赖包重复的问题(com.android.dex.DexException)

你们是不是会经常遇到这样的一个错误:com.android.dex.DexException: Multiple dex files define XXXX,一般情况下,是我们项目中引用了重复的库或者jar包引起的,我们找到去掉即可解决,但是如果你远程...


Android Studio使用小技巧,只能说666

一般的什么快捷键,技巧的文章也有很多。我也看过很多。下面这些事我在来自国外大神发布的:Android Studio Tips of the Day( https://plus.google.com/u/0/collection/wtO0PB )查看到的,而且对于我来说有...


android studio 使用gradle打jar包并混淆

昨天准备把写好的代码使用gradle打jar包出来,并打算加混淆。打jar包容易,结果在混淆上走了弯路。 首先打jar包的配置很简单,使用jar的task,具体代码如下: task buildJar(type: Jar, dependsOn: ['...


Android应用性能优化之使用SparseArray

最近在看一些Android应用性能优化的文章时,发现提到了SparseArray替代HashMap可以优化app性能,就对SparseArray做了一番了解,并记录使用心得。 我们来看看SparseArray点击进去包含了那些方法 ////...


Android线程,线程池使用及原理博文参考

这块的知识可以说是一大块,要撸清楚还是要花点时间,线程池中关联到的队列不仅在线程池中使用,在各种第三方网络框架和图片框架等等中也是通过自己调度队列来实现异步。有关理论的东西...


Android滑动效果是如何产生的

相对于Android2.X版本中常见的长按、点击操作,滑动的操作方式具有更好的用户体验性。因此,从Android4.X版本开始,滑动操作就大量出现在了Android系统中,各种第三方应用也竞相模仿这种效果...


Android 如何编写基于编译时注解的项目

在Android应用开发中,我们常常为了提升开发效率会选择使用一些基于注解的框架,但是由于反射造成一定运行效率的损耗,所以我们会更青睐于编译时注解的框架,例如: butterknife 免去我们...


如何提高 Android 代码质量 -工具篇

这是一篇翻译文章,原文: How to improve quality and syntax of your Android code ,为了理解连贯,翻译过程中我修改了一些陈述逻辑和顺序,同时也加了一些自己的补充。 在这片文章中,我将从工具使...


Android中使用Rxjava时,内存泄漏了吗?

今天有位同学问了我一个问题,话说,问我 “有遇到网络请求一半,退出Activity造成的Theard泄露吗?已在销毁时调用了un了 我去查看了下rx的源码的unsubscribe方法,定位到一个实现类,NewThre...