You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:57:24