关于pcm:多媒体开发5音频特征声音可以调大一点吗

基本上,当初罕用的声音采样方法是pcm,而对于压缩音频的解码,失去的也pcm数据。这个pcm数据,只是一堆数值,有正有负,看这个值看不出什么花色。 声音采集,采的是什么呢? 采的是声音的强度变动,也是声音这种能量的强弱变动,这种强弱用分贝来示意,即dB。所以,pcm数据跟这个dB就肯定有关系,这个关系是这样的: dB=20∗log10(pcm)pcm=pow(10,(dB/20.0))模数转换ADC时罕用的位深是16bit,也就是用16位来示意一个sample,这里不思考偷懒而应用有余16位的状况。16位能示意65536个值,也就意味着有65536个dB能够示意进去,哪又怎么样?很厉害了吗? 确实是比拟厉害的了。 16位的pcm数值,分正负,那负数的范畴是0至32767,正数的范畴是-1至-32768,轻易挑几个来看看,对应的dB是多少,如下图: 由下面的运算可知,16位的pcm值,如果不分正负,最大能够示意96dB,如果分正负,也能示意到90dB。90dB是什么概念?有数据表明(我也不分明什么数据),85dB就会挫伤了你,90dB相当于摩托车启动的声音--你有开过吗? 所以,你的pcm数据须要去到90dB以上吗?想祸患谁?个别状况下,能示意到90dB就很够用了。 既然晓得了pcm数值与dB的关系,就能够搞点事件了,比方把pcm转成dB后再放大一点,再保留成新的文件,是不是播放就能够大声一点了呢? 来做个试验。 import mathimport mathimport waveimport audioreadimport contextlibimport sysimport mathimport structdef gainpcm(filepath): try: with audioread.audio_open(filepath) as f: with contextlib.closing(wave.open(filepath+'.wav', 'w')) as of: of.setnchannels(f.channels) of.setframerate(f.samplerate) of.setsampwidth(2) for buf in f: for i in range(0, len(buf)-2, 2): s = buf[i] + buf[i+1] pcm = struct.unpack('<h', s)[0] apcm = abs(pcm) if apcm==0: apcm=1 db = 20*math.log10(apcm) db = db * 1.2 apcm=int(math.pow(10, float(db)/20.0)) if apcm>32767: apcm=32767 if pcm < 0: pcm=-apcm else: pcm = apcm tbuf = struct.pack('<h', pcm) of.writeframes(tbuf) except audioread.DecodeError: print("File could not be decoded.") sys.exit(1)if __name__ == '__main__': gainpcm('test.mp3')这里是对代码的简略解释: ...

January 12, 2021 · 1 min · jiezi

纯js实现web端录音与播放功能

纯js实现web端录音功能,功能并不是特别多,逐步增加中,详细地址:github。getUserMedia在非localhost和127的情况下,需要开启https,由于腾讯云的没备案,demo就不放了,可以自行获取代码并启动测试。实现方式实现原理的话,主要是以下三点,利用webrtc的getUserMedia方法获取设备音频输入,使用audioprocess得到音频流(pcm流,范围-1到1)。转码,利用前端中的ArrayBuffer等二进制操作按采样位数处理流信息。使用decodeAudioData转码arraybuffer到audioBuffer并播放(小文件,大文件使用audio)。使用方式script方式直接引入dist下的recorder.js即可let recorder = new Recorder();npm方式安装:npm i js-audio-recorder调用:import Recorder from ‘js-audio-recorder’;let recorder = new Recorder();API基本方法// 开始录音recorder.start();// 暂停录音recorder.pause();// 继续录音recorder.resume()// 结束录音recorder.stop();// 录音播放recorder.play();// 销毁录音实例,释放资源,fn为回调函数,recorder.destroy(fn);recorder = null;下载功能// 下载pcm文件recorder.downloadPCM();// 下载wav文件recorder.downloadWAV();// 重命名pcm文件,wav也支持recorder.downloadPCM(‘重命名’);获取录音时长// 回调持续输出时长recorder.onprocess = function(duration) { console.log(duration);}// 手动获取录音时长console.log(recorder.duration);默认配置sampleBits,采样位数,默认是16 sampleRate,采样频率,浏览器默认的,我的chrome是48000 numChannels,声道数,默认是1传入参数new Recorder时支持传入参数,{ sampleBits: 16, // 采样位数,范围8或16 sampleRate: 16000, // 采样率,范围11025、16000、22050、24000、44100、48000 numChannels: 1, // 声道,范围1或2}注意使用127.0.0.1或localhost尝试,因为getUserMedia在高版本的chrome下需要使用https。兼容性主要是以下几个方面:Web Audio Apihttps://caniuse.com/#search=w…getUserMediahttps://caniuse.com/#search=g…Typed Arrayshttps://caniuse.com/#search=t…欢迎访问和查看:recorder。其他资源基于阿里云实现简单的语音识别功能web Audio学习与音频播放web Audio实现pcm音频数据收集js实现pcm数据编码js转化pcm到wav格式与播放

April 17, 2019 · 1 min · jiezi

如何在浏览器中播放pcm音频

本文记录一点工作经历,探讨音频文件的格式更多访问我的博客前言最近在整理音视频编程的知识,回忆起半年多,有一次需求是在后台播放某来源的 pcm 文件,当时处理方法用了点技巧,记录下来背景:业务需求,在web后台里播放 pcm 文件,文件不大(约300KB,已知 pcm 的参数采样率16000,采样位数16,声道数1如何播放浏览器是无法直接播放 pcm 音频的,因为 pcm 是比较原始的音频格式:PCM(Puls Code Modulation)全称脉码调制录音,PCM录音就是将声音的模拟信号表示成0,1标识的数字信号,未经任何编码和压缩处理,所以可以认为PCM是未经压缩的音频原始格式。PCM格式文件中不包含头部信息,播放器无法知道采样率,声道数,采样位数,音频数据大小等信息,导致无法播放。如何让浏览器识别 pcm浏览器可以播放另一种音频格式:WAV格式全称为WAVE,前面提到只需要在PCM文件的前面添加WAV文件头,就可以生成WAV格式文件所以我的解决方法是给 pcm 添加 wav header,接下来就是 browser javascript 的实践编码了javascript 如何处理文件流js 在处理文件流、网络数据,常用到 ArrayBuffer 类型,关于 ArrayBuffer 类型的API调用方法,需要事先多了解。第一步,ajax异步获取网络 pcm 文件的 ArrayBufferconst getWebFileArrayBuffer = async (url) => { return await fetch(url).then(response => response.arrayBuffer())}第二步,对获取的 pcm 文件流 ArrayBuffer 添加 wav header,下面以代码注释为大家解释const getWebPcm2WavArrayBuffer = async (url) => { const bytes = await getWebFileArrayBuffer(url) return addWavHeader(bytes, 16000, 16, 1) // 这里是当前业务需求,特定的参数,采样率16000,采样位数16,声道数1}const addWavHeader = function (samples, sampleRateTmp, sampleBits, channelCount) { let dataLength = samples.byteLength let buffer = new ArrayBuffer(44 + dataLength) let view = new DataView(buffer) function writeString (view, offset, string) { for (let i = 0; i < string.length; i++) { view.setUint8(offset + i, string.charCodeAt(i)) } } let offset = 0 /* 资源交换文件标识符 / writeString(view, offset, ‘RIFF’); offset += 4 / 下个地址开始到文件尾总字节数,即文件大小-8 / view.setUint32(offset, / 32 / 36 + dataLength, true); offset += 4 / WAV文件标志 / writeString(view, offset, ‘WAVE’); offset += 4 / 波形格式标志 / writeString(view, offset, ‘fmt ‘); offset += 4 / 过滤字节,一般为 0x10 = 16 / view.setUint32(offset, 16, true); offset += 4 / 格式类别 (PCM形式采样数据) / view.setUint16(offset, 1, true); offset += 2 / 通道数 / view.setUint16(offset, channelCount, true); offset += 2 / 采样率,每秒样本数,表示每个通道的播放速度 / view.setUint32(offset, sampleRateTmp, true); offset += 4 / 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 / view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset += 4 / 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 / view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2 / 每样本数据位数 / view.setUint16(offset, sampleBits, true); offset += 2 / 数据标识符 / writeString(view, offset, ‘data’); offset += 4 / 采样数据总数,即数据总大小-44 */ view.setUint32(offset, dataLength, true); offset += 4 function floatTo32BitPCM (output, offset, input) { input = new Int32Array(input) for (let i = 0; i < input.length; i++, offset += 4) { output.setInt32(offset, input[i], true) } } function floatTo16BitPCM (output, offset, input) { input = new Int16Array(input) for (let i = 0; i < input.length; i++, offset += 2) { output.setInt16(offset, input[i], true) } } function floatTo8BitPCM (output, offset, input) { input = new Int8Array(input) for (let i = 0; i < input.length; i++, offset++) { output.setInt8(offset, input[i], true) } } if (sampleBits == 16) { floatTo16BitPCM(view, 44, samples) } else if (sampleBits == 8) { floatTo8BitPCM(view, 44, samples) } else { floatTo32BitPCM(view, 44, samples) } return view.buffer}第三步,在浏览器播放 pcm 转出的 wav 的文件流 ArrayBuffer先转成 base64 格式const getWebPcm2WavBase64 = async (url) => { let bytes = await getWebPcm2WavArrayBuffer(url) return data:audio/wav;base64,${btoa(new Uint8Array(bytes).reduce((data, byte) =&gt; { return data + String.fromCharCode(byte) }, ''))}}将 base64 字符串放入<audio>组件中,这里以 react/ant design 的组件为例,封装一个方法const playWebPcm = async (url) => { try { let pcmBase64 = await fileServer.getWebPcm2WavBase64(url) Modal.info({ title: ‘播放音频’, content: ( <audio controls src={pcmBase64} type=“audio/wav” autoPlay /> ), onOk () {}, okText: ‘关闭’, }) } catch (err) { console.error(err) message.error(‘预载音频文件失败’) }}Reference音频格式简介和PCM转换成WAV,Java版本 ...

January 22, 2019 · 3 min · jiezi