如何使用WaveSurfer-JS与ReactJS保留音频选中区域并删除未选部分
React + WaveSurfer-JS 实现音频选区裁剪保留功能方案
核心需求说明
- 基于ReactJS搭建带音频编辑能力的Web项目,使用WaveSurfer-JS渲染音频轨道
- 已集成Regions插件支持用户在轨道上框选特定音频区间
- 需要实现两个核心裁剪能力:
- 点击按钮后删除选中区域外的所有音频内容,仅保留选中片段在轨道中展示
- 支持将选中片段的原始音频数据存入变量,供后续流程调用
- 交互参考:轨道上黑色区块为用户选中范围,标注「je veux cette partie」的按钮为保留选中片段的触发控件
实现思路
1. 实例初始化与选区监听
首先在React组件的useEffect钩子中完成WaveSurfer实例与Regions插件的初始化,监听选区更新事件,实时保存当前选中区间的起止时间:
import { useEffect, useRef, useState } from 'react'; import WaveSurfer from 'wavesurfer.js'; import RegionsPlugin from 'wavesurfer.js/dist/plugin/wavesurfer.regions.min.js'; const AudioEditor = () => { const wavesurferRef = useRef(null); const [selectedRegion, setSelectedRegion] = useState(null); useEffect(() => { const wavesurfer = WaveSurfer.create({ container: wavesurferRef.current, waveColor: '#A8DBA8', progressColor: '#3B8686', plugins: [ RegionsPlugin.create({ dragSelection: true // 开启拖拽框选能力 }) ] }); wavesurferRef.current = wavesurfer; // 监听选区创建,保证页面仅保留一个有效选中区间 wavesurfer.on('region-created', (region) => { Object.values(wavesurfer.regions.list).forEach(r => { if (r.id !== region.id) r.remove(); }); setSelectedRegion({ start: region.start, end: region.end }); }); // 加载目标音频文件 wavesurfer.load('target-audio.mp3'); return () => wavesurfer.destroy(); }, []);
2. 核心音频裁剪逻辑
裁剪逻辑基于Web Audio API原生AudioBuffer实现,无需引入额外音频处理库:
- 从WaveSurfer实例中获取当前加载的完整解码后音频数据
- 根据选中区间的起止时间,换算对应采样点的偏移位置
- 创建新的空白音频缓冲区,将选中区间的采样数据逐声道拷贝到新缓冲区中
AudioBuffer就是前端存储解码后音频数据的标准格式,可直接存入变量供后续上传、二次编辑等流程使用- 如果需要在轨道上预览裁剪结果,直接调用WaveSurfer的
loadDecodedBuffer方法加载新生成的切片缓冲区即可
const handleKeepSelectedRegion = () => { if (!selectedRegion || !wavesurferRef.current) return; const wavesurfer = wavesurferRef.current; const { start, end } = selectedRegion; const originalBuffer = wavesurfer.backend.buffer; const sampleRate = originalBuffer.sampleRate; const channelCount = originalBuffer.numberOfChannels; // 计算切片对应的采样点范围 const startOffset = Math.floor(start * sampleRate); const endOffset = Math.floor(end * sampleRate); const clipLength = endOffset - startOffset; // 创建存放裁剪结果的空白音频缓冲区 const clippedBuffer = new AudioBuffer({ length: clipLength, numberOfChannels: channelCount, sampleRate: sampleRate }); // 逐声道拷贝选中区间的采样数据 for (let channel = 0; channel < channelCount; channel++) { const originalData = originalBuffer.getChannelData(channel); const clippedData = clippedBuffer.getChannelData(channel); for (let i = 0; i < clipLength; i++) { clippedData[i] = originalData[startOffset + i]; } } // 场景1:替换当前轨道音频,实现裁剪后预览 wavesurfer.loadDecodedBuffer(clippedBuffer); // 场景2:将裁剪后的音频存入变量供后续使用 // const savedAudioClip = clippedBuffer; };
如果需要实现「删除选中区域、保留其余音频」的反向裁剪,只需要调整采样数据拷贝逻辑:分别拷贝选区前、选区后的两段采样数据,拼接生成新的AudioBuffer加载即可。
3. 交互绑定
将裁剪处理函数绑定到对应按钮的点击事件即可完成功能:
return ( <div className="audio-editor"> <div ref={wavesurferRef}></div> <button onClick={handleKeepSelectedRegion}> je veux cette partie </button> </div> ) } export default AudioEditor;
内容的提问来源于stack exchange,提问作者Camille Rakoto
相关产品推荐
相关产品推荐

