Error in user YAML: (<unknown>): found a tab character that violate indentation while scanning a plain scalar at line 3 column 3
---
- oeasy Python 0758
- 这是 oeasy 系统化 Python 教程,从基础一步步讲,扎实、完整、不跳步。愿意花时间学,就能真正学会。
- 本教程同步发布在:
- 个人网站: `https://oeasy.org`
- 蓝桥云课: `https://www.lanqiao.cn/courses/3584`
- GitHub: `https://github.com/overmind1980/oeasy-python-tutorial`
- Gitee: `https://gitee.com/overmind1980/oeasypython`
---普通话的阴阳上去的调值变化,如果是其他方言呢?做成相应字符串的列表。
# 纯本地方言声调生成工具 - 无任何第三方库依赖
import sys
import os
import numpy as np
import wave
import struct
from datetime import datetime
# 定义各地方言的阴平、阳平、上声、去声调值(五度标记法)
dialect_tone_values = {
'北京话': {
'阴平': '55',
'阳平': '35',
'上声': '214',
'去声': '51'
},
'上海话': {
'阴平': '53',
'阳平': '24',
'上声': '34',
'去声': '22'
},
'广州话': {
'阴平': '55',
'阳平': '21',
'上声': '35',
'去声': '22'
},
'成都话': {
'阴平': '55',
'阳平': '41',
'上声': '53',
'去声': '13'
},
'武汉话': {
'阴平': '44',
'阳平': '213',
'上声': '42',
'去声': '35'
},
'南京话': {
'阴平': '31',
'阳平': '13',
'上声': '22',
'去声': '44'
},
'西安话': {
'阴平': '21',
'阳平': '24',
'上声': '53',
'去声': '44'
},
'天津话': {
'阴平': '11',
'阳平': '45',
'上声': '214',
'去声': '53'
}
}
# 音频参数配置
DEFAULT_SAMPLE_RATE = 44100
DEFAULT_DURATION = 1.0 # 每个音的持续时间,单位秒
DEFAULT_FREQ = 440.0 # 基础频率,对应A4音
DEFAULT_VOLUME = 0.5 # 音量,0.0-1.0
# 将五度标记法转换为频率调整因子
def tone_value_to_frequency_adjustment(tone_value, base_freq=DEFAULT_FREQ):
"""将五度标记法转换为对应的频率调整因子"""
# 五度对应的相对频率(1-5度)
pitch_levels = {
1: 0.5946, # 降低一个半音
2: 0.7071, # 保持较低
3: 1.0000, # 基准音高
4: 1.4142, # 保持较高
5: 1.6818 # 升高一个半音
}
# 解析调值(可能是两位或三位数字)
digits = [int(d) for d in str(tone_value)]
if len(digits) == 2:
# 两值调:开始值和结束值
start_level, end_level = digits
# 生成平滑过渡的频率序列
num_steps = int(DEFAULT_SAMPLE_RATE * DEFAULT_DURATION)
start_freq = base_freq * pitch_levels[start_level]
end_freq = base_freq * pitch_levels[end_level]
# 线性插值生成频率数组
freq_adjustments = np.linspace(start_freq, end_freq, num_steps)
elif len(digits) == 3:
# 三值调:开始值、中间值和结束值
start_level, mid_level, end_level = digits
# 分两段过渡
half_steps = int(DEFAULT_SAMPLE_RATE * DEFAULT_DURATION / 2)
start_freq = base_freq * pitch_levels[start_level]
mid_freq = base_freq * pitch_levels[mid_level]
end_freq = base_freq * pitch_levels[end_level]
# 生成两段插值
first_segment = np.linspace(start_freq, mid_freq, half_steps)
second_segment = np.linspace(mid_freq, end_freq, half_steps)
freq_adjustments = np.concatenate((first_segment, second_segment))
else:
# 单值调:保持固定频率
level = digits[0]
num_steps = int(DEFAULT_SAMPLE_RATE * DEFAULT_DURATION)
freq_adjustments = np.array([base_freq * pitch_levels[level]] * num_steps)
return freq_adjustments
# 生成正弦波数据
def generate_sine_wave(frequency, duration, volume=DEFAULT_VOLUME, sample_rate=DEFAULT_SAMPLE_RATE):
"""生成正弦波数据"""
num_samples = int(sample_rate * duration)
x = np.arange(num_samples)
# 生成正弦波
sine_wave = volume * np.sin(2 * np.pi * frequency * x / sample_rate)
# 转换为16位整数
return np.int16(sine_wave * 32767)
# 生成频率变化的音频数据
def generate_variable_frequency_audio(freq_adjustments, volume=DEFAULT_VOLUME, sample_rate=DEFAULT_SAMPLE_RATE):
"""根据频率调整序列生成音频数据"""
num_samples = len(freq_adjustments)
audio_data = np.zeros(num_samples, dtype=np.int16)
# 为每个样本点生成对应的正弦波值
for i in range(num_samples):
t = i / sample_rate # 当前时间
# 生成当前频率的正弦波值
audio_data[i] = np.int16(volume * 32767 * np.sin(2 * np.pi * freq_adjustments[i] * t))
return audio_data
# 保存音频数据为WAV文件
def save_audio_to_wav(audio_data, filename, sample_rate=DEFAULT_SAMPLE_RATE):
"""将音频数据保存为WAV文件"""
with wave.open(filename, 'w') as wav_file:
# 设置WAV文件参数
wav_file.setnchannels(1) # 单声道
wav_file.setsampwidth(2) # 16位
wav_file.setframerate(sample_rate)
# 写入音频数据
for sample in audio_data:
wav_file.writeframes(struct.pack('<h', sample))
# 主函数:生成拼音的四种声调音频
def generate_pinyin_tones(pinyin, dialect):
"""纯本地生成给定拼音在指定方言下的四种声调音频"""
if dialect not in dialect_tone_values:
print(f"未找到方言: {dialect}")
available_dialects = ', '.join(dialect_tone_values.keys())
print(f"可用方言: {available_dialects}")
return False
print(f"正在纯本地生成{dialect}中拼音'{pinyin}'的四种声调音频...")
# 创建输出目录
output_dir = f"{pinyin}_{dialect}_pure_local_tones_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
os.makedirs(output_dir, exist_ok=True)
# 首先生成阴平(55)的基础音频
print(" 首先生成阴平(55)的基础音频...")
yinping_freqs = tone_value_to_frequency_adjustment('55')
yinping_audio = generate_variable_frequency_audio(yinping_freqs)
# 保存阴平音频
yinping_file = os.path.join(output_dir, f"{pinyin}_阴平_55.wav")
save_audio_to_wav(yinping_audio, yinping_file)
print(f" 阴平音频已保存: {yinping_file}")
# 创建配置文件,记录声调信息
config_data = {
"timestamp": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
"pinyin": pinyin,
"dialect": dialect,
"base_tone": "阴平(55)",
"tones": {}
}
# 然后根据阴平音频调整生成其他三个声调
for tone_type in ['阳平', '上声', '去声']:
tone_value = dialect_tone_values[dialect][tone_type]
config_data["tones"][tone_type] = tone_value
print(f" 根据阴平基础音频调整生成{tone_type}({tone_value})音频...")
# 计算该声调的频率调整
tone_freqs = tone_value_to_frequency_adjustment(tone_value)
# 生成该声调的音频
tone_audio = generate_variable_frequency_audio(tone_freqs)
# 保存音频文件
output_file = os.path.join(output_dir, f"{pinyin}_{tone_type}_{tone_value}.wav")
save_audio_to_wav(tone_audio, output_file)
print(f" {tone_type}音频已保存: {output_file}")
# 保存配置文件
config_file = os.path.join(output_dir, "tone_config.json")
import json
with open(config_file, 'w', encoding='utf-8') as f:
json.dump(config_data, f, ensure_ascii=False, indent=2)
print(f"\n所有音频生成完成!")
print(f"保存在目录: {output_dir}")
print(f"配置文件已保存: {config_file}")
print("\n提示:")
print("1. 这是纯本地生成的WAV格式音频,使用Python内置模块,无需任何第三方库")
print("2. 实现了先生成阴平(55)基础音频,再根据方言特点调整生成其他三个声调的要求")
print("3. 音频基于五度标记法进行频率调整,模拟方言声调特点")
print("4. 您可以调整代码中的DEFAULT_FREQ和DEFAULT_DURATION参数来获得不同效果")
return True
# 交互式菜单
def interactive_menu():
"""交互式菜单功能"""
while True:
print("\n===== 纯本地方言声调生成工具 ======")
print("1. 生成拼音的四种声调音频")
print("2. 查看支持的方言列表")
print("3. 退出")
choice = input("请选择操作 (1-3): ")
if choice == '1':
pinyin = input("请输入要生成音频的拼音: ")
print("支持的方言:", ', '.join(dialect_tone_values.keys()))
dialect = input("请输入方言名称: ")
generate_pinyin_tones(pinyin, dialect)
elif choice == '2':
print("\n支持的方言列表:")
for dialect, tones in dialect_tone_values.items():
print(f"\n{dialect}:")
for tone_type, tone_value in tones.items():
print(f" {tone_type}: {tone_value}")
elif choice == '3':
print("感谢使用纯本地方言声调生成工具,再见!")
break
else:
print("无效的选择,请重新输入")
# 主程序入口
if __name__ == "__main__":
# 检查是否以命令行参数模式运行
if len(sys.argv) == 3:
# 参数1是拼音,参数2是方言
pinyin = sys.argv[1]
dialect = sys.argv[2]
generate_pinyin_tones(pinyin, dialect)
else:
# 交互式模式
print("欢迎使用纯本地方言声调生成工具!")
print("本工具无需网络连接,不依赖任何第三方库,完全在本地生成方言声调音频")
interactive_menu()- 调用
python3 pure_local_dialect_tool.py ma 天津话
- 观察频率
- 本文来自 oeasy Python 系统教程。
- 想完整、扎实学 Python,
- 搜索 oeasy 即可。
