python 实现音乐可视化壁纸_python 音频可视化

本文介绍了如何使用Python的wave和pyaudio模块进行音乐播放和傅里叶变换,实现音乐的频域可视化。通过读取WAV文件,使用PyAudio进行音频输出,同时利用numpy和傅里叶变换对音频数据进行处理,实时绘制频域图形。文章适合对傅里叶变换有一定了解的读者,提供了完整的代码示例。
摘要由CSDN通过智能技术生成

苍天好轮回,代码饶过谁,一坑未平,又入一坑,坑坑相套,永无天日,这篇不是小白文,要求了解傅里叶变换的基本概念,直接上代码,注释尽量写详细。

ennnnnn,我还是先介绍几个模块吧,可能我未来相当长一段时间不会再碰python了,怕自己忘记了

wave模块

wave 模块提供了一个处理 WAV 声音格式的便利接口。它不支持压缩/解压,但是支持单声道/立体声。

wave.open(file, mode=None)

如果 file 是一个字符串,打开对应文件名的文件。否则就把它作为文件类对象来处理。mode 可以为以下值:

'rb'

只读模式。

'wb'

只写模式。

注意不支持同时读写WAV文件。

mode 设为 'rb' 时返回一个 Wave_read 对象,而 mode 设为 'wb' 时返回一个 Wave_write 对象。如果省略 mode 并指定 file 来传入一个文件类对象,则 file.mode 会被用作 mode 的默认值。

如果操作的是文件对象,当使用 wave 对象的 close() 方法时,并不会真正关闭文件对象,这需要调用者负责来关闭文件对象。

The open() function may be used in a with statement. When the with block completes, the Wave_read.close() or Wave_write.close() method is called.

在 3.4 版更改: 添加了对不可搜索文件的支持。

wave.openfp(file, mode)

同 open(),用于向后兼容。

Deprecated since version 3.7, will be removed in version 3.9.

exception wave.Error

当不符合WAV格式或无法操作时引发的错误。

Wave_read对象

由 open() 返回的 Wave_read 对象,有以下几种方法:

Wave_read.close()

关闭 wave 打开的数据流并使对象不可用。当对象销毁时会自动调用。

Wave_read.getnchannels()

返回声道数量(1 为单声道,2 为立体声)

Wave_read.getsampwidth()

返回采样字节长度。

Wave_read.getframerate()

返回采样频率。

Wave_read.getnframes()

返回音频总帧数。

Wave_read.getcomptype()

返回压缩类型(只支持 'NONE' 类型)

Wave_read.getcompname()

getcomptype() 的通俗版本。使用 'not compressed' 代替 'NONE'。

Wave_read.getparams()

返回一个 namedtuple() (nchannels, sampwidth, framerate, nframes, comptype, compname),与 get*() 方法的输出相同。

Wave_read.readframes(n)

读取并返回以 bytes 对象表示的最多 n 帧音频。

Wave_read.rewind()

设置当前文件指针位置。

后面两个方法是为了和 aifc 保持兼容,实际不做任何事情。

Wave_read.getmarkers()

返回 None。

Wave_read.getmark(id)

引发错误异常。

以下两个方法都使用指针,具体实现由其底层决定。

Wave_read.setpos(pos)

设置文件指针到指定位置。

Wave_read.tell()

返回当前文件指针位置。

Wave_write 对象

由 open() 返回的 Wave_write 对象,有以下几种方法:

Wave_write.close()

确保nframes正确,并在波形打开时关闭文件。在对象集合时调用此方法。如果输出流不可搜索且nframe与实际写入的帧数不匹配,则会引发异常。

Wave_write.setnchannels(n)

设置声道数。

Wave_write.setsampwidth(n)

设置采样字节长度为 n。

Wave_write.setframerate(n)

设置采样频率为 n。

在 3.2 版更改: A non-integral input to this method is rounded to the nearest integer.

Wave_write.setnframes(n)

将帧数设置为n。如果实际写入的帧数不同,则将在以后更改(如果输出流不可搜索,则此更新尝试将引发错误)。

Wave_write.setcomptype(type, name)

设置压缩格式。目前只支持 NONE 即无压缩格式。

Wave_write.setparams(tuple)

tuple 应该是 (nchannels, sampwidth, framerate, nframes, comptype, compname),每项的值应可用于 set*() 方法。设置所有形参。

Wave_write.tell()

返回当前文件指针,其指针含义和 Wave_read.tell() 以及 Wave_read.setpos() 是一致的。

Wave_write.writeframesraw(data)

写入音频数据但不更新 nframes。

在 3.4 版更改: Any bytes-like object is now accepted.

Wave_write.writeframes(data)

写入音频帧并确保nframe正确。如果输出流不可搜索,则会引发错误,并且在写入数据之后写入的帧总数与先前设置的nframes值不匹配。

在 3.4 版更改: Any bytes-like object is now accepted.

注意在调用 writeframes() 或 writeframesraw() 之后再设置任何格式参数是无效的,而且任何这样的尝试将引发 wave.Error。

然后是pyArduio模块

就不介绍了,代码写详细点

# coding=gbk

import warnings

warnings.simplefilter("ignore", DeprecationWarning)#防止报警告

import pyaudio

import wave

import numpy as np

import pygame

from pygame.locals import *

CHUNK = 1024#我把它理解为缓冲流

wf = wave.open("1qom8-vi8uq.wav", 'rb')#以只读的方式打开"1qom8-vi8uq.wav"文件

#创建播放器

p = pyaudio.PyAudio()

#打开数据流 output=True表示音频输出

stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),

channels=wf.getnchannels(),#设置声道数

rate=wf.getframerate(),#设置流的频率

output=True)

data = wf.readframes(CHUNK)#音频数据初始化

pygame.init()#pygame初始化

pygame.display.set_caption('实时频域')#设置窗口标题

screen = pygame.display.set_mode((850, 400), 0, 32)#窗口大小为(850,400)

while data != '':#直到音频放完

stream.write(data)#播放缓冲流的音频

data = wf.readframes(CHUNK)#更新data

numpydata = np.fromstring(data, dtype=np.int16)#把data由字符串以十六进制的方式转变为数组

transforamed=np.real(np.fft.fft(numpydata))#傅里叶变换获取实数部分

screen.fill((0, 0, 0))#清空屏幕

for event in pygame.event.get():

if event.type == pygame.QUIT:

pygame.quit() #这段代码防止无响应

count=50#设置间隔区

for n in range(0,transforamed.size,count):#从频域中的2048个数据中没隔count个数据中选取一条

hight=abs(int(transforamed[n]/10000))#对这么多数据取整和绝对值

pygame.draw.rect(screen,(255,255,255),Rect((20*n/count,400),(20,-hight)))#画矩形

pygame.display.update()#更新屏幕

stream.stop_stream()

stream.close()

#关闭流

p.terminate()

ce5a37c07af2b63402634f411f0898d4.png

效果图

事实上,你还可以做的更炫酷,比如,更具振幅的高低来改变颜色,窗口透明之类的(不过pygame是sdl,不支持透明,但是你可以用pyQt)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值