【学习K230-例程23】GT6700-音频FFT柱状图

B站视频


FFT

  在前面例程我们介绍了FFT(傅里叶变换)和音频的录制与播放实验,本次实验结合二者,通过将时域采集到的音频数据通过 FFT 为频域。

  例程功能:获取耳机麦克风的音频数据作为时域数据输入 FFT 模块进行 FFT 得到频域数据后,计算频域数据各个频率点的幅值并在 LCD 上进行直观的图像显示。

                   

代码展示

python 复制代码
import time
import os
import urandom
import sys
import array
import gc
from media.media import *   #导入media模块,用于初始化vb buffer
from media.pyaudio import * #导入pyaudio模块,用于采集和播放音频
from machine import FFT
from media.display import *
import media.wave as wave   #导入wav模块,用于保存和加载wav音频文件

HIST_NUM = 50
FFT_POINTS = 128
DISPLAY_MODE = "LCD"

# 根据模式设置显示宽高
if DISPLAY_MODE == "VIRT":
    # 虚拟显示器模式
    DISPLAY_WIDTH = ALIGN_UP(800, 16)
    DISPLAY_HEIGHT = 480
    hist_width = int(DISPLAY_WIDTH / HIST_NUM)
elif DISPLAY_MODE == "LCD":
    # LCD寸屏幕模式
    DISPLAY_WIDTH = ALIGN_UP(480, 16)
    DISPLAY_HEIGHT = 800
    hist_width = int(DISPLAY_HEIGHT / HIST_NUM)
elif DISPLAY_MODE == "HDMI":
    # HDMI扩展板模式
    DISPLAY_WIDTH = ALIGN_UP(1920, 16)
    DISPLAY_HEIGHT = 1080
    hist_width = int(DISPLAY_WIDTH / HIST_NUM)
else:
    raise ValueError("请选择 'VIRT', 'LCD' 或 'HDMI'")



def exit_check():
    try:
        os.exitpoint()
    except KeyboardInterrupt as e:
        print("用户停止: ", e)
        return True
    return False

def audio_fft(filename):

    # 创建用于绘制的图像
    img = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.RGB565)
    if DISPLAY_MODE == "VIRT":
        # 使用 IDE 作为输出显示,可以设定任意分辨率
        Display.init(Display.VIRT, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, fps=30)
    elif DISPLAY_MODE == "LCD":
        # 使用 LCD 作为显示输出
        Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT,fps=10, to_ide=True)
    elif DISPLAY_MODE == "HDMI":
        # 使用 HDMI 作为显示输出
        Display.init(Display.LT9611, to_ide=True)
    else:
        raise ValueError("请选择 'VIRT', 'LCD' 或 'HDMI'")

    try:
        wavef = wave.open(filename, 'rb')       #打开wav文件
        CHUNK = int(wavef.get_framerate()/25)   #设置音频chunk值
        pya = PyAudio()         #创建PyAudio对象
        pya.initialize(CHUNK)   #初始化PyAudio对象
        MediaManager.init()     #vb buffer初始化
        #创建音频输出流,设置的音频参数均为wave中获取到的参数
        stream = pya.open(format=pya.get_format_from_width(wavef.get_sampwidth()),
                    channels=wavef.get_channels(),
                    rate=wavef.get_framerate(),
                    output=True,frames_per_buffer=CHUNK)
        stream.volume(vol=30)           #设置音频输出流的音量
        data = wavef.read_frames(CHUNK) #从wav文件中读取数一帧数据
        #从音频输入流中获取数据写入到音频输出流中,并用柱状图显示音频数据
        while True:
            stream.write(data)              #将帧数据写入到音频输出流中

            img.clear()
            # 读取音频数据,缓存在data
            data = wavef.read_frames(CHUNK) #从wav文件中读取数一帧数据
            # 创建一个FFT对象,运算点数为FFT_POINTS,偏移是0
            fft1 = FFT(data,FFT_POINTS,0)
            # 对data进行进行傅里叶变换,并返回相应的频率
            res = fft1.run()
            # 获取各个频率点的幅值
            amp = fft1.amplitude(res)

            # 将获取的音频幅值转换为,显示矩形高度
            if DISPLAY_MODE == "LCD":
                for hist in range(HIST_NUM):
                    if amp[hist] > DISPLAY_WIDTH:
                        hist_height = DISPLAY_WIDTH
                    else:
                        hist_height = amp[hist]
                    # 根据音频幅值画矩形
                    img.draw_rectangle(0,hist * hist_width, hist_height,
                                       hist_width,color=(255, 255, 255), fill=True)
            else:
                for hist in range(HIST_NUM):
                    if amp[hist] > DISPLAY_HEIGHT:
                        hist_height = DISPLAY_HEIGHT
                    else:
                        hist_height = amp[hist]
                    # 根据音频幅值画矩形
                    img.draw_rectangle(hist * hist_width, DISPLAY_HEIGHT - hist_height, hist_width,
                                       hist_height,color=(255, 255, 255), fill=True)
            # 将绘制的图像显示
            Display.show_image(img)
            time.sleep(0.01)
            os.exitpoint()
            gc.collect()
            if exit_check():
                break
    except BaseException as e:
            print(f"异常: {e}")

    # 销毁显示
    finally:
        stream.stop_stream()    #停止音频输出流
        stream.close()          #关闭音频输出流
        pya.terminate()             #释放音频对象
        Display.deinit()
        os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
        time.sleep_ms(100)
        # 释放媒体缓冲区
        MediaManager.deinit()

if __name__ == "__main__":
    os.exitpoint(os.EXITPOINT_ENABLE)
    print("audio sample start")
    audio_fft('/sdcard/examples/Jzhou.wav') #采集音频并输出
    print("audio sample done")

效果展示

  点击 CanMV IDE 上的"开始(运行脚本)"按钮后, 便了看到 LCD 上显示了板载数字麦克风采集到音频数据的频谱图,如下图所示:

【学习k230 - 例程23】音频FFT柱状图

相关推荐
几秒前
Python 图片处理:裁剪缩放至300×200,格式JPG/PNG/GIF,控制大小≤100KB
linux·前端·python
2601_962294613 分钟前
Python工具软件开发:借助InsCode AI IDE开启智能编程新时代
ide·python·ai·开发工具·智能化编程
2601_962097362 小时前
GraphQL,Grafana和Dash
python·grafana·数据可视化·graphql·dash
mykj15518 小时前
英语单词APP解锁学习新方式,智能高效背单词
学习·英语单词app
知识分享小能手9 小时前
深度学习学习教程,从入门到精通,深度学习中的正则化 — 完整知识点与代码示例(7)
人工智能·深度学习·学习
benchmark_cc9 小时前
REST API 和 Python SDK 应该怎么选?量化交易数据接口选型实战
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
~kiss~10 小时前
Agent 的 未来吗?String: An Agentic OS Where Every App Is a Markdown File
学习
HugoStudio_SWAN10 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
2601_9623824311 小时前
python快乐编程网络爬虫课后答案
python·网络爬虫·学习工具·课后答案·刷题app
鹏哥带你干乡墅11 小时前
优选乡墅赋能培训平台如何帮助提升乡村建设?
大数据·人工智能·python