js实现音频PCM数据合并、拼接、裁剪、调节音量等功能

关于音频的内容,我边学习,边实践也总结了一些,从最开始实现一个简单的web音乐播放器的自定义工具栏,到后来的实现简单的音频频谱图.直到今天的对音频数据进行的进一步操作,我也是一点点的在进步.虽然很多地方,并不是那么完美和准确,但是希望能和大家能共同学习进步.

一、准备工作

声音的基本原理

首先关于音频的一些原理性的内容,在之前的https://blog.csdn.net/yun_master/article/details/104133520关于音频频谱的博客中已经简单介绍过了,这里就不详细展开来说了

前端操作内存的方法

但是如果要实现对音频PCM数据的修改,只是了解了声音的原理,恐怕还是有点不太够用.
这里还需要了解es6中提供的arrayBuffer以及其视图的相关内容,这里推荐阮一峰老师的es6入门这本书的关于arrayBuffer这个章节,进行简单的了解

web audio API

这方面的内容,也是很重要的一部分内容、但是由于web Audio API实在太多了,往往在用的时候再去看,已然是来不及了.那个时候往往是一头雾水,面对海量API无从下手,不知道从哪里入手.所以推荐利用空闲时间、从最基础的api看起.慢慢会发现,真正常用的功能所需要的,并不是特别多.
推荐MDN关于这一部分的介绍:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API

二、音频处理

如果想要快速实现一些针对音频PCM数据的处理工作,推荐使用crunker这个方法库,虽然功能有限,但是对于获取音频二进制数据、合并、拼接等工作,安装方便、使用简单.重要的是性能真的不错.
npm地址:https://www.npmjs.com/package/crunker

音频裁剪

原理:音频裁剪,其实就是对音频数据的裁剪,并拷贝出来,创建一份新的音频数据.这就是音频的裁剪.

//获取audioBuffer数据的方式之一
fetch(audioUrl)
	.then(res => res.arrayBuffer())
	.then(buffer => {  // 获取音频二进制数据
		const audioCtx = new audioContext();
		audioCtx.decodeAudio(buffer)
			.then(audioBuffer => {  // 获取音频解码后的audioBuffer数据
				// to do sth
			})
	});

/**
* 音频裁剪
* @param audioBuffer 待裁剪的数据
* @param duration 音频总时长
* @param startOffset 裁剪偏移时间,单位s
*/
clipAudio(audioBuffer,duration,startOffset = 0){
	return new Promise((resolve,reject) => {
		// 获取音频通道数量
		const channels = audioBuffer,.numberOfChannels;
		// 获取采样率
		const rate = audioBuffer,.sampleRate;
		
		// 计算截取后需要的采样数量
		const endOffset = rate * duration;
		const frameCount = endOffset - 0;
		
		// 创建新的audioBuffer数据
		const newAudioBuffer = new AudioContext().createBuffer(channels,frameCount,rate);
		
		// 创建Float32的空间,作为copy数据的载体
		const anotherArray = new Float32Array(frameCount);
		
		// 裁剪后放置的起始位置
		const offset = 0;
		
		// 遍历通道,将每个通道的数据分别copy到对应的newAudioBuffer的通道
		for(let channel = 0; channel < channels;channel++){
			audioBuffer.copyFromChannel(anotherArray, channel, rate * startOffset);
			newAudioBuffer.copyToChannel(anotherArray, channel, offset);
		}
		// 完成裁剪
		resolve(newAudioBuffer);
	})
	
}

音频音量调整

fetch(url)
.then(res => res.arrayBuffer)
.then(buffer => {
	const audioCtx = new AudioContext();
	audioCtx.decodeAudioData(buffer)
	.then(audioBuffer => {
		//获取声道数量
		const channels = audioBuffer.numberOfChannels;
		// 更改每个通道内的数据
		for(let channel = 0; channel < channels; channel++){
			const channelData = audioBuffer.getChannelData(channel);
			for(let j = 0; j < channelData.length; j++){
				channelData[j] = channelData[j] * volumn; // volunm [0,1]
			}
		}
	})
})

除了音频裁剪之外的功能,可以利用Crunker这个第三方的库来实现.具体实现方式,可以参考crunker源码

安装

npm i crunker -S

Example

let audio = new Crunker();

audio.fetchAudio("/audio/url/1.m\p3","/audio/url/2.mp3")
.then(buffers => {
	// => [AudioBuffer,AudioBuffer]
	audio.mergeAudio(buffers); // 将两个音频进行合成(非拼接)
})
.then(merged => {
	// => AudioBuffer
	audio.export(merged,"audio/mp3");
})
.then(output => {
	// => {blob,element,url}
	audio.download(output.blob);
	document.addpend(output.element);
	console.log(output.url);
})
.then(error => {
	// => Error Message
})

audio.notSupported(() => {
	// Handle no brower support
})

API

crunker.fetchAudio(soneURL,anotherSongURL)

获取音频buffer数据

const crunker = new Crunker();

crunker.fetchAudio(url1,url2,url3,...)
.then(buffers => {
	// 获取到全部音频的buffer数据,buffers为数组
})

crunker.mergeAudio(arrayOfBuffers)

合成音频为一个buffer

const resultBuffer = crunker.mergeAudio([buffer1,buffer2,buffer3,...]);

crunker.concatAudio(arrayOfBuffers);

拼接音频为一个buffer

const resultBuffer = crunker.concatAudio([buffer1,buffer2,buffer3,...]);

crunker.export(buffer,type)

导出blob和url对象
type为可选参数:‘audio/mp3’, ‘audio/wav’, ‘audio/ogg’

const blob = crunker.export(audioBuffers, "audio/mp3");

crunker.download(blob,fileName)

自动下载

crunker.play(blob)

开始播放

audio.notSupported(callback)

如果用户浏览器不支持Web audio API ,自行定义代码.

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要基于FFTW库实现C语言分析音频PCM数据的频率大小,可以按照以下步骤进行: 1. 首先,确保已经安装了FFTW库。你可以从FFTW的官方网站(http://www.fftw.org/)下载并安装库文件。 2. 在你的C程序中包含FFTW库的头文件: ```c #include <fftw3.h> ``` 3. 定义需要用到的变量,例如音频数据的长度、采样率等: ```c int audioLength = ...; // 音频数据的长度 int sampleRate = ...; // 音频数据的采样率 ``` 4. 创建输入和输出数组,用于存储音频数据和频率大小的结果: ```c fftw_complex *input = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * audioLength); fftw_complex *output = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * audioLength); ``` 5. 创建FFTW计划: ```c fftw_plan plan = fftw_plan_dft_1d(audioLength, input, output, FFTW_FORWARD, FFTW_ESTIMATE); ``` 6. 将音频数据填充到输入数组中: ```c for (int i = 0; i < audioLength; i++) { input[i][0] = audioData[i]; // 实部 input[i][1] = 0; // 虚部(置为0) } ``` 7. 执行FFT变换: ```c fftw_execute(plan); ``` 8. 计算频率大小: ```c for (int i = 0; i < audioLength; i++) { double frequency = (double)i * sampleRate / audioLength; // 计算频率 double magnitude = sqrt(output[i][0] * output[i][0] + output[i][1] * output[i][1]); // 计算幅度 // 在这里可以根据需要对频率大小进行处理或输出 } ``` 9. 清理内存并销毁FFTW计划: ```c fftw_destroy_plan(plan); fftw_free(input); fftw_free(output); ``` 以上是一个基本的框架,你可以根据具体的需求进行进一步的处理和优化。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值