强制对齐音频与转录文本 - MFA的安装及使用

强制对齐音频与转录文本 - MFA的安装及使用

MFA是基于Kaldi的强制对齐工具。它可以将音频信号中的每个声音片段与相应的文本对齐,以确定每个词或音素的开始和结束时间。
其中,Kaldi是目前最流行的开源自动语音识别Automatic speech recognition (ASR)工具箱,包含了几乎所有目前主流ASR系统用到的算法,代码使用C++编写。具体的介绍可参考Kaldi官网,也可以参考Kaldi Tutorial文档。

本文想要实现的功能是,将一段音频与音频对应的文本在单词级别进行对齐,并进行可视化。

MFA安装

安装环境: Mac OS, M1芯片。

安装命令:

$ conda create -n aligner -c conda-forge montreal-forced-aligner

执行上面命令后,查看即将安装的package列表,如果存在Kaldi,因此无需再单独安装。
如果命令执行成功,会创建一个名为aligner的conda环境,后续的对齐操作要在这个环境中进行。

更新MFA:
执行下面命令,可将MFA更新到最新版本。

$ conda update -c conda-forge montreal-forced-aligner kalpy kaldi=*=cpu* --update-deps

激活环境:

$ conda activate aligner 

下载模型:
网页中找到需要的模型及字典后,可以在Terminal使用命令行下载:

# 下载中文模型
$ mfa models download acoustic mandarin_mfa
# 下载中文字典
$ mfa model download dictionary mandarin_china_mfa

其他依赖包:
由于使用MFA对齐需要其他一些依赖包,比如spacy,用来进行tokenization。
执行下面命令进行安装:

# 安装
$ conda install spacy
# 安装英文语言模型
$ python -m spacy download en_core_web_sm
# 安装中文语言模型
$ python -m spacy download en_core_web_sm
# 中文 tokenization
$ pip install spacy-pkuseg dragonmapper hanziconv

使用MFA对齐语音及文本

执行对齐命令:

$ mfa align ./data mandarin_china_mfa mandarin_mfa ./data/result

./data路径下文件结构如下:

-data
    -speaker1 # 第一个音频及文本所在的目录
        -speaker1.wav # 第一个音频
        -speaker1.txt # 第一个音频的转录文本
    -speaker2 # 第二个音频及文本所在的目录
        -speaker2.wav
        -speaker2.txt
    -result # 存放生成的TextGrid文件,对齐命令执行后生成下面文件
        -speaker1
            -speaker1.TextGrid
        -speaker2
            -speaker2.TextGrid

上述命令会将./data目录下的音频文件和文本文件中的内容对齐,生成.TextGrid文件。
.TextGrid文件是Praat软件用来存储音频标注的文件格式,这些标注通常用于表示音素、单词、短语或其他语音成分的时间边界。

比如生成的.TextGrid会包含如下内容:

	1.	总时间范围:
		xmin = 0
		xmax = 3.584
		这表示整个TextGrid文件覆盖从0秒到3.584秒的时间范围。
	2.	第一个IntervalTier (“words”):
		class = "IntervalTier"
		name = "words" # 单词或短语
		xmin = 0
		xmax = 3.584
		intervals: size = 6:这个层级包含6个时间间隔。
		每个间隔有一个开始时间(xmin),结束时间(xmax),以及标注文本(text)。
	3.	第二个IntervalTier (“phones”):
		class = "IntervalTier" #音素
		name = "phones"
		xmin = 0
		xmax = 3.584
		intervals: size = 16:这个层级包含16个时间间隔。
		每个间隔有一个开始时间(xmin),结束时间(xmax),以及标注文本(text)。

对齐结果可视化

下面是将其中一个.TextGrid文件可视化,得到的每个单词或短语对应的时间-频率图:

在这里插入图片描述

代码如下:

import parselmouth
import matplotlib.pyplot as plt
import numpy as np
import tgt
from matplotlib.font_manager import FontProperties
import pandas as pd

# 设置中文字体
font = FontProperties(fname='/System/Library/Fonts/STHeiti Medium.ttc')
# 设置支持IPA字符的字体
ipa_font = FontProperties(fname='/Users/xxx/Library/Fonts/DejaVuSans.ttf')  # 确保路径正确

def remove_outliers_and_zeroes(pitch_values, threshold=3):
    # 将音高值为0的点设置为NaN
    pitch_values = np.where(pitch_values != 0, pitch_values, np.nan)
    
    # 计算音高值的均值和标准差
    mean = np.nanmean(pitch_values)
    std = np.nanstd(pitch_values)
    
    # 计算Z-score
    z_scores = (pitch_values - mean) / std
    
    # 将超过阈值的音高值设置为NaN
    pitch_values = np.where(np.abs(z_scores) < threshold, pitch_values, np.nan)
    return pitch_values

def plot_alignment(audio_path, textgrid_path, title):
    # 读取音频文件
    sound = parselmouth.Sound(audio_path)
    
    # 读取TextGrid文件
    tg = tgt.io.read_textgrid(textgrid_path)
    
    # 提取音高信息
    pitch = sound.to_pitch()
    pitch_values = pitch.selected_array['frequency']
    pitch_times = pitch.xs()
    
    # 去除离群值和音高值为0的点
    pitch_values = remove_outliers_and_zeroes(pitch_values)
    
    # 找到名为'words'和'phones'的tier
    words_tier = tg.get_tier_by_name('words')
    phones_tier = tg.get_tier_by_name('phones')
    
    # 绘制音高轮廓
    plt.figure(figsize=(14, 8))
    plt.plot(pitch_times, pitch_values, '-', markersize=5, color='b', label="Pitch")
    
    # 从TextGrid中提取单词间隔并绘制
    for interval in words_tier.intervals:
        plt.axvline(x=interval.start_time, color='k', linestyle='--')
        plt.text((interval.start_time + interval.end_time) / 2, np.nanmax(pitch_values) * 0.9, interval.text, 
                 horizontalalignment='center', verticalalignment='center', color='red', fontsize=12, fontproperties=font)
    
    # 从TextGrid中提取音素间隔并绘制
    for interval in phones_tier.intervals:
        plt.axvline(x=interval.start_time, color='gray', linestyle=':')
        plt.text((interval.start_time + interval.end_time) / 2, np.nanmax(pitch_values) * 0.8, interval.text, 
                 horizontalalignment='center', verticalalignment='center', color='green', fontsize=8, fontproperties=ipa_font)
    
    plt.grid(True)
    plt.title(title, fontproperties=font)
    plt.xlabel("Time (s)", fontproperties=font)
    plt.ylabel("Pitch (Hz)", fontproperties=font)
    plt.legend(prop=font)
    plt.show()

plot_alignment("data/speaker1/speaker1.wav", "data/result/speaker1/speaker1.TextGrid", "Speaker 1 Alignment")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值