python模拟声⾳输出_声⾳的输⼊输出
# 声⾳的输⼊输出
掌握了上⾯的基础知识之后,就可以做许多有趣的声效处理的算法实验了。声效处理⽅⾯的内容将在以后的章节详细介绍。
## 读写Wave⽂件
WAV是Microsoft开发的⼀种声⾳⽂件格式,虽然它⽀持多种压缩格式,不过它通常被⽤来保存未压缩的声⾳数据(PCM脉冲编码调制)。WAV有三个重要的参数:声道数、取样频率和量化位数。
* 声道数:可以是单声道或者是双声道
* 采样频率:⼀秒内对声⾳信号的采集次数,常⽤的有8kHz, 16kHz, 32kHz, 48kHz, 11.025kHz, 22.05kHz, 44.1kHz
* 量化位数:⽤多少bit表达⼀次采样所采集的数据,通常有8bit、16bit、24bit和32bit等⼏种
例如CD中所储存的声⾳信号是双声道、44.1kHz、16bit。
### 读Wave⽂件
下⾯让我们来看看如何在Python中读写声⾳⽂件:
```
# -*- coding: utf-8 -*-
import wave
import pylab as pl
import numpy as np
# 打开WAV⽂档
f = wave.open(r"c:\WINDOWS\Media\ding.wav", "rb")
# 读取格式信息
# (nchannels, sampwidth, framerate, nframes, comptype, compname)
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
# 读取波形数据
str_data = f.readframes(nframes)
f.close()
#将波形数据转换为数组
wave_data = np.fromstring(str_data, dtype=np.short)
wave_data.shape = -1, 2
wave_data = wave_data.T
time = np.arange(0, nframes) * (1.0 / framerate)
# 绘制波形
pl.subplot(211)
pl.plot(time, wave_data[0])
pl.subplot(212)
pl.plot(time, wave_data[1], c="g")
pl.xlabel("time (seconds)")
pl.show()
```
WindowsXP的经典"叮"声的波形
⾸先载⼊Python的标准处理WAV⽂件的模块,然后调⽤wave.open打开wav⽂件,注意需要使⽤"rb"(⼆进制模式)打开⽂件:
```
import wave
f = wave.open(r"c:\WINDOWS\Media\ding.wav", "rb")
```
open返回⼀个的是⼀个Wave_read类的实例,通过调⽤它的⽅法读取WAV⽂件的格式和数据:
* getparams:⼀次性返回所有的WAV⽂件的格式信息,它返回的是⼀个组元(tuple):声道数, 量化位数(byte单位), 采样频率, 采样点数,压缩类型, 压缩类型的描述。wave模块只⽀持⾮压缩的数据,因此可以忽略最后两个信息:
```
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
```
* getnchannels, getsampwidth, getframerate, getnframes等⽅法可以单独返回WAV⽂件的特定的信息。
* readframes:读取声⾳数据,传递⼀个参数指定需要读取的长度(以取样点为单位),readframes返回的是⼆进制数据(⼀⼤堆bytes),在Python中⽤字符串表⽰⼆进制数据:
```
str_data = f.readframes(nframes)
```
接下来需要根据声道数和量化单位,将读取的⼆进制数据转换为⼀个可以计算的数组:
```
wave_data = np.fromstring(str_data, dtype=np.short)
```
通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声⾳格式是以两个字节表⽰⼀个取样值,因此采⽤short数据类型转换。现在我们得到的wave_data是⼀个⼀维的short类型的数组,但是因为我们的声⾳⽂件是双声道的,因此它由左右两个声道的取样交替构成:LR(L表⽰左声道的取样值,R表⽰右声道取样值)。修改wave_data的sharp之后:
```
wave_data.shape = -1, 2
```
将其转置得到:
```
wave_data = wave_data.T
```
整个转换过程如下图所⽰:
最后通过取样点数和取样频率计算出每个取样的时间:
```
time = np.arange(0, nframes) * (1.0 / framerate)
```
### 写Wave⽂件
写WAV⽂件的⽅法和读类似:
```
# -*- coding: utf-8 -*-
import wave
import numpy as np
import scipy.signal as signal
python怎么读的
framerate = 44100
time = 10
# 产⽣10秒44.1kHz的100Hz - 1kHz的频率扫描波
t = np.arange(0, time, 1.0/framerate)
wave_data = signal.chirp(t, 100, time, 1000, method='linear') * 10000
wave_data = wave_data.astype(np.short)
# 打开WAV⽂档
f = wave.open(r"sweep.wav", "wb")
# 配置声道数、量化位数和取样频率
f.setnchannels(1)
f.setsampwidth(2)
f.setframerate(framerate)
# 将wav_data转换为⼆进制数据写⼊⽂件
f.writeframes(string())
f.close()
```
10-12⾏通过调⽤scipy.signal库中的chrip函数,产⽣长度为10秒、取样频率为44.1kHz、100Hz到1kHz的频率扫描波。由于chrip函数返回的数组为float64型,需要调⽤数组的astype⽅法将其转换为short型。
18-20⾏分别设置输出WAV⽂件的声道数、量化位数和取样频率,当然也可以调⽤⽂件对象的setparams⽅法⼀次性配置所有的参数。最后21⾏调⽤⽂件的writeframes⽅法,将数组的内部的⼆进制数据写⼊⽂件。writeframes⽅法会⾃动的更新WAV⽂件头中的长度信息(nframes),保证其和真正的数据数量⼀致。
## ⽤pyAudio播放和录⾳
通过上⼀节介绍的读写声⾳⽂件的⽅法,我们可以离线处理已经录制好的声⾳。不过更酷的是我们可以通过pyAudio库从声卡读取声⾳数据,处理之后再写回声卡,这样就可以在电脑上实时地输⼊、处理和输出声⾳数据。想象⼀下,我们可以做⼀个⼩程序,读取麦克风的数据;加上回声并和WAV⽂件中的数据进⾏混合;最后从声卡输出。这不就是⼀个Karaoke的原型么。
### 播放
下⾯先来看看如何⽤pyAudio播放声⾳。
```
# -*- coding: utf-8 -*-
import pyaudio
import wave
chunk = 1024
wf = wave.open(r"c:\WINDOWS\Media\ding.wav", 'rb')
p = pyaudio.PyAudio()
# 打开声⾳输出流
stream = p.open(format = p.get_format_from_sampwidth()),
channels = wf.getnchannels(),
rate = wf.getframerate(),
output = True)
# 写声⾳输出流进⾏播放
while True:
data = wf.readframes(chunk)
if data == "": break
stream.write(data)
stream.close()
```
这段程序⾸先根据WAV⽂件的量化格式、声道数和取样频率,分别配置open函数的各个参数,然后循环从WAV⽂件读取数据,写⼊⽤open函数打开的声⾳输出流。我们看到17-20⾏的while循环没有任何等待的代码。因为pyAudio使⽤阻塞模式,因此当底层的输出数据缓存没有空间保存数据时,stream.write会阻塞⽤户程序,直到stream.write能将数据写⼊输出缓存。
PyAudio类的open函数有许多参数:
* **rate** - 取样频率
* **channels** - 声道数
* **format** - 取样值的量化格式 (paFloat32, paInt32, paInt24, paInt16, paInt8 ...)。在上⾯的例⼦中,使⽤get_format_from_width ⽅法将wf.sampwidth()的返回值2转换为paInt16
* **input** - 输⼊流标志,如果为True的话则开启输⼊流
* **output** - 输出流标志,如果为True的话则开启输出流
* **input_device_index** - 输⼊流所使⽤的设备的编号,如果不指定的话,则使⽤系统的缺省设备
* **output_device_index** - 输出流所使⽤的设备的编号,如果不指定的话,则使⽤系统的缺省设备
* **frames_per_buffer** - 底层的缓存的块的⼤⼩,底层的缓存由N个同样⼤⼩的块组成
* **start** - 指定是否⽴即开启输⼊输出流,缺省值为True
### 录⾳
从声卡读取数据和写⼊数据⼀样简单,下⾯我们⽤⼀个简单的声⾳监测⼩程序来展⽰⼀下如何⽤pyAudio读取声⾳数据。```
# -*- coding: utf-8 -*-
from pyaudio import PyAudio, paInt16
import numpy as np
from datetime import datetime
import wave
# 将data中的数据保存到名为filename的WAV⽂件中
def save_wave_file(filename, data):
wf = wave.open(filename, 'wb')
wf.setnchannels(1)
wf.setsampwidth(2)
wf.setframerate(SAMPLING_RATE)
wf.writeframes("".join(data))
wf.close()
NUM_SAMPLES = 2000 # pyAudio内部缓存的块的⼤⼩
SAMPLING_RATE = 8000 # 取样频率
LEVEL = 1500 # 声⾳保存的阈值
COUNT_NUM = 20 # NUM_SAMPLES个取样之内出现COUNT_NUM个⼤于LEVEL的取样则记录声⾳
SAVE_LENGTH = 8 # 声⾳记录的最⼩长度:SAVE_LENGTH * NUM_SAMPLES 个取样
# 开启声⾳输⼊
pa = PyAudio()
stream = pa.open(format=paInt16, channels=1, rate=SAMPLING_RATE, input=True,
frames_per_buffer=NUM_SAMPLES)
save_count = 0
save_buffer = []
while True:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。