You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin实现WAV音频指纹相似度对比问题求助

Android英语听读练习应用的音频指纹匹配问题

我正在开发一款“听读练习”类英语学习应用,需要对比Android文本转语音(TTS)生成的短句WAV文件与用户通过OmRecorder库录制的同一句WAV文件的指纹相似度,返回匹配分数。由于FFT实现复杂且耗时,希望借助现成库完成,目前试用musicg库但结果异常,始终返回0或固定值0.047。

调试时已确认两个音频参数一致:

音频文件参数

文件1(TTS生成)参数

chunkId: RIFF
chunkSize: 53286
format: WAVE
subChunk1Id: fmt 
subChunk1Size: 16
audioFormat: 1
channels: 1
sampleRate: 10240
byteRate: 20480
blockAlign: 2
bitsPerSample: 16
subChunk2Id: data
subChunk2Size: 53250
length: 2.6000977

文件2(用户录制)参数

chunkId: RIFF
chunkSize: 24378
format: WAVE
subChunk1Id: fmt 
subChunk1Size: 16
audioFormat: 1
channels: 1
sampleRate: 10240
byteRate: 20480
blockAlign: 2
bitsPerSample: 16
subChunk2Id: data
subChunk2Size: 24342
length: 1.1885742

指纹对比Kotlin代码

val w1 = Wave(this.cacheDir.toString() + "/file1.wav")
val w2 = Wave(this.cacheDir.toString() + "/file2.wav")
println("Wave 1 = " + w1.waveHeader)
println("Wave 2 = " + w2.waveHeader)
val fpsc1: FingerprintSimilarity = w1.getFingerprintSimilarity(w2)
val scorec = fpsc1.score
val simc = fpsc1.similarity
(findViewById<View>(R.id.tvScore) as TextView).text = scorec.toString()
(findViewById<View>(R.id.tvSimilarity) as TextView).text = simc.toString()

OmRecorder录制代码片段

private var recorder: Recorder? = null

private fun startRecording() {
    if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.RECORD_AUDIO
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        return
    }

    val file: String = this.cacheDir.toString() + "/file2.wav"

    recorder = OmRecorder.wav(
        PullTransport.Default(
            mic()
        ) { audioChunk -> animateVoice((audioChunk.maxAmplitude() / 200.0).toFloat()) }, File(file)
    )

    recorder!!.startRecording()
}

private fun mic(): PullableSource {
    return PullableSource.Default(
        AudioRecordConfig.Default(
            MediaRecorder.AudioSource.MIC, AudioFormat.ENCODING_PCM_16BIT,
            AudioFormat.CHANNEL_IN_MONO, 8000
        )
    )
}

private fun animateVoice(maxPeak: Float) {
    (findViewById<View>(R.id.microphone) as ImageView).animate().scaleX(1 + maxPeak).scaleY(1 + maxPeak).setDuration(10).start()
}

可行解决方案建议

1. 优先解决音频时长对齐问题

从参数看两段音频长度差异明显(2.6s vs 1.19s),musicg的指纹匹配对时长对齐要求极高。可先做对齐处理:

  • 对较短的音频补零,使其样本数与长音频一致
  • 或手动提取两段音频中对应语句的有效片段,确保时间轴完全匹配后再测试

2. 替换为适配Android的音频特征匹配库

TarsosDSP库

支持Android平台,可提取MFCC、频谱特征,手动实现余弦相似度或动态时间规整(DTW)对比,性能适配移动端场景,适合短句语音的特征匹配。

结合Google ML Kit的混合方案

既然是英语短句,可采用“语音转文本+语音特征辅助”的混合评分:

  • 用ML Kit语音识别将两段音频转成文本,计算文本匹配度
  • 额外提取基频、短时能量等时域特征,综合得到最终发音匹配分数

3. 实现轻量级自定义匹配逻辑

如果不想依赖第三方库,可实现简单的时域特征对比:

  • 提取两段音频的短时能量、过零率序列,用DTW算法计算序列距离(DTW专门处理时长不同的序列匹配)
  • 优化计算量,只取关键帧特征,避免全序列遍历

4. 排查musicg库参数问题

检查musicg版本兼容性,尝试手动调整FingerprintConfiguration的窗口大小、步长等参数,默认参数可能不适合短句语音的指纹提取。

内容的提问来源于stack exchange,提问作者Diego Perez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 07:37:51