效果图: 操作演示: 技术要点: 1matplotlib的南丁格尔玫瑰图,用极坐标polar制作,并动画显示。 2pygame新版的播放mp3,但本机的操作系统不能播放mp3,我用pydub做些格式转换。 3用librosa获取音乐的相关数据和采样。 4参考代码,并对源代码进行修改,增加,删减,排版和注释,感谢原作者,如有侵权,请联系,定删除。https:github。comhahacydSimpleMusicVisualizer 下面分步,讲解代码 第1步:模块导入importosimporttimeimportpygameimportlibrosaimportnumpyasnpfrompydubimportAudioSegmentimportmatplotlib。pyplotaspltfrommatplotlib。animationimportFuncAnimation 第2步:窗口的初始化设置print(开始格式转换,请等待,一会马上就会播放音乐,请欣赏音乐和可视化)plt。rcParams〔axes。unicodeminus〕False负号显示画布的大小和背景颜色设置figplt。figure(facecolorblack,edgecolorblack,figsize(12,7))axplt。subplot(projectionpolar)ax。patch。setfacecolor(black)图形背景颜色设置设置显示界面的位置mngrplt。getcurrentfigmanager()mngr。window。wmgeometry(500200) 第3步:参数设置设置显示的柱状图的个数binnums24设置显示的频率范围:(01350Hz)frequencythreshold1350音乐时长(s)musiclength0。0帧时长,即每一帧所需的时长简而言之就是每隔‘samplinginterval’秒刷新一次samplinginterval0。05tempnp。tile(0,binnums)重复数组,角度musicplaystarttime0currenttime0musicfftnp。empty(0)创建空数组binsnp。empty(0) 第4步:核心代码:polar柱状图,如果是垂直柱状图,就是适当进行修改可视化柱子和上头线设置比如选择了RdBu色谱,选择分为24段colorsplt。getcmap(RdPu,24)cmap即colormaps获取图谱使用plt。getcmap(‘xxx’)扇形柱子的宽度width2np。pibinnums角度和数据radnp。cumsum(〔width〕binnums)每个扇形的起始角度扇形柱状图rectsax。bar(rad,temp,widthwidth,colorcolors(range(0,binnums)),alpha1,bottom900)初始化柱状图中的横线跌落效果line,ax。plot(rad,temp,,colorwhite,linewidth10)ax。setthetazerolocation(N)设置极坐标的起点(即0度)在正上方向ax。grid(False)不显示极轴ax。spines〔polar〕。setvisible(False)不显示极坐标最外的圆形ax。setyticks(〔〕)不显示坐标间隔ax。setthetagrids(〔〕)不显示极轴坐标核心代码部分 第5步:filter类classExpFilter:definit(self,val0。0,alphadecay0。5,alpharise0。5):self。alphadecayalphadecayself。alpharisealphariseself。valuevaldefupdate(self,value):ifisinstance(self。value,(list,np。ndarray,tuple)):alphavalueself。valuealpha〔alpha0。0〕self。alpharisealpha〔alpha0。0〕self。alphadecayelse:alphaself。alphariseifvalueself。valueelseself。alphadecayself。valuealphavalue(1。0alpha)self。valuereturnself。value使用filter,来使得柱形图中的变化平缓一些alphadecay和alpharise,其值需在01之间,分别表示下降和上升的反应速度越大越灵敏,如果都设为1,将失去滤波的效果这里选择了0。3和0。6,即下降时较慢,而上升较快filterExpFilter(np。tile(0,binnums),alphadecay0。30,alpharise0。60) 第6步:函数定义初始化definit():globalymaxax。setylim(0,ymax)returnrects更新函数defupdate(frame):currenttimetime。time()获知当前歌曲的播放进度,以选择此进度下的fft数据currentframe((currenttimemusicplaystarttime)samplinginterval)播放完了,处理ifcurrentframeFRAMES1:exit()这里的musicfft是从getBin()获得的sourcemusicfft〔int(currentframe)1〕注意这里一般可能不需要1,根据不同mp3而定indexmaxymax(ymax80)sourcesource〔indexmax〕ymax(ymax80)更新柱状图binsfilter。update(source)更新柱状图中的横线跌落效果lineydataline。getydata()lineydataint(ymax30)lineindexlineydataint(ymax100)binslineydata〔lineindex〕bins〔lineindex〕int(ymax100)line。setydata(lineydata)forrect,hinzip(rects,bins):rect。setheight(h)fig。canvas。flushevents()刷新fig。canvas。draw()重新绘图图像更新后将保持一帧的时间time。sleep(samplinginterval)fig。canvas。manager。setwindowtitle(总共:d秒;已经播放时间:d秒(round(musiclength),round(currenttimemusicplaystarttime,0)))窗口标题名设置处理音乐中的每一帧数据defgetBin(y,sr,samplinginterval):time1time。time()计算每一帧有多少采样,用于计算fftfftintervalint(srsamplinginterval)lengthfftinterval2nums(srbinnums)(frequencythreshold2)batchlengthnumsresultnp。atleast2d(np。tile(0,binnums))foriinrange(int(musiclengthsamplinginterval)):fftnp。fft。fft(y〔fftintervali:fftinterval(i1)〕)freqbinnp。array(〔np。abs(fft〔batchx:batch(x1)〕)。sum()samplingintervalforxinrange(binnums)〕)resultnp。vstack(〔result,freqbin〕)time2time。time()returnresult播放指定的歌曲defplay():pygame。init()pygame。mixer。music。stop()播放音乐musicpygame。mixer。music。load(naudiopath)转换成ogg的临时文件pygame。mixer。music。play() 第7步:启动主函数ifnamemain:设置音乐文件的路径audiopath。cwsk。mp3本操作系统,新版pygame不支持mp3,需要转换soundAudioSegment。fromfile(audiopath)转换后放在临时主目录下filesound。export(newsong。ogg,formatogg)naudiopath。newsong。ogg临时文件y,srlibrosa。load(naudiopath,srNone)musiclengthlen(y)srprint(时长:gs采样率:gkHz(musiclength,sr1000))musicfftgetBin(yy,srsr,samplingintervalsamplinginterval)ymaxmusicfft。max()3FRAMESmusicfft。shape〔0〕aniFuncAnimation(fig,update,initfuncinit,blitFalse,interval0,framesFRAMES1,repeatFalse)play()记录音乐开始播放的时间musicplaystarttimetime。time()plt。tightlayout()紧凑布局,缩小外边距plt。show()显示plt。pause(musiclength) 自己整理,分享出来,希望大家喜欢。