HarmonyOS鸿蒙NEXT应用开发中怎么使用AudioCapturer实现PCM音频编辑?

HarmonyOS鸿蒙NEXT应用开发中怎么使用AudioCapturer实现PCM音频编辑? 音频录制时,需对某个时间段音频进行覆盖或裁剪操作,且需要实时绘制音频波形。有示例demo吗?

3 回复

参考文档:PCM音频编辑

更多关于HarmonyOS鸿蒙NEXT应用开发中怎么使用AudioCapturer实现PCM音频编辑?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS NEXT中,使用AudioCapturer进行PCM音频编辑的步骤如下:

  1. 导入@ohos.multimedia.audio模块。
  2. 创建AudioCapturer实例,通过createAudioCapturer方法并配置AudioCapturerOptions参数,设置采样率、声道数、采样格式(如audio.AudioSampleFormat.SAMPLE_FORMAT_F32LE)等。
  3. 调用start方法开始捕获音频原始数据。
  4. 在捕获过程中,通过read方法读取PCM数据到ArrayBuffer
  5. 对读取到的PCM数据直接进行编辑处理(如增益、剪切、混音等)。
  6. 处理完成后,调用stoprelease方法停止捕获并释放资源。

编辑操作直接在内存中的二进制PCM数据上进行。

在HarmonyOS NEXT中,使用AudioCapturer结合AudioStreamAudioRenderer可以实现PCM音频的实时录制、编辑与波形绘制。以下是一个核心实现思路和关键代码片段:

1. 音频录制与PCM数据获取

首先创建AudioCapturer实例,配置音频参数(采样率、声道、采样格式),并开始录制以获取原始PCM数据流:

import audio from '@ohos.multimedia.audio';

// 配置音频参数
let audioCapturerInfo: audio.AudioCapturerInfo = {
  source: audio.SourceType.SOURCE_TYPE_MIC,
  capturerFlags: 0
};
let audioCapturerOptions: audio.AudioCapturerOptions = {
  streamInfo: {
    samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_44100,
    channels: audio.AudioChannel.CHANNEL_1,
    sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
    encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
  },
  capturerInfo: audioCapturerInfo
};

// 创建AudioCapturer实例
let audioCapturer: audio.AudioCapturer = await audio.createAudioCapturer(audioCapturerOptions);
await audioCapturer.start();

// 循环读取PCM数据
let bufferSize = await audioCapturer.getBufferSize();
let audioBuffer = await audioCapturer.read(bufferSize, true);

2. PCM数据编辑(覆盖/裁剪)

  • 裁剪操作:通过ArrayBuffer.slice()截取特定时间段的PCM数据:
// 计算裁剪时间范围对应的字节位置(示例:裁剪第2-5秒)
let startOffset = 2 * 44100 * 2; // 时间(秒) * 采样率 * 每样本字节数(S16LE为2字节)
let endOffset = 5 * 44100 * 2;
let clippedBuffer = audioBuffer.buffer.slice(startOffset, endOffset);
  • 覆盖操作:将新音频数据写入目标位置:
// 将新PCM数据覆盖到原缓冲区的指定位置
let newAudioData = await getNewAudioData(); // 获取新音频数据
let targetOffset = 3 * 44100 * 2; // 从第3秒开始覆盖
audioBuffer.buffer.set(newAudioData, targetOffset);

3. 实时波形绘制

将PCM数据转换为振幅值,使用Canvas组件绘制波形:

// 提取振幅数据(S16LE格式为例)
let dataView = new DataView(audioBuffer.buffer);
let amplitudes = [];
for (let i = 0; i < dataView.byteLength; i += 2) {
  let amplitude = dataView.getInt16(i, true);
  amplitudes.push(amplitude / 32768); // 归一化到[-1, 1]
}

// Canvas绘制波形(示例片段)
@Entry
@Component
struct WaveformComponent {
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);

  build() {
    Canvas(this.context)
      .onReady(() => {
        this.drawWaveform(amplitudes);
      })
  }

  drawWaveform(amplitudes: number[]) {
    let canvasWidth = 300;
    let canvasHeight = 150;
    let step = canvasWidth / amplitudes.length;

    this.context.beginPath();
    for (let i = 0; i < amplitudes.length; i++) {
      let x = i * step;
      let y = canvasHeight / 2 * (1 - amplitudes[i]);
      i === 0 ? this.context.moveTo(x, y) : this.context.lineTo(x, y);
    }
    this.context.stroke();
  }
}

4. 关键注意事项

  • 时间精度:编辑时需根据采样率精确计算字节偏移量。
  • 数据格式:确保所有操作符合PCM格式(如S16LE为有符号16位小端序)。
  • 性能优化:实时绘制时可对振幅数据降采样(如每100个采样取一个点)以减少渲染压力。
  • 线程管理:音频数据读取建议在Worker线程进行,避免阻塞UI渲染。

完整示例可参考HarmonyOS官方示例仓库中的AudioDemo,其中包含音频采集、播放及基础处理的完整实现。

回到顶部