> **技术栈**: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 音频引擎单例类

```typescript

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 波形生成实现

```typescript

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 噪音生成(白噪音/粉红噪音/棕色噪音)

```typescript

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 音频数据写入循环

```typescript

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深色模式适配实战

**🎓 我的HarmonyOS开发课堂**:[点击进入课堂学习](https://developer.huawei.com/consumer/cn/training/classDetail/03d6a547f8124d35aab33fc40840288f?type=1?ha_source=hmosclass&ha_sourceId=89000248)

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐