HarmonyOS音频渲染引擎开发实战——从零实现多波形音频生成器

HarmonyOS音频渲染引擎开发实战——从零实现多波形音频生成器

技术栈:HarmonyOS 5.0 + ArkTS + @ohos.multimedia.audio

适用场景:听力测试、手机排水、冥想助手、白噪音等音频类应用


前言

在开发听力测试、手机排水、冥想助手等音频类应用时,核心需求是生成不同频率和波形的音频信号。本文将详细介绍如何使用HarmonyOS的@ohos.multimedia.audio模块实现一个功能完整的音频引擎。

一、需求分析

我们的音频引擎需要支持:

  • 多种波形:正弦波、方波、三角波、锯齿波
  • 多种音频类型:纯音、白噪音、粉红噪音、扫频
  • 实时控制:频率、音量、播放时长
  • 震动联动:配合设备震动增强效果

二、核心原理

2.1 数字音频基础

数字音频通过采样将模拟信号转换为离散数据:

  • 采样率:每秒采样次数,48000Hz表示每秒48000个采样点
  • 位深度:每个采样点的精度,16位可表示-32768~32767
  • 相位:波形在一个周期内的位置

2.2 波形生成公式

正弦波:sample = sin(phase)
方波:sample = sin(phase) >= 0 ? 1 : -1
三角波:sample = 4 * |t - 0.5| - 1,其中t = phase / 2π
锯齿波:sample = 2 * (phase / 2π) - 1

三、代码实现

3.1 音频引擎单例类

import audio from '@ohos.multimedia.audio';
import { BusinessError } from '@ohos.base';

export class AudioEngine {
  private audioRenderer: audio.AudioRenderer | null = null;
  private isPlaying: boolean = false;
  private currentFrequency: number = 440;
  private currentVolume: number = 0.8;
  private waveformType: 'sine' | 'square' | 'triangle' | 'sawtooth' = 'sine';
  private sampleRate: number = 48000;
  private static instance: AudioEngine | null = null;

  private constructor() {}

  static getInstance(): AudioEngine {
    if (!AudioEngine.instance) {
      AudioEngine.instance = new AudioEngine();
    }
    return AudioEngine.instance;
  }

  async init(): Promise<void> {
    const audioRendererOptions: audio.AudioRendererOptions = {
      streamInfo: {
        samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
        channels: audio.AudioChannel.CHANNEL_1,
        sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
        encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
      },
      rendererInfo: {
        content: audio.ContentType.CONTENT_TYPE_MUSIC,
        usage: audio.StreamUsage.STREAM_USAGE_MEDIA,
        rendererFlags: 0
      }
    };

    try {
      this.audioRenderer = await audio.createAudioRenderer(audioRendererOptions);
      console.info('AudioEngine: 初始化成功');
    } catch (err) {
      const error = err as BusinessError;
      throw new Error(`初始化失败: ${error.message}`);
    }
  }
}

3.2 波形生成实现

private generateToneSample(phase: number): number {
  let sample: number;
  switch (this.waveformType) {
    case 'sine':
      sample = Math.sin(phase);
      break;
    case 'square':
      sample = Math.sin(phase) >= 0 ? 1 : -1;
      break;
    case 'triangle':
      const t = (phase / (2 * Math.PI)) % 1;
      sample = 4 * Math.abs(t - 0.5) - 1;
      break;
    case 'sawtooth':
      const s = (phase / (2 * Math.PI)) % 1;
      sample = 2 * s - 1;
      break;
    default:
      sample = Math.sin(phase);
  }
  return sample * this.currentVolume;
}

3.3 噪音生成(白噪音/粉红噪音/棕色噪音)

private generateNoiseSample(pinkState: number[], brownState: number): NoiseResult {
  let sample: number;
  const white = Math.random() * 2 - 1;

  switch (this.noiseType) {
    case 'white':
      sample = white;
      break;
    case 'pink':
      // Paul Kellet's refined method
      pinkState[0] = 0.99886 * pinkState[0] + white * 0.0555179;
      pinkState[1] = 0.99332 * pinkState[1] + white * 0.0750759;
      pinkState[2] = 0.96900 * pinkState[2] + white * 0.1538520;
      sample = (pinkState[0] + pinkState[1] + pinkState[2] + white * 0.5362) * 0.11;
      break;
    case 'brown':
      brownState = (brownState + (0.02 * white)) / 1.02;
      sample = brownState * 3.5;
      break;
    default:
      sample = white;
  }
  return { sample: sample * this.currentVolume, pinkState, brownState };
}

3.4 音频数据写入循环

private async writeAudioData(): Promise<void> {
  const bufferSize = this.sampleRate;
  let phase = 0;

  while (this.isPlaying && this.audioRenderer) {
    const buffer = new ArrayBuffer(bufferSize * 2);
    const dataView = new DataView(buffer);

    for (let i = 0; i < bufferSize; i++) {
      const sample = this.generateToneSample(phase);
      phase += (2 * Math.PI * this.currentFrequency) / this.sampleRate;
      if (phase > 2 * Math.PI) phase -= 2 * Math.PI;
      
      const intSample = Math.max(-32768, Math.min(32767, Math.floor(sample * 32767)));
      dataView.setInt16(i * 2, intSample, true);
    }

    await this.audioRenderer.write(buffer);
  }
}

四、实际应用场景

应用场景 音频类型 频率范围 波形
手机排水 tone 165Hz 正弦波
听力测试 tone 125-8000Hz 正弦波
冥想助手 noise - 粉红噪音
专注模式 noise - 白/粉红/棕色噪音

五、避坑指南

  1. 采样率选择:推荐48000Hz,兼容性最好
  2. 相位溢出:相位累加超过2π时要减去2π,避免数值溢出
  3. 资源释放:页面销毁时务必调用release()释放音频资源
  4. 音量限制:音量值限制在0-1之间,避免爆音

总结

本文实现了一个功能完整的HarmonyOS音频引擎,支持多种波形和噪音类型生成。该引擎已在实际项目中应用于手机排水、听力测试、冥想助手等多个功能模块。


相关文章

  • HarmonyOS分贝检测器开发
  • HarmonyOS数据持久化最佳实践
  • HarmonyOS深色模式适配实战
posted @ 2025-12-18 11:03  柠果丶  阅读(3)  评论(0)    收藏  举报