功能:
- wav音频文件本地录音,并播放
- 录音模块:INMP441
- 音频模块:MAX98357
- 喇叭:3W
程序
from machine import I2S,SPI
from machine import Pin
import os, utime
import uos
import time
def createWavHeader(sampleRate, bitsPerSample, num_channels, datasize):
o = bytes("RIFF",'ascii') # (4byte) Marks file as RIFF
o += (datasize + 36).to_bytes(4,'little') # (4byte) File size in bytes excluding this and RIFF marker
o += bytes("WAVE",'ascii') # (4byte) File type
o += bytes("fmt ",'ascii') # (4byte) Format Chunk Marker
o += (16).to_bytes(4,'little') # (4byte) Length of above format data
o += (1).to_bytes(2,'little') # (2byte) Format type (1 - PCM)
o += (num_channels).to_bytes(2,'little') # (2byte)
o += (sampleRate).to_bytes(4,'little') # (4byte)
o += (sampleRate * num_channels * bitsPerSample // 8).to_bytes(4,'little') # (4byte)
o += (num_channels * bitsPerSample // 8).to_bytes(2,'little') # (2byte)
o += (bitsPerSample).to_bytes(2,'little') # (2byte)
o += bytes("data",'ascii') # (4byte) Data Chunk Marker
o += (datasize).to_bytes(4,'little') # (4byte) Data size in bytes
return o
def start_in(sfile='s.wav', sampleRate=8000, bitsPerSample=16):
bufSize=32768
# 连接端口:3.3V SD->G21 WS->G22 SCK->G23 L/R-> 低电频
#I2S所需管脚
#数据时钟(INMP441模块SCK)
sck_pin = Pin(23)
#帧时钟(INMP441模块模块WS)
ws_pin = Pin(22)
#数据(INMP441模块模块SD)
sd_pin = Pin(21)
#创建用于音频录制的I2S对象
audioInI2S = I2S(0,
sck=sck_pin, ws=ws_pin, sd=sd_pin,
mode=I2S.RX,
bits=bitsPerSample,
format=I2S.STEREO,
rate=sampleRate,
ibuf=bufSize)
#音频数据读取缓冲
readBuf = bytearray(bufSize)
print("start ready.......")
#休眠一点时间
utime.sleep(2.0)
# 检查文件是否存在
if sfile in uos.listdir():
# 删除文件
print('del', sfile)
uos.remove(sfile)
utime.sleep(0.5)
fin = open(sfile, 'wb')
file_duration = 10 # 文件时长(秒)
start_time = time.time()
num_channels = 2
f = True
head = createWavHeader(sampleRate, bitsPerSample, num_channels, bufSize*file_duration)
fin.write(head)
print("in ready.......")
while f:
# 读取音频数据
currByteCount = audioInI2S.readinto(readBuf)
print('in ', len(readBuf))
audio_data = bytearray()
audio_data.extend(readBuf)
fin.write(audio_data)
# 检查是否到达文件时长
if time.time() - start_time >= file_duration:
f = False
fin.close()
print('in end')
def start_out(sfile='s.wav', sampleRate=8000, bitsPerSample=16):
if not sfile in uos.listdir():
print('not found ', sfile)
return
# 初始化引脚定义
"""
GPIO13 -- DIN
GPIO12 --- BCLK
GPIO14 -- LRC
GND -- GND
5V或3.3V -- VCC
"""
sck_pin = Pin(12) # 串行时钟输出
ws_pin = Pin(14) # 字时钟
sd_pin = Pin(13) # 串行数据输出
# 初始化i2s
audio_out = I2S(1, sck=sck_pin, ws=ws_pin, sd=sd_pin,
mode=I2S.TX, bits=bitsPerSample, format=I2S.STEREO,
rate=sampleRate, ibuf=20000)
f = open(sfile,'rb')
# 跳过文件的开头的44个字节,直到数据段的第1个字节
pos = f.seek(44)
wav_samples = bytearray(1024)
wav_samples_mv = memoryview(wav_samples)
print("start out ...")
#并将其写入I2S DAC
while True:
try:
num_read = f.readinto(wav_samples_mv)
# WAV文件结束
if num_read == 0:
break
# 直到所有样本都写入I2S外围设备
num_written = 0
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv[num_written:num_read])
except Exception as ret:
print("产生异常...", ret)
break
print(' out end')
print('start')
# 录音
start_in()
# 音频播放
start_out()
print('end')
运行日志
start
start ready.......
del s.wav
in ready.......
in 32768
in 32768
in 32768
in 32768
in 32768
in 32768
in 32768
in 32768
in end
start out ...
out end
end