原文链接:http://www.juzicode.com/archives/597
在《Python进阶教程m01–模块》中学习了模块的导入,这篇文章讲解一个导入模块的例子,实现一个摩斯电码发报机,用电脑的音响或者蜂鸣器模拟发报机的声音。
1 winsound发声
要模拟发报机声音首先要能让电脑发出声音,可以用winsound模块的Beep()函数实现,Beep函数带2个入参,第1个入参为频率值,第2个入参为发声的时长。先熟悉下Beep()函数的调用,下面这个例子中发声的时长都为1000ms,频率设置为500,1000和0Hz,可以看到在频率为0Hz时抛异常,提示频率范围必须是37-32767,这正好覆盖了人耳能分辨的大部分频率范围:
import winsound #导入winsound模块
interval = 1000 #发声时长1000ms
freq = 500 #频率
print('freq=',freq)
winsound.Beep(freq,interval) #发出声音
freq = 1000
print('freq=',freq)
winsound.Beep(freq,interval)
freq = 0
print('freq=',freq)
winsound.Beep(freq,interval) #频率入参必须在37-32767
==========结果==========
freq= 500
freq= 1000
freq= 0
Traceback (most recent call last):
File "E:\juzicode\py3study\msy01-摩斯电码\beep01.py", line 25, in <module>
winsound.Beep(freq,interval) #频率入参必须在37-32767
ValueError: frequency must be in 37 thru 32767
2 摩斯电码
摩斯电码是用一串长短不一的声音来表示特定的字符,比如字母S用3个短音表示(…),O用3个长音表示(—),这样SOS用摩斯码表示就是 “… — …” ,如果换成声音就是3个短音,3个长音,3个短音。这种对应关系可以用字典来表示,下面的code_dict就是数字、字母和常见符号对应的摩斯编码:
code_dict = {'0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.',
'H': '....','I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.',
'O': '---', 'P': '.--.','Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-',
'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-','Y': '-.--', 'Z': '--..',
'.': '.-.-.-', ':': '---...',',': '--..--', ';': '-.-.-.', '?': '..--..',
'=': '-...-', "'": '.----.', '/': '-..-.', '!': '-.-.--','--': '-....-',
'-': '..--.-', '"': '.-..-.', '(': '-.--.', ')': '-.--.-'}
Beep()函数的第2个入参就是发声的时长,所以在控制发出短音和长音时就可以用不同的时长入参来控制发声的时长:
interv_short = 100 #短音“.”的发声时长
interv_long = 300 #长音“-”的发声时长
为了能更好的区分短音和长音,也可以将短音和长音的发声频率设置成不一样,这样更能方便人耳区分:
freq1=1500 #短音发声频率
freq2=2000 #长音发声频率
如果遇到短音“.”就使用1500Hz的频率发出100ms时长的声音,遇到长音“-”就使用2000Hz的频率发出300ms时长的声音:
if c == '.':
ret = winsound.Beep(freq1,interv_short)
print('ret = ',ret)
time.sleep(0.1)
elif c == '-':
ret = winsound.Beep(freq2,interv_long)
print('ret = ',ret)
time.sleep(0.1)
3 完整实现
首先提示输入要发送的消息字符串,因为编码字典key值的字母都是大写,所以需要用字符串的upper()方法将输入的字符串转换为大写。然后用一个for循环遍历这一串输入的消息字符串,每次提取一个字符,利用这个字符作为key值在编码字典中找到摩斯码,再用一个for循环遍历这个摩斯码,每次提取一个摩斯编码符号,如果符号为短音“.”就调用winsound.Beep(freq1,interv_short),如果符号为长音“-”则调用winsound.Beep(freq2,interv_long),消息字符串的每一个字符之间使用time.sleep(0.5)延时0.5s,方便人耳区分字符间隔。完整的代码实现( beep-and-morse.py):
'''
author: juzicode
address: www.juzicode.com
公众号: juzicode/桔子code
date: 2020.6.23
'''
print('\n')
print('-----欢迎来到www.juzicode.com')
print('-----公众号: juzicode/桔子code\n')
import time
import winsound
freq1=1500 #短音发声频率
freq2=2000 #长音发声频率
interv_short = 100 #短音“.”的发声时长
interv_long = 300 #长音“-”的发声时长
msg = input('输入要发送的消息:')
msg = msg.upper() #转换大写,摩斯码中不区分大小写
code_dict = {'0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.',
'H': '....','I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.',
'O': '---', 'P': '.--.','Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-',
'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-','Y': '-.--', 'Z': '--..',
'.': '.-.-.-', ':': '---...',',': '--..--', ';': '-.-.-.', '?': '..--..',
'=': '-...-', "'": '.----.', '/': '-..-.', '!': '-.-.--','--': '-....-',
'-': '..--.-', '"': '.-..-.', '(': '-.--.', ')': '-.--.-'}
for m in msg:
print('m:',m)
code = code_dict.get(m)
if code is None:
print('该符号不在字典中')
continue
print('code',code)
for c in code:
if c == '.':
ret = winsound.Beep(freq1,interv_short)
print('ret = ',ret)
time.sleep(0.1) #加入0.1s延时
elif c == '-':
ret = winsound.Beep(freq2,interv_long)
print('ret = ',ret)
time.sleep(0.1)
else:
print('错误编码')
time.sleep(0.5)
有趣的Python-摩斯码发报机(不同的电脑声音效果会有些差异):