技术栈:HarmonyOS 5.0 + ArkTS + AudioRenderer
适用场景:听力健康应用、医疗辅助工具
前言
纯音测听(Pure Tone Audiometry)是临床上最常用的听力检测方法。本文将介绍如何在HarmonyOS应用中实现一个专业的纯音测听功能。
一、纯音测听原理
1.1 测试频率
标准纯音测听使用以下频率:
- 125Hz, 250Hz, 500Hz:低频
- 1000Hz, 2000Hz:中频(语音频率)
- 4000Hz, 8000Hz:高频
1.2 听阈分级(WHO标准)
| 听阈 (dB) | 听力等级 |
|---|---|
| ≤25 | 正常 |
| 26-40 | 轻度损失 |
| 41-55 | 中度损失 |
| 56-70 | 中重度损失 |
| 71-90 | 重度损失 |
| >90 | 极重度损失 |
二、数据结构设计
typescript
export interface PureToneFrequencyResult {
frequency: number; // 测试频率 Hz
leftEarThreshold: number; // 左耳听阈 dB,-1表示未测试
rightEarThreshold: number;// 右耳听阈 dB
}
export interface PureToneTestResult {
id: string;
timestamp: number;
results: PureToneFrequencyResult[];
leftEarAverage: number;
rightEarAverage: number;
overallLevel: string;
leftEarLevel: string;
rightEarLevel: string;
}
三、测试页面实现
3.1 页面状态管理
typescript
@Entry
@Component
struct PureToneTestPage {
@StorageLink('appDarkMode') isDarkMode: boolean = true;
@State currentEar: string = 'left';
@State currentFrequencyIndex: number = 0;
@State currentVolume: number = 30;
@State isPlaying: boolean = false;
@State testResults: PureToneFrequencyResult[] = [];
@State testPhase: string = 'intro';
private testFrequencies: number[] = [125, 250, 500, 1000, 2000, 4000, 8000];
private audioEngine: AudioEngine = AudioEngine.getInstance();
aboutToAppear(): void {
this.initTestResults();
this.audioEngine.init();
}
private initTestResults(): void {
this.testResults = this.testFrequencies.map((freq: number) => ({
frequency: freq,
leftEarThreshold: -1,
rightEarThreshold: -1
}));
}
}
3.2 播放测试音
typescript
private async playTestTone(): Promise<void> {
if (this.isPlaying) {
await this.audioEngine.stop();
this.isPlaying = false;
return;
}
this.isPlaying = true;
const frequency = this.testFrequencies[this.currentFrequencyIndex];
const safeVolume = Math.max(0.1, this.currentVolume / 100);
this.audioEngine.setAudioType('tone');
this.audioEngine.setWaveformType('sine');
this.audioEngine.setFrequency(frequency);
this.audioEngine.setVolume(safeVolume);
await this.audioEngine.start(3);
setTimeout(() => { this.isPlaying = false; }, 3000);
}
3.3 记录听阈
typescript
private recordThreshold(): void {
const result = this.testResults[this.currentFrequencyIndex];
if (this.currentEar === 'left') {
result.leftEarThreshold = this.currentVolume;
} else {
result.rightEarThreshold = this.currentVolume;
}
// 震动反馈
vibrator.startVibration({ type: 'time', duration: 50 }, { id: 0, usage: 'notification' });
this.nextTest();
}
private nextTest(): void {
if (this.currentEar === 'left') {
this.currentEar = 'right';
this.currentVolume = 30;
} else {
this.currentEar = 'left';
this.currentFrequencyIndex++;
this.currentVolume = 30;
if (this.currentFrequencyIndex >= this.testFrequencies.length) {
this.testPhase = 'completed';
this.saveResults();
}
}
}
3.4 计算平均听阈
typescript
static async savePureToneTestResult(results: PureToneFrequencyResult[]): Promise<PureToneTestResult> {
const speechFrequencies = [500, 1000, 2000, 4000];
let leftSum = 0, rightSum = 0, leftCount = 0, rightCount = 0;
for (const r of results) {
if (speechFrequencies.includes(r.frequency)) {
if (r.leftEarThreshold >= 0) {
leftSum += r.leftEarThreshold;
leftCount++;
}
if (r.rightEarThreshold >= 0) {
rightSum += r.rightEarThreshold;
rightCount++;
}
}
}
const leftAvg = leftCount > 0 ? Math.round(leftSum / leftCount) : -1;
const rightAvg = rightCount > 0 ? Math.round(rightSum / rightCount) : -1;
return {
id: `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
timestamp: Date.now(),
results: results,
leftEarAverage: leftAvg,
rightEarAverage: rightAvg,
overallLevel: getHearingLevelByThreshold(Math.max(leftAvg, rightAvg)),
leftEarLevel: getHearingLevelByThreshold(leftAvg),
rightEarLevel: getHearingLevelByThreshold(rightAvg)
};
}
static getHearingLevelByThreshold(threshold: number): string {
if (threshold < 0) return '未测试';
if (threshold <= 25) return '正常';
if (threshold <= 40) return '轻度损失';
if (threshold <= 55) return '中度损失';
if (threshold <= 70) return '中重度损失';
if (threshold <= 90) return '重度损失';
return '极重度损失';
}
四、UI界面示例
typescript
build() {
Column() {
// 进度指示
Row() {
ForEach(this.testFrequencies, (freq: number, index: number) => {
Circle()
.width(12).height(12)
.fill(index < this.currentFrequencyIndex ? '#2D7FF9' :
index === this.currentFrequencyIndex ? '#34C759' : '#333')
})
}.justifyContent(FlexAlign.SpaceEvenly).width('100%')
Text(`${this.testFrequencies[this.currentFrequencyIndex]} Hz`)
.fontSize(48).fontWeight(FontWeight.Bold)
Text(`${this.currentEar === 'left' ? '左耳' : '右耳'}`)
.fontSize(20)
Slider({ value: this.currentVolume, min: 0, max: 100, step: 5 })
.onChange((value: number) => { this.currentVolume = value; })
Row() {
Button('播放').onClick(() => this.playTestTone())
Button('听到了').onClick(() => this.recordThreshold())
}.justifyContent(FlexAlign.SpaceEvenly)
}
}
五、避坑指南
- 音量校准:不同设备音量输出不同,建议添加校准功能
- 测试环境:提醒用户在安静环境中使用耳机测试
- 免责声明:明确说明仅供参考,不能替代专业医学检查
- 数据保护:测试结果仅存储在本地
总结
本文实现了一个专业的纯音测听功能,包括标准频率测试、听阈记录、等级评估等。该功能可帮助用户初步了解自己的听力状况。