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音频编辑的步骤如下:
- 导入
@ohos.multimedia.audio模块。 - 创建
AudioCapturer实例,通过createAudioCapturer方法并配置AudioCapturerOptions参数,设置采样率、声道数、采样格式(如audio.AudioSampleFormat.SAMPLE_FORMAT_F32LE)等。 - 调用
start方法开始捕获音频原始数据。 - 在捕获过程中,通过
read方法读取PCM数据到ArrayBuffer。 - 对读取到的PCM数据直接进行编辑处理(如增益、剪切、混音等)。
- 处理完成后,调用
stop和release方法停止捕获并释放资源。
编辑操作直接在内存中的二进制PCM数据上进行。
在HarmonyOS NEXT中,使用AudioCapturer结合AudioStream和AudioRenderer可以实现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,其中包含音频采集、播放及基础处理的完整实现。

