【音频播放】自制音频播放器—音视频基础概念,未完待续。。。

本文详细介绍了声音的物理特性和数字化过程,包括声音的本质是波、声音的数字化、采样率、量化精度、声道数、音频帧和声道的概念。还探讨了音频开发中的关键参数,如采样率至少需要40kHz以保证人耳听觉不失真,以及非整数倍采样率转换可能导致的音质损失。此外,提到了Android系统中音频处理的挑战和常见音频格式的使用。
摘要由CSDN通过智能技术生成

近期用Electron制作了一个简易版客户端,未完待补充,重点在播放,引用凯教,先说几点。(图片禁止搬运,不得允许不准转载)

  • 研究音频的数字化技术之前,必须对声音和图像的的物理性质有基本的了解。

       如下

  • 声音的物理特性

    声音的本质是波:物体通过振动,对空气(传播介质)产生挤压,使空气有节奏的振动并产生疏密变化,从而形成疏密相间的纵波。

  • 声音的数字化

    数字化音频技术,就是声音的采集、存储和回放。

        采样:

        采样就是在时间轴上数字化声音信号。

        为了提高采样质量,根据采样定理,需要按比声音最高频率高2倍以上的频率对声音进行采            样。人耳能听到的声音频率范围20Hz~20KHz,所有典型的采样率为44.1kHz(表示一秒钟            采集44100次数据)。

音频开发基础概念

(1)采样率(samplerate)

是指录音设备在一秒钟内对声音信号的采样次数。

采样频率越高声音的还原就越真实越自然。单位用赫兹(Hz)

采样定理: (奈奎斯特定理)

在进行模拟/数字信号的转换过程中,当采样频率fs.max大于信号中最高频率fmax的2倍时(fs.max>2fmax),采样之后的数字信号完整地保留了原始信号中的信息,一般实际应用中保证采样频率为信号最高频率的2.56~4倍;

人耳能听到的声波的频率范围通常?    20~20000Hz

为了保证声音不失真,采样频率应在40kHz以上.

但是,常用的音频采样频率有:8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz、96kHz、192kHz等。

例如:电话是标准的8khz采样率!

话音信号频率在0.3~3.4kHz范围内,用8kHz的抽样频率,就可获得能取代原来连续话音信号的抽样信号。

而一般CD采集采样频率为44.1kHz。

目前,一般情况下的录音都是采用44100Hz的。

(2)量化精度(位宽)

就是把采样得到的声音信号幅度转换成数字值,

用于表示信号强度。

量化精度:用多少个二进位来表示每一个采样值,也称为量化位数。

声音信号的量化位数一般是 4,6,8,12或16 bits 。

这个数值的数据类型大小可以是:4bit、8bit、16bit、32bit等等,位数越多,表示得就越精细,声音质量自然就越好。

当然,数据量也会成倍增大。

一般采用的是16bit。

(3)声道数(channels)

由于音频的采集和播放是可以叠加的.

因此,可以同时从多个音频源采集声音,并分别输出到不同的扬声器,故声道数一般表示声音录制时的音源数量或回放时相应的扬声器数量。

单声道(Mono)和双声道(Stereo)比较常见,顾名思义,前者的声道数为1,后者为2。

(4)音频帧(frame)

音频跟视频很不一样,视频每一帧就是一张图像,而从上面的正弦波可以看出,音频数据是流式的,本身没有明确的一帧帧的概念。

在实际的应用中,为了音频算法处理/传输的方便,一般约定俗成取2.5ms~60ms为单位的数据量为一帧音频。

这个时间被称之为“采样时间”,其长度没有特别的标准,它是根据编解码器和具体应用的需求来决定的,我们可以计算一下一帧音频帧的大小:

AAC: 一个AAC帧对应的采样点个数1024, 采样率(samplerate)为 44100Hz

当前一帧的播放时间 = 1024 * 1000000/44100= 22.32ms(单位为ms)

mp3: 每帧均为1152个字节

当前一帧的播放时间 = 1152* 1000000/44100= 26.122ms(单位为ms)

(5)声道
当人听到声音时,能对声源进行定位,那么通过在不同的位置设置声源,就可以造就出更好的听觉感受,如果配合影像进行音频位置的调整,则会得到更好的视听效果。常见的声道有:

单声道,mono
双声道,stereo,最常见的类型,包含左声道以及右声道
2.1声道,在双声道基础上加入一个低音声道
5.1声道,包含一个正面声道、左前方声道、右前方声道、左环绕声道、右环绕声道、一个低音声道,最早应用于早期的电影院
7.1声道,在5.1声道的基础上,把左右的环绕声道拆分为左右环绕声道以及左右后置声道,主要应用于BD以及现代的电影院
如下是一个双声道的音频系统

一般情况下大家使用的音箱或耳机都是“立体声(Stereo)”的,即只有左右两个声道;而家庭影院的“环绕声(Surround)”则一般至少有四个声道。声道数通常用类似“X.Y”的数字表示,常见的声道配置有4.0,5.1,7.1等。一般家用可以简单地理解为:小数点前的数字表示全音域声道数,也就是普通音箱的数量;小数点后的数字表示低频声道数,也就是低音炮(Subwoofer)的数量

(6)采样率
音频采样,是把声音从模拟信号转换为数字信号。采样率,就是每秒对声音进行采集的次数,同样也是所得的数字信号的每秒样本数。正常人听觉的频率范围大约在20Hz~20kHz之间。根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。

常用的音频采样频率有8kHz(电话)、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz(CD)、48kHz(视频音轨)、96k/192k(Hi-Res)等。

出于历史原因,所有CD一律采用44.1KHz,而DVD/BD视频音轨一律采用48KHz。所以不出意外,你听到的那些音乐都是44.1KHz,而你看的视频,它们的音频一般都采用48KHz的采样率。

如下图所示,原则上更高的采样率更为精准,但是一般认为44.1KHz就接近人耳极限了。

为什么常见的WAV比特率是1141KBit/s了:44.1KHz * 32bit =1141.2
题外话:非整数倍SRC(Sample Rate Convert,采样率转换)带来的毁灭性后果。

既然原则上采样率越高越好,是不是意味着我们可以随便改变采样率呢?答案是否定的:

从图中可以看出,原始波形分4段5个采样点(包括首尾),如果整数倍转换,采用了8个分段9个采样点(采样率翻倍),波形是没有改变的。但是,如果新的采样率是原来的1.5倍,采用6个分段7个采样点,新的波形就会和原波形相差很远,造成很大的误差,换言之,这是一个有损转换过程。同样,44.1KHz和48KHz之间的转换也是属于非整数倍转换,会带来可观的音质损失。

android系统之所以不适合多媒体,是因为android系统会把所有非44.1KHz的音频强制转换成44.1KHz再输出。但是这问题也不大——你听到的多数音乐文件都是用44.1KHz,无非是多数视频文件的音频被改变了——谁管呢。

但是android一旦碰上高通,毁灭性的就来了:高通的CPU,会把44.1KHz的先转换成48KHz(一次有损),然后android系统再把48KHz转换成44.1KHz。这是最悲惨的过程。注意,这两次转换不是说效果相互抵消,而是相互叠加——你看看上图最后一个折线图,你采用原始的采样率看看,波形变化有多恐怖。

开发基础

js

  var noticeAudio = "pub/audios/notice.mp3";
  var audio = new Audio(noticeAudio);
  audio .play(); //播放
    对象方法:
    play() 播放歌曲
    pause() 暂停歌曲
    load()重新加载歌曲

标签

  方式一:
  <div class="wrap">
      <audio autoplay="autoplay" src="http://sd.freeisland.net/o_1c4efkd3u9dkfjltv814v6i4a9.mp3"></audio>
  </div>
  方式二:
  <audio autoplay controls loop>
  <source src="music/1.mp3" type='audio/ogg'>
  <source src="music/1.mp3" type='audio/mpeg'>   
  </audio>

  对象属性:
    currentTime 获取当前播放时间
    duration 获取歌曲的总时间
    play 是否在播放 返回true/false
    pause 是否暂停 返回true/false

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Java中,泛型是一种强类型机制,它可以让你在编译时检查类型错误,从而提高代码的安全性和可读性。在使用泛型时,我们经常会遇到父类和子类的泛型转换问题。 首先,我们需要明确一点:子类泛型不能转换成父类泛型。这是因为Java中的泛型是不协变的。例如,如果有一个类A和它的子类B,那么List<A>和List<B>之间是不存在继承关系的。 下面我们来看一个例子: ```java public class Animal { //... } public class Dog extends Animal { //... } public class Test { public static void main(String[] args) { List<Animal> list1 = new ArrayList<>(); List<Dog> list2 = new ArrayList<>(); list1 = list2; // 编译错误 } } ``` 在这个例子中,我们定义了Animal类和它的子类Dog。然后我们定义了两个List,分别是List<Animal>和List<Dog>。如果将List<Dog>赋值给List<Animal>,会出现编译错误。这是因为List<Animal>和List<Dog>之间不存在继承关系。 那么,如果我们想要让子类泛型转换成父类泛型,应该怎么办呢?这时我们可以使用通配符来解决问题。通配符可以表示任意类型,包括父类和子类。例如,我们可以将List<Dog>赋值给List<? extends Animal>,这样就可以实现子类泛型转换成父类泛型了。 下面我们来看一个使用通配符的例子: ```java public class Animal { //... } public class Dog extends Animal { //... } public class Test { public static void main(String[] args) { List<Animal> list1 = new ArrayList<>(); List<Dog> list2 = new ArrayList<>(); list1 = list2; // 编译错误 List<? extends Animal> list3 = new ArrayList<>(); list3 = list2; // 正确 } } ``` 在这个例子中,我们定义了List<? extends Animal>来表示任意继承自Animal的类型。然后我们将List<Dog>赋值给List<? extends Animal>,这样就可以实现子类泛型转换成父类泛型了。 总结一下,Java中的泛型是不协变的,子类泛型不能转换成父类泛型。如果需要实现子类泛型转换成父类泛型,可以使用通配符来解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BMG-Princess

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值